mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-02-02 18:43:48 +00:00
Big re-organization of repository [W.I.P]
This commit is contained in:
370
modules/acore/deps/g3dlite/source/AABox.cpp
Normal file
370
modules/acore/deps/g3dlite/source/AABox.cpp
Normal file
@@ -0,0 +1,370 @@
|
||||
/**
|
||||
@file AABox.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2004-01-10
|
||||
@edited 2006-01-11
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/AABox.h"
|
||||
#include "G3D/Box.h"
|
||||
#include "G3D/Plane.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
|
||||
namespace G3D {
|
||||
|
||||
const AABox& AABox::maxFinite() {
|
||||
static const AABox b = AABox(Vector3::minFinite(),
|
||||
Vector3::maxFinite());
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
const AABox& AABox::large() {
|
||||
static const AABox b = AABox(Vector3::minFinite() * 0.5f,
|
||||
Vector3::maxFinite() * 0.5f);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
const AABox& AABox::inf() {
|
||||
static const AABox b = AABox(-Vector3::inf(), Vector3::inf());
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
const AABox& AABox::zero() {
|
||||
static const AABox b = AABox(Vector3::zero(), Vector3::zero());
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
void AABox::serialize(class BinaryOutput& b) const {
|
||||
b.writeVector3(lo);
|
||||
b.writeVector3(hi);
|
||||
}
|
||||
|
||||
|
||||
void AABox::deserialize(class BinaryInput& b) {
|
||||
lo = b.readVector3();
|
||||
hi = b.readVector3();
|
||||
}
|
||||
|
||||
|
||||
void AABox::split(const Vector3::Axis& axis, float location, AABox& low, AABox& high) const {
|
||||
// Low, medium, and high along the chosen axis
|
||||
float L = G3D::min(location, lo[axis]);
|
||||
float M = G3D::min(G3D::max(location, lo[axis]), hi[axis]);
|
||||
float H = G3D::max(location, hi[axis]);
|
||||
|
||||
// Copy over this box.
|
||||
high = low = *this;
|
||||
|
||||
// Now move the split points along the special axis
|
||||
low.lo[axis] = L;
|
||||
low.hi[axis] = M;
|
||||
high.lo[axis] = M;
|
||||
high.hi[axis] = H;
|
||||
}
|
||||
|
||||
|
||||
Vector3 AABox::randomSurfacePoint() const {
|
||||
Vector3 extent = hi - lo;
|
||||
float aXY = extent.x * extent.y;
|
||||
float aYZ = extent.y * extent.z;
|
||||
float aZX = extent.z * extent.x;
|
||||
|
||||
float r = (float)uniformRandom(0.0f, aXY + aYZ + aZX);
|
||||
|
||||
// Choose evenly between positive and negative face planes
|
||||
float d = ((float)uniformRandom(0, 1) < 0.5f) ? 0.0f : 1.0f;
|
||||
|
||||
// The probability of choosing a given face is proportional to
|
||||
// its area.
|
||||
if (r < aXY) {
|
||||
return
|
||||
lo +
|
||||
Vector3(
|
||||
(float)uniformRandom(0.0f, extent.x),
|
||||
(float)uniformRandom(0.0f, extent.y),
|
||||
d * extent.z);
|
||||
} else if (r < aYZ) {
|
||||
return
|
||||
lo +
|
||||
Vector3(
|
||||
d * extent.x,
|
||||
(float)uniformRandom(0, extent.y),
|
||||
(float)uniformRandom(0, extent.z));
|
||||
} else {
|
||||
return
|
||||
lo +
|
||||
Vector3(
|
||||
(float)uniformRandom(0, extent.x),
|
||||
d * extent.y,
|
||||
(float)uniformRandom(0, extent.z));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector3 AABox::randomInteriorPoint() const {
|
||||
return Vector3(
|
||||
(float)uniformRandom(lo.x, hi.x),
|
||||
(float)uniformRandom(lo.y, hi.y),
|
||||
(float)uniformRandom(lo.z, hi.z));
|
||||
}
|
||||
|
||||
|
||||
bool AABox::intersects(const AABox& other) const {
|
||||
// Must be overlap along all three axes.
|
||||
// Try to find a separating axis.
|
||||
|
||||
for (int a = 0; a < 3; ++a) {
|
||||
|
||||
// |--------|
|
||||
// |------|
|
||||
|
||||
if ((lo[a] > other.hi[a]) ||
|
||||
(hi[a] < other.lo[a])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int AABox::dummy = 0;
|
||||
|
||||
bool AABox::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask,
|
||||
uint32& childMask) const {
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(plane.size() < 31);
|
||||
|
||||
childMask = 0;
|
||||
|
||||
const bool finite =
|
||||
(abs(lo.x) < G3D::finf()) &&
|
||||
(abs(hi.x) < G3D::finf()) &&
|
||||
(abs(lo.y) < G3D::finf()) &&
|
||||
(abs(hi.y) < G3D::finf()) &&
|
||||
(abs(lo.z) < G3D::finf()) &&
|
||||
(abs(hi.z) < G3D::finf());
|
||||
|
||||
// See if there is one plane for which all of the
|
||||
// vertices are in the negative half space.
|
||||
for (int p = 0; p < plane.size(); ++p) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
|
||||
Vector3 corner;
|
||||
|
||||
int numContained = 0;
|
||||
int v = 0;
|
||||
|
||||
// We can early-out only if we have found one point on each
|
||||
// side of the plane (i.e. if we are straddling). That
|
||||
// occurs when (numContained < v) && (numContained > 0)
|
||||
for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) {
|
||||
// Unrolling these 3 if's into a switch decreases performance
|
||||
// by about 2x
|
||||
corner.x = (v & 1) ? hi.x : lo.x;
|
||||
corner.y = (v & 2) ? hi.y : lo.y;
|
||||
corner.z = (v & 4) ? hi.z : lo.z;
|
||||
|
||||
if (finite) { // this branch is highly predictable
|
||||
if (plane[p].halfSpaceContainsFinite(corner)) {
|
||||
++numContained;
|
||||
}
|
||||
} else {
|
||||
if (plane[p].halfSpaceContains(corner)) {
|
||||
++numContained;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numContained == 0) {
|
||||
// Plane p culled the box
|
||||
cullingPlane = p;
|
||||
|
||||
// The caller should not recurse into the children,
|
||||
// since the parent is culled. If they do recurse,
|
||||
// make them only test against this one plane, which
|
||||
// will immediately cull the volume.
|
||||
childMask = 1 << p;
|
||||
return true;
|
||||
|
||||
} else if (numContained < v) {
|
||||
// The bounding volume straddled the plane; we have
|
||||
// to keep testing against this plane
|
||||
childMask |= (1 << p);
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next bit.
|
||||
inMask = inMask >> 1;
|
||||
}
|
||||
|
||||
// None of the planes could cull this box
|
||||
cullingPlane = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool AABox::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask) const {
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(plane.size() < 31);
|
||||
|
||||
const bool finite =
|
||||
(abs(lo.x) < G3D::finf()) &&
|
||||
(abs(hi.x) < G3D::finf()) &&
|
||||
(abs(lo.y) < G3D::finf()) &&
|
||||
(abs(hi.y) < G3D::finf()) &&
|
||||
(abs(lo.z) < G3D::finf()) &&
|
||||
(abs(hi.z) < G3D::finf());
|
||||
|
||||
// See if there is one plane for which all of the
|
||||
// vertices are in the negative half space.
|
||||
for (int p = 0; p < plane.size(); ++p) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
|
||||
bool culled = true;
|
||||
Vector3 corner;
|
||||
|
||||
int v;
|
||||
|
||||
// Assume this plane culls all points. See if there is a point
|
||||
// not culled by the plane... early out when at least one point
|
||||
// is in the positive half space.
|
||||
for (v = 0; (v < 8) && culled; ++v) {
|
||||
|
||||
// Unrolling these 3 if's into a switch decreases performance
|
||||
// by about 2x
|
||||
corner.x = (v & 1) ? hi.x : lo.x;
|
||||
corner.y = (v & 2) ? hi.y : lo.y;
|
||||
corner.z = (v & 4) ? hi.z : lo.z;
|
||||
|
||||
if (finite) { // this branch is highly predictable
|
||||
culled = ! plane[p].halfSpaceContainsFinite(corner);
|
||||
} else {
|
||||
culled = ! plane[p].halfSpaceContains(corner);
|
||||
}
|
||||
}
|
||||
|
||||
if (culled) {
|
||||
// Plane p culled the box
|
||||
cullingPlane = p;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next bit.
|
||||
inMask = inMask >> 1;
|
||||
}
|
||||
|
||||
// None of the planes could cull this box
|
||||
cullingPlane = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
void AABox::getBounds(Sphere& s) const {
|
||||
s.center = center();
|
||||
s.radius = extent().length() / 2;
|
||||
}
|
||||
|
||||
bool AABox::intersects(const class Sphere& sphere) const {
|
||||
double d = 0;
|
||||
|
||||
//find the square of the distance
|
||||
//from the sphere to the box
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (sphere.center[i] < lo[i]) {
|
||||
d += square(sphere.center[i] - lo[i]);
|
||||
} else if (sphere.center[i] > hi[i]) {
|
||||
d += square(sphere.center[i] - hi[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return d <= square(sphere.radius);
|
||||
}
|
||||
|
||||
Vector3 AABox::corner(int index) const {
|
||||
|
||||
// default constructor inits all components to 0
|
||||
Vector3 v;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
v.x = lo.x;
|
||||
v.y = lo.y;
|
||||
v.z = hi.z;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
v.x = hi.x;
|
||||
v.y = lo.y;
|
||||
v.z = hi.z;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
v.x = hi.x;
|
||||
v.y = hi.y;
|
||||
v.z = hi.z;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
v.x = lo.x;
|
||||
v.y = hi.y;
|
||||
v.z = hi.z;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
v.x = lo.x;
|
||||
v.y = lo.y;
|
||||
v.z = lo.z;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
v.x = hi.x;
|
||||
v.y = lo.y;
|
||||
v.z = lo.z;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
v.x = hi.x;
|
||||
v.y = hi.y;
|
||||
v.z = lo.z;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
v.x = lo.x;
|
||||
v.y = hi.y;
|
||||
v.z = lo.z;
|
||||
break;
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Invalid corner index");
|
||||
break;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
1350
modules/acore/deps/g3dlite/source/Any.cpp
Normal file
1350
modules/acore/deps/g3dlite/source/Any.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1379
modules/acore/deps/g3dlite/source/AnyVal.cpp
Normal file
1379
modules/acore/deps/g3dlite/source/AnyVal.cpp
Normal file
File diff suppressed because it is too large
Load Diff
87
modules/acore/deps/g3dlite/source/AreaMemoryManager.cpp
Normal file
87
modules/acore/deps/g3dlite/source/AreaMemoryManager.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
@file AreaMemoryManager.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2009-01-20
|
||||
@edited 2009-01-20
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/AreaMemoryManager.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
AreaMemoryManager::Buffer::Buffer(size_t size) : m_size(size), m_used(0) {
|
||||
// Allocate space for a lot of buffers.
|
||||
m_first = (uint8*)::malloc(m_size);
|
||||
}
|
||||
|
||||
|
||||
AreaMemoryManager::Buffer::~Buffer() {
|
||||
::free(m_first);
|
||||
}
|
||||
|
||||
|
||||
void* AreaMemoryManager::Buffer::alloc(size_t s) {
|
||||
if (s + m_used > m_size) {
|
||||
return NULL;
|
||||
} else {
|
||||
void* old = m_first + m_used;
|
||||
m_used += s;
|
||||
return old;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AreaMemoryManager::isThreadsafe() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
AreaMemoryManager::Ref AreaMemoryManager::create(size_t sizeHint) {
|
||||
return new AreaMemoryManager(sizeHint);
|
||||
}
|
||||
|
||||
|
||||
AreaMemoryManager::AreaMemoryManager(size_t sizeHint) : m_sizeHint(sizeHint) {
|
||||
debugAssert(sizeHint > 0);
|
||||
}
|
||||
|
||||
|
||||
AreaMemoryManager::~AreaMemoryManager() {
|
||||
deallocateAll();
|
||||
}
|
||||
|
||||
|
||||
size_t AreaMemoryManager::bytesAllocated() const {
|
||||
return m_sizeHint * m_bufferArray.size();
|
||||
}
|
||||
|
||||
|
||||
void* AreaMemoryManager::alloc(size_t s) {
|
||||
void* n = (m_bufferArray.size() > 0) ? m_bufferArray.last()->alloc(s) : NULL;
|
||||
if (n == NULL) {
|
||||
// This buffer is full
|
||||
m_bufferArray.append(new Buffer(max(s, m_sizeHint)));
|
||||
return m_bufferArray.last()->alloc(s);
|
||||
} else {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AreaMemoryManager::free(void* x) {
|
||||
// Intentionally empty; we block deallocate
|
||||
}
|
||||
|
||||
|
||||
void AreaMemoryManager::deallocateAll() {
|
||||
m_bufferArray.deleteAll();
|
||||
m_bufferArray.clear();
|
||||
}
|
||||
|
||||
}
|
||||
81
modules/acore/deps/g3dlite/source/BinaryFormat.cpp
Normal file
81
modules/acore/deps/g3dlite/source/BinaryFormat.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
@file BinaryFormat.cpp
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2005-06-10
|
||||
@edited 2005-06-10
|
||||
*/
|
||||
|
||||
#include "G3D/BinaryFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
int32 byteSize(BinaryFormat f) {
|
||||
switch (f) {
|
||||
case BOOL8_BINFMT:
|
||||
case UINT8_BINFMT:
|
||||
case INT8_BINFMT:
|
||||
return 1;
|
||||
|
||||
case UINT16_BINFMT:
|
||||
case INT16_BINFMT:
|
||||
return 2;
|
||||
|
||||
case FLOAT16_BINFMT:
|
||||
return 2;
|
||||
|
||||
case UINT32_BINFMT:
|
||||
case INT32_BINFMT:
|
||||
case FLOAT32_BINFMT:
|
||||
return 4;
|
||||
|
||||
case FLOAT64_BINFMT:
|
||||
case UINT64_BINFMT:
|
||||
case INT64_BINFMT:
|
||||
return 8;
|
||||
|
||||
case INT128_BINFMT:
|
||||
case UINT128_BINFMT:
|
||||
return 16;
|
||||
|
||||
case VECTOR2_BINFMT:
|
||||
return 2 * 4;
|
||||
|
||||
case VECTOR2INT16_BINFMT:
|
||||
return 2 * 2;
|
||||
|
||||
case VECTOR3_BINFMT:
|
||||
return 3 * 4;
|
||||
|
||||
case VECTOR3INT16_BINFMT:
|
||||
return 3 * 2;
|
||||
|
||||
case VECTOR4_BINFMT:
|
||||
return 4 * 4;
|
||||
|
||||
case VECTOR4INT16_BINFMT:
|
||||
return 4 * 4;
|
||||
|
||||
case COLOR3_BINFMT:
|
||||
return 3 * 4;
|
||||
|
||||
case COLOR3UINT8_BINFMT:
|
||||
return 3 * 1;
|
||||
|
||||
case COLOR3INT16_BINFMT:
|
||||
return 3 * 2;
|
||||
|
||||
case COLOR4_BINFMT:
|
||||
return 4 * 4;
|
||||
|
||||
case COLOR4UINT8_BINFMT:
|
||||
return 4 * 1;
|
||||
|
||||
case COLOR4INT16_BINFMT:
|
||||
return 4 * 2;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
621
modules/acore/deps/g3dlite/source/BinaryInput.cpp
Normal file
621
modules/acore/deps/g3dlite/source/BinaryInput.cpp
Normal file
@@ -0,0 +1,621 @@
|
||||
/**
|
||||
@file BinaryInput.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
Copyright 2001-2007, Morgan McGuire. All rights reserved.
|
||||
|
||||
@created 2001-08-09
|
||||
@edited 2010-03-05
|
||||
|
||||
|
||||
<PRE>
|
||||
{
|
||||
BinaryOutput b("c:/tmp/test.b", BinaryOutput::LITTLE_ENDIAN);
|
||||
|
||||
float f = 3.1415926;
|
||||
int i = 1027221;
|
||||
std::string s = "Hello World!";
|
||||
|
||||
b.writeFloat32(f);
|
||||
b.writeInt32(i);
|
||||
b.writeString(s);
|
||||
b.commit();
|
||||
|
||||
|
||||
BinaryInput in("c:/tmp/test.b", BinaryInput::LITTLE_ENDIAN);
|
||||
|
||||
debugAssert(f == in.readFloat32());
|
||||
int ii = in.readInt32();
|
||||
debugAssert(i == ii);
|
||||
debugAssert(s == in.readString());
|
||||
}
|
||||
</PRE>
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/Array.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/Log.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
#include <zlib.h>
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
#include "zip.h"
|
||||
#endif
|
||||
#include <cstring>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void BinaryInput::readBool8(std::vector<bool>& out, int64 n) {
|
||||
out.resize((int)n);
|
||||
// std::vector optimizes bool in a way that prevents fast reading
|
||||
for (int64 i = 0; i < n ; ++i) {
|
||||
out[i] = readBool8();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BinaryInput::readBool8(Array<bool>& out, int64 n) {
|
||||
out.resize(n);
|
||||
readBool8(out.begin(), n);
|
||||
}
|
||||
|
||||
|
||||
#define IMPLEMENT_READER(ucase, lcase)\
|
||||
void BinaryInput::read##ucase(std::vector<lcase>& out, int64 n) {\
|
||||
out.resize(n);\
|
||||
read##ucase(&out[0], n);\
|
||||
}\
|
||||
\
|
||||
\
|
||||
void BinaryInput::read##ucase(Array<lcase>& out, int64 n) {\
|
||||
out.resize(n);\
|
||||
read##ucase(out.begin(), n);\
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_READER(UInt8, uint8)
|
||||
IMPLEMENT_READER(Int8, int8)
|
||||
IMPLEMENT_READER(UInt16, uint16)
|
||||
IMPLEMENT_READER(Int16, int16)
|
||||
IMPLEMENT_READER(UInt32, uint32)
|
||||
IMPLEMENT_READER(Int32, int32)
|
||||
IMPLEMENT_READER(UInt64, uint64)
|
||||
IMPLEMENT_READER(Int64, int64)
|
||||
IMPLEMENT_READER(Float32, float32)
|
||||
IMPLEMENT_READER(Float64, float64)
|
||||
|
||||
#undef IMPLEMENT_READER
|
||||
|
||||
// Data structures that are one byte per element can be
|
||||
// directly copied, regardles of endian-ness.
|
||||
#define IMPLEMENT_READER(ucase, lcase)\
|
||||
void BinaryInput::read##ucase(lcase* out, int64 n) {\
|
||||
if (sizeof(lcase) == 1) {\
|
||||
readBytes(out, n);\
|
||||
} else {\
|
||||
for (int64 i = 0; i < n ; ++i) {\
|
||||
out[i] = read##ucase();\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
|
||||
IMPLEMENT_READER(Bool8, bool)
|
||||
IMPLEMENT_READER(UInt8, uint8)
|
||||
IMPLEMENT_READER(Int8, int8)
|
||||
|
||||
#undef IMPLEMENT_READER
|
||||
|
||||
|
||||
#define IMPLEMENT_READER(ucase, lcase)\
|
||||
void BinaryInput::read##ucase(lcase* out, int64 n) {\
|
||||
if (m_swapBytes) {\
|
||||
for (int64 i = 0; i < n; ++i) {\
|
||||
out[i] = read##ucase();\
|
||||
}\
|
||||
} else {\
|
||||
readBytes(out, sizeof(lcase) * n);\
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_READER(UInt16, uint16)
|
||||
IMPLEMENT_READER(Int16, int16)
|
||||
IMPLEMENT_READER(UInt32, uint32)
|
||||
IMPLEMENT_READER(Int32, int32)
|
||||
IMPLEMENT_READER(UInt64, uint64)
|
||||
IMPLEMENT_READER(Int64, int64)
|
||||
IMPLEMENT_READER(Float32, float32)
|
||||
IMPLEMENT_READER(Float64, float64)
|
||||
|
||||
#undef IMPLEMENT_READER
|
||||
|
||||
void BinaryInput::loadIntoMemory(int64 startPosition, int64 minLength) {
|
||||
// Load the next section of the file
|
||||
debugAssertM(m_filename != "<memory>", "Read past end of file.");
|
||||
|
||||
int64 absPos = m_alreadyRead + m_pos;
|
||||
|
||||
if (m_bufferLength < minLength) {
|
||||
// The current buffer isn't big enough to hold the chunk we want to read.
|
||||
// This happens if there was little memory available during the initial constructor
|
||||
// read but more memory has since been freed.
|
||||
m_bufferLength = minLength;
|
||||
debugAssert(m_freeBuffer);
|
||||
m_buffer = (uint8*)System::realloc(m_buffer, m_bufferLength);
|
||||
if (m_buffer == NULL) {
|
||||
throw "Tried to read a larger memory chunk than could fit in memory. (2)";
|
||||
}
|
||||
}
|
||||
|
||||
m_alreadyRead = startPosition;
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
FILE* file = fopen(m_filename.c_str(), "rb");
|
||||
debugAssert(file);
|
||||
int ret = fseek(file, (off_t)m_alreadyRead, SEEK_SET);
|
||||
debugAssert(ret == 0);
|
||||
size_t toRead = (size_t)G3D::min(m_bufferLength, m_length - m_alreadyRead);
|
||||
ret = fread(m_buffer, 1, toRead, file);
|
||||
debugAssert(ret == toRead);
|
||||
fclose(file);
|
||||
file = NULL;
|
||||
|
||||
# else
|
||||
FILE* file = fopen(m_filename.c_str(), "rb");
|
||||
debugAssert(file);
|
||||
int ret = fseeko(file, (off_t)m_alreadyRead, SEEK_SET);
|
||||
debugAssert(ret == 0);
|
||||
size_t toRead = (size_t)G3D::min<int64>(m_bufferLength, m_length - m_alreadyRead);
|
||||
ret = fread(m_buffer, 1, toRead, file);
|
||||
debugAssert((size_t)ret == (size_t)toRead);
|
||||
fclose(file);
|
||||
file = NULL;
|
||||
# endif
|
||||
|
||||
m_pos = absPos - m_alreadyRead;
|
||||
debugAssert(m_pos >= 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const bool BinaryInput::NO_COPY = false;
|
||||
|
||||
static bool needSwapBytes(G3DEndian fileEndian) {
|
||||
return (fileEndian != System::machineEndian());
|
||||
}
|
||||
|
||||
|
||||
/** Helper used by the constructors for decompression */
|
||||
static uint32 readUInt32(const uint8* data, bool swapBytes) {
|
||||
if (swapBytes) {
|
||||
uint8 out[4];
|
||||
out[0] = data[3];
|
||||
out[1] = data[2];
|
||||
out[2] = data[1];
|
||||
out[3] = data[0];
|
||||
return *((uint32*)out);
|
||||
} else {
|
||||
return *((uint32*)data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BinaryInput::setEndian(G3DEndian e) {
|
||||
m_fileEndian = e;
|
||||
m_swapBytes = needSwapBytes(m_fileEndian);
|
||||
}
|
||||
|
||||
|
||||
BinaryInput::BinaryInput(
|
||||
const uint8* data,
|
||||
int64 dataLen,
|
||||
G3DEndian dataEndian,
|
||||
bool compressed,
|
||||
bool copyMemory) :
|
||||
m_filename("<memory>"),
|
||||
m_bitPos(0),
|
||||
m_bitString(0),
|
||||
m_beginEndBits(0),
|
||||
m_alreadyRead(0),
|
||||
m_bufferLength(0),
|
||||
m_pos(0) {
|
||||
|
||||
m_freeBuffer = copyMemory || compressed;
|
||||
|
||||
setEndian(dataEndian);
|
||||
|
||||
if (compressed) {
|
||||
// Read the decompressed size from the first 4 bytes
|
||||
m_length = G3D::readUInt32(data, m_swapBytes);
|
||||
|
||||
debugAssert(m_freeBuffer);
|
||||
m_buffer = (uint8*)System::alignedMalloc(m_length, 16);
|
||||
|
||||
unsigned long L = m_length;
|
||||
// Decompress with zlib
|
||||
int64 result = uncompress(m_buffer, (unsigned long*)&L, data + 4, dataLen - 4);
|
||||
m_length = L;
|
||||
m_bufferLength = L;
|
||||
debugAssert(result == Z_OK); (void)result;
|
||||
|
||||
} else {
|
||||
m_length = dataLen;
|
||||
m_bufferLength = m_length;
|
||||
if (! copyMemory) {
|
||||
debugAssert(!m_freeBuffer);
|
||||
m_buffer = const_cast<uint8*>(data);
|
||||
} else {
|
||||
debugAssert(m_freeBuffer);
|
||||
m_buffer = (uint8*)System::alignedMalloc(m_length, 16);
|
||||
System::memcpy(m_buffer, data, dataLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BinaryInput::BinaryInput(
|
||||
const std::string& filename,
|
||||
G3DEndian fileEndian,
|
||||
bool compressed) :
|
||||
m_filename(filename),
|
||||
m_bitPos(0),
|
||||
m_bitString(0),
|
||||
m_beginEndBits(0),
|
||||
m_alreadyRead(0),
|
||||
m_length(0),
|
||||
m_bufferLength(0),
|
||||
m_buffer(NULL),
|
||||
m_pos(0),
|
||||
m_freeBuffer(true) {
|
||||
|
||||
setEndian(fileEndian);
|
||||
|
||||
// Update global file tracker
|
||||
_internal::currentFilesUsed.insert(m_filename);
|
||||
|
||||
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
std::string zipfile;
|
||||
if (FileSystem::inZipfile(m_filename, zipfile)) {
|
||||
// Load from zipfile
|
||||
// zipRead(filename, v, s);
|
||||
|
||||
std::string internalFile = m_filename.substr(zipfile.length() + 1);
|
||||
struct zip* z = zip_open(zipfile.c_str(), ZIP_CHECKCONS, NULL);
|
||||
{
|
||||
struct zip_stat info;
|
||||
zip_stat_init( &info ); // TODO: Docs unclear if zip_stat_init is required.
|
||||
zip_stat(z, internalFile.c_str(), ZIP_FL_NOCASE, &info);
|
||||
m_bufferLength = m_length = info.size;
|
||||
// sets machines up to use MMX, if they want
|
||||
m_buffer = reinterpret_cast<uint8*>(System::alignedMalloc(m_length, 16));
|
||||
struct zip_file* zf = zip_fopen( z, internalFile.c_str(), ZIP_FL_NOCASE );
|
||||
{
|
||||
int64 test = zip_fread( zf, m_buffer, m_length );
|
||||
debugAssertM(test == m_length,
|
||||
internalFile + " was corrupt because it unzipped to the wrong size.");
|
||||
(void)test;
|
||||
}
|
||||
zip_fclose( zf );
|
||||
}
|
||||
zip_close( z );
|
||||
|
||||
if (compressed) {
|
||||
decompress();
|
||||
}
|
||||
m_freeBuffer = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Figure out how big the file is and verify that it exists.
|
||||
m_length = FileSystem::size(m_filename);
|
||||
|
||||
// Read the file into memory
|
||||
FILE* file = fopen(m_filename.c_str(), "rb");
|
||||
|
||||
if (! file || (m_length == -1)) {
|
||||
throw format("File not found: \"%s\"", m_filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (! compressed && (m_length > INITIAL_BUFFER_LENGTH)) {
|
||||
// Read only a subset of the file so we don't consume
|
||||
// all available memory.
|
||||
m_bufferLength = INITIAL_BUFFER_LENGTH;
|
||||
} else {
|
||||
// Either the length is fine or the file is compressed
|
||||
// and requires us to read the whole thing for zlib.
|
||||
m_bufferLength = m_length;
|
||||
}
|
||||
|
||||
debugAssert(m_freeBuffer);
|
||||
m_buffer = (uint8*)System::alignedMalloc(m_bufferLength, 16);
|
||||
if (m_buffer == NULL) {
|
||||
if (compressed) {
|
||||
throw "Not enough memory to load compressed file. (1)";
|
||||
}
|
||||
|
||||
// Try to allocate a small array; not much memory is available.
|
||||
// Give up if we can't allocate even 1k.
|
||||
while ((m_buffer == NULL) && (m_bufferLength > 1024)) {
|
||||
m_bufferLength /= 2;
|
||||
m_buffer = (uint8*)System::alignedMalloc(m_bufferLength, 16);
|
||||
}
|
||||
}
|
||||
debugAssert(m_buffer);
|
||||
|
||||
fread(m_buffer, m_bufferLength, sizeof(int8), file);
|
||||
fclose(file);
|
||||
file = NULL;
|
||||
|
||||
if (compressed) {
|
||||
if (m_bufferLength != m_length) {
|
||||
throw "Not enough memory to load compressed file. (2)";
|
||||
}
|
||||
|
||||
decompress();
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryInput::decompress() {
|
||||
// Decompress
|
||||
// Use the existing buffer as the source, allocate
|
||||
// a new buffer to use as the destination.
|
||||
|
||||
int64 tempLength = m_length;
|
||||
m_length = G3D::readUInt32(m_buffer, m_swapBytes);
|
||||
|
||||
// The file couldn't have better than 500:1 compression
|
||||
alwaysAssertM(m_length < m_bufferLength * 500, "Compressed file header is corrupted");
|
||||
|
||||
uint8* tempBuffer = m_buffer;
|
||||
m_buffer = (uint8*)System::alignedMalloc(m_length, 16);
|
||||
|
||||
debugAssert(m_buffer);
|
||||
debugAssert(isValidHeapPointer(tempBuffer));
|
||||
debugAssert(isValidHeapPointer(m_buffer));
|
||||
|
||||
unsigned long L = m_length;
|
||||
int64 result = uncompress(m_buffer, &L, tempBuffer + 4, tempLength - 4);
|
||||
m_length = L;
|
||||
m_bufferLength = m_length;
|
||||
|
||||
debugAssertM(result == Z_OK, "BinaryInput/zlib detected corruption in " + m_filename);
|
||||
(void)result;
|
||||
|
||||
System::alignedFree(tempBuffer);
|
||||
}
|
||||
|
||||
|
||||
void BinaryInput::readBytes(void* bytes, int64 n) {
|
||||
prepareToRead(n);
|
||||
debugAssert(isValidPointer(bytes));
|
||||
|
||||
memcpy(bytes, m_buffer + m_pos, n);
|
||||
m_pos += n;
|
||||
}
|
||||
|
||||
|
||||
BinaryInput::~BinaryInput() {
|
||||
|
||||
if (m_freeBuffer) {
|
||||
System::alignedFree(m_buffer);
|
||||
}
|
||||
m_buffer = NULL;
|
||||
}
|
||||
|
||||
|
||||
uint64 BinaryInput::readUInt64() {
|
||||
prepareToRead(8);
|
||||
uint8 out[8];
|
||||
|
||||
if (m_swapBytes) {
|
||||
out[0] = m_buffer[m_pos + 7];
|
||||
out[1] = m_buffer[m_pos + 6];
|
||||
out[2] = m_buffer[m_pos + 5];
|
||||
out[3] = m_buffer[m_pos + 4];
|
||||
out[4] = m_buffer[m_pos + 3];
|
||||
out[5] = m_buffer[m_pos + 2];
|
||||
out[6] = m_buffer[m_pos + 1];
|
||||
out[7] = m_buffer[m_pos + 0];
|
||||
} else {
|
||||
*(uint64*)out = *(uint64*)(m_buffer + m_pos);
|
||||
}
|
||||
|
||||
m_pos += 8;
|
||||
return *(uint64*)out;
|
||||
}
|
||||
|
||||
|
||||
std::string BinaryInput::readString(int64 n) {
|
||||
prepareToRead(n);
|
||||
debugAssertM((m_pos + n) <= m_length, "Read past end of file");
|
||||
|
||||
char *s = (char*)System::alignedMalloc(n + 1, 16);
|
||||
assert(s != NULL);
|
||||
|
||||
memcpy(s, m_buffer + m_pos, n);
|
||||
// There may not be a null, so make sure
|
||||
// we add one.
|
||||
s[n] = '\0';
|
||||
|
||||
std::string out = s;
|
||||
System::alignedFree(s);
|
||||
s = NULL;
|
||||
|
||||
m_pos += n;
|
||||
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::string BinaryInput::readString() {
|
||||
int64 n = 0;
|
||||
|
||||
if ((m_pos + m_alreadyRead + n) < (m_length - 1)) {
|
||||
prepareToRead(1);
|
||||
}
|
||||
|
||||
if ( ((m_pos + m_alreadyRead + n) < (m_length - 1)) &&
|
||||
(m_buffer[m_pos + n] != '\0')) {
|
||||
|
||||
++n;
|
||||
while ( ((m_pos + m_alreadyRead + n) < (m_length - 1)) &&
|
||||
(m_buffer[m_pos + n] != '\0')) {
|
||||
|
||||
prepareToRead(1);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
// Consume NULL
|
||||
++n;
|
||||
|
||||
return readString(n);
|
||||
}
|
||||
|
||||
static bool isNewline(char c) {
|
||||
return c == '\n' || c == '\r';
|
||||
}
|
||||
|
||||
std::string BinaryInput::readStringNewline() {
|
||||
int64 n = 0;
|
||||
|
||||
if ((m_pos + m_alreadyRead + n) < (m_length - 1)) {
|
||||
prepareToRead(1);
|
||||
}
|
||||
|
||||
if ( ((m_pos + m_alreadyRead + n) < (m_length - 1)) &&
|
||||
! isNewline(m_buffer[m_pos + n])) {
|
||||
|
||||
++n;
|
||||
while ( ((m_pos + m_alreadyRead + n) < (m_length - 1)) &&
|
||||
! isNewline(m_buffer[m_pos + n])) {
|
||||
|
||||
prepareToRead(1);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string s = readString(n);
|
||||
|
||||
// Consume the newline
|
||||
char firstNLChar = readUInt8();
|
||||
|
||||
// Consume the 2nd newline
|
||||
if (isNewline(m_buffer[m_pos + 1]) && (m_buffer[m_pos + 1] != firstNLChar)) {
|
||||
readUInt8();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
std::string BinaryInput::readStringEven() {
|
||||
std::string x = readString();
|
||||
if (hasMore() && (G3D::isOdd(x.length() + 1))) {
|
||||
skip(1);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
std::string BinaryInput::readString32() {
|
||||
int len = readUInt32();
|
||||
return readString(len);
|
||||
}
|
||||
|
||||
|
||||
Vector4 BinaryInput::readVector4() {
|
||||
float x = readFloat32();
|
||||
float y = readFloat32();
|
||||
float z = readFloat32();
|
||||
float w = readFloat32();
|
||||
return Vector4(x, y, z, w);
|
||||
}
|
||||
|
||||
|
||||
Vector3 BinaryInput::readVector3() {
|
||||
float x = readFloat32();
|
||||
float y = readFloat32();
|
||||
float z = readFloat32();
|
||||
return Vector3(x, y, z);
|
||||
}
|
||||
|
||||
|
||||
Vector2 BinaryInput::readVector2() {
|
||||
float x = readFloat32();
|
||||
float y = readFloat32();
|
||||
return Vector2(x, y);
|
||||
}
|
||||
|
||||
|
||||
Color4 BinaryInput::readColor4() {
|
||||
float r = readFloat32();
|
||||
float g = readFloat32();
|
||||
float b = readFloat32();
|
||||
float a = readFloat32();
|
||||
return Color4(r, g, b, a);
|
||||
}
|
||||
|
||||
|
||||
Color3 BinaryInput::readColor3() {
|
||||
float r = readFloat32();
|
||||
float g = readFloat32();
|
||||
float b = readFloat32();
|
||||
return Color3(r, g, b);
|
||||
}
|
||||
|
||||
|
||||
void BinaryInput::beginBits() {
|
||||
debugAssert(m_beginEndBits == 0);
|
||||
m_beginEndBits = 1;
|
||||
m_bitPos = 0;
|
||||
|
||||
debugAssertM(hasMore(), "Can't call beginBits when at the end of a file");
|
||||
m_bitString = readUInt8();
|
||||
}
|
||||
|
||||
|
||||
uint32 BinaryInput::readBits(int numBits) {
|
||||
debugAssert(m_beginEndBits == 1);
|
||||
|
||||
uint32 out = 0;
|
||||
|
||||
const int total = numBits;
|
||||
while (numBits > 0) {
|
||||
if (m_bitPos > 7) {
|
||||
// Consume a new byte for reading. We do this at the beginning
|
||||
// of the loop so that we don't try to read past the end of the file.
|
||||
m_bitPos = 0;
|
||||
m_bitString = readUInt8();
|
||||
}
|
||||
|
||||
// Slide the lowest bit of the bitString into
|
||||
// the correct position.
|
||||
out |= (m_bitString & 1) << (total - numBits);
|
||||
|
||||
// Shift over to the next bit
|
||||
m_bitString = m_bitString >> 1;
|
||||
++m_bitPos;
|
||||
--numBits;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void BinaryInput::endBits() {
|
||||
debugAssert(m_beginEndBits == 1);
|
||||
if (m_bitPos == 0) {
|
||||
// Put back the last byte we read
|
||||
--m_pos;
|
||||
}
|
||||
m_beginEndBits = 0;
|
||||
m_bitPos = 0;
|
||||
}
|
||||
|
||||
}
|
||||
534
modules/acore/deps/g3dlite/source/BinaryOutput.cpp
Normal file
534
modules/acore/deps/g3dlite/source/BinaryOutput.cpp
Normal file
@@ -0,0 +1,534 @@
|
||||
/**
|
||||
@file BinaryOutput.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
Copyright 2002-2010, Morgan McGuire, All rights reserved.
|
||||
|
||||
@created 2002-02-20
|
||||
@edited 2010-03-17
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/Array.h"
|
||||
#include <zlib.h>
|
||||
#include "G3D/Log.h"
|
||||
#include <cstring>
|
||||
|
||||
#ifdef G3D_LINUX
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
// Largest memory buffer that the system will use for writing to
|
||||
// disk. After this (or if the system runs out of memory)
|
||||
// chunks of the file will be dumped to disk.
|
||||
//
|
||||
// Currently 400 MB
|
||||
#define MAX_BINARYOUTPUT_BUFFER_SIZE 400000000
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void BinaryOutput::writeBool8(const std::vector<bool>& out, int n) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
writeBool8(out[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeBool8(const Array<bool>& out, int n) {
|
||||
writeBool8(out.getCArray(), n);
|
||||
}
|
||||
|
||||
#define IMPLEMENT_WRITER(ucase, lcase)\
|
||||
void BinaryOutput::write##ucase(const std::vector<lcase>& out, int n) {\
|
||||
write##ucase(&out[0], n);\
|
||||
}\
|
||||
\
|
||||
\
|
||||
void BinaryOutput::write##ucase(const Array<lcase>& out, int n) {\
|
||||
write##ucase(out.getCArray(), n);\
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_WRITER(UInt8, uint8)
|
||||
IMPLEMENT_WRITER(Int8, int8)
|
||||
IMPLEMENT_WRITER(UInt16, uint16)
|
||||
IMPLEMENT_WRITER(Int16, int16)
|
||||
IMPLEMENT_WRITER(UInt32, uint32)
|
||||
IMPLEMENT_WRITER(Int32, int32)
|
||||
IMPLEMENT_WRITER(UInt64, uint64)
|
||||
IMPLEMENT_WRITER(Int64, int64)
|
||||
IMPLEMENT_WRITER(Float32, float32)
|
||||
IMPLEMENT_WRITER(Float64, float64)
|
||||
|
||||
#undef IMPLEMENT_WRITER
|
||||
|
||||
// Data structures that are one byte per element can be
|
||||
// directly copied, regardles of endian-ness.
|
||||
#define IMPLEMENT_WRITER(ucase, lcase)\
|
||||
void BinaryOutput::write##ucase(const lcase* out, int n) {\
|
||||
if (sizeof(lcase) == 1) {\
|
||||
writeBytes((void*)out, n);\
|
||||
} else {\
|
||||
for (int i = 0; i < n ; ++i) {\
|
||||
write##ucase(out[i]);\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
|
||||
IMPLEMENT_WRITER(Bool8, bool)
|
||||
IMPLEMENT_WRITER(UInt8, uint8)
|
||||
IMPLEMENT_WRITER(Int8, int8)
|
||||
|
||||
#undef IMPLEMENT_WRITER
|
||||
|
||||
|
||||
#define IMPLEMENT_WRITER(ucase, lcase)\
|
||||
void BinaryOutput::write##ucase(const lcase* out, int n) {\
|
||||
if (m_swapBytes) {\
|
||||
for (int i = 0; i < n; ++i) {\
|
||||
write##ucase(out[i]);\
|
||||
}\
|
||||
} else {\
|
||||
writeBytes((const void*)out, sizeof(lcase) * n);\
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_WRITER(UInt16, uint16)
|
||||
IMPLEMENT_WRITER(Int16, int16)
|
||||
IMPLEMENT_WRITER(UInt32, uint32)
|
||||
IMPLEMENT_WRITER(Int32, int32)
|
||||
IMPLEMENT_WRITER(UInt64, uint64)
|
||||
IMPLEMENT_WRITER(Int64, int64)
|
||||
IMPLEMENT_WRITER(Float32, float32)
|
||||
IMPLEMENT_WRITER(Float64, float64)
|
||||
|
||||
#undef IMPLEMENT_WRITER
|
||||
|
||||
|
||||
void BinaryOutput::reallocBuffer(size_t bytes, size_t oldBufferLen) {
|
||||
//debugPrintf("reallocBuffer(%d, %d)\n", bytes, oldBufferLen);
|
||||
|
||||
size_t newBufferLen = (int)(m_bufferLen * 1.5) + 100;
|
||||
uint8* newBuffer = NULL;
|
||||
|
||||
if ((m_filename == "<memory>") || (newBufferLen < MAX_BINARYOUTPUT_BUFFER_SIZE)) {
|
||||
// We're either writing to memory (in which case we *have* to try and allocate)
|
||||
// or we've been asked to allocate a reasonable size buffer.
|
||||
|
||||
//debugPrintf(" realloc(%d)\n", newBufferLen);
|
||||
newBuffer = (uint8*)System::realloc(m_buffer, newBufferLen);
|
||||
if (newBuffer != NULL) {
|
||||
m_maxBufferLen = newBufferLen;
|
||||
}
|
||||
}
|
||||
|
||||
if ((newBuffer == NULL) && (bytes > 0)) {
|
||||
// Realloc failed; we're probably out of memory. Back out
|
||||
// the entire call and try to dump some data to disk.
|
||||
m_bufferLen = oldBufferLen;
|
||||
reserveBytesWhenOutOfMemory(bytes);
|
||||
} else {
|
||||
m_buffer = newBuffer;
|
||||
debugAssert(isValidHeapPointer(m_buffer));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::reserveBytesWhenOutOfMemory(size_t bytes) {
|
||||
if (m_filename == "<memory>") {
|
||||
throw "Out of memory while writing to memory in BinaryOutput (no RAM left).";
|
||||
} else if ((int)bytes > (int)m_maxBufferLen) {
|
||||
throw "Out of memory while writing to disk in BinaryOutput (could not create a large enough buffer).";
|
||||
} else {
|
||||
|
||||
// Dump the contents to disk. In order to enable seeking backwards,
|
||||
// we keep the last 10 MB in memory.
|
||||
int writeBytes = m_bufferLen - 10 * 1024 * 1024;
|
||||
|
||||
if (writeBytes < m_bufferLen / 3) {
|
||||
// We're going to write less than 1/3 of the file;
|
||||
// give up and just write the whole thing.
|
||||
writeBytes = m_bufferLen;
|
||||
}
|
||||
debugAssert(writeBytes > 0);
|
||||
|
||||
//debugPrintf("Writing %d bytes to disk\n", writeBytes);
|
||||
|
||||
const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb";
|
||||
FILE* file = FileSystem::fopen(m_filename.c_str(), mode);
|
||||
debugAssert(file);
|
||||
|
||||
size_t count = fwrite(m_buffer, 1, writeBytes, file);
|
||||
debugAssert((int)count == writeBytes); (void)count;
|
||||
|
||||
fclose(file);
|
||||
file = NULL;
|
||||
|
||||
// Record that we saved this data.
|
||||
m_alreadyWritten += writeBytes;
|
||||
m_bufferLen -= writeBytes;
|
||||
m_pos -= writeBytes;
|
||||
|
||||
debugAssert(m_bufferLen < m_maxBufferLen);
|
||||
debugAssert(m_bufferLen >= 0);
|
||||
debugAssert(m_pos >= 0);
|
||||
debugAssert(m_pos <= m_bufferLen);
|
||||
|
||||
// Shift the unwritten data back appropriately in the buffer.
|
||||
debugAssert(isValidHeapPointer(m_buffer));
|
||||
System::memcpy(m_buffer, m_buffer + writeBytes, m_bufferLen);
|
||||
debugAssert(isValidHeapPointer(m_buffer));
|
||||
|
||||
// *now* we allocate bytes (there should presumably be enough
|
||||
// space in the buffer; if not, we'll come back through this
|
||||
// code and dump the last 10MB to disk as well. Note that the
|
||||
// bytes > maxBufferLen case above would already have triggered
|
||||
// if this call couldn't succeed.
|
||||
reserveBytes(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BinaryOutput::BinaryOutput() {
|
||||
m_alreadyWritten = 0;
|
||||
m_swapBytes = false;
|
||||
m_pos = 0;
|
||||
m_filename = "<memory>";
|
||||
m_buffer = NULL;
|
||||
m_bufferLen = 0;
|
||||
m_maxBufferLen = 0;
|
||||
m_beginEndBits = 0;
|
||||
m_bitString = 0;
|
||||
m_bitPos = 0;
|
||||
m_ok = true;
|
||||
m_committed = false;
|
||||
}
|
||||
|
||||
|
||||
BinaryOutput::BinaryOutput(
|
||||
const std::string& filename,
|
||||
G3DEndian fileEndian) {
|
||||
|
||||
m_pos = 0;
|
||||
m_alreadyWritten = 0;
|
||||
setEndian(fileEndian);
|
||||
m_filename = filename;
|
||||
m_buffer = NULL;
|
||||
m_bufferLen = 0;
|
||||
m_maxBufferLen = 0;
|
||||
m_beginEndBits = 0;
|
||||
m_bitString = 0;
|
||||
m_bitPos = 0;
|
||||
m_committed = false;
|
||||
|
||||
m_ok = true;
|
||||
/** Verify ability to write to disk */
|
||||
commit(false);
|
||||
m_committed = false;
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::reset() {
|
||||
debugAssert(m_beginEndBits == 0);
|
||||
alwaysAssertM(m_filename == "<memory>",
|
||||
"Can only reset a BinaryOutput that writes to memory.");
|
||||
|
||||
// Do not reallocate, just clear the size of the buffer.
|
||||
m_pos = 0;
|
||||
m_alreadyWritten = 0;
|
||||
m_bufferLen = 0;
|
||||
m_beginEndBits = 0;
|
||||
m_bitString = 0;
|
||||
m_bitPos = 0;
|
||||
m_committed = false;
|
||||
}
|
||||
|
||||
|
||||
BinaryOutput::~BinaryOutput() {
|
||||
debugAssert((m_buffer == NULL) || isValidHeapPointer(m_buffer));
|
||||
System::free(m_buffer);
|
||||
m_buffer = NULL;
|
||||
m_bufferLen = 0;
|
||||
m_maxBufferLen = 0;
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::setEndian(G3DEndian fileEndian) {
|
||||
m_fileEndian = fileEndian;
|
||||
m_swapBytes = (fileEndian != System::machineEndian());
|
||||
}
|
||||
|
||||
|
||||
bool BinaryOutput::ok() const {
|
||||
return m_ok;
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::compress() {
|
||||
if (m_alreadyWritten > 0) {
|
||||
throw "Cannot compress huge files (part of this file has already been written to disk).";
|
||||
}
|
||||
|
||||
// Old buffer size
|
||||
int L = m_bufferLen;
|
||||
uint8* convert = (uint8*)&L;
|
||||
|
||||
// Zlib requires the output buffer to be this big
|
||||
unsigned long newSize = iCeil(m_bufferLen * 1.01) + 12;
|
||||
uint8* temp = (uint8*)System::malloc(newSize);
|
||||
int result = compress2(temp, &newSize, m_buffer, m_bufferLen, 9);
|
||||
|
||||
debugAssert(result == Z_OK); (void)result;
|
||||
|
||||
// Write the header
|
||||
if (m_swapBytes) {
|
||||
m_buffer[0] = convert[3];
|
||||
m_buffer[1] = convert[2];
|
||||
m_buffer[2] = convert[1];
|
||||
m_buffer[3] = convert[0];
|
||||
} else {
|
||||
m_buffer[0] = convert[0];
|
||||
m_buffer[1] = convert[1];
|
||||
m_buffer[2] = convert[2];
|
||||
m_buffer[3] = convert[3];
|
||||
}
|
||||
|
||||
// Write the data
|
||||
if ((int64)newSize + 4 > (int64)m_maxBufferLen) {
|
||||
m_maxBufferLen = newSize + 4;
|
||||
m_buffer = (uint8*)System::realloc(m_buffer, m_maxBufferLen);
|
||||
}
|
||||
m_bufferLen = newSize + 4;
|
||||
System::memcpy(m_buffer + 4, temp, newSize);
|
||||
m_pos = m_bufferLen;
|
||||
|
||||
System::free(temp);
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::commit(bool flush) {
|
||||
debugAssertM(! m_committed, "Cannot commit twice");
|
||||
m_committed = true;
|
||||
debugAssertM(m_beginEndBits == 0, "Missing endBits before commit");
|
||||
|
||||
// Make sure the directory exists.
|
||||
std::string root, base, ext, path;
|
||||
Array<std::string> pathArray;
|
||||
parseFilename(m_filename, root, pathArray, base, ext);
|
||||
|
||||
path = root + stringJoin(pathArray, '/');
|
||||
if (! FileSystem::exists(path, false)) {
|
||||
FileSystem::createDirectory(path);
|
||||
}
|
||||
|
||||
const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb";
|
||||
|
||||
FILE* file = FileSystem::fopen(m_filename.c_str(), mode);
|
||||
|
||||
if (! file) {
|
||||
logPrintf("Error %d while trying to open \"%s\"\n", errno, m_filename.c_str());
|
||||
}
|
||||
m_ok = (file != NULL) && m_ok;
|
||||
|
||||
if (m_ok) {
|
||||
debugAssertM(file, std::string("Could not open '") + m_filename + "'");
|
||||
|
||||
if (m_buffer != NULL) {
|
||||
m_alreadyWritten += m_bufferLen;
|
||||
|
||||
int success = fwrite(m_buffer, m_bufferLen, 1, file);
|
||||
(void)success;
|
||||
debugAssertM(success == 1, std::string("Could not write to '") + m_filename + "'");
|
||||
}
|
||||
if (flush) {
|
||||
fflush(file);
|
||||
}
|
||||
FileSystem::fclose(file);
|
||||
file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::commit(
|
||||
uint8* out) {
|
||||
debugAssertM(! m_committed, "Cannot commit twice");
|
||||
m_committed = true;
|
||||
|
||||
System::memcpy(out, m_buffer, m_bufferLen);
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeUInt16(uint16 u) {
|
||||
reserveBytes(2);
|
||||
|
||||
uint8* convert = (uint8*)&u;
|
||||
|
||||
if (m_swapBytes) {
|
||||
m_buffer[m_pos] = convert[1];
|
||||
m_buffer[m_pos + 1] = convert[0];
|
||||
} else {
|
||||
*(uint16*)(m_buffer + m_pos) = u;
|
||||
}
|
||||
|
||||
m_pos += 2;
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeUInt32(uint32 u) {
|
||||
reserveBytes(4);
|
||||
|
||||
uint8* convert = (uint8*)&u;
|
||||
|
||||
debugAssert(m_beginEndBits == 0);
|
||||
|
||||
if (m_swapBytes) {
|
||||
m_buffer[m_pos] = convert[3];
|
||||
m_buffer[m_pos + 1] = convert[2];
|
||||
m_buffer[m_pos + 2] = convert[1];
|
||||
m_buffer[m_pos + 3] = convert[0];
|
||||
} else {
|
||||
*(uint32*)(m_buffer + m_pos) = u;
|
||||
}
|
||||
|
||||
m_pos += 4;
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeUInt64(uint64 u) {
|
||||
reserveBytes(8);
|
||||
|
||||
uint8* convert = (uint8*)&u;
|
||||
|
||||
if (m_swapBytes) {
|
||||
m_buffer[m_pos] = convert[7];
|
||||
m_buffer[m_pos + 1] = convert[6];
|
||||
m_buffer[m_pos + 2] = convert[5];
|
||||
m_buffer[m_pos + 3] = convert[4];
|
||||
m_buffer[m_pos + 4] = convert[3];
|
||||
m_buffer[m_pos + 5] = convert[2];
|
||||
m_buffer[m_pos + 6] = convert[1];
|
||||
m_buffer[m_pos + 7] = convert[0];
|
||||
} else {
|
||||
*(uint64*)(m_buffer + m_pos) = u;
|
||||
}
|
||||
|
||||
m_pos += 8;
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeString(const char* s) {
|
||||
// +1 is because strlen doesn't count the null
|
||||
int len = strlen(s) + 1;
|
||||
|
||||
debugAssert(m_beginEndBits == 0);
|
||||
reserveBytes(len);
|
||||
System::memcpy(m_buffer + m_pos, s, len);
|
||||
m_pos += len;
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeStringEven(const char* s) {
|
||||
// +1 is because strlen doesn't count the null
|
||||
int len = strlen(s) + 1;
|
||||
|
||||
reserveBytes(len);
|
||||
System::memcpy(m_buffer + m_pos, s, len);
|
||||
m_pos += len;
|
||||
|
||||
// Pad with another NULL
|
||||
if ((len % 2) == 1) {
|
||||
writeUInt8(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeString32(const char* s) {
|
||||
writeUInt32(strlen(s) + 1);
|
||||
writeString(s);
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeVector4(const Vector4& v) {
|
||||
writeFloat32(v.x);
|
||||
writeFloat32(v.y);
|
||||
writeFloat32(v.z);
|
||||
writeFloat32(v.w);
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeVector3(const Vector3& v) {
|
||||
writeFloat32(v.x);
|
||||
writeFloat32(v.y);
|
||||
writeFloat32(v.z);
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeVector2(const Vector2& v) {
|
||||
writeFloat32(v.x);
|
||||
writeFloat32(v.y);
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeColor4(const Color4& v) {
|
||||
writeFloat32(v.r);
|
||||
writeFloat32(v.g);
|
||||
writeFloat32(v.b);
|
||||
writeFloat32(v.a);
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeColor3(const Color3& v) {
|
||||
writeFloat32(v.r);
|
||||
writeFloat32(v.g);
|
||||
writeFloat32(v.b);
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::beginBits() {
|
||||
debugAssertM(m_beginEndBits == 0, "Already in beginBits...endBits");
|
||||
m_bitString = 0x00;
|
||||
m_bitPos = 0;
|
||||
m_beginEndBits = 1;
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::writeBits(uint32 value, int numBits) {
|
||||
|
||||
while (numBits > 0) {
|
||||
// Extract the current bit of value and
|
||||
// insert it into the current byte
|
||||
m_bitString |= (value & 1) << m_bitPos;
|
||||
++m_bitPos;
|
||||
value = value >> 1;
|
||||
--numBits;
|
||||
|
||||
if (m_bitPos > 7) {
|
||||
// We've reached the end of this byte
|
||||
writeUInt8(m_bitString);
|
||||
m_bitString = 0x00;
|
||||
m_bitPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BinaryOutput::endBits() {
|
||||
debugAssertM(m_beginEndBits == 1, "Not in beginBits...endBits");
|
||||
if (m_bitPos > 0) {
|
||||
writeUInt8(m_bitString);
|
||||
}
|
||||
m_bitString = 0;
|
||||
m_bitPos = 0;
|
||||
m_beginEndBits = 0;
|
||||
}
|
||||
|
||||
}
|
||||
393
modules/acore/deps/g3dlite/source/Box.cpp
Normal file
393
modules/acore/deps/g3dlite/source/Box.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
/**
|
||||
@file Box.cpp
|
||||
Box class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2006-02-05
|
||||
*/
|
||||
|
||||
#include "G3D/Box.h"
|
||||
#include "G3D/debug.h"
|
||||
#include "G3D/Plane.h"
|
||||
#include "G3D/AABox.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
/**
|
||||
Sets a field on four vertices. Used by the constructor.
|
||||
*/
|
||||
#define setMany(i0, i1, i2, i3, field, extreme) \
|
||||
_corner[i0].field = _corner[i1].field = \
|
||||
_corner[i2].field = _corner[i3].field = \
|
||||
(extreme).field
|
||||
|
||||
Box::Box() {
|
||||
}
|
||||
|
||||
|
||||
Box::Box(const AABox& b) {
|
||||
init(b.low(), b.high());
|
||||
}
|
||||
|
||||
Box::Box(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Box::serialize(class BinaryOutput& b) const {
|
||||
int i;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
_corner[i].serialize(b);
|
||||
}
|
||||
|
||||
// Other state can be reconstructed
|
||||
}
|
||||
|
||||
|
||||
void Box::deserialize(class BinaryInput& b) {
|
||||
int i;
|
||||
|
||||
_center = Vector3::zero();
|
||||
for (i = 0; i < 8; ++i) {
|
||||
_corner[i].deserialize(b);
|
||||
_center += _corner[i];
|
||||
}
|
||||
|
||||
_center = _center / 8;
|
||||
|
||||
// Reconstruct other state from the corners
|
||||
_axis[0] = _corner[5] - _corner[4];
|
||||
_axis[1] = _corner[7] - _corner[4];
|
||||
_axis[2] = _corner[0] - _corner[4];
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
_extent[i] = _axis[i].magnitude();
|
||||
_axis[i] /= _extent[i];
|
||||
}
|
||||
|
||||
_volume = _extent.x * _extent.y * _extent.z;
|
||||
|
||||
_area = 2 *
|
||||
(_extent.x * _extent.y +
|
||||
_extent.y * _extent.z +
|
||||
_extent.z * _extent.x);
|
||||
}
|
||||
|
||||
|
||||
Box::Box(
|
||||
const Vector3& min,
|
||||
const Vector3& max) {
|
||||
|
||||
init(min.min(max), min.max(max));
|
||||
|
||||
}
|
||||
|
||||
void Box::init(
|
||||
const Vector3& min,
|
||||
const Vector3& max) {
|
||||
|
||||
debugAssert(
|
||||
(min.x <= max.x) &&
|
||||
(min.y <= max.y) &&
|
||||
(min.z <= max.z));
|
||||
|
||||
setMany(0, 1, 2, 3, z, max);
|
||||
setMany(4, 5, 6, 7, z, min);
|
||||
|
||||
setMany(1, 2, 5, 6, x, max);
|
||||
setMany(0, 3, 4, 7, x, min);
|
||||
|
||||
setMany(3, 2, 6, 7, y, max);
|
||||
setMany(0, 1, 5, 4, y, min);
|
||||
|
||||
_extent = max - min;
|
||||
|
||||
_axis[0] = Vector3::unitX();
|
||||
_axis[1] = Vector3::unitY();
|
||||
_axis[2] = Vector3::unitZ();
|
||||
|
||||
if (_extent.isFinite()) {
|
||||
_volume = _extent.x * _extent.y * _extent.z;
|
||||
} else {
|
||||
_volume = G3D::finf();
|
||||
}
|
||||
|
||||
debugAssert(! isNaN(_extent.x));
|
||||
|
||||
_area = 2 *
|
||||
(_extent.x * _extent.y +
|
||||
_extent.y * _extent.z +
|
||||
_extent.z * _extent.x);
|
||||
|
||||
_center = (max + min) * 0.5f;
|
||||
|
||||
// If the extent is infinite along an axis, make the center zero to avoid NaNs
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (! G3D::isFinite(_extent[i])) {
|
||||
_center[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float Box::volume() const {
|
||||
return _volume;
|
||||
}
|
||||
|
||||
|
||||
float Box::area() const {
|
||||
return _area;
|
||||
}
|
||||
|
||||
|
||||
void Box::getLocalFrame(CoordinateFrame& frame) const {
|
||||
|
||||
frame.rotation = Matrix3(
|
||||
_axis[0][0], _axis[1][0], _axis[2][0],
|
||||
_axis[0][1], _axis[1][1], _axis[2][1],
|
||||
_axis[0][2], _axis[1][2], _axis[2][2]);
|
||||
|
||||
frame.translation = _center;
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame Box::localFrame() const {
|
||||
CoordinateFrame out;
|
||||
getLocalFrame(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Box::getFaceCorners(int f, Vector3& v0, Vector3& v1, Vector3& v2, Vector3& v3) const {
|
||||
switch (f) {
|
||||
case 0:
|
||||
v0 = _corner[0]; v1 = _corner[1]; v2 = _corner[2]; v3 = _corner[3];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
v0 = _corner[1]; v1 = _corner[5]; v2 = _corner[6]; v3 = _corner[2];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
v0 = _corner[7]; v1 = _corner[6]; v2 = _corner[5]; v3 = _corner[4];
|
||||
break;
|
||||
|
||||
case 3:
|
||||
v0 = _corner[2]; v1 = _corner[6]; v2 = _corner[7]; v3 = _corner[3];
|
||||
break;
|
||||
|
||||
case 4:
|
||||
v0 = _corner[3]; v1 = _corner[7]; v2 = _corner[4]; v3 = _corner[0];
|
||||
break;
|
||||
|
||||
case 5:
|
||||
v0 = _corner[1]; v1 = _corner[0]; v2 = _corner[4]; v3 = _corner[5];
|
||||
break;
|
||||
|
||||
default:
|
||||
debugAssert((f >= 0) && (f < 6));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Box::dummy = 0;
|
||||
|
||||
bool Box::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask,
|
||||
uint32& childMask) const {
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(plane.size() < 31);
|
||||
|
||||
childMask = 0;
|
||||
|
||||
// See if there is one plane for which all of the
|
||||
// vertices are in the negative half space.
|
||||
for (int p = 0; p < plane.size(); ++p) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
|
||||
Vector3 corner;
|
||||
|
||||
int numContained = 0;
|
||||
int v = 0;
|
||||
|
||||
// We can early-out only if we have found one point on each
|
||||
// side of the plane (i.e. if we are straddling). That
|
||||
// occurs when (numContained < v) && (numContained > 0)
|
||||
for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) {
|
||||
if (plane[p].halfSpaceContains(_corner[v])) {
|
||||
++numContained;
|
||||
}
|
||||
}
|
||||
|
||||
if (numContained == 0) {
|
||||
// Plane p culled the box
|
||||
cullingPlane = p;
|
||||
|
||||
// The caller should not recurse into the children,
|
||||
// since the parent is culled. If they do recurse,
|
||||
// make them only test against this one plane, which
|
||||
// will immediately cull the volume.
|
||||
childMask = 1 << p;
|
||||
return true;
|
||||
|
||||
} else if (numContained < v) {
|
||||
// The bounding volume straddled the plane; we have
|
||||
// to keep testing against this plane
|
||||
childMask |= (1 << p);
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next bit.
|
||||
inMask = inMask >> 1;
|
||||
}
|
||||
|
||||
// None of the planes could cull this box
|
||||
cullingPlane = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Box::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask) const {
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(plane.size() < 31);
|
||||
|
||||
// See if there is one plane for which all of the
|
||||
// vertices are in the negative half space.
|
||||
for (int p = 0; p < plane.size(); ++p) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
|
||||
bool culled = true;
|
||||
|
||||
int v;
|
||||
|
||||
// Assume this plane culls all points. See if there is a point
|
||||
// not culled by the plane... early out when at least one point
|
||||
// is in the positive half space.
|
||||
for (v = 0; (v < 8) && culled; ++v) {
|
||||
culled = ! plane[p].halfSpaceContains(corner(v));
|
||||
}
|
||||
|
||||
if (culled) {
|
||||
// Plane p culled the box
|
||||
cullingPlane = p;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next bit.
|
||||
inMask = inMask >> 1;
|
||||
}
|
||||
|
||||
// None of the planes could cull this box
|
||||
cullingPlane = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Box::contains(
|
||||
const Vector3& point) const {
|
||||
|
||||
// Form axes from three edges, transform the point into that
|
||||
// space, and perform 3 interval tests
|
||||
|
||||
Vector3 u = _corner[4] - _corner[0];
|
||||
Vector3 v = _corner[3] - _corner[0];
|
||||
Vector3 w = _corner[1] - _corner[0];
|
||||
|
||||
Matrix3 M = Matrix3(u.x, v.x, w.x,
|
||||
u.y, v.y, w.y,
|
||||
u.z, v.z, w.z);
|
||||
|
||||
// M^-1 * (point - _corner[0]) = point in unit cube's object space
|
||||
// compute the inverse of M
|
||||
Vector3 osPoint = M.inverse() * (point - _corner[0]);
|
||||
|
||||
return
|
||||
(osPoint.x >= 0) &&
|
||||
(osPoint.y >= 0) &&
|
||||
(osPoint.z >= 0) &&
|
||||
(osPoint.x <= 1) &&
|
||||
(osPoint.y <= 1) &&
|
||||
(osPoint.z <= 1);
|
||||
}
|
||||
|
||||
#undef setMany
|
||||
|
||||
|
||||
void Box::getRandomSurfacePoint(Vector3& P, Vector3& N) const {
|
||||
float aXY = _extent.x * _extent.y;
|
||||
float aYZ = _extent.y * _extent.z;
|
||||
float aZX = _extent.z * _extent.x;
|
||||
|
||||
float r = (float)uniformRandom(0, aXY + aYZ + aZX);
|
||||
|
||||
// Choose evenly between positive and negative face planes
|
||||
float d = (uniformRandom(0, 1) < 0.5f) ? -1.0f : 1.0f;
|
||||
|
||||
// The probability of choosing a given face is proportional to
|
||||
// its area.
|
||||
if (r < aXY) {
|
||||
P = _axis[0] * (float)uniformRandom(-0.5, 0.5) * _extent.x +
|
||||
_axis[1] * (float)uniformRandom(-0.5, 0.5) * _extent.y +
|
||||
_center + _axis[2] * d * _extent.z * 0.5f;
|
||||
N = _axis[2] * d;
|
||||
} else if (r < aYZ) {
|
||||
P = _axis[1] * (float)uniformRandom(-0.5, 0.5) * _extent.y +
|
||||
_axis[2] * (float)uniformRandom(-0.5, 0.5) * _extent.z +
|
||||
_center + _axis[0] * d * _extent.x * 0.5f;
|
||||
N = _axis[0] * d;
|
||||
} else {
|
||||
P = _axis[2] * (float)uniformRandom(-0.5, 0.5) * _extent.z +
|
||||
_axis[0] *(float) uniformRandom(-0.5, 0.5) * _extent.x +
|
||||
_center + _axis[1] * d * _extent.y * 0.5f;
|
||||
N = _axis[1] * d;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector3 Box::randomInteriorPoint() const {
|
||||
Vector3 sum = _center;
|
||||
|
||||
for (int a = 0; a < 3; ++a) {
|
||||
sum += _axis[a] * (float)uniformRandom(-0.5, 0.5) * _extent[a];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
Box Box::inf() {
|
||||
return Box(-Vector3::inf(), Vector3::inf());
|
||||
}
|
||||
|
||||
void Box::getBounds(class AABox& aabb) const {
|
||||
|
||||
Vector3 lo = _corner[0];
|
||||
Vector3 hi = lo;
|
||||
|
||||
for (int v = 1; v < 8; ++v) {
|
||||
const Vector3& C = _corner[v];
|
||||
lo = lo.min(C);
|
||||
hi = hi.max(C);
|
||||
}
|
||||
|
||||
aabb = AABox(lo, hi);
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
113
modules/acore/deps/g3dlite/source/Box2D.cpp
Normal file
113
modules/acore/deps/g3dlite/source/Box2D.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
@file Box.cpp
|
||||
Box class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2008-12-27
|
||||
*/
|
||||
|
||||
#include "G3D/Box2D.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Rect2D.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
bool Box2D::overlaps1Way(const Box2D& other) const {
|
||||
for (int a = 0; a < 2; ++a) {
|
||||
|
||||
float t = other.m_corner[0].dot(m_axisin[a]);
|
||||
|
||||
// Find the extent of box 2 on m_axisin a
|
||||
float tMin = t;
|
||||
float tMax = t;
|
||||
|
||||
for (int c = 1; c < 4; ++c) {
|
||||
t = other.m_corner[c].dot(m_axisin[a]);
|
||||
|
||||
if (t < tMin) {
|
||||
tMin = t;
|
||||
} else if (t > tMax) {
|
||||
tMax = t;
|
||||
}
|
||||
}
|
||||
|
||||
// We have to subtract off the origin
|
||||
|
||||
// See if [tMin, tMax] intersects [0, 1]
|
||||
if ((tMin > 1 + origin[a]) || (tMax < origin[a])) {
|
||||
// There was no intersection along this dimension;
|
||||
// the boxes cannot possibly overlap.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// There was no dimension along which there is no intersection.
|
||||
// Therefore the boxes overlap.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Box2D::computeAxes() {
|
||||
m_axis[0] = m_corner[1] - m_corner[0];
|
||||
m_axis[1] = m_corner[3] - m_corner[0];
|
||||
|
||||
// Make the length of each m_axisin = 1/edge length so we know any
|
||||
// dot product must be less than 1 to fall within the edge.
|
||||
float len[2];
|
||||
for (int a = 0; a < 2; ++a) {
|
||||
float lenSq = m_axis[a].squaredLength();
|
||||
m_axisin[a] = m_axis[a] / lenSq;
|
||||
origin[a] = m_corner[0].dot(m_axisin[a]);
|
||||
len[a] = sqrt(lenSq);
|
||||
m_axis[a] /= len[a];
|
||||
}
|
||||
|
||||
// w * h
|
||||
m_area = len[0] * len[1];
|
||||
|
||||
|
||||
m_center = (m_corner[0] + m_corner[2]) * 0.5f;
|
||||
}
|
||||
|
||||
|
||||
Box2D::Box2D(const Vector2& center, float w, float h, float angle) {
|
||||
Vector2 X( cos(angle), sin(angle));
|
||||
Vector2 Y(-sin(angle), cos(angle));
|
||||
|
||||
X *= w / 2;
|
||||
Y *= h / 2;
|
||||
|
||||
m_corner[0] = center - X - Y;
|
||||
m_corner[1] = center + X - Y;
|
||||
m_corner[2] = center + X + Y;
|
||||
m_corner[3] = center - X + Y;
|
||||
|
||||
computeAxes();
|
||||
}
|
||||
|
||||
|
||||
Box2D::Box2D(const AABox2D& b) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
m_corner[i] = b.corner(i);
|
||||
}
|
||||
|
||||
computeAxes();
|
||||
}
|
||||
|
||||
|
||||
Box2D::Box2D(const Vector2& min, const Vector2& max) {
|
||||
*this = Box2D(Rect2D::xyxy(min, max));
|
||||
}
|
||||
|
||||
|
||||
Box2D::Box2D(const CFrame& frame, Box2D& b) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
m_corner[i] = frame.pointToWorldSpace(Vector3(b.corner(i), 0)).xy();
|
||||
}
|
||||
computeAxes();
|
||||
}
|
||||
|
||||
|
||||
} // G3D
|
||||
43
modules/acore/deps/g3dlite/source/BumpMapPreprocess.cpp
Normal file
43
modules/acore/deps/g3dlite/source/BumpMapPreprocess.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
\file BumpMapPreprocess.cpp
|
||||
|
||||
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
\created 2010-01-28
|
||||
\edited 2010-01-28
|
||||
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
#include "G3D/BumpMapPreprocess.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
BumpMapPreprocess::BumpMapPreprocess(const Any& any) {
|
||||
*this = BumpMapPreprocess();
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "lowpassfilter") {
|
||||
lowPassFilter = it->value;
|
||||
} else if (key == "zextentpixels") {
|
||||
zExtentPixels = it->value;
|
||||
} else if (key == "scalezbynz") {
|
||||
scaleZByNz = it->value;
|
||||
} else {
|
||||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BumpMapPreprocess::operator Any() const {
|
||||
Any any(Any::TABLE, "BumpMapPreprocess");
|
||||
any["lowPassFilter"] = lowPassFilter;
|
||||
any["zExtentPixels"] = zExtentPixels;
|
||||
any["scaleZByNz"] = scaleZByNz;
|
||||
return any;
|
||||
}
|
||||
|
||||
}
|
||||
179
modules/acore/deps/g3dlite/source/Capsule.cpp
Normal file
179
modules/acore/deps/g3dlite/source/Capsule.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
@file Capsule.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-02-07
|
||||
@edited 2005-08-18
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/Capsule.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/LineSegment.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Line.h"
|
||||
#include "G3D/AABox.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Capsule::Capsule(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
Capsule::Capsule() {
|
||||
}
|
||||
|
||||
|
||||
Capsule::Capsule(const Vector3& _p1, const Vector3& _p2, float _r)
|
||||
: p1(_p1), p2(_p2), _radius(_r) {
|
||||
}
|
||||
|
||||
|
||||
void Capsule::serialize(class BinaryOutput& b) const {
|
||||
p1.serialize(b);
|
||||
p2.serialize(b);
|
||||
b.writeFloat64(_radius);
|
||||
}
|
||||
|
||||
|
||||
void Capsule::deserialize(class BinaryInput& b) {
|
||||
p1.deserialize(b);
|
||||
p2.deserialize(b);
|
||||
_radius = b.readFloat64();
|
||||
}
|
||||
|
||||
|
||||
Line Capsule::axis() const {
|
||||
return Line::fromTwoPoints(p1, p2);
|
||||
}
|
||||
|
||||
|
||||
float Capsule::volume() const {
|
||||
return
|
||||
// Sphere volume
|
||||
pow(_radius, 3) * pi() * 4 / 3 +
|
||||
|
||||
// Cylinder volume
|
||||
pow(_radius, 2) * (p1 - p2).magnitude();
|
||||
}
|
||||
|
||||
|
||||
float Capsule::area() const {
|
||||
|
||||
return
|
||||
// Sphere area
|
||||
pow(_radius, 2) * 4 * pi() +
|
||||
|
||||
// Cylinder area
|
||||
twoPi() * _radius * (p1 - p2).magnitude();
|
||||
}
|
||||
|
||||
|
||||
void Capsule::getBounds(AABox& out) const {
|
||||
Vector3 min = p1.min(p2) - (Vector3(1, 1, 1) * _radius);
|
||||
Vector3 max = p1.max(p2) + (Vector3(1, 1, 1) * _radius);
|
||||
|
||||
out = AABox(min, max);
|
||||
}
|
||||
|
||||
|
||||
bool Capsule::contains(const Vector3& p) const {
|
||||
return LineSegment::fromTwoPoints(p1, p2).distanceSquared(p) <= square(radius());
|
||||
}
|
||||
|
||||
|
||||
void Capsule::getRandomSurfacePoint(Vector3& p, Vector3& N) const {
|
||||
float h = height();
|
||||
float r = radius();
|
||||
|
||||
// Create a random point on a standard capsule and then rotate to the global frame.
|
||||
|
||||
// Relative areas
|
||||
float capRelArea = sqrt(r) / 2.0f;
|
||||
float sideRelArea = r * h;
|
||||
|
||||
float r1 = uniformRandom(0, capRelArea * 2 + sideRelArea);
|
||||
|
||||
if (r1 < capRelArea * 2) {
|
||||
|
||||
// Select a point uniformly at random on a sphere
|
||||
N = Sphere(Vector3::zero(), 1).randomSurfacePoint();
|
||||
p = N * r;
|
||||
p.y += sign(p.y) * h / 2.0f;
|
||||
} else {
|
||||
// Side
|
||||
float a = uniformRandom(0, (float)twoPi());
|
||||
N.x = cos(a);
|
||||
N.y = 0;
|
||||
N.z = sin(a);
|
||||
p.x = N.x * r;
|
||||
p.z = N.y * r;
|
||||
p.y = uniformRandom(-h / 2.0f, h / 2.0f);
|
||||
}
|
||||
|
||||
// Transform to world space
|
||||
CoordinateFrame cframe;
|
||||
getReferenceFrame(cframe);
|
||||
|
||||
p = cframe.pointToWorldSpace(p);
|
||||
N = cframe.normalToWorldSpace(N);
|
||||
}
|
||||
|
||||
|
||||
void Capsule::getReferenceFrame(CoordinateFrame& cframe) const {
|
||||
cframe.translation = center();
|
||||
|
||||
Vector3 Y = (p1 - p2).direction();
|
||||
Vector3 X = (abs(Y.dot(Vector3::unitX())) > 0.9) ? Vector3::unitY() : Vector3::unitX();
|
||||
Vector3 Z = X.cross(Y).direction();
|
||||
X = Y.cross(Z);
|
||||
cframe.rotation.setColumn(0, X);
|
||||
cframe.rotation.setColumn(1, Y);
|
||||
cframe.rotation.setColumn(2, Z);
|
||||
}
|
||||
|
||||
|
||||
Vector3 Capsule::randomInteriorPoint() const {
|
||||
float h = height();
|
||||
float r = radius();
|
||||
|
||||
// Create a random point in a standard capsule and then rotate to the global frame.
|
||||
|
||||
Vector3 p;
|
||||
|
||||
float hemiVolume = pi() * (r*r*r) * 4 / 6.0;
|
||||
float cylVolume = pi() * square(r) * h;
|
||||
|
||||
float r1 = uniformRandom(0, 2.0 * hemiVolume + cylVolume);
|
||||
|
||||
if (r1 < 2.0 * hemiVolume) {
|
||||
|
||||
p = Sphere(Vector3::zero(), r).randomInteriorPoint();
|
||||
|
||||
p.y += sign(p.y) * h / 2.0f;
|
||||
|
||||
} else {
|
||||
|
||||
// Select a point uniformly at random on a disk
|
||||
float a = uniformRandom(0, (float)twoPi());
|
||||
float r2 = sqrt(uniformRandom(0, 1)) * r;
|
||||
|
||||
p = Vector3(cos(a) * r2,
|
||||
uniformRandom(-h / 2.0f, h / 2.0f),
|
||||
sin(a) * r2);
|
||||
}
|
||||
|
||||
// Transform to world space
|
||||
CoordinateFrame cframe;
|
||||
getReferenceFrame(cframe);
|
||||
|
||||
return cframe.pointToWorldSpace(p);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
2455
modules/acore/deps/g3dlite/source/CollisionDetection.cpp
Normal file
2455
modules/acore/deps/g3dlite/source/CollisionDetection.cpp
Normal file
File diff suppressed because it is too large
Load Diff
58
modules/acore/deps/g3dlite/source/Color1.cpp
Normal file
58
modules/acore/deps/g3dlite/source/Color1.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
@file Color1.cpp
|
||||
|
||||
Color class.
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-30
|
||||
@edited 2009-03-27
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Color3.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
const Color1& Color1::one() {
|
||||
static const Color1 x(1.0f);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
const Color1& Color1::zero() {
|
||||
const static Color1 x(0.0f);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
Color1::Color1(BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
Color3 Color1::rgb() const {
|
||||
return Color3(value, value, value);
|
||||
}
|
||||
|
||||
|
||||
void Color1::deserialize(BinaryInput& bi) {
|
||||
value = bi.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Color1::serialize(BinaryOutput& bo) const {
|
||||
bo.writeFloat32(value);
|
||||
}
|
||||
|
||||
|
||||
Color1::Color1(const class Color1uint8& other) {
|
||||
value = other.value / 255.0f;
|
||||
}
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
38
modules/acore/deps/g3dlite/source/Color1uint8.cpp
Normal file
38
modules/acore/deps/g3dlite/source/Color1uint8.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
@file Color1uint8.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-30
|
||||
@edited 2007-01-30
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Color1uint8::Color1uint8(const class Color1& c) : value(iClamp(iFloor(c.value * 256), 0, 255)) {
|
||||
}
|
||||
|
||||
|
||||
Color1uint8::Color1uint8(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Color1uint8::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeUInt8(value);
|
||||
}
|
||||
|
||||
|
||||
void Color1uint8::deserialize(class BinaryInput& bi) {
|
||||
value = bi.readUInt8();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
384
modules/acore/deps/g3dlite/source/Color3.cpp
Normal file
384
modules/acore/deps/g3dlite/source/Color3.cpp
Normal file
@@ -0,0 +1,384 @@
|
||||
/**
|
||||
@file Color3.cpp
|
||||
|
||||
Color class.
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2010-01-28
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include <stdlib.h>
|
||||
#include "G3D/Color3.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Color3uint8.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Color3::Color3(const Any& any) {
|
||||
*this = Color3::zero();
|
||||
any.verifyName("Color3");
|
||||
std::string name = toLower(any.name());
|
||||
|
||||
switch (any.type()) {
|
||||
case Any::TABLE:
|
||||
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "r") {
|
||||
r = it->value;
|
||||
} else if (key == "g") {
|
||||
g = it->value;
|
||||
} else if (key == "b") {
|
||||
b = it->value;
|
||||
} else {
|
||||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Any::ARRAY:
|
||||
if (name == "color3") {
|
||||
any.verifySize(3);
|
||||
r = any[0];
|
||||
g = any[1];
|
||||
b = any[2];
|
||||
} else if (name == "color3::one") {
|
||||
any.verifySize(0);
|
||||
*this = one();
|
||||
} else if (name == "color3::zero") {
|
||||
any.verifySize(0);
|
||||
*this = zero();
|
||||
} else if (name == "color3::fromargb") {
|
||||
*this = Color3::fromARGB((int)any[0].number());
|
||||
} else {
|
||||
any.verify(false, "Expected Color3 constructor");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
any.verify(false, "Bad Color3 constructor");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Color3::operator Any() const {
|
||||
Any a(Any::ARRAY, "Color3");
|
||||
a.append(r, g, b);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
Color3 Color3::ansiMap(uint32 i) {
|
||||
static const Color3 map[] =
|
||||
{Color3::black(), Color3::red() * 0.75f, Color3::green() * 0.75f, Color3::yellow() * 0.75f,
|
||||
Color3::blue() * 0.75f, Color3::purple() * 0.75f, Color3::cyan() * 0.75f, Color3::white() * 0.75f,
|
||||
Color3::white() * 0.90f, Color3::red(), Color3::green(), Color3::yellow(), Color3::blue(),
|
||||
Color3::purple(), Color3::cyan(), Color3::white()};
|
||||
|
||||
return map[i & 15];
|
||||
}
|
||||
|
||||
|
||||
Color3 Color3::pastelMap(uint32 i) {
|
||||
uint32 x = Crypto::crc32(&i, sizeof(uint32));
|
||||
// Create fairly bright, saturated colors
|
||||
Vector3 v(((x >> 22) & 1023) / 1023.0f,
|
||||
(((x >> 11) & 2047) / 2047.0f) * 0.5f + 0.25f,
|
||||
((x & 2047) / 2047.0f) * 0.75f + 0.25f);
|
||||
return Color3::fromHSV(v);
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::red() {
|
||||
static Color3 c(1.0f, 0.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::green() {
|
||||
static Color3 c(0.0f, 1.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::blue() {
|
||||
static Color3 c(0.0f, 0.0f, 1.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::purple() {
|
||||
static Color3 c(0.7f, 0.0f, 1.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::cyan() {
|
||||
static Color3 c(0.0f, 0.7f, 1.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::yellow() {
|
||||
static Color3 c(1.0f, 1.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::brown() {
|
||||
static Color3 c(0.5f, 0.5f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::orange() {
|
||||
static Color3 c(1.0f, 0.5f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::black() {
|
||||
static Color3 c(0.0f, 0.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
const Color3& Color3::zero() {
|
||||
static Color3 c(0.0f, 0.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::one() {
|
||||
static Color3 c(1.0f, 1.0f, 1.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::gray() {
|
||||
static Color3 c(0.7f, 0.7f, 0.7f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::white() {
|
||||
static Color3 c(1, 1, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
bool Color3::isFinite() const {
|
||||
return G3D::isFinite(r) && G3D::isFinite(g) && G3D::isFinite(b);
|
||||
}
|
||||
|
||||
|
||||
Color3::Color3(BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Color3::deserialize(BinaryInput& bi) {
|
||||
r = bi.readFloat32();
|
||||
g = bi.readFloat32();
|
||||
b = bi.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Color3::serialize(BinaryOutput& bo) const {
|
||||
bo.writeFloat32(r);
|
||||
bo.writeFloat32(g);
|
||||
bo.writeFloat32(b);
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::wheelRandom() {
|
||||
static const Color3 colorArray[8] =
|
||||
{Color3::blue(), Color3::red(), Color3::green(),
|
||||
Color3::orange(), Color3::yellow(),
|
||||
Color3::cyan(), Color3::purple(), Color3::brown()};
|
||||
|
||||
return colorArray[iRandom(0, 7)];
|
||||
}
|
||||
|
||||
|
||||
size_t Color3::hashCode() const {
|
||||
unsigned int rhash = (*(int*)(void*)(&r));
|
||||
unsigned int ghash = (*(int*)(void*)(&g));
|
||||
unsigned int bhash = (*(int*)(void*)(&b));
|
||||
|
||||
return rhash + (ghash * 37) + (bhash * 101);
|
||||
}
|
||||
|
||||
|
||||
Color3::Color3(const Vector3& v) {
|
||||
r = v.x;
|
||||
g = v.y;
|
||||
b = v.z;
|
||||
}
|
||||
|
||||
|
||||
Color3::Color3(const class Color3uint8& other) {
|
||||
r = other.r / 255.0f;
|
||||
g = other.g / 255.0f;
|
||||
b = other.b / 255.0f;
|
||||
}
|
||||
|
||||
|
||||
Color3 Color3::fromARGB(uint32 x) {
|
||||
return Color3((float)((x >> 16) & 0xFF), (float)((x >> 8) & 0xFF), (float)(x & 0xFF)) / 255.0f;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
Color3 Color3::random() {
|
||||
return Color3(uniformRandom(),
|
||||
uniformRandom(),
|
||||
uniformRandom()).direction();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Color3& Color3::operator/= (float fScalar) {
|
||||
if (fScalar != 0.0f) {
|
||||
float fInvScalar = 1.0f / fScalar;
|
||||
r *= fInvScalar;
|
||||
g *= fInvScalar;
|
||||
b *= fInvScalar;
|
||||
} else {
|
||||
r = (float)G3D::finf();
|
||||
g = (float)G3D::finf();
|
||||
b = (float)G3D::finf();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Color3::unitize (float fTolerance) {
|
||||
float fLength = length();
|
||||
|
||||
if ( fLength > fTolerance ) {
|
||||
float fInvLength = 1.0f / fLength;
|
||||
r *= fInvLength;
|
||||
g *= fInvLength;
|
||||
b *= fInvLength;
|
||||
} else {
|
||||
fLength = 0.0f;
|
||||
}
|
||||
|
||||
return fLength;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Color3 Color3::fromHSV(const Vector3& _hsv) {
|
||||
debugAssertM((_hsv.x <= 1.0f && _hsv.x >= 0.0f)
|
||||
&& (_hsv.y <= 1.0f && _hsv.y >= 0.0f)
|
||||
&& ( _hsv.z <= 1.0f && _hsv.z >= 0.0f), "H,S,V must be between [0,1]");
|
||||
const int i = iMin(5, G3D::iFloor(6.0 * _hsv.x));
|
||||
const float f = 6.0f * _hsv.x - i;
|
||||
const float m = _hsv.z * (1.0f - (_hsv.y));
|
||||
const float n = _hsv.z * (1.0f - (_hsv.y * f));
|
||||
const float k = _hsv.z * (1.0f - (_hsv.y * (1 - f)));
|
||||
switch(i) {
|
||||
case 0:
|
||||
return Color3(_hsv.z, k, m);
|
||||
|
||||
case 1:
|
||||
return Color3(n, _hsv.z, m);
|
||||
|
||||
case 2:
|
||||
return Color3(m, _hsv.z, k);
|
||||
|
||||
case 3:
|
||||
return Color3(m, n, _hsv.z);
|
||||
|
||||
case 4:
|
||||
return Color3(k, m, _hsv.z);
|
||||
|
||||
case 5:
|
||||
return Color3(_hsv.z, m, n);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "fell through switch..");
|
||||
}
|
||||
return Color3::black();
|
||||
}
|
||||
|
||||
|
||||
Vector3 Color3::toHSV(const Color3& _rgb) {
|
||||
debugAssertM((_rgb.r <= 1.0f && _rgb.r >= 0.0f)
|
||||
&& (_rgb.g <= 1.0f && _rgb.g >= 0.0f)
|
||||
&& (_rgb.b <= 1.0f && _rgb.b >= 0.0f), "R,G,B must be between [0,1]");
|
||||
Vector3 hsv = Vector3::zero();
|
||||
hsv.z = G3D::max(G3D::max(_rgb.r, _rgb.g), _rgb.b);
|
||||
if (G3D::fuzzyEq(hsv.z, 0.0f)) {
|
||||
return hsv;
|
||||
}
|
||||
|
||||
const float x = G3D::min(G3D::min(_rgb.r, _rgb.g), _rgb.b);
|
||||
hsv.y = (hsv.z - x) / hsv.z;
|
||||
|
||||
if (G3D::fuzzyEq(hsv.y, 0.0f)) {
|
||||
return hsv;
|
||||
}
|
||||
|
||||
Vector3 rgbN;
|
||||
rgbN.x = (hsv.z - _rgb.r) / (hsv.z - x);
|
||||
rgbN.y = (hsv.z - _rgb.g) / (hsv.z - x);
|
||||
rgbN.z = (hsv.z - _rgb.b) / (hsv.z - x);
|
||||
|
||||
if (_rgb.r == hsv.z) { // note from the max we know that it exactly equals one of the three.
|
||||
hsv.x = (_rgb.g == x)? 5.0f + rgbN.z : 1.0f - rgbN.y;
|
||||
} else if (_rgb.g == hsv.z) {
|
||||
hsv.x = (_rgb.b == x)? 1.0f + rgbN.x : 3.0f - rgbN.z;
|
||||
} else {
|
||||
hsv.x = (_rgb.r == x)? 3.0f + rgbN.y : 5.0f - rgbN.x;
|
||||
}
|
||||
|
||||
hsv.x /= 6.0f;
|
||||
|
||||
return hsv;
|
||||
}
|
||||
|
||||
Color3 Color3::jetColorMap(const float& val) {
|
||||
debugAssertM(val <= 1.0f && val >= 0.0f , "value should be in [0,1]");
|
||||
|
||||
//truncated triangles where sides have slope 4
|
||||
Color3 jet;
|
||||
|
||||
jet.r = G3D::min(4.0f * val - 1.5f,-4.0f * val + 4.5f) ;
|
||||
jet.g = G3D::min(4.0f * val - 0.5f,-4.0f * val + 3.5f) ;
|
||||
jet.b = G3D::min(4.0f * val + 0.5f,-4.0f * val + 2.5f) ;
|
||||
|
||||
|
||||
jet.r = G3D::clamp(jet.r, 0.0f, 1.0f);
|
||||
jet.g = G3D::clamp(jet.g, 0.0f, 1.0f);
|
||||
jet.b = G3D::clamp(jet.b, 0.0f, 1.0f);
|
||||
|
||||
return jet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
std::string Color3::toString() const {
|
||||
return G3D::format("(%g, %g, %g)", r, g, b);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Color3 Color3::rainbowColorMap(float hue) {
|
||||
return fromHSV(Vector3(hue, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
|
||||
}; // namespace
|
||||
|
||||
45
modules/acore/deps/g3dlite/source/Color3uint8.cpp
Normal file
45
modules/acore/deps/g3dlite/source/Color3uint8.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
@file Color3uint8.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-04-07
|
||||
@edited 2006-01-07
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Color3uint8.h"
|
||||
#include "G3D/Color3.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Color3uint8::Color3uint8(const class Color3& c) {
|
||||
r = iMin(255, iFloor(c.r * 256));
|
||||
g = iMin(255, iFloor(c.g * 256));
|
||||
b = iMin(255, iFloor(c.b * 256));
|
||||
}
|
||||
|
||||
|
||||
Color3uint8::Color3uint8(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Color3uint8::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeUInt8(r);
|
||||
bo.writeUInt8(g);
|
||||
bo.writeUInt8(b);
|
||||
}
|
||||
|
||||
|
||||
void Color3uint8::deserialize(class BinaryInput& bi) {
|
||||
r = bi.readUInt8();
|
||||
g = bi.readUInt8();
|
||||
b = bi.readUInt8();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
192
modules/acore/deps/g3dlite/source/Color4.cpp
Normal file
192
modules/acore/deps/g3dlite/source/Color4.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
@file Color4.cpp
|
||||
|
||||
Color class.
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@cite Portions by Laura Wollstadt, graphics3d.com
|
||||
@cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com
|
||||
|
||||
|
||||
@created 2002-06-25
|
||||
@edited 2009-11-10
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/Vector4.h"
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Color4::Color4(const Any& any) {
|
||||
*this = Color4::zero();
|
||||
any.verifyName("Color4");
|
||||
|
||||
if (any.type() == Any::TABLE) {
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "r") {
|
||||
r = it->value;
|
||||
} else if (key == "g") {
|
||||
g = it->value;
|
||||
} else if (key == "b") {
|
||||
b = it->value;
|
||||
} else if (key == "a") {
|
||||
a = it->value;
|
||||
} else {
|
||||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
} else if (toLower(any.name()) == "color4") {
|
||||
r = any[0];
|
||||
g = any[1];
|
||||
b = any[2];
|
||||
a = any[3];
|
||||
} else {
|
||||
any.verifyName("Color4::fromARGB");
|
||||
*this = Color4::fromARGB((int)any[0].number());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Color4::operator Any() const {
|
||||
Any any(Any::ARRAY, "Color4");
|
||||
any.append(r, g, b, a);
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
const Color4& Color4::one() {
|
||||
const static Color4 x(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
const Color4& Color4::zero() {
|
||||
static Color4 c(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color4& Color4::inf() {
|
||||
static Color4 c((float)G3D::finf(), (float)G3D::finf(), (float)G3D::finf(), (float)G3D::finf());
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color4& Color4::nan() {
|
||||
static Color4 c((float)G3D::fnan(), (float)G3D::fnan(), (float)G3D::fnan(), (float)G3D::fnan());
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color4& Color4::clear() {
|
||||
return Color4::zero();
|
||||
}
|
||||
|
||||
|
||||
Color4::Color4(const Vector4& v) {
|
||||
r = v.x;
|
||||
g = v.y;
|
||||
b = v.z;
|
||||
a = v.w;
|
||||
}
|
||||
|
||||
|
||||
Color4::Color4(const Color4uint8& c) : r(c.r), g(c.g), b(c.b), a(c.a) {
|
||||
*this /= 255.0f;
|
||||
}
|
||||
|
||||
size_t Color4::hashCode() const {
|
||||
unsigned int rhash = (*(int*)(void*)(&r));
|
||||
unsigned int ghash = (*(int*)(void*)(&g));
|
||||
unsigned int bhash = (*(int*)(void*)(&b));
|
||||
unsigned int ahash = (*(int*)(void*)(&a));
|
||||
|
||||
return rhash + (ghash * 37) + (bhash * 101) + (ahash * 241);
|
||||
}
|
||||
|
||||
Color4 Color4::fromARGB(uint32 x) {
|
||||
return Color4(
|
||||
(float)((x >> 16) & 0xFF),
|
||||
(float)((x >> 8) & 0xFF),
|
||||
(float)(x & 0xFF),
|
||||
(float)((x >> 24) & 0xFF)) / 255.0;
|
||||
}
|
||||
|
||||
|
||||
Color4::Color4(BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Color4::deserialize(BinaryInput& bi) {
|
||||
r = bi.readFloat32();
|
||||
g = bi.readFloat32();
|
||||
b = bi.readFloat32();
|
||||
a = bi.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Color4::serialize(BinaryOutput& bo) const {
|
||||
bo.writeFloat32(r);
|
||||
bo.writeFloat32(g);
|
||||
bo.writeFloat32(b);
|
||||
bo.writeFloat32(a);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Color4 Color4::operator/ (float fScalar) const {
|
||||
Color4 kQuot;
|
||||
|
||||
if (fScalar != 0.0f) {
|
||||
float fInvScalar = 1.0f / fScalar;
|
||||
kQuot.r = fInvScalar * r;
|
||||
kQuot.g = fInvScalar * g;
|
||||
kQuot.b = fInvScalar * b;
|
||||
kQuot.a = fInvScalar * a;
|
||||
return kQuot;
|
||||
|
||||
} else {
|
||||
|
||||
return Color4::inf();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Color4& Color4::operator/= (float fScalar) {
|
||||
if (fScalar != 0.0f) {
|
||||
float fInvScalar = 1.0f / fScalar;
|
||||
r *= fInvScalar;
|
||||
g *= fInvScalar;
|
||||
b *= fInvScalar;
|
||||
a *= fInvScalar;
|
||||
} else {
|
||||
r = (float)G3D::finf();
|
||||
g = (float)G3D::finf();
|
||||
b = (float)G3D::finf();
|
||||
a = (float)G3D::finf();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
std::string Color4::toString() const {
|
||||
return G3D::format("(%g, %g, %g, %g)", r, g, b, a);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace
|
||||
|
||||
47
modules/acore/deps/g3dlite/source/Color4uint8.cpp
Normal file
47
modules/acore/deps/g3dlite/source/Color4uint8.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
@file Color4uint8.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-04-07
|
||||
@edited 2006-01-07
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Color4uint8::Color4uint8(const class Color4& c) {
|
||||
r = iMin(255, iFloor(c.r * 256));
|
||||
g = iMin(255, iFloor(c.g * 256));
|
||||
b = iMin(255, iFloor(c.b * 256));
|
||||
a = iMin(255, iFloor(c.a * 256));
|
||||
}
|
||||
|
||||
|
||||
Color4uint8::Color4uint8(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Color4uint8::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeUInt8(r);
|
||||
bo.writeUInt8(g);
|
||||
bo.writeUInt8(b);
|
||||
bo.writeUInt8(a);
|
||||
}
|
||||
|
||||
|
||||
void Color4uint8::deserialize(class BinaryInput& bi) {
|
||||
r = bi.readUInt8();
|
||||
g = bi.readUInt8();
|
||||
b = bi.readUInt8();
|
||||
a = bi.readUInt8();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
79
modules/acore/deps/g3dlite/source/Cone.cpp
Normal file
79
modules/acore/deps/g3dlite/source/Cone.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
@file Cone.cpp
|
||||
|
||||
Cone class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-07-09
|
||||
@edited 2006-01-29
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Cone.h"
|
||||
#include "G3D/Line.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/Box.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Cone::Cone(const Vector3 &tip, const Vector3 &direction, float angle) {
|
||||
this->tip = tip;
|
||||
this->direction = direction.direction();
|
||||
this->angle = angle;
|
||||
|
||||
debugAssert(angle >= 0);
|
||||
debugAssert(angle <= pi());
|
||||
}
|
||||
|
||||
/**
|
||||
Forms the smallest cone that contains the box. Undefined if
|
||||
the tip is inside or on the box.
|
||||
*/
|
||||
Cone::Cone(const Vector3& tip, const Box& box) {
|
||||
this->tip = tip;
|
||||
this->direction = (box.center() - tip).direction();
|
||||
|
||||
// Find the biggest angle
|
||||
float smallestDotProduct = direction.dot((box.corner(0) - tip).direction());
|
||||
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
float dp = direction.dot((box.corner(i) - tip).direction());
|
||||
|
||||
debugAssert(dp > 0);
|
||||
|
||||
if (dp < smallestDotProduct) {
|
||||
smallestDotProduct = dp;
|
||||
}
|
||||
}
|
||||
|
||||
angle = acosf(smallestDotProduct);
|
||||
}
|
||||
|
||||
|
||||
bool Cone::intersects(const Sphere& b) const {
|
||||
// If the bounding sphere contains the tip, then
|
||||
// they definitely touch.
|
||||
if (b.contains(this->tip)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Move the tip backwards, effectively making the cone bigger
|
||||
// to account for the radius of the sphere.
|
||||
|
||||
Vector3 tip = this->tip - direction * b.radius / sinf(angle);
|
||||
|
||||
return Cone(tip, direction, angle).contains(b.center);
|
||||
}
|
||||
|
||||
|
||||
bool Cone::contains(const Vector3& v) const {
|
||||
|
||||
Vector3 d = (v - tip).direction();
|
||||
|
||||
float x = d.dot(direction);
|
||||
|
||||
return (x > 0) && (x >= cosf(angle));
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
457
modules/acore/deps/g3dlite/source/ConvexPolyhedron.cpp
Normal file
457
modules/acore/deps/g3dlite/source/ConvexPolyhedron.cpp
Normal file
@@ -0,0 +1,457 @@
|
||||
/**
|
||||
@file ConvexPolyhedron.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-11-11
|
||||
@edited 2009-08-10
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/ConvexPolyhedron.h"
|
||||
#include "G3D/debug.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
ConvexPolygon::ConvexPolygon(const Array<Vector3>& __vertex) : _vertex(__vertex) {
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
|
||||
ConvexPolygon::ConvexPolygon(const Vector3& v0, const Vector3& v1, const Vector3& v2) {
|
||||
_vertex.append(v0, v1, v2);
|
||||
}
|
||||
|
||||
|
||||
bool ConvexPolygon::isEmpty() const {
|
||||
return (_vertex.length() == 0) || (getArea() <= fuzzyEpsilon);
|
||||
}
|
||||
|
||||
|
||||
float ConvexPolygon::getArea() const {
|
||||
|
||||
if (_vertex.length() < 3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float sum = 0;
|
||||
|
||||
int length = _vertex.length();
|
||||
// Split into triangle fan, compute individual area
|
||||
for (int v = 2; v < length; v++) {
|
||||
int i0 = 0;
|
||||
int i1 = v - 1;
|
||||
int i2 = v;
|
||||
|
||||
sum += (_vertex[i1] - _vertex[i0]).cross(_vertex[i2] - _vertex[i0]).magnitude() / 2;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
void ConvexPolygon::cut(const Plane& plane, ConvexPolygon &above, ConvexPolygon &below) {
|
||||
DirectedEdge edge;
|
||||
cut(plane, above, below, edge);
|
||||
}
|
||||
|
||||
void ConvexPolygon::cut(const Plane& plane, ConvexPolygon &above, ConvexPolygon &below, DirectedEdge &newEdge) {
|
||||
above._vertex.resize(0);
|
||||
below._vertex.resize(0);
|
||||
|
||||
if (isEmpty()) {
|
||||
//debugPrintf("Empty\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int v = 0;
|
||||
int length = _vertex.length();
|
||||
|
||||
|
||||
Vector3 polyNormal = normal();
|
||||
Vector3 planeNormal= plane.normal();
|
||||
|
||||
// See if the polygon is *in* the plane.
|
||||
if (planeNormal.fuzzyEq(polyNormal) || planeNormal.fuzzyEq(-polyNormal)) {
|
||||
// Polygon is parallel to the plane. It must be either above,
|
||||
// below, or in the plane.
|
||||
|
||||
double a, b, c, d;
|
||||
Vector3 pt = _vertex[0];
|
||||
|
||||
plane.getEquation(a,b,c,d);
|
||||
float r = (float)(a * pt.x + b * pt.y + c * pt.z + d);
|
||||
|
||||
if (fuzzyGe(r, 0)) {
|
||||
// The polygon is entirely in the plane.
|
||||
//debugPrintf("Entirely above\n");
|
||||
above = *this;
|
||||
return;
|
||||
} else {
|
||||
//debugPrintf("Entirely below (1)\n");
|
||||
below = *this;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Number of edges crossing the plane. Used for
|
||||
// debug assertions.
|
||||
int count = 0;
|
||||
|
||||
// True when the last _vertex we looked at was above the plane
|
||||
bool lastAbove = plane.halfSpaceContains(_vertex[v]);
|
||||
|
||||
if (lastAbove) {
|
||||
above._vertex.append(_vertex[v]);
|
||||
} else {
|
||||
below._vertex.append(_vertex[v]);
|
||||
}
|
||||
|
||||
for (v = 1; v < length; v++) {
|
||||
bool isAbove = plane.halfSpaceContains(_vertex[v]);
|
||||
|
||||
if (lastAbove ^ isAbove) {
|
||||
// Switched sides.
|
||||
// Create an interpolated point that lies
|
||||
// in the plane, between the two points.
|
||||
Line line = Line::fromTwoPoints(_vertex[v - 1], _vertex[v]);
|
||||
Vector3 interp = line.intersection(plane);
|
||||
|
||||
if (! interp.isFinite()) {
|
||||
|
||||
// Since the polygon is not in the plane (we checked above),
|
||||
// it must be the case that this edge (and only this edge)
|
||||
// is in the plane. This only happens when the polygon is
|
||||
// entirely below the plane except for one edge. This edge
|
||||
// forms a degenerate polygon, so just treat the whole polygon
|
||||
// as below the plane.
|
||||
below = *this;
|
||||
above._vertex.resize(0);
|
||||
//debugPrintf("Entirely below\n");
|
||||
return;
|
||||
}
|
||||
|
||||
above._vertex.append(interp);
|
||||
below._vertex.append(interp);
|
||||
if (lastAbove) {
|
||||
newEdge.stop = interp;
|
||||
} else {
|
||||
newEdge.start = interp;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
lastAbove = isAbove;
|
||||
if (lastAbove) {
|
||||
above._vertex.append(_vertex[v]);
|
||||
} else {
|
||||
below._vertex.append(_vertex[v]);
|
||||
}
|
||||
}
|
||||
|
||||
// Loop back to the first point, seeing if an interpolated point is
|
||||
// needed.
|
||||
bool isAbove = plane.halfSpaceContains(_vertex[0]);
|
||||
if (lastAbove ^ isAbove) {
|
||||
Line line = Line::fromTwoPoints(_vertex[length - 1], _vertex[0]);
|
||||
Vector3 interp = line.intersection(plane);
|
||||
if (! interp.isFinite()) {
|
||||
// Since the polygon is not in the plane (we checked above),
|
||||
// it must be the case that this edge (and only this edge)
|
||||
// is in the plane. This only happens when the polygon is
|
||||
// entirely below the plane except for one edge. This edge
|
||||
// forms a degenerate polygon, so just treat the whole polygon
|
||||
// as below the plane.
|
||||
below = *this;
|
||||
above._vertex.resize(0);
|
||||
//debugPrintf("Entirely below\n");
|
||||
return;
|
||||
}
|
||||
|
||||
above._vertex.append(interp);
|
||||
below._vertex.append(interp);
|
||||
debugAssertM(count < 2, "Convex polygons may only intersect planes at two edges.");
|
||||
if (lastAbove) {
|
||||
newEdge.stop = interp;
|
||||
} else {
|
||||
newEdge.start = interp;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
|
||||
debugAssertM((count == 2) || (count == 0), "Convex polygons may only intersect planes at two edges.");
|
||||
}
|
||||
|
||||
|
||||
ConvexPolygon ConvexPolygon::inverse() const {
|
||||
ConvexPolygon result;
|
||||
int length = _vertex.length();
|
||||
result._vertex.resize(length);
|
||||
|
||||
for (int v = 0; v < length; v++) {
|
||||
result._vertex[v] = _vertex[length - v - 1];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void ConvexPolygon::removeDuplicateVertices(){
|
||||
// Any valid polygon should have 3 or more vertices, but why take chances?
|
||||
if (_vertex.size() >= 2){
|
||||
|
||||
// Remove duplicate vertices.
|
||||
for (int i=0;i<_vertex.size()-1;++i){
|
||||
if (_vertex[i].fuzzyEq(_vertex[i+1])){
|
||||
_vertex.remove(i+1);
|
||||
--i; // Don't move forward.
|
||||
}
|
||||
}
|
||||
|
||||
// Check the last vertex against the first.
|
||||
if (_vertex[_vertex.size()-1].fuzzyEq(_vertex[0])){
|
||||
_vertex.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ConvexPolyhedron::ConvexPolyhedron(const Array<ConvexPolygon>& _face) : face(_face) {
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
|
||||
float ConvexPolyhedron::getVolume() const {
|
||||
|
||||
if (face.length() < 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The volume of any pyramid is 1/3 * h * base area.
|
||||
// Discussion at: http://nrich.maths.org/mathsf/journalf/oct01/art1/
|
||||
|
||||
float sum = 0;
|
||||
|
||||
// Choose the first _vertex of the first face as the origin.
|
||||
// This lets us skip one face, too, and avoids negative heights.
|
||||
Vector3 v0 = face[0]._vertex[0];
|
||||
for (int f = 1; f < face.length(); f++) {
|
||||
const ConvexPolygon& poly = face[f];
|
||||
|
||||
float height = (poly._vertex[0] - v0).dot(poly.normal());
|
||||
float base = poly.getArea();
|
||||
|
||||
sum += height * base;
|
||||
}
|
||||
|
||||
return sum / 3;
|
||||
}
|
||||
|
||||
bool ConvexPolyhedron::isEmpty() const {
|
||||
return (face.length() == 0) || (getVolume() <= fuzzyEpsilon);
|
||||
}
|
||||
|
||||
void ConvexPolyhedron::cut(const Plane& plane, ConvexPolyhedron &above, ConvexPolyhedron &below) {
|
||||
above.face.resize(0);
|
||||
below.face.resize(0);
|
||||
|
||||
Array<DirectedEdge> edge;
|
||||
|
||||
int f;
|
||||
|
||||
// See if the plane cuts this polyhedron at all. Detect when
|
||||
// the polyhedron is entirely to one side or the other.
|
||||
//{
|
||||
int numAbove = 0, numIn = 0, numBelow = 0;
|
||||
bool ruledOut = false;
|
||||
double d;
|
||||
Vector3 abc;
|
||||
plane.getEquation(abc, d);
|
||||
|
||||
// This number has to be fairly large to prevent precision problems down
|
||||
// the road.
|
||||
const float eps = 0.005f;
|
||||
for (f = face.length() - 1; (f >= 0) && (!ruledOut); f--) {
|
||||
const ConvexPolygon& poly = face[f];
|
||||
for (int v = poly._vertex.length() - 1; (v >= 0) && (!ruledOut); v--) {
|
||||
double r = abc.dot(poly._vertex[v]) + d;
|
||||
if (r > eps) {
|
||||
numAbove++;
|
||||
} else if (r < -eps) {
|
||||
numBelow++;
|
||||
} else {
|
||||
numIn++;
|
||||
}
|
||||
|
||||
ruledOut = (numAbove != 0) && (numBelow !=0);
|
||||
}
|
||||
}
|
||||
|
||||
if (numBelow == 0) {
|
||||
above = *this;
|
||||
return;
|
||||
} else if (numAbove == 0) {
|
||||
below = *this;
|
||||
return;
|
||||
}
|
||||
//}
|
||||
|
||||
// Clip each polygon, collecting split edges.
|
||||
for (f = face.length() - 1; f >= 0; f--) {
|
||||
ConvexPolygon a, b;
|
||||
DirectedEdge e;
|
||||
face[f].cut(plane, a, b, e);
|
||||
|
||||
bool aEmpty = a.isEmpty();
|
||||
bool bEmpty = b.isEmpty();
|
||||
|
||||
//debugPrintf("\n");
|
||||
if (! aEmpty) {
|
||||
//debugPrintf(" Above %f\n", a.getArea());
|
||||
above.face.append(a);
|
||||
}
|
||||
|
||||
if (! bEmpty) {
|
||||
//debugPrintf(" Below %f\n", b.getArea());
|
||||
below.face.append(b);
|
||||
}
|
||||
|
||||
if (! aEmpty && ! bEmpty) {
|
||||
//debugPrintf(" == Split\n");
|
||||
edge.append(e);
|
||||
} else {
|
||||
// Might be the case that the polygon is entirely on
|
||||
// one side of the plane yet there is an edge we need
|
||||
// because it touches the plane.
|
||||
//
|
||||
// Extract the non-empty _vertex list and examine it.
|
||||
// If we find exactly one edge in the plane, add that edge.
|
||||
const Array<Vector3>& _vertex = (aEmpty ? b._vertex : a._vertex);
|
||||
int L = _vertex.length();
|
||||
int count = 0;
|
||||
for (int v = 0; v < L; v++) {
|
||||
if (plane.fuzzyContains(_vertex[v]) && plane.fuzzyContains(_vertex[(v + 1) % L])) {
|
||||
e.start = _vertex[v];
|
||||
e.stop = _vertex[(v + 1) % L];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
edge.append(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (above.face.length() == 1) {
|
||||
// Only one face above means that this entire
|
||||
// polyhedron is below the plane. Move that face over.
|
||||
below.face.append(above.face[0]);
|
||||
above.face.resize(0);
|
||||
} else if (below.face.length() == 1) {
|
||||
// This shouldn't happen, but it arises in practice
|
||||
// from numerical imprecision.
|
||||
above.face.append(below.face[0]);
|
||||
below.face.resize(0);
|
||||
}
|
||||
|
||||
if ((above.face.length() > 0) && (below.face.length() > 0)) {
|
||||
// The polyhedron was actually cut; create a cap polygon
|
||||
ConvexPolygon cap;
|
||||
|
||||
// Collect the final polgyon by sorting the edges
|
||||
int numVertices = edge.length();
|
||||
/*debugPrintf("\n");
|
||||
for (int xx=0; xx < numVertices; xx++) {
|
||||
std::string s1 = edge[xx].start.toString();
|
||||
std::string s2 = edge[xx].stop.toString();
|
||||
debugPrintf("%s -> %s\n", s1.c_str(), s2.c_str());
|
||||
}
|
||||
*/
|
||||
|
||||
// Need at least three points to make a polygon
|
||||
debugAssert(numVertices >= 3);
|
||||
|
||||
Vector3 last_vertex = edge.last().stop;
|
||||
cap._vertex.append(last_vertex);
|
||||
|
||||
// Search for the next _vertex. Because of accumulating
|
||||
// numerical error, we have to find the closest match, not
|
||||
// just the one we expect.
|
||||
for (int v = numVertices - 1; v >= 0; v--) {
|
||||
// matching edge index
|
||||
int index = 0;
|
||||
int num = edge.length();
|
||||
double distance = (edge[index].start - last_vertex).squaredMagnitude();
|
||||
for (int e = 1; e < num; e++) {
|
||||
double d = (edge[e].start - last_vertex).squaredMagnitude();
|
||||
|
||||
if (d < distance) {
|
||||
// This is the new closest one
|
||||
index = e;
|
||||
distance = d;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't tolerate ridiculous error.
|
||||
debugAssertM(distance < 0.02, "Edge missing while closing polygon.");
|
||||
|
||||
last_vertex = edge[index].stop;
|
||||
cap._vertex.append(last_vertex);
|
||||
}
|
||||
|
||||
//debugPrintf("\n");
|
||||
//debugPrintf("Cap (both) %f\n", cap.getArea());
|
||||
above.face.append(cap);
|
||||
below.face.append(cap.inverse());
|
||||
}
|
||||
|
||||
// Make sure we put enough faces on each polyhedra
|
||||
debugAssert((above.face.length() == 0) || (above.face.length() >= 4));
|
||||
debugAssert((below.face.length() == 0) || (below.face.length() >= 4));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
|
||||
ConvexPolygon2D::ConvexPolygon2D(const Array<Vector2>& pts, bool reverse) : m_vertex(pts) {
|
||||
if (reverse) {
|
||||
m_vertex.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ConvexPolygon2D::contains(const Vector2& p, bool reverse) const {
|
||||
// Compute the signed area of each polygon from p to an edge.
|
||||
// If the area is non-negative for all polygons then p is inside
|
||||
// the polygon. (To adapt this algorithm for a concave polygon,
|
||||
// the *sum* of the areas must be non-negative).
|
||||
|
||||
float r = reverse ? -1 : 1;
|
||||
|
||||
for (int i0 = 0; i0 < m_vertex.size(); ++i0) {
|
||||
int i1 = (i0 + 1) % m_vertex.size();
|
||||
const Vector2& v0 = m_vertex[i0];
|
||||
const Vector2& v1 = m_vertex[i1];
|
||||
|
||||
Vector2 e0 = v0 - p;
|
||||
Vector2 e1 = v1 - p;
|
||||
|
||||
// Area = (1/2) cross product, negated to be ccw in
|
||||
// a 2D space; we neglect the 1/2
|
||||
float area = -(e0.x * e1.y - e0.y * e1.x);
|
||||
|
||||
if (area * r < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
465
modules/acore/deps/g3dlite/source/CoordinateFrame.cpp
Normal file
465
modules/acore/deps/g3dlite/source/CoordinateFrame.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
/**
|
||||
@file CoordinateFrame.cpp
|
||||
|
||||
Coordinate frame class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2010-03-13
|
||||
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Quat.h"
|
||||
#include "G3D/Matrix4.h"
|
||||
#include "G3D/Box.h"
|
||||
#include "G3D/AABox.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/Triangle.h"
|
||||
#include "G3D/Ray.h"
|
||||
#include "G3D/Capsule.h"
|
||||
#include "G3D/Cylinder.h"
|
||||
#include "G3D/UprightFrame.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/PhysicsFrame.h"
|
||||
#include "G3D/UprightFrame.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
std::string CoordinateFrame::toXYZYPRDegreesString() const {
|
||||
UprightFrame uframe(*this);
|
||||
|
||||
return format("CFrame::fromXYZYPRDegrees(% 5.1ff, % 5.1ff, % 5.1ff, % 5.1ff, % 5.1ff, % 5.1ff)",
|
||||
uframe.translation.x, uframe.translation.y, uframe.translation.z,
|
||||
toDegrees(uframe.yaw), toDegrees(uframe.pitch), 0.0f);
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame::CoordinateFrame(const Any& any) {
|
||||
*this = CFrame();
|
||||
|
||||
const std::string& n = toUpper(any.name());
|
||||
|
||||
if (beginsWith(n, "VECTOR3")) {
|
||||
translation = any;
|
||||
} else if (beginsWith(n, "MATRIX3")) {
|
||||
rotation = any;
|
||||
} else if ((n == "CFRAME") || (n == "COORDINATEFRAME")) {
|
||||
any.verifyType(Any::TABLE, Any::ARRAY);
|
||||
if (any.type() == Any::ARRAY) {
|
||||
any.verifySize(2);
|
||||
rotation = any[0];
|
||||
translation = any[1];
|
||||
} else {
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& n = toLower(it->key);
|
||||
if (n == "translation") {
|
||||
translation = Vector3(it->value);
|
||||
} else if (n == "rotation") {
|
||||
rotation = Matrix3(it->value);
|
||||
} else {
|
||||
any.verify(false, "Illegal table key: " + it->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (beginsWith(n, "PHYSICSFRAME") || beginsWith(n, "PFRAME")) {
|
||||
*this = PhysicsFrame(any);
|
||||
} else {
|
||||
any.verifyName("CFrame::fromXYZYPRDegrees", "CoordinateFrame::fromXYZYPRDegrees");
|
||||
any.verifyType(Any::ARRAY);
|
||||
any.verifySize(3, 6);
|
||||
|
||||
int s = any.size();
|
||||
|
||||
*this = fromXYZYPRDegrees(any[0], any[1], any[2],
|
||||
(s > 3) ? any[3].number() : 0.0f,
|
||||
(s > 4) ? any[4].number() : 0.0f,
|
||||
(s > 5) ? any[5].number() : 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame::operator Any() const {
|
||||
float x, y, z, yaw, pitch, roll;
|
||||
getXYZYPRDegrees(x, y, z, yaw, pitch, roll);
|
||||
Any a(Any::ARRAY, "CFrame::fromXYZYPRDegrees");
|
||||
a.append(x, y, z, yaw);
|
||||
if ( ! G3D::fuzzyEq(yaw, 0.0f) || ! G3D::fuzzyEq(pitch, 0.0f) || ! G3D::fuzzyEq(roll, 0.0f)) {
|
||||
a.append(yaw);
|
||||
if (! G3D::fuzzyEq(pitch, 0.0f) || ! G3D::fuzzyEq(roll, 0.0f)) {
|
||||
a.append(pitch);
|
||||
if (! G3D::fuzzyEq(roll, 0.0f)) {
|
||||
a.append(roll);
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame::CoordinateFrame(const class UprightFrame& f) {
|
||||
*this = f.toCoordinateFrame();
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame::CoordinateFrame() :
|
||||
rotation(Matrix3::identity()), translation(Vector3::zero()) {
|
||||
}
|
||||
|
||||
CoordinateFrame CoordinateFrame::fromXYZYPRRadians(float x, float y, float z, float yaw,
|
||||
float pitch, float roll) {
|
||||
Matrix3 rotation = Matrix3::fromAxisAngle(Vector3::unitY(), yaw);
|
||||
|
||||
rotation = Matrix3::fromAxisAngle(rotation.column(0), pitch) * rotation;
|
||||
rotation = Matrix3::fromAxisAngle(rotation.column(2), roll) * rotation;
|
||||
|
||||
const Vector3 translation(x, y, z);
|
||||
|
||||
return CoordinateFrame(rotation, translation);
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::getXYZYPRRadians(float& x, float& y, float& z,
|
||||
float& yaw, float& pitch, float& roll) const {
|
||||
x = translation.x;
|
||||
y = translation.y;
|
||||
z = translation.z;
|
||||
|
||||
const Vector3& look = lookVector();
|
||||
|
||||
if (abs(look.y) > 0.99f) {
|
||||
// Looking nearly straight up or down
|
||||
|
||||
yaw = G3D::pi() + atan2(look.x, look.z);
|
||||
pitch = asin(look.y);
|
||||
roll = 0.0f;
|
||||
|
||||
} else {
|
||||
|
||||
// Yaw cannot be affected by others, so pull it first
|
||||
yaw = G3D::pi() + atan2(look.x, look.z);
|
||||
|
||||
// Pitch is the elevation of the yaw vector
|
||||
pitch = asin(look.y);
|
||||
|
||||
Vector3 actualRight = rightVector();
|
||||
Vector3 expectedRight = look.cross(Vector3::unitY());
|
||||
|
||||
roll = 0;//acos(actualRight.dot(expectedRight)); TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::getXYZYPRDegrees(float& x, float& y, float& z,
|
||||
float& yaw, float& pitch, float& roll) const {
|
||||
getXYZYPRRadians(x, y, z, yaw, pitch, roll);
|
||||
yaw = toDegrees(yaw);
|
||||
pitch = toDegrees(pitch);
|
||||
roll = toDegrees(roll);
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame CoordinateFrame::fromXYZYPRDegrees(float x, float y, float z,
|
||||
float yaw, float pitch, float roll) {
|
||||
return fromXYZYPRRadians(x, y, z, toRadians(yaw), toRadians(pitch), toRadians(roll));
|
||||
}
|
||||
|
||||
|
||||
Ray CoordinateFrame::lookRay() const {
|
||||
return Ray::fromOriginAndDirection(translation, lookVector());
|
||||
}
|
||||
|
||||
|
||||
bool CoordinateFrame::fuzzyEq(const CoordinateFrame& other) const {
|
||||
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
if (! G3D::fuzzyEq(other.rotation[r][c], rotation[r][c])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (! G3D::fuzzyEq(translation[c], other.translation[c])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CoordinateFrame::fuzzyIsIdentity() const {
|
||||
const Matrix3& I = Matrix3::identity();
|
||||
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
if (fuzzyNe(I[r][c], rotation[r][c])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fuzzyNe(translation[c], 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CoordinateFrame::isIdentity() const {
|
||||
return
|
||||
(translation == Vector3::zero()) &&
|
||||
(rotation == Matrix3::identity());
|
||||
}
|
||||
|
||||
|
||||
Matrix4 CoordinateFrame::toMatrix4() const {
|
||||
return Matrix4(*this);
|
||||
}
|
||||
|
||||
|
||||
std::string CoordinateFrame::toXML() const {
|
||||
return G3D::format(
|
||||
"<COORDINATEFRAME>\n %lf,%lf,%lf,%lf,\n %lf,%lf,%lf,%lf,\n %lf,%lf,%lf,%lf,\n %lf,%lf,%lf,%lf\n</COORDINATEFRAME>\n",
|
||||
rotation[0][0], rotation[0][1], rotation[0][2], translation.x,
|
||||
rotation[1][0], rotation[1][1], rotation[1][2], translation.y,
|
||||
rotation[2][0], rotation[2][1], rotation[2][2], translation.z,
|
||||
0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
|
||||
Plane CoordinateFrame::toObjectSpace(const Plane& p) const {
|
||||
Vector3 N, P;
|
||||
double d;
|
||||
p.getEquation(N, d);
|
||||
P = N * (float)d;
|
||||
P = pointToObjectSpace(P);
|
||||
N = normalToObjectSpace(N);
|
||||
return Plane(N, P);
|
||||
}
|
||||
|
||||
|
||||
Plane CoordinateFrame::toWorldSpace(const Plane& p) const {
|
||||
Vector3 N, P;
|
||||
double d;
|
||||
p.getEquation(N, d);
|
||||
P = N * (float)d;
|
||||
P = pointToWorldSpace(P);
|
||||
N = normalToWorldSpace(N);
|
||||
return Plane(N, P);
|
||||
}
|
||||
|
||||
|
||||
Triangle CoordinateFrame::toObjectSpace(const Triangle& t) const {
|
||||
return Triangle(pointToObjectSpace(t.vertex(0)),
|
||||
pointToObjectSpace(t.vertex(1)),
|
||||
pointToObjectSpace(t.vertex(2)));
|
||||
}
|
||||
|
||||
|
||||
Triangle CoordinateFrame::toWorldSpace(const Triangle& t) const {
|
||||
return Triangle(pointToWorldSpace(t.vertex(0)),
|
||||
pointToWorldSpace(t.vertex(1)),
|
||||
pointToWorldSpace(t.vertex(2)));
|
||||
}
|
||||
|
||||
|
||||
Cylinder CoordinateFrame::toWorldSpace(const Cylinder& c) const {
|
||||
return Cylinder(
|
||||
pointToWorldSpace(c.point(0)),
|
||||
pointToWorldSpace(c.point(1)),
|
||||
c.radius());
|
||||
}
|
||||
|
||||
|
||||
Capsule CoordinateFrame::toWorldSpace(const Capsule& c) const {
|
||||
return Capsule(
|
||||
pointToWorldSpace(c.point(0)),
|
||||
pointToWorldSpace(c.point(1)),
|
||||
c.radius());
|
||||
}
|
||||
|
||||
|
||||
Box CoordinateFrame::toWorldSpace(const AABox& b) const {
|
||||
Box b2(b);
|
||||
return toWorldSpace(b2);
|
||||
}
|
||||
|
||||
|
||||
Box CoordinateFrame::toWorldSpace(const Box& b) const {
|
||||
Box out(b);
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
out._corner[i] = pointToWorldSpace(b._corner[i]);
|
||||
debugAssert(! isNaN(out._corner[i].x));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
out._axis[i] = vectorToWorldSpace(b._axis[i]);
|
||||
}
|
||||
|
||||
out._center = pointToWorldSpace(b._center);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Box CoordinateFrame::toObjectSpace(const Box &b) const {
|
||||
return inverse().toWorldSpace(b);
|
||||
}
|
||||
|
||||
|
||||
Box CoordinateFrame::toObjectSpace(const AABox& b) const {
|
||||
return toObjectSpace(Box(b));
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame::CoordinateFrame(class BinaryInput& b) : rotation(Matrix3::zero()) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::deserialize(class BinaryInput& b) {
|
||||
rotation.deserialize(b);
|
||||
translation.deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::serialize(class BinaryOutput& b) const {
|
||||
rotation.serialize(b);
|
||||
translation.serialize(b);
|
||||
}
|
||||
|
||||
|
||||
Sphere CoordinateFrame::toWorldSpace(const Sphere &b) const {
|
||||
return Sphere(pointToWorldSpace(b.center), b.radius);
|
||||
}
|
||||
|
||||
|
||||
Sphere CoordinateFrame::toObjectSpace(const Sphere &b) const {
|
||||
return Sphere(pointToObjectSpace(b.center), b.radius);
|
||||
}
|
||||
|
||||
|
||||
Ray CoordinateFrame::toWorldSpace(const Ray& r) const {
|
||||
return Ray::fromOriginAndDirection(pointToWorldSpace(r.origin()), vectorToWorldSpace(r.direction()));
|
||||
}
|
||||
|
||||
|
||||
Ray CoordinateFrame::toObjectSpace(const Ray& r) const {
|
||||
return Ray::fromOriginAndDirection(pointToObjectSpace(r.origin()), vectorToObjectSpace(r.direction()));
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::lookAt(const Vector3 &target) {
|
||||
lookAt(target, Vector3::unitY());
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::lookAt(
|
||||
const Vector3& target,
|
||||
Vector3 up) {
|
||||
|
||||
up = up.direction();
|
||||
|
||||
Vector3 look = (target - translation).direction();
|
||||
if (fabs(look.dot(up)) > .99f) {
|
||||
up = Vector3::unitX();
|
||||
if (fabs(look.dot(up)) > .99f) {
|
||||
up = Vector3::unitY();
|
||||
}
|
||||
}
|
||||
|
||||
up -= look * look.dot(up);
|
||||
up.unitize();
|
||||
|
||||
Vector3 z = -look;
|
||||
Vector3 x = -z.cross(up);
|
||||
x.unitize();
|
||||
|
||||
Vector3 y = z.cross(x);
|
||||
|
||||
rotation.setColumn(0, x);
|
||||
rotation.setColumn(1, y);
|
||||
rotation.setColumn(2, z);
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame CoordinateFrame::lerp(
|
||||
const CoordinateFrame& other,
|
||||
float alpha) const {
|
||||
|
||||
if (alpha == 1.0f) {
|
||||
return other;
|
||||
} else if (alpha == 0.0f) {
|
||||
return *this;
|
||||
} else {
|
||||
const Quat q1(this->rotation);
|
||||
const Quat q2(other.rotation);
|
||||
|
||||
return CoordinateFrame(
|
||||
q1.slerp(q2, alpha).toRotationMatrix(),
|
||||
translation * (1 - alpha) + other.translation * alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::pointToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
|
||||
vout.resize(v.size());
|
||||
|
||||
for (int i = 0; i < v.size(); ++i) {
|
||||
vout[i] = pointToWorldSpace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::normalToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
|
||||
vout.resize(v.size());
|
||||
|
||||
for (int i = 0; i < v.size(); ++i) {
|
||||
vout[i] = normalToWorldSpace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::vectorToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
|
||||
vout.resize(v.size());
|
||||
|
||||
for (int i = v.size() - 1; i >= 0; --i) {
|
||||
vout[i] = vectorToWorldSpace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::pointToObjectSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
|
||||
vout.resize(v.size());
|
||||
|
||||
for (int i = v.size() - 1; i >= 0; --i) {
|
||||
vout[i] = pointToObjectSpace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::normalToObjectSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
|
||||
vout.resize(v.size());
|
||||
|
||||
for (int i = v.size() - 1; i >= 0; --i) {
|
||||
vout[i] = normalToObjectSpace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CoordinateFrame::vectorToObjectSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
|
||||
vout.resize(v.size());
|
||||
|
||||
for (int i = v.size() - 1; i >= 0; --i) {
|
||||
vout[i] = vectorToObjectSpace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
70
modules/acore/deps/g3dlite/source/Crypto.cpp
Normal file
70
modules/acore/deps/g3dlite/source/Crypto.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
@file Crypto.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
|
||||
@created 2006-03-28
|
||||
@edited 2006-04-06
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Crypto.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include <zlib.h>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
int Crypto::smallPrime(int n) {
|
||||
debugAssert(n < numSmallPrimes() && n >= 0);
|
||||
|
||||
// From:
|
||||
// http://primes.utm.edu/lists/small/1000.txt
|
||||
|
||||
static const int table[] = {
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
||||
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
||||
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
|
||||
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
|
||||
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
|
||||
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
|
||||
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
|
||||
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
|
||||
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
|
||||
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
|
||||
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
|
||||
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
|
||||
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
|
||||
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
|
||||
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
|
||||
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
|
||||
947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013,
|
||||
1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
|
||||
1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
|
||||
1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
|
||||
1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
|
||||
1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373,
|
||||
1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
|
||||
1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
|
||||
1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
|
||||
1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657,
|
||||
1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
|
||||
1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
|
||||
1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
|
||||
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
|
||||
1993, 1997, 1999};
|
||||
|
||||
return table[n];
|
||||
}
|
||||
|
||||
|
||||
int Crypto::numSmallPrimes() {
|
||||
return 303;
|
||||
}
|
||||
|
||||
uint32 Crypto::crc32(const void* byte, size_t numBytes) {
|
||||
return ::crc32(::crc32(0, Z_NULL, 0), static_cast<const Bytef *>(byte), numBytes);
|
||||
}
|
||||
|
||||
} // G3D
|
||||
471
modules/acore/deps/g3dlite/source/Crypto_md5.cpp
Normal file
471
modules/acore/deps/g3dlite/source/Crypto_md5.cpp
Normal file
@@ -0,0 +1,471 @@
|
||||
/**
|
||||
@file Crypto_md5.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
Copyright 2006-2007, Morgan McGuire. All rights reserved.
|
||||
|
||||
@created 2006-03-28
|
||||
@edited 2006-04-06
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Crypto.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
MD5Hash::MD5Hash(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void MD5Hash::deserialize(class BinaryInput& b) {
|
||||
b.readBytes(value, 16);
|
||||
}
|
||||
|
||||
|
||||
void MD5Hash::serialize(class BinaryOutput& b) const {
|
||||
b.writeBytes(value, 16);
|
||||
}
|
||||
|
||||
|
||||
typedef unsigned char md5_byte_t; /* 8-bit byte */
|
||||
typedef unsigned int md5_word_t; /* 32-bit word */
|
||||
|
||||
/* Define the state of the MD5 Algorithm. */
|
||||
typedef struct md5_state_s {
|
||||
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||
md5_word_t abcd[4]; /* digest buffer */
|
||||
md5_byte_t buf[64]; /* accumulate block */
|
||||
} md5_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Initialize the algorithm. */
|
||||
static void md5_init(md5_state_t *pms);
|
||||
|
||||
/* Append a string to the message. */
|
||||
static void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
|
||||
|
||||
/* Finish the message and return the digest. */
|
||||
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
MD5Hash Crypto::md5(const void* data, size_t n) {
|
||||
md5_state_t state;
|
||||
md5_init(&state);
|
||||
md5_append(&state, (const uint8*)data, (int)n);
|
||||
|
||||
MD5Hash h;
|
||||
md5_finish(&state, &(h[0]));
|
||||
return h;
|
||||
}
|
||||
|
||||
/*
|
||||
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.c is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
|
||||
either statically or dynamically; added missing #include <string.h>
|
||||
in library.
|
||||
2002-03-11 lpd Corrected argument list for main(), and added int return
|
||||
type, in test program and T value program.
|
||||
2002-02-21 lpd Added missing #include <stdio.h> in test program.
|
||||
2000-07-03 lpd Patched to eliminate warnings about "constant is
|
||||
unsigned in ANSI C, signed in traditional"; made test program
|
||||
self-checking.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This package supports both compile-time and run-time determination of CPU
|
||||
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
|
||||
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
|
||||
* defined as non-zero, the code will be compiled to run only on big-endian
|
||||
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
|
||||
* run on either big- or little-endian CPUs, but will run slightly less
|
||||
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
|
||||
*/
|
||||
|
||||
|
||||
#if defined(G3D_LINUX) || defined(G3D_OSX)
|
||||
# if defined(G3D_OSX_PPC)
|
||||
# include <ppc/endian.h>
|
||||
# elif defined(G3D_OSX_INTEL)
|
||||
# include <i386/endian.h>
|
||||
# elif defined(__linux__)
|
||||
# include <endian.h>
|
||||
# elif defined(__FreeBSD__)
|
||||
# include <sys/endian.h>
|
||||
# endif
|
||||
#else
|
||||
# define BYTE_ORDER 0
|
||||
#endif
|
||||
|
||||
#define T_MASK ((md5_word_t)~0)
|
||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||
#define T3 0x242070db
|
||||
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||
#define T6 0x4787c62a
|
||||
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||
#define T9 0x698098d8
|
||||
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
||||
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
||||
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
||||
#define T13 0x6b901122
|
||||
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||
#define T16 0x49b40821
|
||||
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||
#define T19 0x265e5a51
|
||||
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||
#define T22 0x02441453
|
||||
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||
#define T25 0x21e1cde6
|
||||
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||
#define T28 0x455a14ed
|
||||
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||
#define T31 0x676f02d9
|
||||
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
||||
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
||||
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
||||
#define T35 0x6d9d6122
|
||||
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||
#define T38 0x4bdecfa9
|
||||
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||
#define T41 0x289b7ec6
|
||||
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||
#define T44 0x04881d05
|
||||
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||
#define T47 0x1fa27cf8
|
||||
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||
#define T50 0x432aff97
|
||||
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||
#define T53 0x655b59c3
|
||||
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
||||
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
||||
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
||||
#define T57 0x6fa87e4f
|
||||
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||
#define T60 0x4e0811a1
|
||||
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
|
||||
static void
|
||||
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
||||
{
|
||||
md5_word_t
|
||||
a = pms->abcd[0], b = pms->abcd[1],
|
||||
c = pms->abcd[2], d = pms->abcd[3];
|
||||
md5_word_t t;
|
||||
#if BYTE_ORDER > 0
|
||||
/* Define storage only for big-endian CPUs. */
|
||||
md5_word_t X[16];
|
||||
#else
|
||||
/* Define storage for little-endian or both types of CPUs. */
|
||||
md5_word_t xbuf[16];
|
||||
const md5_word_t *X;
|
||||
#endif
|
||||
|
||||
{
|
||||
#if BYTE_ORDER == 0
|
||||
/*
|
||||
* Determine dynamically whether this is a big-endian or
|
||||
* little-endian machine, since we can use a more efficient
|
||||
* algorithm on the latter.
|
||||
*/
|
||||
static const int w = 1;
|
||||
|
||||
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER <= 0 /* little-endian */
|
||||
{
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!((data - (const md5_byte_t *)0) & 3)) {
|
||||
/* data are properly aligned */
|
||||
X = (const md5_word_t *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if BYTE_ORDER == 0
|
||||
else /* dynamic big-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER >= 0 /* big-endian */
|
||||
{
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const md5_byte_t *xp = data;
|
||||
int i;
|
||||
|
||||
# if BYTE_ORDER == 0
|
||||
X = xbuf; /* (dynamic only) */
|
||||
# else
|
||||
# define xbuf X /* (static only) */
|
||||
# endif
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + F(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + G(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + H(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + I(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
#undef SET
|
||||
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
pms->abcd[0] += a;
|
||||
pms->abcd[1] += b;
|
||||
pms->abcd[2] += c;
|
||||
pms->abcd[3] += d;
|
||||
}
|
||||
|
||||
void
|
||||
md5_init(md5_state_t *pms)
|
||||
{
|
||||
pms->count[0] = pms->count[1] = 0;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void
|
||||
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
|
||||
{
|
||||
const md5_byte_t *p = data;
|
||||
int left = nbytes;
|
||||
int offset = (pms->count[0] >> 3) & 63;
|
||||
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
pms->count[1] += nbytes >> 29;
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset) {
|
||||
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
|
||||
memcpy(pms->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(pms, pms->buf);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
void
|
||||
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
|
||||
{
|
||||
static const md5_byte_t pad[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
md5_byte_t data[8];
|
||||
int i;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
md5_append(pms, data, 8);
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
|
||||
}
|
||||
176
modules/acore/deps/g3dlite/source/Cylinder.cpp
Normal file
176
modules/acore/deps/g3dlite/source/Cylinder.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
@file Cylinder.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-02-07
|
||||
@edited 2006-02-18
|
||||
|
||||
Copyright 2000-2006, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Cylinder.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/LineSegment.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Line.h"
|
||||
#include "G3D/AABox.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Cylinder::Cylinder(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
Cylinder::Cylinder() {
|
||||
}
|
||||
|
||||
|
||||
Cylinder::Cylinder(const Vector3& _p1, const Vector3& _p2, float _r)
|
||||
: p1(_p1), p2(_p2), mRadius(_r) {
|
||||
}
|
||||
|
||||
|
||||
void Cylinder::serialize(class BinaryOutput& b) const {
|
||||
p1.serialize(b);
|
||||
p2.serialize(b);
|
||||
b.writeFloat64(mRadius);
|
||||
}
|
||||
|
||||
|
||||
void Cylinder::deserialize(class BinaryInput& b) {
|
||||
p1.deserialize(b);
|
||||
p2.deserialize(b);
|
||||
mRadius = b.readFloat64();
|
||||
}
|
||||
|
||||
|
||||
Line Cylinder::axis() const {
|
||||
return Line::fromTwoPoints(p1, p2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
float Cylinder::radius() const {
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
|
||||
float Cylinder::volume() const {
|
||||
return
|
||||
(float)pi() * square(mRadius) * (p1 - p2).magnitude();
|
||||
}
|
||||
|
||||
|
||||
float Cylinder::area() const {
|
||||
return
|
||||
// Sides
|
||||
(twoPi() * mRadius) * height() +
|
||||
|
||||
// Caps
|
||||
twoPi() * square(mRadius);
|
||||
}
|
||||
|
||||
void Cylinder::getBounds(AABox& out) const {
|
||||
Vector3 min = p1.min(p2) - (Vector3(1, 1, 1) * mRadius);
|
||||
Vector3 max = p1.max(p2) + (Vector3(1, 1, 1) * mRadius);
|
||||
out = AABox(min, max);
|
||||
}
|
||||
|
||||
bool Cylinder::contains(const Vector3& p) const {
|
||||
return LineSegment::fromTwoPoints(p1, p2).distanceSquared(p) <= square(mRadius);
|
||||
}
|
||||
|
||||
|
||||
void Cylinder::getReferenceFrame(CoordinateFrame& cframe) const {
|
||||
cframe.translation = center();
|
||||
|
||||
Vector3 Y = (p1 - p2).direction();
|
||||
Vector3 X = (abs(Y.dot(Vector3::unitX())) > 0.9) ? Vector3::unitY() : Vector3::unitX();
|
||||
Vector3 Z = X.cross(Y).direction();
|
||||
X = Y.cross(Z);
|
||||
cframe.rotation.setColumn(0, X);
|
||||
cframe.rotation.setColumn(1, Y);
|
||||
cframe.rotation.setColumn(2, Z);
|
||||
}
|
||||
|
||||
|
||||
void Cylinder::getRandomSurfacePoint(Vector3& p, Vector3& N) const {
|
||||
float h = height();
|
||||
float r = radius();
|
||||
|
||||
// Create a random point on a standard cylinder and then rotate to the global frame.
|
||||
|
||||
// Relative areas (factor of 2PI already taken out)
|
||||
float capRelArea = square(r) / 2.0f;
|
||||
float sideRelArea = r * h;
|
||||
|
||||
float r1 = uniformRandom(0, capRelArea * 2 + sideRelArea);
|
||||
|
||||
if (r1 < capRelArea * 2) {
|
||||
|
||||
// Select a point uniformly at random on a disk
|
||||
// @cite http://mathworld.wolfram.com/DiskPointPicking.html
|
||||
float a = uniformRandom(0, (float)twoPi());
|
||||
float r2 = sqrt(uniformRandom(0, 1)) * r;
|
||||
p.x = cos(a) * r2;
|
||||
p.z = sin(a) * r2;
|
||||
|
||||
N.x = 0;
|
||||
N.z = 0;
|
||||
if (r1 < capRelArea) {
|
||||
// Top
|
||||
p.y = h / 2.0f;
|
||||
N.y = 1;
|
||||
} else {
|
||||
// Bottom
|
||||
p.y = -h / 2.0f;
|
||||
N.y = -1;
|
||||
}
|
||||
} else {
|
||||
// Side
|
||||
float a = uniformRandom(0, (float)twoPi());
|
||||
N.x = cos(a);
|
||||
N.y = 0;
|
||||
N.z = sin(a);
|
||||
p.x = N.x * r;
|
||||
p.z = N.y * r;
|
||||
p.y = uniformRandom(-h / 2.0f, h / 2.0f);
|
||||
}
|
||||
|
||||
// Transform to world space
|
||||
CoordinateFrame cframe;
|
||||
getReferenceFrame(cframe);
|
||||
|
||||
p = cframe.pointToWorldSpace(p);
|
||||
N = cframe.normalToWorldSpace(N);
|
||||
}
|
||||
|
||||
|
||||
Vector3 Cylinder::randomInteriorPoint() const {
|
||||
float h = height();
|
||||
float r = radius();
|
||||
|
||||
// Create a random point in a standard cylinder and then rotate to the global frame.
|
||||
|
||||
// Select a point uniformly at random on a disk
|
||||
// @cite http://mathworld.wolfram.com/DiskPointPicking.html
|
||||
float a = uniformRandom(0, (float)twoPi());
|
||||
float r2 = sqrt(uniformRandom(0, 1)) * r;
|
||||
|
||||
Vector3 p( cos(a) * r2,
|
||||
uniformRandom(-h / 2.0f, h / 2.0f),
|
||||
sin(a) * r2);
|
||||
|
||||
// Transform to world space
|
||||
CoordinateFrame cframe;
|
||||
getReferenceFrame(cframe);
|
||||
|
||||
return cframe.pointToWorldSpace(p);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
874
modules/acore/deps/g3dlite/source/FileSystem.cpp
Normal file
874
modules/acore/deps/g3dlite/source/FileSystem.cpp
Normal file
@@ -0,0 +1,874 @@
|
||||
/**
|
||||
@file FileSystem.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@author 2002-06-06
|
||||
@edited 2010-04-10
|
||||
*/
|
||||
#include "G3D/FileSystem.h"
|
||||
#include "G3D/System.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
#include "zip.h"
|
||||
#endif
|
||||
#include "G3D/g3dfnmatch.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
// Needed for _getcwd
|
||||
# include <direct.h>
|
||||
|
||||
// Needed for _findfirst
|
||||
# include <io.h>
|
||||
# ifdef __MINGW32__
|
||||
# define stat64 stat
|
||||
# else
|
||||
# define stat64 _stat64
|
||||
# endif
|
||||
#else
|
||||
# include <dirent.h>
|
||||
# include <fnmatch.h>
|
||||
# include <unistd.h>
|
||||
# define _getcwd getcwd
|
||||
# define _stat stat
|
||||
#endif
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
#define stat64 stat
|
||||
#endif
|
||||
|
||||
namespace G3D {
|
||||
|
||||
static FileSystem* common = NULL;
|
||||
|
||||
FileSystem& FileSystem::instance() {
|
||||
init();
|
||||
return *common;
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::init() {
|
||||
if (common == NULL) {
|
||||
common = new FileSystem();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::cleanup() {
|
||||
if (common != NULL) {
|
||||
delete common;
|
||||
common = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
FileSystem::FileSystem() : m_cacheLifetime(10) {}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
bool FileSystem::Dir::contains(const std::string& f) const {
|
||||
|
||||
for (int i = 0; i < nodeArray.size(); ++i) {
|
||||
# ifdef G3D_WIN32
|
||||
if (stricmp(f.c_str(), nodeArray[i].name.c_str()) == 0) {
|
||||
return true;
|
||||
}
|
||||
# else
|
||||
if (f == nodeArray[i].name) {
|
||||
return true;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::string& pathInsideZipfile) {
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
struct zip* z = zip_open( FilePath::removeTrailingSlash(zipfile).c_str(), ZIP_CHECKCONS, NULL );
|
||||
debugAssert(z);
|
||||
|
||||
int count = zip_get_num_files( z );
|
||||
Set<std::string> alreadyAdded;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
struct zip_stat info;
|
||||
zip_stat_init( &info ); // TODO: Docs unclear if zip_stat_init is required.
|
||||
zip_stat_index( z, i, ZIP_FL_NOCASE, &info );
|
||||
|
||||
// Fully-qualified name of a file inside zipfile
|
||||
std::string name = info.name;
|
||||
|
||||
if (beginsWith(name, pathInsideZipfile)) {
|
||||
// We found something inside the directory we were looking for,
|
||||
// so the directory itself must exist
|
||||
exists = true;
|
||||
|
||||
// For building the cached directory listing, extract only elements that do not contain
|
||||
// additional subdirectories.
|
||||
|
||||
int start = pathInsideZipfile.size();
|
||||
if ((int(name.length()) > start) && isSlash(name[start])) {
|
||||
++start;
|
||||
}
|
||||
int end = findSlash(name, start);
|
||||
if (end == -1) {
|
||||
// There are no more slashes; add this name
|
||||
name = name.substr(start);
|
||||
if (alreadyAdded.insert(name)) {
|
||||
Entry& e = nodeArray.next();
|
||||
e.name = name;
|
||||
e.type = FILE_TYPE;
|
||||
}
|
||||
} else {
|
||||
// There are more slashes, indicating that this is a directory
|
||||
name = name.substr(start, end);
|
||||
if (alreadyAdded.insert(name)) {
|
||||
Entry& e = nodeArray.next();
|
||||
e.name = name;
|
||||
e.type = DIR_TYPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zip_close(z);
|
||||
z = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpdate) {
|
||||
const std::string& key =
|
||||
# if defined(G3D_WIN32)
|
||||
FilePath::canonicalize(FilePath::removeTrailingSlash(toLower(FilePath::canonicalize(resolve(path)))));
|
||||
# else
|
||||
FilePath::canonicalize(FilePath::removeTrailingSlash(FilePath::canonicalize(resolve(path))));
|
||||
# endif
|
||||
|
||||
RealTime now = System::time();
|
||||
Dir& dir = m_cache.getCreate(key);
|
||||
|
||||
if ((now > dir.lastChecked + cacheLifetime()) || forceUpdate) {
|
||||
dir = Dir();
|
||||
|
||||
// Out of date: update
|
||||
dir.lastChecked = now;
|
||||
|
||||
struct _stat st;
|
||||
const bool exists = _stat(key.c_str(), &st) != -1;
|
||||
const bool isDirectory = (st.st_mode & S_IFDIR) != 0;
|
||||
|
||||
// Does this path exist on the real filesystem?
|
||||
if (exists && isDirectory) {
|
||||
|
||||
// Is this path actually a directory?
|
||||
if (isDirectory) {
|
||||
dir.exists = true;
|
||||
// Update contents
|
||||
# ifdef G3D_WIN32
|
||||
const std::string& filespec = FilePath::concat(key, "*");
|
||||
struct _finddata_t fileinfo;
|
||||
intptr_t handle = _findfirst(filespec.c_str(), &fileinfo);
|
||||
debugAssert(handle != -1);
|
||||
int result = 0;
|
||||
do {
|
||||
if ((strcmp(fileinfo.name, ".") != 0) && (strcmp(fileinfo.name, "..") != 0)) {
|
||||
Entry& e = dir.nodeArray.next();
|
||||
e.name = fileinfo.name;
|
||||
if ((fileinfo.attrib & _A_SUBDIR) != 0) {
|
||||
e.type = DIR_TYPE;
|
||||
} else {
|
||||
e.type = FILE_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
result = _findnext(handle, &fileinfo);
|
||||
} while (result == 0);
|
||||
_findclose(handle);
|
||||
|
||||
# else
|
||||
DIR* listing = opendir(key.c_str());
|
||||
debugAssertM(listing, "opendir failed on '" + key + "'");
|
||||
struct dirent* entry = readdir(listing);
|
||||
while (entry != NULL) {
|
||||
if ((strcmp(entry->d_name, "..") != 0) && (strcmp(entry->d_name, ".") != 0)) {
|
||||
Entry& e = dir.nodeArray.next();
|
||||
e.name = entry->d_name;
|
||||
|
||||
# ifdef _DIRENT_HAVE_D_TYPE
|
||||
// Not all POSIX systems support this field
|
||||
// http://www.delorie.com/gnu/docs/glibc/libc_270.html
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR:
|
||||
e.type = DIR_TYPE;
|
||||
break;
|
||||
|
||||
case DT_REG:
|
||||
e.type = FILE_TYPE;
|
||||
break;
|
||||
|
||||
case DT_UNKNOWN:
|
||||
default:
|
||||
e.type = UNKNOWN;
|
||||
break;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
entry = readdir(listing);
|
||||
}
|
||||
closedir(listing);
|
||||
listing = NULL;
|
||||
entry = NULL;
|
||||
# endif
|
||||
}
|
||||
|
||||
} else {
|
||||
std::string zip;
|
||||
|
||||
if (exists && isZipfile(path)) {
|
||||
// This is a zipfile; get its root
|
||||
dir.isZipfile = true;
|
||||
dir.computeZipListing(path, "");
|
||||
|
||||
} else if (inZipfile(path, zip)) {
|
||||
|
||||
// There is a zipfile somewhere in the path. Does
|
||||
// the rest of the path exist inside the zipfile?
|
||||
dir.inZipfile = true;
|
||||
|
||||
dir.computeZipListing(zip, path.substr(zip.length() + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::_inZipfile(const std::string& path, std::string& z) {
|
||||
// Reject trivial cases before parsing
|
||||
if (path.find('.') == std::string::npos) {
|
||||
// There is no zipfile possible, since G3D requires
|
||||
// an extension on zipfiles.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look at all sub-paths containing periods.
|
||||
// For each, ask if it is a zipfile.
|
||||
int current = 0;
|
||||
current = path.find('.', current);
|
||||
|
||||
while (current != -1) {
|
||||
// xxxxx/foo.zip/yyyyy
|
||||
current = path.find('.', current);
|
||||
|
||||
// Look forward for the next slash
|
||||
int s = findSlash(path, current);
|
||||
|
||||
if (s == -1) {
|
||||
// No more slashes
|
||||
return false;
|
||||
}
|
||||
|
||||
z = path.substr(0, s);
|
||||
if (_isZipfile(z)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
current = s + 1;
|
||||
}
|
||||
|
||||
z = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::_isZipfile(const std::string& filename) {
|
||||
if (FilePath::ext(filename).empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* f = fopen(FilePath::removeTrailingSlash(filename).c_str(), "r");
|
||||
if (f == NULL) {
|
||||
return false;
|
||||
}
|
||||
uint8 header[4];
|
||||
fread(header, 4, 1, f);
|
||||
|
||||
const uint8 zipHeader[4] = {0x50, 0x4b, 0x03, 0x04};
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (header[i] != zipHeader[i]) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
FILE* FileSystem::_fopen(const char* filename, const char* mode) {
|
||||
for (const char* m = mode; *m != '\0'; ++m) {
|
||||
if (*m == 'w') {
|
||||
// Purge the cache entry for the parent of this directory
|
||||
_clearCache(FilePath::parent(_resolve(filename)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ::fopen(filename, mode);
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::_clearCache(const std::string& path) {
|
||||
if ((path == "") || FilePath::isRoot(path)) {
|
||||
m_cache.clear();
|
||||
} else {
|
||||
Array<std::string> keys;
|
||||
m_cache.getKeys(keys);
|
||||
|
||||
const std::string& prefix =
|
||||
# ifdef G3D_WIN32
|
||||
toLower(FilePath::canonicalize(FilePath::removeTrailingSlash(_resolve(path))));
|
||||
# else
|
||||
FilePath::canonicalize(FilePath::removeTrailingSlash(_resolve(path)));
|
||||
# endif
|
||||
const std::string& prefixSlash = prefix + "/";
|
||||
|
||||
for (int k = 0; k < keys.size(); ++k) {
|
||||
const std::string& key = keys[k];
|
||||
if ((key == prefix) || beginsWith(key, prefixSlash)) {
|
||||
m_cache.remove(keys[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::_setCacheLifetime(float t) {
|
||||
m_cacheLifetime = t;
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::_createDirectory(const std::string& dir) {
|
||||
|
||||
if (dir == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string d = _resolve(dir);
|
||||
|
||||
// Add a trailing / if there isn't one.
|
||||
switch (d[d.size() - 1]) {
|
||||
case '/':
|
||||
case '\\':
|
||||
break;
|
||||
|
||||
default:
|
||||
d += "/";
|
||||
}
|
||||
|
||||
// If it already exists, do nothing
|
||||
if (_exists(FilePath::removeTrailingSlash(d))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the name apart
|
||||
std::string root, base, ext;
|
||||
Array<std::string> path;
|
||||
|
||||
std::string lead;
|
||||
FilePath::parse(d, root, path, base, ext);
|
||||
debugAssert(base == "");
|
||||
debugAssert(ext == "");
|
||||
|
||||
// Begin with an extra period so "c:\" becomes "c:\.\" after
|
||||
// appending a path and "c:" becomes "c:.\", not root: "c:\"
|
||||
std::string p = root + ".";
|
||||
|
||||
// Create any intermediate that doesn't exist
|
||||
for (int i = 0; i < path.size(); ++i) {
|
||||
p += "/" + path[i];
|
||||
if (! _exists(p)) {
|
||||
// Windows only requires one argument to mkdir,
|
||||
// where as unix also requires the permissions.
|
||||
# ifndef G3D_WIN32
|
||||
mkdir(p.c_str(), 0777);
|
||||
# else
|
||||
_mkdir(p.c_str());
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
_clearCache(FilePath::parent(FilePath::removeTrailingSlash(d)));
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::_copyFile(const std::string& source, const std::string& dest) {
|
||||
# ifdef G3D_WIN32
|
||||
// TODO: handle case where srcPath is in a zipfile
|
||||
CopyFileA(source.c_str(), dest.c_str(), FALSE);
|
||||
_clearCache(FilePath::parent(_resolve(dest)));
|
||||
# else
|
||||
// Read it all in, then dump it out
|
||||
BinaryInput in(source, G3D_LITTLE_ENDIAN);
|
||||
BinaryOutput out(dest, G3D_LITTLE_ENDIAN);
|
||||
out.writeBytes(in.getCArray(), in.size());
|
||||
out.commit(false);
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::_exists(const std::string& f, bool trustCache) {
|
||||
|
||||
if (FilePath::isRoot(f)) {
|
||||
# ifdef G3D_WIN32
|
||||
const std::string& winname = toLower(f.substr(0, 1)) + ":\\";
|
||||
return _drives().contains(winname);
|
||||
# else
|
||||
return true;
|
||||
# endif
|
||||
}
|
||||
|
||||
std::string path = FilePath::removeTrailingSlash(f);
|
||||
std::string parentPath = FilePath::parent(path);
|
||||
|
||||
const Dir& entry = getContents(parentPath, ! trustCache);
|
||||
|
||||
if (FilePath::containsWildcards(f)) {
|
||||
if (! entry.exists) {
|
||||
// The directory didn't exist, so neither do its contents
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& pattern = FilePath::baseExt(path);
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
static const int flags = FNM_CASEFOLD;
|
||||
# else
|
||||
static const int flags = 0;
|
||||
# endif
|
||||
|
||||
// See if any element of entry matches the wild card
|
||||
for (int i = 0; i < entry.nodeArray.size(); ++i) {
|
||||
if (FilePath::matches(entry.nodeArray[i].name, pattern, flags)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Could not find a match
|
||||
return false;
|
||||
|
||||
} else {
|
||||
return entry.exists && entry.contains(FilePath::baseExt(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::_isDirectory(const std::string& filename) {
|
||||
// TODO: work with zipfiles and cache
|
||||
struct _stat st;
|
||||
const bool exists = _stat(FilePath::removeTrailingSlash(filename).c_str(), &st) != -1;
|
||||
return exists && ((st.st_mode & S_IFDIR) != 0);
|
||||
}
|
||||
|
||||
|
||||
std::string FileSystem::_resolve(const std::string& filename, const std::string& cwd) {
|
||||
if (filename.size() >= 1) {
|
||||
if (isSlash(filename[0])) {
|
||||
// Already resolved
|
||||
return filename;
|
||||
} else {
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
if ((filename.size() >= 2) && (filename[1] == ':')) {
|
||||
// There is a drive spec on the front.
|
||||
if ((filename.size() >= 3) && isSlash(filename[2])) {
|
||||
// Already fully qualified
|
||||
return filename;
|
||||
} else {
|
||||
// The drive spec is relative to the
|
||||
// working directory on that drive.
|
||||
debugAssertM(false, "Files of the form d:path are"
|
||||
" not supported (use a fully qualified"
|
||||
" name).");
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Prepend the working directory.
|
||||
return FilePath::concat(cwd, filename);
|
||||
}
|
||||
|
||||
|
||||
std::string FileSystem::_currentDirectory() {
|
||||
static const int N = 2048;
|
||||
char buffer[N];
|
||||
|
||||
_getcwd(buffer, N);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::_isNewer(const std::string& src, const std::string& dst) {
|
||||
// TODO: work with cache and zipfiles
|
||||
struct _stat sts;
|
||||
bool sexists = _stat(src.c_str(), &sts) != -1;
|
||||
|
||||
struct _stat dts;
|
||||
bool dexists = _stat(dst.c_str(), &dts) != -1;
|
||||
|
||||
return sexists && ((! dexists) || (sts.st_mtime > dts.st_mtime));
|
||||
}
|
||||
|
||||
|
||||
int64 FileSystem::_size(const std::string& filename) {
|
||||
struct stat64 st;
|
||||
int result = stat64(filename.c_str(), &st);
|
||||
|
||||
if (result == -1) {
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
std::string zip, contents;
|
||||
if (zipfileExists(filename, zip, contents)) {
|
||||
int64 requiredMem;
|
||||
|
||||
struct zip *z = zip_open( zip.c_str(), ZIP_CHECKCONS, NULL );
|
||||
debugAssertM(z != NULL, zip + ": zip open failed.");
|
||||
{
|
||||
struct zip_stat info;
|
||||
zip_stat_init( &info ); // Docs unclear if zip_stat_init is required.
|
||||
int success = zip_stat( z, contents.c_str(), ZIP_FL_NOCASE, &info );
|
||||
debugAssertM(success == 0, zip + ": " + contents + ": zip stat failed.");
|
||||
requiredMem = info.size;
|
||||
}
|
||||
zip_close(z);
|
||||
return requiredMem;
|
||||
} else {
|
||||
#endif
|
||||
return -1;
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::listHelper(const std::string& shortSpec, const std::string& parentPath, Array<std::string>& result, const ListSettings& settings) {
|
||||
Dir& dir = getContents(parentPath, false);
|
||||
|
||||
if (! dir.exists) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dir.nodeArray.size(); ++i) {
|
||||
Entry& entry = dir.nodeArray[i];
|
||||
// See if it matches the spec
|
||||
if (FilePath::matches(entry.name, shortSpec, settings.caseSensitive)) {
|
||||
|
||||
if ((entry.type == UNKNOWN) && ! (settings.files && settings.directories)) {
|
||||
// Update the type
|
||||
entry.type = isDirectory(FilePath::concat(parentPath, entry.name)) ? DIR_TYPE : FILE_TYPE;
|
||||
}
|
||||
|
||||
if ((settings.files && settings.directories) ||
|
||||
(settings.files && (entry.type == FILE_TYPE)) ||
|
||||
(settings.directories && (entry.type == DIR_TYPE))) {
|
||||
|
||||
if (settings.includeParentPath) {
|
||||
result.append(FilePath::concat(parentPath, entry.name));
|
||||
} else {
|
||||
result.append(entry.name);
|
||||
}
|
||||
}
|
||||
} // match
|
||||
|
||||
if (settings.recursive && (entry.type == DIR_TYPE)) {
|
||||
listHelper(shortSpec, FilePath::concat(parentPath, entry.name), result, settings);
|
||||
}
|
||||
} // for
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::_list(const std::string& spec, Array<std::string>& result, const ListSettings& settings) {
|
||||
const std::string& shortSpec = FilePath::baseExt(spec);
|
||||
const std::string& parentPath = FilePath::parent(spec);
|
||||
|
||||
listHelper(shortSpec, parentPath, result, settings);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
const Array<std::string>& FileSystem::_drives() {
|
||||
if (m_winDrive.length() == 0) {
|
||||
// See http://msdn.microsoft.com/en-us/library/aa364975(VS.85).aspx
|
||||
static const size_t bufSize = 5000;
|
||||
char bufData[bufSize];
|
||||
GetLogicalDriveStringsA(bufSize, bufData);
|
||||
|
||||
// Drive list is a series of NULL-terminated strings, itself terminated with a NULL.
|
||||
for (int i = 0; bufData[i] != '\0'; ++i) {
|
||||
const char* thisString = bufData + i;
|
||||
m_winDrive.append(toLower(thisString));
|
||||
i += strlen(thisString) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return m_winDrive;
|
||||
}
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool FilePath::isRoot(const std::string& f) {
|
||||
# ifdef G3D_WIN32
|
||||
if (f.length() < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f[1] == ':') {
|
||||
if (f.length() == 2) {
|
||||
// e.g., "x:"
|
||||
return true;
|
||||
} else if ((f.length() == 3) && isSlash(f[2])) {
|
||||
// e.g., "x:\"
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSlash(f[0]) && isSlash(f[1])) {
|
||||
// e.g., "\\foo\"
|
||||
return true;
|
||||
}
|
||||
# else
|
||||
if (f == "/") {
|
||||
return true;
|
||||
}
|
||||
# endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::removeTrailingSlash(const std::string& f) {
|
||||
bool removeSlash = ((endsWith(f, "/") || endsWith(f, "\\"))) && ! isRoot(f);
|
||||
|
||||
return removeSlash ? f.substr(0, f.length() - 1) : f;
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::concat(const std::string& dirname, const std::string& file) {
|
||||
// Ensure that the directory ends in a slash
|
||||
if (! dirname.empty() &&
|
||||
! isSlash(dirname[dirname.size() - 1]) &&
|
||||
(dirname[dirname.size() - 1] != ':')) {
|
||||
return dirname + '/' + file;
|
||||
} else {
|
||||
return dirname + file;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::ext(const std::string& filename) {
|
||||
int i = filename.rfind(".");
|
||||
if (i >= 0) {
|
||||
return filename.substr(i + 1, filename.length() - i);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::baseExt(const std::string& filename) {
|
||||
int i = findLastSlash(filename);
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
int j = filename.rfind(":");
|
||||
if ((i == -1) && (j >= 0)) {
|
||||
i = j;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (i == -1) {
|
||||
return filename;
|
||||
} else {
|
||||
return filename.substr(i + 1, filename.length() - i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::base(const std::string& path) {
|
||||
std::string filename = baseExt(path);
|
||||
int i = filename.rfind(".");
|
||||
if (i == -1) {
|
||||
// No extension
|
||||
return filename;
|
||||
} else {
|
||||
return filename.substr(0, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::parent(const std::string& path) {
|
||||
int i = findLastSlash(removeTrailingSlash(path));
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
int j = path.rfind(":");
|
||||
if ((i == -1) && (j >= 0)) {
|
||||
i = j;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (i == -1) {
|
||||
return "";
|
||||
} else {
|
||||
return path.substr(0, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FilePath::containsWildcards(const std::string& filename) {
|
||||
return (filename.find('*') != std::string::npos) || (filename.find('?') != std::string::npos);
|
||||
}
|
||||
|
||||
|
||||
bool FilePath::matches(const std::string& path, const std::string& pattern, bool caseSensitive) {
|
||||
int flags = FNM_PERIOD | FNM_NOESCAPE | FNM_PATHNAME;
|
||||
if (! caseSensitive) {
|
||||
flags |= FNM_CASEFOLD;
|
||||
}
|
||||
return g3dfnmatch(pattern.c_str(), path.c_str(), flags) == 0;
|
||||
}
|
||||
|
||||
|
||||
static int fixslash(int c) {
|
||||
return (c == '\\') ? '/' : c;
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::canonicalize(std::string x) {
|
||||
std::transform(x.begin(), x.end(), x.begin(), fixslash);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
void FilePath::parse
|
||||
(const std::string& filename,
|
||||
std::string& root,
|
||||
Array<std::string>& path,
|
||||
std::string& base,
|
||||
std::string& ext) {
|
||||
|
||||
std::string f = filename;
|
||||
|
||||
root = "";
|
||||
path.clear();
|
||||
base = "";
|
||||
ext = "";
|
||||
|
||||
if (f == "") {
|
||||
// Empty filename
|
||||
return;
|
||||
}
|
||||
|
||||
// See if there is a root/drive spec.
|
||||
if ((f.size() >= 2) && (f[1] == ':')) {
|
||||
|
||||
if ((f.size() > 2) && isSlash(f[2])) {
|
||||
|
||||
// e.g. c:\foo
|
||||
root = f.substr(0, 3);
|
||||
f = f.substr(3, f.size() - 3);
|
||||
|
||||
} else {
|
||||
|
||||
// e.g. c:foo
|
||||
root = f.substr(2);
|
||||
f = f.substr(2, f.size() - 2);
|
||||
|
||||
}
|
||||
|
||||
} else if ((f.size() >= 2) & isSlash(f[0]) && isSlash(f[1])) {
|
||||
|
||||
// e.g. //foo
|
||||
root = f.substr(0, 2);
|
||||
f = f.substr(2, f.size() - 2);
|
||||
|
||||
} else if (isSlash(f[0])) {
|
||||
|
||||
root = f.substr(0, 1);
|
||||
f = f.substr(1, f.size() - 1);
|
||||
|
||||
}
|
||||
|
||||
// Pull the extension off
|
||||
{
|
||||
// Find the period
|
||||
size_t i = f.rfind('.');
|
||||
|
||||
if (i != std::string::npos) {
|
||||
// Make sure it is after the last slash!
|
||||
size_t j = iMax(f.rfind('/'), f.rfind('\\'));
|
||||
if ((j == std::string::npos) || (i > j)) {
|
||||
ext = f.substr(i + 1, f.size() - i - 1);
|
||||
f = f.substr(0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pull the basename off
|
||||
{
|
||||
// Find the last slash
|
||||
size_t i = iMax(f.rfind('/'), f.rfind('\\'));
|
||||
|
||||
if (i == std::string::npos) {
|
||||
|
||||
// There is no slash; the basename is the whole thing
|
||||
base = f;
|
||||
f = "";
|
||||
|
||||
} else if ((i != std::string::npos) && (i < f.size() - 1)) {
|
||||
|
||||
base = f.substr(i + 1, f.size() - i - 1);
|
||||
f = f.substr(0, i);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Parse what remains into path.
|
||||
size_t prev, cur = 0;
|
||||
|
||||
while (cur < f.size()) {
|
||||
prev = cur;
|
||||
|
||||
// Allow either slash
|
||||
size_t i = f.find('/', prev + 1);
|
||||
size_t j = f.find('\\', prev + 1);
|
||||
if (i == std::string::npos) {
|
||||
i = f.size();
|
||||
}
|
||||
|
||||
if (j == std::string::npos) {
|
||||
j = f.size();
|
||||
}
|
||||
|
||||
cur = iMin(i, j);
|
||||
|
||||
if (cur == std::string::npos) {
|
||||
cur = f.size();
|
||||
}
|
||||
|
||||
path.append(f.substr(prev, cur - prev));
|
||||
++cur;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
511
modules/acore/deps/g3dlite/source/GCamera.cpp
Normal file
511
modules/acore/deps/g3dlite/source/GCamera.cpp
Normal file
@@ -0,0 +1,511 @@
|
||||
/**
|
||||
@file GCamera.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@author Jeff Marsceill, 08jcm@williams.edu
|
||||
|
||||
@created 2005-07-20
|
||||
@edited 2010-02-22
|
||||
*/
|
||||
#include "G3D/GCamera.h"
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Rect2D.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Ray.h"
|
||||
#include "G3D/Matrix4.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
GCamera::GCamera(const Any& any) {
|
||||
any.verifyName("GCamera");
|
||||
any.verifyType(Any::TABLE);
|
||||
*this = GCamera();
|
||||
|
||||
const Any::AnyTable& table = any.table();
|
||||
Any::AnyTable::Iterator it = table.begin();
|
||||
while (it.hasMore()) {
|
||||
const std::string& k = toUpper(it->key);
|
||||
if (k == "FOVDIRECTION") {
|
||||
const std::string& v = toUpper(it->value);
|
||||
if (v == "HORIZONTAL") {
|
||||
m_direction = HORIZONTAL;
|
||||
} else if (v == "VERTICAL") {
|
||||
m_direction = VERTICAL;
|
||||
} else {
|
||||
any.verify(false, "fovDirection must be \"HORIZONTAL\" or \"VERTICAL\"");
|
||||
}
|
||||
} else if (k == "COORDINATEFRAME") {
|
||||
m_cframe = it->value;
|
||||
} else if (k == "FOVDEGREES") {
|
||||
m_fieldOfView = toRadians(it->value.number());
|
||||
} else if (k == "NEARPLANEZ") {
|
||||
m_nearPlaneZ = it->value;
|
||||
} else if (k == "FARPLANEZ") {
|
||||
m_farPlaneZ = it->value;
|
||||
} else if (k == "PIXELOFFSET") {
|
||||
m_pixelOffset = it->value;
|
||||
} else {
|
||||
any.verify(false, std::string("Illegal key in table: ") + it->key);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GCamera::operator Any() const {
|
||||
Any any(Any::TABLE, "GCamera");
|
||||
|
||||
any.set("fovDirection", std::string((m_direction == HORIZONTAL) ? "HORIZONTAL" : "VERTICAL"));
|
||||
any.set("fovDegrees", toDegrees(m_fieldOfView));
|
||||
any.set("nearPlaneZ", nearPlaneZ());
|
||||
any.set("farPlaneZ", farPlaneZ());
|
||||
any.set("coordinateFrame", coordinateFrame());
|
||||
any.set("pixelOffset", pixelOffset());
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
GCamera::GCamera() {
|
||||
setNearPlaneZ(-0.2f);
|
||||
setFarPlaneZ(-150.0f);
|
||||
setFieldOfView((float)toRadians(90.0f), HORIZONTAL);
|
||||
}
|
||||
|
||||
|
||||
GCamera::GCamera(const Matrix4& proj, const CFrame& frame) {
|
||||
float left, right, bottom, top, nearval, farval;
|
||||
proj.getPerspectiveProjectionParameters(left, right, bottom, top, nearval, farval);
|
||||
setNearPlaneZ(-nearval);
|
||||
setFarPlaneZ(-farval);
|
||||
float x = right;
|
||||
|
||||
// Assume horizontal field of view
|
||||
setFieldOfView(atan2(x, -m_nearPlaneZ) * 2.0f, HORIZONTAL);
|
||||
setCoordinateFrame(frame);
|
||||
}
|
||||
|
||||
|
||||
GCamera::~GCamera() {
|
||||
}
|
||||
|
||||
|
||||
void GCamera::getCoordinateFrame(CoordinateFrame& c) const {
|
||||
c = m_cframe;
|
||||
}
|
||||
|
||||
|
||||
void GCamera::setCoordinateFrame(const CoordinateFrame& c) {
|
||||
m_cframe = c;
|
||||
}
|
||||
|
||||
|
||||
void GCamera::setFieldOfView(float angle, FOVDirection dir) {
|
||||
debugAssert((angle < pi()) && (angle > 0));
|
||||
|
||||
m_fieldOfView = angle;
|
||||
m_direction = dir;
|
||||
}
|
||||
|
||||
|
||||
float GCamera::imagePlaneDepth() const{
|
||||
return -m_nearPlaneZ;
|
||||
}
|
||||
|
||||
float GCamera::viewportWidth(const Rect2D& viewport) const {
|
||||
// Compute the side of a square at the near plane based on our field of view
|
||||
float s = 2.0f * -m_nearPlaneZ * tan(m_fieldOfView * 0.5f);
|
||||
|
||||
if (m_direction == VERTICAL) {
|
||||
s *= viewport.width() / viewport.height();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
float GCamera::viewportHeight(const Rect2D& viewport) const {
|
||||
// Compute the side of a square at the near plane based on our field of view
|
||||
float s = 2.0f * -m_nearPlaneZ * tan(m_fieldOfView * 0.5f);
|
||||
|
||||
debugAssert(m_fieldOfView < toRadians(180));
|
||||
if (m_direction == HORIZONTAL) {
|
||||
s *= viewport.height() / viewport.width();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Ray GCamera::worldRay(float x, float y, const Rect2D& viewport) const {
|
||||
|
||||
int screenWidth = iFloor(viewport.width());
|
||||
int screenHeight = iFloor(viewport.height());
|
||||
|
||||
Vector3 origin = m_cframe.translation;
|
||||
|
||||
float cx = screenWidth / 2.0f;
|
||||
float cy = screenHeight / 2.0f;
|
||||
|
||||
float vw = viewportWidth(viewport);
|
||||
float vh = viewportHeight(viewport);
|
||||
|
||||
Vector3 direction = Vector3( (x - cx) * vw / screenWidth,
|
||||
-(y - cy) * vh / screenHeight,
|
||||
m_nearPlaneZ);
|
||||
|
||||
direction = m_cframe.vectorToWorldSpace(direction);
|
||||
|
||||
// Normalize the direction (we didn't do it before)
|
||||
direction = direction.direction();
|
||||
|
||||
return Ray::fromOriginAndDirection(origin, direction);
|
||||
}
|
||||
|
||||
|
||||
void GCamera::getProjectPixelMatrix(const Rect2D& viewport, Matrix4& P) const {
|
||||
getProjectUnitMatrix(viewport, P);
|
||||
float screenWidth = viewport.width();
|
||||
float screenHeight = viewport.height();
|
||||
|
||||
float sx = screenWidth / 2.0;
|
||||
float sy = screenHeight / 2.0;
|
||||
|
||||
P = Matrix4(sx, 0, 0, sx + viewport.x0() - m_pixelOffset.x,
|
||||
0, -sy, 0, sy + viewport.y0() + m_pixelOffset.y,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1) * P;
|
||||
}
|
||||
|
||||
|
||||
void GCamera::getProjectUnitMatrix(const Rect2D& viewport, Matrix4& P) const {
|
||||
|
||||
float screenWidth = viewport.width();
|
||||
float screenHeight = viewport.height();
|
||||
|
||||
float r, l, t, b, n, f, x, y;
|
||||
|
||||
float s = 1.0f;
|
||||
if (m_direction == VERTICAL) {
|
||||
y = -m_nearPlaneZ * tan(m_fieldOfView / 2);
|
||||
x = y * (screenWidth / screenHeight);
|
||||
s = screenHeight;
|
||||
} else { //m_direction == HORIZONTAL
|
||||
x = -m_nearPlaneZ * tan(m_fieldOfView / 2);
|
||||
y = x * (screenHeight / screenWidth);
|
||||
s = screenWidth;
|
||||
}
|
||||
|
||||
n = -m_nearPlaneZ;
|
||||
f = -m_farPlaneZ;
|
||||
r = x - m_pixelOffset.x/s;
|
||||
l = -x - m_pixelOffset.x/s;
|
||||
t = y + m_pixelOffset.y/s;
|
||||
b = -y + m_pixelOffset.y/s;
|
||||
|
||||
P = Matrix4::perspectiveProjection(l, r, b, t, n, f);
|
||||
}
|
||||
|
||||
|
||||
Vector3 GCamera::projectUnit(const Vector3& point, const Rect2D& viewport) const {
|
||||
Matrix4 M;
|
||||
getProjectUnitMatrix(viewport, M);
|
||||
|
||||
Vector4 cameraSpacePoint(coordinateFrame().pointToObjectSpace(point), 1.0f);
|
||||
const Vector4& screenSpacePoint = M * cameraSpacePoint;
|
||||
|
||||
return Vector3(screenSpacePoint.xyz() / screenSpacePoint.w);
|
||||
}
|
||||
|
||||
Vector3 GCamera::project(const Vector3& point,
|
||||
const Rect2D& viewport) const {
|
||||
|
||||
// Find the point in the homogeneous cube
|
||||
const Vector3& cube = projectUnit(point, viewport);
|
||||
|
||||
return convertFromUnitToNormal(cube, viewport);
|
||||
}
|
||||
|
||||
Vector3 GCamera::unprojectUnit(const Vector3& v, const Rect2D& viewport) const {
|
||||
|
||||
const Vector3& projectedPoint = convertFromUnitToNormal(v, viewport);
|
||||
|
||||
return unproject(projectedPoint, viewport);
|
||||
}
|
||||
|
||||
|
||||
Vector3 GCamera::unproject(const Vector3& v, const Rect2D& viewport) const {
|
||||
|
||||
const float n = m_nearPlaneZ;
|
||||
const float f = m_farPlaneZ;
|
||||
|
||||
float z;
|
||||
|
||||
if (-f >= finf()) {
|
||||
// Infinite far plane
|
||||
z = 1.0f / (((-1.0f / n) * v.z) + 1.0f / n);
|
||||
} else {
|
||||
z = 1.0f / ((((1.0f / f) - (1.0f / n)) * v.z) + 1.0f / n);
|
||||
}
|
||||
|
||||
const Ray& ray = worldRay(v.x - m_pixelOffset.x, v.y - m_pixelOffset.y, viewport);
|
||||
|
||||
// Find out where the ray reaches the specified depth.
|
||||
const Vector3& out = ray.origin() + ray.direction() * -z / (ray.direction().dot(m_cframe.lookVector()));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
float GCamera::worldToScreenSpaceArea(float area, float z, const Rect2D& viewport) const {
|
||||
(void)viewport;
|
||||
if (z >= 0) {
|
||||
return finf();
|
||||
}
|
||||
return area * (float)square(imagePlaneDepth() / z);
|
||||
}
|
||||
|
||||
|
||||
void GCamera::getClipPlanes(
|
||||
const Rect2D& viewport,
|
||||
Array<Plane>& clip) const {
|
||||
|
||||
Frustum fr;
|
||||
frustum(viewport, fr);
|
||||
clip.resize(fr.faceArray.size(), DONT_SHRINK_UNDERLYING_ARRAY);
|
||||
for (int f = 0; f < clip.size(); ++f) {
|
||||
clip[f] = fr.faceArray[f].plane;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GCamera::Frustum GCamera::frustum(const Rect2D& viewport) const {
|
||||
Frustum f;
|
||||
frustum(viewport, f);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
void GCamera::frustum(const Rect2D& viewport, Frustum& fr) const {
|
||||
|
||||
// The volume is the convex hull of the vertices definining the view
|
||||
// frustum and the light source point at infinity.
|
||||
|
||||
const float x = viewportWidth(viewport) / 2;
|
||||
const float y = viewportHeight(viewport) / 2;
|
||||
const float zn = m_nearPlaneZ;
|
||||
const float zf = m_farPlaneZ;
|
||||
float xx, zz, yy;
|
||||
|
||||
float halfFOV = m_fieldOfView * 0.5f;
|
||||
|
||||
// This computes the normal, which is based on the complement of the
|
||||
// halfFOV angle, so the equations are "backwards"
|
||||
if (m_direction == VERTICAL) {
|
||||
yy = -cosf(halfFOV);
|
||||
xx = yy * viewport.height() / viewport.width();
|
||||
zz = -sinf(halfFOV);
|
||||
} else {
|
||||
xx = -cosf(halfFOV);
|
||||
yy = xx * viewport.width() / viewport.height();
|
||||
zz = -sinf(halfFOV);
|
||||
}
|
||||
|
||||
// Near face (ccw from UR)
|
||||
fr.vertexPos.append(
|
||||
Vector4( x, y, zn, 1),
|
||||
Vector4(-x, y, zn, 1),
|
||||
Vector4(-x, -y, zn, 1),
|
||||
Vector4( x, -y, zn, 1));
|
||||
|
||||
// Far face (ccw from UR, from origin)
|
||||
if (m_farPlaneZ == -finf()) {
|
||||
fr.vertexPos.append(Vector4( x, y, zn, 0),
|
||||
Vector4(-x, y, zn, 0),
|
||||
Vector4(-x, -y, zn, 0),
|
||||
Vector4( x, -y, zn, 0));
|
||||
} else {
|
||||
// Finite
|
||||
const float s = zf / zn;
|
||||
fr.vertexPos.append(Vector4( x * s, y * s, zf, 1),
|
||||
Vector4(-x * s, y * s, zf, 1),
|
||||
Vector4(-x * s, -y * s, zf, 1),
|
||||
Vector4( x * s, -y * s, zf, 1));
|
||||
}
|
||||
|
||||
Frustum::Face face;
|
||||
|
||||
// Near plane (wind backwards so normal faces into frustum)
|
||||
// Recall that nearPlane, farPlane are positive numbers, so
|
||||
// we need to negate them to produce actual z values.
|
||||
face.plane = Plane(Vector3(0,0,-1), Vector3(0,0,m_nearPlaneZ));
|
||||
face.vertexIndex[0] = 3;
|
||||
face.vertexIndex[1] = 2;
|
||||
face.vertexIndex[2] = 1;
|
||||
face.vertexIndex[3] = 0;
|
||||
fr.faceArray.append(face);
|
||||
|
||||
// Right plane
|
||||
face.plane = Plane(Vector3(xx, 0, zz), Vector3::zero());
|
||||
face.vertexIndex[0] = 0;
|
||||
face.vertexIndex[1] = 4;
|
||||
face.vertexIndex[2] = 7;
|
||||
face.vertexIndex[3] = 3;
|
||||
fr.faceArray.append(face);
|
||||
|
||||
// Left plane
|
||||
face.plane = Plane(Vector3(-fr.faceArray.last().plane.normal().x, 0, fr.faceArray.last().plane.normal().z), Vector3::zero());
|
||||
face.vertexIndex[0] = 5;
|
||||
face.vertexIndex[1] = 1;
|
||||
face.vertexIndex[2] = 2;
|
||||
face.vertexIndex[3] = 6;
|
||||
fr.faceArray.append(face);
|
||||
|
||||
// Top plane
|
||||
face.plane = Plane(Vector3(0, yy, zz), Vector3::zero());
|
||||
face.vertexIndex[0] = 1;
|
||||
face.vertexIndex[1] = 5;
|
||||
face.vertexIndex[2] = 4;
|
||||
face.vertexIndex[3] = 0;
|
||||
fr.faceArray.append(face);
|
||||
|
||||
// Bottom plane
|
||||
face.plane = Plane(Vector3(0, -fr.faceArray.last().plane.normal().y, fr.faceArray.last().plane.normal().z), Vector3::zero());
|
||||
face.vertexIndex[0] = 2;
|
||||
face.vertexIndex[1] = 3;
|
||||
face.vertexIndex[2] = 7;
|
||||
face.vertexIndex[3] = 6;
|
||||
fr.faceArray.append(face);
|
||||
|
||||
// Far plane
|
||||
if (-m_farPlaneZ < finf()) {
|
||||
face.plane = Plane(Vector3(0, 0, 1), Vector3(0, 0, m_farPlaneZ));
|
||||
face.vertexIndex[0] = 4;
|
||||
face.vertexIndex[1] = 5;
|
||||
face.vertexIndex[2] = 6;
|
||||
face.vertexIndex[3] = 7;
|
||||
fr.faceArray.append(face);
|
||||
}
|
||||
|
||||
// Transform vertices to world space
|
||||
for (int v = 0; v < fr.vertexPos.size(); ++v) {
|
||||
fr.vertexPos[v] = m_cframe.toWorldSpace(fr.vertexPos[v]);
|
||||
}
|
||||
|
||||
// Transform planes to world space
|
||||
for (int p = 0; p < fr.faceArray.size(); ++p) {
|
||||
// Since there is no scale factor, we don't have to
|
||||
// worry about the inverse transpose of the normal.
|
||||
Vector3 normal;
|
||||
float d;
|
||||
|
||||
fr.faceArray[p].plane.getEquation(normal, d);
|
||||
|
||||
Vector3 newNormal = m_cframe.rotation * normal;
|
||||
|
||||
if (isFinite(d)) {
|
||||
d = (newNormal * -d + m_cframe.translation).dot(newNormal);
|
||||
fr.faceArray[p].plane = Plane(newNormal, newNormal * d);
|
||||
} else {
|
||||
// When d is infinite, we can't multiply 0's by it without
|
||||
// generating NaNs.
|
||||
fr.faceArray[p].plane = Plane::fromEquation(newNormal.x, newNormal.y, newNormal.z, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GCamera::getNearViewportCorners
|
||||
(const Rect2D& viewport,
|
||||
Vector3& outUR,
|
||||
Vector3& outUL,
|
||||
Vector3& outLL,
|
||||
Vector3& outLR) const {
|
||||
|
||||
// Must be kept in sync with getFrustum()
|
||||
const float w = viewportWidth(viewport) / 2.0f;
|
||||
const float h = viewportHeight(viewport) / 2.0f;
|
||||
const float z = nearPlaneZ();
|
||||
|
||||
// Compute the points
|
||||
outUR = Vector3( w, h, z);
|
||||
outUL = Vector3(-w, h, z);
|
||||
outLL = Vector3(-w, -h, z);
|
||||
outLR = Vector3( w, -h, z);
|
||||
|
||||
// Take to world space
|
||||
outUR = m_cframe.pointToWorldSpace(outUR);
|
||||
outUL = m_cframe.pointToWorldSpace(outUL);
|
||||
outLR = m_cframe.pointToWorldSpace(outLR);
|
||||
outLL = m_cframe.pointToWorldSpace(outLL);
|
||||
}
|
||||
|
||||
void GCamera::getFarViewportCorners(
|
||||
const Rect2D& viewport,
|
||||
Vector3& outUR,
|
||||
Vector3& outUL,
|
||||
Vector3& outLL,
|
||||
Vector3& outLR) const {
|
||||
|
||||
// Must be kept in sync with getFrustum()
|
||||
const float w = viewportWidth(viewport) * m_farPlaneZ / m_nearPlaneZ;
|
||||
const float h = viewportHeight(viewport) * m_farPlaneZ / m_nearPlaneZ;
|
||||
const float z = m_farPlaneZ;
|
||||
|
||||
// Compute the points
|
||||
outUR = Vector3( w/2, h/2, z);
|
||||
outUL = Vector3(-w/2, h/2, z);
|
||||
outLL = Vector3(-w/2, -h/2, z);
|
||||
outLR = Vector3( w/2, -h/2, z);
|
||||
|
||||
// Take to world space
|
||||
outUR = m_cframe.pointToWorldSpace(outUR);
|
||||
outUL = m_cframe.pointToWorldSpace(outUL);
|
||||
outLR = m_cframe.pointToWorldSpace(outLR);
|
||||
outLL = m_cframe.pointToWorldSpace(outLL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GCamera::setPosition(const Vector3& t) {
|
||||
m_cframe.translation = t;
|
||||
}
|
||||
|
||||
|
||||
void GCamera::lookAt(const Vector3& position, const Vector3& up) {
|
||||
m_cframe.lookAt(position, up);
|
||||
}
|
||||
|
||||
|
||||
void GCamera::serialize(BinaryOutput& bo) const {
|
||||
bo.writeFloat32(m_fieldOfView);
|
||||
bo.writeFloat32(imagePlaneDepth());
|
||||
debugAssert(nearPlaneZ() < 0.0f);
|
||||
bo.writeFloat32(nearPlaneZ());
|
||||
debugAssert(farPlaneZ() < 0.0f);
|
||||
bo.writeFloat32(farPlaneZ());
|
||||
m_cframe.serialize(bo);
|
||||
bo.writeInt8(m_direction);
|
||||
m_pixelOffset.serialize(bo);
|
||||
}
|
||||
|
||||
|
||||
void GCamera::deserialize(BinaryInput& bi) {
|
||||
m_fieldOfView = bi.readFloat32();
|
||||
m_nearPlaneZ = bi.readFloat32();
|
||||
debugAssert(m_nearPlaneZ < 0.0f);
|
||||
m_farPlaneZ = bi.readFloat32();
|
||||
debugAssert(m_farPlaneZ < 0.0f);
|
||||
m_cframe.deserialize(bi);
|
||||
m_direction = (FOVDirection)bi.readInt8();
|
||||
m_pixelOffset.deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
Vector3 GCamera::convertFromUnitToNormal(const Vector3& in, const Rect2D& viewport) const{
|
||||
return (in + Vector3(1,1,1)) * 0.5 * Vector3(viewport.width(), -viewport.height(), 1) +
|
||||
Vector3(viewport.x0(), viewport.y1(), 0);
|
||||
}
|
||||
} // namespace
|
||||
1166
modules/acore/deps/g3dlite/source/GImage.cpp
Normal file
1166
modules/acore/deps/g3dlite/source/GImage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
298
modules/acore/deps/g3dlite/source/GImage_bayer.cpp
Normal file
298
modules/acore/deps/g3dlite/source/GImage_bayer.cpp
Normal file
@@ -0,0 +1,298 @@
|
||||
/**
|
||||
@file GImage_bayer.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2006-05-10
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void GImage::BAYER_G8B8_R8G8_to_Quarter_R8G8B8(int width, int height, const uint8* in, uint8* out) {
|
||||
debugAssert(in != out);
|
||||
|
||||
int halfHeight = height / 2;
|
||||
int halfWidth = width / 2;
|
||||
|
||||
int dst_off = 0;
|
||||
for (int y = 0; y < halfHeight; ++y) {
|
||||
for (int x = 0; x < halfWidth; ++x) {
|
||||
// GBRG
|
||||
int src_off = x*2 + y*2*width;
|
||||
out[dst_off] = in[src_off+width]; // red
|
||||
out[dst_off+1] = ((int)in[src_off] + (int)in[src_off+width+1])/2; // green
|
||||
out[dst_off+2] = in[src_off+1]; // blue
|
||||
|
||||
dst_off = dst_off + 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GImage::Quarter_R8G8B8_to_BAYER_G8B8_R8G8(int inWidth, int inHeight, const uint8* in, uint8* out) {
|
||||
// Undo quarter-size Bayer as best we can. This code isn't very efficient, but it
|
||||
// also isn't used very frequently.
|
||||
|
||||
debugAssert(out != in);
|
||||
|
||||
int outWidth = 2 * inWidth;
|
||||
int outHeight = 2 * inHeight;
|
||||
|
||||
for (int y = 0; y < outHeight; ++y) {
|
||||
for (int x = 0; x < outWidth; ++x) {
|
||||
const Color3uint8* inp = ((const Color3uint8*)in) + ((x/2) + (y/2)* inWidth);
|
||||
uint8* outp = out + x + y * outWidth;
|
||||
|
||||
if (isEven(y)) {
|
||||
// GB row
|
||||
if (isEven(x)) {
|
||||
// Green
|
||||
*outp = inp->g;
|
||||
} else {
|
||||
// Blue
|
||||
*outp = inp->b;
|
||||
}
|
||||
} else {
|
||||
// RG row
|
||||
if (isEven(x)) {
|
||||
// Red
|
||||
*outp = inp->r;
|
||||
} else {
|
||||
// Green
|
||||
*outp = inp->g;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Applies a 5x5 filter to monochrome image I (wrapping at the boundaries) */
|
||||
static uint8 applyFilter(
|
||||
const uint8* I,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h,
|
||||
const float filter[5][5]) {
|
||||
|
||||
debugAssert(isEven(w));
|
||||
debugAssert(isEven(h));
|
||||
|
||||
float sum = 0.0f;
|
||||
float denom = 0.0f;
|
||||
|
||||
for (int dy = 0; dy < 5; ++dy) {
|
||||
int offset = ((y + dy + h - 2) % h) * w;
|
||||
|
||||
for (int dx = 0; dx < 5; ++dx) {
|
||||
float f = filter[dy][dx];
|
||||
sum += f * I[((x + dx + w - 2) % w) + offset];
|
||||
denom += f;
|
||||
}
|
||||
}
|
||||
|
||||
return (uint8)iClamp(iRound(sum / denom), 0, 255);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bayer conversions
|
||||
//
|
||||
|
||||
// There are two kinds of rows (GR and BG).
|
||||
// In each row, there are two kinds of pixels (G/R, B/G).
|
||||
// We express the four kinds of INPUT pixels as:
|
||||
// GRG, GRG, BGB, BGG
|
||||
//
|
||||
// There are three kinds of OUTPUT pixels: R, G, B.
|
||||
// Thus there are nominally 12 different I/O combinations,
|
||||
// but several are impulses because needed output at that
|
||||
// location *is* the input (e.g., G_GRG and G_BGG).
|
||||
//
|
||||
// The following 5x5 row-major filters are named as output_input.
|
||||
|
||||
// Green
|
||||
static const float G_GRR[5][5] =
|
||||
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
||||
{ -1.0f, 2.0f, 4.0f, 2.0f, -1.0f},
|
||||
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
|
||||
|
||||
static const float G_BGB[5][5] =
|
||||
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
||||
{ -1.0f, 2.0f, 4.0f, 2.0f, -1.0f},
|
||||
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
|
||||
|
||||
// Red
|
||||
//(the caption in the paper is wrong for this case:
|
||||
// "R row B column really means R row G column"
|
||||
static const float R_GRG[5][5] =
|
||||
{{ 0.0f, 0.0f, 0.5f, 0.0f, 0.0f},
|
||||
{ 0.0f, -1.0f, 0.0f, -1.0f, 0.0f},
|
||||
{ -1.0f, 4.0f, 5.0f, 4.0f, -1.0f},
|
||||
{ 0.0f, -1.0f, 0.0f, -1.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, 0.5f, 0.0f, 0.0f}};
|
||||
|
||||
static const float R_BGG[5][5] =
|
||||
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, -1.0f, 4.0f, -1.0f, 0.0f},
|
||||
{ 0.5f, 0.0f, 5.0f, 0.0f, 0.5f},
|
||||
{ 0.0f, -1.0f, 4.0f, -1.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
|
||||
|
||||
static const float R_BGB[5][5] =
|
||||
{{ 0.0f, 0.0f, -3.0f/2.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 2.0f, 0.0f, 2.0f, 0.0f},
|
||||
{-3.0f/2.0f, 0.0f, 6.0f, 0.0f, -3.0f/2.0f},
|
||||
{ 0.0f, 2.0f, 0.0f, 2.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, -3.0f/2.0f, 0.0f, 0.0f}};
|
||||
|
||||
|
||||
// Blue
|
||||
//(the caption in the paper is wrong for this case:
|
||||
// "B row R column really means B row G column")
|
||||
#define B_BGG R_GRG
|
||||
#define B_GRG R_BGG
|
||||
#define B_GRR R_BGB
|
||||
|
||||
|
||||
void GImage::BAYER_R8G8_G8B8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
|
||||
debugAssert(in != _out);
|
||||
|
||||
Color3uint8* out = (Color3uint8*)_out;
|
||||
|
||||
for (int y = 0; y < h; ++y) {
|
||||
|
||||
// Row beginning in the input array.
|
||||
int offset = y * w;
|
||||
|
||||
// RG row
|
||||
for (int x = 0; x < w; ++x, ++out) {
|
||||
// R pixel
|
||||
{
|
||||
out->r = in[x + offset];
|
||||
out->g = applyFilter(in, x, y, w, h, G_GRR);
|
||||
out->b = applyFilter(in, x, y, w, h, B_GRR);
|
||||
}
|
||||
++x; ++out;
|
||||
|
||||
// G pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_GRG);
|
||||
out->g = in[x + offset];
|
||||
out->b = applyFilter(in, x, y, w, h, B_GRG);
|
||||
}
|
||||
}
|
||||
|
||||
++y;
|
||||
offset += w;
|
||||
|
||||
// GB row
|
||||
for (int x = 0; x < w; ++x, ++out) {
|
||||
// G pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_BGG);
|
||||
out->g = in[x + offset];
|
||||
out->b = applyFilter(in, x, y, w, h, B_BGG);
|
||||
}
|
||||
++x; ++out;
|
||||
|
||||
// B pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_BGB);
|
||||
out->g = applyFilter(in, x, y, w, h, G_BGB);
|
||||
out->b = in[x + offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void swapRedAndBlue(int N, Color3uint8* out) {
|
||||
for (int i = N - 1; i >= 0; --i) {
|
||||
uint8 tmp = out[i].r;
|
||||
out[i].r = out[i].b;
|
||||
out[i].b = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void GImage::BAYER_G8R8_B8G8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
|
||||
// Run the equivalent function for red
|
||||
BAYER_G8B8_R8G8_to_R8G8B8_MHC(w, h, in, _out);
|
||||
|
||||
// Now swap red and blue
|
||||
swapRedAndBlue(w * h, (Color3uint8*)_out);
|
||||
}
|
||||
|
||||
|
||||
void GImage::BAYER_B8G8_G8R8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
|
||||
// Run the equivalent function for red
|
||||
BAYER_R8G8_G8B8_to_R8G8B8_MHC(w, h, in, _out);
|
||||
|
||||
// Now swap red and blue
|
||||
swapRedAndBlue(w * h, (Color3uint8*)_out);
|
||||
}
|
||||
|
||||
|
||||
void GImage::BAYER_G8B8_R8G8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
|
||||
|
||||
debugAssert(in != _out);
|
||||
|
||||
Color3uint8* out = (Color3uint8*)_out;
|
||||
|
||||
for (int y = 0; y < h; ++y) {
|
||||
|
||||
// Row beginning in the input array.
|
||||
int offset = y * w;
|
||||
|
||||
// GB row
|
||||
for (int x = 0; x < w; ++x, ++out) {
|
||||
// G pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_BGG);
|
||||
out->g = in[x + offset];
|
||||
out->b = applyFilter(in, x, y, w, h, B_BGG);
|
||||
}
|
||||
++x; ++out;
|
||||
|
||||
// B pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_BGB);
|
||||
out->g = applyFilter(in, x, y, w, h, G_BGB);
|
||||
out->b = in[x + offset];
|
||||
}
|
||||
}
|
||||
|
||||
++y;
|
||||
offset += w;
|
||||
|
||||
// RG row
|
||||
for (int x = 0; x < w; ++x, ++out) {
|
||||
// R pixel
|
||||
{
|
||||
out->r = in[x + offset];
|
||||
out->g = applyFilter(in, x, y, w, h, G_GRR);
|
||||
out->b = applyFilter(in, x, y, w, h, B_GRR);
|
||||
}
|
||||
++x; ++out;
|
||||
|
||||
// G pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_GRG);
|
||||
out->g = in[x + offset];
|
||||
out->b = applyFilter(in, x, y, w, h, B_GRG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#undef B_BGG
|
||||
#undef B_GRG
|
||||
#undef B_GRR
|
||||
|
||||
}
|
||||
717
modules/acore/deps/g3dlite/source/GImage_bmp.cpp
Normal file
717
modules/acore/deps/g3dlite/source/GImage_bmp.cpp
Normal file
@@ -0,0 +1,717 @@
|
||||
/**
|
||||
@file GImage_bmp.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2006-05-10
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Log.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
#ifndef G3D_WIN32
|
||||
/**
|
||||
This is used by the Windows bitmap I/O.
|
||||
*/
|
||||
static const int BI_RGB = 0;
|
||||
#endif
|
||||
|
||||
void GImage::encodeBMP(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
debugAssert(m_channels == 1 || m_channels == 3);
|
||||
out.setEndian(G3D_LITTLE_ENDIAN);
|
||||
|
||||
uint8 red;
|
||||
uint8 green;
|
||||
uint8 blue;
|
||||
int pixelBufferSize = m_width * m_height * 3;
|
||||
int fileHeaderSize = 14;
|
||||
int infoHeaderSize = 40;
|
||||
int BMScanWidth;
|
||||
int BMPadding;
|
||||
|
||||
// First write the BITMAPFILEHEADER
|
||||
//
|
||||
// WORD bfType;
|
||||
// DWORD bfSize;
|
||||
// WORD bfReserved1;
|
||||
// WORD bfReserved2;
|
||||
// DWORD bfOffBits;
|
||||
|
||||
// Type
|
||||
out.writeUInt8('B');
|
||||
out.writeUInt8('M');
|
||||
|
||||
// File size
|
||||
out.writeUInt32(fileHeaderSize + infoHeaderSize + pixelBufferSize);
|
||||
|
||||
// Two reserved fields set to zero
|
||||
out.writeUInt16(0);
|
||||
out.writeUInt16(0);
|
||||
|
||||
// The offset, in bytes, from the BITMAPFILEHEADER structure
|
||||
// to the bitmap bits.
|
||||
out.writeUInt32(infoHeaderSize + fileHeaderSize);
|
||||
|
||||
// Now the BITMAPINFOHEADER
|
||||
//
|
||||
// DWORD biSize;
|
||||
// LONG biWidth;
|
||||
// LONG biHeight;
|
||||
// WORD biPlanes;
|
||||
// WORD biBitCount
|
||||
// DWORD biCompression;
|
||||
// DWORD biSizeImage;
|
||||
// LONG biXPelsPerMeter;
|
||||
// LONG biYPelsPerMeter;
|
||||
// DWORD biClrUsed;
|
||||
// DWORD biClrImportant;
|
||||
|
||||
// Size of the info header
|
||||
out.writeUInt32(infoHeaderSize);
|
||||
|
||||
// Width and height of the image
|
||||
out.writeUInt32(m_width);
|
||||
out.writeUInt32(m_height);
|
||||
|
||||
// Planes ("must be set to 1")
|
||||
out.writeUInt16(1);
|
||||
|
||||
// BitCount and CompressionType
|
||||
out.writeUInt16(24);
|
||||
out.writeUInt32(BI_RGB);
|
||||
|
||||
// Image size ("may be zero for BI_RGB bitmaps")
|
||||
out.writeUInt32(0);
|
||||
|
||||
// biXPelsPerMeter
|
||||
out.writeUInt32(0);
|
||||
// biYPelsPerMeter
|
||||
out.writeUInt32(0);
|
||||
|
||||
// biClrUsed
|
||||
out.writeUInt32(0);
|
||||
|
||||
// biClrImportant
|
||||
out.writeUInt32(0);
|
||||
|
||||
BMScanWidth = m_width * 3;
|
||||
|
||||
if (BMScanWidth & 3) {
|
||||
BMPadding = 4 - (BMScanWidth & 3);
|
||||
} else {
|
||||
BMPadding = 0;
|
||||
}
|
||||
|
||||
int hStart = m_height - 1;
|
||||
int hEnd = -1;
|
||||
int hDir = -1;
|
||||
int dest;
|
||||
|
||||
// Write the pixel data
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
dest = m_channels * h * m_width;
|
||||
for (int w = 0; w < m_width; ++w) {
|
||||
|
||||
if (m_channels == 3) {
|
||||
red = m_byte[dest];
|
||||
green = m_byte[dest + 1];
|
||||
blue = m_byte[dest + 2];
|
||||
} else {
|
||||
red = m_byte[dest];
|
||||
green = m_byte[dest];
|
||||
blue = m_byte[dest];
|
||||
}
|
||||
|
||||
out.writeUInt8(blue);
|
||||
out.writeUInt8(green);
|
||||
out.writeUInt8(red);
|
||||
|
||||
dest += m_channels;
|
||||
}
|
||||
|
||||
if (BMPadding > 0) {
|
||||
out.skip(BMPadding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodeBMP(
|
||||
BinaryInput& input) {
|
||||
|
||||
// The BMP decoding uses these flags.
|
||||
static const uint16 PICTURE_NONE = 0x0000;
|
||||
static const uint16 PICTURE_BITMAP = 0x1000;
|
||||
|
||||
// Compression Flags
|
||||
static const uint16 PICTURE_UNCOMPRESSED = 0x0100;
|
||||
static const uint16 PICTURE_MONOCHROME = 0x0001;
|
||||
static const uint16 PICTURE_4BIT = 0x0002;
|
||||
static const uint16 PICTURE_8BIT = 0x0004;
|
||||
static const uint16 PICTURE_16BIT = 0x0008;
|
||||
static const uint16 PICTURE_24BIT = 0x0010;
|
||||
static const uint16 PICTURE_32BIT = 0x0020;
|
||||
|
||||
(void)PICTURE_16BIT;
|
||||
(void)PICTURE_32BIT;
|
||||
|
||||
// This is a simple BMP loader that can handle uncompressed BMP files.
|
||||
// Verify this is a BMP file by looking for the BM tag.
|
||||
input.reset();
|
||||
std::string tag = input.readString(2);
|
||||
if (tag != "BM") {
|
||||
throw Error("Not a BMP file", input.getFilename());
|
||||
}
|
||||
|
||||
m_channels = 3;
|
||||
// Skip to the BITMAPINFOHEADER's width and height
|
||||
input.skip(16);
|
||||
|
||||
m_width = input.readUInt32();
|
||||
m_height = input.readUInt32();
|
||||
|
||||
// Skip to the bit count and compression type
|
||||
input.skip(2);
|
||||
|
||||
uint16 bitCount = input.readUInt16();
|
||||
uint32 compressionType = input.readUInt32();
|
||||
|
||||
uint8 red;
|
||||
uint8 green;
|
||||
uint8 blue;
|
||||
uint8 blank;
|
||||
|
||||
// Only uncompressed bitmaps are supported by this code
|
||||
if ((int32)compressionType != BI_RGB) {
|
||||
throw Error("BMP images must be uncompressed", input.getFilename());
|
||||
}
|
||||
|
||||
uint8* palette = NULL;
|
||||
|
||||
// Create the palette if needed
|
||||
if (bitCount <= 8) {
|
||||
|
||||
// Skip to the palette color count in the header
|
||||
input.skip(12);
|
||||
|
||||
int numColors = input.readUInt32();
|
||||
|
||||
palette = (uint8*)System::malloc(numColors * 3);
|
||||
debugAssert(palette);
|
||||
|
||||
// Skip past the end of the header to the palette info
|
||||
input.skip(4);
|
||||
|
||||
int c;
|
||||
for(c = 0; c < numColors * 3; c += 3) {
|
||||
// Palette information in bitmaps is stored in BGR_ format.
|
||||
// That means it's blue-green-red-blank, for each entry.
|
||||
blue = input.readUInt8();
|
||||
green = input.readUInt8();
|
||||
red = input.readUInt8();
|
||||
blank = input.readUInt8();
|
||||
|
||||
palette[c] = red;
|
||||
palette[c + 1] = green;
|
||||
palette[c + 2] = blue;
|
||||
}
|
||||
}
|
||||
|
||||
int hStart = 0;
|
||||
int hEnd = 0;
|
||||
int hDir = 0;
|
||||
|
||||
if (m_height < 0) {
|
||||
m_height = -m_height;
|
||||
hStart = 0;
|
||||
hEnd = m_height;
|
||||
hDir = 1;
|
||||
} else {
|
||||
//height = height;
|
||||
hStart = m_height - 1;
|
||||
hEnd = -1;
|
||||
hDir = -1;
|
||||
}
|
||||
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * 3);
|
||||
debugAssert(m_byte);
|
||||
|
||||
int BMScanWidth;
|
||||
int BMPadding;
|
||||
uint8 BMGroup;
|
||||
uint8 BMPixel8;
|
||||
int currPixel;
|
||||
int dest;
|
||||
int flags = PICTURE_NONE;
|
||||
|
||||
if (bitCount == 1) {
|
||||
// Note that this file is not necessarily grayscale, since it's possible
|
||||
// the palette is blue-and-white, or whatever. But of course most image
|
||||
// programs only write 1-bit images if they're black-and-white.
|
||||
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_MONOCHROME;
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
BMScanWidth = (m_width + 7) >> 3;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
// Powers of 2
|
||||
int pow2[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
dest = 3 * h * m_width;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; ++w) {
|
||||
|
||||
BMGroup = input.readUInt8();
|
||||
|
||||
// Now we read the pixels. Usually there are eight pixels per byte,
|
||||
// since each pixel is represented by one bit, but if the width
|
||||
// is not a multiple of eight, the last byte will have some bits
|
||||
// set, with the others just being extra. Plus there's the
|
||||
// dword-alignment padding. So we keep checking to see if we've
|
||||
// already read "width" number of pixels.
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
if (currPixel < m_width) {
|
||||
int src = 3 * ((BMGroup & pow2[i]) >> i);
|
||||
|
||||
m_byte[dest] = palette[src];
|
||||
m_byte[dest + 1] = palette[src + 1];
|
||||
m_byte[dest + 2] = palette[src + 2];
|
||||
|
||||
++currPixel;
|
||||
dest += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitCount == 4) {
|
||||
|
||||
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_4BIT;
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
int BMScanWidth = (m_width + 1) >> 1;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
dest = 3 * h * m_width;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; w++) {
|
||||
|
||||
BMGroup = input.readUInt8();
|
||||
int src[2];
|
||||
src[0] = 3 * ((BMGroup & 0xF0) >> 4);
|
||||
src[1] = 3 * (BMGroup & 0x0F);
|
||||
|
||||
// Now we read the pixels. Usually there are two pixels per byte,
|
||||
// since each pixel is represented by four bits, but if the width
|
||||
// is not a multiple of two, the last byte will have only four bits
|
||||
// set, with the others just being extra. Plus there's the
|
||||
// dword-alignment padding. So we keep checking to see if we've
|
||||
// already read "Width" number of pixels.
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (currPixel < m_width) {
|
||||
int tsrc = src[i];
|
||||
|
||||
m_byte[dest] = palette[tsrc];
|
||||
m_byte[dest + 1] = palette[tsrc + 1];
|
||||
m_byte[dest + 2] = palette[tsrc + 2];
|
||||
|
||||
++currPixel;
|
||||
dest += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitCount == 8) {
|
||||
|
||||
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_8BIT;
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
BMScanWidth = m_width;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; ++w) {
|
||||
|
||||
BMPixel8 = input.readUInt8();
|
||||
|
||||
if (currPixel < m_width) {
|
||||
dest = 3 * ((h * m_width) + currPixel);
|
||||
int src = 3 * BMPixel8;
|
||||
|
||||
m_byte[dest] = palette[src];
|
||||
m_byte[dest + 1] = palette[src + 1];
|
||||
m_byte[dest + 2] = palette[src + 2];
|
||||
|
||||
++currPixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitCount == 16) {
|
||||
|
||||
m_memMan->free(m_byte);
|
||||
m_byte = NULL;
|
||||
System::free(palette);
|
||||
palette = NULL;
|
||||
throw Error("16-bit bitmaps not supported", input.getFilename());
|
||||
|
||||
} else if (bitCount == 24) {
|
||||
input.skip(20);
|
||||
|
||||
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_24BIT;
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
BMScanWidth = m_width * 3;
|
||||
|
||||
if (BMScanWidth & 3) {
|
||||
BMPadding = 4 - (BMScanWidth & 3);
|
||||
} else {
|
||||
BMPadding = 0;
|
||||
}
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
dest = 3 * h * m_width;
|
||||
for (int w = 0; w < m_width; ++w) {
|
||||
|
||||
blue = input.readUInt8();
|
||||
green = input.readUInt8();
|
||||
red = input.readUInt8();
|
||||
|
||||
m_byte[dest] = red;
|
||||
m_byte[dest + 1] = green;
|
||||
m_byte[dest + 2] = blue;
|
||||
|
||||
dest += 3;
|
||||
}
|
||||
|
||||
if (BMPadding) {
|
||||
input.skip(2);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitCount == 32) {
|
||||
|
||||
m_memMan->free(m_byte);
|
||||
m_byte = NULL;
|
||||
System::free(palette);
|
||||
palette = NULL;
|
||||
throw Error("32 bit bitmaps not supported", input.getFilename());
|
||||
|
||||
} else {
|
||||
// We support all possible bit depths, so if the
|
||||
// code gets here, it's not even a real bitmap.
|
||||
m_memMan->free(m_byte);
|
||||
m_byte = NULL;
|
||||
throw Error("Not a bitmap!", input.getFilename());
|
||||
}
|
||||
|
||||
System::free(palette);
|
||||
palette = NULL;
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodeICO(
|
||||
BinaryInput& input) {
|
||||
|
||||
// Header
|
||||
uint16 r = input.readUInt16();
|
||||
debugAssert(r == 0);
|
||||
r = input.readUInt16();
|
||||
debugAssert(r == 1);
|
||||
|
||||
// Read the number of icons, although we'll only load the
|
||||
// first one.
|
||||
int count = input.readUInt16();
|
||||
|
||||
m_channels = 4;
|
||||
|
||||
debugAssert(count > 0);
|
||||
|
||||
const uint8* headerBuffer = input.getCArray() + input.getPosition();
|
||||
int maxWidth = 0, maxHeight = 0;
|
||||
int maxHeaderNum = 0;
|
||||
for (int currentHeader = 0; currentHeader < count; ++currentHeader) {
|
||||
|
||||
const uint8* curHeaderBuffer = headerBuffer + (currentHeader * 16);
|
||||
int tmpWidth = curHeaderBuffer[0];
|
||||
int tmpHeight = curHeaderBuffer[1];
|
||||
// Just in case there is a non-square icon, checking area
|
||||
if ((tmpWidth * tmpHeight) > (maxWidth * maxHeight)) {
|
||||
maxWidth = tmpWidth;
|
||||
maxHeight = tmpHeight;
|
||||
maxHeaderNum = currentHeader;
|
||||
}
|
||||
}
|
||||
|
||||
input.skip(maxHeaderNum * 16);
|
||||
|
||||
m_width = input.readUInt8();
|
||||
m_height = input.readUInt8();
|
||||
int numColors = input.readUInt8();
|
||||
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * m_channels);
|
||||
debugAssert(m_byte);
|
||||
|
||||
// Bit mask for packed bits
|
||||
int mask = 0;
|
||||
|
||||
int bitsPerPixel = 8;
|
||||
|
||||
switch (numColors) {
|
||||
case 2:
|
||||
mask = 0x01;
|
||||
bitsPerPixel = 1;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
mask = 0x0F;
|
||||
bitsPerPixel = 4;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
numColors = 256;
|
||||
mask = 0xFF;
|
||||
bitsPerPixel = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Error("Unsupported ICO color count.", input.getFilename());
|
||||
}
|
||||
|
||||
input.skip(5);
|
||||
// Skip 'size' unused
|
||||
input.skip(4);
|
||||
|
||||
int offset = input.readUInt32();
|
||||
|
||||
// Skip over any other icon descriptions
|
||||
input.setPosition(offset);
|
||||
|
||||
// Skip over bitmap header; it is redundant
|
||||
input.skip(40);
|
||||
|
||||
Array<Color4uint8> palette;
|
||||
palette.resize(numColors, true);
|
||||
for (int c = 0; c < numColors; ++c) {
|
||||
palette[c].b = input.readUInt8();
|
||||
palette[c].g = input.readUInt8();
|
||||
palette[c].r = input.readUInt8();
|
||||
palette[c].a = input.readUInt8();
|
||||
}
|
||||
|
||||
// The actual image and mask follow
|
||||
|
||||
// The XOR Bitmap is stored as 1-bit, 4-bit or 8-bit uncompressed Bitmap
|
||||
// using the same encoding as BMP files. The AND Bitmap is stored in as
|
||||
// 1-bit uncompressed Bitmap.
|
||||
//
|
||||
// Pixels are stored bottom-up, left-to-right. Pixel lines are padded
|
||||
// with zeros to end on a 32bit (4byte) boundary. Every line will have the
|
||||
// same number of bytes. Color indices are zero based, meaning a pixel color
|
||||
// of 0 represents the first color table entry, a pixel color of 255 (if there
|
||||
// are that many) represents the 256th entry.
|
||||
/*
|
||||
int bitsPerRow = width * bitsPerPixel;
|
||||
int bytesPerRow = iCeil((double)bitsPerRow / 8);
|
||||
// Rows are padded to 32-bit boundaries
|
||||
bytesPerRow += bytesPerRow % 4;
|
||||
|
||||
// Read the XOR values into the color channel
|
||||
for (int y = height - 1; y >= 0; --y) {
|
||||
int x = 0;
|
||||
// Read the row
|
||||
for (int i = 0; i < bytesPerRow; ++i) {
|
||||
uint8 byte = input.readUInt8();
|
||||
for (int j = 0; (j < 8) && (x < width); ++x, j += bitsPerPixel) {
|
||||
int bit = ((byte << j) >> (8 - bitsPerPixel)) & mask;
|
||||
pixel4(x, y) = colorTable[bit];
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
int hStart = 0;
|
||||
int hEnd = 0;
|
||||
int hDir = 0;
|
||||
|
||||
if (m_height < 0) {
|
||||
m_height = -m_height;
|
||||
hStart = 0;
|
||||
hEnd = m_height;
|
||||
hDir = 1;
|
||||
} else {
|
||||
//height = height;
|
||||
hStart = m_height - 1;
|
||||
hEnd = -1;
|
||||
hDir = -1;
|
||||
}
|
||||
|
||||
int BMScanWidth;
|
||||
uint8 BMGroup;
|
||||
uint8 BMPixel8;
|
||||
int currPixel;
|
||||
int dest;
|
||||
|
||||
if (bitsPerPixel == 1) {
|
||||
// Note that this file is not necessarily grayscale, since it's possible
|
||||
// the palette is blue-and-white, or whatever. But of course most image
|
||||
// programs only write 1-bit images if they're black-and-white.
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
BMScanWidth = (m_width + 7) >> 3;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
// Powers of 2
|
||||
int pow2[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
dest = 3 * h * m_width;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; ++w) {
|
||||
|
||||
BMGroup = input.readUInt8();
|
||||
|
||||
// Now we read the pixels. Usually there are eight pixels per byte,
|
||||
// since each pixel is represented by one bit, but if the width
|
||||
// is not a multiple of eight, the last byte will have some bits
|
||||
// set, with the others just being extra. Plus there's the
|
||||
// dword-alignment padding. So we keep checking to see if we've
|
||||
// already read "width" number of pixels.
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
if (currPixel < m_width) {
|
||||
int src = ((BMGroup & pow2[i]) >> i);
|
||||
|
||||
m_byte[dest] = palette[src].r;
|
||||
m_byte[dest + 1] = palette[src].g;
|
||||
m_byte[dest + 2] = palette[src].b;
|
||||
|
||||
++currPixel;
|
||||
dest += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitsPerPixel == 4) {
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
int BMScanWidth = (m_width + 1) >> 1;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
dest = 4 * h * m_width;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; w++) {
|
||||
|
||||
BMGroup = input.readUInt8();
|
||||
int src[2];
|
||||
src[0] = ((BMGroup & 0xF0) >> 4);
|
||||
src[1] = (BMGroup & 0x0F);
|
||||
|
||||
// Now we read the pixels. Usually there are two pixels per byte,
|
||||
// since each pixel is represented by four bits, but if the width
|
||||
// is not a multiple of two, the last byte will have only four bits
|
||||
// set, with the others just being extra. Plus there's the
|
||||
// dword-alignment padding. So we keep checking to see if we've
|
||||
// already read "Width" number of pixels.
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (currPixel < m_width) {
|
||||
int tsrc = src[i];
|
||||
|
||||
m_byte[dest] = palette[tsrc].r;
|
||||
m_byte[dest + 1] = palette[tsrc].g;
|
||||
m_byte[dest + 2] = palette[tsrc].b;
|
||||
|
||||
++currPixel;
|
||||
dest += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitsPerPixel == 8) {
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
BMScanWidth = m_width;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; ++w) {
|
||||
|
||||
BMPixel8 = input.readUInt8();
|
||||
|
||||
if (currPixel < m_width) {
|
||||
dest = 4 * ((h * m_width) + currPixel);
|
||||
int src = BMPixel8;
|
||||
|
||||
m_byte[dest] = palette[src].r;
|
||||
m_byte[dest + 1] = palette[src].g;
|
||||
m_byte[dest + 2] = palette[src].b;
|
||||
|
||||
++currPixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read the mask into the alpha channel
|
||||
int bitsPerRow = m_width;
|
||||
int bytesPerRow = iCeil((double)bitsPerRow / 8);
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
//BMScanWidth = (width + 1) >> 1;
|
||||
if (bytesPerRow & 3) {
|
||||
bytesPerRow += 4 - (bytesPerRow & 3);
|
||||
}
|
||||
|
||||
for (int y = m_height - 1; y >= 0; --y) {
|
||||
int x = 0;
|
||||
// Read the row
|
||||
for (int i = 0; i < bytesPerRow; ++i) {
|
||||
uint8 byte = input.readUInt8();
|
||||
for (int j = 0; (j < 8) && (x < m_width); ++x, ++j) {
|
||||
int bit = (byte >> (7 - j)) & 0x01;
|
||||
pixel4(x, y).a = (1 - bit) * 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
446
modules/acore/deps/g3dlite/source/GImage_jpeg.cpp
Normal file
446
modules/acore/deps/g3dlite/source/GImage_jpeg.cpp
Normal file
@@ -0,0 +1,446 @@
|
||||
/**
|
||||
@file GImage_jpeg.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2009-04-20
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
#ifdef G3D_LINUX
|
||||
# include <jconfig.h>
|
||||
# include <jpeglib.h>
|
||||
#else
|
||||
# include "jconfig.h"
|
||||
# include "jpeglib.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
const int jpegQuality = 96;
|
||||
|
||||
/**
|
||||
The IJG library needs special setup for compress/decompressing
|
||||
from memory. These classes provide them.
|
||||
|
||||
The format of this class is defined by the IJG library; do not
|
||||
change it.
|
||||
*/
|
||||
class memory_destination_mgr {
|
||||
public:
|
||||
struct jpeg_destination_mgr pub;
|
||||
JOCTET* buffer;
|
||||
int size;
|
||||
int count;
|
||||
};
|
||||
|
||||
typedef memory_destination_mgr* mem_dest_ptr;
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void init_destination (
|
||||
j_compress_ptr cinfo) {
|
||||
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = dest->size;
|
||||
dest->count=0;
|
||||
}
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static boolean empty_output_buffer (
|
||||
j_compress_ptr cinfo) {
|
||||
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = dest->size;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void term_destination (
|
||||
j_compress_ptr cinfo) {
|
||||
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
dest->count = dest->size - dest->pub.free_in_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void jpeg_memory_dest (
|
||||
j_compress_ptr cinfo,
|
||||
JOCTET* buffer,
|
||||
int size) {
|
||||
|
||||
mem_dest_ptr dest;
|
||||
|
||||
if (cinfo->dest == NULL) {
|
||||
// First time for this JPEG object; call the
|
||||
// IJG allocator to get space.
|
||||
cinfo->dest = (struct jpeg_destination_mgr*)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
|
||||
JPOOL_PERMANENT,
|
||||
sizeof(memory_destination_mgr));
|
||||
}
|
||||
|
||||
dest = (mem_dest_ptr) cinfo->dest;
|
||||
dest->size = size;
|
||||
dest->buffer = buffer;
|
||||
dest->pub.init_destination = init_destination;
|
||||
dest->pub.empty_output_buffer = empty_output_buffer;
|
||||
dest->pub.term_destination = term_destination;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define INPUT_BUF_SIZE 4096
|
||||
|
||||
/**
|
||||
Structure dictated by IJG.
|
||||
*/
|
||||
class memory_source_mgr {
|
||||
public:
|
||||
struct jpeg_source_mgr pub;
|
||||
int source_size;
|
||||
unsigned char* source_data;
|
||||
boolean start_of_data;
|
||||
JOCTET* buffer;
|
||||
};
|
||||
|
||||
|
||||
typedef memory_source_mgr* mem_src_ptr;
|
||||
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void init_source(
|
||||
j_decompress_ptr cinfo) {
|
||||
|
||||
mem_src_ptr src = (mem_src_ptr) cinfo->src;
|
||||
|
||||
src->start_of_data = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static boolean fill_input_buffer(
|
||||
j_decompress_ptr cinfo) {
|
||||
|
||||
mem_src_ptr src = (mem_src_ptr) cinfo->src;
|
||||
|
||||
size_t bytes_read = 0;
|
||||
|
||||
if (src->source_size > INPUT_BUF_SIZE)
|
||||
bytes_read = INPUT_BUF_SIZE;
|
||||
else
|
||||
bytes_read = src->source_size;
|
||||
|
||||
memcpy (src->buffer, src->source_data, bytes_read);
|
||||
|
||||
src->source_data += bytes_read;
|
||||
src->source_size -= bytes_read;
|
||||
|
||||
src->pub.next_input_byte = src->buffer;
|
||||
src->pub.bytes_in_buffer = bytes_read;
|
||||
src->start_of_data = FALSE;
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void skip_input_data(
|
||||
j_decompress_ptr cinfo,
|
||||
long num_bytes) {
|
||||
|
||||
mem_src_ptr src = (mem_src_ptr)cinfo->src;
|
||||
|
||||
if (num_bytes > 0) {
|
||||
while (num_bytes > (long) src->pub.bytes_in_buffer) {
|
||||
num_bytes -= (long) src->pub.bytes_in_buffer;
|
||||
boolean s = fill_input_buffer(cinfo);
|
||||
debugAssert(s); (void)s;
|
||||
}
|
||||
|
||||
src->pub.next_input_byte += (size_t) num_bytes;
|
||||
src->pub.bytes_in_buffer -= (size_t) num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void term_source (
|
||||
j_decompress_ptr cinfo) {
|
||||
(void)cinfo;
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void jpeg_memory_src (
|
||||
j_decompress_ptr cinfo,
|
||||
JOCTET* buffer,
|
||||
int size) {
|
||||
|
||||
mem_src_ptr src;
|
||||
|
||||
if (cinfo->src == NULL) {
|
||||
// First time for this JPEG object
|
||||
cinfo->src = (struct jpeg_source_mgr*)
|
||||
(*cinfo->mem->alloc_small)(
|
||||
(j_common_ptr) cinfo,
|
||||
JPOOL_PERMANENT,
|
||||
sizeof(memory_source_mgr));
|
||||
|
||||
src = (mem_src_ptr)cinfo->src;
|
||||
|
||||
src->buffer = (JOCTET*)
|
||||
(*cinfo->mem->alloc_small)(
|
||||
(j_common_ptr) cinfo,
|
||||
JPOOL_PERMANENT,
|
||||
INPUT_BUF_SIZE * sizeof(JOCTET));
|
||||
}
|
||||
|
||||
src = (mem_src_ptr)cinfo->src;
|
||||
src->pub.init_source = init_source;
|
||||
src->pub.fill_input_buffer = fill_input_buffer;
|
||||
src->pub.skip_input_data = skip_input_data;
|
||||
|
||||
// use default method
|
||||
src->pub.resync_to_restart = jpeg_resync_to_restart;
|
||||
src->pub.term_source = term_source;
|
||||
src->source_data = buffer;
|
||||
src->source_size = size;
|
||||
|
||||
// forces fill_input_buffer on first read
|
||||
src->pub.bytes_in_buffer = 0;
|
||||
|
||||
// until buffer loaded
|
||||
src->pub.next_input_byte = NULL;
|
||||
}
|
||||
|
||||
|
||||
void GImage::encodeJPEG(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
if (m_channels != 3) {
|
||||
// Convert to three channel
|
||||
GImage tmp = *this;
|
||||
tmp.convertToRGB();
|
||||
tmp.encodeJPEG(out);
|
||||
return;
|
||||
}
|
||||
|
||||
debugAssert(m_channels == 3);
|
||||
out.setEndian(G3D_LITTLE_ENDIAN);
|
||||
|
||||
// Allocate and initialize a compression object
|
||||
jpeg_compress_struct cinfo;
|
||||
jpeg_error_mgr jerr;
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&cinfo);
|
||||
|
||||
// Specify the destination for the compressed data.
|
||||
// (Overestimate the size)
|
||||
int buffer_size = m_width * m_height * 3 + 200;
|
||||
JOCTET* compressed_data = (JOCTET*)System::malloc(buffer_size);
|
||||
jpeg_memory_dest(&cinfo, compressed_data, buffer_size);
|
||||
|
||||
|
||||
cinfo.image_width = m_width;
|
||||
cinfo.image_height = m_height;
|
||||
|
||||
// # of color components per pixel
|
||||
cinfo.input_components = 3;
|
||||
|
||||
// colorspace of input image
|
||||
cinfo.in_color_space = JCS_RGB;
|
||||
cinfo.input_gamma = 1.0;
|
||||
|
||||
// Set parameters for compression, including image size & colorspace
|
||||
jpeg_set_defaults(&cinfo);
|
||||
jpeg_set_quality(&cinfo, jpegQuality, false);
|
||||
cinfo.smoothing_factor = 0;
|
||||
cinfo.optimize_coding = TRUE;
|
||||
// cinfo.dct_method = JDCT_FLOAT;
|
||||
cinfo.dct_method = JDCT_ISLOW;
|
||||
cinfo.jpeg_color_space = JCS_YCbCr;
|
||||
|
||||
// Initialize the compressor
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
// Iterate over all scanlines from top to bottom
|
||||
// pointer to a single row
|
||||
JSAMPROW row_pointer[1];
|
||||
|
||||
// JSAMPLEs per row in image_buffer
|
||||
int row_stride = cinfo.image_width * 3;
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
row_pointer[0] = &(m_byte[cinfo.next_scanline * row_stride]);
|
||||
jpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||
}
|
||||
|
||||
// Shut down the compressor
|
||||
jpeg_finish_compress(&cinfo);
|
||||
|
||||
// Figure out how big the result was.
|
||||
int outLength = ((mem_dest_ptr)cinfo.dest)->count;
|
||||
|
||||
// Release the JPEG compression object
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
// Copy into an appropriately sized output buffer.
|
||||
out.writeBytes(compressed_data, outLength);
|
||||
|
||||
// Free the conservative buffer.
|
||||
System::free(compressed_data);
|
||||
compressed_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodeJPEG(
|
||||
BinaryInput& input) {
|
||||
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
int loc = 0;
|
||||
|
||||
m_channels = 3;
|
||||
// We have to set up the error handler, in case initialization fails.
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
|
||||
// Initialize the JPEG decompression object.
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
// Specify data source (eg, a file, for us, memory)
|
||||
jpeg_memory_src(&cinfo, const_cast<uint8*>(input.getCArray()), input.size());
|
||||
|
||||
// Read the parameters with jpeg_read_header()
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
|
||||
// Set parameters for decompression
|
||||
// (We do nothing here since the defaults are fine)
|
||||
|
||||
// Start decompressor
|
||||
jpeg_start_decompress(&cinfo);
|
||||
|
||||
// Get and set the values of interest to this object
|
||||
m_width = cinfo.output_width;
|
||||
m_height = cinfo.output_height;
|
||||
|
||||
// Prepare the pointer object for the pixel data
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * 3);
|
||||
|
||||
// JSAMPLEs per row in output buffer
|
||||
int bpp = cinfo.output_components;
|
||||
int row_stride = cinfo.output_width * bpp;
|
||||
|
||||
// Make a one-row-high sample array that will go away when done with image
|
||||
JSAMPARRAY temp = (*cinfo.mem->alloc_sarray)
|
||||
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
|
||||
|
||||
// Read data on a scanline by scanline basis
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
|
||||
// We may need to adjust the output based on the
|
||||
// number of channels it has.
|
||||
switch (bpp) {
|
||||
case 1:
|
||||
// Grayscale; decompress to temp.
|
||||
jpeg_read_scanlines(&cinfo, temp, 1);
|
||||
|
||||
// Expand to three channels
|
||||
{
|
||||
uint8* scan = &(m_byte[loc * 3]);
|
||||
uint8* endScan = scan + (m_width * 3);
|
||||
uint8* t = *temp;
|
||||
|
||||
while (scan < endScan) {
|
||||
uint8 value = t[0];
|
||||
|
||||
// Spread the value 3x.
|
||||
scan[0] = value;
|
||||
scan[1] = value;
|
||||
scan[2] = value;
|
||||
|
||||
scan += 3;
|
||||
t += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// Read directly into the array
|
||||
{
|
||||
// Need one extra level of indirection.
|
||||
uint8* scan = m_byte + loc;
|
||||
JSAMPARRAY ptr = &scan;
|
||||
jpeg_read_scanlines(&cinfo, ptr, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// RGBA; decompress to temp.
|
||||
jpeg_read_scanlines(&cinfo, temp, 1);
|
||||
|
||||
// Drop the 3rd channel
|
||||
{
|
||||
uint8* scan = &(m_byte[loc * 3]);
|
||||
uint8* endScan = scan + m_width * 3;
|
||||
uint8* t = *temp;
|
||||
|
||||
while (scan < endScan) {
|
||||
scan[0] = t[0];
|
||||
scan[1] = t[1];
|
||||
scan[2] = t[2];
|
||||
|
||||
scan += 3;
|
||||
t += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Error("Unexpected number of channels.", input.getFilename());
|
||||
}
|
||||
|
||||
loc += row_stride;
|
||||
}
|
||||
|
||||
// Finish decompression
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
|
||||
alwaysAssertM(this, "Corrupt GImage");
|
||||
// Release JPEG decompression object
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
276
modules/acore/deps/g3dlite/source/GImage_png.cpp
Normal file
276
modules/acore/deps/g3dlite/source/GImage_png.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
/**
|
||||
@file GImage_png.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2009-04-20
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Log.h"
|
||||
#include <png.h>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
//libpng required function signature
|
||||
static void png_read_data(
|
||||
png_structp png_ptr,
|
||||
png_bytep data,
|
||||
png_size_t length) {
|
||||
|
||||
|
||||
debugAssert( png_ptr->io_ptr != NULL );
|
||||
debugAssert( length >= 0 );
|
||||
debugAssert( data != NULL );
|
||||
|
||||
((BinaryInput*)png_ptr->io_ptr)->readBytes(data, length);
|
||||
}
|
||||
|
||||
//libpng required function signature
|
||||
static void png_write_data(png_structp png_ptr,
|
||||
png_bytep data,
|
||||
png_size_t length) {
|
||||
|
||||
debugAssert( png_ptr->io_ptr != NULL );
|
||||
debugAssert( data != NULL );
|
||||
|
||||
((BinaryOutput*)png_ptr->io_ptr)->writeBytes(data, length);
|
||||
}
|
||||
|
||||
//libpng required function signature
|
||||
static void png_flush_data(
|
||||
png_structp png_ptr) {
|
||||
(void)png_ptr;
|
||||
//Do nothing.
|
||||
}
|
||||
|
||||
//libpng required function signature
|
||||
static void png_error(
|
||||
png_structp png_ptr,
|
||||
png_const_charp error_msg) {
|
||||
|
||||
(void)png_ptr;
|
||||
debugAssert( error_msg != NULL );
|
||||
throw GImage::Error(error_msg, "PNG");
|
||||
}
|
||||
|
||||
|
||||
//libpng required function signature
|
||||
void png_warning(
|
||||
png_structp png_ptr,
|
||||
png_const_charp warning_msg) {
|
||||
|
||||
(void)png_ptr;
|
||||
debugAssert( warning_msg != NULL );
|
||||
Log::common()->println(warning_msg);
|
||||
}
|
||||
|
||||
|
||||
void GImage::encodePNG(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
if (! (m_channels == 1 || m_channels == 3 || m_channels == 4)) {
|
||||
throw GImage::Error(format("Illegal channels for PNG: %d", m_channels), out.getFilename());
|
||||
}
|
||||
if (m_width <= 0) {
|
||||
throw GImage::Error(format("Illegal width for PNG: %d", m_width), out.getFilename());
|
||||
}
|
||||
if (m_height <= 0) {
|
||||
throw GImage::Error(format("Illegal height for PNG: %d", m_height), out.getFilename());
|
||||
}
|
||||
|
||||
// PNG library requires that the height * pointer size fit within an int
|
||||
if (png_uint_32(m_height) * png_sizeof(png_bytep) > PNG_UINT_32_MAX) {
|
||||
throw GImage::Error("Unsupported PNG height.", out.getFilename());
|
||||
}
|
||||
|
||||
out.setEndian(G3D_LITTLE_ENDIAN);
|
||||
|
||||
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_error, png_warning);
|
||||
if (! png_ptr) {
|
||||
throw GImage::Error("Unable to initialize PNG encoder.", out.getFilename());
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (! info_ptr) {
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
throw GImage::Error("Unable to initialize PNG encoder.", out.getFilename());
|
||||
}
|
||||
|
||||
//setup libpng write handler so can use BinaryOutput
|
||||
png_set_write_fn(png_ptr, (void*)&out, png_write_data, png_flush_data);
|
||||
png_color_8_struct sig_bit;
|
||||
|
||||
switch (m_channels) {
|
||||
case 1:
|
||||
png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 8, PNG_COLOR_TYPE_GRAY,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
sig_bit.red = 0;
|
||||
sig_bit.green = 0;
|
||||
sig_bit.blue = 0;
|
||||
sig_bit.alpha = 0;
|
||||
sig_bit.gray = 8;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 8, PNG_COLOR_TYPE_RGB,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
|
||||
sig_bit.red = 8;
|
||||
sig_bit.green = 8;
|
||||
sig_bit.blue = 8;
|
||||
sig_bit.alpha = 0;
|
||||
sig_bit.gray = 0;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 8, PNG_COLOR_TYPE_RGBA,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
sig_bit.red = 8;
|
||||
sig_bit.green = 8;
|
||||
sig_bit.blue = 8;
|
||||
sig_bit.alpha = 8;
|
||||
sig_bit.gray = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
throw GImage::Error("Unsupported number of channels for PNG.", out.getFilename());
|
||||
}
|
||||
|
||||
|
||||
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
|
||||
|
||||
//write the png header
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
png_bytepp row_pointers = new png_bytep[m_height];
|
||||
|
||||
for (int i=0; i < m_height; ++i) {
|
||||
row_pointers[i] = (png_bytep)&m_byte[m_width * m_channels * i];
|
||||
}
|
||||
|
||||
png_write_image(png_ptr, row_pointers);
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
|
||||
delete[] row_pointers;
|
||||
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodePNG(
|
||||
BinaryInput& input) {
|
||||
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error, png_warning);
|
||||
if (png_ptr == NULL) {
|
||||
throw GImage::Error("Unable to initialize PNG decoder.", input.getFilename());
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == NULL) {
|
||||
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
|
||||
throw GImage::Error("Unable to initialize PNG decoder.", input.getFilename());
|
||||
}
|
||||
|
||||
png_infop end_info = png_create_info_struct(png_ptr);
|
||||
if (end_info == NULL) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||||
throw GImage::Error("Unable to initialize PNG decoder.", input.getFilename());
|
||||
}
|
||||
|
||||
// now that the libpng structures are setup, change the error handlers and read routines
|
||||
// to use G3D functions so that BinaryInput can be used.
|
||||
|
||||
png_set_read_fn(png_ptr, (png_voidp)&input, png_read_data);
|
||||
|
||||
// read in sequentially so that three copies of the file are not in memory at once
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
png_uint_32 png_width, png_height;
|
||||
int bit_depth, color_type, interlace_type;
|
||||
// this will validate the data it extracts from info_ptr
|
||||
png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &bit_depth, &color_type,
|
||||
&interlace_type, NULL, NULL);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
throw GImage::Error("Unsupported PNG color type - PNG_COLOR_TYPE_GRAY_ALPHA.", input.getFilename());
|
||||
}
|
||||
|
||||
m_width = static_cast<uint32>(png_width);
|
||||
m_height = static_cast<uint32>(png_height);
|
||||
|
||||
//swap bytes of 16 bit files to least significant byte first
|
||||
png_set_swap(png_ptr);
|
||||
|
||||
png_set_strip_16(png_ptr);
|
||||
|
||||
//Expand paletted colors into true RGB triplets
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
}
|
||||
|
||||
//Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
|
||||
png_set_expand(png_ptr);
|
||||
}
|
||||
|
||||
//Expand paletted or RGB images with transparency to full alpha channels
|
||||
//so the data will be available as RGBA quartets.
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
|
||||
png_set_tRNS_to_alpha(png_ptr);
|
||||
}
|
||||
|
||||
// Fix sub-8 bit_depth to 8bit
|
||||
if (bit_depth < 8) {
|
||||
png_set_packing(png_ptr);
|
||||
}
|
||||
|
||||
if ((color_type == PNG_COLOR_TYPE_RGBA) ||
|
||||
((color_type == PNG_COLOR_TYPE_PALETTE) && (png_ptr->num_trans > 0)) ) {
|
||||
|
||||
m_channels = 4;
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * 4);
|
||||
|
||||
} else if ((color_type == PNG_COLOR_TYPE_RGB) ||
|
||||
(color_type == PNG_COLOR_TYPE_PALETTE)) {
|
||||
|
||||
m_channels = 3;
|
||||
m_byte = (uint8*)System::malloc(m_width * m_height * 3);
|
||||
|
||||
} else if (color_type == PNG_COLOR_TYPE_GRAY) {
|
||||
|
||||
m_channels = 1;
|
||||
|
||||
// Round up to the nearest 8 rows to avoid a bug in the PNG decoder
|
||||
int h = iCeil(m_height / 8) * 8;
|
||||
int sz = m_width * h;
|
||||
m_byte = (uint8*)m_memMan->alloc(sz);
|
||||
|
||||
} else {
|
||||
throw GImage::Error("Unsupported PNG bit-depth or type.", input.getFilename());
|
||||
}
|
||||
|
||||
//since we are reading row by row, required to handle interlacing
|
||||
uint32 number_passes = png_set_interlace_handling(png_ptr);
|
||||
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
for (uint32 pass = 0; pass < number_passes; ++pass) {
|
||||
for (uint32 y = 0; y < (uint32)m_height; ++y) {
|
||||
png_bytep rowPointer = &m_byte[m_width * m_channels * y];
|
||||
png_read_rows(png_ptr, &rowPointer, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// png_read_image(png_ptr, &_byte);
|
||||
png_read_end(png_ptr, info_ptr);
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
}
|
||||
|
||||
}
|
||||
217
modules/acore/deps/g3dlite/source/GImage_ppm.cpp
Normal file
217
modules/acore/deps/g3dlite/source/GImage_ppm.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
@file GImage_ppm.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2006-05-10
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/TextInput.h"
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/Log.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void GImage::encodePPMASCII(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
TextOutput::Settings ppmOptions;
|
||||
ppmOptions.convertNewlines = false;
|
||||
ppmOptions.numColumns = 70;
|
||||
ppmOptions.wordWrap = TextOutput::Settings::WRAP_WITHOUT_BREAKING;
|
||||
TextOutput ppm(ppmOptions);
|
||||
|
||||
switch (m_channels) {
|
||||
case 1:
|
||||
{
|
||||
ppm.printf("P2\n%d %d\n255\n", m_width, m_height);
|
||||
|
||||
const Color1uint8* c = this->pixel1();
|
||||
// Insert newlines every 70 characters max
|
||||
for (uint32 i = 0; i < (uint32)(m_width * m_height); ++i) {
|
||||
ppm.printf("%d%c", c[i].value, (i % (70/4) == 0) ? '\n' : ' ');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
ppm.printf("P3\n%d %d\n255\n", m_width, m_height);
|
||||
|
||||
const Color3uint8* c = this->pixel3();
|
||||
// Insert newlines every 70 characters max
|
||||
for (uint32 i = 0; i < (uint32)(m_width * m_height); ++i) {
|
||||
ppm.printf("%d %d %d%c", c[i].r, c[i].g, c[i].b,
|
||||
(i % (70/12) == 0) ?
|
||||
'\n' : ' ');
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
alwaysAssertM(false, "PPM requires either 1 or 3 channels exactly.");
|
||||
}
|
||||
|
||||
const std::string& s = ppm.commitString();
|
||||
out.writeBytes(s.c_str(), s.length());
|
||||
}
|
||||
|
||||
|
||||
void GImage::encodePPM(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
// http://netpbm.sourceforge.net/doc/ppm.html
|
||||
if (m_channels == 3) {
|
||||
std::string header = format("P6 %d %d 255 ", m_width, m_height);
|
||||
out.writeBytes(header.c_str(), header.size());
|
||||
out.writeBytes(this->pixel3(), m_width * m_height * 3);
|
||||
} else if (m_channels == 1) {
|
||||
std::string header = format("P5 %d %d 255 ", m_width, m_height);
|
||||
out.writeBytes(header.c_str(), header.size());
|
||||
out.writeBytes(this->pixel1(), m_width * m_height);
|
||||
} else {
|
||||
alwaysAssertM(false, "PPM requires either 1 or 3 channels exactly.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodePPMASCII(
|
||||
BinaryInput& input) {
|
||||
|
||||
int ppmWidth;
|
||||
int ppmHeight;
|
||||
|
||||
double maxColor;
|
||||
|
||||
// Create a TextInput object to parse ascii format
|
||||
// Mixed binary/ascii formats will require more
|
||||
|
||||
const std::string inputStr = input.readString();
|
||||
|
||||
TextInput::Settings ppmOptions;
|
||||
ppmOptions.cppLineComments = false;
|
||||
ppmOptions.otherCommentCharacter = '#';
|
||||
ppmOptions.signedNumbers = true;
|
||||
ppmOptions.singleQuotedStrings = false;
|
||||
|
||||
TextInput ppmInput(TextInput::FROM_STRING, inputStr, ppmOptions);
|
||||
|
||||
//Skip first line in header P#
|
||||
std::string ppmType = ppmInput.readSymbol();
|
||||
|
||||
ppmWidth = (int)ppmInput.readNumber();
|
||||
ppmHeight = (int)ppmInput.readNumber();
|
||||
|
||||
// Everything but a PBM will have a max color value
|
||||
if (ppmType != "P2") {
|
||||
maxColor = ppmInput.readNumber();
|
||||
} else {
|
||||
maxColor = 255;
|
||||
}
|
||||
|
||||
if ((ppmWidth < 0) ||
|
||||
(ppmHeight < 0) ||
|
||||
(maxColor <= 0)) {
|
||||
throw GImage::Error("Invalid PPM Header.", input.getFilename());
|
||||
}
|
||||
|
||||
// I don't think it's proper to scale values less than 255
|
||||
if (maxColor <= 255.0) {
|
||||
maxColor = 255.0;
|
||||
}
|
||||
|
||||
m_width = ppmWidth;
|
||||
m_height = ppmHeight;
|
||||
m_channels = 3;
|
||||
// always scale down to 1 byte per channel
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * 3);
|
||||
|
||||
// Read in the image data. I am not validating if the values match the maxColor
|
||||
// requirements. I only scale if needed to fit within the byte available.
|
||||
for (uint32 i = 0; i < (uint32)(m_width * m_height); ++i) {
|
||||
// read in color and scale to max pixel defined in header
|
||||
// A max color less than 255 might need to be left alone and not scaled.
|
||||
Color3uint8& curPixel = *(pixel3() + i);
|
||||
|
||||
if (ppmType == "P3") {
|
||||
curPixel.r = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
|
||||
curPixel.g = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
|
||||
curPixel.b = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
|
||||
} else if (ppmType == "P2") {
|
||||
uint8 pixel = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
|
||||
curPixel.r = pixel;
|
||||
curPixel.g = pixel;
|
||||
curPixel.b = pixel;
|
||||
} else if (ppmType == "P1") {
|
||||
int pixel = (uint8)(ppmInput.readNumber() * maxColor);
|
||||
curPixel.r = pixel;
|
||||
curPixel.g = pixel;
|
||||
curPixel.b = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Consumes whitespace up to and including a number, but not the following character */
|
||||
static int scanUInt(BinaryInput& input) {
|
||||
char c = input.readUInt8();
|
||||
while (isWhiteSpace(c)) {
|
||||
c = input.readUInt8();
|
||||
}
|
||||
|
||||
std::string s;
|
||||
s += c;
|
||||
c = input.readUInt8();
|
||||
while (!isWhiteSpace(c)) {
|
||||
s += c;
|
||||
c = input.readUInt8();
|
||||
}
|
||||
|
||||
// Back up one to avoid consuming the last character
|
||||
input.setPosition(input.getPosition() - 1);
|
||||
|
||||
int x;
|
||||
sscanf(s.c_str(), "%d", &x);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodePPM(
|
||||
BinaryInput& input) {
|
||||
|
||||
char head[2];
|
||||
int w, h;
|
||||
|
||||
input.readBytes(head, 2);
|
||||
if (head[0] != 'P' || ((head[1] != '6') && (head[1] != '5'))) {
|
||||
throw GImage::Error("Invalid PPM Header.", input.getFilename());
|
||||
}
|
||||
|
||||
w = scanUInt(input);
|
||||
h = scanUInt(input);
|
||||
|
||||
// Skip the max color specifier
|
||||
scanUInt(input);
|
||||
|
||||
if ((w < 0) ||
|
||||
(h < 0) ||
|
||||
(w > 100000) ||
|
||||
(h > 100000)) {
|
||||
throw GImage::Error("Invalid PPM size in header.", input.getFilename());
|
||||
}
|
||||
|
||||
// Trailing whitespace
|
||||
input.readUInt8();
|
||||
|
||||
if (head[1] == '6') {
|
||||
// 3 channel
|
||||
resize(w, h, 3);
|
||||
input.readBytes(m_byte, m_width * m_height * 3);
|
||||
} else if (head[1] == '5') {
|
||||
// 1 channel
|
||||
resize(w, h, 1);
|
||||
input.readBytes(m_byte, m_width * m_height);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
236
modules/acore/deps/g3dlite/source/GImage_tga.cpp
Normal file
236
modules/acore/deps/g3dlite/source/GImage_tga.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
@file GImage_tga.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2009-05-10
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Log.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void GImage::encodeTGA(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
out.setEndian(G3D_LITTLE_ENDIAN);
|
||||
|
||||
// ID length
|
||||
out.writeUInt8(0);
|
||||
|
||||
// Color map Type
|
||||
out.writeUInt8(0);
|
||||
|
||||
// Type
|
||||
out.writeUInt8(2);
|
||||
|
||||
// Color map
|
||||
out.skip(5);
|
||||
|
||||
// x, y offsets
|
||||
out.writeUInt16(0);
|
||||
out.writeUInt16(0);
|
||||
|
||||
// Width & height
|
||||
out.writeUInt16(m_width);
|
||||
out.writeUInt16(m_height);
|
||||
|
||||
// Color depth
|
||||
if (m_channels == 1) {
|
||||
// Force RGB mode
|
||||
out.writeUInt8(8 * 3);
|
||||
} else {
|
||||
out.writeUInt8(8 * m_channels);
|
||||
}
|
||||
|
||||
// Image descriptor
|
||||
if (m_channels < 4) {
|
||||
// 0 alpha bits
|
||||
out.writeUInt8(0);
|
||||
} else {
|
||||
// 8 alpha bits
|
||||
out.writeUInt8(8);
|
||||
}
|
||||
|
||||
// Image ID (zero length)
|
||||
|
||||
if (m_channels == 1) {
|
||||
// Pixels are upside down in BGR format.
|
||||
for (int y = m_height - 1; y >= 0; --y) {
|
||||
for (int x = 0; x < m_width; ++x) {
|
||||
uint8 p = (m_byte[(y * m_width + x)]);
|
||||
out.writeUInt8(p);
|
||||
out.writeUInt8(p);
|
||||
out.writeUInt8(p);
|
||||
}
|
||||
}
|
||||
} else if (m_channels == 3) {
|
||||
// Pixels are upside down in BGR format.
|
||||
for (int y = m_height - 1; y >= 0; --y) {
|
||||
for (int x = 0; x < m_width; ++x) {
|
||||
uint8* p = &(m_byte[3 * (y * m_width + x)]);
|
||||
out.writeUInt8(p[2]);
|
||||
out.writeUInt8(p[1]);
|
||||
out.writeUInt8(p[0]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Pixels are upside down in BGRA format.
|
||||
for (int y = m_height - 1; y >= 0; --y) {
|
||||
for (int x = 0; x < m_width; ++x) {
|
||||
uint8* p = &(m_byte[4 * (y * m_width + x)]);
|
||||
out.writeUInt8(p[2]);
|
||||
out.writeUInt8(p[1]);
|
||||
out.writeUInt8(p[0]);
|
||||
out.writeUInt8(p[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write "TRUEVISION-XFILE " 18 bytes from the end
|
||||
// (with null termination)
|
||||
out.writeString("TRUEVISION-XFILE ");
|
||||
}
|
||||
|
||||
inline static void readBGR(uint8* byte, BinaryInput& bi) {
|
||||
int b = bi.readUInt8();
|
||||
int g = bi.readUInt8();
|
||||
int r = bi.readUInt8();
|
||||
|
||||
byte[0] = r;
|
||||
byte[1] = g;
|
||||
byte[2] = b;
|
||||
}
|
||||
|
||||
inline static void readBGRA(uint8* byte, BinaryInput& bi) {
|
||||
readBGR(byte, bi);
|
||||
byte[3] = bi.readUInt8();
|
||||
}
|
||||
|
||||
void GImage::decodeTGA(
|
||||
BinaryInput& input) {
|
||||
|
||||
// This is a simple TGA loader that can handle uncompressed
|
||||
// truecolor TGA files (TGA type 2).
|
||||
// Verify this is a TGA file by looking for the TRUEVISION tag.
|
||||
int pos = input.getPosition();
|
||||
input.setPosition(input.size() - 18);
|
||||
std::string tag = input.readString(16);
|
||||
if (tag != "TRUEVISION-XFILE") {
|
||||
throw Error("Not a TGA file", input.getFilename());
|
||||
}
|
||||
|
||||
input.setPosition(pos);
|
||||
|
||||
int IDLength = input.readUInt8();
|
||||
int colorMapType = input.readUInt8();
|
||||
int imageType = input.readUInt8();
|
||||
|
||||
(void)colorMapType;
|
||||
|
||||
// 2 is the type supported by this routine.
|
||||
if (imageType != 2 && imageType != 10) {
|
||||
throw Error("TGA images must be type 2 (Uncompressed truecolor) or 10 (Run-length truecolor)", input.getFilename());
|
||||
}
|
||||
|
||||
// Color map specification
|
||||
input.skip(5);
|
||||
|
||||
// Image specification
|
||||
|
||||
// Skip x and y offsets
|
||||
input.skip(4);
|
||||
|
||||
m_width = input.readInt16();
|
||||
m_height = input.readInt16();
|
||||
|
||||
int colorDepth = input.readUInt8();
|
||||
|
||||
if ((colorDepth != 24) && (colorDepth != 32)) {
|
||||
throw Error("TGA files must be 24 or 32 bit.", input.getFilename());
|
||||
}
|
||||
|
||||
if (colorDepth == 32) {
|
||||
m_channels = 4;
|
||||
} else {
|
||||
m_channels = 3;
|
||||
}
|
||||
|
||||
// Image descriptor contains overlay data as well
|
||||
// as data indicating where the origin is
|
||||
int imageDescriptor = input.readUInt8();
|
||||
(void)imageDescriptor;
|
||||
|
||||
// Image ID
|
||||
input.skip(IDLength);
|
||||
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * m_channels);
|
||||
debugAssert(m_byte);
|
||||
|
||||
// Pixel data
|
||||
int x;
|
||||
int y;
|
||||
|
||||
if (imageType == 2) {
|
||||
// Uncompressed
|
||||
if (m_channels == 3) {
|
||||
for (y = m_height - 1; y >= 0; --y) {
|
||||
for (x = 0; x < m_width; ++x) {
|
||||
int i = (x + y * m_width) * 3;
|
||||
readBGR(m_byte + i, input);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = m_height - 1; y >= 0; --y) {
|
||||
for (x = 0; x < m_width; ++x) {
|
||||
int i = (x + y * m_width) * 4;
|
||||
readBGRA(m_byte + i, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (imageType == 10) {
|
||||
|
||||
// Run-length encoded
|
||||
for (y = m_height - 1; y >= 0; --y) {
|
||||
for (int x = 0; x < m_width; /* intentionally no x increment */) {
|
||||
// The specification guarantees that no packet will wrap past the end of a row
|
||||
const uint8 repetitionCount = input.readUInt8();
|
||||
const uint8 numValues = (repetitionCount & (~128)) + 1;
|
||||
int byteOffset = (x + y * m_width) * 3;
|
||||
|
||||
if (repetitionCount & 128) {
|
||||
// When the high bit is 1, this is a run-length packet
|
||||
if (m_channels == 3) {
|
||||
Color3uint8 value;
|
||||
readBGR((uint8*)(&value), input);
|
||||
for (int i = 0; i < numValues; ++i, ++x) {
|
||||
for (int b = 0; b < 3; ++b, ++byteOffset) {
|
||||
m_byte[byteOffset] = value[b];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Color4uint8 value;
|
||||
readBGRA((uint8*)(&value), input);
|
||||
for (int i = 0; i < numValues; ++i, ++x) {
|
||||
for (int b = 0; b < 3; ++b, ++byteOffset) {
|
||||
m_byte[byteOffset] = value[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// When the high bit is 0, this is a raw packet
|
||||
for (int i = 0; i < numValues; ++i, ++x, byteOffset += m_channels) {
|
||||
readBGR(m_byte + byteOffset, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alwaysAssertM(false, "Unsupported type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
275
modules/acore/deps/g3dlite/source/GLight.cpp
Normal file
275
modules/acore/deps/g3dlite/source/GLight.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/**
|
||||
@file GLight.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-11-12
|
||||
@edited 2009-11-16
|
||||
*/
|
||||
#include "G3D/GLight.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
GLight::GLight(const Any& any) {
|
||||
any.verifyName("GLight");
|
||||
|
||||
if (any.type() == Any::TABLE) {
|
||||
*this = GLight();
|
||||
Vector3 spotTarget;
|
||||
bool hasSpotTarget = false;
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "position") {
|
||||
position = it->value;
|
||||
} else if (key == "rightdirection") {
|
||||
rightDirection = it->value;
|
||||
} else if (key == "spotdirection") {
|
||||
spotDirection = Vector3(it->value).directionOrZero();
|
||||
} else if (key == "spottarget") {
|
||||
spotTarget = it->value;
|
||||
hasSpotTarget = true;
|
||||
} else if (key == "spotcutoff") {
|
||||
spotCutoff = it->value.number();
|
||||
} else if (key == "spotsquare") {
|
||||
spotSquare = it->value.boolean();
|
||||
} else if (key == "attenuation") {
|
||||
attenuation[0] = it->value[0].number();
|
||||
attenuation[1] = it->value[1].number();
|
||||
attenuation[2] = it->value[2].number();
|
||||
} else if (key == "color") {
|
||||
color = it->value;
|
||||
} else if (key == "enabled") {
|
||||
enabled = it->value.boolean();
|
||||
} else if (key == "specular") {
|
||||
specular = it->value.boolean();
|
||||
} else if (key == "diffuse") {
|
||||
diffuse = it->value.boolean();
|
||||
} else {
|
||||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
if (hasSpotTarget) {
|
||||
spotDirection = (spotTarget - position.xyz()).direction();
|
||||
}
|
||||
} else if (toLower(any.name()) == "glight::directional") {
|
||||
|
||||
*this = directional(any[0], any[1],
|
||||
(any.size() > 2) ? any[2] : Any(true),
|
||||
(any.size() > 3) ? any[3] : Any(true));
|
||||
|
||||
} else if (toLower(any.name()) == "glight::point") {
|
||||
|
||||
*this = point(any[0], any[1],
|
||||
(any.size() > 2) ? any[2] : Any(1),
|
||||
(any.size() > 3) ? any[3] : Any(0),
|
||||
(any.size() > 4) ? any[4] : Any(0.5f),
|
||||
(any.size() > 5) ? any[5] : Any(true),
|
||||
(any.size() > 6) ? any[6] : Any(true));
|
||||
|
||||
} else if (toLower(any.name()) == "glight::spot") {
|
||||
|
||||
*this = spot(any[0], any[1], any[2], any[3],
|
||||
(any.size() > 4) ? any[4] : Any(1),
|
||||
(any.size() > 5) ? any[5] : Any(0),
|
||||
(any.size() > 6) ? any[6] : Any(0),
|
||||
(any.size() > 7) ? any[7] : Any(true),
|
||||
(any.size() > 8) ? any[8] : Any(true));
|
||||
} else {
|
||||
any.verify(false, "Unrecognized name");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GLight::operator Any() const {
|
||||
Any a(Any::TABLE, "GLight");
|
||||
a.set("position", position.operator Any());
|
||||
a.set("rightDirection", rightDirection.operator Any());
|
||||
a.set("spotDirection", spotDirection.operator Any());
|
||||
a.set("spotCutoff", spotCutoff);
|
||||
a.set("spotSquare", spotSquare);
|
||||
|
||||
Any att(Any::ARRAY);
|
||||
att.append(attenuation[0], attenuation[1], attenuation[2]);
|
||||
a.set("attenuation", att);
|
||||
a.set("color", color.operator Any());
|
||||
a.set("enabled", enabled);
|
||||
a.set("specular", specular);
|
||||
a.set("diffuse", diffuse);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
GLight::GLight() :
|
||||
position(0, 0, 0, 0),
|
||||
rightDirection(0,0,0),
|
||||
spotDirection(0, 0, -1),
|
||||
spotCutoff(180),
|
||||
spotSquare(false),
|
||||
color(Color3::white()),
|
||||
enabled(false),
|
||||
specular(true),
|
||||
diffuse(true) {
|
||||
|
||||
attenuation[0] = 1.0;
|
||||
attenuation[1] = 0.0;
|
||||
attenuation[2] = 0.0;
|
||||
}
|
||||
|
||||
|
||||
GLight GLight::directional(const Vector3& toLight, const Color3& color, bool s, bool d) {
|
||||
GLight L;
|
||||
L.position = Vector4(toLight.direction(), 0);
|
||||
L.color = color;
|
||||
L.specular = s;
|
||||
L.diffuse = d;
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
GLight GLight::point(const Vector3& pos, const Color3& color, float constAtt, float linAtt, float quadAtt, bool s, bool d) {
|
||||
GLight L;
|
||||
L.position = Vector4(pos, 1);
|
||||
L.color = color;
|
||||
L.attenuation[0] = constAtt;
|
||||
L.attenuation[1] = linAtt;
|
||||
L.attenuation[2] = quadAtt;
|
||||
L.specular = s;
|
||||
L.diffuse = d;
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
GLight GLight::spot(const Vector3& pos, const Vector3& pointDirection, float cutOffAngleDegrees, const Color3& color, float constAtt, float linAtt, float quadAtt, bool s, bool d) {
|
||||
GLight L;
|
||||
L.position = Vector4(pos, 1.0f);
|
||||
L.spotDirection = pointDirection.direction();
|
||||
debugAssert(cutOffAngleDegrees <= 90);
|
||||
L.spotCutoff = cutOffAngleDegrees;
|
||||
L.color = color;
|
||||
L.attenuation[0] = constAtt;
|
||||
L.attenuation[1] = linAtt;
|
||||
L.attenuation[2] = quadAtt;
|
||||
L.specular = s;
|
||||
L.diffuse = d;
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
bool GLight::operator==(const GLight& other) const {
|
||||
return (position == other.position) &&
|
||||
(rightDirection == other.rightDirection) &&
|
||||
(spotDirection == other.spotDirection) &&
|
||||
(spotCutoff == other.spotCutoff) &&
|
||||
(spotSquare == other.spotSquare) &&
|
||||
(attenuation[0] == other.attenuation[0]) &&
|
||||
(attenuation[1] == other.attenuation[1]) &&
|
||||
(attenuation[2] == other.attenuation[2]) &&
|
||||
(color == other.color) &&
|
||||
(enabled == other.enabled) &&
|
||||
(specular == other.specular) &&
|
||||
(diffuse == other.diffuse);
|
||||
}
|
||||
|
||||
|
||||
bool GLight::operator!=(const GLight& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
Sphere GLight::effectSphere(float cutoff) const {
|
||||
if (position.w == 0) {
|
||||
// Directional light
|
||||
return Sphere(Vector3::zero(), finf());
|
||||
} else {
|
||||
// Avoid divide by zero
|
||||
cutoff = max(cutoff, 0.00001f);
|
||||
float maxIntensity = max(color.r, max(color.g, color.b));
|
||||
|
||||
float radius = finf();
|
||||
|
||||
if (attenuation[2] != 0) {
|
||||
|
||||
// Solve I / attenuation.dot(1, r, r^2) < cutoff for r
|
||||
//
|
||||
// a[0] + a[1] r + a[2] r^2 > I/cutoff
|
||||
//
|
||||
|
||||
float a = attenuation[2];
|
||||
float b = attenuation[1];
|
||||
float c = attenuation[0] - maxIntensity / cutoff;
|
||||
|
||||
float discrim = square(b) - 4 * a * c;
|
||||
|
||||
if (discrim >= 0) {
|
||||
discrim = sqrt(discrim);
|
||||
|
||||
float r1 = (-b + discrim) / (2 * a);
|
||||
float r2 = (-b - discrim) / (2 * a);
|
||||
|
||||
if (r1 < 0) {
|
||||
if (r2 > 0) {
|
||||
radius = r2;
|
||||
}
|
||||
} else if (r2 > 0) {
|
||||
radius = min(r1, r2);
|
||||
} else {
|
||||
radius = r1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (attenuation[1] != 0) {
|
||||
|
||||
// Solve I / attenuation.dot(1, r) < cutoff for r
|
||||
//
|
||||
// r * a[1] + a[0] = I / cutoff
|
||||
// r = (I / cutoff - a[0]) / a[1]
|
||||
|
||||
float radius = (maxIntensity / cutoff - attenuation[0]) / attenuation[1];
|
||||
radius = max(radius, 0.0f);
|
||||
}
|
||||
|
||||
return Sphere(position.xyz(), radius);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame GLight::frame() const {
|
||||
CoordinateFrame f;
|
||||
if (rightDirection == Vector3::zero()) {
|
||||
// No specified right direction; choose one automatically
|
||||
if (position.w == 0) {
|
||||
// Directional light
|
||||
f.lookAt(-position.xyz());
|
||||
} else {
|
||||
// Spot light
|
||||
f.lookAt(spotDirection);
|
||||
}
|
||||
} else {
|
||||
const Vector3& Z = -spotDirection.direction();
|
||||
Vector3 X = rightDirection.direction();
|
||||
|
||||
// Ensure the vectors are not too close together
|
||||
while (abs(X.dot(Z)) > 0.9f) {
|
||||
X = Vector3::random();
|
||||
}
|
||||
|
||||
// Ensure perpendicular
|
||||
X -= Z * Z.dot(X);
|
||||
const Vector3& Y = Z.cross(X);
|
||||
|
||||
f.rotation.setColumn(Vector3::X_AXIS, X);
|
||||
f.rotation.setColumn(Vector3::Y_AXIS, Y);
|
||||
f.rotation.setColumn(Vector3::Z_AXIS, Z);
|
||||
}
|
||||
f.translation = position.xyz();
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
} // G3D
|
||||
229
modules/acore/deps/g3dlite/source/GThread.cpp
Normal file
229
modules/acore/deps/g3dlite/source/GThread.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
@file GThread.cpp
|
||||
|
||||
GThread class.
|
||||
|
||||
@created 2005-09-24
|
||||
@edited 2005-10-22
|
||||
*/
|
||||
|
||||
#include "G3D/GThread.h"
|
||||
#include "G3D/System.h"
|
||||
#include "G3D/debugAssert.h"
|
||||
#include "G3D/GMutex.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
namespace _internal {
|
||||
|
||||
class BasicThread: public GThread {
|
||||
public:
|
||||
BasicThread(const std::string& name, void (*proc)(void*), void* param):
|
||||
GThread(name), m_wrapperProc(proc), m_param(param) { }
|
||||
protected:
|
||||
virtual void threadMain() {
|
||||
m_wrapperProc(m_param);
|
||||
}
|
||||
|
||||
private:
|
||||
void (*m_wrapperProc)(void*);
|
||||
|
||||
void* m_param;
|
||||
};
|
||||
|
||||
} // namespace _internal
|
||||
|
||||
|
||||
GThread::GThread(const std::string& name):
|
||||
m_status(STATUS_CREATED),
|
||||
m_name(name) {
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
m_event = NULL;
|
||||
#endif
|
||||
|
||||
// system-independent clear of handle
|
||||
System::memset(&m_handle, 0, sizeof(m_handle));
|
||||
}
|
||||
|
||||
GThread::~GThread() {
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( push )
|
||||
# pragma warning( disable : 4127 )
|
||||
#endif
|
||||
alwaysAssertM(m_status != STATUS_RUNNING, "Deleting thread while running.");
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
if (m_event) {
|
||||
::CloseHandle(m_event);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GThreadRef GThread::create(const std::string& name, void (*proc)(void*), void* param) {
|
||||
return new _internal::BasicThread(name, proc, param);
|
||||
}
|
||||
|
||||
|
||||
bool GThread::started() const {
|
||||
return m_status != STATUS_CREATED;
|
||||
}
|
||||
|
||||
bool GThread::start(SpawnBehavior behavior) {
|
||||
|
||||
debugAssertM(! started(), "Thread has already executed.");
|
||||
if (started()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_status = STATUS_STARTED;
|
||||
|
||||
if (behavior == USE_CURRENT_THREAD) {
|
||||
// Run on this thread
|
||||
m_status = STATUS_RUNNING;
|
||||
threadMain();
|
||||
m_status = STATUS_COMPLETED;
|
||||
return true;
|
||||
}
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
DWORD threadId;
|
||||
|
||||
m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
debugAssert(m_event);
|
||||
|
||||
m_handle = ::CreateThread(NULL, 0, &internalThreadProc, this, 0, &threadId);
|
||||
|
||||
if (m_handle == NULL) {
|
||||
::CloseHandle(m_event);
|
||||
m_event = NULL;
|
||||
}
|
||||
|
||||
return (m_handle != NULL);
|
||||
# else
|
||||
if (!pthread_create(&m_handle, NULL, &internalThreadProc, this)) {
|
||||
return true;
|
||||
} else {
|
||||
// system-independent clear of handle
|
||||
System::memset(&m_handle, 0, sizeof(m_handle));
|
||||
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
void GThread::terminate() {
|
||||
if (m_handle) {
|
||||
# ifdef G3D_WIN32
|
||||
::TerminateThread(m_handle, 0);
|
||||
# else
|
||||
pthread_kill(m_handle, SIGSTOP);
|
||||
# endif
|
||||
// system-independent clear of handle
|
||||
System::memset(&m_handle, 0, sizeof(m_handle));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool GThread::running() const{
|
||||
return (m_status == STATUS_RUNNING);
|
||||
}
|
||||
|
||||
|
||||
bool GThread::completed() const {
|
||||
return (m_status == STATUS_COMPLETED);
|
||||
}
|
||||
|
||||
|
||||
void GThread::waitForCompletion() {
|
||||
if (m_status == STATUS_COMPLETED) {
|
||||
// Must be done
|
||||
return;
|
||||
}
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
debugAssert(m_event);
|
||||
::WaitForSingleObject(m_event, INFINITE);
|
||||
# else
|
||||
debugAssert(m_handle);
|
||||
pthread_join(m_handle, NULL);
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
DWORD WINAPI GThread::internalThreadProc(LPVOID param) {
|
||||
GThread* current = reinterpret_cast<GThread*>(param);
|
||||
debugAssert(current->m_event);
|
||||
current->m_status = STATUS_RUNNING;
|
||||
current->threadMain();
|
||||
current->m_status = STATUS_COMPLETED;
|
||||
::SetEvent(current->m_event);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
void* GThread::internalThreadProc(void* param) {
|
||||
GThread* current = reinterpret_cast<GThread*>(param);
|
||||
current->m_status = STATUS_RUNNING;
|
||||
current->threadMain();
|
||||
current->m_status = STATUS_COMPLETED;
|
||||
return (void*)NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//GMutex implementation
|
||||
GMutex::GMutex() {
|
||||
#ifdef G3D_WIN32
|
||||
::InitializeCriticalSection(&m_handle);
|
||||
#else
|
||||
int ret = pthread_mutexattr_init(&m_attr);
|
||||
debugAssert(ret == 0);
|
||||
ret = pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
debugAssert(ret == 0);
|
||||
ret = pthread_mutex_init(&m_handle, &m_attr);
|
||||
debugAssert(ret == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
GMutex::~GMutex() {
|
||||
//TODO: Debug check for locked
|
||||
#ifdef G3D_WIN32
|
||||
::DeleteCriticalSection(&m_handle);
|
||||
#else
|
||||
int ret = pthread_mutex_destroy(&m_handle);
|
||||
debugAssert(ret == 0);
|
||||
ret = pthread_mutexattr_destroy(&m_attr);
|
||||
debugAssert(ret == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GMutex::tryLock() {
|
||||
#ifdef G3D_WIN32
|
||||
return (::TryEnterCriticalSection(&m_handle) != 0);
|
||||
#else
|
||||
return (pthread_mutex_trylock(&m_handle) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GMutex::lock() {
|
||||
#ifdef G3D_WIN32
|
||||
::EnterCriticalSection(&m_handle);
|
||||
#else
|
||||
pthread_mutex_lock(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GMutex::unlock() {
|
||||
#ifdef G3D_WIN32
|
||||
::LeaveCriticalSection(&m_handle);
|
||||
#else
|
||||
pthread_mutex_unlock(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace G3D
|
||||
78
modules/acore/deps/g3dlite/source/GUniqueID.cpp
Normal file
78
modules/acore/deps/g3dlite/source/GUniqueID.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
@file GUniqueID.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
*/
|
||||
#include "G3D/GUniqueID.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/TextInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/NetworkDevice.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void GUniqueID::serialize(BinaryOutput& b) const {
|
||||
b.writeUInt64(id);
|
||||
}
|
||||
|
||||
|
||||
void GUniqueID::deserialize(BinaryInput& b) {
|
||||
id = b.readUInt64();
|
||||
}
|
||||
|
||||
void GUniqueID::serialize(TextOutput& t) const {
|
||||
t.writeSymbol("(");
|
||||
t.writeNumber((double)(id >> 32));
|
||||
t.writeNumber((double)(id & 0xFFFFFFFF));
|
||||
t.writeSymbol(")");
|
||||
}
|
||||
|
||||
void GUniqueID::deserialize(TextInput& t) {
|
||||
t.readSymbol("(");
|
||||
id = (((uint64)t.readNumber()) << 32) + (uint64)t.readNumber();
|
||||
t.readSymbol(")");
|
||||
}
|
||||
|
||||
|
||||
GUniqueID GUniqueID::create(uint16 tag) {
|
||||
static uint64 counter = 0;
|
||||
static uint64 systemID = 0;
|
||||
|
||||
if (systemID == 0) {
|
||||
// Create a unique ID for this machine/program instance
|
||||
|
||||
// TODO: see ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr)
|
||||
Array<NetAddress> addr;
|
||||
NetworkDevice::instance()->localHostAddresses(addr);
|
||||
if (addr.size() > 0) {
|
||||
systemID |= addr[0].ip();
|
||||
}
|
||||
|
||||
union {
|
||||
float64 ft;
|
||||
uint64 ut;
|
||||
};
|
||||
ft = System::time();
|
||||
systemID = ut << 22;
|
||||
systemID ^= ((uint64)iRandom(0, 32768)) << 8;
|
||||
|
||||
systemID &= ~((uint64)1023 << 54);
|
||||
|
||||
// Ensure that the systemID is non-zero (vanishingly small probability)
|
||||
if (systemID == 0) {
|
||||
systemID = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// No need for modulo; we'll all be dead before this counter
|
||||
// overflows 54 bits
|
||||
++counter;
|
||||
|
||||
GUniqueID i;
|
||||
|
||||
i.id = (((uint64)(tag & 1023)) << 54) | (counter ^ systemID);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
} // G3D
|
||||
224
modules/acore/deps/g3dlite/source/Image1.cpp
Normal file
224
modules/acore/deps/g3dlite/source/Image1.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
@file Image1.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2007-01-31
|
||||
*/
|
||||
|
||||
|
||||
#include "G3D/Image1.h"
|
||||
#include "G3D/Image1uint8.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image1::Image1(int w, int h, WrapMode wrap) : Map2D<Color1, Color1>(w, h, wrap) {
|
||||
setAll(Color1(0.0f));
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromImage1uint8(const ReferenceCountedPointer<Image1uint8>& im) {
|
||||
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
|
||||
out->resize(im->width(), im->height());
|
||||
|
||||
int N = im->width() * im->height();
|
||||
const Color1uint8* src = reinterpret_cast<Color1uint8*>(im->getCArray());
|
||||
for (int i = 0; i < N; ++i) {
|
||||
out->data[i] = Color1(src[i]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Type(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename, fmt);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image1::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
void Image1::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color3uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color1* dst = data.getCArray();
|
||||
// Convert int8 -> float
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1(Color3(src[i]).average());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color4uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color1* dst = data.getCArray();
|
||||
|
||||
// Strip alpha and convert
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1(Color3(src[i].rgb()).average());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), src, w * h * sizeof(Color1));
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color1* dst = data.getCArray();
|
||||
|
||||
// Strip alpha
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1(src[i].rgb().average());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color1uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i]= Color1(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1(src[i].average());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image1::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 1);
|
||||
|
||||
int N = im.width() * im.height();
|
||||
Color1uint8* dst = im.pixel1();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1uint8(data[i]);
|
||||
}
|
||||
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* Image1::format() const {
|
||||
return ImageFormat::L32F();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
212
modules/acore/deps/g3dlite/source/Image1uint8.cpp
Normal file
212
modules/acore/deps/g3dlite/source/Image1uint8.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
@file Image1uint8.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2008-01-13
|
||||
*/
|
||||
|
||||
#include "G3D/Image1uint8.h"
|
||||
#include "G3D/Image3uint8.h"
|
||||
#include "G3D/Image1.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image1uint8::Image1uint8(int w, int h, WrapMode wrap) : Map2D<Color1uint8, Color1>(w, h, wrap) {
|
||||
setAll(Color1uint8(0));
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromImage3uint8(const ReferenceCountedPointer<class Image3uint8>& im) {
|
||||
return fromArray(im->getCArray(), im->width(), im->height(), im->wrapMode());
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromImage1(const ReferenceCountedPointer<Image1>& im) {
|
||||
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
|
||||
out->copyArray(im->getCArray(), im->width(), im->height());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Type(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename, fmt);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyArray(const Color3uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].value = (src[i].r + src[i].g + src[i].b) / 3;
|
||||
}
|
||||
}
|
||||
|
||||
void Image1uint8::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1uint8(Color1(src[i].average()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyArray(const Color1uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), ptr, w * h);
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1uint8(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyArray(const Color4uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].value = (ptr[i].r + ptr[i].g + ptr[i].b) / 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1uint8(Color1(src[i].rgb().average()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image1uint8::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 1);
|
||||
System::memcpy(im.byte(), getCArray(), width() * height());
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* Image1uint8::format() const {
|
||||
return ImageFormat::L8();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
225
modules/acore/deps/g3dlite/source/Image3.cpp
Normal file
225
modules/acore/deps/g3dlite/source/Image3.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
@file Image3.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2007-01-31
|
||||
*/
|
||||
|
||||
|
||||
#include "G3D/Image3.h"
|
||||
#include "G3D/Image3uint8.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image3::Image3(int w, int h, WrapMode wrap) : Map2D<Color3, Color3>(w, h, wrap) {
|
||||
setAll(Color3::black());
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromImage3uint8(const ReferenceCountedPointer<Image3uint8>& im) {
|
||||
Ref out = createEmpty(im->wrapMode());
|
||||
out->resize(im->width(), im->height());
|
||||
|
||||
int N = im->width() * im->height();
|
||||
const Color3uint8* src = reinterpret_cast<Color3uint8*>(im->getCArray());
|
||||
for (int i = 0; i < N; ++i) {
|
||||
out->data[i] = Color3(src[i]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Image3(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename, fmt);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image3::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color3uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color3* dst = data.getCArray();
|
||||
// Convert int8 -> float
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color3(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color4uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color3* dst = data.getCArray();
|
||||
|
||||
// Strip alpha and convert
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color3(src[i].rgb());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), src, w * h * sizeof(Color3));
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color3* dst = data.getCArray();
|
||||
|
||||
// Strip alpha
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = src[i].rgb();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color1uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = Color1(src[i]).value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = src[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image3::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 3);
|
||||
|
||||
int N = im.width() * im.height();
|
||||
Color3uint8* dst = im.pixel3();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color3uint8(data[i]);
|
||||
}
|
||||
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* Image3::format() const {
|
||||
return ImageFormat::RGB32F();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
225
modules/acore/deps/g3dlite/source/Image3uint8.cpp
Normal file
225
modules/acore/deps/g3dlite/source/Image3uint8.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
@file Image3uint8.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2008-01-08
|
||||
*/
|
||||
|
||||
#include "G3D/Image1uint8.h"
|
||||
#include "G3D/Image3uint8.h"
|
||||
#include "G3D/Image3.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromImage1uint8(const ReferenceCountedPointer<class Image1uint8>& im) {
|
||||
return fromArray(im->getCArray(), im->width(), im->height(), im->wrapMode());
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Image3uint8(int w, int h, WrapMode wrap) : Map2D<Color3uint8>(w, h, wrap) {
|
||||
setAll(Color3::black());
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromImage3(const ReferenceCountedPointer<Image3>& im) {
|
||||
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
|
||||
out->copyArray(im->getCArray(), im->width(), im->height());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Type(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename, fmt);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyArray(const Color1uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = src[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
void Image3uint8::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = Color1uint8(src[i]).value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyArray(const Color3uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), ptr, w * h * 3);
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color3uint8(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyArray(const Color4uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
// Copy 3/4 bytes
|
||||
GImage::RGBAtoRGB((const uint8*)ptr, (uint8*)getCArray(), w * h);
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color3uint8(src[i].rgb());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image3uint8::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 3);
|
||||
System::memcpy(im.byte(), getCArray(), width() * height() * 3);
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
|
||||
ReferenceCountedPointer<class Image1uint8> Image3uint8::getChannel(int c) const {
|
||||
debugAssert(c >= 0 && c <= 2);
|
||||
|
||||
Image1uint8Ref dst = Image1uint8::createEmpty(width(), height(), wrapMode());
|
||||
const Color3uint8* srcArray = getCArray();
|
||||
Color1uint8* dstArray = dst->getCArray();
|
||||
|
||||
const int N = width() * height();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dstArray[i] = Color1uint8(srcArray[i][c]);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* Image3uint8::format() const {
|
||||
return ImageFormat::RGB8();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
226
modules/acore/deps/g3dlite/source/Image4.cpp
Normal file
226
modules/acore/deps/g3dlite/source/Image4.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
@file Image4.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2008-07-27
|
||||
*/
|
||||
|
||||
|
||||
#include "G3D/Image4.h"
|
||||
#include "G3D/Image4uint8.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color3.h"
|
||||
#include "G3D/Color3uint8.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image4::Image4(int w, int h, WrapMode wrap) : Map2D<Color4, Color4>(w, h, wrap) {
|
||||
setAll(Color4::zero());
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromImage4uint8(const ReferenceCountedPointer<Image4uint8>& im) {
|
||||
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
|
||||
out->resize(im->width(), im->height());
|
||||
|
||||
int N = im->width() * im->height();
|
||||
const Color4uint8* src = reinterpret_cast<Color4uint8*>(im->getCArray());
|
||||
for (int i = 0; i < N; ++i) {
|
||||
out->data[i] = Color4(src[i]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Type(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image4::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color4uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color4* dst = data.getCArray();
|
||||
// Convert int8 -> float
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color3uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color4* dst = data.getCArray();
|
||||
|
||||
// Add alpha and convert
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4(Color3(src[i]), 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), src, w * h * sizeof(Color4));
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color4* dst = data.getCArray();
|
||||
|
||||
// Add alpha
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4(src[i], 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color1uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = Color1(src[i]).value;
|
||||
dst[i].a = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = src[i].value;
|
||||
dst[i].a = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image4::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 4);
|
||||
|
||||
int N = im.width() * im.height();
|
||||
Color4uint8* dst = im.pixel4();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4uint8(data[i]);
|
||||
}
|
||||
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
const ImageFormat* Image4::format() const {
|
||||
return ImageFormat::RGBA32F();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
222
modules/acore/deps/g3dlite/source/Image4uint8.cpp
Normal file
222
modules/acore/deps/g3dlite/source/Image4uint8.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
@file Image4uint8.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2008-07-31
|
||||
*/
|
||||
|
||||
#include "G3D/Image4uint8.h"
|
||||
#include "G3D/Image4.h"
|
||||
#include "G3D/Image3uint8.h"
|
||||
#include "G3D/Image3.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image4uint8::Image4uint8(int w, int h, WrapMode wrap) : Map2D<Color4uint8, Color4>(w, h, wrap) {
|
||||
setAll(Color4::zero());
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromImage4(const ReferenceCountedPointer<Image4>& im) {
|
||||
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
|
||||
out->copyArray(im->getCArray(), im->width(), im->height());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Type(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename, fmt);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyArray(const Color1uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = src[i].value;
|
||||
dst[i].a = 255;
|
||||
}
|
||||
}
|
||||
|
||||
void Image4uint8::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = Color1uint8(src[i]).value;
|
||||
dst[i].a = 255;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyArray(const Color4uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), ptr, w * h * 4);
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4uint8(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyArray(const Color3uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
GImage::RGBtoRGBA((const uint8*)ptr, (uint8*)getCArray(), w * h);
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4uint8(Color4(src[i], 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image4uint8::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 4);
|
||||
System::memcpy(im.byte(), getCArray(), width() * height() * 4);
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
|
||||
ReferenceCountedPointer<class Image1uint8> Image4uint8::getChannel(int c) const {
|
||||
debugAssert(c >= 0 && c <= 3);
|
||||
|
||||
Image1uint8Ref dst = Image1uint8::createEmpty(width(), height(), wrapMode());
|
||||
const Color4uint8* srcArray = getCArray();
|
||||
Color1uint8* dstArray = dst->getCArray();
|
||||
|
||||
const int N = width() * height();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dstArray[i] = Color1uint8(srcArray[i][c]);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* Image4uint8::format() const {
|
||||
return ImageFormat::RGBA8();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
588
modules/acore/deps/g3dlite/source/ImageFormat.cpp
Normal file
588
modules/acore/deps/g3dlite/source/ImageFormat.cpp
Normal file
@@ -0,0 +1,588 @@
|
||||
/**
|
||||
@file ImageFormat.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-05-23
|
||||
@edited 2010-03-30
|
||||
*/
|
||||
|
||||
#include "GLG3D/glheaders.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
ImageFormat::ImageFormat(
|
||||
int _numComponents,
|
||||
bool _compressed,
|
||||
int _glFormat,
|
||||
int _glBaseFormat,
|
||||
int _luminanceBits,
|
||||
int _alphaBits,
|
||||
int _redBits,
|
||||
int _greenBits,
|
||||
int _blueBits,
|
||||
int _depthBits,
|
||||
int _stencilBits,
|
||||
int _hardwareBitsPerTexel,
|
||||
int _packedBitsPerTexel,
|
||||
int glDataFormat,
|
||||
bool _opaque,
|
||||
bool _floatingPoint,
|
||||
Code _code,
|
||||
ColorSpace _colorSpace,
|
||||
BayerPattern _bayerPattern) :
|
||||
|
||||
numComponents(_numComponents),
|
||||
compressed(_compressed),
|
||||
code(_code),
|
||||
colorSpace(_colorSpace),
|
||||
bayerPattern(_bayerPattern),
|
||||
openGLFormat(_glFormat),
|
||||
openGLBaseFormat(_glBaseFormat),
|
||||
luminanceBits(_luminanceBits),
|
||||
alphaBits(_alphaBits),
|
||||
redBits(_redBits),
|
||||
greenBits(_greenBits),
|
||||
blueBits(_blueBits),
|
||||
stencilBits(_stencilBits),
|
||||
depthBits(_depthBits),
|
||||
cpuBitsPerPixel(_packedBitsPerTexel),
|
||||
packedBitsPerTexel(_packedBitsPerTexel),
|
||||
openGLBitsPerPixel(_hardwareBitsPerTexel),
|
||||
hardwareBitsPerTexel(_hardwareBitsPerTexel),
|
||||
openGLDataFormat(glDataFormat),
|
||||
opaque(_opaque),
|
||||
floatingPoint(_floatingPoint) {
|
||||
|
||||
debugAssert(_packedBitsPerTexel <= _hardwareBitsPerTexel);
|
||||
}
|
||||
|
||||
const ImageFormat* ImageFormat::depth(int depthBits) {
|
||||
|
||||
switch (depthBits) {
|
||||
case 16:
|
||||
return DEPTH16();
|
||||
|
||||
case 24:
|
||||
return DEPTH24();
|
||||
|
||||
case 32:
|
||||
return DEPTH32();
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Depth must be 16, 24, or 32.");
|
||||
return DEPTH32();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* ImageFormat::stencil(int bits) {
|
||||
switch (bits) {
|
||||
case 1:
|
||||
return STENCIL1();
|
||||
|
||||
case 4:
|
||||
return STENCIL4();
|
||||
|
||||
case 8:
|
||||
return STENCIL8();
|
||||
|
||||
case 16:
|
||||
return STENCIL16();
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Stencil must be 1, 4, 8 or 16.");
|
||||
return STENCIL16();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const std::string nameArray[] =
|
||||
{
|
||||
"L8",
|
||||
"L16",
|
||||
"L16F",
|
||||
"L32F",
|
||||
|
||||
"A8",
|
||||
"A16",
|
||||
"A16F",
|
||||
"A32F",
|
||||
|
||||
"LA4",
|
||||
"LA8",
|
||||
"LA16",
|
||||
"LA16F",
|
||||
"LA32F",
|
||||
|
||||
"RGB5",
|
||||
"RGB5A1",
|
||||
"RGB8",
|
||||
"RGB10",
|
||||
"RGB10A2",
|
||||
"RGB16",
|
||||
"RGB16F",
|
||||
"RGB32F",
|
||||
"R11G11B10F",
|
||||
"RGB9E10F",
|
||||
|
||||
"RGB8I",
|
||||
"RGB8UI",
|
||||
|
||||
"RGBA8UI",
|
||||
|
||||
"ARGB8",
|
||||
"BGR8",
|
||||
|
||||
"R8",
|
||||
|
||||
"RG8",
|
||||
"RG8I",
|
||||
"RG8UI",
|
||||
|
||||
"RG16F",
|
||||
|
||||
"RGBA8",
|
||||
"RGBA16",
|
||||
"RGBA16F",
|
||||
"RGBA32F",
|
||||
|
||||
"RGBA32UI",
|
||||
|
||||
"BAYER_RGGB8",
|
||||
"BAYER_GRBG8",
|
||||
"BAYER_GBRG8",
|
||||
"BAYER_BGGR8",
|
||||
"BAYER_RGGB32F",
|
||||
"BAYER_GRBG32F",
|
||||
"BAYER_GBRG32F",
|
||||
"BAYER_BGGR32F",
|
||||
|
||||
"HSV8",
|
||||
"HSV32F",
|
||||
|
||||
"YUV420_PLANAR",
|
||||
"YUV422",
|
||||
"YUV444",
|
||||
|
||||
"RGB_DXT1",
|
||||
"RGBA_DXT1",
|
||||
"RGBA_DXT3",
|
||||
"RGBA_DXT5",
|
||||
|
||||
"SRGB8",
|
||||
"SRGBA8",
|
||||
|
||||
"SL8",
|
||||
"SLA8",
|
||||
|
||||
"SRGB_DXT1",
|
||||
"SRGBA_DXT1",
|
||||
"SRGBA_DXT3",
|
||||
"SRGBA_DXT5",
|
||||
|
||||
"DEPTH16",
|
||||
"DEPTH24",
|
||||
"DEPTH32",
|
||||
"DEPTH32F",
|
||||
|
||||
"STENCIL1",
|
||||
"STENCIL4",
|
||||
"STENCIL8",
|
||||
"STENCIL16",
|
||||
|
||||
"DEPTH24_STENCIL8",
|
||||
""
|
||||
};
|
||||
|
||||
const std::string& ImageFormat::name() const {
|
||||
debugAssert(code < CODE_NUM);
|
||||
return nameArray[code];
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* ImageFormat::fromString(const std::string& s) {
|
||||
|
||||
for (int i = 0; ! nameArray[i].empty(); ++i) {
|
||||
if (s == nameArray[i]) {
|
||||
return fromCode(ImageFormat::Code(i));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
|
||||
switch (code) {
|
||||
case ImageFormat::CODE_L8:
|
||||
return ImageFormat::L8();
|
||||
|
||||
case ImageFormat::CODE_L16:
|
||||
return ImageFormat::L16();
|
||||
|
||||
case ImageFormat::CODE_L16F:
|
||||
return ImageFormat::L16F();
|
||||
|
||||
case ImageFormat::CODE_L32F:
|
||||
return ImageFormat::L32F();
|
||||
|
||||
case ImageFormat::CODE_A8:
|
||||
return ImageFormat::A8();
|
||||
|
||||
case ImageFormat::CODE_A16:
|
||||
return ImageFormat::A16();
|
||||
|
||||
case ImageFormat::CODE_A16F:
|
||||
return ImageFormat::A16F();
|
||||
|
||||
case ImageFormat::CODE_A32F:
|
||||
return ImageFormat::A32F();
|
||||
|
||||
case ImageFormat::CODE_LA4:
|
||||
return ImageFormat::LA4();
|
||||
|
||||
case ImageFormat::CODE_LA8:
|
||||
return ImageFormat::LA8();
|
||||
|
||||
case ImageFormat::CODE_LA16:
|
||||
return ImageFormat::LA16();
|
||||
|
||||
case ImageFormat::CODE_LA16F:
|
||||
return ImageFormat::LA16F();
|
||||
break;
|
||||
case ImageFormat::CODE_LA32F:
|
||||
return ImageFormat::LA32F();
|
||||
|
||||
case ImageFormat::CODE_RGB5:
|
||||
return ImageFormat::RGB5();
|
||||
|
||||
case ImageFormat::CODE_RGB5A1:
|
||||
return ImageFormat::RGB5A1();
|
||||
|
||||
case ImageFormat::CODE_RGB8:
|
||||
return ImageFormat::RGB8();
|
||||
|
||||
case ImageFormat::CODE_RGB10:
|
||||
return ImageFormat::RGB10();
|
||||
|
||||
case ImageFormat::CODE_RGB10A2:
|
||||
return ImageFormat::RGB10A2();
|
||||
|
||||
case ImageFormat::CODE_RGB16:
|
||||
return ImageFormat::RGB16();
|
||||
|
||||
case ImageFormat::CODE_RGB32F:
|
||||
return ImageFormat::RGB32F();
|
||||
|
||||
case ImageFormat::CODE_R11G11B10F:
|
||||
return ImageFormat::R11G11B10F();
|
||||
|
||||
case ImageFormat::CODE_RGB9E5F:
|
||||
return ImageFormat::RGB9E5F();
|
||||
|
||||
case ImageFormat::CODE_RGB8I:
|
||||
return ImageFormat::RGB8I();
|
||||
|
||||
case ImageFormat::CODE_RGB8UI:
|
||||
return ImageFormat::RGB8UI();
|
||||
|
||||
case ImageFormat::CODE_ARGB8:
|
||||
return NULL;
|
||||
|
||||
case ImageFormat::CODE_BGR8:
|
||||
return ImageFormat::BGR8();
|
||||
|
||||
case ImageFormat::CODE_R8:
|
||||
return ImageFormat::R8();
|
||||
|
||||
case ImageFormat::CODE_RG8:
|
||||
return ImageFormat::RG8();
|
||||
|
||||
case ImageFormat::CODE_RG8I:
|
||||
return ImageFormat::RG8I();
|
||||
|
||||
case ImageFormat::CODE_RG8UI:
|
||||
return ImageFormat::RG8UI();
|
||||
|
||||
case ImageFormat::CODE_RG16F:
|
||||
return ImageFormat::RG16F();
|
||||
|
||||
case ImageFormat::CODE_RGBA8:
|
||||
return ImageFormat::RGBA8();
|
||||
|
||||
case ImageFormat::CODE_RGBA16:
|
||||
return ImageFormat::RGBA16();
|
||||
|
||||
case ImageFormat::CODE_RGBA16F:
|
||||
return ImageFormat::RGBA16F();
|
||||
|
||||
case ImageFormat::CODE_RGBA32F:
|
||||
return ImageFormat::RGBA32F();
|
||||
|
||||
case ImageFormat::CODE_RGBA32UI:
|
||||
return ImageFormat::RGBA32UI();
|
||||
|
||||
case ImageFormat::CODE_BAYER_RGGB8:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_GRBG8:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_GBRG8:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_BGGR8:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_RGGB32F:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_GRBG32F:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_GBRG32F:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_BGGR32F:
|
||||
// TODO
|
||||
|
||||
case ImageFormat::CODE_HSV8:
|
||||
// TODO
|
||||
case ImageFormat::CODE_HSV32F:
|
||||
// TODO
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_RGB_DXT1:
|
||||
return ImageFormat::RGB_DXT1();
|
||||
break;
|
||||
case ImageFormat::CODE_RGBA_DXT1:
|
||||
return ImageFormat::RGBA_DXT1();
|
||||
break;
|
||||
case ImageFormat::CODE_RGBA_DXT3:
|
||||
return ImageFormat::RGBA_DXT3();
|
||||
break;
|
||||
case ImageFormat::CODE_RGBA_DXT5:
|
||||
return ImageFormat::RGBA_DXT5();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGB8:
|
||||
return ImageFormat::SRGB8();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGBA8:
|
||||
return ImageFormat::SRGBA8();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SL8:
|
||||
return ImageFormat::SL8();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SLA8:
|
||||
return ImageFormat::SLA8();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGB_DXT1:
|
||||
return ImageFormat::SRGB_DXT1();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGBA_DXT1:
|
||||
return ImageFormat::SRGBA_DXT1();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGBA_DXT3:
|
||||
return ImageFormat::SRGBA_DXT3();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGBA_DXT5:
|
||||
return ImageFormat::SRGBA_DXT5();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_DEPTH16:
|
||||
return ImageFormat::DEPTH16();
|
||||
break;
|
||||
case ImageFormat::CODE_DEPTH24:
|
||||
return ImageFormat::DEPTH24();
|
||||
break;
|
||||
case ImageFormat::CODE_DEPTH32:
|
||||
return ImageFormat::DEPTH32();
|
||||
break;
|
||||
case ImageFormat::CODE_DEPTH32F:
|
||||
return ImageFormat::DEPTH32F();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_STENCIL1:
|
||||
return ImageFormat::STENCIL1();
|
||||
break;
|
||||
case ImageFormat::CODE_STENCIL4:
|
||||
return ImageFormat::STENCIL4();
|
||||
break;
|
||||
case ImageFormat::CODE_STENCIL8:
|
||||
return ImageFormat::STENCIL8();
|
||||
break;
|
||||
case ImageFormat::CODE_STENCIL16:
|
||||
return ImageFormat::STENCIL16();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_DEPTH24_STENCIL8:
|
||||
return ImageFormat::DEPTH24_STENCIL8();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_YUV420_PLANAR:
|
||||
return ImageFormat::YUV420_PLANAR();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_YUV422:
|
||||
return ImageFormat::YUV422();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_YUV444:
|
||||
return ImageFormat::YUV444();
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper variables for defining texture formats
|
||||
|
||||
// Is floating point format
|
||||
static const bool FLOAT_FORMAT = true;
|
||||
static const bool INT_FORMAT = false;
|
||||
|
||||
// Is opaque format (no alpha)
|
||||
static const bool OPAQUE_FORMAT = true;
|
||||
static const bool CLEAR_FORMAT = false;
|
||||
|
||||
// Is compressed format (not raw component data)
|
||||
static const bool COMP_FORMAT = true;
|
||||
static const bool UNCOMP_FORMAT = false;
|
||||
|
||||
#define DEFINE_TEXTUREFORMAT_METHOD(enumname, cmpnts, cmprssd, glf, glbf, lb, ab, rb, gb, bb, db, sb, hbpt, pbpt, gldf, opq, fp, code, cs) \
|
||||
const ImageFormat* ImageFormat::enumname() { \
|
||||
static const ImageFormat format(cmpnts, cmprssd, glf, glbf, lb, ab, rb, gb, bb, db, sb, hbpt, pbpt, gldf, opq, fp, code, cs); \
|
||||
return &format; }
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(L8, 1, UNCOMP_FORMAT, GL_LUMINANCE8, GL_LUMINANCE, 8, 0, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, CODE_L8, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(L16, 1, UNCOMP_FORMAT, GL_LUMINANCE16, GL_LUMINANCE, 16, 0, 0, 0, 0, 0, 0, 16, 16,GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INT_FORMAT, CODE_L16, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(L16F, 1, UNCOMP_FORMAT, GL_LUMINANCE16F_ARB,GL_LUMINANCE, 16, 0, 0, 0, 0, 0, 0, 16, 16, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, CODE_L16F, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(L32F, 1, UNCOMP_FORMAT, GL_LUMINANCE32F_ARB,GL_LUMINANCE, 32, 0, 0, 0, 0, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, CODE_L32F, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(A8, 1, UNCOMP_FORMAT, GL_ALPHA8, GL_ALPHA, 0, 8, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, CODE_A8, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(A16, 1, UNCOMP_FORMAT, GL_ALPHA16, GL_ALPHA, 0, 16, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, CODE_A16, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(A16F, 1, UNCOMP_FORMAT, GL_ALPHA16F_ARB, GL_ALPHA, 0, 16, 0, 0, 0, 0, 0, 16, 16, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, CODE_A16F, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(A32F, 1, UNCOMP_FORMAT, GL_ALPHA32F_ARB, GL_ALPHA, 0, 32, 0, 0, 0, 0, 0, 32, 32, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, CODE_A32F, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(LA4, 2, UNCOMP_FORMAT, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE_ALPHA, 4, 4, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, CODE_LA4, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(LA8, 2, UNCOMP_FORMAT, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, 8, 8, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, CODE_LA8, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(LA16, 2, UNCOMP_FORMAT, GL_LUMINANCE16_ALPHA16, GL_LUMINANCE_ALPHA, 16, 16, 0, 0, 0, 0, 0, 16*2, 16*2, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, CODE_LA16, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(LA16F, 2, UNCOMP_FORMAT, GL_LUMINANCE_ALPHA16F_ARB, GL_LUMINANCE_ALPHA, 16, 16, 0, 0, 0, 0, 0, 16*2, 16*2, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_LA16F, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(LA32F, 2, UNCOMP_FORMAT, GL_LUMINANCE_ALPHA32F_ARB, GL_LUMINANCE_ALPHA, 32, 32, 0, 0, 0, 0, 0, 32*2, 32*2, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_LA32F, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(BGR8, 3, UNCOMP_FORMAT, GL_RGB8, GL_BGR, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_BGR8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(R8, 1, UNCOMP_FORMAT, GL_R8, GL_RED, 0, 0, 8, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_R8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8, 2, UNCOMP_FORMAT, GL_RG8, GL_RG, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
// The base format for integer formats must be *_INTEGER even though the spec doesn't state this
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8I, 2, UNCOMP_FORMAT, GL_RG8I, GL_RG_INTEGER, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8I, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8UI, 2, UNCOMP_FORMAT, GL_RG8UI, GL_RG_INTEGER, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG16F, 2, UNCOMP_FORMAT, GL_RG16F, GL_RG, 0, 0, 16, 16, 0, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RG16F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB5, 3, UNCOMP_FORMAT, GL_RGB5, GL_RGBA, 0, 0, 5, 5, 5, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB5, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB5A1, 4, UNCOMP_FORMAT, GL_RGB5_A1, GL_RGBA, 0, 1, 5, 5, 5, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB5A1, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB8, 3, UNCOMP_FORMAT, GL_RGB8, GL_RGB, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB10, 3, UNCOMP_FORMAT, GL_RGB10, GL_RGB, 0, 0, 10, 10, 10, 0, 0, 32, 10*3, GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB10, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB10A2, 4, UNCOMP_FORMAT, GL_RGB10_A2, GL_RGBA, 0, 2, 10, 10, 10, 0, 0, 32, 32, GL_UNSIGNED_INT_10_10_10_2, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB10A2, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB16, 3, UNCOMP_FORMAT, GL_RGB16, GL_RGB, 0, 0, 16, 16, 16, 0, 0, 16*3, 16*3, GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB16, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB16F, 3, UNCOMP_FORMAT, GL_RGB16F_ARB, GL_RGB, 0, 0, 16, 16, 16, 0, 0, 16*3, 16*3, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGB16F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB32F, 3, UNCOMP_FORMAT, GL_RGB32F_ARB, GL_RGB, 0, 0, 32, 32, 32, 0, 0, 32*3, 32*3, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGB32F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA8, 4, UNCOMP_FORMAT, GL_RGBA8, GL_RGBA, 0, 8, 8, 8, 8, 0, 0, 32, 32, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA16, 4, UNCOMP_FORMAT, GL_RGBA16, GL_RGBA, 0, 16, 16, 16, 16, 0, 0, 16*4, 16*4, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA16, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA16F, 4, UNCOMP_FORMAT, GL_RGBA16F_ARB, GL_RGBA, 0, 16, 16, 16, 16, 0, 0, 16*4, 16*4, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGBA16F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA32F, 4, UNCOMP_FORMAT, GL_RGBA32F_ARB, GL_RGBA, 0, 32, 32, 32, 32, 0, 0, 32*4, 32*4, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGBA32F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
// The base format for integer formats must be *_INTEGER even though the spec doesn't state this
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA32UI, 4, UNCOMP_FORMAT, GL_RGBA32UI, GL_RGBA_INTEGER, 0, 32, 32, 32, 32, 0, 0, 32*4, 32*4, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA32UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
// Unsigned
|
||||
DEFINE_TEXTUREFORMAT_METHOD(R11G11B10F, 3, UNCOMP_FORMAT, GL_R11F_G11F_B10F_EXT, GL_RGB, 0, 0, 11, 11, 10, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_R11G11B10F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
// Unsigned
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB9E5F, 3, UNCOMP_FORMAT, GL_RGB9_E5_EXT, GL_RGB, 0, 0, 14, 14, 14, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGB9E5F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
// The base format for integer formats must be *_INTEGER even though the spec doesn't state this
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB8I, 3, UNCOMP_FORMAT, GL_RGB8I_EXT, GL_RGB_INTEGER, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8I, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB8UI, 3, UNCOMP_FORMAT, GL_RGB8UI_EXT, GL_RGB_INTEGER, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA8UI, 4, UNCOMP_FORMAT, GL_RGBA8UI_EXT, GL_RGBA_INTEGER, 0, 0, 8, 8, 8, 8, 0, 32, 32, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA8UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB_DXT1, 3, COMP_FORMAT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB_DXT1, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA_DXT1, 4, COMP_FORMAT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA_DXT1, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA_DXT3, 4, COMP_FORMAT, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 128, 128, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA_DXT3, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA_DXT5, 4, COMP_FORMAT, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 128, 128, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA_DXT5, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGB8, 3, UNCOMP_FORMAT, GL_SRGB8, GL_RGB, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGB8, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGBA8, 4, UNCOMP_FORMAT, GL_SRGB8_ALPHA8, GL_RGBA, 0, 8, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGBA8, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SL8, 1, UNCOMP_FORMAT, GL_SLUMINANCE8, GL_LUMINANCE, 8, 0, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_SL8, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SLA8, 2, UNCOMP_FORMAT, GL_SLUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, 8, 8, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_SLA8, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGB_DXT1, 3, COMP_FORMAT, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGB, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGB_DXT1, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGBA_DXT1, 4, COMP_FORMAT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGBA_DXT1, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGBA_DXT3, 4, COMP_FORMAT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 128, 128, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGBA_DXT3, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGBA_DXT5, 4, COMP_FORMAT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 128, 128, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGBA_DXT5, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(DEPTH16, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT16_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 16, 0, 16, 16, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH16, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(DEPTH24, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT24_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 24, 0, 32, 24, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH24, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(DEPTH32, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT32_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 32, 0, 32, 32, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH32, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(DEPTH32F, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT32_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 32, 0, 32, 32, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_DEPTH32F, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
// These formats are for use with Renderbuffers only!
|
||||
DEFINE_TEXTUREFORMAT_METHOD(STENCIL1, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX1_EXT, GL_STENCIL_INDEX, 0, 0, 0, 0, 0, 0, 1, 1, 1, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL1, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(STENCIL4, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX4_EXT, GL_STENCIL_INDEX, 0, 0, 0, 0, 0, 0, 4, 4, 4, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL4, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(STENCIL8, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX8_EXT, GL_STENCIL_INDEX, 0, 0, 0, 0, 0, 0, 8, 8, 8, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL8, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(STENCIL16, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX16_EXT, GL_STENCIL_INDEX, 0, 0, 0, 0, 0, 0, 16, 16, 16, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL16, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(DEPTH24_STENCIL8, 2, UNCOMP_FORMAT, GL_DEPTH24_STENCIL8_EXT, GL_DEPTH_STENCIL_EXT,0, 0, 0, 0, 0, 24, 8, 32, 32, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH24_STENCIL8, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(YUV420_PLANAR, 3, UNCOMP_FORMAT, GL_NONE, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 12, 12, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_YUV420_PLANAR, ImageFormat::COLOR_SPACE_YUV);
|
||||
DEFINE_TEXTUREFORMAT_METHOD(YUV422, 3, UNCOMP_FORMAT, GL_NONE, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_YUV422, ImageFormat::COLOR_SPACE_YUV);
|
||||
DEFINE_TEXTUREFORMAT_METHOD(YUV444, 3, UNCOMP_FORMAT, GL_NONE, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 24, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_YUV444, ImageFormat::COLOR_SPACE_YUV);
|
||||
|
||||
}
|
||||
1307
modules/acore/deps/g3dlite/source/ImageFormat_convert.cpp
Normal file
1307
modules/acore/deps/g3dlite/source/ImageFormat_convert.cpp
Normal file
File diff suppressed because it is too large
Load Diff
844
modules/acore/deps/g3dlite/source/Intersect.cpp
Normal file
844
modules/acore/deps/g3dlite/source/Intersect.cpp
Normal file
@@ -0,0 +1,844 @@
|
||||
/**
|
||||
@file Intersect.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2009-06-29
|
||||
@edited 2009-06-29
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
|
||||
From the G3D Innovation Engine
|
||||
http://g3d.sf.net
|
||||
*/
|
||||
#include "G3D/Intersect.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Turn on fast floating-point optimizations
|
||||
#pragma float_control( push )
|
||||
#pragma fp_contract( on )
|
||||
#pragma fenv_access( off )
|
||||
#pragma float_control( except, off )
|
||||
#pragma float_control( precise, off )
|
||||
#endif
|
||||
|
||||
bool __fastcall Intersect::rayAABox(const Ray& ray, const AABox& box) {
|
||||
switch (ray.classification) {
|
||||
case Ray::MMM:
|
||||
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MMP:
|
||||
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MPM:
|
||||
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MPP:
|
||||
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PMM:
|
||||
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PMP:
|
||||
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PPM:
|
||||
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PPP:
|
||||
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::OMM:
|
||||
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::OMP:
|
||||
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::OPM:
|
||||
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::OPP:
|
||||
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MOM:
|
||||
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MOP:
|
||||
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::POM:
|
||||
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::POP:
|
||||
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MMO:
|
||||
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MPO:
|
||||
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PMO:
|
||||
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PPO:
|
||||
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MOO:
|
||||
|
||||
if((ray.m_origin.x < box.lo.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::POO:
|
||||
|
||||
if((ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::OMO:
|
||||
|
||||
if((ray.m_origin.y < box.lo.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
)
|
||||
return false;
|
||||
|
||||
case Ray::OPO:
|
||||
|
||||
if((ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
)
|
||||
return false;
|
||||
|
||||
case Ray::OOM:
|
||||
|
||||
if((ray.m_origin.z < box.lo.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
)
|
||||
return false;
|
||||
|
||||
case Ray::OOP:
|
||||
|
||||
if((ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool __fastcall Intersect::rayAABox(const Ray& ray, const AABox& box, float& time) {
|
||||
|
||||
switch (ray.classification) {
|
||||
case Ray::MMM:
|
||||
{
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// compute the intersection distance
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::MMP:
|
||||
{
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::MPM:
|
||||
{
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::MPP:
|
||||
{
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::PMM:
|
||||
{
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::PMP:
|
||||
{
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::PPM:
|
||||
{
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::PPP:
|
||||
{
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OMM:
|
||||
{
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OMP:
|
||||
{
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OPM:
|
||||
{
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OPP:
|
||||
{
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::MOM:
|
||||
{
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::MOP:
|
||||
{
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::POM:
|
||||
{
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::POP:
|
||||
{
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::MMO:
|
||||
{
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::MPO:
|
||||
{
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::PMO:
|
||||
{
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::PPO:
|
||||
{
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::MOO:
|
||||
{
|
||||
if((ray.m_origin.x < box.lo.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::POO:
|
||||
{
|
||||
if ((ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OMO:
|
||||
{
|
||||
if ((ray.m_origin.y < box.lo.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OPO:
|
||||
{
|
||||
if ((ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::OOM:
|
||||
{
|
||||
if ((ray.m_origin.z < box.lo.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OOP:
|
||||
{
|
||||
if ((ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Turn off fast floating-point optimizations
|
||||
#pragma float_control( pop )
|
||||
#endif
|
||||
|
||||
}
|
||||
89
modules/acore/deps/g3dlite/source/Line.cpp
Normal file
89
modules/acore/deps/g3dlite/source/Line.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
@file Line.cpp
|
||||
|
||||
Line class
|
||||
|
||||
@maintainer Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2006-01-28
|
||||
*/
|
||||
|
||||
#include "G3D/Line.h"
|
||||
#include "G3D/Plane.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector3 Line::intersection(const Plane& plane) const {
|
||||
float d;
|
||||
Vector3 normal = plane.normal();
|
||||
plane.getEquation(normal, d);
|
||||
float rate = _direction.dot(normal);
|
||||
|
||||
if (rate == 0) {
|
||||
|
||||
return Vector3::inf();
|
||||
|
||||
} else {
|
||||
float t = -(d + _point.dot(normal)) / rate;
|
||||
|
||||
return _point + _direction * t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Line::Line(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Line::serialize(class BinaryOutput& b) const {
|
||||
_point.serialize(b);
|
||||
_direction.serialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Line::deserialize(class BinaryInput& b) {
|
||||
_point.deserialize(b);
|
||||
_direction.deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
Vector3 Line::closestPoint(const Vector3& pt) const {
|
||||
float t = _direction.dot(pt - _point);
|
||||
return _point + _direction * t;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Line::point() const {
|
||||
return _point;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Line::direction() const {
|
||||
return _direction;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Line::closestPoint(const Line& B, float& minDist) const {
|
||||
const Vector3& P1 = _point;
|
||||
const Vector3& U1 = _direction;
|
||||
|
||||
Vector3 P2 = B.point();
|
||||
Vector3 U2 = B.direction();
|
||||
|
||||
const Vector3& P21 = P2 - P1;
|
||||
const Vector3& M = U2.cross(U1);
|
||||
float m2 = M.length();
|
||||
|
||||
Vector3 R = P21.cross(M) / m2;
|
||||
|
||||
float t1 = R.dot(U2);
|
||||
|
||||
minDist = abs(P21.dot(M)) / sqrt(m2);
|
||||
|
||||
return P1 + t1 * U1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
236
modules/acore/deps/g3dlite/source/LineSegment.cpp
Normal file
236
modules/acore/deps/g3dlite/source/LineSegment.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
@file LineSegment.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-02-08
|
||||
@edited 2008-02-02
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/LineSegment.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/debug.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
Vector3 LineSegment::closestPoint(const Vector3& p) const {
|
||||
|
||||
// The vector from the end of the capsule to the point in question.
|
||||
Vector3 v(p - _point);
|
||||
|
||||
// Projection of v onto the line segment scaled by
|
||||
// the length of direction.
|
||||
float t = direction.dot(v);
|
||||
|
||||
// Avoid some square roots. Derivation:
|
||||
// t/direction.length() <= direction.length()
|
||||
// t <= direction.squaredLength()
|
||||
|
||||
if ((t >= 0) && (t <= direction.squaredMagnitude())) {
|
||||
|
||||
// The point falls within the segment. Normalize direction,
|
||||
// divide t by the length of direction.
|
||||
return _point + direction * t / direction.squaredMagnitude();
|
||||
|
||||
} else {
|
||||
|
||||
// The point does not fall within the segment; see which end is closer.
|
||||
|
||||
// Distance from 0, squared
|
||||
float d0Squared = v.squaredMagnitude();
|
||||
|
||||
// Distance from 1, squared
|
||||
float d1Squared = (v - direction).squaredMagnitude();
|
||||
|
||||
if (d0Squared < d1Squared) {
|
||||
|
||||
// Point 0 is closer
|
||||
return _point;
|
||||
|
||||
} else {
|
||||
|
||||
// Point 1 is closer
|
||||
return _point + direction;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vector3 LineSegment::point(int i) const {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return _point;
|
||||
|
||||
case 1:
|
||||
return _point + direction;
|
||||
|
||||
default:
|
||||
debugAssertM(i == 0 || i == 1, "Argument to point must be 0 or 1");
|
||||
return _point;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LineSegment::intersectsSolidSphere(const class Sphere& s) const {
|
||||
return distanceSquared(s.center) <= square(s.radius);
|
||||
}
|
||||
|
||||
|
||||
LineSegment::LineSegment(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void LineSegment::serialize(class BinaryOutput& b) const {
|
||||
_point.serialize(b);
|
||||
direction.serialize(b);
|
||||
}
|
||||
|
||||
|
||||
void LineSegment::deserialize(class BinaryInput& b) {
|
||||
_point.deserialize(b);
|
||||
direction.deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
Vector3 LineSegment::randomPoint() const {
|
||||
return _point + uniformRandom(0, 1) * direction;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LineSegment2D LineSegment2D::fromTwoPoints(const Vector2& p0, const Vector2& p1) {
|
||||
LineSegment2D s;
|
||||
s.m_origin = p0;
|
||||
s.m_direction = p1 - p0;
|
||||
s.m_length = s.m_direction.length();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Vector2 LineSegment2D::point(int i) const {
|
||||
debugAssert(i == 0 || i == 1);
|
||||
if (i == 0) {
|
||||
return m_origin;
|
||||
} else {
|
||||
return m_direction + m_origin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector2 LineSegment2D::closestPoint(const Vector2& Q) const {
|
||||
// Two constants that appear in the result
|
||||
const Vector2 k1(m_origin - Q);
|
||||
const Vector2& k2 = m_direction;
|
||||
|
||||
if (fuzzyEq(m_length, 0)) {
|
||||
// This line segment has no length
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
// Time [0, 1] at which we hit the closest point travelling from p0 to p1.
|
||||
// Derivation can be obtained by minimizing the expression
|
||||
// ||P0 + (P1 - P0)t - Q||.
|
||||
const float t = -k1.dot(k2) / (m_length * m_length);
|
||||
|
||||
if (t < 0) {
|
||||
// Clipped to low end point
|
||||
return m_origin;
|
||||
} else if (t > 1) {
|
||||
// Clipped to high end point
|
||||
return m_origin + m_direction;
|
||||
} else {
|
||||
// Subsitute into the line equation to find
|
||||
// the point on the segment.
|
||||
return m_origin + k2 * t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float LineSegment2D::distance(const Vector2& p) const {
|
||||
Vector2 closest = closestPoint(p);
|
||||
return (closest - p).length();
|
||||
}
|
||||
|
||||
|
||||
float LineSegment2D::length() const {
|
||||
return m_length;
|
||||
}
|
||||
|
||||
|
||||
Vector2 LineSegment2D::intersection(const LineSegment2D& other) const {
|
||||
|
||||
if ((m_origin == other.m_origin) ||
|
||||
(m_origin == other.m_origin + other.m_direction)) {
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
if (m_origin + m_direction == other.m_origin) {
|
||||
return other.m_origin;
|
||||
}
|
||||
|
||||
// Note: Now that we've checked the endpoints, all other parallel lines can now be assumed
|
||||
// to not intersect (within numerical precision)
|
||||
|
||||
Vector2 dir1 = m_direction;
|
||||
Vector2 dir2 = other.m_direction;
|
||||
Vector2 origin1 = m_origin;
|
||||
Vector2 origin2 = other.m_origin;
|
||||
|
||||
if (dir1.x == 0) {
|
||||
// Avoid an upcoming divide by zero
|
||||
dir1 = dir1.yx();
|
||||
dir2 = dir2.yx();
|
||||
origin1 = origin1.yx();
|
||||
origin2 = origin2.yx();
|
||||
}
|
||||
|
||||
// t1 = ((other.m_origin.x - m_origin.x) + other.m_direction.x * t2) / m_direction.x
|
||||
//
|
||||
// ((other.m_origin.x - m_origin.x) + other.m_direction.x * t2) * m_direction.y / m_direction.x =
|
||||
// (other.m_origin.y - m_origin.y) + other.m_direction.y * t2
|
||||
//
|
||||
// m = m_direction.y / m_direction.x
|
||||
// d = other.m_origin - m_origin
|
||||
//
|
||||
// (d.x + other.m_direction.x * t2) * m = d.y + other.m_direction.y * t2
|
||||
//
|
||||
// d.x * m + other.m_direction.x * m * t2 = d.y + other.m_direction.y * t2
|
||||
//
|
||||
// d.x * m - d.y = (other.m_direction.y - other.m_direction.x * m) * t2
|
||||
//
|
||||
// (d.x * m - d.y) / (other.m_direction.y - other.m_direction.x * m) = t2
|
||||
//
|
||||
|
||||
Vector2 d = origin2 - origin1;
|
||||
float m = dir1.y / dir1.x;
|
||||
|
||||
float t2 = (d.x * m - d.y) / (dir2.y - dir2.x * m);
|
||||
if (! isFinite(t2)) {
|
||||
// Parallel lines: no intersection
|
||||
return Vector2::inf();
|
||||
}
|
||||
|
||||
if ((t2 < 0.0f) || (t2 > 1.0f)) {
|
||||
// Intersection occurs past the end of the line segments
|
||||
return Vector2::inf();
|
||||
}
|
||||
|
||||
float t1 = (d.x + dir2.x * t2) / dir1.x;
|
||||
if ((t1 < 0.0f) || (t1 > 1.0f)) {
|
||||
// Intersection occurs past the end of the line segments
|
||||
return Vector2::inf();
|
||||
}
|
||||
|
||||
// Return the intersection point (computed from non-transposed
|
||||
// variables even if we flipped above)
|
||||
return m_origin + m_direction * t1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
147
modules/acore/deps/g3dlite/source/Log.cpp
Normal file
147
modules/acore/deps/g3dlite/source/Log.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
@file Log.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2001-08-04
|
||||
@edited 2010-01-15
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Log.h"
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/Array.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
#include <time.h>
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
#include <imagehlp.h>
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void logPrintf(const char* fmt, ...) {
|
||||
va_list arg_list;
|
||||
va_start(arg_list, fmt);
|
||||
Log::common()->vprintf(fmt, arg_list);
|
||||
va_end(arg_list);
|
||||
}
|
||||
|
||||
|
||||
void logLazyPrintf(const char* fmt, ...) {
|
||||
va_list arg_list;
|
||||
va_start(arg_list, fmt);
|
||||
Log::common()->lazyvprintf(fmt, arg_list);
|
||||
va_end(arg_list);
|
||||
}
|
||||
|
||||
Log* Log::commonLog = NULL;
|
||||
|
||||
Log::Log(const std::string& filename, int stripFromStackBottom) :
|
||||
stripFromStackBottom(stripFromStackBottom) {
|
||||
|
||||
this->filename = filename;
|
||||
|
||||
logFile = FileSystem::fopen(filename.c_str(), "w");
|
||||
|
||||
if (logFile == NULL) {
|
||||
std::string drive, base, ext;
|
||||
Array<std::string> path;
|
||||
parseFilename(filename, drive, path, base, ext);
|
||||
std::string logName = base + ((ext != "") ? ("." + ext) : "");
|
||||
|
||||
// Write time is greater than 1ms. This may be a network drive.... try another file.
|
||||
#ifdef G3D_WIN32
|
||||
logName = std::string(std::getenv("TEMP")) + logName;
|
||||
#else
|
||||
logName = std::string("/tmp/") + logName;
|
||||
#endif
|
||||
|
||||
logFile = FileSystem::fopen(logName.c_str(), "w");
|
||||
}
|
||||
|
||||
// Use a large buffer (although we flush in logPrintf)
|
||||
setvbuf(logFile, NULL, _IOFBF, 2048);
|
||||
|
||||
fprintf(logFile, "Application Log\n");
|
||||
time_t t;
|
||||
time(&t);
|
||||
fprintf(logFile, "Start: %s\n", ctime(&t));
|
||||
fflush(logFile);
|
||||
|
||||
if (commonLog == NULL) {
|
||||
commonLog = this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Log::~Log() {
|
||||
section("Shutdown");
|
||||
println("Closing log file");
|
||||
|
||||
// Make sure we don't leave a dangling pointer
|
||||
if (Log::commonLog == this) {
|
||||
Log::commonLog = NULL;
|
||||
}
|
||||
|
||||
fclose(logFile);
|
||||
}
|
||||
|
||||
|
||||
FILE* Log::getFile() const {
|
||||
return logFile;
|
||||
}
|
||||
|
||||
|
||||
Log* Log::common() {
|
||||
if (commonLog == NULL) {
|
||||
commonLog = new Log();
|
||||
}
|
||||
return commonLog;
|
||||
}
|
||||
|
||||
|
||||
std::string Log::getCommonLogFilename() {
|
||||
return common()->filename;
|
||||
}
|
||||
|
||||
|
||||
void Log::section(const std::string& s) {
|
||||
fprintf(logFile, "_____________________________________________________\n");
|
||||
fprintf(logFile, "\n ### %s ###\n\n", s.c_str());
|
||||
}
|
||||
|
||||
|
||||
void __cdecl Log::printf(const char* fmt, ...) {
|
||||
va_list arg_list;
|
||||
va_start(arg_list, fmt);
|
||||
print(vformat(fmt, arg_list));
|
||||
va_end(arg_list);
|
||||
}
|
||||
|
||||
|
||||
void __cdecl Log::vprintf(const char* fmt, va_list argPtr) {
|
||||
vfprintf(logFile, fmt, argPtr);
|
||||
fflush(logFile);
|
||||
}
|
||||
|
||||
|
||||
void __cdecl Log::lazyvprintf(const char* fmt, va_list argPtr) {
|
||||
vfprintf(logFile, fmt, argPtr);
|
||||
}
|
||||
|
||||
|
||||
void Log::print(const std::string& s) {
|
||||
fprintf(logFile, "%s", s.c_str());
|
||||
fflush(logFile);
|
||||
}
|
||||
|
||||
|
||||
void Log::println(const std::string& s) {
|
||||
fprintf(logFile, "%s\n", s.c_str());
|
||||
fflush(logFile);
|
||||
}
|
||||
|
||||
}
|
||||
1802
modules/acore/deps/g3dlite/source/Matrix.cpp
Normal file
1802
modules/acore/deps/g3dlite/source/Matrix.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1933
modules/acore/deps/g3dlite/source/Matrix3.cpp
Normal file
1933
modules/acore/deps/g3dlite/source/Matrix3.cpp
Normal file
File diff suppressed because it is too large
Load Diff
528
modules/acore/deps/g3dlite/source/Matrix4.cpp
Normal file
528
modules/acore/deps/g3dlite/source/Matrix4.cpp
Normal file
@@ -0,0 +1,528 @@
|
||||
/**
|
||||
@file Matrix4.cpp
|
||||
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-10-02
|
||||
@edited 2010-01-29
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Matrix4.h"
|
||||
#include "G3D/Matrix3.h"
|
||||
#include "G3D/Vector4.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Rect2D.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
Matrix4::Matrix4(const Any& any) {
|
||||
any.verifyName("Matrix4");
|
||||
any.verifyType(Any::ARRAY);
|
||||
|
||||
const std::string& name = toLower(any.name());
|
||||
if (name == "matrix4") {
|
||||
any.verifySize(16);
|
||||
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
elt[r][c] = any[r * 4 + c];
|
||||
}
|
||||
}
|
||||
} else if (name == "matrix4::scale") {
|
||||
if (any.size() == 1) {
|
||||
*this = scale(any[0].number());
|
||||
} else if (any.size() == 3) {
|
||||
*this = scale(any[0], any[1], any[2]);
|
||||
} else {
|
||||
any.verify(false, "Matrix4::scale() takes either 1 or 3 arguments");
|
||||
}
|
||||
} else if (name == "matrix4::translation") {
|
||||
if (any.size() == 3) {
|
||||
*this = translation(any[0], any[1], any[2]);
|
||||
} else {
|
||||
any.verify(false, "Matrix4::translation() takes either 1 or 3 arguments");
|
||||
} } else {
|
||||
any.verify(false, "Expected Matrix4 constructor");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Matrix4::operator Any() const {
|
||||
Any any(Any::ARRAY, "Matrix4");
|
||||
any.resize(16);
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
any[r * 4 + c] = elt[r][c];
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
const Matrix4& Matrix4::identity() {
|
||||
static Matrix4 m(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
const Matrix4& Matrix4::zero() {
|
||||
static Matrix4 m(
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
Matrix4::Matrix4(const class CoordinateFrame& cframe) {
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
elt[r][c] = cframe.rotation[r][c];
|
||||
}
|
||||
elt[r][3] = cframe.translation[r];
|
||||
}
|
||||
elt[3][0] = 0.0f;
|
||||
elt[3][1] = 0.0f;
|
||||
elt[3][2] = 0.0f;
|
||||
elt[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
Matrix4::Matrix4(const Matrix3& upper3x3, const Vector3& lastCol) {
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
elt[r][c] = upper3x3[r][c];
|
||||
}
|
||||
elt[r][3] = lastCol[r];
|
||||
}
|
||||
elt[3][0] = 0.0f;
|
||||
elt[3][1] = 0.0f;
|
||||
elt[3][2] = 0.0f;
|
||||
elt[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
Matrix3 Matrix4::upper3x3() const {
|
||||
return Matrix3(elt[0][0], elt[0][1], elt[0][2],
|
||||
elt[1][0], elt[1][1], elt[1][2],
|
||||
elt[2][0], elt[2][1], elt[2][2]);
|
||||
}
|
||||
|
||||
|
||||
Matrix4 Matrix4::orthogonalProjection(
|
||||
const class Rect2D& rect,
|
||||
float nearval,
|
||||
float farval,
|
||||
float upDirection) {
|
||||
return Matrix4::orthogonalProjection(rect.x0(), rect.x1(), rect.y1(), rect.y0(), nearval, farval, upDirection);
|
||||
}
|
||||
|
||||
|
||||
Matrix4 Matrix4::orthogonalProjection(
|
||||
float left,
|
||||
float right,
|
||||
float bottom,
|
||||
float top,
|
||||
float nearval,
|
||||
float farval,
|
||||
float upDirection) {
|
||||
|
||||
// Adapted from Mesa. Note that Microsoft (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/glfunc03_8qnj.asp)
|
||||
// and Linux (http://www.xfree86.org/current/glOrtho.3.html) have different matrices shown in their documentation.
|
||||
|
||||
float x, y, z;
|
||||
float tx, ty, tz;
|
||||
|
||||
x = 2.0f / (right-left);
|
||||
y = 2.0f / (top-bottom);
|
||||
z = -2.0f / (farval-nearval);
|
||||
tx = -(right+left) / (right-left);
|
||||
ty = -(top+bottom) / (top-bottom);
|
||||
tz = -(farval+nearval) / (farval-nearval);
|
||||
|
||||
y *= upDirection;
|
||||
ty *= upDirection;
|
||||
|
||||
return
|
||||
Matrix4( x , 0.0f, 0.0f, tx,
|
||||
0.0f, y , 0.0f, ty,
|
||||
0.0f, 0.0f, z , tz,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
Matrix4 Matrix4::perspectiveProjection(
|
||||
float left,
|
||||
float right,
|
||||
float bottom,
|
||||
float top,
|
||||
float nearval,
|
||||
float farval,
|
||||
float upDirection) {
|
||||
|
||||
float x, y, a, b, c, d;
|
||||
|
||||
x = (2.0f*nearval) / (right-left);
|
||||
y = (2.0f*nearval) / (top-bottom);
|
||||
a = (right+left) / (right-left);
|
||||
b = (top+bottom) / (top-bottom);
|
||||
|
||||
if (farval >= finf()) {
|
||||
// Infinite view frustum
|
||||
c = -1.0f;
|
||||
d = -2.0f * nearval;
|
||||
} else {
|
||||
c = -(farval+nearval) / (farval-nearval);
|
||||
d = -(2.0f*farval*nearval) / (farval-nearval);
|
||||
}
|
||||
|
||||
debugAssertM(abs(upDirection) == 1.0f, "upDirection must be -1 or +1");
|
||||
y *= upDirection;
|
||||
b *= upDirection;
|
||||
|
||||
return Matrix4(
|
||||
x, 0, a, 0,
|
||||
0, y, b, 0,
|
||||
0, 0, c, d,
|
||||
0, 0, -1, 0);
|
||||
}
|
||||
|
||||
|
||||
void Matrix4::getPerspectiveProjectionParameters(
|
||||
float& left,
|
||||
float& right,
|
||||
float& bottom,
|
||||
float& top,
|
||||
float& nearval,
|
||||
float& farval,
|
||||
float upDirection) const {
|
||||
|
||||
debugAssertM(abs(upDirection) == 1.0f, "upDirection must be -1 or +1");
|
||||
|
||||
float x = elt[0][0];
|
||||
float y = elt[1][1] * upDirection;
|
||||
float a = elt[0][2];
|
||||
float b = elt[1][2] * upDirection;
|
||||
float c = elt[2][2];
|
||||
float d = elt[2][3];
|
||||
|
||||
// Verify that this really is a projection matrix
|
||||
debugAssertM(elt[3][2] == -1, "Not a projection matrix");
|
||||
debugAssertM(elt[0][1] == 0, "Not a projection matrix");
|
||||
debugAssertM(elt[0][3] == 0, "Not a projection matrix");
|
||||
debugAssertM(elt[1][3] == 0, "Not a projection matrix");
|
||||
debugAssertM(elt[3][3] == 0, "Not a projection matrix");
|
||||
debugAssertM(elt[1][0] == 0, "Not a projection matrix");
|
||||
debugAssertM(elt[2][0] == 0, "Not a projection matrix");
|
||||
debugAssertM(elt[2][1] == 0, "Not a projection matrix");
|
||||
debugAssertM(elt[3][0] == 0, "Not a projection matrix");
|
||||
debugAssertM(elt[3][1] == 0, "Not a projection matrix");
|
||||
|
||||
if (c == -1) {
|
||||
farval = finf();
|
||||
nearval = -d / 2.0f;
|
||||
} else {
|
||||
nearval = d * ((c - 1.0f) / (c + 1.0f) - 1.0f) / (-2.0f * (c - 1.0f) / (c + 1.0f));
|
||||
farval = nearval * ((c - 1.0f) / (c + 1.0f));
|
||||
}
|
||||
|
||||
|
||||
left = (a - 1.0f) * nearval / x;
|
||||
right = 2.0f * nearval / x + left;
|
||||
|
||||
bottom = (b - 1.0f) * nearval / y;
|
||||
top = 2.0f * nearval / y + bottom;
|
||||
}
|
||||
|
||||
|
||||
Matrix4::Matrix4(
|
||||
float r1c1, float r1c2, float r1c3, float r1c4,
|
||||
float r2c1, float r2c2, float r2c3, float r2c4,
|
||||
float r3c1, float r3c2, float r3c3, float r3c4,
|
||||
float r4c1, float r4c2, float r4c3, float r4c4) {
|
||||
elt[0][0] = r1c1; elt[0][1] = r1c2; elt[0][2] = r1c3; elt[0][3] = r1c4;
|
||||
elt[1][0] = r2c1; elt[1][1] = r2c2; elt[1][2] = r2c3; elt[1][3] = r2c4;
|
||||
elt[2][0] = r3c1; elt[2][1] = r3c2; elt[2][2] = r3c3; elt[2][3] = r3c4;
|
||||
elt[3][0] = r4c1; elt[3][1] = r4c2; elt[3][2] = r4c3; elt[3][3] = r4c4;
|
||||
}
|
||||
|
||||
/**
|
||||
init should be <B>row major</B>.
|
||||
*/
|
||||
Matrix4::Matrix4(const float* init) {
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
elt[r][c] = init[r * 4 + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Matrix4::Matrix4(const double* init) {
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
elt[r][c] = (float)init[r * 4 + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Matrix4::Matrix4() {
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
elt[r][c] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Matrix4::setRow(int r, const Vector4& v) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
elt[r][c] = v[c];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Matrix4::setColumn(int c, const Vector4& v) {
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
elt[r][c] = v[r];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const Vector4& Matrix4::row(int r) const {
|
||||
return reinterpret_cast<const Vector4*>(elt[r])[0];
|
||||
}
|
||||
|
||||
|
||||
Vector4 Matrix4::column(int c) const {
|
||||
Vector4 v;
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
v[r] = elt[r][c];
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
Matrix4 Matrix4::operator*(const Matrix4& other) const {
|
||||
Matrix4 result;
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
result.elt[r][c] += elt[r][i] * other.elt[i][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Matrix4 Matrix4::operator*(const float s) const {
|
||||
Matrix4 result;
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
result.elt[r][c] = elt[r][c] * s;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Matrix4::homoMul(const class Vector3& v, float w) const {
|
||||
Vector4 r = (*this) * Vector4(v, w);
|
||||
return r.xyz() * (1.0f / r.w);
|
||||
}
|
||||
|
||||
|
||||
Vector4 Matrix4::operator*(const Vector4& vector) const {
|
||||
Vector4 result(0,0,0,0);
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
result[r] += elt[r][c] * vector[c];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Matrix4 Matrix4::transpose() const {
|
||||
Matrix4 result;
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
result.elt[c][r] = elt[r][c];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool Matrix4::operator!=(const Matrix4& other) const {
|
||||
return ! (*this == other);
|
||||
}
|
||||
|
||||
|
||||
bool Matrix4::operator==(const Matrix4& other) const {
|
||||
|
||||
// If the bit patterns are identical, they must be
|
||||
// the same matrix. If not, they *might* still have
|
||||
// equal elements due to floating point weirdness.
|
||||
if (memcmp(this, &other, sizeof(Matrix4)) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
if (elt[r][c] != other.elt[r][c]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
float Matrix4::determinant() const {
|
||||
// Determinant is the dot product of the first row and the first row
|
||||
// of cofactors (i.e. the first col of the adjoint matrix)
|
||||
return cofactor().row(0).dot(row(0));
|
||||
}
|
||||
|
||||
|
||||
Matrix4 Matrix4::adjoint() const {
|
||||
return cofactor().transpose();
|
||||
}
|
||||
|
||||
|
||||
Matrix4 Matrix4::inverse() const {
|
||||
// Inverse = adjoint / determinant
|
||||
|
||||
Matrix4 A = adjoint();
|
||||
|
||||
// Determinant is the dot product of the first row and the first row
|
||||
// of cofactors (i.e. the first col of the adjoint matrix)
|
||||
float det = A.column(0).dot(row(0));
|
||||
|
||||
return A * (1.0f / det);
|
||||
}
|
||||
|
||||
|
||||
Matrix4 Matrix4::cofactor() const {
|
||||
Matrix4 out;
|
||||
|
||||
// We'll use i to incrementally compute -1 ^ (r+c)
|
||||
int i = 1;
|
||||
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
// Compute the determinant of the 3x3 submatrix
|
||||
float det = subDeterminant(r, c);
|
||||
out.elt[r][c] = i * det;
|
||||
i = -i;
|
||||
}
|
||||
i = -i;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
float Matrix4::subDeterminant(int excludeRow, int excludeCol) const {
|
||||
// Compute non-excluded row and column indices
|
||||
int row[3];
|
||||
int col[3];
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
row[i] = i;
|
||||
col[i] = i;
|
||||
|
||||
if (i >= excludeRow) {
|
||||
++row[i];
|
||||
}
|
||||
if (i >= excludeCol) {
|
||||
++col[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the first row of cofactors
|
||||
float cofactor00 =
|
||||
elt[row[1]][col[1]] * elt[row[2]][col[2]] -
|
||||
elt[row[1]][col[2]] * elt[row[2]][col[1]];
|
||||
|
||||
float cofactor10 =
|
||||
elt[row[1]][col[2]] * elt[row[2]][col[0]] -
|
||||
elt[row[1]][col[0]] * elt[row[2]][col[2]];
|
||||
|
||||
float cofactor20 =
|
||||
elt[row[1]][col[0]] * elt[row[2]][col[1]] -
|
||||
elt[row[1]][col[1]] * elt[row[2]][col[0]];
|
||||
|
||||
// Product of the first row and the cofactors along the first row
|
||||
return
|
||||
elt[row[0]][col[0]] * cofactor00 +
|
||||
elt[row[0]][col[1]] * cofactor10 +
|
||||
elt[row[0]][col[2]] * cofactor20;
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame Matrix4::approxCoordinateFrame() const {
|
||||
CoordinateFrame cframe;
|
||||
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
cframe.rotation[r][c] = elt[r][c];
|
||||
}
|
||||
cframe.translation[r] = elt[r][3];
|
||||
}
|
||||
|
||||
// Ensure that the rotation matrix is orthonormal
|
||||
cframe.rotation.orthonormalize();
|
||||
|
||||
return cframe;
|
||||
}
|
||||
|
||||
|
||||
void Matrix4::serialize(class BinaryOutput& b) const {
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
b.writeFloat32(elt[r][c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Matrix4::deserialize(class BinaryInput& b) {
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
elt[r][c] = b.readFloat32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Matrix4::toString() const {
|
||||
return G3D::format("[%g, %g, %g, %g; %g, %g, %g, %g; %g, %g, %g, %g; %g, %g, %g, %g]",
|
||||
elt[0][0], elt[0][1], elt[0][2], elt[0][3],
|
||||
elt[1][0], elt[1][1], elt[1][2], elt[1][3],
|
||||
elt[2][0], elt[2][1], elt[2][2], elt[2][3],
|
||||
elt[3][0], elt[3][1], elt[3][2], elt[3][3]);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
91
modules/acore/deps/g3dlite/source/MemoryManager.cpp
Normal file
91
modules/acore/deps/g3dlite/source/MemoryManager.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
@file MemoryManager.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2009-04-20
|
||||
@edited 2009-05-29
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/MemoryManager.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
MemoryManager::MemoryManager() {}
|
||||
|
||||
|
||||
void* MemoryManager::alloc(size_t s) {
|
||||
return System::malloc(s);
|
||||
}
|
||||
|
||||
|
||||
void MemoryManager::free(void* ptr) {
|
||||
System::free(ptr);
|
||||
}
|
||||
|
||||
|
||||
bool MemoryManager::isThreadsafe() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
MemoryManager::Ref MemoryManager::create() {
|
||||
static MemoryManager::Ref m = new MemoryManager();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
AlignedMemoryManager::AlignedMemoryManager() {}
|
||||
|
||||
|
||||
void* AlignedMemoryManager::alloc(size_t s) {
|
||||
return System::alignedMalloc(s, 16);
|
||||
}
|
||||
|
||||
|
||||
void AlignedMemoryManager::free(void* ptr) {
|
||||
System::alignedFree(ptr);
|
||||
}
|
||||
|
||||
|
||||
bool AlignedMemoryManager::isThreadsafe() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
AlignedMemoryManager::Ref AlignedMemoryManager::create() {
|
||||
static AlignedMemoryManager::Ref m = new AlignedMemoryManager();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
CRTMemoryManager::CRTMemoryManager() {}
|
||||
|
||||
|
||||
void* CRTMemoryManager::alloc(size_t s) {
|
||||
return ::malloc(s);
|
||||
}
|
||||
|
||||
|
||||
void CRTMemoryManager::free(void* ptr) {
|
||||
return ::free(ptr);
|
||||
}
|
||||
|
||||
|
||||
bool CRTMemoryManager::isThreadsafe() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
CRTMemoryManager::Ref CRTMemoryManager::create() {
|
||||
static CRTMemoryManager::Ref m = new CRTMemoryManager();
|
||||
return m;
|
||||
}
|
||||
}
|
||||
637
modules/acore/deps/g3dlite/source/MeshAlg.cpp
Normal file
637
modules/acore/deps/g3dlite/source/MeshAlg.cpp
Normal file
@@ -0,0 +1,637 @@
|
||||
/**
|
||||
@file MeshAlg.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2003-09-14
|
||||
@edited 2008-09-03
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "G3D/MeshAlg.h"
|
||||
#include "G3D/Table.h"
|
||||
#include "G3D/Set.h"
|
||||
#include "G3D/Box.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/vectorMath.h"
|
||||
#include "G3D/AABox.h"
|
||||
#include "G3D/Image1.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
const int MeshAlg::Face::NONE = INT_MIN;
|
||||
|
||||
void MeshAlg::generateGrid(
|
||||
Array<Vector3>& vertex,
|
||||
Array<Vector2>& texCoord,
|
||||
Array<int>& index,
|
||||
int wCells,
|
||||
int hCells,
|
||||
const Vector2& textureScale,
|
||||
bool spaceCentered,
|
||||
bool twoSided,
|
||||
const CoordinateFrame& xform,
|
||||
const Image1::Ref& height) {
|
||||
|
||||
vertex.fastClear();
|
||||
texCoord.fastClear();
|
||||
index.fastClear();
|
||||
|
||||
// Generate vertices
|
||||
for (int z = 0; z <= hCells; ++z) {
|
||||
for (int x = 0; x <= wCells; ++x) {
|
||||
Vector3 v(x / (float)wCells, 0, z / (float)hCells);
|
||||
|
||||
Vector2 t = v.xz() * textureScale;
|
||||
|
||||
texCoord.append(t);
|
||||
|
||||
if (height.notNull()) {
|
||||
v.y = height->nearest(v.x * (height->width() - 1), v.z * (height->height() - 1)).value;
|
||||
}
|
||||
if (spaceCentered) {
|
||||
v -= Vector3(0.5f, 0, 0.5f);
|
||||
}
|
||||
v = xform.pointToWorldSpace(v);
|
||||
vertex.append(v);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate indices
|
||||
for (int z = 0; z < hCells; ++z) {
|
||||
for (int x = 0; x < wCells; ++x) {
|
||||
int A = x + z * (wCells + 1);
|
||||
int B = A + 1;
|
||||
int C = A + (wCells + 1);
|
||||
int D = C + 1;
|
||||
|
||||
// A B
|
||||
// *-----*
|
||||
// | \ |
|
||||
// | \ |
|
||||
// *-----*
|
||||
// C D
|
||||
|
||||
index.append(A, D, B);
|
||||
index.append(A, C, D);
|
||||
}
|
||||
}
|
||||
|
||||
if (twoSided) {
|
||||
// The index array needs to have reversed winding for the bottom
|
||||
// and offset by the original number of vertices
|
||||
Array<int> ti = index;
|
||||
ti.reverse();
|
||||
for (int i = 0; i < ti.size(); ++i) {
|
||||
ti[i] += vertex.size();
|
||||
}
|
||||
index.append(ti);
|
||||
|
||||
// Duplicate the arrays
|
||||
vertex.append(Array<Vector3>(vertex));
|
||||
texCoord.append(Array<Vector2>(texCoord));
|
||||
}
|
||||
}
|
||||
|
||||
MeshAlg::Face::Face() {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
edgeIndex[i] = 0;
|
||||
vertexIndex[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MeshAlg::Edge::Edge() {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
vertexIndex[i] = 0;
|
||||
// Negative face indices are faces that don't exist
|
||||
faceIndex[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MeshAlg::Geometry& MeshAlg::Geometry::operator=(const MeshAlg::Geometry& src) {
|
||||
vertexArray.resize(src.vertexArray.size());
|
||||
normalArray.resize(src.vertexArray.size());
|
||||
|
||||
System::memcpy(vertexArray.getCArray(), src.vertexArray.getCArray(), sizeof(Vector3)*vertexArray.size());
|
||||
System::memcpy(normalArray.getCArray(), src.normalArray.getCArray(), sizeof(Vector3)*normalArray.size());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeNormals(
|
||||
Geometry& geometry,
|
||||
const Array<int>& indexArray) {
|
||||
|
||||
Array<Face> faceArray;
|
||||
Array<Vertex> vertexArray;
|
||||
Array<Edge> edgeArray;
|
||||
Array<Vector3> faceNormalArray;
|
||||
|
||||
computeAdjacency(geometry.vertexArray, indexArray, faceArray, edgeArray, vertexArray);
|
||||
|
||||
computeNormals(geometry.vertexArray, faceArray, vertexArray,
|
||||
geometry.normalArray, faceNormalArray);
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeNormals(
|
||||
const Array<Vector3>& vertexGeometry,
|
||||
const Array<Face>& faceArray,
|
||||
const Array< Array<int> >& adjacentFaceArray,
|
||||
Array<Vector3>& vertexNormalArray,
|
||||
Array<Vector3>& faceNormalArray) {
|
||||
|
||||
// Construct a fake vertex array for backwards compatibility
|
||||
Array<Vertex> fakeVertexArray;
|
||||
fakeVertexArray.resize(adjacentFaceArray.size());
|
||||
|
||||
for (int v = 0; v < adjacentFaceArray.size(); ++v) {
|
||||
fakeVertexArray[v].faceIndex.resize(adjacentFaceArray[v].size());
|
||||
for (int i = 0; i < fakeVertexArray[v].faceIndex.size(); ++i) {
|
||||
fakeVertexArray[v].faceIndex[i] = adjacentFaceArray[v][i];
|
||||
}
|
||||
// We leave out the edges because they aren't used to compute normals
|
||||
}
|
||||
|
||||
computeNormals(vertexGeometry, faceArray, fakeVertexArray,
|
||||
vertexNormalArray, faceNormalArray);
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeNormals(
|
||||
const Array<Vector3>& vertexGeometry,
|
||||
const Array<Face>& faceArray,
|
||||
const Array<Vertex>& vertexArray,
|
||||
Array<Vector3>& vertexNormalArray,
|
||||
Array<Vector3>& faceNormalArray) {
|
||||
|
||||
// Face normals (not unit length)
|
||||
faceNormalArray.resize(faceArray.size());
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
const Face& face = faceArray[f];
|
||||
|
||||
Vector3 vertex[3];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
vertex[j] = vertexGeometry[face.vertexIndex[j]];
|
||||
debugAssert(vertex[j].isFinite());
|
||||
}
|
||||
|
||||
faceNormalArray[f] = (vertex[1] - vertex[0]).cross(vertex[2] - vertex[0]);
|
||||
# ifdef G3D_DEBUG
|
||||
const Vector3& N = faceNormalArray[f];
|
||||
debugAssert(N.isFinite());
|
||||
# endif
|
||||
}
|
||||
|
||||
// Per-vertex normals, computed by averaging
|
||||
vertexNormalArray.resize(vertexGeometry.size());
|
||||
for (int v = 0; v < vertexNormalArray.size(); ++v) {
|
||||
Vector3 sum = Vector3::zero();
|
||||
for (int k = 0; k < vertexArray[v].faceIndex.size(); ++k) {
|
||||
const int f = vertexArray[v].faceIndex[k];
|
||||
sum += faceNormalArray[f];
|
||||
}
|
||||
vertexNormalArray[v] = sum.directionOrZero();
|
||||
# ifdef G3D_DEBUG
|
||||
const Vector3& N = vertexNormalArray[v];
|
||||
debugAssert(N.isUnit() || N.isZero());
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
faceNormalArray[f] = faceNormalArray[f].directionOrZero();
|
||||
# ifdef G3D_DEBUG
|
||||
const Vector3& N = faceNormalArray[f];
|
||||
debugAssert(N.isUnit() || N.isZero());
|
||||
# endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeFaceNormals(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<MeshAlg::Face>& faceArray,
|
||||
Array<Vector3>& faceNormals,
|
||||
bool normalize) {
|
||||
|
||||
faceNormals.resize(faceArray.size());
|
||||
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
const MeshAlg::Face& face = faceArray[f];
|
||||
|
||||
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
|
||||
const Vector3& v1 = vertexArray[face.vertexIndex[1]];
|
||||
const Vector3& v2 = vertexArray[face.vertexIndex[2]];
|
||||
|
||||
faceNormals[f] = (v1 - v0).cross(v2 - v0);
|
||||
}
|
||||
|
||||
if (normalize) {
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
faceNormals[f] = faceNormals[f].direction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::identifyBackfaces(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<MeshAlg::Face>& faceArray,
|
||||
const Vector4& HP,
|
||||
Array<bool>& backface) {
|
||||
|
||||
Vector3 P = HP.xyz();
|
||||
|
||||
backface.resize(faceArray.size());
|
||||
|
||||
if (fuzzyEq(HP.w, 0.0)) {
|
||||
// Infinite case
|
||||
for (int f = faceArray.size() - 1; f >= 0; --f) {
|
||||
const MeshAlg::Face& face = faceArray[f];
|
||||
|
||||
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
|
||||
const Vector3& v1 = vertexArray[face.vertexIndex[1]];
|
||||
const Vector3& v2 = vertexArray[face.vertexIndex[2]];
|
||||
|
||||
const Vector3 N = (v1 - v0).cross(v2 - v0);
|
||||
|
||||
backface[f] = N.dot(P) < 0;
|
||||
}
|
||||
} else {
|
||||
// Finite case
|
||||
for (int f = faceArray.size() - 1; f >= 0; --f) {
|
||||
const MeshAlg::Face& face = faceArray[f];
|
||||
|
||||
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
|
||||
const Vector3& v1 = vertexArray[face.vertexIndex[1]];
|
||||
const Vector3& v2 = vertexArray[face.vertexIndex[2]];
|
||||
|
||||
const Vector3 N = (v1 - v0).cross(v2 - v0);
|
||||
|
||||
backface[f] = N.dot(P - v0) < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::identifyBackfaces(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<MeshAlg::Face>& faceArray,
|
||||
const Vector4& HP,
|
||||
Array<bool>& backface,
|
||||
const Array<Vector3>& faceNormals) {
|
||||
|
||||
Vector3 P = HP.xyz();
|
||||
|
||||
backface.resize(faceArray.size());
|
||||
|
||||
if (fuzzyEq(HP.w, 0.0)) {
|
||||
// Infinite case
|
||||
for (int f = faceArray.size() - 1; f >= 0; --f) {
|
||||
const Vector3& N = faceNormals[f];
|
||||
backface[f] = N.dot(P) < 0;
|
||||
}
|
||||
} else {
|
||||
// Finite case
|
||||
for (int f = faceArray.size() - 1; f >= 0; --f) {
|
||||
const MeshAlg::Face& face = faceArray[f];
|
||||
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
|
||||
const Vector3& N = faceNormals[f];
|
||||
|
||||
backface[f] = N.dot(P - v0) < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::createIndexArray(int n, Array<int>& array, int start, int run, int skip) {
|
||||
debugAssert(skip >= 0);
|
||||
debugAssert(run >= 0);
|
||||
|
||||
array.resize(n);
|
||||
if (skip == 0) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
array[i] = start + i;
|
||||
}
|
||||
} else {
|
||||
int rcount = 0;
|
||||
int j = start;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
array[i] = j;
|
||||
|
||||
++j;
|
||||
++rcount;
|
||||
|
||||
if (rcount == run) {
|
||||
rcount = 0;
|
||||
j += skip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeAreaStatistics(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<int>& indexArray,
|
||||
double& minEdgeLength,
|
||||
double& meanEdgeLength,
|
||||
double& medianEdgeLength,
|
||||
double& maxEdgeLength,
|
||||
double& minFaceArea,
|
||||
double& meanFaceArea,
|
||||
double& medianFaceArea,
|
||||
double& maxFaceArea) {
|
||||
|
||||
debugAssert(indexArray.size() % 3 == 0);
|
||||
|
||||
Array<double> area;
|
||||
area.resize(indexArray.size() / 3);
|
||||
Array<double> magnitude;
|
||||
magnitude.resize(indexArray.size());
|
||||
|
||||
for (int i = 0; i < indexArray.size(); i += 3) {
|
||||
const Vector3& v0 = vertexArray[indexArray[i]];
|
||||
const Vector3& v1 = vertexArray[indexArray[i + 1]];
|
||||
const Vector3& v2 = vertexArray[indexArray[i + 2]];
|
||||
|
||||
area[i / 3] = (v1 - v0).cross(v2 - v0).magnitude() / 2.0;
|
||||
magnitude[i] = (v1 - v0).magnitude();
|
||||
magnitude[i + 1] = (v2 - v1).magnitude();
|
||||
magnitude[i + 2] = (v0 - v2).magnitude();
|
||||
}
|
||||
|
||||
area.sort();
|
||||
magnitude.sort();
|
||||
|
||||
minEdgeLength = max(0.0, magnitude[0]);
|
||||
maxEdgeLength = max(0.0, magnitude.last());
|
||||
medianEdgeLength = max(0.0, magnitude[magnitude.size() / 2]);
|
||||
meanEdgeLength = 0;
|
||||
for (int i = 0; i < magnitude.size(); ++i) {
|
||||
meanEdgeLength += magnitude[i];
|
||||
}
|
||||
meanEdgeLength /= magnitude.size();
|
||||
|
||||
minFaceArea = max(0.0, area[0]);
|
||||
maxFaceArea = max(0.0, area.last());
|
||||
medianFaceArea = max(0.0, area[area.size() / 2]);
|
||||
meanFaceArea = 0;
|
||||
for (int i = 0; i < area.size(); ++i) {
|
||||
meanFaceArea += area[i];
|
||||
}
|
||||
meanFaceArea /= area.size();
|
||||
|
||||
|
||||
// Make sure round-off hasn't pushed values less than zero
|
||||
meanFaceArea = max(0.0, meanFaceArea);
|
||||
meanEdgeLength = max(0.0, meanEdgeLength);
|
||||
}
|
||||
|
||||
|
||||
int MeshAlg::countBoundaryEdges(const Array<MeshAlg::Edge>& edgeArray) {
|
||||
int b = 0;
|
||||
|
||||
for (int i = 0; i < edgeArray.size(); ++i) {
|
||||
if ((edgeArray[i].faceIndex[0] == MeshAlg::Face::NONE) !=
|
||||
(edgeArray[i].faceIndex[1] == MeshAlg::Face::NONE)) {
|
||||
++b;
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void MeshAlg::computeBounds(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<int>& indexArray,
|
||||
AABox& box,
|
||||
Sphere& sphere) {
|
||||
|
||||
Array<Vector3> newArray;
|
||||
newArray.resize(indexArray.size());
|
||||
for (int i = 0; i < indexArray.size(); ++i) {
|
||||
newArray[i] = vertexArray[indexArray[i]];
|
||||
}
|
||||
computeBounds(newArray, box, sphere);
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeBounds(
|
||||
const Array<Vector3>& vertexArray,
|
||||
AABox& box,
|
||||
Sphere& sphere) {
|
||||
|
||||
Vector3 xmin, xmax, ymin, ymax, zmin, zmax;
|
||||
|
||||
// FIRST PASS: find 6 minima/maxima points
|
||||
xmin.x = ymin.y = zmin.z = finf();
|
||||
xmax.x = ymax.y = zmax.z = -finf();
|
||||
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
const Vector3& vertex = vertexArray[v];
|
||||
|
||||
if (vertex.x < xmin.x) {
|
||||
xmin = vertex;
|
||||
}
|
||||
|
||||
if (vertex.x > xmax.x) {
|
||||
xmax = vertex;
|
||||
}
|
||||
|
||||
if (vertex.y < ymin.y) {
|
||||
ymin = vertex;
|
||||
}
|
||||
|
||||
if (vertex.y > ymax.y) {
|
||||
ymax = vertex;
|
||||
}
|
||||
|
||||
if (vertex.z < zmin.z) {
|
||||
zmin = vertex;
|
||||
}
|
||||
|
||||
if (vertex.z > zmax.z) {
|
||||
zmax = vertex;
|
||||
}
|
||||
}
|
||||
|
||||
// Set points dia1 & dia2 to the maximally separated pair
|
||||
Vector3 dia1 = xmin;
|
||||
Vector3 dia2 = xmax;
|
||||
{
|
||||
// Set xspan = distance between the 2 points xmin & xmax (squared)
|
||||
double xspan = (xmax - xmin).squaredMagnitude();
|
||||
|
||||
// Same for y & z spans
|
||||
double yspan = (ymax - ymin).squaredMagnitude();
|
||||
double zspan = (zmax - zmin).squaredMagnitude();
|
||||
|
||||
double maxspan = xspan;
|
||||
|
||||
if (yspan > maxspan) {
|
||||
maxspan = yspan;
|
||||
dia1 = ymin;
|
||||
dia2 = ymax;
|
||||
}
|
||||
|
||||
if (zspan > maxspan) {
|
||||
maxspan = zspan;
|
||||
dia1 = zmin;
|
||||
dia2 = zmax;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// dia1, dia2 is a diameter of initial sphere
|
||||
|
||||
// calc initial center
|
||||
Vector3 center = (dia1 + dia2) / 2.0;
|
||||
|
||||
// calculate initial radius^2 and radius
|
||||
Vector3 d = dia2 - sphere.center;
|
||||
|
||||
double radSq = d.squaredMagnitude();
|
||||
double rad = sqrt(radSq);
|
||||
|
||||
// SECOND PASS: increment current sphere
|
||||
double old_to_p, old_to_new;
|
||||
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
const Vector3& vertex = vertexArray[v];
|
||||
|
||||
d = vertex - center;
|
||||
|
||||
double old_to_p_sq = d.squaredMagnitude();
|
||||
|
||||
// do r^2 test first
|
||||
if (old_to_p_sq > radSq) {
|
||||
// this point is outside of current sphere
|
||||
old_to_p = sqrt(old_to_p_sq);
|
||||
|
||||
// calc radius of new sphere
|
||||
rad = (rad + old_to_p) / 2.0;
|
||||
|
||||
// for next r^2 compare
|
||||
radSq = rad * rad;
|
||||
old_to_new = old_to_p - rad;
|
||||
|
||||
// calc center of new sphere
|
||||
center = (rad * center + old_to_new * vertex) / old_to_p;
|
||||
}
|
||||
}
|
||||
|
||||
const Vector3 min(xmin.x, ymin.y, zmin.z);
|
||||
const Vector3 max(xmax.x, ymax.y, zmax.z);
|
||||
|
||||
box = AABox(min, max);
|
||||
|
||||
const float boxRadSq = (max - min).squaredMagnitude() * 0.25f;
|
||||
|
||||
if (boxRadSq >= radSq){
|
||||
if (isNaN(center.x) || ! isFinite(rad)) {
|
||||
sphere = Sphere(Vector3::zero(), finf());
|
||||
} else {
|
||||
sphere = Sphere(center, rad);
|
||||
}
|
||||
} else {
|
||||
sphere = Sphere((max + min) * 0.5f, sqrt(boxRadSq));
|
||||
}
|
||||
}
|
||||
|
||||
void MeshAlg::computeTangentSpaceBasis(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector2>& texCoordArray,
|
||||
const Array<Vector3>& vertexNormalArray,
|
||||
const Array<Face>& faceArray,
|
||||
Array<Vector3>& tangent,
|
||||
Array<Vector3>& binormal) {
|
||||
|
||||
debugAssertM(faceArray.size() != 0, "Unable to calculate valid tangent space without faces.");
|
||||
|
||||
tangent.resize(vertexArray.size());
|
||||
binormal.resize(vertexArray.size());
|
||||
|
||||
// Zero the output arrays.
|
||||
System::memset(tangent.getCArray(), 0, sizeof(Vector3) * tangent.size());
|
||||
System::memset(binormal.getCArray(), 0, sizeof(Vector3) * binormal.size());
|
||||
|
||||
// Iterate over faces, computing the tangent vectors for each
|
||||
// vertex. Accumulate those into the tangent and binormal arrays
|
||||
// and then orthonormalize at the end.
|
||||
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
const Face& face = faceArray[f];
|
||||
|
||||
const int i0 = face.vertexIndex[0];
|
||||
const int i1 = face.vertexIndex[1];
|
||||
const int i2 = face.vertexIndex[2];
|
||||
|
||||
const Vector3& v0 = vertexArray[i0];
|
||||
const Vector3& v1 = vertexArray[i1];
|
||||
const Vector3& v2 = vertexArray[i2];
|
||||
|
||||
const Vector2& t0 = texCoordArray[i0];
|
||||
const Vector2& t1 = texCoordArray[i1];
|
||||
const Vector2& t2 = texCoordArray[i2];
|
||||
|
||||
// See http://www.terathon.com/code/tangent.html for a derivation of the following code
|
||||
|
||||
// vertex edges
|
||||
Vector3 ve1 = v1 - v0;
|
||||
Vector3 ve2 = v2 - v0;
|
||||
|
||||
// texture edges
|
||||
Vector2 te1 = t1 - t0;
|
||||
Vector2 te2 = t2 - t0;
|
||||
|
||||
Vector3 n(ve1.cross(ve2).direction());
|
||||
Vector3 t, b;
|
||||
|
||||
float r = te1.x * te2.y - te1.y * te2.x;
|
||||
if (r == 0.0) {
|
||||
// degenerate case
|
||||
Vector3::generateOrthonormalBasis(t, b, n, true);
|
||||
} else {
|
||||
r = 1.0f / r;
|
||||
t = (te2.y * ve1 - te1.y * ve2) * r;
|
||||
b = (te2.x * ve1 - te1.x * ve2) * r;
|
||||
}
|
||||
|
||||
for (int v = 0; v < 3; ++v) {
|
||||
int i = face.vertexIndex[v];
|
||||
tangent[i] += t;
|
||||
binormal[i] += b;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize the basis vectors
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
// Remove the component parallel to the normal
|
||||
const Vector3& N = vertexNormalArray[v];
|
||||
Vector3& T = tangent[v];
|
||||
Vector3& B = binormal[v];
|
||||
|
||||
debugAssertM(N.isUnit() || N.isZero(), "Input normals must have unit length");
|
||||
|
||||
T -= T.dot(N) * N;
|
||||
B -= B.dot(N) * N;
|
||||
|
||||
// Normalize
|
||||
T = T.directionOrZero();
|
||||
B = B.directionOrZero();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // G3D namespace
|
||||
745
modules/acore/deps/g3dlite/source/MeshAlgAdjacency.cpp
Normal file
745
modules/acore/deps/g3dlite/source/MeshAlgAdjacency.cpp
Normal file
@@ -0,0 +1,745 @@
|
||||
/**
|
||||
@file MeshAlgAdjacency.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2003-09-14
|
||||
@edited 2010-04-26
|
||||
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "G3D/Table.h"
|
||||
#include "G3D/MeshAlg.h"
|
||||
#include "G3D/Set.h"
|
||||
#include "G3D/Stopwatch.h"
|
||||
#include "G3D/SmallArray.h"
|
||||
#include "G3D/AreaMemoryManager.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
/** Two-level table mapping index 0 -> index 1 -> list of face indices */
|
||||
class MeshEdgeTable {
|
||||
public:
|
||||
|
||||
/** We expect 2 faces per edge. */
|
||||
typedef SmallArray<int, 2> FaceIndexArray;
|
||||
|
||||
class Edge {
|
||||
public:
|
||||
int i1;
|
||||
|
||||
FaceIndexArray faceIndexArray;
|
||||
};
|
||||
|
||||
/** We expect at most 6 edges per vertex; that matches a typical regular grid mesh */
|
||||
typedef SmallArray<Edge, 6> EdgeArray;
|
||||
|
||||
typedef Array< EdgeArray > ET;
|
||||
|
||||
private:
|
||||
|
||||
ET table;
|
||||
|
||||
public:
|
||||
|
||||
MeshEdgeTable() {
|
||||
AreaMemoryManager::Ref mm = AreaMemoryManager::create();
|
||||
table.clearAndSetMemoryManager(mm);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
table.clear();
|
||||
}
|
||||
|
||||
void resize(int maxV) {
|
||||
table.resize(maxV);
|
||||
}
|
||||
|
||||
/**
|
||||
Inserts the faceIndex into the edge's face list.
|
||||
The index may be a negative number indicating a backface.
|
||||
|
||||
\param v0 Vertex index 0
|
||||
\param v1 Vertex index 1
|
||||
*/
|
||||
void insert(int v0, int v1, int faceIndex) {
|
||||
|
||||
debugAssert(v0 <= v1);
|
||||
EdgeArray& edgeArray = table[v0];
|
||||
for (int i = 0; i < edgeArray.size(); ++i) {
|
||||
if (edgeArray[i].i1 == v1) {
|
||||
edgeArray[i].faceIndexArray.push(faceIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Edge& p = edgeArray.next();
|
||||
p.i1 = v1;
|
||||
p.faceIndexArray.push(faceIndex);
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
friend class MeshEdgeTable;
|
||||
private:
|
||||
|
||||
int m_i0;
|
||||
/** Pair index */
|
||||
int m_p;
|
||||
ET& m_array;
|
||||
EdgeArray* m_edgeArray;
|
||||
bool m_end;
|
||||
|
||||
public:
|
||||
|
||||
int i0() const {
|
||||
return m_i0;
|
||||
}
|
||||
|
||||
int i1() const {
|
||||
return (*m_edgeArray)[m_p].i1;
|
||||
}
|
||||
|
||||
FaceIndexArray& faceIndex() {
|
||||
return (*m_edgeArray)[m_p].faceIndexArray;
|
||||
}
|
||||
|
||||
Iterator& operator++() {
|
||||
if ((m_i0 >= 0) && (m_p < m_edgeArray->size() - 1)) {
|
||||
++m_p;
|
||||
} else {
|
||||
// Skip over elements with no face array
|
||||
do {
|
||||
++m_i0;
|
||||
if (m_i0 == m_array.size()) {
|
||||
m_end = true;
|
||||
return *this;
|
||||
} else {
|
||||
m_edgeArray = &m_array[m_i0];
|
||||
m_p = 0;
|
||||
}
|
||||
} while (m_edgeArray->size() == 0);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool hasMore() const {
|
||||
return ! m_end;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Iterator(ET& a) : m_i0(-1), m_p(-1), m_array(a), m_edgeArray(NULL), m_end(false) {
|
||||
++(*this);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Iterator begin() {
|
||||
return Iterator(table);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Assigns the edge index into the next unassigned edge
|
||||
index. The edge index may be negative, indicating
|
||||
a reverse edge.
|
||||
*/
|
||||
static void assignEdgeIndex(MeshAlg::Face& face, int e) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (face.edgeIndex[i] == MeshAlg::Face::NONE) {
|
||||
face.edgeIndex[i] = e;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
debugAssertM(false, "Face has already been assigned 3 edges");
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeAdjacency(
|
||||
const Array<Vector3>& vertexGeometry,
|
||||
const Array<int>& indexArray,
|
||||
Array<Face>& faceArray,
|
||||
Array<Edge>& edgeArray,
|
||||
Array< Array<int> >& adjacentFaceArray) {
|
||||
|
||||
Array<Vertex> vertexArray;
|
||||
|
||||
computeAdjacency(vertexGeometry, indexArray, faceArray, edgeArray, vertexArray);
|
||||
|
||||
// Convert the vertexArray into adjacentFaceArray
|
||||
adjacentFaceArray.clear();
|
||||
adjacentFaceArray.resize(vertexArray.size());
|
||||
for (int v = 0; v < adjacentFaceArray.size(); ++v) {
|
||||
const SmallArray<int, 6>& src = vertexArray[v].faceIndex;
|
||||
Array<int>& dst = adjacentFaceArray[v];
|
||||
dst.resize(src.size());
|
||||
for (int f = 0; f < dst.size(); ++f) {
|
||||
dst[f] = src[f];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeAdjacency(
|
||||
const Array<Vector3>& vertexGeometry,
|
||||
const Array<int>& indexArray,
|
||||
Array<Face>& faceArray,
|
||||
Array<Edge>& edgeArray,
|
||||
Array<Vertex>& vertexArray) {
|
||||
|
||||
MeshEdgeTable edgeTable;
|
||||
|
||||
edgeArray.clear();
|
||||
vertexArray.clear();
|
||||
faceArray.clear();
|
||||
|
||||
// Face normals
|
||||
Array<Vector3> faceNormal;
|
||||
faceNormal.resize(indexArray.size() / 3);
|
||||
faceArray.resize(faceNormal.size());
|
||||
|
||||
// This array has the same size as the vertex array
|
||||
vertexArray.resize(vertexGeometry.size());
|
||||
|
||||
edgeTable.resize(vertexArray.size());
|
||||
|
||||
// Iterate through the triangle list
|
||||
for (int q = 0, f = 0; q < indexArray.size(); ++f, q += 3) {
|
||||
|
||||
Vector3 vertex[3];
|
||||
MeshAlg::Face& face = faceArray[f];
|
||||
|
||||
// Construct the face
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
int v = indexArray[q + j];
|
||||
face.vertexIndex[j] = v;
|
||||
face.edgeIndex[j] = Face::NONE;
|
||||
|
||||
// Store back pointers in the vertices
|
||||
vertexArray[v].faceIndex.append(f);
|
||||
|
||||
// We'll need these vertices to find the face normal
|
||||
vertex[j] = vertexGeometry[v];
|
||||
}
|
||||
|
||||
// Compute the face normal
|
||||
const Vector3& N = (vertex[1] - vertex[0]).cross(vertex[2] - vertex[0]);
|
||||
faceNormal[f] = N.directionOrZero();
|
||||
|
||||
static const int nextIndex[] = {1, 2, 0};
|
||||
|
||||
// Add each edge to the edge table.
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
const int i0 = indexArray[q + j];
|
||||
const int i1 = indexArray[q + nextIndex[j]];
|
||||
|
||||
if (i0 < i1) {
|
||||
// The edge was directed in the same manner as in the face
|
||||
edgeTable.insert(i0, i1, f);
|
||||
} else {
|
||||
// The edge was directed in the opposite manner as in the face
|
||||
edgeTable.insert(i1, i0, ~f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For each edge in the edge table, create an edge in the edge array.
|
||||
// Collapse every 2 edges from adjacent faces.
|
||||
|
||||
MeshEdgeTable::Iterator cur = edgeTable.begin();
|
||||
|
||||
Array<Edge> tempEdgeArray;
|
||||
while (cur.hasMore()) {
|
||||
MeshEdgeTable::FaceIndexArray& faceIndexArray = cur.faceIndex();
|
||||
|
||||
// Process this edge
|
||||
while (faceIndexArray.size() > 0) {
|
||||
|
||||
// Remove the last index
|
||||
int f0 = faceIndexArray.pop();
|
||||
|
||||
// Find the normal to that face
|
||||
const Vector3& n0 = faceNormal[(f0 >= 0) ? f0 : ~f0];
|
||||
|
||||
bool found = false;
|
||||
|
||||
// We try to find the matching face with the closest
|
||||
// normal. This ensures that we don't introduce a lot
|
||||
// of artificial ridges into flat parts of a mesh.
|
||||
float ndotn = -2;
|
||||
int f1 = -1, i1 = -1;
|
||||
|
||||
// Try to find the face with the matching edge
|
||||
for (int i = faceIndexArray.size() - 1; i >= 0; --i) {
|
||||
int f = faceIndexArray[i];
|
||||
|
||||
if ((f >= 0) != (f0 >= 0)) {
|
||||
// This face contains the oppositely oriented edge
|
||||
// and has not been assigned too many edges
|
||||
|
||||
const Vector3& n1 = faceNormal[(f >= 0) ? f : ~f];
|
||||
float d = n1.dot(n0);
|
||||
|
||||
if (found) {
|
||||
// We previously found a good face; see if this
|
||||
// one is better.
|
||||
if (d > ndotn) {
|
||||
// This face is better.
|
||||
ndotn = d;
|
||||
f1 = f;
|
||||
i1 = i;
|
||||
}
|
||||
} else {
|
||||
// This is the first face we've found
|
||||
found = true;
|
||||
ndotn = d;
|
||||
f1 = f;
|
||||
i1 = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the new edge
|
||||
int e = tempEdgeArray.size();
|
||||
Edge& edge = tempEdgeArray.next();
|
||||
|
||||
edge.vertexIndex[0] = cur.i0();
|
||||
edge.vertexIndex[1] = cur.i1();
|
||||
|
||||
if (f0 >= 0) {
|
||||
edge.faceIndex[0] = f0;
|
||||
edge.faceIndex[1] = Face::NONE;
|
||||
assignEdgeIndex(faceArray[f0], e);
|
||||
} else {
|
||||
// The face indices above are two's complemented.
|
||||
// this code restores them to regular indices.
|
||||
debugAssert((~f0) >= 0);
|
||||
edge.faceIndex[1] = ~f0;
|
||||
edge.faceIndex[0] = Face::NONE;
|
||||
|
||||
// The edge index *does* need to be inverted, however.
|
||||
assignEdgeIndex(faceArray[~f0], ~e);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
// We found a matching face; remove both
|
||||
// faces from the active list.
|
||||
faceIndexArray.fastRemove(i1);
|
||||
|
||||
if (f1 >= 0) {
|
||||
edge.faceIndex[0] = f1;
|
||||
assignEdgeIndex(faceArray[f1], e);
|
||||
} else {
|
||||
edge.faceIndex[1] = ~f1;
|
||||
assignEdgeIndex(faceArray[~f1], ~e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++cur;
|
||||
}
|
||||
|
||||
edgeTable.clear();
|
||||
|
||||
// Move boundary edges to the end of the list and then
|
||||
// clean up the face references into them
|
||||
{
|
||||
// Map old edge indices to new edge indices
|
||||
Array<int> newIndex;
|
||||
newIndex.resize(tempEdgeArray.size());
|
||||
|
||||
// Index of the start and end of the edge array
|
||||
int i = 0;
|
||||
int j = tempEdgeArray.size() - 1;
|
||||
|
||||
edgeArray.resize(tempEdgeArray.size());
|
||||
for (int e = 0; e < tempEdgeArray.size(); ++e) {
|
||||
if (tempEdgeArray[e].boundary()) {
|
||||
newIndex[e] = j;
|
||||
--j;
|
||||
} else {
|
||||
newIndex[e] = i;
|
||||
++i;
|
||||
}
|
||||
edgeArray[newIndex[e]] = tempEdgeArray[e];
|
||||
}
|
||||
|
||||
debugAssertM(i == j + 1, "Counting from front and back of array did not match");
|
||||
|
||||
// Fix the faces
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
Face& face = faceArray[f];
|
||||
for (int q = 0; q < 3; ++q) {
|
||||
int e = face.edgeIndex[q];
|
||||
if (e < 0) {
|
||||
// Backwards edge; twiddle before and after conversion
|
||||
face.edgeIndex[q] = ~newIndex[~e];
|
||||
} else {
|
||||
// Regular edge; remap the index
|
||||
face.edgeIndex[q] = newIndex[e];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now order the edge indices inside the faces correctly.
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
Face& face = faceArray[f];
|
||||
int e0 = face.edgeIndex[0];
|
||||
int e1 = face.edgeIndex[1];
|
||||
int e2 = face.edgeIndex[2];
|
||||
|
||||
// e0 will always remain first. The only
|
||||
// question is whether e1 and e2 should be swapped.
|
||||
|
||||
// See if e1 begins at the vertex where e1 ends.
|
||||
const int e0End = (e0 < 0) ?
|
||||
edgeArray[~e0].vertexIndex[0] :
|
||||
edgeArray[e0].vertexIndex[1];
|
||||
|
||||
const int e1Begin = (e1 < 0) ?
|
||||
edgeArray[~e1].vertexIndex[1] :
|
||||
edgeArray[e1].vertexIndex[0];
|
||||
|
||||
if (e0End != e1Begin) {
|
||||
// We must swap e1 and e2
|
||||
face.edgeIndex[1] = e2;
|
||||
face.edgeIndex[2] = e1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill out the edge adjacency information in the vertex array
|
||||
for (int e = 0; e < edgeArray.size(); ++e) {
|
||||
const Edge& edge = edgeArray[e];
|
||||
vertexArray[edge.vertexIndex[0]].edgeIndex.append(e);
|
||||
vertexArray[edge.vertexIndex[1]].edgeIndex.append(~e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::weldBoundaryEdges(
|
||||
Array<Face>& faceArray,
|
||||
Array<Edge>& edgeArray,
|
||||
Array<Vertex>& vertexArray) {
|
||||
|
||||
// Copy over the original edge array
|
||||
Array<Edge> oldEdgeArray = edgeArray;
|
||||
|
||||
// newEdgeIndex[e] is the new index of the old edge with index e
|
||||
// Note that newEdgeIndex[e] might be negative, indicating that
|
||||
// the edge switched direction between the arrays.
|
||||
Array<int> newEdgeIndex;
|
||||
newEdgeIndex.resize(edgeArray.size());
|
||||
edgeArray.resize(0);
|
||||
|
||||
// boundaryEdgeIndices[v_low] is an array of the indices of
|
||||
// all boundary edges whose lower vertex is v_low.
|
||||
Table<int, Array<int> > boundaryEdgeIndices;
|
||||
|
||||
// Copy over non-boundary edges to the new array
|
||||
for (int e = 0; e < oldEdgeArray.size(); ++e) {
|
||||
if (oldEdgeArray[e].boundary()) {
|
||||
|
||||
// Add to the boundary table
|
||||
const int v_low = iMin(oldEdgeArray[e].vertexIndex[0], oldEdgeArray[e].vertexIndex[1]);
|
||||
if (! boundaryEdgeIndices.containsKey(v_low)) {
|
||||
boundaryEdgeIndices.set(v_low, Array<int>());
|
||||
}
|
||||
boundaryEdgeIndices[v_low].append(e);
|
||||
|
||||
// We'll fill out newEdgeIndex[e] later, when we find pairs
|
||||
|
||||
} else {
|
||||
|
||||
// Copy the edge to the new array
|
||||
newEdgeIndex[e] = edgeArray.size();
|
||||
edgeArray.append(oldEdgeArray[e]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove all edges from the table that have pairs.
|
||||
Table<int, Array<int> >::Iterator cur = boundaryEdgeIndices.begin();
|
||||
Table<int, Array<int> >::Iterator end = boundaryEdgeIndices.end();
|
||||
while (cur != end) {
|
||||
Array<int>& boundaryEdge = cur->value;
|
||||
|
||||
for (int i = 0; i < boundaryEdge.size(); ++i) {
|
||||
int ei = boundaryEdge[i];
|
||||
const Edge& edgei = oldEdgeArray[ei];
|
||||
|
||||
for (int j = i + 1; j < boundaryEdge.size(); ++j) {
|
||||
int ej = boundaryEdge[j];
|
||||
const Edge& edgej = oldEdgeArray[ej];
|
||||
|
||||
// See if edge ei is the reverse (match) of edge ej.
|
||||
|
||||
// True if the edges match
|
||||
bool match = false;
|
||||
|
||||
// True if edgej's vertex indices are reversed from
|
||||
// edgei's (usually true).
|
||||
bool reversej = false;
|
||||
|
||||
int u = edgei.vertexIndex[0];
|
||||
int v = edgei.vertexIndex[1];
|
||||
|
||||
if (edgei.faceIndex[0] != Face::NONE) {
|
||||
// verts|faces
|
||||
// edgei = [u v A /]
|
||||
|
||||
if (edgej.faceIndex[0] != Face::NONE) {
|
||||
if ((edgej.vertexIndex[0] == v) && (edgej.vertexIndex[1] == u)) {
|
||||
// This is the most common of the four cases
|
||||
|
||||
// edgej = [v u B /]
|
||||
match = true;
|
||||
reversej = true;
|
||||
}
|
||||
} else {
|
||||
if ((edgej.vertexIndex[0] == u) && (edgej.vertexIndex[1] == v)) {
|
||||
// edgej = [u v / B]
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// edgei = [u v / A]
|
||||
if (edgej.faceIndex[0] != Face::NONE) {
|
||||
if ((edgej.vertexIndex[0] == u) && (edgej.vertexIndex[1] == v)) {
|
||||
// edgej = [u v B /]
|
||||
match = true;
|
||||
}
|
||||
} else {
|
||||
if ((edgej.vertexIndex[0] == v) && (edgej.vertexIndex[1] == u)) {
|
||||
// edgej = [v u / B]
|
||||
match = true;
|
||||
reversej = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
// ei and ej can be paired as a single edge
|
||||
int e = edgeArray.size();
|
||||
Edge& edge = edgeArray.next();
|
||||
|
||||
// Follow the direction of edgei.
|
||||
edge = edgei;
|
||||
newEdgeIndex[ei] = e;
|
||||
|
||||
// Insert the face index for edgej.
|
||||
int fj = edgej.faceIndex[0];
|
||||
if (fj == Face::NONE) {
|
||||
fj = edgej.faceIndex[1];
|
||||
}
|
||||
|
||||
if (edge.faceIndex[0] == Face::NONE) {
|
||||
edge.faceIndex[0] = fj;
|
||||
} else {
|
||||
edge.faceIndex[1] = fj;
|
||||
}
|
||||
|
||||
if (reversej) {
|
||||
// The new edge is backwards of the old edge for ej
|
||||
newEdgeIndex[ej] = ~e;
|
||||
} else {
|
||||
newEdgeIndex[ej] = e;
|
||||
}
|
||||
|
||||
// Remove both ei and ej from being candidates for future pairing.
|
||||
// Remove ej first since it comes later in the list (removing
|
||||
// ei would decrease the index of ej to j - 1).
|
||||
boundaryEdge.fastRemove(j);
|
||||
boundaryEdge.fastRemove(i);
|
||||
|
||||
// Re-process element i, which is now a new edge index
|
||||
--i;
|
||||
|
||||
// Jump out of the j for-loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
++cur;
|
||||
}
|
||||
|
||||
// Anything remaining in the table is a real boundary edge; just copy it to
|
||||
// the end of the array.
|
||||
cur = boundaryEdgeIndices.begin();
|
||||
end = boundaryEdgeIndices.end();
|
||||
while (cur != end) {
|
||||
Array<int>& boundaryEdge = cur->value;
|
||||
|
||||
for (int b = 0; b < boundaryEdge.size(); ++b) {
|
||||
const int e = boundaryEdge[b];
|
||||
|
||||
newEdgeIndex[e] = edgeArray.size();
|
||||
edgeArray.append(oldEdgeArray[e]);
|
||||
}
|
||||
|
||||
++cur;
|
||||
}
|
||||
|
||||
// Finally, fix up edge indices in the face and vertex arrays
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
Face& face = faceArray[f];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
int e = face.edgeIndex[i];
|
||||
|
||||
if (e < 0) {
|
||||
face.edgeIndex[i] = ~newEdgeIndex[~e];
|
||||
} else {
|
||||
face.edgeIndex[i] = newEdgeIndex[e];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
Vertex& vertex = vertexArray[v];
|
||||
for (int i = 0; i < vertex.edgeIndex.size(); ++i) {
|
||||
int e = vertex.edgeIndex[i];
|
||||
|
||||
if (e < 0) {
|
||||
vertex.edgeIndex[i] = ~newEdgeIndex[~e];
|
||||
} else {
|
||||
vertex.edgeIndex[i] = newEdgeIndex[e];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::weldAdjacency(
|
||||
const Array<Vector3>& originalGeometry,
|
||||
Array<Face>& faceArray,
|
||||
Array<Edge>& edgeArray,
|
||||
Array<Vertex>& vertexArray,
|
||||
double radius) {
|
||||
|
||||
// Num vertices
|
||||
const int n = originalGeometry.size();
|
||||
|
||||
// canonical[v] = first occurance of any vertex near oldVertexArray[v]
|
||||
Array<int> canonical;
|
||||
canonical.resize(n);
|
||||
|
||||
Array<int> toNew, toOld;
|
||||
// Throw away the new vertex array
|
||||
Array<Vector3> dummy;
|
||||
computeWeld(originalGeometry, dummy, toNew, toOld, radius);
|
||||
|
||||
for (int v = 0; v < canonical.size(); ++v) {
|
||||
// Round-trip through the toNew/toOld process. This will give
|
||||
// us the original vertex.
|
||||
canonical[v] = toOld[toNew[v]];
|
||||
}
|
||||
|
||||
// Destroy vertexArray (we reconstruct it below)
|
||||
vertexArray.clear();
|
||||
vertexArray.resize(n);
|
||||
|
||||
bool hasBoundaryEdges = false;
|
||||
|
||||
// Fix edge vertex indices
|
||||
for (int e = 0; e < edgeArray.size(); ++e) {
|
||||
Edge& edge = edgeArray[e];
|
||||
|
||||
const int v0 = canonical[edge.vertexIndex[0]];
|
||||
const int v1 = canonical[edge.vertexIndex[1]];
|
||||
|
||||
edge.vertexIndex[0] = v0;
|
||||
edge.vertexIndex[1] = v1;
|
||||
|
||||
vertexArray[v0].edgeIndex.append(e);
|
||||
vertexArray[v1].edgeIndex.append(~e);
|
||||
|
||||
hasBoundaryEdges = hasBoundaryEdges || edge.boundary();
|
||||
}
|
||||
|
||||
// Fix face vertex indices
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
Face& face = faceArray[f];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const int v = canonical[face.vertexIndex[i]];
|
||||
|
||||
face.vertexIndex[i] = v;
|
||||
|
||||
// Add the back pointer
|
||||
vertexArray[v].faceIndex.append(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasBoundaryEdges) {
|
||||
// As a result of the welding, some of the boundary edges at
|
||||
// the end of the array may now have mates and no longer be
|
||||
// boundaries. Try to pair these up.
|
||||
|
||||
weldBoundaryEdges(faceArray, edgeArray, vertexArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::debugCheckConsistency(
|
||||
const Array<Face>& faceArray,
|
||||
const Array<Edge>& edgeArray,
|
||||
const Array<Vertex>& vertexArray) {
|
||||
|
||||
#ifdef _DEBUG
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
const MeshAlg::Vertex& vertex = vertexArray[v];
|
||||
|
||||
for (int i = 0; i < vertex.edgeIndex.size(); ++i) {
|
||||
const int e = vertex.edgeIndex[i];
|
||||
debugAssert(edgeArray[(e >= 0) ? e : ~e].containsVertex(v));
|
||||
}
|
||||
|
||||
for (int i = 0; i < vertex.faceIndex.size(); ++i) {
|
||||
const int f = vertex.faceIndex[i];
|
||||
debugAssert(faceArray[f].containsVertex(v));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (int e = 0; e < edgeArray.size(); ++e) {
|
||||
const MeshAlg::Edge& edge = edgeArray[e];
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
debugAssert((edge.faceIndex[i] == MeshAlg::Face::NONE) ||
|
||||
faceArray[edge.faceIndex[i]].containsEdge(e));
|
||||
|
||||
debugAssert(vertexArray[edge.vertexIndex[i]].inEdge(e));
|
||||
}
|
||||
}
|
||||
|
||||
// Every face's edge must be on that face
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
const MeshAlg::Face& face = faceArray[f];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
int e = face.edgeIndex[i];
|
||||
int ei = (e >= 0) ? e : ~e;
|
||||
debugAssert(edgeArray[ei].inFace(f));
|
||||
|
||||
// Make sure the edge is oriented appropriately
|
||||
if (e >= 0) {
|
||||
debugAssert(edgeArray[ei].faceIndex[0] == (int)f);
|
||||
} else {
|
||||
debugAssert(edgeArray[ei].faceIndex[1] == (int)f);
|
||||
}
|
||||
|
||||
debugAssert(vertexArray[face.vertexIndex[i]].inFace(f));
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)faceArray;
|
||||
(void)edgeArray;
|
||||
(void)vertexArray;
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
} // G3D namespace
|
||||
213
modules/acore/deps/g3dlite/source/MeshAlgWeld.cpp
Normal file
213
modules/acore/deps/g3dlite/source/MeshAlgWeld.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
@file MeshAlgWeld.cpp
|
||||
|
||||
The MeshAlg::computeWeld method.
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2003-10-22
|
||||
@edited 2005-02-24
|
||||
|
||||
Copyright 2000-2003, Morgan McGuire.
|
||||
All rights reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "G3D/MeshAlg.h"
|
||||
#include "G3D/Table.h"
|
||||
#include "G3D/Set.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
namespace _internal {
|
||||
|
||||
class Welder {
|
||||
private:
|
||||
|
||||
// Intentionally illegal
|
||||
Welder& operator=(const Welder& w);
|
||||
|
||||
public:
|
||||
/** Indices of newVertexArray elements in <B>or near</B> a grid cell. */
|
||||
typedef Array<int> List;
|
||||
|
||||
enum {GRID_RES = 32};
|
||||
|
||||
List grid[GRID_RES][GRID_RES][GRID_RES];
|
||||
|
||||
const Array<Vector3>& oldVertexArray;
|
||||
Array<Vector3>& newVertexArray;
|
||||
Array<int>& toNew;
|
||||
Array<int>& toOld;
|
||||
|
||||
/** Must be less than one grid cell, not checked */
|
||||
const double radius;
|
||||
|
||||
/** (oldVertexArray[i] - offset) * scale is on the range [0, 1] */
|
||||
Vector3 offset;
|
||||
Vector3 scale;
|
||||
|
||||
Welder(
|
||||
const Array<Vector3>& _oldVertexArray,
|
||||
Array<Vector3>& _newVertexArray,
|
||||
Array<int>& _toNew,
|
||||
Array<int>& _toOld,
|
||||
double _radius);
|
||||
|
||||
/**
|
||||
Computes the grid index from an ordinate.
|
||||
*/
|
||||
void toGridCoords(Vector3 v, int& x, int& y, int& z) const;
|
||||
|
||||
/** Gets the index of a vertex, adding it to
|
||||
newVertexArray if necessary. */
|
||||
int getIndex(const Vector3& vertex);
|
||||
|
||||
void weld();
|
||||
};
|
||||
|
||||
} // namespace _internal
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
template<> struct HashTrait<G3D::_internal::Welder::List*> {
|
||||
static size_t hashCode(const G3D::_internal::Welder::List* key) { return reinterpret_cast<size_t>(key); }
|
||||
};
|
||||
|
||||
namespace G3D {
|
||||
namespace _internal {
|
||||
|
||||
Welder::Welder(
|
||||
const Array<Vector3>& _oldVertexArray,
|
||||
Array<Vector3>& _newVertexArray,
|
||||
Array<int>& _toNew,
|
||||
Array<int>& _toOld,
|
||||
double _radius) :
|
||||
oldVertexArray(_oldVertexArray),
|
||||
newVertexArray(_newVertexArray),
|
||||
toNew(_toNew),
|
||||
toOld(_toOld),
|
||||
radius(_radius) {
|
||||
|
||||
// Compute a scale factor that moves the range
|
||||
// of all ordinates to [0, 1]
|
||||
Vector3 minBound = Vector3::inf();
|
||||
Vector3 maxBound = -minBound;
|
||||
|
||||
for (int i = 0; i < oldVertexArray.size(); ++i) {
|
||||
minBound = minBound.min(oldVertexArray[i]);
|
||||
maxBound = maxBound.max(oldVertexArray[i]);
|
||||
}
|
||||
|
||||
offset = minBound;
|
||||
scale = maxBound - minBound;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
// The model might have zero extent along some axis
|
||||
if (fuzzyEq(scale[i], 0.0)) {
|
||||
scale[i] = 1.0;
|
||||
} else {
|
||||
scale[i] = 1.0 / scale[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Welder::toGridCoords(Vector3 v, int& x, int& y, int& z) const {
|
||||
v = (v - offset) * scale;
|
||||
x = iClamp(iFloor(v.x * GRID_RES), 0, GRID_RES - 1);
|
||||
y = iClamp(iFloor(v.y * GRID_RES), 0, GRID_RES - 1);
|
||||
z = iClamp(iFloor(v.z * GRID_RES), 0, GRID_RES - 1);
|
||||
}
|
||||
|
||||
|
||||
int Welder::getIndex(const Vector3& vertex) {
|
||||
|
||||
int closestIndex = -1;
|
||||
double distanceSquared = inf();
|
||||
|
||||
int ix, iy, iz;
|
||||
toGridCoords(vertex, ix, iy, iz);
|
||||
|
||||
// Check against all vertices within radius of this grid cube
|
||||
const List& list = grid[ix][iy][iz];
|
||||
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
double d = (newVertexArray[list[i]] - vertex).squaredMagnitude();
|
||||
|
||||
if (d < distanceSquared) {
|
||||
distanceSquared = d;
|
||||
closestIndex = list[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (distanceSquared <= radius * radius) {
|
||||
|
||||
return closestIndex;
|
||||
|
||||
} else {
|
||||
|
||||
// This is a new vertex
|
||||
int newIndex = newVertexArray.size();
|
||||
newVertexArray.append(vertex);
|
||||
|
||||
// Create a new vertex and store its index in the
|
||||
// neighboring grid cells (usually, only 1 neighbor)
|
||||
|
||||
Set<List*> neighbors;
|
||||
|
||||
for (float dx = -1; dx <= +1; ++dx) {
|
||||
for (float dy = -1; dy <= +1; ++dy) {
|
||||
for (float dz = -1; dz <= +1; ++dz) {
|
||||
int ix, iy, iz;
|
||||
toGridCoords(vertex + Vector3(dx, dy, dz) * radius, ix, iy, iz);
|
||||
neighbors.insert(&(grid[ix][iy][iz]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<List*>::Iterator neighbor(neighbors.begin());
|
||||
Set<List*>::Iterator none(neighbors.end());
|
||||
|
||||
while (neighbor != none) {
|
||||
(*neighbor)->append(newIndex);
|
||||
++neighbor;
|
||||
}
|
||||
|
||||
return newIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Welder::weld() {
|
||||
newVertexArray.resize(0);
|
||||
|
||||
// Prime the vertex positions
|
||||
for (int i = 0; i < oldVertexArray.size(); ++i) {
|
||||
getIndex(oldVertexArray[i]);
|
||||
}
|
||||
|
||||
// Now create the official remapping by snapping to
|
||||
// nearby vertices.
|
||||
toNew.resize(oldVertexArray.size());
|
||||
toOld.resize(newVertexArray.size());
|
||||
|
||||
for (int oi = 0; oi < oldVertexArray.size(); ++oi) {
|
||||
toNew[oi] = getIndex(oldVertexArray[oi]);
|
||||
toOld[toNew[oi]] = oi;
|
||||
}
|
||||
}
|
||||
|
||||
} // internal namespace
|
||||
|
||||
|
||||
void MeshAlg::computeWeld(
|
||||
const Array<Vector3>& oldVertexArray,
|
||||
Array<Vector3>& newVertexArray,
|
||||
Array<int>& toNew,
|
||||
Array<int>& toOld,
|
||||
double radius) {
|
||||
|
||||
_internal::Welder welder(oldVertexArray, newVertexArray, toNew, toOld, radius);
|
||||
welder.weld();
|
||||
}
|
||||
|
||||
} // G3D namespace
|
||||
113
modules/acore/deps/g3dlite/source/MeshBuilder.cpp
Normal file
113
modules/acore/deps/g3dlite/source/MeshBuilder.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
@file MeshBuilder.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2002-02-27
|
||||
@edited 2005-02-24
|
||||
*/
|
||||
|
||||
#include "G3D/MeshBuilder.h"
|
||||
#include "G3D/MeshAlg.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void MeshBuilder::setName(const std::string& n) {
|
||||
name = n;
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::commit(std::string& n, Array<int>& indexArray, Array<Vector3>& outvertexArray) {
|
||||
n = name;
|
||||
|
||||
// Make the data fit in a unit cube
|
||||
centerTriList();
|
||||
|
||||
Array<int> toNew, toOld;
|
||||
|
||||
if (close == MeshBuilder::AUTO_WELD) {
|
||||
Array<int> index;
|
||||
MeshAlg::createIndexArray(triList.size(), index);
|
||||
double minEdgeLen, maxEdgeLen, meanEdgeLen, medianEdgeLen;
|
||||
double minFaceArea, maxFaceArea, meanFaceArea, medianFaceArea;
|
||||
MeshAlg::computeAreaStatistics(triList, index,
|
||||
minEdgeLen, meanEdgeLen, medianEdgeLen, maxEdgeLen,
|
||||
minFaceArea, meanFaceArea, medianFaceArea, maxFaceArea);
|
||||
close = minEdgeLen * 0.1;
|
||||
}
|
||||
|
||||
MeshAlg::computeWeld(triList, outvertexArray, toNew, toOld, close);
|
||||
|
||||
// Construct triangles
|
||||
for (int t = 0; t < triList.size(); t += 3) {
|
||||
int index[3];
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
index[i] = toNew[t + i];
|
||||
}
|
||||
|
||||
// Throw out zero size triangles
|
||||
if ((index[0] != index[1]) &&
|
||||
(index[1] != index[2]) &&
|
||||
(index[2] != index[0])) {
|
||||
indexArray.append(index[0], index[1], index[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::centerTriList() {
|
||||
// Compute the range of the vertices
|
||||
Vector3 vmin, vmax;
|
||||
|
||||
computeBounds(vmin, vmax);
|
||||
|
||||
Vector3 diagonal = vmax - vmin;
|
||||
double scale = max(max(diagonal.x, diagonal.y), diagonal.z) / 2;
|
||||
debugAssert(scale > 0);
|
||||
|
||||
Vector3 translation = vmin + diagonal / 2;
|
||||
|
||||
// Center and scale all vertices in the input list
|
||||
int v;
|
||||
|
||||
//Matrix3 rot90 = Matrix3::fromAxisAngle(Vector3::UNIT_Y, toRadians(180)) * Matrix3::fromAxisAngle(Vector3::UNIT_X, toRadians(90));
|
||||
for (v = 0; v < triList.size(); ++v) {
|
||||
triList[v] = (triList[v] - translation) / scale;
|
||||
//triList[v] = rot90 * triList[v];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::computeBounds(Vector3& min, Vector3& max) {
|
||||
min = Vector3::inf();
|
||||
max = -min;
|
||||
|
||||
int v;
|
||||
for (v = 0; v < triList.size(); ++v) {
|
||||
min = min.min(triList[v]);
|
||||
max = max.max(triList[v]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::addTriangle(const Vector3& a, const Vector3& b, const Vector3& c) {
|
||||
triList.append(a, b, c);
|
||||
|
||||
if (_twoSided) {
|
||||
triList.append(c, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::addQuad(const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d) {
|
||||
addTriangle(a, b, c);
|
||||
addTriangle(a, c, d);
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::addTriangle(const Triangle& t) {
|
||||
addTriangle(t.vertex(0), t.vertex(1), t.vertex(2));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
164
modules/acore/deps/g3dlite/source/NetAddress.cpp
Normal file
164
modules/acore/deps/g3dlite/source/NetAddress.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
@file NetMessage.cpp
|
||||
|
||||
@maintainer Morgan McGuire, morgan@cs.brown.edu
|
||||
@created 2005-02-06
|
||||
@edited 2005-02-06
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/NetAddress.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Array.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/System.h"
|
||||
#include "G3D/NetworkDevice.h"
|
||||
|
||||
#if defined(G3D_LINUX) || defined(G3D_OSX)
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#define _alloca alloca
|
||||
|
||||
# ifndef SOCKADDR_IN
|
||||
# define SOCKADDR_IN struct sockaddr_in
|
||||
# endif
|
||||
# ifndef SOCKET
|
||||
# define SOCKET int
|
||||
# endif
|
||||
|
||||
// SOCKADDR_IN is supposed to be defined in NetAddress.h
|
||||
#ifndef SOCKADDR_IN
|
||||
# error Network headers included in wrong order
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
namespace G3D {
|
||||
|
||||
NetAddress::NetAddress() {
|
||||
System::memset(&addr, 0, sizeof(addr));
|
||||
}
|
||||
|
||||
void NetAddress::init(uint32 host, uint16 port) {
|
||||
if ((host != 0) || (port != 0)) {
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
if (host == 0) {
|
||||
host = INADDR_ANY;
|
||||
}
|
||||
addr.sin_addr.s_addr = htonl(host);
|
||||
} else {
|
||||
System::memset(&addr, 0, sizeof(addr));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NetAddress::NetAddress(
|
||||
const std::string& hostname,
|
||||
uint16 port) {
|
||||
init(hostname, port);
|
||||
}
|
||||
|
||||
|
||||
void NetAddress::init(
|
||||
const std::string& hostname,
|
||||
uint16 port) {
|
||||
|
||||
uint32 addr;
|
||||
|
||||
if (hostname == "") {
|
||||
addr = INADDR_NONE;
|
||||
} else {
|
||||
addr = inet_addr(hostname.c_str());
|
||||
}
|
||||
|
||||
// The address wasn't in numeric form, resolve it
|
||||
if (addr == INADDR_NONE) {
|
||||
// Get the IP address of the server and store it in host
|
||||
struct hostent* host = gethostbyname(hostname.c_str());
|
||||
|
||||
if (host == NULL) {
|
||||
init(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
System::memcpy(&addr, host->h_addr_list[0], host->h_length);
|
||||
}
|
||||
|
||||
if (addr != INADDR_NONE) {
|
||||
addr = ntohl(addr);
|
||||
}
|
||||
init(addr, port);
|
||||
}
|
||||
|
||||
|
||||
NetAddress::NetAddress(uint32 hostip, uint16 port) {
|
||||
init(hostip, port);
|
||||
}
|
||||
|
||||
|
||||
NetAddress NetAddress::broadcastAddress(uint16 port) {
|
||||
return NetAddress(NetworkDevice::instance()->broadcastAddressArray()[0], port);
|
||||
}
|
||||
|
||||
|
||||
NetAddress::NetAddress(const std::string& hostnameAndPort) {
|
||||
|
||||
Array<std::string> part = stringSplit(hostnameAndPort, ':');
|
||||
|
||||
debugAssert(part.length() == 2);
|
||||
init(part[0], atoi(part[1].c_str()));
|
||||
}
|
||||
|
||||
|
||||
NetAddress::NetAddress(const SOCKADDR_IN& a) {
|
||||
addr = a;
|
||||
}
|
||||
|
||||
|
||||
NetAddress::NetAddress(const struct in_addr& addr, uint16 port) {
|
||||
#ifdef G3D_WIN32
|
||||
init(ntohl(addr.S_un.S_addr), port);
|
||||
#else
|
||||
init(htonl(addr.s_addr), port);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NetAddress::serialize(class BinaryOutput& b) const {
|
||||
b.writeUInt32(ip());
|
||||
b.writeUInt16(port());
|
||||
}
|
||||
|
||||
|
||||
void NetAddress::deserialize(class BinaryInput& b) {
|
||||
uint32 i;
|
||||
uint16 p;
|
||||
|
||||
i = b.readUInt32();
|
||||
p = b.readUInt16();
|
||||
|
||||
init(i, p);
|
||||
}
|
||||
|
||||
|
||||
bool NetAddress::ok() const {
|
||||
return addr.sin_family != 0;
|
||||
}
|
||||
|
||||
|
||||
std::string NetAddress::ipString() const {
|
||||
return format("%s", inet_ntoa(*(in_addr*)&(addr.sin_addr)));
|
||||
}
|
||||
|
||||
|
||||
std::string NetAddress::toString() const {
|
||||
return ipString() + format(":%d", ntohs(addr.sin_port));
|
||||
}
|
||||
|
||||
}
|
||||
1274
modules/acore/deps/g3dlite/source/NetworkDevice.cpp
Normal file
1274
modules/acore/deps/g3dlite/source/NetworkDevice.cpp
Normal file
File diff suppressed because it is too large
Load Diff
110
modules/acore/deps/g3dlite/source/PhysicsFrame.cpp
Normal file
110
modules/acore/deps/g3dlite/source/PhysicsFrame.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
@file PhysicsFrame.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2002-07-09
|
||||
@edited 2010-03-25
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/PhysicsFrame.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
PhysicsFrame::PhysicsFrame() {
|
||||
translation = Vector3::zero();
|
||||
rotation = Quat();
|
||||
}
|
||||
|
||||
|
||||
PhysicsFrame::PhysicsFrame(
|
||||
const CoordinateFrame& coordinateFrame) {
|
||||
|
||||
translation = coordinateFrame.translation;
|
||||
rotation = Quat(coordinateFrame.rotation);
|
||||
}
|
||||
|
||||
|
||||
PhysicsFrame::PhysicsFrame(const Any& a) {
|
||||
const std::string& n = toLower(a.name());
|
||||
*this = PhysicsFrame();
|
||||
|
||||
if (beginsWith(n, "vector3")) {
|
||||
*this = PhysicsFrame(Vector3(a));
|
||||
} else if (beginsWith(n, "matrix3")) {
|
||||
*this = PhysicsFrame(Matrix3(a));
|
||||
} else if (beginsWith(n, "cframe") || beginsWith(n, "coordinateframe")) {
|
||||
*this = PhysicsFrame(CoordinateFrame(a));
|
||||
} else if (beginsWith(n, "pframe") || beginsWith(n, "physicsframe")) {
|
||||
if (a.type() == Any::ARRAY) {
|
||||
a.verifySize(2);
|
||||
rotation = a[0];
|
||||
translation = a[1];
|
||||
} else {
|
||||
for (Any::AnyTable::Iterator it = a.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& n = toLower(it->key);
|
||||
if (n == "translation") {
|
||||
translation = it->value;
|
||||
} else if (n == "rotation") {
|
||||
rotation = it->value;
|
||||
} else {
|
||||
a.verify(false, "Illegal table key: " + it->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PhysicsFrame PhysicsFrame::operator*(const PhysicsFrame& other) const {
|
||||
PhysicsFrame result;
|
||||
|
||||
result.rotation = rotation * other.rotation;
|
||||
result.translation = translation + rotation.toRotationMatrix() * other.translation;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
PhysicsFrame::operator CoordinateFrame() const {
|
||||
CoordinateFrame f;
|
||||
|
||||
f.translation = translation;
|
||||
f.rotation = rotation.toRotationMatrix();
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
PhysicsFrame PhysicsFrame::lerp(
|
||||
const PhysicsFrame& other,
|
||||
float alpha) const {
|
||||
|
||||
PhysicsFrame result;
|
||||
|
||||
result.translation = translation.lerp(other.translation, alpha);
|
||||
result.rotation = rotation.slerp(other.rotation, alpha);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void PhysicsFrame::deserialize(class BinaryInput& b) {
|
||||
translation.deserialize(b);
|
||||
rotation.deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void PhysicsFrame::serialize(class BinaryOutput& b) const {
|
||||
translation.serialize(b);
|
||||
rotation.serialize(b);
|
||||
}
|
||||
|
||||
|
||||
}; // namespace
|
||||
|
||||
80
modules/acore/deps/g3dlite/source/PhysicsFrameSpline.cpp
Normal file
80
modules/acore/deps/g3dlite/source/PhysicsFrameSpline.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
\file PhysicsFrameSpline.cpp
|
||||
|
||||
\author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
*/
|
||||
#include "G3D/PhysicsFrameSpline.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
PhysicsFrameSpline::PhysicsFrameSpline() {}
|
||||
|
||||
PhysicsFrameSpline::PhysicsFrameSpline(const Any& any) {
|
||||
*this = any;
|
||||
}
|
||||
|
||||
PhysicsFrameSpline& PhysicsFrameSpline::operator=(const Any& any) {
|
||||
const std::string& n = toLower(any.name());
|
||||
*this = PhysicsFrameSpline();
|
||||
|
||||
if (n == "physicsframespline" || n == "pframespline") {
|
||||
any.verifyName("PhysicsFrameSpline", "PFrameSpline");
|
||||
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& k = toLower(it->key);
|
||||
if (k == "cyclic") {
|
||||
cyclic = it->value;
|
||||
} else if (k == "control") {
|
||||
const Any& v = it->value;
|
||||
v.verifyType(Any::ARRAY);
|
||||
control.resize(v.size());
|
||||
for (int i = 0; i < control.size(); ++i) {
|
||||
control[i] = v[i];
|
||||
}
|
||||
if (! any.containsKey("time")) {
|
||||
time.resize(control.size());
|
||||
for (int i = 0; i < time.size(); ++i) {
|
||||
time[i] = i;
|
||||
}
|
||||
}
|
||||
} else if (k == "finalinterval") {
|
||||
finalInterval = it->value;
|
||||
} else if (k == "time") {
|
||||
const Any& v = it->value;
|
||||
v.verifyType(Any::ARRAY);
|
||||
time.resize(v.size());
|
||||
for (int i = 0; i < time.size(); ++i) {
|
||||
time[i] = v[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Must be a PhysicsFrame constructor of some kind
|
||||
append(any);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void PhysicsFrameSpline::correct(PhysicsFrame& frame) const {
|
||||
frame.rotation.unitize();
|
||||
}
|
||||
|
||||
|
||||
void PhysicsFrameSpline::ensureShortestPath(PhysicsFrame* A, int N) const {
|
||||
for (int i = 1; i < N; ++i) {
|
||||
const Quat& p = A[i - 1].rotation;
|
||||
Quat& q = A[i].rotation;
|
||||
|
||||
float cosphi = p.dot(q);
|
||||
|
||||
if (cosphi < 0) {
|
||||
// Going the long way, so change the order
|
||||
q = -q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
149
modules/acore/deps/g3dlite/source/Plane.cpp
Normal file
149
modules/acore/deps/g3dlite/source/Plane.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
@file Plane.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-02-06
|
||||
@edited 2006-01-29
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Plane.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Plane::Plane(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Plane::serialize(class BinaryOutput& b) const {
|
||||
_normal.serialize(b);
|
||||
b.writeFloat64(_distance);
|
||||
}
|
||||
|
||||
|
||||
void Plane::deserialize(class BinaryInput& b) {
|
||||
_normal.deserialize(b);
|
||||
_distance = (float)b.readFloat64();
|
||||
}
|
||||
|
||||
|
||||
Plane::Plane(
|
||||
Vector4 point0,
|
||||
Vector4 point1,
|
||||
Vector4 point2) {
|
||||
|
||||
debugAssertM(
|
||||
point0.w != 0 ||
|
||||
point1.w != 0 ||
|
||||
point2.w != 0,
|
||||
"At least one point must be finite.");
|
||||
|
||||
// Rotate the points around so that the finite points come first.
|
||||
|
||||
while ((point0.w == 0) &&
|
||||
((point1.w == 0) || (point2.w != 0))) {
|
||||
Vector4 temp = point0;
|
||||
point0 = point1;
|
||||
point1 = point2;
|
||||
point2 = temp;
|
||||
}
|
||||
|
||||
Vector3 dir1;
|
||||
Vector3 dir2;
|
||||
|
||||
if (point1.w == 0) {
|
||||
// 1 finite, 2 infinite points; the plane must contain
|
||||
// the direction of the two direcitons
|
||||
dir1 = point1.xyz();
|
||||
dir2 = point2.xyz();
|
||||
} else if (point2.w != 0) {
|
||||
// 3 finite points, the plane must contain the directions
|
||||
// betwseen the points.
|
||||
dir1 = point1.xyz() - point0.xyz();
|
||||
dir2 = point2.xyz() - point0.xyz();
|
||||
} else {
|
||||
// 2 finite, 1 infinite point; the plane must contain
|
||||
// the direction between the first two points and the
|
||||
// direction of the third point.
|
||||
dir1 = point1.xyz() - point0.xyz();
|
||||
dir2 = point2.xyz();
|
||||
}
|
||||
|
||||
_normal = dir1.cross(dir2).direction();
|
||||
_distance = _normal.dot(point0.xyz());
|
||||
}
|
||||
|
||||
|
||||
Plane::Plane(
|
||||
const Vector3& point0,
|
||||
const Vector3& point1,
|
||||
const Vector3& point2) {
|
||||
|
||||
_normal = (point1 - point0).cross(point2 - point0).direction();
|
||||
_distance = _normal.dot(point0);
|
||||
}
|
||||
|
||||
|
||||
Plane::Plane(
|
||||
const Vector3& __normal,
|
||||
const Vector3& point) {
|
||||
|
||||
_normal = __normal.direction();
|
||||
_distance = _normal.dot(point);
|
||||
}
|
||||
|
||||
|
||||
Plane Plane::fromEquation(float a, float b, float c, float d) {
|
||||
Vector3 n(a, b, c);
|
||||
float magnitude = n.magnitude();
|
||||
d /= magnitude;
|
||||
n /= magnitude;
|
||||
return Plane(n, -d);
|
||||
}
|
||||
|
||||
|
||||
void Plane::flip() {
|
||||
_normal = -_normal;
|
||||
_distance = -_distance;
|
||||
}
|
||||
|
||||
|
||||
void Plane::getEquation(Vector3& n, float& d) const {
|
||||
double _d;
|
||||
getEquation(n, _d);
|
||||
d = (float)_d;
|
||||
}
|
||||
|
||||
void Plane::getEquation(Vector3& n, double& d) const {
|
||||
n = _normal;
|
||||
d = -_distance;
|
||||
}
|
||||
|
||||
|
||||
void Plane::getEquation(float& a, float& b, float& c, float& d) const {
|
||||
double _a, _b, _c, _d;
|
||||
getEquation(_a, _b, _c, _d);
|
||||
a = (float)_a;
|
||||
b = (float)_b;
|
||||
c = (float)_c;
|
||||
d = (float)_d;
|
||||
}
|
||||
|
||||
void Plane::getEquation(double& a, double& b, double& c, double& d) const {
|
||||
a = _normal.x;
|
||||
b = _normal.y;
|
||||
c = _normal.z;
|
||||
d = -_distance;
|
||||
}
|
||||
|
||||
|
||||
std::string Plane::toString() const {
|
||||
return format("Plane(%g, %g, %g, %g)", _normal.x, _normal.y, _normal.z, _distance);
|
||||
}
|
||||
|
||||
}
|
||||
125
modules/acore/deps/g3dlite/source/PrecomputedRandom.cpp
Normal file
125
modules/acore/deps/g3dlite/source/PrecomputedRandom.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
@file PrecomputedRandom.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2009-03-31
|
||||
@edited 2009-07-01
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/PrecomputedRandom.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
PrecomputedRandom::PrecomputedRandom(int dataSize, uint32 seed) :
|
||||
Random((void*)NULL),
|
||||
m_hemiUniform(NULL),
|
||||
m_sphereBits(NULL),
|
||||
m_modMask(dataSize - 1),
|
||||
m_freeData(true) {
|
||||
|
||||
alwaysAssertM(isPow2(dataSize), "dataSize must be a power of 2");
|
||||
m_index = seed & m_modMask;
|
||||
|
||||
HemiUniformData* h;
|
||||
SphereBitsData* s;
|
||||
m_hemiUniform = h = (HemiUniformData*) System::malloc(sizeof(HemiUniformData) * dataSize);
|
||||
m_sphereBits = s = (SphereBitsData*) System::malloc(sizeof(SphereBitsData) * dataSize);
|
||||
|
||||
Random r;
|
||||
|
||||
for (int i = 0; i < dataSize; ++i) {
|
||||
h[i].uniform = r.uniform();
|
||||
r.cosHemi(h[i].cosHemiX, h[i].cosHemiY, h[i].cosHemiZ);
|
||||
|
||||
s[i].bits = r.bits();
|
||||
r.sphere(s[i].sphereX, s[i].sphereY, s[i].sphereZ);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
PrecomputedRandom::PrecomputedRandom(const HemiUniformData* data1, const SphereBitsData* data2, int dataSize, uint32 seed) :
|
||||
Random((void*)NULL),
|
||||
m_hemiUniform(data1),
|
||||
m_sphereBits(data2),
|
||||
m_modMask(dataSize - 1),
|
||||
m_freeData(false) {
|
||||
|
||||
m_index = seed & m_modMask;
|
||||
alwaysAssertM(isPow2(dataSize), "dataSize must be a power of 2");
|
||||
}
|
||||
|
||||
|
||||
PrecomputedRandom::~PrecomputedRandom() {
|
||||
if (m_freeData) {
|
||||
System::free(const_cast<HemiUniformData*>(m_hemiUniform));
|
||||
System::free(const_cast<SphereBitsData*>(m_sphereBits));
|
||||
}
|
||||
}
|
||||
|
||||
float PrecomputedRandom::uniform(float low, float high) {
|
||||
m_index = (m_index + 1) & m_modMask;
|
||||
return low + m_hemiUniform[m_index].uniform * (high - low);
|
||||
}
|
||||
|
||||
|
||||
float PrecomputedRandom::uniform() {
|
||||
m_index = (m_index + 1) & m_modMask;
|
||||
return m_hemiUniform[m_index].uniform;
|
||||
}
|
||||
|
||||
|
||||
void PrecomputedRandom::cosHemi(float& x, float& y, float& z) {
|
||||
m_index = (m_index + 1) & m_modMask;
|
||||
x = m_hemiUniform[m_index].cosHemiX;
|
||||
y = m_hemiUniform[m_index].cosHemiY;
|
||||
z = m_hemiUniform[m_index].cosHemiZ;
|
||||
}
|
||||
|
||||
void PrecomputedRandom::cosPowHemi(const float k, float& x, float& y, float& z) {
|
||||
// Computing a cosPowHemi costs 4 slow functions (pow, sqrt, sin,
|
||||
// cos). We can do it with two, given a cosHemi sample, basically
|
||||
// saving the cost of sin and cos and making a single 128-byte
|
||||
// memory read (for a vector) instead of two (for adjacent uniform
|
||||
// floats).
|
||||
|
||||
// cos^1 distribution sample
|
||||
float cos1;
|
||||
cosHemi(x, y, cos1);
|
||||
|
||||
// Fix the distribution by adjusting the cosine:
|
||||
// rnd(cos^k t) = (rnd(cos(t))^2)^(1/k)
|
||||
|
||||
// produces cos^k distribution sample
|
||||
z = pow(cos1, 2.0f / (1.0f + k));
|
||||
|
||||
// Rescale x and y by sqrt(1.0f - square(z)) / sqrt(x*x + y*y).
|
||||
// Add a very tiny offset to handle the (almost impossibly unlikely) case where
|
||||
// z = 1 and x^2+y^2 = 0.
|
||||
static const float eps = 0.000001f;
|
||||
const float s = sqrt((1.0f + eps - square(z)) / (square(x) + square(y) + eps));
|
||||
|
||||
x *= s;
|
||||
y *= s;
|
||||
}
|
||||
|
||||
|
||||
uint32 PrecomputedRandom::bits() {
|
||||
m_index = (m_index + 1) & m_modMask;
|
||||
return m_sphereBits[m_index].bits;
|
||||
}
|
||||
|
||||
|
||||
void PrecomputedRandom::sphere(float& x, float& y, float& z) {
|
||||
m_index = (m_index + 1) & m_modMask;
|
||||
x = m_sphereBits[m_index].sphereX;
|
||||
y = m_sphereBits[m_index].sphereY;
|
||||
z = m_sphereBits[m_index].sphereZ;
|
||||
}
|
||||
|
||||
}
|
||||
599
modules/acore/deps/g3dlite/source/Quat.cpp
Normal file
599
modules/acore/deps/g3dlite/source/Quat.cpp
Normal file
@@ -0,0 +1,599 @@
|
||||
/**
|
||||
@file Quat.cpp
|
||||
|
||||
Quaternion implementation based on Watt & Watt page 363
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2002-01-23
|
||||
@edited 2010-03-31
|
||||
*/
|
||||
|
||||
#include "G3D/Quat.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Quat Quat::fromAxisAngleRotation(
|
||||
const Vector3& axis,
|
||||
float angle) {
|
||||
|
||||
Quat q;
|
||||
|
||||
q.w = cos(angle / 2.0f);
|
||||
q.imag() = axis.direction() * sin(angle / 2.0f);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
Quat::Quat(const class Any& a) {
|
||||
*this = Quat();
|
||||
if (beginsWith(toLower(a.name()), "matrix3")) {
|
||||
*this = a;
|
||||
} else {
|
||||
a.verifyName("Quat");
|
||||
a.verifyType(Any::ARRAY);
|
||||
x = a[0];
|
||||
y = a[1];
|
||||
z = a[2];
|
||||
w = a[3];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Quat::Quat(const Matrix3& rot) {
|
||||
|
||||
static const int plus1mod3[] = {1, 2, 0};
|
||||
|
||||
// Find the index of the largest diagonal component
|
||||
// These ? operations hopefully compile to conditional
|
||||
// move instructions instead of branches.
|
||||
int i = (rot[1][1] > rot[0][0]) ? 1 : 0;
|
||||
i = (rot[2][2] > rot[i][i]) ? 2 : i;
|
||||
|
||||
// Find the indices of the other elements
|
||||
int j = plus1mod3[i];
|
||||
int k = plus1mod3[j];
|
||||
|
||||
// Index the elements of the vector part of the quaternion as a float*
|
||||
float* v = (float*)(this);
|
||||
|
||||
// If we attempted to pre-normalize and trusted the matrix to be
|
||||
// perfectly orthonormal, the result would be:
|
||||
//
|
||||
// double c = sqrt((rot[i][i] - (rot[j][j] + rot[k][k])) + 1.0)
|
||||
// v[i] = -c * 0.5
|
||||
// v[j] = -(rot[i][j] + rot[j][i]) * 0.5 / c
|
||||
// v[k] = -(rot[i][k] + rot[k][i]) * 0.5 / c
|
||||
// w = (rot[j][k] - rot[k][j]) * 0.5 / c
|
||||
//
|
||||
// Since we're going to pay the sqrt anyway, we perform a post normalization, which also
|
||||
// fixes any poorly normalized input. Multiply all elements by 2*c in the above, giving:
|
||||
|
||||
// nc2 = -c^2
|
||||
double nc2 = ((rot[j][j] + rot[k][k]) - rot[i][i]) - 1.0;
|
||||
v[i] = nc2;
|
||||
w = (rot[j][k] - rot[k][j]);
|
||||
v[j] = -(rot[i][j] + rot[j][i]);
|
||||
v[k] = -(rot[i][k] + rot[k][i]);
|
||||
|
||||
// We now have the correct result with the wrong magnitude, so normalize it:
|
||||
float s = sqrt(x*x + y*y + z*z + w*w);
|
||||
if (s > 0.00001f) {
|
||||
s = 1.0f / s;
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
w *= s;
|
||||
} else {
|
||||
// The quaternion is nearly zero. Make it 0 0 0 1
|
||||
x = 0.0f;
|
||||
y = 0.0f;
|
||||
z = 0.0f;
|
||||
w = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Quat::toAxisAngleRotation(
|
||||
Vector3& axis,
|
||||
double& angle) const {
|
||||
|
||||
// Decompose the quaternion into an angle and an axis.
|
||||
|
||||
axis = Vector3(x, y, z);
|
||||
angle = 2 * acos(w);
|
||||
|
||||
float len = sqrt(1.0f - w * w);
|
||||
|
||||
if (fuzzyGt(abs(len), 0.0f)) {
|
||||
axis /= len;
|
||||
}
|
||||
|
||||
// Reduce the range of the angle.
|
||||
|
||||
if (angle < 0) {
|
||||
angle = -angle;
|
||||
axis = -axis;
|
||||
}
|
||||
|
||||
while (angle > twoPi()) {
|
||||
angle -= twoPi();
|
||||
}
|
||||
|
||||
if (abs(angle) > pi()) {
|
||||
angle -= twoPi();
|
||||
}
|
||||
|
||||
// Make the angle positive.
|
||||
|
||||
if (angle < 0.0f) {
|
||||
angle = -angle;
|
||||
axis = -axis;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Matrix3 Quat::toRotationMatrix() const {
|
||||
Matrix3 out = Matrix3::zero();
|
||||
|
||||
toRotationMatrix(out);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Quat::toRotationMatrix(
|
||||
Matrix3& rot) const {
|
||||
|
||||
rot = Matrix3(*this);
|
||||
}
|
||||
|
||||
|
||||
Quat Quat::slerp(
|
||||
const Quat& _quat1,
|
||||
float alpha,
|
||||
float threshold) const {
|
||||
|
||||
// From: Game Physics -- David Eberly pg 538-540
|
||||
// Modified to include lerp for small angles, which
|
||||
// is a common practice.
|
||||
|
||||
// See also:
|
||||
// http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/index.html
|
||||
|
||||
const Quat& quat0 = *this;
|
||||
Quat quat1 = _quat1;
|
||||
|
||||
// angle between quaternion rotations
|
||||
float phi;
|
||||
float cosphi = quat0.dot(quat1);
|
||||
|
||||
|
||||
if (cosphi < 0) {
|
||||
// Change the sign and fix the dot product; we need to
|
||||
// loop the other way to get the shortest path
|
||||
quat1 = -quat1;
|
||||
cosphi = -cosphi;
|
||||
}
|
||||
|
||||
// Using G3D::aCos will clamp the angle to 0 and pi
|
||||
phi = static_cast<float>(G3D::aCos(cosphi));
|
||||
|
||||
if (phi >= threshold) {
|
||||
// For large angles, slerp
|
||||
float scale0, scale1;
|
||||
|
||||
scale0 = sin((1.0f - alpha) * phi);
|
||||
scale1 = sin(alpha * phi);
|
||||
|
||||
return ( (quat0 * scale0) + (quat1 * scale1) ) / sin(phi);
|
||||
} else {
|
||||
// For small angles, linear interpolate
|
||||
return quat0.nlerp(quat1, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Quat Quat::nlerp(
|
||||
const Quat& quat1,
|
||||
float alpha) const {
|
||||
|
||||
Quat result = (*this) * (1.0f - alpha) + quat1 * alpha;
|
||||
return result / result.magnitude();
|
||||
}
|
||||
|
||||
|
||||
Quat Quat::operator*(const Quat& other) const {
|
||||
|
||||
// Following Watt & Watt, page 360
|
||||
const Vector3& v1 = imag();
|
||||
const Vector3& v2 = other.imag();
|
||||
float s1 = w;
|
||||
float s2 = other.w;
|
||||
|
||||
return Quat(s1*v2 + s2*v1 + v1.cross(v2), s1*s2 - v1.dot(v2));
|
||||
}
|
||||
|
||||
|
||||
// From "Uniform Random Rotations", Ken Shoemake, Graphics Gems III.
|
||||
Quat Quat::unitRandom() {
|
||||
float x0 = uniformRandom();
|
||||
float r1 = sqrtf(1 - x0),
|
||||
r2 = sqrtf(x0);
|
||||
float t1 = (float)G3D::twoPi() * uniformRandom();
|
||||
float t2 = (float)G3D::twoPi() * uniformRandom();
|
||||
float c1 = cosf(t1),
|
||||
s1 = sinf(t1);
|
||||
float c2 = cosf(t2),
|
||||
s2 = sinf(t2);
|
||||
return Quat(s1 * r1, c1 * r1, s2 * r2, c2 * r2);
|
||||
}
|
||||
|
||||
|
||||
void Quat::deserialize(class BinaryInput& b) {
|
||||
x = b.readFloat32();
|
||||
y = b.readFloat32();
|
||||
z = b.readFloat32();
|
||||
w = b.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Quat::serialize(class BinaryOutput& b) const {
|
||||
b.writeFloat32(x);
|
||||
b.writeFloat32(y);
|
||||
b.writeFloat32(z);
|
||||
b.writeFloat32(w);
|
||||
}
|
||||
|
||||
|
||||
// 2-char swizzles
|
||||
|
||||
Vector2 Quat::xx() const { return Vector2 (x, x); }
|
||||
Vector2 Quat::yx() const { return Vector2 (y, x); }
|
||||
Vector2 Quat::zx() const { return Vector2 (z, x); }
|
||||
Vector2 Quat::wx() const { return Vector2 (w, x); }
|
||||
Vector2 Quat::xy() const { return Vector2 (x, y); }
|
||||
Vector2 Quat::yy() const { return Vector2 (y, y); }
|
||||
Vector2 Quat::zy() const { return Vector2 (z, y); }
|
||||
Vector2 Quat::wy() const { return Vector2 (w, y); }
|
||||
Vector2 Quat::xz() const { return Vector2 (x, z); }
|
||||
Vector2 Quat::yz() const { return Vector2 (y, z); }
|
||||
Vector2 Quat::zz() const { return Vector2 (z, z); }
|
||||
Vector2 Quat::wz() const { return Vector2 (w, z); }
|
||||
Vector2 Quat::xw() const { return Vector2 (x, w); }
|
||||
Vector2 Quat::yw() const { return Vector2 (y, w); }
|
||||
Vector2 Quat::zw() const { return Vector2 (z, w); }
|
||||
Vector2 Quat::ww() const { return Vector2 (w, w); }
|
||||
|
||||
// 3-char swizzles
|
||||
|
||||
Vector3 Quat::xxx() const { return Vector3 (x, x, x); }
|
||||
Vector3 Quat::yxx() const { return Vector3 (y, x, x); }
|
||||
Vector3 Quat::zxx() const { return Vector3 (z, x, x); }
|
||||
Vector3 Quat::wxx() const { return Vector3 (w, x, x); }
|
||||
Vector3 Quat::xyx() const { return Vector3 (x, y, x); }
|
||||
Vector3 Quat::yyx() const { return Vector3 (y, y, x); }
|
||||
Vector3 Quat::zyx() const { return Vector3 (z, y, x); }
|
||||
Vector3 Quat::wyx() const { return Vector3 (w, y, x); }
|
||||
Vector3 Quat::xzx() const { return Vector3 (x, z, x); }
|
||||
Vector3 Quat::yzx() const { return Vector3 (y, z, x); }
|
||||
Vector3 Quat::zzx() const { return Vector3 (z, z, x); }
|
||||
Vector3 Quat::wzx() const { return Vector3 (w, z, x); }
|
||||
Vector3 Quat::xwx() const { return Vector3 (x, w, x); }
|
||||
Vector3 Quat::ywx() const { return Vector3 (y, w, x); }
|
||||
Vector3 Quat::zwx() const { return Vector3 (z, w, x); }
|
||||
Vector3 Quat::wwx() const { return Vector3 (w, w, x); }
|
||||
Vector3 Quat::xxy() const { return Vector3 (x, x, y); }
|
||||
Vector3 Quat::yxy() const { return Vector3 (y, x, y); }
|
||||
Vector3 Quat::zxy() const { return Vector3 (z, x, y); }
|
||||
Vector3 Quat::wxy() const { return Vector3 (w, x, y); }
|
||||
Vector3 Quat::xyy() const { return Vector3 (x, y, y); }
|
||||
Vector3 Quat::yyy() const { return Vector3 (y, y, y); }
|
||||
Vector3 Quat::zyy() const { return Vector3 (z, y, y); }
|
||||
Vector3 Quat::wyy() const { return Vector3 (w, y, y); }
|
||||
Vector3 Quat::xzy() const { return Vector3 (x, z, y); }
|
||||
Vector3 Quat::yzy() const { return Vector3 (y, z, y); }
|
||||
Vector3 Quat::zzy() const { return Vector3 (z, z, y); }
|
||||
Vector3 Quat::wzy() const { return Vector3 (w, z, y); }
|
||||
Vector3 Quat::xwy() const { return Vector3 (x, w, y); }
|
||||
Vector3 Quat::ywy() const { return Vector3 (y, w, y); }
|
||||
Vector3 Quat::zwy() const { return Vector3 (z, w, y); }
|
||||
Vector3 Quat::wwy() const { return Vector3 (w, w, y); }
|
||||
Vector3 Quat::xxz() const { return Vector3 (x, x, z); }
|
||||
Vector3 Quat::yxz() const { return Vector3 (y, x, z); }
|
||||
Vector3 Quat::zxz() const { return Vector3 (z, x, z); }
|
||||
Vector3 Quat::wxz() const { return Vector3 (w, x, z); }
|
||||
Vector3 Quat::xyz() const { return Vector3 (x, y, z); }
|
||||
Vector3 Quat::yyz() const { return Vector3 (y, y, z); }
|
||||
Vector3 Quat::zyz() const { return Vector3 (z, y, z); }
|
||||
Vector3 Quat::wyz() const { return Vector3 (w, y, z); }
|
||||
Vector3 Quat::xzz() const { return Vector3 (x, z, z); }
|
||||
Vector3 Quat::yzz() const { return Vector3 (y, z, z); }
|
||||
Vector3 Quat::zzz() const { return Vector3 (z, z, z); }
|
||||
Vector3 Quat::wzz() const { return Vector3 (w, z, z); }
|
||||
Vector3 Quat::xwz() const { return Vector3 (x, w, z); }
|
||||
Vector3 Quat::ywz() const { return Vector3 (y, w, z); }
|
||||
Vector3 Quat::zwz() const { return Vector3 (z, w, z); }
|
||||
Vector3 Quat::wwz() const { return Vector3 (w, w, z); }
|
||||
Vector3 Quat::xxw() const { return Vector3 (x, x, w); }
|
||||
Vector3 Quat::yxw() const { return Vector3 (y, x, w); }
|
||||
Vector3 Quat::zxw() const { return Vector3 (z, x, w); }
|
||||
Vector3 Quat::wxw() const { return Vector3 (w, x, w); }
|
||||
Vector3 Quat::xyw() const { return Vector3 (x, y, w); }
|
||||
Vector3 Quat::yyw() const { return Vector3 (y, y, w); }
|
||||
Vector3 Quat::zyw() const { return Vector3 (z, y, w); }
|
||||
Vector3 Quat::wyw() const { return Vector3 (w, y, w); }
|
||||
Vector3 Quat::xzw() const { return Vector3 (x, z, w); }
|
||||
Vector3 Quat::yzw() const { return Vector3 (y, z, w); }
|
||||
Vector3 Quat::zzw() const { return Vector3 (z, z, w); }
|
||||
Vector3 Quat::wzw() const { return Vector3 (w, z, w); }
|
||||
Vector3 Quat::xww() const { return Vector3 (x, w, w); }
|
||||
Vector3 Quat::yww() const { return Vector3 (y, w, w); }
|
||||
Vector3 Quat::zww() const { return Vector3 (z, w, w); }
|
||||
Vector3 Quat::www() const { return Vector3 (w, w, w); }
|
||||
|
||||
// 4-char swizzles
|
||||
|
||||
Vector4 Quat::xxxx() const { return Vector4 (x, x, x, x); }
|
||||
Vector4 Quat::yxxx() const { return Vector4 (y, x, x, x); }
|
||||
Vector4 Quat::zxxx() const { return Vector4 (z, x, x, x); }
|
||||
Vector4 Quat::wxxx() const { return Vector4 (w, x, x, x); }
|
||||
Vector4 Quat::xyxx() const { return Vector4 (x, y, x, x); }
|
||||
Vector4 Quat::yyxx() const { return Vector4 (y, y, x, x); }
|
||||
Vector4 Quat::zyxx() const { return Vector4 (z, y, x, x); }
|
||||
Vector4 Quat::wyxx() const { return Vector4 (w, y, x, x); }
|
||||
Vector4 Quat::xzxx() const { return Vector4 (x, z, x, x); }
|
||||
Vector4 Quat::yzxx() const { return Vector4 (y, z, x, x); }
|
||||
Vector4 Quat::zzxx() const { return Vector4 (z, z, x, x); }
|
||||
Vector4 Quat::wzxx() const { return Vector4 (w, z, x, x); }
|
||||
Vector4 Quat::xwxx() const { return Vector4 (x, w, x, x); }
|
||||
Vector4 Quat::ywxx() const { return Vector4 (y, w, x, x); }
|
||||
Vector4 Quat::zwxx() const { return Vector4 (z, w, x, x); }
|
||||
Vector4 Quat::wwxx() const { return Vector4 (w, w, x, x); }
|
||||
Vector4 Quat::xxyx() const { return Vector4 (x, x, y, x); }
|
||||
Vector4 Quat::yxyx() const { return Vector4 (y, x, y, x); }
|
||||
Vector4 Quat::zxyx() const { return Vector4 (z, x, y, x); }
|
||||
Vector4 Quat::wxyx() const { return Vector4 (w, x, y, x); }
|
||||
Vector4 Quat::xyyx() const { return Vector4 (x, y, y, x); }
|
||||
Vector4 Quat::yyyx() const { return Vector4 (y, y, y, x); }
|
||||
Vector4 Quat::zyyx() const { return Vector4 (z, y, y, x); }
|
||||
Vector4 Quat::wyyx() const { return Vector4 (w, y, y, x); }
|
||||
Vector4 Quat::xzyx() const { return Vector4 (x, z, y, x); }
|
||||
Vector4 Quat::yzyx() const { return Vector4 (y, z, y, x); }
|
||||
Vector4 Quat::zzyx() const { return Vector4 (z, z, y, x); }
|
||||
Vector4 Quat::wzyx() const { return Vector4 (w, z, y, x); }
|
||||
Vector4 Quat::xwyx() const { return Vector4 (x, w, y, x); }
|
||||
Vector4 Quat::ywyx() const { return Vector4 (y, w, y, x); }
|
||||
Vector4 Quat::zwyx() const { return Vector4 (z, w, y, x); }
|
||||
Vector4 Quat::wwyx() const { return Vector4 (w, w, y, x); }
|
||||
Vector4 Quat::xxzx() const { return Vector4 (x, x, z, x); }
|
||||
Vector4 Quat::yxzx() const { return Vector4 (y, x, z, x); }
|
||||
Vector4 Quat::zxzx() const { return Vector4 (z, x, z, x); }
|
||||
Vector4 Quat::wxzx() const { return Vector4 (w, x, z, x); }
|
||||
Vector4 Quat::xyzx() const { return Vector4 (x, y, z, x); }
|
||||
Vector4 Quat::yyzx() const { return Vector4 (y, y, z, x); }
|
||||
Vector4 Quat::zyzx() const { return Vector4 (z, y, z, x); }
|
||||
Vector4 Quat::wyzx() const { return Vector4 (w, y, z, x); }
|
||||
Vector4 Quat::xzzx() const { return Vector4 (x, z, z, x); }
|
||||
Vector4 Quat::yzzx() const { return Vector4 (y, z, z, x); }
|
||||
Vector4 Quat::zzzx() const { return Vector4 (z, z, z, x); }
|
||||
Vector4 Quat::wzzx() const { return Vector4 (w, z, z, x); }
|
||||
Vector4 Quat::xwzx() const { return Vector4 (x, w, z, x); }
|
||||
Vector4 Quat::ywzx() const { return Vector4 (y, w, z, x); }
|
||||
Vector4 Quat::zwzx() const { return Vector4 (z, w, z, x); }
|
||||
Vector4 Quat::wwzx() const { return Vector4 (w, w, z, x); }
|
||||
Vector4 Quat::xxwx() const { return Vector4 (x, x, w, x); }
|
||||
Vector4 Quat::yxwx() const { return Vector4 (y, x, w, x); }
|
||||
Vector4 Quat::zxwx() const { return Vector4 (z, x, w, x); }
|
||||
Vector4 Quat::wxwx() const { return Vector4 (w, x, w, x); }
|
||||
Vector4 Quat::xywx() const { return Vector4 (x, y, w, x); }
|
||||
Vector4 Quat::yywx() const { return Vector4 (y, y, w, x); }
|
||||
Vector4 Quat::zywx() const { return Vector4 (z, y, w, x); }
|
||||
Vector4 Quat::wywx() const { return Vector4 (w, y, w, x); }
|
||||
Vector4 Quat::xzwx() const { return Vector4 (x, z, w, x); }
|
||||
Vector4 Quat::yzwx() const { return Vector4 (y, z, w, x); }
|
||||
Vector4 Quat::zzwx() const { return Vector4 (z, z, w, x); }
|
||||
Vector4 Quat::wzwx() const { return Vector4 (w, z, w, x); }
|
||||
Vector4 Quat::xwwx() const { return Vector4 (x, w, w, x); }
|
||||
Vector4 Quat::ywwx() const { return Vector4 (y, w, w, x); }
|
||||
Vector4 Quat::zwwx() const { return Vector4 (z, w, w, x); }
|
||||
Vector4 Quat::wwwx() const { return Vector4 (w, w, w, x); }
|
||||
Vector4 Quat::xxxy() const { return Vector4 (x, x, x, y); }
|
||||
Vector4 Quat::yxxy() const { return Vector4 (y, x, x, y); }
|
||||
Vector4 Quat::zxxy() const { return Vector4 (z, x, x, y); }
|
||||
Vector4 Quat::wxxy() const { return Vector4 (w, x, x, y); }
|
||||
Vector4 Quat::xyxy() const { return Vector4 (x, y, x, y); }
|
||||
Vector4 Quat::yyxy() const { return Vector4 (y, y, x, y); }
|
||||
Vector4 Quat::zyxy() const { return Vector4 (z, y, x, y); }
|
||||
Vector4 Quat::wyxy() const { return Vector4 (w, y, x, y); }
|
||||
Vector4 Quat::xzxy() const { return Vector4 (x, z, x, y); }
|
||||
Vector4 Quat::yzxy() const { return Vector4 (y, z, x, y); }
|
||||
Vector4 Quat::zzxy() const { return Vector4 (z, z, x, y); }
|
||||
Vector4 Quat::wzxy() const { return Vector4 (w, z, x, y); }
|
||||
Vector4 Quat::xwxy() const { return Vector4 (x, w, x, y); }
|
||||
Vector4 Quat::ywxy() const { return Vector4 (y, w, x, y); }
|
||||
Vector4 Quat::zwxy() const { return Vector4 (z, w, x, y); }
|
||||
Vector4 Quat::wwxy() const { return Vector4 (w, w, x, y); }
|
||||
Vector4 Quat::xxyy() const { return Vector4 (x, x, y, y); }
|
||||
Vector4 Quat::yxyy() const { return Vector4 (y, x, y, y); }
|
||||
Vector4 Quat::zxyy() const { return Vector4 (z, x, y, y); }
|
||||
Vector4 Quat::wxyy() const { return Vector4 (w, x, y, y); }
|
||||
Vector4 Quat::xyyy() const { return Vector4 (x, y, y, y); }
|
||||
Vector4 Quat::yyyy() const { return Vector4 (y, y, y, y); }
|
||||
Vector4 Quat::zyyy() const { return Vector4 (z, y, y, y); }
|
||||
Vector4 Quat::wyyy() const { return Vector4 (w, y, y, y); }
|
||||
Vector4 Quat::xzyy() const { return Vector4 (x, z, y, y); }
|
||||
Vector4 Quat::yzyy() const { return Vector4 (y, z, y, y); }
|
||||
Vector4 Quat::zzyy() const { return Vector4 (z, z, y, y); }
|
||||
Vector4 Quat::wzyy() const { return Vector4 (w, z, y, y); }
|
||||
Vector4 Quat::xwyy() const { return Vector4 (x, w, y, y); }
|
||||
Vector4 Quat::ywyy() const { return Vector4 (y, w, y, y); }
|
||||
Vector4 Quat::zwyy() const { return Vector4 (z, w, y, y); }
|
||||
Vector4 Quat::wwyy() const { return Vector4 (w, w, y, y); }
|
||||
Vector4 Quat::xxzy() const { return Vector4 (x, x, z, y); }
|
||||
Vector4 Quat::yxzy() const { return Vector4 (y, x, z, y); }
|
||||
Vector4 Quat::zxzy() const { return Vector4 (z, x, z, y); }
|
||||
Vector4 Quat::wxzy() const { return Vector4 (w, x, z, y); }
|
||||
Vector4 Quat::xyzy() const { return Vector4 (x, y, z, y); }
|
||||
Vector4 Quat::yyzy() const { return Vector4 (y, y, z, y); }
|
||||
Vector4 Quat::zyzy() const { return Vector4 (z, y, z, y); }
|
||||
Vector4 Quat::wyzy() const { return Vector4 (w, y, z, y); }
|
||||
Vector4 Quat::xzzy() const { return Vector4 (x, z, z, y); }
|
||||
Vector4 Quat::yzzy() const { return Vector4 (y, z, z, y); }
|
||||
Vector4 Quat::zzzy() const { return Vector4 (z, z, z, y); }
|
||||
Vector4 Quat::wzzy() const { return Vector4 (w, z, z, y); }
|
||||
Vector4 Quat::xwzy() const { return Vector4 (x, w, z, y); }
|
||||
Vector4 Quat::ywzy() const { return Vector4 (y, w, z, y); }
|
||||
Vector4 Quat::zwzy() const { return Vector4 (z, w, z, y); }
|
||||
Vector4 Quat::wwzy() const { return Vector4 (w, w, z, y); }
|
||||
Vector4 Quat::xxwy() const { return Vector4 (x, x, w, y); }
|
||||
Vector4 Quat::yxwy() const { return Vector4 (y, x, w, y); }
|
||||
Vector4 Quat::zxwy() const { return Vector4 (z, x, w, y); }
|
||||
Vector4 Quat::wxwy() const { return Vector4 (w, x, w, y); }
|
||||
Vector4 Quat::xywy() const { return Vector4 (x, y, w, y); }
|
||||
Vector4 Quat::yywy() const { return Vector4 (y, y, w, y); }
|
||||
Vector4 Quat::zywy() const { return Vector4 (z, y, w, y); }
|
||||
Vector4 Quat::wywy() const { return Vector4 (w, y, w, y); }
|
||||
Vector4 Quat::xzwy() const { return Vector4 (x, z, w, y); }
|
||||
Vector4 Quat::yzwy() const { return Vector4 (y, z, w, y); }
|
||||
Vector4 Quat::zzwy() const { return Vector4 (z, z, w, y); }
|
||||
Vector4 Quat::wzwy() const { return Vector4 (w, z, w, y); }
|
||||
Vector4 Quat::xwwy() const { return Vector4 (x, w, w, y); }
|
||||
Vector4 Quat::ywwy() const { return Vector4 (y, w, w, y); }
|
||||
Vector4 Quat::zwwy() const { return Vector4 (z, w, w, y); }
|
||||
Vector4 Quat::wwwy() const { return Vector4 (w, w, w, y); }
|
||||
Vector4 Quat::xxxz() const { return Vector4 (x, x, x, z); }
|
||||
Vector4 Quat::yxxz() const { return Vector4 (y, x, x, z); }
|
||||
Vector4 Quat::zxxz() const { return Vector4 (z, x, x, z); }
|
||||
Vector4 Quat::wxxz() const { return Vector4 (w, x, x, z); }
|
||||
Vector4 Quat::xyxz() const { return Vector4 (x, y, x, z); }
|
||||
Vector4 Quat::yyxz() const { return Vector4 (y, y, x, z); }
|
||||
Vector4 Quat::zyxz() const { return Vector4 (z, y, x, z); }
|
||||
Vector4 Quat::wyxz() const { return Vector4 (w, y, x, z); }
|
||||
Vector4 Quat::xzxz() const { return Vector4 (x, z, x, z); }
|
||||
Vector4 Quat::yzxz() const { return Vector4 (y, z, x, z); }
|
||||
Vector4 Quat::zzxz() const { return Vector4 (z, z, x, z); }
|
||||
Vector4 Quat::wzxz() const { return Vector4 (w, z, x, z); }
|
||||
Vector4 Quat::xwxz() const { return Vector4 (x, w, x, z); }
|
||||
Vector4 Quat::ywxz() const { return Vector4 (y, w, x, z); }
|
||||
Vector4 Quat::zwxz() const { return Vector4 (z, w, x, z); }
|
||||
Vector4 Quat::wwxz() const { return Vector4 (w, w, x, z); }
|
||||
Vector4 Quat::xxyz() const { return Vector4 (x, x, y, z); }
|
||||
Vector4 Quat::yxyz() const { return Vector4 (y, x, y, z); }
|
||||
Vector4 Quat::zxyz() const { return Vector4 (z, x, y, z); }
|
||||
Vector4 Quat::wxyz() const { return Vector4 (w, x, y, z); }
|
||||
Vector4 Quat::xyyz() const { return Vector4 (x, y, y, z); }
|
||||
Vector4 Quat::yyyz() const { return Vector4 (y, y, y, z); }
|
||||
Vector4 Quat::zyyz() const { return Vector4 (z, y, y, z); }
|
||||
Vector4 Quat::wyyz() const { return Vector4 (w, y, y, z); }
|
||||
Vector4 Quat::xzyz() const { return Vector4 (x, z, y, z); }
|
||||
Vector4 Quat::yzyz() const { return Vector4 (y, z, y, z); }
|
||||
Vector4 Quat::zzyz() const { return Vector4 (z, z, y, z); }
|
||||
Vector4 Quat::wzyz() const { return Vector4 (w, z, y, z); }
|
||||
Vector4 Quat::xwyz() const { return Vector4 (x, w, y, z); }
|
||||
Vector4 Quat::ywyz() const { return Vector4 (y, w, y, z); }
|
||||
Vector4 Quat::zwyz() const { return Vector4 (z, w, y, z); }
|
||||
Vector4 Quat::wwyz() const { return Vector4 (w, w, y, z); }
|
||||
Vector4 Quat::xxzz() const { return Vector4 (x, x, z, z); }
|
||||
Vector4 Quat::yxzz() const { return Vector4 (y, x, z, z); }
|
||||
Vector4 Quat::zxzz() const { return Vector4 (z, x, z, z); }
|
||||
Vector4 Quat::wxzz() const { return Vector4 (w, x, z, z); }
|
||||
Vector4 Quat::xyzz() const { return Vector4 (x, y, z, z); }
|
||||
Vector4 Quat::yyzz() const { return Vector4 (y, y, z, z); }
|
||||
Vector4 Quat::zyzz() const { return Vector4 (z, y, z, z); }
|
||||
Vector4 Quat::wyzz() const { return Vector4 (w, y, z, z); }
|
||||
Vector4 Quat::xzzz() const { return Vector4 (x, z, z, z); }
|
||||
Vector4 Quat::yzzz() const { return Vector4 (y, z, z, z); }
|
||||
Vector4 Quat::zzzz() const { return Vector4 (z, z, z, z); }
|
||||
Vector4 Quat::wzzz() const { return Vector4 (w, z, z, z); }
|
||||
Vector4 Quat::xwzz() const { return Vector4 (x, w, z, z); }
|
||||
Vector4 Quat::ywzz() const { return Vector4 (y, w, z, z); }
|
||||
Vector4 Quat::zwzz() const { return Vector4 (z, w, z, z); }
|
||||
Vector4 Quat::wwzz() const { return Vector4 (w, w, z, z); }
|
||||
Vector4 Quat::xxwz() const { return Vector4 (x, x, w, z); }
|
||||
Vector4 Quat::yxwz() const { return Vector4 (y, x, w, z); }
|
||||
Vector4 Quat::zxwz() const { return Vector4 (z, x, w, z); }
|
||||
Vector4 Quat::wxwz() const { return Vector4 (w, x, w, z); }
|
||||
Vector4 Quat::xywz() const { return Vector4 (x, y, w, z); }
|
||||
Vector4 Quat::yywz() const { return Vector4 (y, y, w, z); }
|
||||
Vector4 Quat::zywz() const { return Vector4 (z, y, w, z); }
|
||||
Vector4 Quat::wywz() const { return Vector4 (w, y, w, z); }
|
||||
Vector4 Quat::xzwz() const { return Vector4 (x, z, w, z); }
|
||||
Vector4 Quat::yzwz() const { return Vector4 (y, z, w, z); }
|
||||
Vector4 Quat::zzwz() const { return Vector4 (z, z, w, z); }
|
||||
Vector4 Quat::wzwz() const { return Vector4 (w, z, w, z); }
|
||||
Vector4 Quat::xwwz() const { return Vector4 (x, w, w, z); }
|
||||
Vector4 Quat::ywwz() const { return Vector4 (y, w, w, z); }
|
||||
Vector4 Quat::zwwz() const { return Vector4 (z, w, w, z); }
|
||||
Vector4 Quat::wwwz() const { return Vector4 (w, w, w, z); }
|
||||
Vector4 Quat::xxxw() const { return Vector4 (x, x, x, w); }
|
||||
Vector4 Quat::yxxw() const { return Vector4 (y, x, x, w); }
|
||||
Vector4 Quat::zxxw() const { return Vector4 (z, x, x, w); }
|
||||
Vector4 Quat::wxxw() const { return Vector4 (w, x, x, w); }
|
||||
Vector4 Quat::xyxw() const { return Vector4 (x, y, x, w); }
|
||||
Vector4 Quat::yyxw() const { return Vector4 (y, y, x, w); }
|
||||
Vector4 Quat::zyxw() const { return Vector4 (z, y, x, w); }
|
||||
Vector4 Quat::wyxw() const { return Vector4 (w, y, x, w); }
|
||||
Vector4 Quat::xzxw() const { return Vector4 (x, z, x, w); }
|
||||
Vector4 Quat::yzxw() const { return Vector4 (y, z, x, w); }
|
||||
Vector4 Quat::zzxw() const { return Vector4 (z, z, x, w); }
|
||||
Vector4 Quat::wzxw() const { return Vector4 (w, z, x, w); }
|
||||
Vector4 Quat::xwxw() const { return Vector4 (x, w, x, w); }
|
||||
Vector4 Quat::ywxw() const { return Vector4 (y, w, x, w); }
|
||||
Vector4 Quat::zwxw() const { return Vector4 (z, w, x, w); }
|
||||
Vector4 Quat::wwxw() const { return Vector4 (w, w, x, w); }
|
||||
Vector4 Quat::xxyw() const { return Vector4 (x, x, y, w); }
|
||||
Vector4 Quat::yxyw() const { return Vector4 (y, x, y, w); }
|
||||
Vector4 Quat::zxyw() const { return Vector4 (z, x, y, w); }
|
||||
Vector4 Quat::wxyw() const { return Vector4 (w, x, y, w); }
|
||||
Vector4 Quat::xyyw() const { return Vector4 (x, y, y, w); }
|
||||
Vector4 Quat::yyyw() const { return Vector4 (y, y, y, w); }
|
||||
Vector4 Quat::zyyw() const { return Vector4 (z, y, y, w); }
|
||||
Vector4 Quat::wyyw() const { return Vector4 (w, y, y, w); }
|
||||
Vector4 Quat::xzyw() const { return Vector4 (x, z, y, w); }
|
||||
Vector4 Quat::yzyw() const { return Vector4 (y, z, y, w); }
|
||||
Vector4 Quat::zzyw() const { return Vector4 (z, z, y, w); }
|
||||
Vector4 Quat::wzyw() const { return Vector4 (w, z, y, w); }
|
||||
Vector4 Quat::xwyw() const { return Vector4 (x, w, y, w); }
|
||||
Vector4 Quat::ywyw() const { return Vector4 (y, w, y, w); }
|
||||
Vector4 Quat::zwyw() const { return Vector4 (z, w, y, w); }
|
||||
Vector4 Quat::wwyw() const { return Vector4 (w, w, y, w); }
|
||||
Vector4 Quat::xxzw() const { return Vector4 (x, x, z, w); }
|
||||
Vector4 Quat::yxzw() const { return Vector4 (y, x, z, w); }
|
||||
Vector4 Quat::zxzw() const { return Vector4 (z, x, z, w); }
|
||||
Vector4 Quat::wxzw() const { return Vector4 (w, x, z, w); }
|
||||
Vector4 Quat::xyzw() const { return Vector4 (x, y, z, w); }
|
||||
Vector4 Quat::yyzw() const { return Vector4 (y, y, z, w); }
|
||||
Vector4 Quat::zyzw() const { return Vector4 (z, y, z, w); }
|
||||
Vector4 Quat::wyzw() const { return Vector4 (w, y, z, w); }
|
||||
Vector4 Quat::xzzw() const { return Vector4 (x, z, z, w); }
|
||||
Vector4 Quat::yzzw() const { return Vector4 (y, z, z, w); }
|
||||
Vector4 Quat::zzzw() const { return Vector4 (z, z, z, w); }
|
||||
Vector4 Quat::wzzw() const { return Vector4 (w, z, z, w); }
|
||||
Vector4 Quat::xwzw() const { return Vector4 (x, w, z, w); }
|
||||
Vector4 Quat::ywzw() const { return Vector4 (y, w, z, w); }
|
||||
Vector4 Quat::zwzw() const { return Vector4 (z, w, z, w); }
|
||||
Vector4 Quat::wwzw() const { return Vector4 (w, w, z, w); }
|
||||
Vector4 Quat::xxww() const { return Vector4 (x, x, w, w); }
|
||||
Vector4 Quat::yxww() const { return Vector4 (y, x, w, w); }
|
||||
Vector4 Quat::zxww() const { return Vector4 (z, x, w, w); }
|
||||
Vector4 Quat::wxww() const { return Vector4 (w, x, w, w); }
|
||||
Vector4 Quat::xyww() const { return Vector4 (x, y, w, w); }
|
||||
Vector4 Quat::yyww() const { return Vector4 (y, y, w, w); }
|
||||
Vector4 Quat::zyww() const { return Vector4 (z, y, w, w); }
|
||||
Vector4 Quat::wyww() const { return Vector4 (w, y, w, w); }
|
||||
Vector4 Quat::xzww() const { return Vector4 (x, z, w, w); }
|
||||
Vector4 Quat::yzww() const { return Vector4 (y, z, w, w); }
|
||||
Vector4 Quat::zzww() const { return Vector4 (z, z, w, w); }
|
||||
Vector4 Quat::wzww() const { return Vector4 (w, z, w, w); }
|
||||
Vector4 Quat::xwww() const { return Vector4 (x, w, w, w); }
|
||||
Vector4 Quat::ywww() const { return Vector4 (y, w, w, w); }
|
||||
Vector4 Quat::zwww() const { return Vector4 (z, w, w, w); }
|
||||
Vector4 Quat::wwww() const { return Vector4 (w, w, w, w); }
|
||||
}
|
||||
|
||||
212
modules/acore/deps/g3dlite/source/Random.cpp
Normal file
212
modules/acore/deps/g3dlite/source/Random.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
@file Random.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2009-01-02
|
||||
@edited 2009-03-29
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
#include "G3D/Random.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Random& Random::common() {
|
||||
static Random r;
|
||||
return r;
|
||||
}
|
||||
|
||||
Random::Random(void* x) : state(NULL), m_threadsafe(false) {
|
||||
(void)x;
|
||||
}
|
||||
|
||||
|
||||
Random::Random(uint32 seed, bool threadsafe) : m_threadsafe(threadsafe) {
|
||||
const uint32 X = 1812433253UL;
|
||||
|
||||
state = new uint32[N];
|
||||
state[0] = seed;
|
||||
for (index = 1; index < (int)N; ++index) {
|
||||
state[index] = X * (state[index - 1] ^ (state[index - 1] >> 30)) + index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Random::~Random() {
|
||||
delete[] state;
|
||||
state = NULL;
|
||||
}
|
||||
|
||||
|
||||
uint32 Random::bits() {
|
||||
// See http://en.wikipedia.org/wiki/Mersenne_twister
|
||||
|
||||
// Make a local copy of the index variable to ensure that it
|
||||
// is not out of bounds
|
||||
int localIndex = index;
|
||||
|
||||
// Automatically checks for index < 0 if corrupted
|
||||
// by unsynchronized threads.
|
||||
if ((unsigned int)localIndex >= (unsigned int)N) {
|
||||
generate();
|
||||
localIndex = 0;
|
||||
}
|
||||
// Increment the global index. It may go out of bounds on
|
||||
// multiple threads, but the above check ensures that the
|
||||
// array index actually used never goes out of bounds.
|
||||
// It doesn't matter if we grab the same array index twice
|
||||
// on two threads, since the distribution of random numbers
|
||||
// will still be uniform.
|
||||
++index;
|
||||
// Return the next random in the sequence
|
||||
uint32 r = state[localIndex];
|
||||
|
||||
// Temper the result
|
||||
r ^= r >> U;
|
||||
r ^= (r << S) & B;
|
||||
r ^= (r << T) & C;
|
||||
r ^= r >> L;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/** Generate the next N ints, and store them for readback later */
|
||||
void Random::generate() {
|
||||
// Lower R bits
|
||||
static const uint32 LOWER_MASK = (1LU << R) - 1;
|
||||
|
||||
// Upper (32 - R) bits
|
||||
static const uint32 UPPER_MASK = 0xFFFFFFFF << R;
|
||||
static const uint32 mag01[2] = {0UL, (uint32)A};
|
||||
|
||||
if (m_threadsafe) {
|
||||
bool contention = ! lock.lock();
|
||||
if (contention) {
|
||||
// Another thread just generated a set of numbers; no need for
|
||||
// this thread to do it too
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// First N - M
|
||||
for (unsigned int i = 0; i < N - M; ++i) {
|
||||
uint32 x = (state[i] & UPPER_MASK) | (state[i + 1] & LOWER_MASK);
|
||||
state[i] = state[i + M] ^ (x >> 1) ^ mag01[x & 1];
|
||||
}
|
||||
|
||||
// Rest
|
||||
for (unsigned int i = N - M + 1; i < N - 1; ++i) {
|
||||
uint32 x = (state[i] & UPPER_MASK) | (state[i + 1] & LOWER_MASK);
|
||||
state[i] = state[i + (M - N)] ^ (x >> 1) ^ mag01[x & 1];
|
||||
}
|
||||
|
||||
uint32 y = (state[N - 1] & UPPER_MASK) | (state[0] & LOWER_MASK);
|
||||
state[N - 1] = state[M - 1] ^ (y >> 1) ^ mag01[y & 1];
|
||||
index = 0;
|
||||
|
||||
if (m_threadsafe) {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Random::integer(int low, int high) {
|
||||
int r = iFloor(low + (high - low + 1) * (double)bits() / 0xFFFFFFFFUL);
|
||||
|
||||
// There is a *very small* chance of generating
|
||||
// a number larger than high.
|
||||
if (r > high) {
|
||||
return high;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float Random::gaussian(float mean, float stdev) {
|
||||
|
||||
// Using Box-Mueller method from http://www.taygeta.com/random/gaussian.html
|
||||
// Modified to specify standard deviation and mean of distribution
|
||||
float w, x1, x2;
|
||||
|
||||
// Loop until w is less than 1 so that log(w) is negative
|
||||
do {
|
||||
x1 = uniform(-1.0, 1.0);
|
||||
x2 = uniform(-1.0, 1.0);
|
||||
|
||||
w = float(square(x1) + square(x2));
|
||||
} while (w > 1.0f);
|
||||
|
||||
// Transform to gassian distribution
|
||||
// Multiply by sigma (stdev ^ 2) and add mean.
|
||||
return x2 * (float)square(stdev) * sqrtf((-2.0f * logf(w) ) / w) + mean;
|
||||
}
|
||||
|
||||
|
||||
void Random::cosHemi(float& x, float& y, float& z) {
|
||||
const float e1 = uniform();
|
||||
const float e2 = uniform();
|
||||
|
||||
// Jensen's method
|
||||
const float sin_theta = sqrtf(1.0f - e1);
|
||||
const float cos_theta = sqrtf(e1);
|
||||
const float phi = 6.28318531f * e2;
|
||||
|
||||
x = cos(phi) * sin_theta;
|
||||
y = sin(phi) * sin_theta;
|
||||
z = cos_theta;
|
||||
|
||||
// We could also use Malley's method (pbrt p.657), since they are the same cost:
|
||||
//
|
||||
// r = sqrt(e1);
|
||||
// t = 2*pi*e2;
|
||||
// x = cos(t)*r;
|
||||
// y = sin(t)*r;
|
||||
// z = sqrt(1.0 - x*x + y*y);
|
||||
}
|
||||
|
||||
|
||||
void Random::cosPowHemi(const float k, float& x, float& y, float& z) {
|
||||
const float e1 = uniform();
|
||||
const float e2 = uniform();
|
||||
|
||||
const float cos_theta = pow(e1, 1.0f / (k + 1.0f));
|
||||
const float sin_theta = sqrtf(1.0f - square(cos_theta));
|
||||
const float phi = 6.28318531f * e2;
|
||||
|
||||
x = cos(phi) * sin_theta;
|
||||
y = sin(phi) * sin_theta;
|
||||
z = cos_theta;
|
||||
}
|
||||
|
||||
|
||||
void Random::hemi(float& x, float& y, float& z) {
|
||||
sphere(x, y, z);
|
||||
z = fabsf(z);
|
||||
}
|
||||
|
||||
|
||||
void Random::sphere(float& x, float& y, float& z) {
|
||||
// Squared magnitude
|
||||
float m2;
|
||||
|
||||
// Rejection sample
|
||||
do {
|
||||
x = uniform() * 2.0f - 1.0f,
|
||||
y = uniform() * 2.0f - 1.0f,
|
||||
z = uniform() * 2.0f - 1.0f;
|
||||
m2 = x*x + y*y + z*z;
|
||||
} while (m2 >= 1.0f);
|
||||
|
||||
// Divide by magnitude to produce a unit vector
|
||||
float s = rsqrt(m2);
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
}
|
||||
|
||||
} // G3D
|
||||
218
modules/acore/deps/g3dlite/source/Ray.cpp
Normal file
218
modules/acore/deps/g3dlite/source/Ray.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
@file Ray.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2002-07-12
|
||||
@edited 2004-03-19
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Ray.h"
|
||||
#include "G3D/Plane.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/CollisionDetection.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void Ray::set(const Vector3& origin, const Vector3& direction) {
|
||||
m_origin = origin;
|
||||
m_direction = direction;
|
||||
debugAssert(direction.isUnit());
|
||||
|
||||
m_invDirection = Vector3::one() / direction;
|
||||
|
||||
// ray slope
|
||||
ibyj = m_direction.x * m_invDirection.y;
|
||||
jbyi = m_direction.y * m_invDirection.x;
|
||||
jbyk = m_direction.y * m_invDirection.z;
|
||||
kbyj = m_direction.z * m_invDirection.y;
|
||||
ibyk = m_direction.x * m_invDirection.z;
|
||||
kbyi = m_direction.z * m_invDirection.x;
|
||||
|
||||
// precomputed terms
|
||||
c_xy = m_origin.y - jbyi * m_origin.x;
|
||||
c_xz = m_origin.z - kbyi * m_origin.x;
|
||||
c_yx = m_origin.x - ibyj * m_origin.y;
|
||||
c_yz = m_origin.z - kbyj * m_origin.y;
|
||||
c_zx = m_origin.x - ibyk * m_origin.z;
|
||||
c_zy = m_origin.y - jbyk * m_origin.z;
|
||||
|
||||
//ray slope classification
|
||||
if (m_direction.x < 0) {
|
||||
if (m_direction.y < 0) {
|
||||
if (m_direction.z < 0) {
|
||||
classification = MMM;
|
||||
} else if (m_direction.z > 0) {
|
||||
classification = MMP;
|
||||
} else { //(m_direction.z >= 0)
|
||||
classification = MMO;
|
||||
}
|
||||
} else { //(m_direction.y >= 0)
|
||||
if (m_direction.z < 0) {
|
||||
if (m_direction.y == 0) {
|
||||
classification = MOM;
|
||||
} else {
|
||||
classification = MPM;
|
||||
}
|
||||
} else { //(m_direction.z >= 0)
|
||||
if ((m_direction.y == 0) && (m_direction.z == 0)) {
|
||||
classification = MOO;
|
||||
} else if (m_direction.z == 0) {
|
||||
classification = MPO;
|
||||
} else if (m_direction.y == 0) {
|
||||
classification = MOP;
|
||||
} else {
|
||||
classification = MPP;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //(m_direction.x >= 0)
|
||||
if (m_direction.y < 0) {
|
||||
if (m_direction.z < 0) {
|
||||
if (m_direction.x == 0) {
|
||||
classification = OMM;
|
||||
} else {
|
||||
classification = PMM;
|
||||
}
|
||||
} else { //(m_direction.z >= 0)
|
||||
if ((m_direction.x == 0) && (m_direction.z == 0)) {
|
||||
classification = OMO;
|
||||
} else if (m_direction.z == 0) {
|
||||
classification = PMO;
|
||||
} else if (m_direction.x == 0) {
|
||||
classification = OMP;
|
||||
} else {
|
||||
classification = PMP;
|
||||
}
|
||||
}
|
||||
} else { //(m_direction.y >= 0)
|
||||
if (m_direction.z < 0) {
|
||||
if ((m_direction.x == 0) && (m_direction.y == 0)) {
|
||||
classification = OOM;
|
||||
} else if (m_direction.x == 0) {
|
||||
classification = OPM;
|
||||
} else if (m_direction.y == 0) {
|
||||
classification = POM;
|
||||
} else {
|
||||
classification = PPM;
|
||||
}
|
||||
} else { //(m_direction.z > 0)
|
||||
if (m_direction.x == 0) {
|
||||
if (m_direction.y == 0) {
|
||||
classification = OOP;
|
||||
} else if (m_direction.z == 0) {
|
||||
classification = OPO;
|
||||
} else {
|
||||
classification = OPP;
|
||||
}
|
||||
} else {
|
||||
if ((m_direction.y == 0) && (m_direction.z == 0)) {
|
||||
classification = POO;
|
||||
} else if (m_direction.y == 0) {
|
||||
classification = POP;
|
||||
} else if (m_direction.z == 0) {
|
||||
classification = PPO;
|
||||
} else {
|
||||
classification = PPP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ray::Ray(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Ray::serialize(class BinaryOutput& b) const {
|
||||
m_origin.serialize(b);
|
||||
m_direction.serialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Ray::deserialize(class BinaryInput& b) {
|
||||
m_origin.deserialize(b);
|
||||
m_direction.deserialize(b);
|
||||
set(m_origin, m_direction);
|
||||
}
|
||||
|
||||
|
||||
Ray Ray::refract(
|
||||
const Vector3& newOrigin,
|
||||
const Vector3& normal,
|
||||
float iInside,
|
||||
float iOutside) const {
|
||||
|
||||
Vector3 D = m_direction.refractionDirection(normal, iInside, iOutside);
|
||||
return Ray(newOrigin + (m_direction + normal * (float)sign(m_direction.dot(normal))) * 0.001f, D);
|
||||
}
|
||||
|
||||
|
||||
Ray Ray::reflect(
|
||||
const Vector3& newOrigin,
|
||||
const Vector3& normal) const {
|
||||
|
||||
Vector3 D = m_direction.reflectionDirection(normal);
|
||||
return Ray(newOrigin + (D + normal) * 0.001f, D);
|
||||
}
|
||||
|
||||
|
||||
Vector3 Ray::intersection(const Plane& plane) const {
|
||||
float d;
|
||||
Vector3 normal = plane.normal();
|
||||
plane.getEquation(normal, d);
|
||||
float rate = m_direction.dot(normal);
|
||||
|
||||
if (rate >= 0.0f) {
|
||||
return Vector3::inf();
|
||||
} else {
|
||||
float t = -(d + m_origin.dot(normal)) / rate;
|
||||
return m_origin + m_direction * t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float Ray::intersectionTime(const class Sphere& sphere, bool solid) const {
|
||||
Vector3 dummy;
|
||||
return CollisionDetection::collisionTimeForMovingPointFixedSphere(
|
||||
m_origin, m_direction, sphere, dummy, dummy, solid);
|
||||
}
|
||||
|
||||
|
||||
float Ray::intersectionTime(const class Plane& plane) const {
|
||||
Vector3 dummy;
|
||||
return CollisionDetection::collisionTimeForMovingPointFixedPlane(
|
||||
m_origin, m_direction, plane, dummy);
|
||||
}
|
||||
|
||||
|
||||
float Ray::intersectionTime(const class Box& box) const {
|
||||
Vector3 dummy;
|
||||
float time = CollisionDetection::collisionTimeForMovingPointFixedBox(
|
||||
m_origin, m_direction, box, dummy);
|
||||
|
||||
if ((time == finf()) && (box.contains(m_origin))) {
|
||||
return 0.0f;
|
||||
} else {
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float Ray::intersectionTime(const class AABox& box) const {
|
||||
Vector3 dummy;
|
||||
bool inside;
|
||||
float time = CollisionDetection::collisionTimeForMovingPointFixedAABox(
|
||||
m_origin, m_direction, box, dummy, inside);
|
||||
|
||||
if ((time == finf()) && inside) {
|
||||
return 0.0f;
|
||||
} else {
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
41
modules/acore/deps/g3dlite/source/Rect2D.cpp
Normal file
41
modules/acore/deps/g3dlite/source/Rect2D.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
@file Rect2D.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-11-13
|
||||
@created 2009-11-16
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Rect2D.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
/** \param any Must either Rect2D::xywh(#, #, #, #) or Rect2D::xyxy(#, #, #, #)*/
|
||||
Rect2D::Rect2D(const Any& any) {
|
||||
any.verifyName("Rect2D");
|
||||
any.verifyType(Any::ARRAY);
|
||||
any.verifySize(4);
|
||||
if (toUpper(any.name()) == "RECT2D::XYWH") {
|
||||
*this = Rect2D::xywh(any[0], any[1], any[2], any[3]);
|
||||
} else {
|
||||
any.verifyName("Rect2D::xyxy");
|
||||
*this = Rect2D::xyxy(any[0], any[1], any[2], any[3]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Converts the Rect2D to an Any. */
|
||||
Rect2D::operator Any() const {
|
||||
Any any(Any::ARRAY, "Rect2D::xywh");
|
||||
any.append(x0(), y0(), width(), height());
|
||||
return any;
|
||||
}
|
||||
|
||||
}
|
||||
61
modules/acore/deps/g3dlite/source/ReferenceCount.cpp
Normal file
61
modules/acore/deps/g3dlite/source/ReferenceCount.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
@file ReferenceCount.cpp
|
||||
|
||||
Reference Counting Garbage Collector for C++
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@cite Adapted and extended from Justin Miller's "RGC" class that appeared in BYTE magazine.
|
||||
@cite See also http://www.jelovic.com/articles/cpp_without_memory_errors_slides.htm
|
||||
|
||||
@created 2001-10-23
|
||||
@edited 2009-04-25
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/ReferenceCount.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
ReferenceCountedObject::ReferenceCountedObject() :
|
||||
ReferenceCountedObject_refCount(0),
|
||||
ReferenceCountedObject_weakPointer(0) {
|
||||
|
||||
debugAssertM(isValidHeapPointer(this),
|
||||
"Reference counted objects must be allocated on the heap.");
|
||||
}
|
||||
|
||||
void ReferenceCountedObject::ReferenceCountedObject_zeroWeakPointers() {
|
||||
// Tell all of my weak pointers that I'm gone.
|
||||
|
||||
_WeakPtrLinkedList* node = ReferenceCountedObject_weakPointer;
|
||||
|
||||
while (node != NULL) {
|
||||
// Notify the weak pointer that it is going away
|
||||
node->weakPtr->objectCollected();
|
||||
|
||||
// Free the node and advance
|
||||
_WeakPtrLinkedList* tmp = node;
|
||||
node = node->next;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
ReferenceCountedObject::~ReferenceCountedObject() {}
|
||||
|
||||
|
||||
ReferenceCountedObject::ReferenceCountedObject(const ReferenceCountedObject& notUsed) :
|
||||
ReferenceCountedObject_refCount(0),
|
||||
ReferenceCountedObject_weakPointer(0) {
|
||||
(void)notUsed;
|
||||
debugAssertM(G3D::isValidHeapPointer(this),
|
||||
"Reference counted objects must be allocated on the heap.");
|
||||
}
|
||||
|
||||
ReferenceCountedObject& ReferenceCountedObject::operator=(const ReferenceCountedObject& other) {
|
||||
(void)other;
|
||||
// Nothing changes when I am assigned; the reference count on
|
||||
// both objects is the same (although my super-class probably
|
||||
// changes).
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // G3D
|
||||
299
modules/acore/deps/g3dlite/source/RegistryUtil.cpp
Normal file
299
modules/acore/deps/g3dlite/source/RegistryUtil.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
@file RegistryUtil.cpp
|
||||
|
||||
@created 2006-04-06
|
||||
@edited 2006-04-24
|
||||
|
||||
Copyright 2000-2006, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
|
||||
// This file is only used on Windows
|
||||
#ifdef G3D_WIN32
|
||||
|
||||
#include "G3D/RegistryUtil.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
#ifdef __MINGW32__
|
||||
# ifndef HKEY_PERFORMANCE_TEXT
|
||||
# define HKEY_PERFORMANCE_TEXT ((HKEY)((LONG)0x80000050))
|
||||
# endif
|
||||
# ifndef HKEY_PERFORMANCE_NLSTEXT
|
||||
# define HKEY_PERFORMANCE_NLSTEXT ((HKEY)((LONG)0x80000060))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace G3D {
|
||||
|
||||
// static helpers
|
||||
static HKEY getRootKeyFromString(const char* str, size_t length);
|
||||
|
||||
|
||||
bool RegistryUtil::keyExists(const std::string& key) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
|
||||
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
RegCloseKey(openKey);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RegistryUtil::valueExists(const std::string& key, const std::string& value) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if ( hkey == NULL ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
uint32 dataSize = 0;
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, NULL, reinterpret_cast<LPDWORD>(&dataSize));
|
||||
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
bool RegistryUtil::readInt32(const std::string& key, const std::string& value, int32& data) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if ( hkey == NULL ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
uint32 dataSize = sizeof(int32);
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(&data), reinterpret_cast<LPDWORD>(&dataSize));
|
||||
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
|
||||
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegistryUtil::readBytes(const std::string& key, const std::string& value, uint8* data, uint32& dataSize) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
if (data == NULL) {
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, NULL, reinterpret_cast<LPDWORD>(&dataSize));
|
||||
} else {
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(&data), reinterpret_cast<LPDWORD>(&dataSize));
|
||||
}
|
||||
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
|
||||
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegistryUtil::readString(const std::string& key, const std::string& value, std::string& data) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
uint32 dataSize = 0;
|
||||
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, NULL, reinterpret_cast<LPDWORD>(&dataSize));
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
|
||||
|
||||
// increment datasize to allow for non null-terminated strings in registry
|
||||
dataSize += 1;
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
char* tmpStr = static_cast<char*>(System::malloc(dataSize));
|
||||
System::memset(tmpStr, 0, dataSize);
|
||||
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(tmpStr), reinterpret_cast<LPDWORD>(&dataSize));
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
data = tmpStr;
|
||||
}
|
||||
|
||||
RegCloseKey(openKey);
|
||||
System::free(tmpStr);
|
||||
}
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegistryUtil::writeInt32(const std::string& key, const std::string& value, int32 data) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_WRITE, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
result = RegSetValueExA(openKey, value.c_str(), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&data), sizeof(int32));
|
||||
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not write registry key value.");
|
||||
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegistryUtil::writeBytes(const std::string& key, const std::string& value, const uint8* data, uint32 dataSize) {
|
||||
debugAssert(data);
|
||||
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_WRITE, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
if (data) {
|
||||
result = RegSetValueExA(openKey, value.c_str(), 0, REG_BINARY, reinterpret_cast<const BYTE*>(data), dataSize);
|
||||
}
|
||||
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not write registry key value.");
|
||||
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegistryUtil::writeString(const std::string& key, const std::string& value, const std::string& data) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_WRITE, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
result = RegSetValueExA(openKey, value.c_str(), 0, REG_SZ, reinterpret_cast<const BYTE*>(data.c_str()), (data.size() + 1));
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not write registry key value.");
|
||||
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
// static helpers
|
||||
static HKEY getRootKeyFromString(const char* str, size_t length) {
|
||||
debugAssert(str);
|
||||
|
||||
if (str) {
|
||||
if ( strncmp(str, "HKEY_CLASSES_ROOT", length) == 0 ) {
|
||||
return HKEY_CLASSES_ROOT;
|
||||
} else if ( strncmp(str, "HKEY_CURRENT_CONFIG", length) == 0 ) {
|
||||
return HKEY_CURRENT_CONFIG;
|
||||
} else if ( strncmp(str, "HKEY_CURRENT_USER", length) == 0 ) {
|
||||
return HKEY_CURRENT_USER;
|
||||
} else if ( strncmp(str, "HKEY_LOCAL_MACHINE", length) == 0 ) {
|
||||
return HKEY_LOCAL_MACHINE;
|
||||
} else if ( strncmp(str, "HKEY_PERFORMANCE_DATA", length) == 0 ) {
|
||||
return HKEY_PERFORMANCE_DATA;
|
||||
} else if ( strncmp(str, "HKEY_PERFORMANCE_NLSTEXT", length) == 0 ) {
|
||||
return HKEY_PERFORMANCE_NLSTEXT;
|
||||
} else if ( strncmp(str, "HKEY_PERFORMANCE_TEXT", length) == 0 ) {
|
||||
return HKEY_PERFORMANCE_TEXT;
|
||||
} else if ( strncmp(str, "HKEY_CLASSES_ROOT", length) == 0 ) {
|
||||
return HKEY_CLASSES_ROOT;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
#endif // G3D_WIN32
|
||||
223
modules/acore/deps/g3dlite/source/Sphere.cpp
Normal file
223
modules/acore/deps/g3dlite/source/Sphere.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
@file Sphere.cpp
|
||||
|
||||
Sphere class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-04-17
|
||||
@edited 2009-01-20
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/AABox.h"
|
||||
#include "G3D/Plane.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
int32 Sphere::dummy;
|
||||
|
||||
Sphere::Sphere(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Sphere::serialize(class BinaryOutput& b) const {
|
||||
center.serialize(b);
|
||||
b.writeFloat64(radius);
|
||||
}
|
||||
|
||||
|
||||
void Sphere::deserialize(class BinaryInput& b) {
|
||||
center.deserialize(b);
|
||||
radius = (float)b.readFloat64();
|
||||
}
|
||||
|
||||
|
||||
std::string Sphere::toString() const {
|
||||
return format("Sphere(<%g, %g, %g>, %g)",
|
||||
center.x, center.y, center.z, radius);
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::contains(const Vector3& point) const {
|
||||
float distance = (center - point).squaredMagnitude();
|
||||
return distance <= square(radius);
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::contains(const Sphere& other) const {
|
||||
float distance = (center - other.center).squaredMagnitude();
|
||||
return (radius >= other.radius) && (distance <= square(radius - other.radius));
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::intersects(const Sphere& other) const {
|
||||
return (other.center - center).length() <= (radius + other.radius);
|
||||
}
|
||||
|
||||
|
||||
void Sphere::merge(const Sphere& other) {
|
||||
if (other.contains(*this)) {
|
||||
*this = other;
|
||||
} else if (! contains(other)) {
|
||||
// The farthest distance is along the axis between the centers, which
|
||||
// must not be colocated since neither contains the other.
|
||||
Vector3 toMe = center - other.center;
|
||||
// Get a point on the axis from each
|
||||
toMe = toMe.direction();
|
||||
const Vector3& A = center + toMe * radius;
|
||||
const Vector3& B = other.center - toMe * other.radius;
|
||||
|
||||
// Now just bound the A->B segment
|
||||
center = (A + B) * 0.5f;
|
||||
radius = (A - B).length();
|
||||
}
|
||||
// (if this contains other, we're done)
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlaneIndex,
|
||||
const uint32 inMask,
|
||||
uint32& outMask) const {
|
||||
|
||||
return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask, outMask);
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlaneIndex,
|
||||
const uint32 inMask) const {
|
||||
|
||||
return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask);
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::culledBy(
|
||||
const class Plane* plane,
|
||||
int numPlanes,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask,
|
||||
uint32& childMask) const {
|
||||
|
||||
if (radius == finf()) {
|
||||
// No plane can cull the infinite box
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(numPlanes < 31);
|
||||
|
||||
childMask = 0;
|
||||
|
||||
// See if there is one plane for which all of the
|
||||
// vertices are in the negative half space.
|
||||
for (int p = 0; p < numPlanes; p++) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
|
||||
bool culledLow = ! plane[p].halfSpaceContainsFinite(center + plane[p].normal() * radius);
|
||||
bool culledHigh = ! plane[p].halfSpaceContainsFinite(center - plane[p].normal() * radius);
|
||||
|
||||
if (culledLow) {
|
||||
// Plane p culled the sphere
|
||||
cullingPlane = p;
|
||||
|
||||
// The caller should not recurse into the children,
|
||||
// since the parent is culled. If they do recurse,
|
||||
// make them only test against this one plane, which
|
||||
// will immediately cull the volume.
|
||||
childMask = 1 << p;
|
||||
return true;
|
||||
|
||||
} else if (culledHigh) {
|
||||
// The bounding volume straddled the plane; we have
|
||||
// to keep testing against this plane
|
||||
childMask |= (1 << p);
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next bit.
|
||||
inMask = inMask >> 1;
|
||||
}
|
||||
|
||||
// None of the planes could cull this box
|
||||
cullingPlane = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::culledBy(
|
||||
const class Plane* plane,
|
||||
int numPlanes,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask) const {
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(numPlanes < 31);
|
||||
|
||||
// See if there is one plane for which all of the
|
||||
// vertices are in the negative half space.
|
||||
for (int p = 0; p < numPlanes; p++) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
bool culled = ! plane[p].halfSpaceContains(center + plane[p].normal() * radius);
|
||||
if (culled) {
|
||||
// Plane p culled the sphere
|
||||
cullingPlane = p;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next bit.
|
||||
inMask = inMask >> 1;
|
||||
}
|
||||
|
||||
// None of the planes could cull this box
|
||||
cullingPlane = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Sphere::randomSurfacePoint() const {
|
||||
return Vector3::random() * radius + center;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Sphere::randomInteriorPoint() const {
|
||||
Vector3 result;
|
||||
do {
|
||||
result = Vector3(uniformRandom(-1, 1),
|
||||
uniformRandom(-1, 1),
|
||||
uniformRandom(-1, 1));
|
||||
} while (result.squaredMagnitude() >= 1.0f);
|
||||
|
||||
return result * radius + center;
|
||||
}
|
||||
|
||||
|
||||
float Sphere::volume() const {
|
||||
return (float)pi() * (4.0f / 3.0f) * powf((float)radius, 3.0f);
|
||||
}
|
||||
|
||||
|
||||
float Sphere::area() const {
|
||||
return (float)pi() * 4.0f * powf((float)radius, 2.0f);
|
||||
}
|
||||
|
||||
|
||||
void Sphere::getBounds(AABox& out) const {
|
||||
Vector3 extent(radius, radius, radius);
|
||||
out = AABox(center - extent, center + extent);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
162
modules/acore/deps/g3dlite/source/SplineBase.cpp
Normal file
162
modules/acore/deps/g3dlite/source/SplineBase.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Spline.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
float SplineBase::getFinalInterval() const {
|
||||
if (! cyclic) {
|
||||
return 0;
|
||||
} else if (finalInterval <= 0) {
|
||||
int N = time.size();
|
||||
if (N >= 2) {
|
||||
return (time[1] - time[0] + time[N - 1] - time[N - 2]) * 0.5f;
|
||||
} else {
|
||||
return 1.0f;
|
||||
}
|
||||
} else {
|
||||
return finalInterval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Matrix4 SplineBase::computeBasis() {
|
||||
// The standard Catmull-Rom spline basis (e.g., Watt & Watt p108)
|
||||
// is for [u^3 u^2 u^1 u^0] * B * [p[0] p[1] p[2] p[3]]^T.
|
||||
// We need a basis formed for:
|
||||
//
|
||||
// U * C * [2*p'[1] p[1] p[2] 2*p'[2]]^T
|
||||
//
|
||||
// U * C * [p2-p0 p1 p2 p3-p1]^T
|
||||
//
|
||||
// To make this transformation, compute the differences of columns in C:
|
||||
// For [p0 p1 p2 p3]
|
||||
Matrix4 basis =
|
||||
Matrix4( -1, 3, -3, 1,
|
||||
2, -5, 4, -1,
|
||||
-1, 0, 1, 0,
|
||||
0, 2, 0, 0) * 0.5f;
|
||||
|
||||
// For [-p0 p1 p2 p3]^T
|
||||
basis.setColumn(0, -basis.column(0));
|
||||
|
||||
// For [-p0 p1 p2 p3-p1]^T
|
||||
basis.setColumn(1, basis.column(1) + basis.column(3));
|
||||
|
||||
// For [p2-p0 p1 p2 p3-p1]^T
|
||||
basis.setColumn(2, basis.column(2) - basis.column(0));
|
||||
|
||||
return basis;
|
||||
}
|
||||
|
||||
|
||||
float SplineBase::duration() const {
|
||||
if (time.size() == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return time.last() - time[0] + getFinalInterval();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SplineBase::computeIndexInBounds(float s, int& i, float& u) const {
|
||||
int N = time.size();
|
||||
float t0 = time[0];
|
||||
float tn = time[N - 1];
|
||||
|
||||
i = iFloor((N - 1) * (s - t0) / (tn - t0));
|
||||
|
||||
// Inclusive bounds for binary search
|
||||
int hi = N - 1;
|
||||
int lo = 0;
|
||||
|
||||
while ((time[i] > s) || (time[i + 1] <= s)) {
|
||||
|
||||
if (time[i] > s) {
|
||||
// too big
|
||||
hi = i - 1;
|
||||
} else if (time[i + 1] <= s) {
|
||||
// too small
|
||||
lo = i + 1;
|
||||
}
|
||||
|
||||
i = (hi + lo) / 2;
|
||||
}
|
||||
|
||||
// Having exited the above loop, i must be correct, so compute u.
|
||||
u = (s - time[i]) / (time[i + 1] - time[i]);
|
||||
}
|
||||
|
||||
|
||||
void SplineBase::computeIndex(float s, int& i, float& u) const {
|
||||
int N = time.size();
|
||||
debugAssertM(N > 0, "No control points");
|
||||
float t0 = time[0];
|
||||
float tn = time[N - 1];
|
||||
|
||||
if (N < 2) {
|
||||
// No control points to work with
|
||||
i = 0;
|
||||
u = 0.0;
|
||||
} else if (cyclic) {
|
||||
float fi = getFinalInterval();
|
||||
|
||||
// Cyclic spline
|
||||
if ((s < t0) || (s >= tn + fi)) {
|
||||
// Cyclic, off the bottom or top
|
||||
|
||||
// Compute offset and reduce to the in-bounds case
|
||||
|
||||
float d = duration();
|
||||
// Number of times we wrapped around the cyclic array
|
||||
int wraps = iFloor((s - t0) / d);
|
||||
|
||||
debugAssert(s - d * wraps >= t0);
|
||||
debugAssert(s - d * wraps < tn + getFinalInterval());
|
||||
|
||||
computeIndex(s - d * wraps, i, u);
|
||||
i += wraps * N;
|
||||
|
||||
} else if (s >= tn) {
|
||||
debugAssert(s < tn + fi);
|
||||
// Cyclic, off the top but before the end of the last interval
|
||||
i = N - 1;
|
||||
u = (s - tn) / fi;
|
||||
|
||||
} else {
|
||||
// Cyclic, in bounds
|
||||
computeIndexInBounds(s, i, u);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Non-cyclic
|
||||
|
||||
if (s < t0) {
|
||||
// Non-cyclic, off the bottom. Assume points are spaced
|
||||
// following the first time interval.
|
||||
|
||||
float dt = time[1] - t0;
|
||||
float x = (s - t0) / dt;
|
||||
i = iFloor(x);
|
||||
u = x - i;
|
||||
|
||||
} else if (s >= tn) {
|
||||
// Non-cyclic, off the top. Assume points are spaced following
|
||||
// the last time interval.
|
||||
|
||||
float dt = tn - time[N - 2];
|
||||
float x = N - 1 + (s - tn) / dt;
|
||||
i = iFloor(x);
|
||||
u = x - i;
|
||||
|
||||
} else {
|
||||
// In bounds, non-cyclic. Assume a regular
|
||||
// distribution (which gives O(1) for uniform spacing)
|
||||
// and then binary search to handle the general case
|
||||
// efficiently.
|
||||
computeIndexInBounds(s, i, u);
|
||||
|
||||
} // if in bounds
|
||||
} // if cyclic
|
||||
}
|
||||
|
||||
}
|
||||
119
modules/acore/deps/g3dlite/source/Stopwatch.cpp
Normal file
119
modules/acore/deps/g3dlite/source/Stopwatch.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
@file Stopwatch.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2005-10-05
|
||||
@edited 2009-03-14
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/Stopwatch.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Stopwatch::Stopwatch(const std::string& myName) :
|
||||
myName(myName),
|
||||
inBetween(false), lastTockTime(-1),
|
||||
lastDuration(0), lastCycleCount(0), m_fps(0), emwaFPS(0),
|
||||
m_smoothFPS(0), emwaDuration(0) {
|
||||
computeOverhead();
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
void Stopwatch::computeOverhead() {
|
||||
cycleOverhead = 0;
|
||||
tick();
|
||||
tock();
|
||||
cycleOverhead = elapsedCycles();
|
||||
}
|
||||
|
||||
|
||||
void Stopwatch::tick() {
|
||||
// This is 'alwaysAssert' instead of 'debugAssert'
|
||||
// since people rarely profile in debug mode.
|
||||
alwaysAssertM(! inBetween, "Stopwatch::tick() called twice in a row.");
|
||||
inBetween = true;
|
||||
|
||||
// We read RDTSC twice here, but it is more abstract to implement this
|
||||
// way and at least we're reading the cycle count last.
|
||||
timeStart = System::time();
|
||||
System::beginCycleCount(cycleStart);
|
||||
}
|
||||
|
||||
|
||||
void Stopwatch::tock() {
|
||||
System::endCycleCount(cycleStart);
|
||||
RealTime now = System::time();
|
||||
lastDuration = now - timeStart;
|
||||
if (abs(emwaDuration - lastDuration) > max(emwaDuration, lastDuration) * 0.50) {
|
||||
// Off by more than 50%
|
||||
emwaDuration = lastDuration;
|
||||
} else {
|
||||
emwaDuration = lastDuration * 0.05 + emwaDuration * 0.95;
|
||||
}
|
||||
|
||||
lastCycleCount = cycleStart - cycleOverhead;
|
||||
if (lastCycleCount < 0) {
|
||||
lastCycleCount = 0;
|
||||
}
|
||||
|
||||
if (lastTockTime != -1.0) {
|
||||
m_fps = 1.0 / (now - lastTockTime);
|
||||
|
||||
const double blend = 0.01;
|
||||
emwaFPS = m_fps * blend + emwaFPS * (1.0 - blend);
|
||||
|
||||
double maxDiscrepancyPercentage = 0.25;
|
||||
if (abs(emwaFPS - m_fps) > max(emwaFPS, m_fps) * maxDiscrepancyPercentage) {
|
||||
// The difference between emwa and m_fps is way off, so
|
||||
// update emwa directly.
|
||||
emwaFPS = m_fps * 0.20 + emwaFPS * 0.80;
|
||||
}
|
||||
|
||||
// Update m_smoothFPS only when the value varies significantly.
|
||||
// We round so as to not mislead the user as to the accuracy of
|
||||
// the number.
|
||||
if (m_smoothFPS == 0) {
|
||||
m_smoothFPS = m_fps;
|
||||
} else if (emwaFPS <= 20) {
|
||||
if (::fabs(m_smoothFPS - emwaFPS) > 0.75) {
|
||||
// Small number and display is off by more than 0.75; round to the nearest 0.1
|
||||
m_smoothFPS = floor(emwaFPS * 10.0 + 0.5) / 10.0;
|
||||
}
|
||||
} else if (::fabs(m_smoothFPS - emwaFPS) > 1.25) {
|
||||
// Large number and display is off by more than 1.25; round to the nearest 1.0
|
||||
m_smoothFPS = floor(emwaFPS + 0.5);
|
||||
}
|
||||
}
|
||||
lastTockTime = now;
|
||||
|
||||
alwaysAssertM(inBetween, "Stopwatch::tock() called without matching tick.");
|
||||
inBetween = false;
|
||||
}
|
||||
|
||||
|
||||
void Stopwatch::reset() {
|
||||
prevTime = startTime = System::time();
|
||||
prevMark = "start";
|
||||
}
|
||||
|
||||
|
||||
void Stopwatch::after(const std::string& s) {
|
||||
RealTime now = System::time();
|
||||
debugPrintf("%s: %10s - %8fs since %s (%fs since start)\n",
|
||||
myName.c_str(),
|
||||
s.c_str(),
|
||||
now - prevTime,
|
||||
prevMark.c_str(),
|
||||
now - startTime);
|
||||
prevTime = now;
|
||||
prevMark = s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
1765
modules/acore/deps/g3dlite/source/System.cpp
Normal file
1765
modules/acore/deps/g3dlite/source/System.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1222
modules/acore/deps/g3dlite/source/TextInput.cpp
Normal file
1222
modules/acore/deps/g3dlite/source/TextInput.cpp
Normal file
File diff suppressed because it is too large
Load Diff
453
modules/acore/deps/g3dlite/source/TextOutput.cpp
Normal file
453
modules/acore/deps/g3dlite/source/TextOutput.cpp
Normal file
@@ -0,0 +1,453 @@
|
||||
/**
|
||||
@file TextOutput.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2004-06-21
|
||||
@edited 2010-03-14
|
||||
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/Log.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
TextOutput::TextOutput(const TextOutput::Settings& opt) :
|
||||
startingNewLine(true),
|
||||
currentColumn(0),
|
||||
inDQuote(false),
|
||||
filename(""),
|
||||
indentLevel(0)
|
||||
{
|
||||
setOptions(opt);
|
||||
}
|
||||
|
||||
|
||||
TextOutput::TextOutput(const std::string& fil, const TextOutput::Settings& opt) :
|
||||
startingNewLine(true),
|
||||
currentColumn(0),
|
||||
inDQuote(false),
|
||||
filename(fil),
|
||||
indentLevel(0)
|
||||
{
|
||||
|
||||
setOptions(opt);
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::setIndentLevel(int i) {
|
||||
indentLevel = i;
|
||||
|
||||
// If there were more pops than pushes, don't let that take us below 0 indent.
|
||||
// Don't ever indent more than the number of columns.
|
||||
indentSpaces =
|
||||
iClamp(option.spacesPerIndent * indentLevel,
|
||||
0,
|
||||
option.numColumns - 1);
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::setOptions(const Settings& _opt) {
|
||||
option = _opt;
|
||||
|
||||
debugAssert(option.numColumns > 1);
|
||||
|
||||
setIndentLevel(indentLevel);
|
||||
|
||||
newline = (option.newlineStyle == Settings::NEWLINE_WINDOWS) ? "\r\n" : "\n";
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::pushIndent() {
|
||||
setIndentLevel(indentLevel + 1);
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::popIndent() {
|
||||
setIndentLevel(indentLevel - 1);
|
||||
}
|
||||
|
||||
|
||||
static std::string escape(const std::string& string) {
|
||||
std::string result = "";
|
||||
|
||||
for (std::string::size_type i = 0; i < string.length(); ++i) {
|
||||
char c = string.at(i);
|
||||
switch (c) {
|
||||
case '\0':
|
||||
result += "\\0";
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
result += "\\r";
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
result += "\\n";
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
result += "\\t";
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
result += "\\\\";
|
||||
break;
|
||||
|
||||
default:
|
||||
result += c;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextOutput::writeString(const std::string& string) {
|
||||
// Convert special characters to escape sequences
|
||||
this->printf("\"%s\"", escape(string).c_str());
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::writeBoolean(bool b) {
|
||||
this->printf("%s ", b ? option.trueSymbol.c_str() : option.falseSymbol.c_str());
|
||||
}
|
||||
|
||||
void TextOutput::writeNumber(double n) {
|
||||
this->printf("%f ", n);
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::writeNumber(int n) {
|
||||
this->printf("%d ", n);
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::writeSymbol(const std::string& string) {
|
||||
if (string.size() > 0) {
|
||||
// TODO: check for legal symbols?
|
||||
this->printf("%s ", string.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void TextOutput::writeSymbols(
|
||||
const std::string& a,
|
||||
const std::string& b,
|
||||
const std::string& c,
|
||||
const std::string& d,
|
||||
const std::string& e,
|
||||
const std::string& f) {
|
||||
|
||||
writeSymbol(a);
|
||||
writeSymbol(b);
|
||||
writeSymbol(c);
|
||||
writeSymbol(d);
|
||||
writeSymbol(e);
|
||||
writeSymbol(f);
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::printf(const std::string formatString, ...) {
|
||||
va_list argList;
|
||||
va_start(argList, formatString);
|
||||
this->vprintf(formatString.c_str(), argList);
|
||||
va_end(argList);
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::printf(const char* formatString, ...) {
|
||||
va_list argList;
|
||||
va_start(argList, formatString);
|
||||
this->vprintf(formatString, argList);
|
||||
va_end(argList);
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::convertNewlines(const std::string& in, std::string& out) {
|
||||
// TODO: can be significantly optimized in cases where
|
||||
// single characters are copied in order by walking through
|
||||
// the array and copying substrings as needed.
|
||||
|
||||
if (option.convertNewlines) {
|
||||
out = "";
|
||||
for (uint32 i = 0; i < in.size(); ++i) {
|
||||
if (in[i] == '\n') {
|
||||
// Unix newline
|
||||
out += newline;
|
||||
} else if ((in[i] == '\r') && (i + 1 < in.size()) && (in[i + 1] == '\n')) {
|
||||
// Windows newline
|
||||
out += newline;
|
||||
++i;
|
||||
} else {
|
||||
out += in[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out = in;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::writeNewline() {
|
||||
for (uint32 i = 0; i < newline.size(); ++i) {
|
||||
indentAppend(newline[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::writeNewlines(int numLines) {
|
||||
for (int i = 0; i < numLines; ++i) {
|
||||
writeNewline();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::wordWrapIndentAppend(const std::string& str) {
|
||||
// TODO: keep track of the last space character we saw so we don't
|
||||
// have to always search.
|
||||
|
||||
if ((option.wordWrap == Settings::WRAP_NONE) ||
|
||||
(currentColumn + (int)str.size() <= option.numColumns)) {
|
||||
// No word-wrapping is needed
|
||||
|
||||
// Add one character at a time.
|
||||
// TODO: optimize for strings without newlines to add multiple
|
||||
// characters.
|
||||
for (uint32 i = 0; i < str.size(); ++i) {
|
||||
indentAppend(str[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Number of columns to wrap against
|
||||
int cols = option.numColumns - indentSpaces;
|
||||
|
||||
// Copy forward until we exceed the column size,
|
||||
// and then back up and try to insert newlines as needed.
|
||||
for (uint32 i = 0; i < str.size(); ++i) {
|
||||
|
||||
indentAppend(str[i]);
|
||||
if ((str[i] == '\r') && (i + 1 < str.size()) && (str[i + 1] == '\n')) {
|
||||
// \r\n, we need to hit the \n to enter word wrapping.
|
||||
++i;
|
||||
indentAppend(str[i]);
|
||||
}
|
||||
|
||||
if (currentColumn >= cols) {
|
||||
debugAssertM(str[i] != '\n' && str[i] != '\r',
|
||||
"Should never enter word-wrapping on a newline character");
|
||||
|
||||
// True when we're allowed to treat a space as a space.
|
||||
bool unquotedSpace = option.allowWordWrapInsideDoubleQuotes || ! inDQuote;
|
||||
|
||||
// Cases:
|
||||
//
|
||||
// 1. Currently in a series of spaces that ends with a newline
|
||||
// strip all spaces and let the newline
|
||||
// flow through.
|
||||
//
|
||||
// 2. Currently in a series of spaces that does not end with a newline
|
||||
// strip all spaces and replace them with single newline
|
||||
//
|
||||
// 3. Not in a series of spaces
|
||||
// search backwards for a space, then execute case 2.
|
||||
|
||||
// Index of most recent space
|
||||
uint32 lastSpace = data.size() - 1;
|
||||
|
||||
// How far back we had to look for a space
|
||||
uint32 k = 0;
|
||||
uint32 maxLookBackward = currentColumn - indentSpaces;
|
||||
|
||||
// Search backwards (from current character), looking for a space.
|
||||
while ((k < maxLookBackward) &&
|
||||
(lastSpace > 0) &&
|
||||
(! ((data[lastSpace] == ' ') && unquotedSpace))) {
|
||||
--lastSpace;
|
||||
++k;
|
||||
|
||||
if ((data[lastSpace] == '\"') && !option.allowWordWrapInsideDoubleQuotes) {
|
||||
unquotedSpace = ! unquotedSpace;
|
||||
}
|
||||
}
|
||||
|
||||
if (k == maxLookBackward) {
|
||||
// We couldn't find a series of spaces
|
||||
|
||||
if (option.wordWrap == Settings::WRAP_ALWAYS) {
|
||||
// Strip the last character we wrote, force a newline,
|
||||
// and replace the last character;
|
||||
data.pop();
|
||||
writeNewline();
|
||||
indentAppend(str[i]);
|
||||
} else {
|
||||
// Must be Settings::WRAP_WITHOUT_BREAKING
|
||||
//
|
||||
// Don't write the newline; we'll come back to
|
||||
// the word wrap code after writing another character
|
||||
}
|
||||
} else {
|
||||
// We found a series of spaces. If they continue
|
||||
// to the new string, strip spaces off both. Otherwise
|
||||
// strip spaces from data only and insert a newline.
|
||||
|
||||
// Find the start of the spaces. firstSpace is the index of the
|
||||
// first non-space, looking backwards from lastSpace.
|
||||
uint32 firstSpace = lastSpace;
|
||||
while ((k < maxLookBackward) &&
|
||||
(firstSpace > 0) &&
|
||||
(data[firstSpace] == ' ')) {
|
||||
--firstSpace;
|
||||
++k;
|
||||
}
|
||||
|
||||
if (k == maxLookBackward) {
|
||||
++firstSpace;
|
||||
}
|
||||
|
||||
if (lastSpace == (uint32)data.size() - 1) {
|
||||
// Spaces continued up to the new string
|
||||
data.resize(firstSpace + 1);
|
||||
writeNewline();
|
||||
|
||||
// Delete the spaces from the new string
|
||||
while ((i < str.size() - 1) && (str[i + 1] == ' ')) {
|
||||
++i;
|
||||
}
|
||||
} else {
|
||||
// Spaces were somewhere in the middle of the old string.
|
||||
// replace them with a newline.
|
||||
|
||||
// Copy over the characters that should be saved
|
||||
Array<char> temp;
|
||||
for (uint32 j = lastSpace + 1; j < (uint32)data.size(); ++j) {
|
||||
char c = data[j];
|
||||
|
||||
if (c == '\"') {
|
||||
// Undo changes to quoting (they will be re-done
|
||||
// when we paste these characters back on).
|
||||
inDQuote = !inDQuote;
|
||||
}
|
||||
temp.append(c);
|
||||
}
|
||||
|
||||
// Remove those characters and replace with a newline.
|
||||
data.resize(firstSpace + 1);
|
||||
writeNewline();
|
||||
|
||||
// Write them back
|
||||
for (uint32 j = 0; j < (uint32)temp.size(); ++j) {
|
||||
indentAppend(temp[j]);
|
||||
}
|
||||
|
||||
// We are now free to continue adding from the
|
||||
// new string, which may or may not begin with spaces.
|
||||
|
||||
} // if spaces included new string
|
||||
} // if hit indent
|
||||
} // if line exceeded
|
||||
} // iterate over str
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::indentAppend(char c) {
|
||||
|
||||
if (startingNewLine) {
|
||||
for (int j = 0; j < indentSpaces; ++j) {
|
||||
data.push(' ');
|
||||
}
|
||||
startingNewLine = false;
|
||||
currentColumn = indentSpaces;
|
||||
}
|
||||
|
||||
data.push(c);
|
||||
|
||||
// Don't increment the column count on return character
|
||||
// newline is taken care of below.
|
||||
if (c != '\r') {
|
||||
++currentColumn;
|
||||
}
|
||||
|
||||
if (c == '\"') {
|
||||
inDQuote = ! inDQuote;
|
||||
}
|
||||
|
||||
startingNewLine = (c == '\n');
|
||||
if (startingNewLine) {
|
||||
currentColumn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::vprintf(const char* formatString, va_list argPtr) {
|
||||
std::string str = vformat(formatString, argPtr);
|
||||
|
||||
std::string clean;
|
||||
convertNewlines(str, clean);
|
||||
wordWrapIndentAppend(clean);
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::commit(bool flush) {
|
||||
std::string p = filenamePath(filename);
|
||||
if (! FileSystem::exists(p, false)) {
|
||||
FileSystem::createDirectory(p);
|
||||
}
|
||||
|
||||
FILE* f = FileSystem::fopen(filename.c_str(), "wb");
|
||||
debugAssertM(f, "Could not open \"" + filename + "\"");
|
||||
fwrite(data.getCArray(), 1, data.size(), f);
|
||||
if (flush) {
|
||||
fflush(f);
|
||||
}
|
||||
FileSystem::fclose(f);
|
||||
}
|
||||
|
||||
|
||||
void TextOutput::commitString(std::string& out) {
|
||||
// Null terminate
|
||||
data.push('\0');
|
||||
out = data.getCArray();
|
||||
data.pop();
|
||||
}
|
||||
|
||||
|
||||
std::string TextOutput::commitString() {
|
||||
std::string str;
|
||||
commitString(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
void serialize(const float& b, TextOutput& to) {
|
||||
to.writeNumber(b);
|
||||
}
|
||||
|
||||
|
||||
void serialize(const bool& b, TextOutput& to) {
|
||||
to.writeSymbol(b ? "true" : "false");
|
||||
}
|
||||
|
||||
|
||||
void serialize(const int& b, TextOutput& to) {
|
||||
to.writeNumber(b);
|
||||
}
|
||||
|
||||
|
||||
void serialize(const uint8& b, TextOutput& to) {
|
||||
to.writeNumber(b);
|
||||
}
|
||||
|
||||
|
||||
void serialize(const double& b, TextOutput& to) {
|
||||
to.writeNumber(b);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
166
modules/acore/deps/g3dlite/source/ThreadSet.cpp
Normal file
166
modules/acore/deps/g3dlite/source/ThreadSet.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "G3D/ThreadSet.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
int ThreadSet::size() const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
me->m_lock.lock();
|
||||
int s = m_thread.size();
|
||||
me->m_lock.unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int ThreadSet::numStarted() const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
me->m_lock.lock();
|
||||
int count = 0;
|
||||
for (int i = 0; i < m_thread.size(); ++i) {
|
||||
if (m_thread[i]->started()) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
me->m_lock.unlock();
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
void ThreadSet::start(GThread::SpawnBehavior lastBehavior) const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
|
||||
Array<GThreadRef> unstarted;
|
||||
me->m_lock.lock();
|
||||
// Find the unstarted threads
|
||||
for (int i = 0; i < m_thread.size(); ++i) {
|
||||
if (! m_thread[i]->started()) {
|
||||
unstarted.append(m_thread[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int last = unstarted.size();
|
||||
if (lastBehavior == GThread::USE_CURRENT_THREAD) {
|
||||
// Save the last unstarted for the current thread
|
||||
--last;
|
||||
}
|
||||
|
||||
for (int i = 0; i < last; ++i) {
|
||||
unstarted[i]->start(GThread::USE_NEW_THREAD);
|
||||
}
|
||||
|
||||
me->m_lock.unlock();
|
||||
|
||||
// Start the last one on my thread
|
||||
if ((unstarted.size() > 0) && (lastBehavior == GThread::USE_CURRENT_THREAD)) {
|
||||
unstarted.last()->start(GThread::USE_CURRENT_THREAD);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ThreadSet::terminate() const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
me->m_lock.lock();
|
||||
for (int i = 0; i < m_thread.size(); ++i) {
|
||||
if (m_thread[i]->started()) {
|
||||
m_thread[i]->terminate();
|
||||
}
|
||||
}
|
||||
me->m_lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
void ThreadSet::waitForCompletion() const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
me->m_lock.lock();
|
||||
for (int i = 0; i < m_thread.size(); ++i) {
|
||||
if (m_thread[i]->started()) {
|
||||
m_thread[i]->waitForCompletion();
|
||||
}
|
||||
}
|
||||
me->m_lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
int ThreadSet::removeCompleted() {
|
||||
m_lock.lock();
|
||||
for (int i = 0; i < m_thread.size(); ++i) {
|
||||
if (m_thread[i]->completed()) {
|
||||
m_thread.fastRemove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
int s = m_thread.size();
|
||||
m_lock.unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void ThreadSet::clear() {
|
||||
m_lock.lock();
|
||||
m_thread.clear();
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
int ThreadSet::insert(const ThreadRef& t) {
|
||||
m_lock.lock();
|
||||
bool found = false;
|
||||
for (int i = 0; i < m_thread.size() && ! found; ++i) {
|
||||
found = (m_thread[i] == t);
|
||||
}
|
||||
if (! found) {
|
||||
m_thread.append(t);
|
||||
}
|
||||
int s = m_thread.size();
|
||||
m_lock.unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
bool ThreadSet::remove(const ThreadRef& t) {
|
||||
m_lock.lock();
|
||||
bool found = false;
|
||||
for (int i = 0; i < m_thread.size() && ! found; ++i) {
|
||||
found = (m_thread[i] == t);
|
||||
if (found) {
|
||||
m_thread.fastRemove(i);
|
||||
}
|
||||
}
|
||||
m_lock.unlock();
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
bool ThreadSet::contains(const ThreadRef& t) const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
me->m_lock.lock();
|
||||
bool found = false;
|
||||
for (int i = 0; i < m_thread.size() && ! found; ++i) {
|
||||
found = (m_thread[i] == t);
|
||||
}
|
||||
me->m_lock.unlock();
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
ThreadSet::Iterator ThreadSet::begin() {
|
||||
return m_thread.begin();
|
||||
}
|
||||
|
||||
|
||||
ThreadSet::Iterator ThreadSet::end() {
|
||||
return m_thread.end();
|
||||
}
|
||||
|
||||
|
||||
ThreadSet::ConstIterator ThreadSet::begin() const {
|
||||
return m_thread.begin();
|
||||
}
|
||||
|
||||
|
||||
ThreadSet::ConstIterator ThreadSet::end() const {
|
||||
return m_thread.end();
|
||||
}
|
||||
|
||||
|
||||
} // namespace G3D
|
||||
186
modules/acore/deps/g3dlite/source/Triangle.cpp
Normal file
186
modules/acore/deps/g3dlite/source/Triangle.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
@file Triangle.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-04-06
|
||||
@edited 2008-12-28
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Triangle.h"
|
||||
#include "G3D/Plane.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/debugAssert.h"
|
||||
#include "G3D/AABox.h"
|
||||
#include "G3D/Ray.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
void Triangle::init(const Vector3& v0, const Vector3& v1, const Vector3& v2) {
|
||||
|
||||
_plane = Plane(v0, v1, v2);
|
||||
_vertex[0] = v0;
|
||||
_vertex[1] = v1;
|
||||
_vertex[2] = v2;
|
||||
|
||||
static int next[] = {1,2,0};
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const Vector3& e = _vertex[next[i]] - _vertex[i];
|
||||
edgeMagnitude[i] = e.magnitude();
|
||||
|
||||
if (edgeMagnitude[i] == 0) {
|
||||
edgeDirection[i] = Vector3::zero();
|
||||
} else {
|
||||
edgeDirection[i] = e / (float)edgeMagnitude[i];
|
||||
}
|
||||
}
|
||||
|
||||
_edge01 = _vertex[1] - _vertex[0];
|
||||
_edge02 = _vertex[2] - _vertex[0];
|
||||
|
||||
_primaryAxis = _plane.normal().primaryAxis();
|
||||
_area = 0.5f * edgeDirection[0].cross(edgeDirection[2]).magnitude() * (edgeMagnitude[0] * edgeMagnitude[2]);
|
||||
//0.5f * (_vertex[1] - _vertex[0]).cross(_vertex[2] - _vertex[0]).dot(_plane.normal());
|
||||
}
|
||||
|
||||
|
||||
Triangle::Triangle() {
|
||||
init(Vector3::zero(), Vector3::zero(), Vector3::zero());
|
||||
}
|
||||
|
||||
|
||||
Triangle::Triangle(const Vector3& v0, const Vector3& v1, const Vector3& v2) {
|
||||
init(v0, v1, v2);
|
||||
}
|
||||
|
||||
|
||||
Triangle::~Triangle() {
|
||||
}
|
||||
|
||||
|
||||
Triangle::Triangle(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Triangle::serialize(class BinaryOutput& b) {
|
||||
_vertex[0].serialize(b);
|
||||
_vertex[1].serialize(b);
|
||||
_vertex[2].serialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Triangle::deserialize(class BinaryInput& b) {
|
||||
_vertex[0].deserialize(b);
|
||||
_vertex[1].deserialize(b);
|
||||
_vertex[2].deserialize(b);
|
||||
init(_vertex[0], _vertex[1], _vertex[2]);
|
||||
}
|
||||
|
||||
|
||||
float Triangle::area() const {
|
||||
return _area;
|
||||
}
|
||||
|
||||
|
||||
const Vector3& Triangle::normal() const {
|
||||
return _plane.normal();
|
||||
}
|
||||
|
||||
|
||||
const Plane& Triangle::plane() const {
|
||||
return _plane;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Triangle::center() const {
|
||||
return (_vertex[0] + _vertex[1] + _vertex[2]) / 3.0;
|
||||
}
|
||||
|
||||
Vector3 Triangle::randomPoint() const {
|
||||
// Choose a random point in the parallelogram
|
||||
|
||||
float s = uniformRandom();
|
||||
float t = uniformRandom();
|
||||
|
||||
if (t > 1.0f - s) {
|
||||
// Outside the triangle; reflect about the
|
||||
// diagonal of the parallelogram
|
||||
t = 1.0f - t;
|
||||
s = 1.0f - s;
|
||||
}
|
||||
|
||||
return _edge01 * s + _edge02 * t + _vertex[0];
|
||||
}
|
||||
|
||||
|
||||
void Triangle::getBounds(AABox& out) const {
|
||||
Vector3 lo = _vertex[0];
|
||||
Vector3 hi = lo;
|
||||
|
||||
for (int i = 1; i < 3; ++i) {
|
||||
lo = lo.min(_vertex[i]);
|
||||
hi = hi.max(_vertex[i]);
|
||||
}
|
||||
|
||||
out = AABox(lo, hi);
|
||||
}
|
||||
|
||||
|
||||
bool Triangle::intersect(const Ray& ray, float& distance, float baryCoord[3]) const {
|
||||
static const float EPS = 1e-5f;
|
||||
|
||||
// See RTR2 ch. 13.7 for the algorithm.
|
||||
|
||||
const Vector3& e1 = edge01();
|
||||
const Vector3& e2 = edge02();
|
||||
const Vector3 p(ray.direction().cross(e2));
|
||||
const float a = e1.dot(p);
|
||||
|
||||
if (abs(a) < EPS) {
|
||||
// Determinant is ill-conditioned; abort early
|
||||
return false;
|
||||
}
|
||||
|
||||
const float f = 1.0f / a;
|
||||
const Vector3 s(ray.origin() - vertex(0));
|
||||
const float u = f * s.dot(p);
|
||||
|
||||
if ((u < 0.0f) || (u > 1.0f)) {
|
||||
// We hit the plane of the m_geometry, but outside the m_geometry
|
||||
return false;
|
||||
}
|
||||
|
||||
const Vector3 q(s.cross(e1));
|
||||
const float v = f * ray.direction().dot(q);
|
||||
|
||||
if ((v < 0.0f) || ((u + v) > 1.0f)) {
|
||||
// We hit the plane of the triangle, but outside the triangle
|
||||
return false;
|
||||
}
|
||||
|
||||
const float t = f * e2.dot(q);
|
||||
|
||||
if ((t > 0.0f) && (t < distance)) {
|
||||
// This is a new hit, closer than the previous one
|
||||
distance = t;
|
||||
|
||||
baryCoord[0] = 1.0 - u - v;
|
||||
baryCoord[1] = u;
|
||||
baryCoord[2] = v;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// This hit is after the previous hit, so ignore it
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // G3D
|
||||
132
modules/acore/deps/g3dlite/source/UprightFrame.cpp
Normal file
132
modules/acore/deps/g3dlite/source/UprightFrame.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
@file UprightFrame.cpp
|
||||
Box class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-05-02
|
||||
@edited 2007-05-05
|
||||
*/
|
||||
|
||||
#include "G3D/UprightFrame.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
UprightFrame::UprightFrame(const CoordinateFrame& cframe) {
|
||||
Vector3 look = cframe.lookVector();
|
||||
|
||||
yaw = G3D::pi() + atan2(look.x, look.z);
|
||||
pitch = asin(look.y);
|
||||
|
||||
translation = cframe.translation;
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame UprightFrame::toCoordinateFrame() const {
|
||||
CoordinateFrame cframe;
|
||||
|
||||
Matrix3 P(Matrix3::fromAxisAngle(Vector3::unitX(), pitch));
|
||||
Matrix3 Y(Matrix3::fromAxisAngle(Vector3::unitY(), yaw));
|
||||
|
||||
cframe.rotation = Y * P;
|
||||
cframe.translation = translation;
|
||||
|
||||
return cframe;
|
||||
}
|
||||
|
||||
|
||||
UprightFrame UprightFrame::operator+(const UprightFrame& other) const {
|
||||
return UprightFrame(translation + other.translation, pitch + other.pitch, yaw + other.yaw);
|
||||
}
|
||||
|
||||
|
||||
UprightFrame UprightFrame::operator*(const float k) const {
|
||||
return UprightFrame(translation * k, pitch * k, yaw * k);
|
||||
}
|
||||
|
||||
|
||||
void UprightFrame::unwrapYaw(UprightFrame* a, int N) {
|
||||
// Use the first point to establish the wrapping convention
|
||||
for (int i = 1; i < N; ++i) {
|
||||
const float prev = a[i - 1].yaw;
|
||||
float& cur = a[i].yaw;
|
||||
|
||||
// No two angles should be more than pi (i.e., 180-degrees) apart.
|
||||
if (abs(cur - prev) > G3D::pi()) {
|
||||
// These angles must have wrapped at zero, causing them
|
||||
// to be interpolated the long way.
|
||||
|
||||
// Find canonical [0, 2pi] versions of these numbers
|
||||
float p = wrap(prev, twoPi());
|
||||
float c = wrap(cur, twoPi());
|
||||
|
||||
// Find the difference -pi < diff < pi between the current and previous values
|
||||
float diff = c - p;
|
||||
if (diff < -G3D::pi()) {
|
||||
diff += twoPi();
|
||||
} else if (diff > G3D::pi()) {
|
||||
diff -= twoPi();
|
||||
}
|
||||
|
||||
// Offset the current from the previous by the difference
|
||||
// between them.
|
||||
cur = prev + diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UprightFrame::serialize(class BinaryOutput& b) const {
|
||||
translation.serialize(b);
|
||||
b.writeFloat32(pitch);
|
||||
b.writeFloat32(yaw);
|
||||
}
|
||||
|
||||
|
||||
void UprightFrame::deserialize(class BinaryInput& b) {
|
||||
translation.deserialize(b);
|
||||
pitch = b.readFloat32();
|
||||
yaw = b.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void UprightSpline::serialize(class BinaryOutput& b) const {
|
||||
b.writeBool8(cyclic);
|
||||
|
||||
b.writeInt32(control.size());
|
||||
for (int i = 0; i < control.size(); ++i) {
|
||||
control[i].serialize(b);
|
||||
}
|
||||
b.writeInt32(time.size());
|
||||
for (int i = 0; i < time.size(); ++i) {
|
||||
b.writeFloat32(time[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UprightSpline::deserialize(class BinaryInput& b) {
|
||||
cyclic = b.readBool8();
|
||||
|
||||
control.resize(b.readInt32());
|
||||
for (int i = 0; i < control.size(); ++i) {
|
||||
control[i].deserialize(b);
|
||||
}
|
||||
|
||||
if (b.hasMore()) {
|
||||
time.resize(b.readInt32());
|
||||
for (int i = 0; i < time.size(); ++i) {
|
||||
time[i] = b.readFloat32();
|
||||
}
|
||||
debugAssert(time.size() == control.size());
|
||||
} else {
|
||||
// Import legacy path
|
||||
time.resize(control.size());
|
||||
for (int i = 0; i < time.size(); ++i) {
|
||||
time[i] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
224
modules/acore/deps/g3dlite/source/Vector2.cpp
Normal file
224
modules/acore/deps/g3dlite/source/Vector2.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
@file Vector2.cpp
|
||||
|
||||
2D vector class, used for texture coordinates primarily.
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@cite Portions based on Dave Eberly'x Magic Software Library
|
||||
at http://www.magic-software.com
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2009-11-16
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include <stdlib.h>
|
||||
#include "G3D/Vector2.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/TextInput.h"
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/Any.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
Vector2::Vector2(const Any& any) {
|
||||
any.verifyName("Vector2");
|
||||
any.verifyType(Any::TABLE, Any::ARRAY);
|
||||
any.verifySize(2);
|
||||
|
||||
if (any.type() == Any::ARRAY) {
|
||||
x = any[0];
|
||||
y = any[1];
|
||||
} else {
|
||||
// Table
|
||||
x = any["x"];
|
||||
y = any["y"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector2::operator Any() const {
|
||||
Any any(Any::ARRAY, "Vector2");
|
||||
any.append(x, y);
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
const Vector2& Vector2::one() {
|
||||
static const Vector2 v(1, 1); return v;
|
||||
}
|
||||
|
||||
|
||||
const Vector2& Vector2::zero() {
|
||||
static Vector2 v(0, 0);
|
||||
return v;
|
||||
}
|
||||
|
||||
const Vector2& Vector2::unitX() {
|
||||
static Vector2 v(1, 0);
|
||||
return v;
|
||||
}
|
||||
|
||||
const Vector2& Vector2::unitY() {
|
||||
static Vector2 v(0, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
const Vector2& Vector2::inf() {
|
||||
static Vector2 v((float)G3D::finf(), (float)G3D::finf());
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
const Vector2& Vector2::nan() {
|
||||
static Vector2 v((float)G3D::fnan(), (float)G3D::fnan());
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
const Vector2& Vector2::minFinite() {
|
||||
static Vector2 v(-FLT_MAX, -FLT_MAX);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
const Vector2& Vector2::maxFinite() {
|
||||
static Vector2 v(FLT_MAX, FLT_MAX);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
size_t Vector2::hashCode() const {
|
||||
unsigned int xhash = (*(int*)(void*)(&x));
|
||||
unsigned int yhash = (*(int*)(void*)(&y));
|
||||
|
||||
return xhash + (yhash * 37);
|
||||
}
|
||||
|
||||
|
||||
Vector2::Vector2(BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Vector2::deserialize(BinaryInput& b) {
|
||||
x = b.readFloat32();
|
||||
y = b.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Vector2::serialize(BinaryOutput& b) const {
|
||||
b.writeFloat32(x);
|
||||
b.writeFloat32(y);
|
||||
}
|
||||
|
||||
|
||||
void Vector2::deserialize(TextInput& t) {
|
||||
t.readSymbol("(");
|
||||
x = (float)t.readNumber();
|
||||
t.readSymbol(",");
|
||||
y = (float)t.readNumber();
|
||||
t.readSymbol(")");
|
||||
}
|
||||
|
||||
|
||||
void Vector2::serialize(TextOutput& t) const {
|
||||
t.writeSymbol("(");
|
||||
t.writeNumber(x);
|
||||
t.writeSymbol(",");
|
||||
t.writeNumber(y);
|
||||
t.writeSymbol(")");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Vector2 Vector2::random(G3D::Random& r) {
|
||||
Vector2 result;
|
||||
|
||||
do {
|
||||
result = Vector2(r.uniform(-1, 1), r.uniform(-1, 1));
|
||||
|
||||
} while (result.squaredLength() >= 1.0f);
|
||||
|
||||
result.unitize();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Vector2 Vector2::operator/ (float k) const {
|
||||
return *this * (1.0f / k);
|
||||
}
|
||||
|
||||
Vector2& Vector2::operator/= (float k) {
|
||||
this->x /= k;
|
||||
this->y /= k;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Vector2::unitize (float fTolerance) {
|
||||
float fLength = length();
|
||||
|
||||
if (fLength > fTolerance) {
|
||||
float fInvLength = 1.0f / fLength;
|
||||
x *= fInvLength;
|
||||
y *= fInvLength;
|
||||
} else {
|
||||
fLength = 0.0;
|
||||
}
|
||||
|
||||
return fLength;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
std::string Vector2::toString() const {
|
||||
return G3D::format("(%g, %g)", x, y);
|
||||
}
|
||||
|
||||
// 2-char swizzles
|
||||
|
||||
Vector2 Vector2::xx() const { return Vector2 (x, x); }
|
||||
Vector2 Vector2::yx() const { return Vector2 (y, x); }
|
||||
Vector2 Vector2::xy() const { return Vector2 (x, y); }
|
||||
Vector2 Vector2::yy() const { return Vector2 (y, y); }
|
||||
|
||||
// 3-char swizzles
|
||||
|
||||
Vector3 Vector2::xxx() const { return Vector3 (x, x, x); }
|
||||
Vector3 Vector2::yxx() const { return Vector3 (y, x, x); }
|
||||
Vector3 Vector2::xyx() const { return Vector3 (x, y, x); }
|
||||
Vector3 Vector2::yyx() const { return Vector3 (y, y, x); }
|
||||
Vector3 Vector2::xxy() const { return Vector3 (x, x, y); }
|
||||
Vector3 Vector2::yxy() const { return Vector3 (y, x, y); }
|
||||
Vector3 Vector2::xyy() const { return Vector3 (x, y, y); }
|
||||
Vector3 Vector2::yyy() const { return Vector3 (y, y, y); }
|
||||
|
||||
// 4-char swizzles
|
||||
|
||||
Vector4 Vector2::xxxx() const { return Vector4 (x, x, x, x); }
|
||||
Vector4 Vector2::yxxx() const { return Vector4 (y, x, x, x); }
|
||||
Vector4 Vector2::xyxx() const { return Vector4 (x, y, x, x); }
|
||||
Vector4 Vector2::yyxx() const { return Vector4 (y, y, x, x); }
|
||||
Vector4 Vector2::xxyx() const { return Vector4 (x, x, y, x); }
|
||||
Vector4 Vector2::yxyx() const { return Vector4 (y, x, y, x); }
|
||||
Vector4 Vector2::xyyx() const { return Vector4 (x, y, y, x); }
|
||||
Vector4 Vector2::yyyx() const { return Vector4 (y, y, y, x); }
|
||||
Vector4 Vector2::xxxy() const { return Vector4 (x, x, x, y); }
|
||||
Vector4 Vector2::yxxy() const { return Vector4 (y, x, x, y); }
|
||||
Vector4 Vector2::xyxy() const { return Vector4 (x, y, x, y); }
|
||||
Vector4 Vector2::yyxy() const { return Vector4 (y, y, x, y); }
|
||||
Vector4 Vector2::xxyy() const { return Vector4 (x, x, y, y); }
|
||||
Vector4 Vector2::yxyy() const { return Vector4 (y, x, y, y); }
|
||||
Vector4 Vector2::xyyy() const { return Vector4 (x, y, y, y); }
|
||||
Vector4 Vector2::yyyy() const { return Vector4 (y, y, y, y); }
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
47
modules/acore/deps/g3dlite/source/Vector2int16.cpp
Normal file
47
modules/acore/deps/g3dlite/source/Vector2int16.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
@file Vector2int16.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-08-09
|
||||
@edited 2006-01-29
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Vector2int16.h"
|
||||
#include "G3D/Vector2.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector2int16::Vector2int16(const class Vector2& v) {
|
||||
x = (int16)iFloor(v.x + 0.5);
|
||||
y = (int16)iFloor(v.y + 0.5);
|
||||
}
|
||||
|
||||
|
||||
Vector2int16::Vector2int16(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Vector2int16::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeInt16(x);
|
||||
bo.writeInt16(y);
|
||||
}
|
||||
|
||||
|
||||
void Vector2int16::deserialize(class BinaryInput& bi) {
|
||||
x = bi.readInt16();
|
||||
y = bi.readInt16();
|
||||
}
|
||||
|
||||
|
||||
Vector2int16 Vector2int16::clamp(const Vector2int16& lo, const Vector2int16& hi) {
|
||||
return Vector2int16(iClamp(x, lo.x, hi.x), iClamp(y, lo.y, hi.y));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
504
modules/acore/deps/g3dlite/source/Vector3.cpp
Normal file
504
modules/acore/deps/g3dlite/source/Vector3.cpp
Normal file
@@ -0,0 +1,504 @@
|
||||
/**
|
||||
@file Vector3.cpp
|
||||
|
||||
3D vector class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2009-11-27
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <stdlib.h>
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/TextInput.h"
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/Vector3int16.h"
|
||||
#include "G3D/Matrix3.h"
|
||||
#include "G3D/Vector2.h"
|
||||
#include "G3D/Color3.h"
|
||||
#include "G3D/Vector4int8.h"
|
||||
#include "G3D/Vector4.h"
|
||||
#include "G3D/Vector3int32.h"
|
||||
#include "G3D/Any.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector3::Vector3(const Any& any) {
|
||||
any.verifyName("Vector3");
|
||||
any.verifyType(Any::TABLE, Any::ARRAY);
|
||||
any.verifySize(3);
|
||||
|
||||
if (any.type() == Any::ARRAY) {
|
||||
x = any[0];
|
||||
y = any[1];
|
||||
z = any[2];
|
||||
} else {
|
||||
// Table
|
||||
x = any["x"];
|
||||
y = any["y"];
|
||||
z = any["z"];
|
||||
}
|
||||
}
|
||||
|
||||
Vector3::operator Any() const {
|
||||
Any any(Any::ARRAY, "Vector3");
|
||||
any.append(x, y, z);
|
||||
return any;
|
||||
}
|
||||
|
||||
Vector3::Vector3(const class Color3& v) : x(v.r), y(v.g), z(v.b) {}
|
||||
|
||||
Vector3::Vector3(const class Vector3int32& v) : x((float)v.x), y((float)v.y), z((float)v.z) {}
|
||||
|
||||
Vector3::Vector3(const Vector4int8& v) : x(v.x / 127.0f), y(v.y / 127.0f), z(v.z / 127.0f) {}
|
||||
|
||||
Vector3::Vector3(const class Vector2& v, float _z) : x(v.x), y(v.y), z(_z) {
|
||||
}
|
||||
|
||||
Vector3& Vector3::ignore() {
|
||||
static Vector3 v;
|
||||
return v;
|
||||
}
|
||||
|
||||
const Vector3& Vector3::zero() { static const Vector3 v(0, 0, 0); return v; }
|
||||
const Vector3& Vector3::one() { static const Vector3 v(1, 1, 1); return v; }
|
||||
const Vector3& Vector3::unitX() { static const Vector3 v(1, 0, 0); return v; }
|
||||
const Vector3& Vector3::unitY() { static const Vector3 v(0, 1, 0); return v; }
|
||||
const Vector3& Vector3::unitZ() { static const Vector3 v(0, 0, 1); return v; }
|
||||
const Vector3& Vector3::inf() { static const Vector3 v((float)G3D::finf(), (float)G3D::finf(), (float)G3D::finf()); return v; }
|
||||
const Vector3& Vector3::nan() { static const Vector3 v((float)G3D::fnan(), (float)G3D::fnan(), (float)G3D::fnan()); return v; }
|
||||
const Vector3& Vector3::minFinite(){ static const Vector3 v(-FLT_MAX, -FLT_MAX, -FLT_MAX); return v; }
|
||||
const Vector3& Vector3::maxFinite(){ static const Vector3 v(FLT_MAX, FLT_MAX, FLT_MAX); return v; }
|
||||
|
||||
Vector3::Axis Vector3::primaryAxis() const {
|
||||
|
||||
Axis a = X_AXIS;
|
||||
|
||||
double nx = abs(x);
|
||||
double ny = abs(y);
|
||||
double nz = abs(z);
|
||||
|
||||
if (nx > ny) {
|
||||
if (nx > nz) {
|
||||
a = X_AXIS;
|
||||
} else {
|
||||
a = Z_AXIS;
|
||||
}
|
||||
} else {
|
||||
if (ny > nz) {
|
||||
a = Y_AXIS;
|
||||
} else {
|
||||
a = Z_AXIS;
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
size_t Vector3::hashCode() const {
|
||||
return Vector4(*this, 0.0f).hashCode();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Vector3& v) {
|
||||
return os << v.toString();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
double frand() {
|
||||
return rand() / (double) RAND_MAX;
|
||||
}
|
||||
|
||||
Vector3::Vector3(TextInput& t) {
|
||||
deserialize(t);
|
||||
}
|
||||
|
||||
Vector3::Vector3(BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
Vector3::Vector3(const class Vector3int16& v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
}
|
||||
|
||||
|
||||
void Vector3::deserialize(BinaryInput& b) {
|
||||
x = b.readFloat32();
|
||||
y = b.readFloat32();
|
||||
z = b.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Vector3::deserialize(TextInput& t) {
|
||||
t.readSymbol("(");
|
||||
x = (float)t.readNumber();
|
||||
t.readSymbol(",");
|
||||
y = (float)t.readNumber();
|
||||
t.readSymbol(",");
|
||||
z = (float)t.readNumber();
|
||||
t.readSymbol(")");
|
||||
}
|
||||
|
||||
|
||||
void Vector3::serialize(TextOutput& t) const {
|
||||
t.writeSymbol("(");
|
||||
t.writeNumber(x);
|
||||
t.writeSymbol(",");
|
||||
t.writeNumber(y);
|
||||
t.writeSymbol(",");
|
||||
t.writeNumber(z);
|
||||
t.writeSymbol(")");
|
||||
}
|
||||
|
||||
|
||||
void Vector3::serialize(BinaryOutput& b) const {
|
||||
b.writeFloat32(x);
|
||||
b.writeFloat32(y);
|
||||
b.writeFloat32(z);
|
||||
}
|
||||
|
||||
|
||||
Vector3 Vector3::random(Random& r) {
|
||||
Vector3 result;
|
||||
r.sphere(result.x, result.y, result.z);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
float Vector3::unitize(float fTolerance) {
|
||||
float fMagnitude = magnitude();
|
||||
|
||||
if (fMagnitude > fTolerance) {
|
||||
float fInvMagnitude = 1.0f / fMagnitude;
|
||||
x *= fInvMagnitude;
|
||||
y *= fInvMagnitude;
|
||||
z *= fInvMagnitude;
|
||||
} else {
|
||||
fMagnitude = 0.0f;
|
||||
}
|
||||
|
||||
return fMagnitude;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Vector3::reflectAbout(const Vector3& normal) const {
|
||||
Vector3 out;
|
||||
|
||||
Vector3 N = normal.direction();
|
||||
|
||||
// 2 * normal.dot(this) * normal - this
|
||||
return N * 2 * this->dot(N) - *this;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Vector3::cosHemiRandom(const Vector3& normal, Random& r) {
|
||||
debugAssertM(G3D::fuzzyEq(normal.length(), 1.0f),
|
||||
"cosHemiRandom requires its argument to have unit length");
|
||||
|
||||
float x, y, z;
|
||||
r.cosHemi(x, y, z);
|
||||
|
||||
// Make a coordinate system
|
||||
const Vector3& Z = normal;
|
||||
|
||||
Vector3 X, Y;
|
||||
normal.getTangents(X, Y);
|
||||
|
||||
return
|
||||
x * X +
|
||||
y * Y +
|
||||
z * Z;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Vector3::cosPowHemiRandom(const Vector3& normal, const float k, Random& r) {
|
||||
debugAssertM(G3D::fuzzyEq(normal.length(), 1.0f),
|
||||
"cosPowHemiRandom requires its argument to have unit length");
|
||||
|
||||
float x, y, z;
|
||||
r.cosPowHemi(k, x, y, z);
|
||||
|
||||
// Make a coordinate system
|
||||
const Vector3& Z = normal;
|
||||
|
||||
Vector3 X, Y;
|
||||
normal.getTangents(X, Y);
|
||||
|
||||
return
|
||||
x * X +
|
||||
y * Y +
|
||||
z * Z;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Vector3::hemiRandom(const Vector3& normal, Random& r) {
|
||||
const Vector3& V = Vector3::random(r);
|
||||
|
||||
if (V.dot(normal) < 0) {
|
||||
return -V;
|
||||
} else {
|
||||
return V;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Vector3 Vector3::reflectionDirection(const Vector3& normal) const {
|
||||
return -reflectAbout(normal).direction();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Vector3 Vector3::refractionDirection(
|
||||
const Vector3& normal,
|
||||
float iInside,
|
||||
float iOutside) const {
|
||||
|
||||
// From pg. 24 of Henrik Wann Jensen. Realistic Image Synthesis
|
||||
// Using Photon Mapping. AK Peters. ISBN: 1568811470. July 2001.
|
||||
|
||||
// Invert the directions from Wann Jensen's formulation
|
||||
// and normalize the vectors.
|
||||
const Vector3 W = -direction();
|
||||
Vector3 N = normal.direction();
|
||||
|
||||
float h1 = iOutside;
|
||||
float h2 = iInside;
|
||||
|
||||
if (normal.dot(*this) > 0.0f) {
|
||||
h1 = iInside;
|
||||
h2 = iOutside;
|
||||
N = -N;
|
||||
}
|
||||
|
||||
const float hRatio = h1 / h2;
|
||||
const float WdotN = W.dot(N);
|
||||
|
||||
float det = 1.0f - (float)square(hRatio) * (1.0f - (float)square(WdotN));
|
||||
|
||||
if (det < 0) {
|
||||
// Total internal reflection
|
||||
return Vector3::zero();
|
||||
} else {
|
||||
return -hRatio * (W - WdotN * N) - N * sqrt(det);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vector3::orthonormalize (Vector3 akVector[3]) {
|
||||
// If the input vectors are v0, v1, and v2, then the Gram-Schmidt
|
||||
// orthonormalization produces vectors u0, u1, and u2 as follows,
|
||||
//
|
||||
// u0 = v0/|v0|
|
||||
// u1 = (v1-(u0*v1)u0)/|v1-(u0*v1)u0|
|
||||
// u2 = (v2-(u0*v2)u0-(u1*v2)u1)/|v2-(u0*v2)u0-(u1*v2)u1|
|
||||
//
|
||||
// where |A| indicates length of vector A and A*B indicates dot
|
||||
// product of vectors A and B.
|
||||
|
||||
// compute u0
|
||||
akVector[0].unitize();
|
||||
|
||||
// compute u1
|
||||
float fDot0 = akVector[0].dot(akVector[1]);
|
||||
akVector[1] -= akVector[0] * fDot0;
|
||||
akVector[1].unitize();
|
||||
|
||||
// compute u2
|
||||
float fDot1 = akVector[1].dot(akVector[2]);
|
||||
fDot0 = akVector[0].dot(akVector[2]);
|
||||
akVector[2] -= akVector[0] * fDot0 + akVector[1] * fDot1;
|
||||
akVector[2].unitize();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vector3::generateOrthonormalBasis (Vector3& rkU, Vector3& rkV,
|
||||
Vector3& rkW, bool bUnitLengthW) {
|
||||
if ( !bUnitLengthW )
|
||||
rkW.unitize();
|
||||
|
||||
if ( G3D::abs(rkW.x) >= G3D::abs(rkW.y)
|
||||
&& G3D::abs(rkW.x) >= G3D::abs(rkW.z) ) {
|
||||
rkU.x = -rkW.y;
|
||||
rkU.y = + rkW.x;
|
||||
rkU.z = 0.0;
|
||||
} else {
|
||||
rkU.x = 0.0;
|
||||
rkU.y = + rkW.z;
|
||||
rkU.z = -rkW.y;
|
||||
}
|
||||
|
||||
rkU.unitize();
|
||||
rkV = rkW.cross(rkU);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
std::string Vector3::toString() const {
|
||||
return G3D::format("(%g, %g, %g)", x, y, z);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Matrix3 Vector3::cross() const {
|
||||
return Matrix3( 0, -z, y,
|
||||
z, 0, -x,
|
||||
-y, x, 0);
|
||||
}
|
||||
|
||||
|
||||
void serialize(const Vector3::Axis& a, class BinaryOutput& bo) {
|
||||
bo.writeUInt8((uint8)a);
|
||||
}
|
||||
|
||||
void deserialize(Vector3::Axis& a, class BinaryInput& bi) {
|
||||
a = (Vector3::Axis)bi.readUInt8();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// 2-char swizzles
|
||||
|
||||
Vector2 Vector3::xx() const { return Vector2 (x, x); }
|
||||
Vector2 Vector3::yx() const { return Vector2 (y, x); }
|
||||
Vector2 Vector3::zx() const { return Vector2 (z, x); }
|
||||
Vector2 Vector3::xy() const { return Vector2 (x, y); }
|
||||
Vector2 Vector3::yy() const { return Vector2 (y, y); }
|
||||
Vector2 Vector3::zy() const { return Vector2 (z, y); }
|
||||
Vector2 Vector3::xz() const { return Vector2 (x, z); }
|
||||
Vector2 Vector3::yz() const { return Vector2 (y, z); }
|
||||
Vector2 Vector3::zz() const { return Vector2 (z, z); }
|
||||
|
||||
// 3-char swizzles
|
||||
|
||||
Vector3 Vector3::xxx() const { return Vector3 (x, x, x); }
|
||||
Vector3 Vector3::yxx() const { return Vector3 (y, x, x); }
|
||||
Vector3 Vector3::zxx() const { return Vector3 (z, x, x); }
|
||||
Vector3 Vector3::xyx() const { return Vector3 (x, y, x); }
|
||||
Vector3 Vector3::yyx() const { return Vector3 (y, y, x); }
|
||||
Vector3 Vector3::zyx() const { return Vector3 (z, y, x); }
|
||||
Vector3 Vector3::xzx() const { return Vector3 (x, z, x); }
|
||||
Vector3 Vector3::yzx() const { return Vector3 (y, z, x); }
|
||||
Vector3 Vector3::zzx() const { return Vector3 (z, z, x); }
|
||||
Vector3 Vector3::xxy() const { return Vector3 (x, x, y); }
|
||||
Vector3 Vector3::yxy() const { return Vector3 (y, x, y); }
|
||||
Vector3 Vector3::zxy() const { return Vector3 (z, x, y); }
|
||||
Vector3 Vector3::xyy() const { return Vector3 (x, y, y); }
|
||||
Vector3 Vector3::yyy() const { return Vector3 (y, y, y); }
|
||||
Vector3 Vector3::zyy() const { return Vector3 (z, y, y); }
|
||||
Vector3 Vector3::xzy() const { return Vector3 (x, z, y); }
|
||||
Vector3 Vector3::yzy() const { return Vector3 (y, z, y); }
|
||||
Vector3 Vector3::zzy() const { return Vector3 (z, z, y); }
|
||||
Vector3 Vector3::xxz() const { return Vector3 (x, x, z); }
|
||||
Vector3 Vector3::yxz() const { return Vector3 (y, x, z); }
|
||||
Vector3 Vector3::zxz() const { return Vector3 (z, x, z); }
|
||||
Vector3 Vector3::xyz() const { return Vector3 (x, y, z); }
|
||||
Vector3 Vector3::yyz() const { return Vector3 (y, y, z); }
|
||||
Vector3 Vector3::zyz() const { return Vector3 (z, y, z); }
|
||||
Vector3 Vector3::xzz() const { return Vector3 (x, z, z); }
|
||||
Vector3 Vector3::yzz() const { return Vector3 (y, z, z); }
|
||||
Vector3 Vector3::zzz() const { return Vector3 (z, z, z); }
|
||||
|
||||
// 4-char swizzles
|
||||
|
||||
Vector4 Vector3::xxxx() const { return Vector4 (x, x, x, x); }
|
||||
Vector4 Vector3::yxxx() const { return Vector4 (y, x, x, x); }
|
||||
Vector4 Vector3::zxxx() const { return Vector4 (z, x, x, x); }
|
||||
Vector4 Vector3::xyxx() const { return Vector4 (x, y, x, x); }
|
||||
Vector4 Vector3::yyxx() const { return Vector4 (y, y, x, x); }
|
||||
Vector4 Vector3::zyxx() const { return Vector4 (z, y, x, x); }
|
||||
Vector4 Vector3::xzxx() const { return Vector4 (x, z, x, x); }
|
||||
Vector4 Vector3::yzxx() const { return Vector4 (y, z, x, x); }
|
||||
Vector4 Vector3::zzxx() const { return Vector4 (z, z, x, x); }
|
||||
Vector4 Vector3::xxyx() const { return Vector4 (x, x, y, x); }
|
||||
Vector4 Vector3::yxyx() const { return Vector4 (y, x, y, x); }
|
||||
Vector4 Vector3::zxyx() const { return Vector4 (z, x, y, x); }
|
||||
Vector4 Vector3::xyyx() const { return Vector4 (x, y, y, x); }
|
||||
Vector4 Vector3::yyyx() const { return Vector4 (y, y, y, x); }
|
||||
Vector4 Vector3::zyyx() const { return Vector4 (z, y, y, x); }
|
||||
Vector4 Vector3::xzyx() const { return Vector4 (x, z, y, x); }
|
||||
Vector4 Vector3::yzyx() const { return Vector4 (y, z, y, x); }
|
||||
Vector4 Vector3::zzyx() const { return Vector4 (z, z, y, x); }
|
||||
Vector4 Vector3::xxzx() const { return Vector4 (x, x, z, x); }
|
||||
Vector4 Vector3::yxzx() const { return Vector4 (y, x, z, x); }
|
||||
Vector4 Vector3::zxzx() const { return Vector4 (z, x, z, x); }
|
||||
Vector4 Vector3::xyzx() const { return Vector4 (x, y, z, x); }
|
||||
Vector4 Vector3::yyzx() const { return Vector4 (y, y, z, x); }
|
||||
Vector4 Vector3::zyzx() const { return Vector4 (z, y, z, x); }
|
||||
Vector4 Vector3::xzzx() const { return Vector4 (x, z, z, x); }
|
||||
Vector4 Vector3::yzzx() const { return Vector4 (y, z, z, x); }
|
||||
Vector4 Vector3::zzzx() const { return Vector4 (z, z, z, x); }
|
||||
Vector4 Vector3::xxxy() const { return Vector4 (x, x, x, y); }
|
||||
Vector4 Vector3::yxxy() const { return Vector4 (y, x, x, y); }
|
||||
Vector4 Vector3::zxxy() const { return Vector4 (z, x, x, y); }
|
||||
Vector4 Vector3::xyxy() const { return Vector4 (x, y, x, y); }
|
||||
Vector4 Vector3::yyxy() const { return Vector4 (y, y, x, y); }
|
||||
Vector4 Vector3::zyxy() const { return Vector4 (z, y, x, y); }
|
||||
Vector4 Vector3::xzxy() const { return Vector4 (x, z, x, y); }
|
||||
Vector4 Vector3::yzxy() const { return Vector4 (y, z, x, y); }
|
||||
Vector4 Vector3::zzxy() const { return Vector4 (z, z, x, y); }
|
||||
Vector4 Vector3::xxyy() const { return Vector4 (x, x, y, y); }
|
||||
Vector4 Vector3::yxyy() const { return Vector4 (y, x, y, y); }
|
||||
Vector4 Vector3::zxyy() const { return Vector4 (z, x, y, y); }
|
||||
Vector4 Vector3::xyyy() const { return Vector4 (x, y, y, y); }
|
||||
Vector4 Vector3::yyyy() const { return Vector4 (y, y, y, y); }
|
||||
Vector4 Vector3::zyyy() const { return Vector4 (z, y, y, y); }
|
||||
Vector4 Vector3::xzyy() const { return Vector4 (x, z, y, y); }
|
||||
Vector4 Vector3::yzyy() const { return Vector4 (y, z, y, y); }
|
||||
Vector4 Vector3::zzyy() const { return Vector4 (z, z, y, y); }
|
||||
Vector4 Vector3::xxzy() const { return Vector4 (x, x, z, y); }
|
||||
Vector4 Vector3::yxzy() const { return Vector4 (y, x, z, y); }
|
||||
Vector4 Vector3::zxzy() const { return Vector4 (z, x, z, y); }
|
||||
Vector4 Vector3::xyzy() const { return Vector4 (x, y, z, y); }
|
||||
Vector4 Vector3::yyzy() const { return Vector4 (y, y, z, y); }
|
||||
Vector4 Vector3::zyzy() const { return Vector4 (z, y, z, y); }
|
||||
Vector4 Vector3::xzzy() const { return Vector4 (x, z, z, y); }
|
||||
Vector4 Vector3::yzzy() const { return Vector4 (y, z, z, y); }
|
||||
Vector4 Vector3::zzzy() const { return Vector4 (z, z, z, y); }
|
||||
Vector4 Vector3::xxxz() const { return Vector4 (x, x, x, z); }
|
||||
Vector4 Vector3::yxxz() const { return Vector4 (y, x, x, z); }
|
||||
Vector4 Vector3::zxxz() const { return Vector4 (z, x, x, z); }
|
||||
Vector4 Vector3::xyxz() const { return Vector4 (x, y, x, z); }
|
||||
Vector4 Vector3::yyxz() const { return Vector4 (y, y, x, z); }
|
||||
Vector4 Vector3::zyxz() const { return Vector4 (z, y, x, z); }
|
||||
Vector4 Vector3::xzxz() const { return Vector4 (x, z, x, z); }
|
||||
Vector4 Vector3::yzxz() const { return Vector4 (y, z, x, z); }
|
||||
Vector4 Vector3::zzxz() const { return Vector4 (z, z, x, z); }
|
||||
Vector4 Vector3::xxyz() const { return Vector4 (x, x, y, z); }
|
||||
Vector4 Vector3::yxyz() const { return Vector4 (y, x, y, z); }
|
||||
Vector4 Vector3::zxyz() const { return Vector4 (z, x, y, z); }
|
||||
Vector4 Vector3::xyyz() const { return Vector4 (x, y, y, z); }
|
||||
Vector4 Vector3::yyyz() const { return Vector4 (y, y, y, z); }
|
||||
Vector4 Vector3::zyyz() const { return Vector4 (z, y, y, z); }
|
||||
Vector4 Vector3::xzyz() const { return Vector4 (x, z, y, z); }
|
||||
Vector4 Vector3::yzyz() const { return Vector4 (y, z, y, z); }
|
||||
Vector4 Vector3::zzyz() const { return Vector4 (z, z, y, z); }
|
||||
Vector4 Vector3::xxzz() const { return Vector4 (x, x, z, z); }
|
||||
Vector4 Vector3::yxzz() const { return Vector4 (y, x, z, z); }
|
||||
Vector4 Vector3::zxzz() const { return Vector4 (z, x, z, z); }
|
||||
Vector4 Vector3::xyzz() const { return Vector4 (x, y, z, z); }
|
||||
Vector4 Vector3::yyzz() const { return Vector4 (y, y, z, z); }
|
||||
Vector4 Vector3::zyzz() const { return Vector4 (z, y, z, z); }
|
||||
Vector4 Vector3::xzzz() const { return Vector4 (x, z, z, z); }
|
||||
Vector4 Vector3::yzzz() const { return Vector4 (y, z, z, z); }
|
||||
Vector4 Vector3::zzzz() const { return Vector4 (z, z, z, z); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
49
modules/acore/deps/g3dlite/source/Vector3int16.cpp
Normal file
49
modules/acore/deps/g3dlite/source/Vector3int16.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
@file Vector3int16.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-04-07
|
||||
@edited 2006-01-17
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Vector3int16.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/format.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector3int16::Vector3int16(const class Vector3& v) {
|
||||
x = (int16)iFloor(v.x + 0.5);
|
||||
y = (int16)iFloor(v.y + 0.5);
|
||||
z = (int16)iFloor(v.z + 0.5);
|
||||
}
|
||||
|
||||
|
||||
Vector3int16::Vector3int16(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Vector3int16::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeInt16(x);
|
||||
bo.writeInt16(y);
|
||||
bo.writeInt16(z);
|
||||
}
|
||||
|
||||
|
||||
void Vector3int16::deserialize(class BinaryInput& bi) {
|
||||
x = bi.readInt16();
|
||||
y = bi.readInt16();
|
||||
z = bi.readInt16();
|
||||
}
|
||||
|
||||
std::string Vector3int16::toString() const {
|
||||
return G3D::format("(%d, %d, %d)", x, y, z);
|
||||
}
|
||||
|
||||
}
|
||||
57
modules/acore/deps/g3dlite/source/Vector3int32.cpp
Normal file
57
modules/acore/deps/g3dlite/source/Vector3int32.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
@file Vector3int32.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2008-07-01
|
||||
@edited 2008-07-01
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Vector3int32.h"
|
||||
#include "G3D/Vector3int16.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/format.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector3int32::Vector3int32(const class Vector3& v) {
|
||||
x = (int32)iFloor(v.x + 0.5);
|
||||
y = (int32)iFloor(v.y + 0.5);
|
||||
z = (int32)iFloor(v.z + 0.5);
|
||||
}
|
||||
|
||||
|
||||
Vector3int32::Vector3int32(const class Vector3int16& v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
}
|
||||
|
||||
|
||||
Vector3int32::Vector3int32(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Vector3int32::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeInt32(x);
|
||||
bo.writeInt32(y);
|
||||
bo.writeInt32(z);
|
||||
}
|
||||
|
||||
|
||||
void Vector3int32::deserialize(class BinaryInput& bi) {
|
||||
x = bi.readInt32();
|
||||
y = bi.readInt32();
|
||||
z = bi.readInt32();
|
||||
}
|
||||
|
||||
std::string Vector3int32::toString() const {
|
||||
return G3D::format("(%d, %d, %d)", x, y, z);
|
||||
}
|
||||
|
||||
}
|
||||
515
modules/acore/deps/g3dlite/source/Vector4.cpp
Normal file
515
modules/acore/deps/g3dlite/source/Vector4.cpp
Normal file
@@ -0,0 +1,515 @@
|
||||
/**
|
||||
@file Vector4.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-07-09
|
||||
@edited 2010-07-05
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits>
|
||||
#include "G3D/Vector4.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Vector4int8.h"
|
||||
#include "G3D/Matrix4.h"
|
||||
#include "G3D/Any.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector4::Vector4(const Any& any) {
|
||||
any.verifyName("Vector4");
|
||||
any.verifyType(Any::TABLE, Any::ARRAY);
|
||||
any.verifySize(4);
|
||||
|
||||
if (any.type() == Any::ARRAY) {
|
||||
x = any[0];
|
||||
y = any[1];
|
||||
z = any[2];
|
||||
w = any[3];
|
||||
} else {
|
||||
// Table
|
||||
x = any["x"];
|
||||
y = any["y"];
|
||||
z = any["z"];
|
||||
w = any["w"];
|
||||
}
|
||||
}
|
||||
|
||||
Vector4::operator Any() const {
|
||||
Any any(Any::ARRAY, "Vector4");
|
||||
any.append(x, y, z, w);
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
Vector4::Vector4(const Vector4int8& v) : x(v.x / 127.0f), y(v.y / 127.0f), z(v.z / 127.0f), w(v.w / 127.0f) {
|
||||
}
|
||||
|
||||
|
||||
const Vector4& Vector4::inf() {
|
||||
static const Vector4 v((float)G3D::finf(), (float)G3D::finf(), (float)G3D::finf(), (float)G3D::finf());
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
const Vector4& Vector4::zero() {
|
||||
static const Vector4 v(0,0,0,0);
|
||||
return v;
|
||||
}
|
||||
|
||||
const Vector4& Vector4::nan() {
|
||||
static Vector4 v((float)G3D::fnan(), (float)G3D::fnan(), (float)G3D::fnan(), (float)G3D::fnan());
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
size_t Vector4::hashCode() const {
|
||||
return HashTrait<uint128>::hashCode(*((uint128*)this));
|
||||
}
|
||||
|
||||
|
||||
Vector4::Vector4(const class Color4& c) {
|
||||
x = c.r;
|
||||
y = c.g;
|
||||
z = c.b;
|
||||
w = c.a;
|
||||
}
|
||||
|
||||
|
||||
Vector4::Vector4(const Vector2& v1, const Vector2& v2) {
|
||||
x = v1.x;
|
||||
y = v1.y;
|
||||
z = v2.x;
|
||||
w = v2.y;
|
||||
}
|
||||
|
||||
|
||||
Vector4::Vector4(const Vector2& v1, float fz, float fw) {
|
||||
x = v1.x;
|
||||
y = v1.y;
|
||||
z = fz;
|
||||
w = fw;
|
||||
}
|
||||
|
||||
Vector4::Vector4(BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Vector4::deserialize(BinaryInput& b) {
|
||||
x = b.readFloat32();
|
||||
y = b.readFloat32();
|
||||
z = b.readFloat32();
|
||||
w = b.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Vector4::serialize(BinaryOutput& b) const {
|
||||
b.writeFloat32(x);
|
||||
b.writeFloat32(y);
|
||||
b.writeFloat32(z);
|
||||
b.writeFloat32(w);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Vector4 Vector4::operator*(const Matrix4& M) const {
|
||||
Vector4 result;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
result[i] = 0.0f;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
result[i] += (*this)[j] * M[j][i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Vector4 Vector4::operator/ (float fScalar) const {
|
||||
Vector4 kQuot;
|
||||
|
||||
if ( fScalar != 0.0 ) {
|
||||
float fInvScalar = 1.0f / fScalar;
|
||||
kQuot.x = fInvScalar * x;
|
||||
kQuot.y = fInvScalar * y;
|
||||
kQuot.z = fInvScalar * z;
|
||||
kQuot.w = fInvScalar * w;
|
||||
return kQuot;
|
||||
} else {
|
||||
return Vector4::inf();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Vector4& Vector4::operator/= (float fScalar) {
|
||||
if (fScalar != 0.0f) {
|
||||
float fInvScalar = 1.0f / fScalar;
|
||||
x *= fInvScalar;
|
||||
y *= fInvScalar;
|
||||
z *= fInvScalar;
|
||||
w *= fInvScalar;
|
||||
} else {
|
||||
*this = Vector4::inf();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
std::string Vector4::toString() const {
|
||||
return G3D::format("(%g, %g, %g, %g)", x, y, z, w);
|
||||
}
|
||||
// 2-char swizzles
|
||||
|
||||
Vector2 Vector4::xx() const { return Vector2 (x, x); }
|
||||
Vector2 Vector4::yx() const { return Vector2 (y, x); }
|
||||
Vector2 Vector4::zx() const { return Vector2 (z, x); }
|
||||
Vector2 Vector4::wx() const { return Vector2 (w, x); }
|
||||
Vector2 Vector4::xy() const { return Vector2 (x, y); }
|
||||
Vector2 Vector4::yy() const { return Vector2 (y, y); }
|
||||
Vector2 Vector4::zy() const { return Vector2 (z, y); }
|
||||
Vector2 Vector4::wy() const { return Vector2 (w, y); }
|
||||
Vector2 Vector4::xz() const { return Vector2 (x, z); }
|
||||
Vector2 Vector4::yz() const { return Vector2 (y, z); }
|
||||
Vector2 Vector4::zz() const { return Vector2 (z, z); }
|
||||
Vector2 Vector4::wz() const { return Vector2 (w, z); }
|
||||
Vector2 Vector4::xw() const { return Vector2 (x, w); }
|
||||
Vector2 Vector4::yw() const { return Vector2 (y, w); }
|
||||
Vector2 Vector4::zw() const { return Vector2 (z, w); }
|
||||
Vector2 Vector4::ww() const { return Vector2 (w, w); }
|
||||
|
||||
// 3-char swizzles
|
||||
|
||||
Vector3 Vector4::xxx() const { return Vector3 (x, x, x); }
|
||||
Vector3 Vector4::yxx() const { return Vector3 (y, x, x); }
|
||||
Vector3 Vector4::zxx() const { return Vector3 (z, x, x); }
|
||||
Vector3 Vector4::wxx() const { return Vector3 (w, x, x); }
|
||||
Vector3 Vector4::xyx() const { return Vector3 (x, y, x); }
|
||||
Vector3 Vector4::yyx() const { return Vector3 (y, y, x); }
|
||||
Vector3 Vector4::zyx() const { return Vector3 (z, y, x); }
|
||||
Vector3 Vector4::wyx() const { return Vector3 (w, y, x); }
|
||||
Vector3 Vector4::xzx() const { return Vector3 (x, z, x); }
|
||||
Vector3 Vector4::yzx() const { return Vector3 (y, z, x); }
|
||||
Vector3 Vector4::zzx() const { return Vector3 (z, z, x); }
|
||||
Vector3 Vector4::wzx() const { return Vector3 (w, z, x); }
|
||||
Vector3 Vector4::xwx() const { return Vector3 (x, w, x); }
|
||||
Vector3 Vector4::ywx() const { return Vector3 (y, w, x); }
|
||||
Vector3 Vector4::zwx() const { return Vector3 (z, w, x); }
|
||||
Vector3 Vector4::wwx() const { return Vector3 (w, w, x); }
|
||||
Vector3 Vector4::xxy() const { return Vector3 (x, x, y); }
|
||||
Vector3 Vector4::yxy() const { return Vector3 (y, x, y); }
|
||||
Vector3 Vector4::zxy() const { return Vector3 (z, x, y); }
|
||||
Vector3 Vector4::wxy() const { return Vector3 (w, x, y); }
|
||||
Vector3 Vector4::xyy() const { return Vector3 (x, y, y); }
|
||||
Vector3 Vector4::yyy() const { return Vector3 (y, y, y); }
|
||||
Vector3 Vector4::zyy() const { return Vector3 (z, y, y); }
|
||||
Vector3 Vector4::wyy() const { return Vector3 (w, y, y); }
|
||||
Vector3 Vector4::xzy() const { return Vector3 (x, z, y); }
|
||||
Vector3 Vector4::yzy() const { return Vector3 (y, z, y); }
|
||||
Vector3 Vector4::zzy() const { return Vector3 (z, z, y); }
|
||||
Vector3 Vector4::wzy() const { return Vector3 (w, z, y); }
|
||||
Vector3 Vector4::xwy() const { return Vector3 (x, w, y); }
|
||||
Vector3 Vector4::ywy() const { return Vector3 (y, w, y); }
|
||||
Vector3 Vector4::zwy() const { return Vector3 (z, w, y); }
|
||||
Vector3 Vector4::wwy() const { return Vector3 (w, w, y); }
|
||||
Vector3 Vector4::xxz() const { return Vector3 (x, x, z); }
|
||||
Vector3 Vector4::yxz() const { return Vector3 (y, x, z); }
|
||||
Vector3 Vector4::zxz() const { return Vector3 (z, x, z); }
|
||||
Vector3 Vector4::wxz() const { return Vector3 (w, x, z); }
|
||||
Vector3 Vector4::xyz() const { return Vector3 (x, y, z); }
|
||||
Vector3 Vector4::yyz() const { return Vector3 (y, y, z); }
|
||||
Vector3 Vector4::zyz() const { return Vector3 (z, y, z); }
|
||||
Vector3 Vector4::wyz() const { return Vector3 (w, y, z); }
|
||||
Vector3 Vector4::xzz() const { return Vector3 (x, z, z); }
|
||||
Vector3 Vector4::yzz() const { return Vector3 (y, z, z); }
|
||||
Vector3 Vector4::zzz() const { return Vector3 (z, z, z); }
|
||||
Vector3 Vector4::wzz() const { return Vector3 (w, z, z); }
|
||||
Vector3 Vector4::xwz() const { return Vector3 (x, w, z); }
|
||||
Vector3 Vector4::ywz() const { return Vector3 (y, w, z); }
|
||||
Vector3 Vector4::zwz() const { return Vector3 (z, w, z); }
|
||||
Vector3 Vector4::wwz() const { return Vector3 (w, w, z); }
|
||||
Vector3 Vector4::xxw() const { return Vector3 (x, x, w); }
|
||||
Vector3 Vector4::yxw() const { return Vector3 (y, x, w); }
|
||||
Vector3 Vector4::zxw() const { return Vector3 (z, x, w); }
|
||||
Vector3 Vector4::wxw() const { return Vector3 (w, x, w); }
|
||||
Vector3 Vector4::xyw() const { return Vector3 (x, y, w); }
|
||||
Vector3 Vector4::yyw() const { return Vector3 (y, y, w); }
|
||||
Vector3 Vector4::zyw() const { return Vector3 (z, y, w); }
|
||||
Vector3 Vector4::wyw() const { return Vector3 (w, y, w); }
|
||||
Vector3 Vector4::xzw() const { return Vector3 (x, z, w); }
|
||||
Vector3 Vector4::yzw() const { return Vector3 (y, z, w); }
|
||||
Vector3 Vector4::zzw() const { return Vector3 (z, z, w); }
|
||||
Vector3 Vector4::wzw() const { return Vector3 (w, z, w); }
|
||||
Vector3 Vector4::xww() const { return Vector3 (x, w, w); }
|
||||
Vector3 Vector4::yww() const { return Vector3 (y, w, w); }
|
||||
Vector3 Vector4::zww() const { return Vector3 (z, w, w); }
|
||||
Vector3 Vector4::www() const { return Vector3 (w, w, w); }
|
||||
|
||||
// 4-char swizzles
|
||||
|
||||
Vector4 Vector4::xxxx() const { return Vector4 (x, x, x, x); }
|
||||
Vector4 Vector4::yxxx() const { return Vector4 (y, x, x, x); }
|
||||
Vector4 Vector4::zxxx() const { return Vector4 (z, x, x, x); }
|
||||
Vector4 Vector4::wxxx() const { return Vector4 (w, x, x, x); }
|
||||
Vector4 Vector4::xyxx() const { return Vector4 (x, y, x, x); }
|
||||
Vector4 Vector4::yyxx() const { return Vector4 (y, y, x, x); }
|
||||
Vector4 Vector4::zyxx() const { return Vector4 (z, y, x, x); }
|
||||
Vector4 Vector4::wyxx() const { return Vector4 (w, y, x, x); }
|
||||
Vector4 Vector4::xzxx() const { return Vector4 (x, z, x, x); }
|
||||
Vector4 Vector4::yzxx() const { return Vector4 (y, z, x, x); }
|
||||
Vector4 Vector4::zzxx() const { return Vector4 (z, z, x, x); }
|
||||
Vector4 Vector4::wzxx() const { return Vector4 (w, z, x, x); }
|
||||
Vector4 Vector4::xwxx() const { return Vector4 (x, w, x, x); }
|
||||
Vector4 Vector4::ywxx() const { return Vector4 (y, w, x, x); }
|
||||
Vector4 Vector4::zwxx() const { return Vector4 (z, w, x, x); }
|
||||
Vector4 Vector4::wwxx() const { return Vector4 (w, w, x, x); }
|
||||
Vector4 Vector4::xxyx() const { return Vector4 (x, x, y, x); }
|
||||
Vector4 Vector4::yxyx() const { return Vector4 (y, x, y, x); }
|
||||
Vector4 Vector4::zxyx() const { return Vector4 (z, x, y, x); }
|
||||
Vector4 Vector4::wxyx() const { return Vector4 (w, x, y, x); }
|
||||
Vector4 Vector4::xyyx() const { return Vector4 (x, y, y, x); }
|
||||
Vector4 Vector4::yyyx() const { return Vector4 (y, y, y, x); }
|
||||
Vector4 Vector4::zyyx() const { return Vector4 (z, y, y, x); }
|
||||
Vector4 Vector4::wyyx() const { return Vector4 (w, y, y, x); }
|
||||
Vector4 Vector4::xzyx() const { return Vector4 (x, z, y, x); }
|
||||
Vector4 Vector4::yzyx() const { return Vector4 (y, z, y, x); }
|
||||
Vector4 Vector4::zzyx() const { return Vector4 (z, z, y, x); }
|
||||
Vector4 Vector4::wzyx() const { return Vector4 (w, z, y, x); }
|
||||
Vector4 Vector4::xwyx() const { return Vector4 (x, w, y, x); }
|
||||
Vector4 Vector4::ywyx() const { return Vector4 (y, w, y, x); }
|
||||
Vector4 Vector4::zwyx() const { return Vector4 (z, w, y, x); }
|
||||
Vector4 Vector4::wwyx() const { return Vector4 (w, w, y, x); }
|
||||
Vector4 Vector4::xxzx() const { return Vector4 (x, x, z, x); }
|
||||
Vector4 Vector4::yxzx() const { return Vector4 (y, x, z, x); }
|
||||
Vector4 Vector4::zxzx() const { return Vector4 (z, x, z, x); }
|
||||
Vector4 Vector4::wxzx() const { return Vector4 (w, x, z, x); }
|
||||
Vector4 Vector4::xyzx() const { return Vector4 (x, y, z, x); }
|
||||
Vector4 Vector4::yyzx() const { return Vector4 (y, y, z, x); }
|
||||
Vector4 Vector4::zyzx() const { return Vector4 (z, y, z, x); }
|
||||
Vector4 Vector4::wyzx() const { return Vector4 (w, y, z, x); }
|
||||
Vector4 Vector4::xzzx() const { return Vector4 (x, z, z, x); }
|
||||
Vector4 Vector4::yzzx() const { return Vector4 (y, z, z, x); }
|
||||
Vector4 Vector4::zzzx() const { return Vector4 (z, z, z, x); }
|
||||
Vector4 Vector4::wzzx() const { return Vector4 (w, z, z, x); }
|
||||
Vector4 Vector4::xwzx() const { return Vector4 (x, w, z, x); }
|
||||
Vector4 Vector4::ywzx() const { return Vector4 (y, w, z, x); }
|
||||
Vector4 Vector4::zwzx() const { return Vector4 (z, w, z, x); }
|
||||
Vector4 Vector4::wwzx() const { return Vector4 (w, w, z, x); }
|
||||
Vector4 Vector4::xxwx() const { return Vector4 (x, x, w, x); }
|
||||
Vector4 Vector4::yxwx() const { return Vector4 (y, x, w, x); }
|
||||
Vector4 Vector4::zxwx() const { return Vector4 (z, x, w, x); }
|
||||
Vector4 Vector4::wxwx() const { return Vector4 (w, x, w, x); }
|
||||
Vector4 Vector4::xywx() const { return Vector4 (x, y, w, x); }
|
||||
Vector4 Vector4::yywx() const { return Vector4 (y, y, w, x); }
|
||||
Vector4 Vector4::zywx() const { return Vector4 (z, y, w, x); }
|
||||
Vector4 Vector4::wywx() const { return Vector4 (w, y, w, x); }
|
||||
Vector4 Vector4::xzwx() const { return Vector4 (x, z, w, x); }
|
||||
Vector4 Vector4::yzwx() const { return Vector4 (y, z, w, x); }
|
||||
Vector4 Vector4::zzwx() const { return Vector4 (z, z, w, x); }
|
||||
Vector4 Vector4::wzwx() const { return Vector4 (w, z, w, x); }
|
||||
Vector4 Vector4::xwwx() const { return Vector4 (x, w, w, x); }
|
||||
Vector4 Vector4::ywwx() const { return Vector4 (y, w, w, x); }
|
||||
Vector4 Vector4::zwwx() const { return Vector4 (z, w, w, x); }
|
||||
Vector4 Vector4::wwwx() const { return Vector4 (w, w, w, x); }
|
||||
Vector4 Vector4::xxxy() const { return Vector4 (x, x, x, y); }
|
||||
Vector4 Vector4::yxxy() const { return Vector4 (y, x, x, y); }
|
||||
Vector4 Vector4::zxxy() const { return Vector4 (z, x, x, y); }
|
||||
Vector4 Vector4::wxxy() const { return Vector4 (w, x, x, y); }
|
||||
Vector4 Vector4::xyxy() const { return Vector4 (x, y, x, y); }
|
||||
Vector4 Vector4::yyxy() const { return Vector4 (y, y, x, y); }
|
||||
Vector4 Vector4::zyxy() const { return Vector4 (z, y, x, y); }
|
||||
Vector4 Vector4::wyxy() const { return Vector4 (w, y, x, y); }
|
||||
Vector4 Vector4::xzxy() const { return Vector4 (x, z, x, y); }
|
||||
Vector4 Vector4::yzxy() const { return Vector4 (y, z, x, y); }
|
||||
Vector4 Vector4::zzxy() const { return Vector4 (z, z, x, y); }
|
||||
Vector4 Vector4::wzxy() const { return Vector4 (w, z, x, y); }
|
||||
Vector4 Vector4::xwxy() const { return Vector4 (x, w, x, y); }
|
||||
Vector4 Vector4::ywxy() const { return Vector4 (y, w, x, y); }
|
||||
Vector4 Vector4::zwxy() const { return Vector4 (z, w, x, y); }
|
||||
Vector4 Vector4::wwxy() const { return Vector4 (w, w, x, y); }
|
||||
Vector4 Vector4::xxyy() const { return Vector4 (x, x, y, y); }
|
||||
Vector4 Vector4::yxyy() const { return Vector4 (y, x, y, y); }
|
||||
Vector4 Vector4::zxyy() const { return Vector4 (z, x, y, y); }
|
||||
Vector4 Vector4::wxyy() const { return Vector4 (w, x, y, y); }
|
||||
Vector4 Vector4::xyyy() const { return Vector4 (x, y, y, y); }
|
||||
Vector4 Vector4::yyyy() const { return Vector4 (y, y, y, y); }
|
||||
Vector4 Vector4::zyyy() const { return Vector4 (z, y, y, y); }
|
||||
Vector4 Vector4::wyyy() const { return Vector4 (w, y, y, y); }
|
||||
Vector4 Vector4::xzyy() const { return Vector4 (x, z, y, y); }
|
||||
Vector4 Vector4::yzyy() const { return Vector4 (y, z, y, y); }
|
||||
Vector4 Vector4::zzyy() const { return Vector4 (z, z, y, y); }
|
||||
Vector4 Vector4::wzyy() const { return Vector4 (w, z, y, y); }
|
||||
Vector4 Vector4::xwyy() const { return Vector4 (x, w, y, y); }
|
||||
Vector4 Vector4::ywyy() const { return Vector4 (y, w, y, y); }
|
||||
Vector4 Vector4::zwyy() const { return Vector4 (z, w, y, y); }
|
||||
Vector4 Vector4::wwyy() const { return Vector4 (w, w, y, y); }
|
||||
Vector4 Vector4::xxzy() const { return Vector4 (x, x, z, y); }
|
||||
Vector4 Vector4::yxzy() const { return Vector4 (y, x, z, y); }
|
||||
Vector4 Vector4::zxzy() const { return Vector4 (z, x, z, y); }
|
||||
Vector4 Vector4::wxzy() const { return Vector4 (w, x, z, y); }
|
||||
Vector4 Vector4::xyzy() const { return Vector4 (x, y, z, y); }
|
||||
Vector4 Vector4::yyzy() const { return Vector4 (y, y, z, y); }
|
||||
Vector4 Vector4::zyzy() const { return Vector4 (z, y, z, y); }
|
||||
Vector4 Vector4::wyzy() const { return Vector4 (w, y, z, y); }
|
||||
Vector4 Vector4::xzzy() const { return Vector4 (x, z, z, y); }
|
||||
Vector4 Vector4::yzzy() const { return Vector4 (y, z, z, y); }
|
||||
Vector4 Vector4::zzzy() const { return Vector4 (z, z, z, y); }
|
||||
Vector4 Vector4::wzzy() const { return Vector4 (w, z, z, y); }
|
||||
Vector4 Vector4::xwzy() const { return Vector4 (x, w, z, y); }
|
||||
Vector4 Vector4::ywzy() const { return Vector4 (y, w, z, y); }
|
||||
Vector4 Vector4::zwzy() const { return Vector4 (z, w, z, y); }
|
||||
Vector4 Vector4::wwzy() const { return Vector4 (w, w, z, y); }
|
||||
Vector4 Vector4::xxwy() const { return Vector4 (x, x, w, y); }
|
||||
Vector4 Vector4::yxwy() const { return Vector4 (y, x, w, y); }
|
||||
Vector4 Vector4::zxwy() const { return Vector4 (z, x, w, y); }
|
||||
Vector4 Vector4::wxwy() const { return Vector4 (w, x, w, y); }
|
||||
Vector4 Vector4::xywy() const { return Vector4 (x, y, w, y); }
|
||||
Vector4 Vector4::yywy() const { return Vector4 (y, y, w, y); }
|
||||
Vector4 Vector4::zywy() const { return Vector4 (z, y, w, y); }
|
||||
Vector4 Vector4::wywy() const { return Vector4 (w, y, w, y); }
|
||||
Vector4 Vector4::xzwy() const { return Vector4 (x, z, w, y); }
|
||||
Vector4 Vector4::yzwy() const { return Vector4 (y, z, w, y); }
|
||||
Vector4 Vector4::zzwy() const { return Vector4 (z, z, w, y); }
|
||||
Vector4 Vector4::wzwy() const { return Vector4 (w, z, w, y); }
|
||||
Vector4 Vector4::xwwy() const { return Vector4 (x, w, w, y); }
|
||||
Vector4 Vector4::ywwy() const { return Vector4 (y, w, w, y); }
|
||||
Vector4 Vector4::zwwy() const { return Vector4 (z, w, w, y); }
|
||||
Vector4 Vector4::wwwy() const { return Vector4 (w, w, w, y); }
|
||||
Vector4 Vector4::xxxz() const { return Vector4 (x, x, x, z); }
|
||||
Vector4 Vector4::yxxz() const { return Vector4 (y, x, x, z); }
|
||||
Vector4 Vector4::zxxz() const { return Vector4 (z, x, x, z); }
|
||||
Vector4 Vector4::wxxz() const { return Vector4 (w, x, x, z); }
|
||||
Vector4 Vector4::xyxz() const { return Vector4 (x, y, x, z); }
|
||||
Vector4 Vector4::yyxz() const { return Vector4 (y, y, x, z); }
|
||||
Vector4 Vector4::zyxz() const { return Vector4 (z, y, x, z); }
|
||||
Vector4 Vector4::wyxz() const { return Vector4 (w, y, x, z); }
|
||||
Vector4 Vector4::xzxz() const { return Vector4 (x, z, x, z); }
|
||||
Vector4 Vector4::yzxz() const { return Vector4 (y, z, x, z); }
|
||||
Vector4 Vector4::zzxz() const { return Vector4 (z, z, x, z); }
|
||||
Vector4 Vector4::wzxz() const { return Vector4 (w, z, x, z); }
|
||||
Vector4 Vector4::xwxz() const { return Vector4 (x, w, x, z); }
|
||||
Vector4 Vector4::ywxz() const { return Vector4 (y, w, x, z); }
|
||||
Vector4 Vector4::zwxz() const { return Vector4 (z, w, x, z); }
|
||||
Vector4 Vector4::wwxz() const { return Vector4 (w, w, x, z); }
|
||||
Vector4 Vector4::xxyz() const { return Vector4 (x, x, y, z); }
|
||||
Vector4 Vector4::yxyz() const { return Vector4 (y, x, y, z); }
|
||||
Vector4 Vector4::zxyz() const { return Vector4 (z, x, y, z); }
|
||||
Vector4 Vector4::wxyz() const { return Vector4 (w, x, y, z); }
|
||||
Vector4 Vector4::xyyz() const { return Vector4 (x, y, y, z); }
|
||||
Vector4 Vector4::yyyz() const { return Vector4 (y, y, y, z); }
|
||||
Vector4 Vector4::zyyz() const { return Vector4 (z, y, y, z); }
|
||||
Vector4 Vector4::wyyz() const { return Vector4 (w, y, y, z); }
|
||||
Vector4 Vector4::xzyz() const { return Vector4 (x, z, y, z); }
|
||||
Vector4 Vector4::yzyz() const { return Vector4 (y, z, y, z); }
|
||||
Vector4 Vector4::zzyz() const { return Vector4 (z, z, y, z); }
|
||||
Vector4 Vector4::wzyz() const { return Vector4 (w, z, y, z); }
|
||||
Vector4 Vector4::xwyz() const { return Vector4 (x, w, y, z); }
|
||||
Vector4 Vector4::ywyz() const { return Vector4 (y, w, y, z); }
|
||||
Vector4 Vector4::zwyz() const { return Vector4 (z, w, y, z); }
|
||||
Vector4 Vector4::wwyz() const { return Vector4 (w, w, y, z); }
|
||||
Vector4 Vector4::xxzz() const { return Vector4 (x, x, z, z); }
|
||||
Vector4 Vector4::yxzz() const { return Vector4 (y, x, z, z); }
|
||||
Vector4 Vector4::zxzz() const { return Vector4 (z, x, z, z); }
|
||||
Vector4 Vector4::wxzz() const { return Vector4 (w, x, z, z); }
|
||||
Vector4 Vector4::xyzz() const { return Vector4 (x, y, z, z); }
|
||||
Vector4 Vector4::yyzz() const { return Vector4 (y, y, z, z); }
|
||||
Vector4 Vector4::zyzz() const { return Vector4 (z, y, z, z); }
|
||||
Vector4 Vector4::wyzz() const { return Vector4 (w, y, z, z); }
|
||||
Vector4 Vector4::xzzz() const { return Vector4 (x, z, z, z); }
|
||||
Vector4 Vector4::yzzz() const { return Vector4 (y, z, z, z); }
|
||||
Vector4 Vector4::zzzz() const { return Vector4 (z, z, z, z); }
|
||||
Vector4 Vector4::wzzz() const { return Vector4 (w, z, z, z); }
|
||||
Vector4 Vector4::xwzz() const { return Vector4 (x, w, z, z); }
|
||||
Vector4 Vector4::ywzz() const { return Vector4 (y, w, z, z); }
|
||||
Vector4 Vector4::zwzz() const { return Vector4 (z, w, z, z); }
|
||||
Vector4 Vector4::wwzz() const { return Vector4 (w, w, z, z); }
|
||||
Vector4 Vector4::xxwz() const { return Vector4 (x, x, w, z); }
|
||||
Vector4 Vector4::yxwz() const { return Vector4 (y, x, w, z); }
|
||||
Vector4 Vector4::zxwz() const { return Vector4 (z, x, w, z); }
|
||||
Vector4 Vector4::wxwz() const { return Vector4 (w, x, w, z); }
|
||||
Vector4 Vector4::xywz() const { return Vector4 (x, y, w, z); }
|
||||
Vector4 Vector4::yywz() const { return Vector4 (y, y, w, z); }
|
||||
Vector4 Vector4::zywz() const { return Vector4 (z, y, w, z); }
|
||||
Vector4 Vector4::wywz() const { return Vector4 (w, y, w, z); }
|
||||
Vector4 Vector4::xzwz() const { return Vector4 (x, z, w, z); }
|
||||
Vector4 Vector4::yzwz() const { return Vector4 (y, z, w, z); }
|
||||
Vector4 Vector4::zzwz() const { return Vector4 (z, z, w, z); }
|
||||
Vector4 Vector4::wzwz() const { return Vector4 (w, z, w, z); }
|
||||
Vector4 Vector4::xwwz() const { return Vector4 (x, w, w, z); }
|
||||
Vector4 Vector4::ywwz() const { return Vector4 (y, w, w, z); }
|
||||
Vector4 Vector4::zwwz() const { return Vector4 (z, w, w, z); }
|
||||
Vector4 Vector4::wwwz() const { return Vector4 (w, w, w, z); }
|
||||
Vector4 Vector4::xxxw() const { return Vector4 (x, x, x, w); }
|
||||
Vector4 Vector4::yxxw() const { return Vector4 (y, x, x, w); }
|
||||
Vector4 Vector4::zxxw() const { return Vector4 (z, x, x, w); }
|
||||
Vector4 Vector4::wxxw() const { return Vector4 (w, x, x, w); }
|
||||
Vector4 Vector4::xyxw() const { return Vector4 (x, y, x, w); }
|
||||
Vector4 Vector4::yyxw() const { return Vector4 (y, y, x, w); }
|
||||
Vector4 Vector4::zyxw() const { return Vector4 (z, y, x, w); }
|
||||
Vector4 Vector4::wyxw() const { return Vector4 (w, y, x, w); }
|
||||
Vector4 Vector4::xzxw() const { return Vector4 (x, z, x, w); }
|
||||
Vector4 Vector4::yzxw() const { return Vector4 (y, z, x, w); }
|
||||
Vector4 Vector4::zzxw() const { return Vector4 (z, z, x, w); }
|
||||
Vector4 Vector4::wzxw() const { return Vector4 (w, z, x, w); }
|
||||
Vector4 Vector4::xwxw() const { return Vector4 (x, w, x, w); }
|
||||
Vector4 Vector4::ywxw() const { return Vector4 (y, w, x, w); }
|
||||
Vector4 Vector4::zwxw() const { return Vector4 (z, w, x, w); }
|
||||
Vector4 Vector4::wwxw() const { return Vector4 (w, w, x, w); }
|
||||
Vector4 Vector4::xxyw() const { return Vector4 (x, x, y, w); }
|
||||
Vector4 Vector4::yxyw() const { return Vector4 (y, x, y, w); }
|
||||
Vector4 Vector4::zxyw() const { return Vector4 (z, x, y, w); }
|
||||
Vector4 Vector4::wxyw() const { return Vector4 (w, x, y, w); }
|
||||
Vector4 Vector4::xyyw() const { return Vector4 (x, y, y, w); }
|
||||
Vector4 Vector4::yyyw() const { return Vector4 (y, y, y, w); }
|
||||
Vector4 Vector4::zyyw() const { return Vector4 (z, y, y, w); }
|
||||
Vector4 Vector4::wyyw() const { return Vector4 (w, y, y, w); }
|
||||
Vector4 Vector4::xzyw() const { return Vector4 (x, z, y, w); }
|
||||
Vector4 Vector4::yzyw() const { return Vector4 (y, z, y, w); }
|
||||
Vector4 Vector4::zzyw() const { return Vector4 (z, z, y, w); }
|
||||
Vector4 Vector4::wzyw() const { return Vector4 (w, z, y, w); }
|
||||
Vector4 Vector4::xwyw() const { return Vector4 (x, w, y, w); }
|
||||
Vector4 Vector4::ywyw() const { return Vector4 (y, w, y, w); }
|
||||
Vector4 Vector4::zwyw() const { return Vector4 (z, w, y, w); }
|
||||
Vector4 Vector4::wwyw() const { return Vector4 (w, w, y, w); }
|
||||
Vector4 Vector4::xxzw() const { return Vector4 (x, x, z, w); }
|
||||
Vector4 Vector4::yxzw() const { return Vector4 (y, x, z, w); }
|
||||
Vector4 Vector4::zxzw() const { return Vector4 (z, x, z, w); }
|
||||
Vector4 Vector4::wxzw() const { return Vector4 (w, x, z, w); }
|
||||
Vector4 Vector4::xyzw() const { return Vector4 (x, y, z, w); }
|
||||
Vector4 Vector4::yyzw() const { return Vector4 (y, y, z, w); }
|
||||
Vector4 Vector4::zyzw() const { return Vector4 (z, y, z, w); }
|
||||
Vector4 Vector4::wyzw() const { return Vector4 (w, y, z, w); }
|
||||
Vector4 Vector4::xzzw() const { return Vector4 (x, z, z, w); }
|
||||
Vector4 Vector4::yzzw() const { return Vector4 (y, z, z, w); }
|
||||
Vector4 Vector4::zzzw() const { return Vector4 (z, z, z, w); }
|
||||
Vector4 Vector4::wzzw() const { return Vector4 (w, z, z, w); }
|
||||
Vector4 Vector4::xwzw() const { return Vector4 (x, w, z, w); }
|
||||
Vector4 Vector4::ywzw() const { return Vector4 (y, w, z, w); }
|
||||
Vector4 Vector4::zwzw() const { return Vector4 (z, w, z, w); }
|
||||
Vector4 Vector4::wwzw() const { return Vector4 (w, w, z, w); }
|
||||
Vector4 Vector4::xxww() const { return Vector4 (x, x, w, w); }
|
||||
Vector4 Vector4::yxww() const { return Vector4 (y, x, w, w); }
|
||||
Vector4 Vector4::zxww() const { return Vector4 (z, x, w, w); }
|
||||
Vector4 Vector4::wxww() const { return Vector4 (w, x, w, w); }
|
||||
Vector4 Vector4::xyww() const { return Vector4 (x, y, w, w); }
|
||||
Vector4 Vector4::yyww() const { return Vector4 (y, y, w, w); }
|
||||
Vector4 Vector4::zyww() const { return Vector4 (z, y, w, w); }
|
||||
Vector4 Vector4::wyww() const { return Vector4 (w, y, w, w); }
|
||||
Vector4 Vector4::xzww() const { return Vector4 (x, z, w, w); }
|
||||
Vector4 Vector4::yzww() const { return Vector4 (y, z, w, w); }
|
||||
Vector4 Vector4::zzww() const { return Vector4 (z, z, w, w); }
|
||||
Vector4 Vector4::wzww() const { return Vector4 (w, z, w, w); }
|
||||
Vector4 Vector4::xwww() const { return Vector4 (x, w, w, w); }
|
||||
Vector4 Vector4::ywww() const { return Vector4 (y, w, w, w); }
|
||||
Vector4 Vector4::zwww() const { return Vector4 (z, w, w, w); }
|
||||
Vector4 Vector4::wwww() const { return Vector4 (w, w, w, w); }
|
||||
|
||||
|
||||
}; // namespace
|
||||
58
modules/acore/deps/g3dlite/source/Vector4int8.cpp
Normal file
58
modules/acore/deps/g3dlite/source/Vector4int8.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
@file Vector4int8.cpp
|
||||
|
||||
Homogeneous vector class.
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-02-09
|
||||
@edited 2007-02-09
|
||||
|
||||
Copyright 2000-2007, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Vector4int8.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/Vector4.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include <string>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector4int8::Vector4int8(const Vector4& source) {
|
||||
x = iClamp(iRound(source.x), -128, 127);
|
||||
y = iClamp(iRound(source.y), -128, 127);
|
||||
z = iClamp(iRound(source.z), -128, 127);
|
||||
w = iClamp(iRound(source.w), -128, 127);
|
||||
}
|
||||
|
||||
Vector4int8::Vector4int8(const Vector3& source, int8 w) : w(w) {
|
||||
x = iClamp(iRound(source.x), -128, 127);
|
||||
y = iClamp(iRound(source.y), -128, 127);
|
||||
z = iClamp(iRound(source.z), -128, 127);
|
||||
}
|
||||
|
||||
Vector4int8::Vector4int8(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
void Vector4int8::serialize(class BinaryOutput& b) const {
|
||||
// Intentionally write individual bytes to avoid endian issues
|
||||
b.writeInt8(x);
|
||||
b.writeInt8(y);
|
||||
b.writeInt8(z);
|
||||
b.writeInt8(w);
|
||||
}
|
||||
|
||||
void Vector4int8::deserialize(class BinaryInput& b) {
|
||||
x = b.readInt8();
|
||||
y = b.readInt8();
|
||||
z = b.readInt8();
|
||||
w = b.readInt8();
|
||||
}
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
425
modules/acore/deps/g3dlite/source/Welder.cpp
Normal file
425
modules/acore/deps/g3dlite/source/Welder.cpp
Normal file
@@ -0,0 +1,425 @@
|
||||
/**
|
||||
@file Welder.cpp
|
||||
|
||||
@author Morgan McGuire, Kyle Whitson, Corey Taylor
|
||||
|
||||
@created 2008-07-30
|
||||
@edited 2009-11-29
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Vector2.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/PointHashGrid.h"
|
||||
#include "G3D/Welder.h"
|
||||
#include "G3D/Stopwatch.h" // for profiling
|
||||
#include "G3D/AreaMemoryManager.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D { namespace _internal{
|
||||
|
||||
|
||||
/** Used by WeldHelper2::smoothNormals. */
|
||||
class VN {
|
||||
public:
|
||||
Vector3 vertex;
|
||||
Vector3 normal;
|
||||
|
||||
VN() {}
|
||||
VN(const Vector3& v, const Vector3& n) : vertex(v), normal(n) {}
|
||||
};
|
||||
|
||||
/** Used by WeldHelper::getIndex to maintain a list of vertices by location. */
|
||||
class VNTi {
|
||||
public:
|
||||
Vector3 vertex;
|
||||
Vector3 normal;
|
||||
Vector2 texCoord;
|
||||
int index;
|
||||
|
||||
VNTi() : index(0) {}
|
||||
|
||||
VNTi(const Vector3& v, const Vector3& n, const Vector2& t, int i) :
|
||||
vertex(v), normal(n), texCoord(t), index(i) {}
|
||||
};
|
||||
|
||||
|
||||
}} // G3D
|
||||
|
||||
template <> struct HashTrait <G3D::_internal::VN> {
|
||||
static size_t hashCode(const G3D::_internal::VN& k) { return static_cast<size_t>(k.vertex.hashCode()); }
|
||||
};
|
||||
template <> struct HashTrait <G3D::_internal::VNTi> {
|
||||
static size_t hashCode(const G3D::_internal::VNTi& k) { return static_cast<size_t>(k.vertex.hashCode()); }
|
||||
};
|
||||
|
||||
|
||||
template<> struct EqualsTrait <G3D::_internal::VN> {
|
||||
static bool equals(const G3D::_internal::VN& a, const G3D::_internal::VN& b) { return a.vertex == b.vertex; }
|
||||
};
|
||||
template<> struct EqualsTrait <G3D::_internal::VNTi> {
|
||||
static bool equals(const G3D::_internal::VNTi& a, const G3D::_internal::VNTi& b) { return a.vertex == b.vertex; }
|
||||
};
|
||||
|
||||
template<> struct PositionTrait<G3D::_internal::VN> {
|
||||
static void getPosition(const G3D::_internal::VN& v, G3D::Vector3& p) { p = v.vertex; }
|
||||
};
|
||||
template<> struct PositionTrait<G3D::_internal::VNTi> {
|
||||
static void getPosition(const G3D::_internal::VNTi& v, G3D::Vector3& p) { p = v.vertex; }
|
||||
};
|
||||
|
||||
namespace G3D { namespace _internal {
|
||||
|
||||
class WeldHelper {
|
||||
private:
|
||||
/** Used by getIndex and updateTriLists. Deallocating this is slow. */
|
||||
PointHashGrid<VNTi> weldGrid;
|
||||
|
||||
Array<Vector3>* outputVertexArray;
|
||||
Array<Vector3>* outputNormalArray;
|
||||
Array<Vector2>* outputTexCoordArray;
|
||||
|
||||
float vertexWeldRadius;
|
||||
/** Squared radius allowed for welding similar normals. */
|
||||
float normalWeldRadius2;
|
||||
float texCoordWeldRadius2;
|
||||
|
||||
float normalSmoothingAngle;
|
||||
|
||||
/**
|
||||
Returns the index of the vertex in
|
||||
outputVertexArray/outputNormalArray/outputTexCoordArray
|
||||
that is within the global tolerances of v,n,t. If there
|
||||
is no such vertex, adds it to the arrays and returns that index.
|
||||
|
||||
Called from updateTriLists().
|
||||
*/
|
||||
int getIndex(const Vector3& v, const Vector3& n, const Vector2& t) {
|
||||
PointHashGrid<VNTi>::SphereIterator it =
|
||||
weldGrid.beginSphereIntersection(Sphere(v, vertexWeldRadius));
|
||||
|
||||
if (n.isZero()) {
|
||||
// Don't bother trying to match the surface normal, since this vertex has no surface normal.
|
||||
while (it.hasMore()) {
|
||||
if ((t - it->texCoord).squaredLength() <= texCoordWeldRadius2) {
|
||||
// This is the vertex
|
||||
return it->index;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
} else {
|
||||
while (it.hasMore()) {
|
||||
if (((n - it->normal).squaredLength() <= normalWeldRadius2) &&
|
||||
((t - it->texCoord).squaredLength() <= texCoordWeldRadius2)) {
|
||||
// This is the vertex
|
||||
return it->index;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Note that a sliver triangle processed before its neighbors may reach here
|
||||
// with a zero length normal.
|
||||
|
||||
// The vertex does not exist. Create it.
|
||||
const int i = outputVertexArray->size();
|
||||
outputVertexArray->append(v);
|
||||
outputNormalArray->append(n);
|
||||
outputTexCoordArray->append(t);
|
||||
|
||||
// Store in the grid so that it will be remembered.
|
||||
weldGrid.insert(VNTi(v, n, t, i));
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Updates each indexArray to refer to vertices in the
|
||||
outputVertexArray.
|
||||
|
||||
Called from process()
|
||||
*/
|
||||
void updateTriLists(
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector3>& normalArray,
|
||||
const Array<Vector2>& texCoordArray) {
|
||||
|
||||
// Compute a hash grid so that we can find neighbors quickly.
|
||||
// It begins empty and is extended as the tri lists are iterated
|
||||
// through.
|
||||
weldGrid.clear();
|
||||
|
||||
// Process all triLists
|
||||
int numTriLists = indexArrayArray.size();
|
||||
int u = 0;
|
||||
for (int t = 0; t < numTriLists; ++t) {
|
||||
if (indexArrayArray[t] != NULL) {
|
||||
Array<int>& triList = *(indexArrayArray[t]);
|
||||
|
||||
// For all vertices in this list
|
||||
for (int v = 0; v < triList.size(); ++v) {
|
||||
// This vertex mapped to u in the flatVertexArray
|
||||
triList[v] = getIndex(vertexArray[u], normalArray[u], texCoordArray[u]);
|
||||
|
||||
/*
|
||||
# ifdef G3D_DEBUG
|
||||
{
|
||||
int i = triList[v];
|
||||
Vector3 N = normalArray[i];
|
||||
debugAssertM(N.length() > 0.9f, "Produced non-unit normal");
|
||||
}
|
||||
# endif
|
||||
*/
|
||||
++u;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Expands the indexed triangle lists into a triangle list.
|
||||
|
||||
Called from process() */
|
||||
void unroll(
|
||||
const Array<Array<int>*>& indexArrayArray,
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& unrolledVertexArray,
|
||||
Array<Vector2>& unrolledTexCoordArray) {
|
||||
|
||||
int numTriLists = indexArrayArray.size();
|
||||
for (int t = 0; t < numTriLists; ++t) {
|
||||
if (indexArrayArray[t] != NULL) {
|
||||
const Array<int>& triList = *(indexArrayArray[t]);
|
||||
for (int v = 0; v < triList.size(); ++v) {
|
||||
int i = triList[v];
|
||||
unrolledVertexArray.append(vertexArray[i]);
|
||||
unrolledTexCoordArray.append(texCoordArray[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** For every three vertices, compute the face normal and store it three times.
|
||||
Sliver triangles have a zero surface normal, which we will later take to
|
||||
match *any* surface normal. */
|
||||
void computeFaceNormals(
|
||||
const Array<Vector3>& vertexArray,
|
||||
Array<Vector3>& faceNormalArray) {
|
||||
|
||||
debugAssertM(vertexArray.size() % 3 == 0, "Input is not a triangle soup");
|
||||
debugAssertM(faceNormalArray.size() == 0, "Output must start empty.");
|
||||
|
||||
for (int v = 0; v < vertexArray.size(); v += 3) {
|
||||
const Vector3& e0 = vertexArray[v + 1] - vertexArray[v];
|
||||
const Vector3& e1 = vertexArray[v + 2] - vertexArray[v];
|
||||
|
||||
// Note that the length may be zero in the case of sliver polygons, e.g.,
|
||||
// those correcting a T-junction. Scale up by 256 to avoid underflow when
|
||||
// multiplying very small edges
|
||||
const Vector3& n = (e0.cross(e1 * 256.0f)).directionOrZero();
|
||||
|
||||
// Append the normal once per vertex.
|
||||
faceNormalArray.append(n, n, n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Computes @a smoothNormalArray, whose elements are those of normalArray averaged
|
||||
with neighbors within the angular cutoff.
|
||||
*/
|
||||
void smoothNormals(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector3>& normalArray,
|
||||
Array<Vector3>& smoothNormalArray) {
|
||||
|
||||
if (normalSmoothingAngle <= 0) {
|
||||
smoothNormalArray = normalArray;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create an area memory manager for fast deallocation
|
||||
MemoryManager::Ref mm = AreaMemoryManager::create(iRound(sizeof(VN) * normalArray.size() * 1.5));
|
||||
|
||||
const float cosThresholdAngle = (float)cos(normalSmoothingAngle);
|
||||
|
||||
debugAssert(vertexArray.size() == normalArray.size());
|
||||
smoothNormalArray.resize(normalArray.size());
|
||||
|
||||
// Compute a hash grid so that we can find neighbors quickly.
|
||||
PointHashGrid<VN> grid(vertexWeldRadius, mm);
|
||||
for (int v = 0; v < normalArray.size(); ++v) {
|
||||
grid.insert(VN(vertexArray[v], normalArray[v]));
|
||||
}
|
||||
|
||||
// TODO: this step could be done on multiple threads
|
||||
for (int v = 0; v < normalArray.size(); ++v) {
|
||||
// Compute the sum of all nearby normals within the cutoff angle.
|
||||
// Search within the vertexWeldRadius, since those are the vertices
|
||||
// that will collapse to the same point.
|
||||
PointHashGrid<VN>::SphereIterator it =
|
||||
grid.beginSphereIntersection(Sphere(vertexArray[v], vertexWeldRadius));
|
||||
|
||||
Vector3 sum;
|
||||
|
||||
const Vector3& original = normalArray[v];
|
||||
while (it.hasMore()) {
|
||||
const Vector3& N = it->normal;
|
||||
const float cosAngle = N.dot(original);
|
||||
|
||||
if (cosAngle > cosThresholdAngle) {
|
||||
// This normal is close enough to consider. Avoid underflow by scaling up
|
||||
sum += (N * 256.0f);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
const Vector3& average = sum.directionOrZero();
|
||||
|
||||
const bool indeterminate = average.isZero();
|
||||
// Never "smooth" a normal so far that it points backwards
|
||||
const bool backFacing = original.dot(average) < 0;
|
||||
|
||||
if (indeterminate || backFacing) {
|
||||
// Revert to the face normal
|
||||
smoothNormalArray[v] = original;
|
||||
} else {
|
||||
// Average available normals
|
||||
smoothNormalArray[v] = average;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
Algorithm:
|
||||
|
||||
1. Unroll the indexed triangle list into a triangle list, where
|
||||
there are duplicated vertices.
|
||||
|
||||
2. Compute face normals for all triangles, and expand those into
|
||||
the triangle vertices.
|
||||
|
||||
3. At each vertex, average all normals that are within normalSmoothingAngle.
|
||||
|
||||
4. Generate output indexArrayArray. While doing so, merge all vertices where
|
||||
the distance between position, texCoord, and normal is within the thresholds.
|
||||
*/
|
||||
void process(
|
||||
Array<Vector3>& vertexArray,
|
||||
Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& normalArray,
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
float normAngle,
|
||||
float texRadius,
|
||||
float normRadius) {
|
||||
|
||||
normalSmoothingAngle = normAngle;
|
||||
normalWeldRadius2 = square(normRadius);
|
||||
texCoordWeldRadius2 = square(texRadius);
|
||||
|
||||
const bool hasTexCoords = (texCoordArray.size() > 0);
|
||||
|
||||
if (hasTexCoords) {
|
||||
debugAssertM(vertexArray.size() == texCoordArray.size(),
|
||||
"Input arrays are not parallel.");
|
||||
}
|
||||
|
||||
Array<Vector3> unrolledVertexArray;
|
||||
Array<Vector3> unrolledFaceNormalArray;
|
||||
Array<Vector3> unrolledSmoothNormalArray;
|
||||
Array<Vector2> unrolledTexCoordArray;
|
||||
|
||||
if (! hasTexCoords) {
|
||||
// Generate all zero texture coordinates
|
||||
texCoordArray.resize(vertexArray.size());
|
||||
}
|
||||
|
||||
// Generate a flat (unrolled) triangle list with texture coordinates.
|
||||
unroll(indexArrayArray, vertexArray, texCoordArray,
|
||||
unrolledVertexArray, unrolledTexCoordArray);
|
||||
|
||||
// Put the output back into the input slots.
|
||||
outputVertexArray = &vertexArray;
|
||||
outputNormalArray = &normalArray;
|
||||
outputTexCoordArray = &texCoordArray;
|
||||
outputVertexArray->fastClear();
|
||||
outputNormalArray->fastClear();
|
||||
outputTexCoordArray->fastClear();
|
||||
|
||||
// For every three vertices, generate their face normal and store it at
|
||||
// each vertex. The output array has the same length as the input.
|
||||
computeFaceNormals(unrolledVertexArray, unrolledFaceNormalArray);
|
||||
|
||||
// Compute smooth normals at vertices.
|
||||
if (unrolledFaceNormalArray.size() > 0) {
|
||||
smoothNormals(unrolledVertexArray, unrolledFaceNormalArray, unrolledSmoothNormalArray);
|
||||
unrolledFaceNormalArray.clear();
|
||||
}
|
||||
|
||||
// Regenerate the triangle lists
|
||||
updateTriLists(indexArrayArray, unrolledVertexArray, unrolledSmoothNormalArray, unrolledTexCoordArray);
|
||||
|
||||
if (! hasTexCoords) {
|
||||
// Throw away the generated texCoords
|
||||
texCoordArray.resize(0);
|
||||
}
|
||||
}
|
||||
|
||||
WeldHelper(float vertRadius) :
|
||||
weldGrid(vertRadius, AreaMemoryManager::create()),
|
||||
vertexWeldRadius(vertRadius) {
|
||||
}
|
||||
|
||||
};
|
||||
} // Internal
|
||||
|
||||
void Welder::weld(
|
||||
Array<Vector3>& vertexArray,
|
||||
Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& normalArray,
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
const Welder::Settings& settings) {
|
||||
|
||||
_internal::WeldHelper(settings.vertexWeldRadius).process(
|
||||
vertexArray, texCoordArray, normalArray, indexArrayArray,
|
||||
settings.normalSmoothingAngle, settings.textureWeldRadius, settings.normalWeldRadius);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Welder::Settings::Settings(const Any& any) {
|
||||
*this = Settings();
|
||||
any.verifyName("Welder::Settings");
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "normalsmoothingangle") {
|
||||
normalSmoothingAngle = it->value;
|
||||
} else if (key == "vertexweldradius") {
|
||||
vertexWeldRadius = it->value;
|
||||
} else if (key == "textureweldradius") {
|
||||
textureWeldRadius = it->value;
|
||||
} else if (key == "normalweldradius") {
|
||||
normalWeldRadius = it->value;
|
||||
} else {
|
||||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Welder::Settings::operator Any() const {
|
||||
Any a(Any::TABLE, "Welder::Settings");
|
||||
a.set("normalSmoothingAngle", normalSmoothingAngle);
|
||||
a.set("vertexWeldRadius", vertexWeldRadius);
|
||||
a.set("textureWeldRadius", textureWeldRadius);
|
||||
a.set("normalWeldRadius", normalWeldRadius);
|
||||
return a;
|
||||
}
|
||||
|
||||
} // G3D
|
||||
159
modules/acore/deps/g3dlite/source/WinMain.cpp
Normal file
159
modules/acore/deps/g3dlite/source/WinMain.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
Dervied from SDL_main.c, which was placed in the public domain by Sam Lantinga 4/13/98
|
||||
|
||||
The WinMain function -- calls your program's main() function
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cctype>
|
||||
|
||||
#ifdef main
|
||||
# ifndef _WIN32_WCE_EMULATION
|
||||
# undef main
|
||||
# endif /* _WIN32_WCE_EMULATION */
|
||||
#endif /* main */
|
||||
|
||||
#if defined(_WIN32_WCE) && _WIN32_WCE < 300
|
||||
/* seems to be undefined in Win CE although in online help */
|
||||
#define isspace(a) (((CHAR)a == ' ') || ((CHAR)a == '\t'))
|
||||
#endif /* _WIN32_WCE < 300 */
|
||||
|
||||
// Turn off the G3D for loop scoping for C++
|
||||
#ifdef for
|
||||
# undef for
|
||||
#endif
|
||||
|
||||
extern int main(int argc, const char** argv);
|
||||
|
||||
/* Parse a command line buffer into arguments */
|
||||
static int ParseCommandLine(char *cmdline, char **argv) {
|
||||
char *bufp;
|
||||
int argc;
|
||||
|
||||
argc = 0;
|
||||
for (bufp = cmdline; *bufp;) {
|
||||
/* Skip leading whitespace */
|
||||
while (isspace(*bufp)) {
|
||||
++bufp;
|
||||
}
|
||||
/* Skip over argument */
|
||||
if (*bufp == '"') {
|
||||
++bufp;
|
||||
if (*bufp) {
|
||||
if (argv) {
|
||||
argv[argc] = bufp;
|
||||
}
|
||||
++argc;
|
||||
}
|
||||
/* Skip over word */
|
||||
while (*bufp && (*bufp != '"')) {
|
||||
++bufp;
|
||||
}
|
||||
} else {
|
||||
if (*bufp) {
|
||||
if (argv) {
|
||||
argv[argc] = bufp;
|
||||
}
|
||||
++argc;
|
||||
}
|
||||
/* Skip over word */
|
||||
while (*bufp && !isspace(*bufp)) {
|
||||
++bufp;
|
||||
}
|
||||
}
|
||||
if (*bufp) {
|
||||
if (argv) {
|
||||
*bufp = '\0';
|
||||
}
|
||||
++bufp;
|
||||
}
|
||||
}
|
||||
if (argv) {
|
||||
argv[argc] = NULL;
|
||||
}
|
||||
return (argc);
|
||||
}
|
||||
|
||||
/* Show an error message */
|
||||
static void ShowError(const char *title, const char *message) {
|
||||
/* If USE_MESSAGEBOX is defined, you need to link with user32.lib */
|
||||
#ifdef USE_MESSAGEBOX
|
||||
MessageBox(NULL, message, title, MB_ICONEXCLAMATION | MB_OK);
|
||||
#else
|
||||
fprintf(stderr, "%s: %s\n", title, message);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pop up an out of memory message, returns to Windows */
|
||||
static BOOL OutOfMemory(void) {
|
||||
ShowError("Fatal Error", "Out of memory - aborting");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int WINAPI G3D_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {
|
||||
char **argv;
|
||||
int argc;
|
||||
int status;
|
||||
char *cmdline;
|
||||
# ifdef _WIN32_WCE
|
||||
wchar_t *bufp;
|
||||
int nLen;
|
||||
# else
|
||||
char *bufp;
|
||||
size_t nLen;
|
||||
# endif
|
||||
(void)sw;
|
||||
(void)szCmdLine;
|
||||
(void)hInst;
|
||||
(void)hPrev;
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
#error WinCE not supported
|
||||
/*
|
||||
nLen = wcslen(szCmdLine) + 128 + 1;
|
||||
bufp = SDL_stack_alloc(wchar_t, nLen * 2);
|
||||
wcscpy(bufp, TEXT("\""));
|
||||
GetModuleFileName(NULL, bufp + 1, 128 - 3);
|
||||
wcscpy(bufp + wcslen(bufp), TEXT("\" "));
|
||||
wcsncpy(bufp + wcslen(bufp), szCmdLine, nLen - wcslen(bufp));
|
||||
nLen = wcslen(bufp) + 1;
|
||||
cmdline = SDL_stack_alloc(char, nLen);
|
||||
if (cmdline == NULL) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL);
|
||||
*/
|
||||
#else
|
||||
/* Grab the command line */
|
||||
bufp = GetCommandLineA();
|
||||
nLen = strlen(bufp) + 1;
|
||||
cmdline = (char*)malloc(sizeof(char) * nLen);
|
||||
if (cmdline == NULL) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
strncpy(cmdline, bufp, nLen);
|
||||
#endif
|
||||
|
||||
/* Parse it into argv and argc */
|
||||
argc = ParseCommandLine(cmdline, NULL);
|
||||
argv = (char**)malloc(sizeof(char*) * (argc + 1));
|
||||
if (argv == NULL) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
ParseCommandLine(cmdline, argv);
|
||||
|
||||
/* Run the main program */
|
||||
status = main(argc, (const char**)argv);
|
||||
free(argv);
|
||||
free(cmdline);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif // if Win32
|
||||
216
modules/acore/deps/g3dlite/source/XML.cpp
Normal file
216
modules/acore/deps/g3dlite/source/XML.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
\file XML.h
|
||||
|
||||
\author Morgan McGuire
|
||||
\maintainer Morgan McGuire
|
||||
|
||||
\created 2010-02-11
|
||||
\edited 2010-02-24
|
||||
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/XML.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/TextInput.h"
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
XML::XML(TextInput& t) : m_type(VALUE) {
|
||||
deserialize(t);
|
||||
}
|
||||
|
||||
double XML::number() const {
|
||||
return TextInput::parseNumber(m_value);
|
||||
}
|
||||
|
||||
|
||||
bool XML::boolean() const {
|
||||
return TextInput::parseBoolean(m_value);
|
||||
}
|
||||
|
||||
|
||||
void XML::load(const std::string& filename) {
|
||||
TextInput::Settings s;
|
||||
s.cppBlockComments = false;
|
||||
s.cppLineComments = false;
|
||||
s.proofSymbols = false;
|
||||
|
||||
TextInput t(filename, s);
|
||||
deserialize(t);
|
||||
}
|
||||
|
||||
|
||||
void XML::save(const std::string& filename) const {
|
||||
std::string s;
|
||||
unparse(s);
|
||||
writeWholeFile(filename, s);
|
||||
}
|
||||
|
||||
|
||||
void XML::unparse(std::string &s) const {
|
||||
TextOutput::Settings set;
|
||||
set.wordWrap = TextOutput::Settings::WRAP_WITHOUT_BREAKING;
|
||||
TextOutput t(set);
|
||||
|
||||
serialize(t);
|
||||
|
||||
t.commitString(s);
|
||||
}
|
||||
|
||||
|
||||
void XML::serialize(TextOutput& t) const {
|
||||
if (m_type == VALUE) {
|
||||
// Raw string; no quotes
|
||||
t.writeSymbol(m_value);
|
||||
} else {
|
||||
t.printf("<%s", m_name.c_str());
|
||||
for (AttributeTable::Iterator it = m_attribute.begin(); it.hasMore(); ++it) {
|
||||
t.printf(" %s=\"%s\"", it->key.c_str(), it->value.m_value.c_str());
|
||||
}
|
||||
t.printf(">");
|
||||
t.writeNewline();
|
||||
t.pushIndent();
|
||||
for (int i = 0; i < m_child.size(); ++i) {
|
||||
m_child[i].serialize(t);
|
||||
if (m_child[i].m_type == VALUE) {
|
||||
// Only tags know to append a newline
|
||||
t.writeNewline();
|
||||
}
|
||||
}
|
||||
t.popIndent();
|
||||
t.printf("</%s>", m_name.c_str());
|
||||
t.writeNewline();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void XML::parse(const std::string& s) {
|
||||
TextInput t(TextInput::FROM_STRING, s);
|
||||
deserialize(t);
|
||||
}
|
||||
|
||||
|
||||
/** True if the next token begins the close tag */
|
||||
static bool atClose(TextInput& t, const std::string name) {
|
||||
if ((t.peek().type() == Token::SYMBOL) && (t.peek().string() == "<")) {
|
||||
// Need to keep looking ahead
|
||||
Token p0 = t.read();
|
||||
if ((t.peek().type() == Token::SYMBOL) && (t.peek().string() == "/")) {
|
||||
// Check the name on the close tag. It *must* match if
|
||||
// this is a well-formed document, but there might be a
|
||||
// tag error.
|
||||
Token p1 = t.read();
|
||||
Token p2 = t.peek();
|
||||
std::string s = p2.string();
|
||||
debugAssertM(beginsWith(name, s), "Mismatched close tag");
|
||||
|
||||
// Put the tokens back
|
||||
t.push(p1);
|
||||
t.push(p0);
|
||||
return true;
|
||||
} else {
|
||||
// Put the read token back
|
||||
t.push(p0);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void XML::deserialize(TextInput& t) {
|
||||
begin:
|
||||
Token n = t.read();
|
||||
m_attribute.clear();
|
||||
m_child.clear();
|
||||
m_name = "";
|
||||
m_value = "";
|
||||
|
||||
if ((n.type() == Token::SYMBOL) && (n.string() == "<")) {
|
||||
// Beginning a tag
|
||||
|
||||
// Read name
|
||||
n = t.read();
|
||||
debugAssert(n.type() == Token::SYMBOL);
|
||||
bool isComment =
|
||||
(n.string() == "!") &&
|
||||
(t.peek().type() == Token::SYMBOL) &&
|
||||
(t.peek().string() == "--");
|
||||
|
||||
// ignored tag: <?xml> or <!xml>
|
||||
// comment tag: <!-- ... -->
|
||||
|
||||
if ((n.string() == "?") || ((n.string() == "!") && ! isComment)) {
|
||||
// Ignore this tag
|
||||
while (t.hasMore() && ! ((n.type() == Token::SYMBOL) && (n.string() == ">"))) {
|
||||
n = t.read();
|
||||
}
|
||||
goto begin;
|
||||
} else if (isComment) {
|
||||
// Ignore until "-->"
|
||||
bool prevWasDash = false;
|
||||
while (t.hasMore() && ! ((n.type() == Token::SYMBOL) && (n.string() == ">") && prevWasDash)) {
|
||||
prevWasDash = (n.type() == Token::SYMBOL) && (n.string() == "--");
|
||||
n = t.read();
|
||||
}
|
||||
goto begin;
|
||||
}
|
||||
|
||||
// Keep reading until no colon
|
||||
m_name += n.string();
|
||||
n = t.read();
|
||||
while ((n.type() == Token::SYMBOL) && (n.string() == ":")) {
|
||||
// tag with namespace: <x:y>
|
||||
m_name += ":" + t.readSymbol();
|
||||
n = t.read();
|
||||
}
|
||||
|
||||
// Read end of tag/close
|
||||
bool done = false;
|
||||
while (! done) {
|
||||
debugAssert(n.type() == Token::SYMBOL);
|
||||
if (n.string() == "/") {
|
||||
// empty-element tag: <foo/>
|
||||
// Consume the close tag
|
||||
t.readSymbol(">");
|
||||
done = true;
|
||||
|
||||
} else if (n.string() == ">") {
|
||||
// End of open tag: read children until close tag
|
||||
while (! atClose(t, m_name)) {
|
||||
m_child.next().deserialize(t);
|
||||
}
|
||||
|
||||
// Read close tag (we wouldn't be here unless it parses correctly)
|
||||
while (t.hasMore() && ! (t.readSymbol() == ">")) {}
|
||||
|
||||
done = true;
|
||||
} else {
|
||||
// Attribute pair
|
||||
std::string k = n.string();
|
||||
t.readSymbol("=");
|
||||
std::string v = t.read().string();
|
||||
m_attribute.set(k, v);
|
||||
|
||||
// Advance to next
|
||||
n = t.read();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Beginning embedded content. Read until the end of file or the next tag.
|
||||
m_type = VALUE;
|
||||
m_value += n.string();
|
||||
|
||||
n = t.peek();
|
||||
while (t.hasMore() && ! ((n.type() == Token::SYMBOL) && (n.string() == "<"))) {
|
||||
m_value += " " + t.read().string();
|
||||
n = t.peek();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
16
modules/acore/deps/g3dlite/source/constants.cpp
Normal file
16
modules/acore/deps/g3dlite/source/constants.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
@file constants.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2009-05-20
|
||||
@edited 2010-01-29
|
||||
*/
|
||||
#include "G3D/constants.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
|
||||
} // G3D
|
||||
389
modules/acore/deps/g3dlite/source/debugAssert.cpp
Normal file
389
modules/acore/deps/g3dlite/source/debugAssert.cpp
Normal file
@@ -0,0 +1,389 @@
|
||||
/**
|
||||
@file debugAssert.cpp
|
||||
|
||||
Windows implementation of assertion routines.
|
||||
|
||||
@maintainer Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2001-08-26
|
||||
@edited 2009-06-02
|
||||
*/
|
||||
|
||||
#include "G3D/debugAssert.h"
|
||||
#include "G3D/platform.h"
|
||||
#ifdef G3D_WIN32
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/prompt.h"
|
||||
#include <string>
|
||||
#include "G3D/debugPrintf.h"
|
||||
#include "G3D/Log.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// disable: "C++ exception handler used"
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable : 4530)
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace G3D { namespace _internal {
|
||||
|
||||
ConsolePrintHook _consolePrintHook;
|
||||
AssertionHook _debugHook = _handleDebugAssert_;
|
||||
AssertionHook _failureHook = _handleErrorCheck_;
|
||||
|
||||
#ifdef G3D_LINUX
|
||||
#if 0 /* G3DFIX: Disabled to avoid requirement for X11 libraries */
|
||||
Display* x11Display = NULL;
|
||||
Window x11Window = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
static void postToClipboard(const char *text) {
|
||||
if (OpenClipboard(NULL)) {
|
||||
HGLOBAL hMem = GlobalAlloc(GHND | GMEM_DDESHARE, strlen(text) + 1);
|
||||
if (hMem) {
|
||||
char *pMem = (char*)GlobalLock(hMem);
|
||||
strcpy(pMem, text);
|
||||
GlobalUnlock(hMem);
|
||||
|
||||
EmptyClipboard();
|
||||
SetClipboardData(CF_TEXT, hMem);
|
||||
}
|
||||
|
||||
CloseClipboard();
|
||||
GlobalFree(hMem);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
outTitle should be set before the call
|
||||
*/
|
||||
static void createErrorMessage(
|
||||
const char* expression,
|
||||
const std::string& message,
|
||||
const char* filename,
|
||||
int lineNumber,
|
||||
std::string& outTitle,
|
||||
std::string& outMessage) {
|
||||
|
||||
std::string le = "";
|
||||
const char* newline = "\n";
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
newline = "\r\n";
|
||||
|
||||
// The last error value. (Which is preserved across the call).
|
||||
DWORD lastErr = GetLastError();
|
||||
|
||||
// The decoded message from FormatMessage
|
||||
LPTSTR formatMsg = NULL;
|
||||
|
||||
if (NULL == formatMsg) {
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
lastErr,
|
||||
0,
|
||||
(LPTSTR)&formatMsg,
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
// Make sure the message got translated into something.
|
||||
LPTSTR realLastErr;
|
||||
if (NULL != formatMsg) {
|
||||
realLastErr = formatMsg;
|
||||
} else {
|
||||
realLastErr = _T("Last error code does not exist.");
|
||||
}
|
||||
|
||||
if (lastErr != 0) {
|
||||
le = G3D::format("Last Error (0x%08X): %s\r\n\r\n", lastErr, (LPCSTR)realLastErr);
|
||||
}
|
||||
|
||||
// Get rid of the allocated memory from FormatMessage.
|
||||
if (NULL != formatMsg) {
|
||||
LocalFree((LPVOID)formatMsg);
|
||||
}
|
||||
|
||||
char modulePath[MAX_PATH];
|
||||
GetModuleFileNameA(NULL, modulePath, MAX_PATH);
|
||||
|
||||
const char* moduleName = strrchr(modulePath, '\\');
|
||||
outTitle = outTitle + string(" - ") + string(moduleName ? (moduleName + 1) : modulePath);
|
||||
|
||||
#endif
|
||||
|
||||
// Build the message.
|
||||
outMessage =
|
||||
G3D::format("%s%s%sExpression: %s%s%s:%d%s%s%s",
|
||||
message.c_str(), newline, newline, expression, newline,
|
||||
filename, lineNumber, newline, newline, le.c_str());
|
||||
}
|
||||
|
||||
|
||||
bool _handleDebugAssert_(
|
||||
const char* expression,
|
||||
const std::string& message,
|
||||
const char* filename,
|
||||
int lineNumber,
|
||||
bool useGuiPrompt) {
|
||||
|
||||
std::string dialogTitle = "Assertion Failure";
|
||||
std::string dialogText = "";
|
||||
createErrorMessage(expression, message, filename, lineNumber, dialogTitle, dialogText);
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
DWORD lastErr = GetLastError();
|
||||
postToClipboard(dialogText.c_str());
|
||||
debugPrintf("\n%s\n", dialogText.c_str());
|
||||
#endif
|
||||
|
||||
const int cBreak = 0;
|
||||
const int cIgnore = 1;
|
||||
const int cAbort = 2;
|
||||
|
||||
static const char* choices[] = {"Debug", "Ignore", "Exit"};
|
||||
|
||||
// Log the error
|
||||
Log::common()->print(std::string("\n**************************\n\n") + dialogTitle + "\n" + dialogText);
|
||||
|
||||
int result = G3D::prompt(dialogTitle.c_str(), dialogText.c_str(), (const char**)choices, 3, useGuiPrompt);
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
// Put the incoming last error back.
|
||||
SetLastError(lastErr);
|
||||
# endif
|
||||
|
||||
switch (result) {
|
||||
// -1 shouldn't actually occur because it means
|
||||
// that we're in release mode.
|
||||
case -1:
|
||||
case cBreak:
|
||||
return true;
|
||||
break;
|
||||
|
||||
case cIgnore:
|
||||
return false;
|
||||
break;
|
||||
|
||||
case cAbort:
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
// Should never get here
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool _handleErrorCheck_(
|
||||
const char* expression,
|
||||
const std::string& message,
|
||||
const char* filename,
|
||||
int lineNumber,
|
||||
bool useGuiPrompt) {
|
||||
|
||||
std::string dialogTitle = "Critical Error";
|
||||
std::string dialogText = "";
|
||||
|
||||
createErrorMessage(expression, message, filename, lineNumber, dialogTitle, dialogText);
|
||||
|
||||
// Log the error
|
||||
Log::common()->print(std::string("\n**************************\n\n") + dialogTitle + "\n" + dialogText);
|
||||
#ifdef G3D_WIN32
|
||||
DWORD lastErr = GetLastError();
|
||||
(void)lastErr;
|
||||
postToClipboard(dialogText.c_str());
|
||||
debugPrintf("\n%s\n", dialogText.c_str());
|
||||
#endif
|
||||
|
||||
static const char* choices[] = {"Ok"};
|
||||
|
||||
const std::string& m =
|
||||
std::string("An internal error has occured in this program and it will now close. "
|
||||
"The specific error is below. More information has been saved in \"") +
|
||||
Log::getCommonLogFilename() + "\".\n" + dialogText;
|
||||
|
||||
int result = G3D::prompt("Error", m.c_str(), (const char**)choices, 1, useGuiPrompt);
|
||||
(void)result;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
static HCURSOR oldCursor;
|
||||
static RECT oldCursorRect;
|
||||
static POINT oldCursorPos;
|
||||
static int oldShowCursorCount;
|
||||
#endif
|
||||
|
||||
void _releaseInputGrab_() {
|
||||
#ifdef G3D_WIN32
|
||||
|
||||
GetCursorPos(&oldCursorPos);
|
||||
|
||||
// Stop hiding the cursor if the application hid it.
|
||||
oldShowCursorCount = ShowCursor(true) - 1;
|
||||
|
||||
if (oldShowCursorCount < -1) {
|
||||
for (int c = oldShowCursorCount; c < -1; ++c) {
|
||||
ShowCursor(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the default cursor in case the application
|
||||
// set the cursor to NULL.
|
||||
oldCursor = GetCursor();
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
|
||||
// Allow the cursor full access to the screen
|
||||
GetClipCursor(&oldCursorRect);
|
||||
ClipCursor(NULL);
|
||||
|
||||
#elif defined(G3D_LINUX)
|
||||
#if 0 /* G3DFIX: Disabled to avoid requirement for X11 libraries */
|
||||
if (x11Display != NULL) {
|
||||
XUngrabPointer(x11Display, CurrentTime);
|
||||
XUngrabKeyboard(x11Display, CurrentTime);
|
||||
if (x11Window != 0) {
|
||||
//XUndefineCursor(x11Display, x11Window);
|
||||
// TODO: Note that we leak this cursor; it should be
|
||||
// freed in the restore code.
|
||||
Cursor c = XCreateFontCursor(x11Display, 68);
|
||||
XDefineCursor(x11Display, x11Window, c);
|
||||
}
|
||||
XSync(x11Display, false);
|
||||
XAllowEvents(x11Display, AsyncPointer, CurrentTime);
|
||||
XFlush(x11Display);
|
||||
}
|
||||
#endif
|
||||
#elif defined(G3D_OSX)
|
||||
// TODO: OS X
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void _restoreInputGrab_() {
|
||||
#ifdef G3D_WIN32
|
||||
|
||||
// Restore the old clipping region
|
||||
ClipCursor(&oldCursorRect);
|
||||
|
||||
SetCursorPos(oldCursorPos.x, oldCursorPos.y);
|
||||
|
||||
// Restore the old cursor
|
||||
SetCursor(oldCursor);
|
||||
|
||||
// Restore old visibility count
|
||||
if (oldShowCursorCount < 0) {
|
||||
for (int c = 0; c > oldShowCursorCount; --c) {
|
||||
ShowCursor(false);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(G3D_LINUX)
|
||||
// TODO: Linux
|
||||
#elif defined(G3D_OSX)
|
||||
// TODO: OS X
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}; // internal namespace
|
||||
|
||||
void setAssertionHook(AssertionHook hook) {
|
||||
G3D::_internal::_debugHook = hook;
|
||||
}
|
||||
|
||||
AssertionHook assertionHook() {
|
||||
return G3D::_internal::_debugHook;
|
||||
}
|
||||
|
||||
void setFailureHook(AssertionHook hook) {
|
||||
G3D::_internal::_failureHook = hook;
|
||||
}
|
||||
|
||||
AssertionHook failureHook() {
|
||||
return G3D::_internal::_failureHook;
|
||||
}
|
||||
|
||||
|
||||
void setConsolePrintHook(ConsolePrintHook h) {
|
||||
G3D::_internal::_consolePrintHook = h;
|
||||
}
|
||||
|
||||
ConsolePrintHook consolePrintHook() {
|
||||
return G3D::_internal::_consolePrintHook;
|
||||
}
|
||||
|
||||
|
||||
std::string __cdecl debugPrint(const std::string& s) {
|
||||
# ifdef G3D_WIN32
|
||||
const int MAX_STRING_LEN = 1024;
|
||||
|
||||
// Windows can't handle really long strings sent to
|
||||
// the console, so we break the string.
|
||||
if (s.size() < MAX_STRING_LEN) {
|
||||
OutputDebugStringA(s.c_str());
|
||||
} else {
|
||||
for (unsigned int i = 0; i < s.size(); i += MAX_STRING_LEN) {
|
||||
std::string sub = s.substr(i, MAX_STRING_LEN);
|
||||
OutputDebugStringA(sub.c_str());
|
||||
}
|
||||
}
|
||||
# else
|
||||
fprintf(stderr, "%s", s.c_str());
|
||||
fflush(stderr);
|
||||
# endif
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string __cdecl debugPrintf(const char* fmt ...) {
|
||||
va_list argList;
|
||||
va_start(argList, fmt);
|
||||
std::string s = G3D::vformat(fmt, argList);
|
||||
va_end(argList);
|
||||
|
||||
return debugPrint(s);
|
||||
// return debugPrint(consolePrint(s));
|
||||
}
|
||||
|
||||
std::string consolePrint(const std::string& s) {
|
||||
FILE* L = Log::common()->getFile();
|
||||
fprintf(L, "%s", s.c_str());
|
||||
|
||||
if (consolePrintHook()) {
|
||||
consolePrintHook()(s);
|
||||
}
|
||||
|
||||
fflush(L);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
std::string __cdecl consolePrintf(const char* fmt ...) {
|
||||
va_list argList;
|
||||
va_start(argList, fmt);
|
||||
std::string s = G3D::vformat(fmt, argList);
|
||||
va_end(argList);
|
||||
|
||||
return consolePrint(s);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
942
modules/acore/deps/g3dlite/source/fileutils.cpp
Normal file
942
modules/acore/deps/g3dlite/source/fileutils.cpp
Normal file
@@ -0,0 +1,942 @@
|
||||
/**
|
||||
@file fileutils.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
||||
@author 2002-06-06
|
||||
@edited 2010-02-05
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/Set.h"
|
||||
#include "G3D/g3dfnmatch.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
#include "zip.h"
|
||||
#endif
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
// Needed for _getcwd
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <fnmatch.h>
|
||||
#include <unistd.h>
|
||||
#define _getcwd getcwd
|
||||
#define _stat stat
|
||||
#endif
|
||||
|
||||
|
||||
namespace G3D {
|
||||
|
||||
namespace _internal {
|
||||
Set<std::string> currentFilesUsed;
|
||||
}
|
||||
|
||||
std::string pathConcat(const std::string& dirname, const std::string& file) {
|
||||
// Ensure that the directory ends in a slash
|
||||
if ((dirname.size() != 0) &&
|
||||
(dirname[dirname.size() - 1] != '/') &&
|
||||
(dirname[dirname.size() - 1] != '\\') &&
|
||||
(dirname[dirname.size() - 1] != ':')) {
|
||||
return dirname + '/' + file;
|
||||
} else {
|
||||
return dirname + file;
|
||||
}
|
||||
}
|
||||
|
||||
std::string resolveFilename(const std::string& filename) {
|
||||
if (filename.size() >= 1) {
|
||||
if ((filename[0] == '/') || (filename[0] == '\\')) {
|
||||
// Already resolved
|
||||
return filename;
|
||||
} else {
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
if ((filename.size() >= 2) && (filename[1] == ':')) {
|
||||
// There is a drive spec on the front.
|
||||
if ((filename.size() >= 3) && ((filename[2] == '\\') ||
|
||||
(filename[2] == '/'))) {
|
||||
// Already fully qualified
|
||||
return filename;
|
||||
} else {
|
||||
// The drive spec is relative to the
|
||||
// working directory on that drive.
|
||||
debugAssertM(false, "Files of the form d:path are"
|
||||
" not supported (use a fully qualified"
|
||||
" name).");
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
// Prepend the working directory.
|
||||
_getcwd(buffer, 1024);
|
||||
|
||||
return format("%s/%s", buffer, filename.c_str());
|
||||
}
|
||||
|
||||
bool zipfileExists(const std::string& filename) {
|
||||
std::string outZipfile;
|
||||
std::string outInternalFile;
|
||||
return zipfileExists(filename, outZipfile, outInternalFile);
|
||||
}
|
||||
|
||||
std::string readWholeFile(
|
||||
const std::string& filename) {
|
||||
|
||||
_internal::currentFilesUsed.insert(filename);
|
||||
|
||||
std::string s;
|
||||
|
||||
debugAssert(filename != "");
|
||||
debugAssertM(FileSystem::exists(filename), filename + " not found");
|
||||
|
||||
if (! FileSystem::inZipfile(filename)) {
|
||||
int64 length = FileSystem::size(filename);
|
||||
|
||||
char* buffer = (char*)System::alignedMalloc(length + 1, 16);
|
||||
debugAssert(buffer);
|
||||
FILE* f = FileSystem::fopen(filename.c_str(), "rb");
|
||||
debugAssert(f);
|
||||
int ret = fread(buffer, 1, length, f);
|
||||
debugAssert(ret == length);(void)ret;
|
||||
FileSystem::fclose(f);
|
||||
|
||||
buffer[length] = '\0';
|
||||
s = std::string(buffer);
|
||||
|
||||
System::alignedFree(buffer);
|
||||
|
||||
} else if (zipfileExists(filename)) {
|
||||
|
||||
void* zipBuffer;
|
||||
size_t length;
|
||||
zipRead(filename, zipBuffer, length);
|
||||
|
||||
char* buffer = (char*)System::alignedMalloc(length + 1, 16);
|
||||
System::memcpy(buffer,zipBuffer, length + 1);
|
||||
zipClose(zipBuffer);
|
||||
|
||||
buffer[length] = '\0';
|
||||
s = std::string(buffer);
|
||||
System::alignedFree(buffer);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void zipRead(const std::string& file,
|
||||
void*& data,
|
||||
size_t& length) {
|
||||
std::string zip, desiredFile;
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
if (zipfileExists(file, zip, desiredFile)) {
|
||||
struct zip *z = zip_open( zip.c_str(), ZIP_CHECKCONS, NULL );
|
||||
{
|
||||
struct zip_stat info;
|
||||
zip_stat_init( &info ); // TODO: Docs unclear if zip_stat_init is required.
|
||||
zip_stat( z, desiredFile.c_str(), ZIP_FL_NOCASE, &info );
|
||||
length = info.size;
|
||||
// sets machines up to use MMX, if they want
|
||||
data = System::alignedMalloc(length, 16);
|
||||
struct zip_file *zf = zip_fopen( z, desiredFile.c_str(), ZIP_FL_NOCASE );
|
||||
{
|
||||
int test = zip_fread( zf, data, length );
|
||||
debugAssertM((size_t)test == length,
|
||||
desiredFile + " was corrupt because it unzipped to the wrong size.");
|
||||
(void)test;
|
||||
}
|
||||
zip_fclose( zf );
|
||||
}
|
||||
zip_close( z );
|
||||
} else {
|
||||
data = NULL;
|
||||
}
|
||||
#else
|
||||
data = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void zipClose(void* data) {
|
||||
System::alignedFree(data);
|
||||
}
|
||||
|
||||
|
||||
int64 fileLength(const std::string& filename) {
|
||||
struct _stat st;
|
||||
int result = _stat(filename.c_str(), &st);
|
||||
|
||||
if (result == -1) {
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
std::string zip, contents;
|
||||
if(zipfileExists(filename, zip, contents)){
|
||||
int64 requiredMem;
|
||||
|
||||
struct zip *z = zip_open( zip.c_str(), ZIP_CHECKCONS, NULL );
|
||||
debugAssertM(z != NULL, zip + ": zip open failed.");
|
||||
{
|
||||
struct zip_stat info;
|
||||
zip_stat_init( &info ); // TODO: Docs unclear if zip_stat_init is required.
|
||||
int success = zip_stat( z, contents.c_str(), ZIP_FL_NOCASE, &info );
|
||||
(void)success;
|
||||
debugAssertM(success == 0, zip + ": " + contents + ": zip stat failed.");
|
||||
requiredMem = info.size;
|
||||
}
|
||||
zip_close( z );
|
||||
return requiredMem;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void writeWholeFile(
|
||||
const std::string& filename,
|
||||
const std::string& str,
|
||||
bool flush) {
|
||||
|
||||
// Make sure the directory exists.
|
||||
std::string root, base, ext, path;
|
||||
Array<std::string> pathArray;
|
||||
parseFilename(filename, root, pathArray, base, ext);
|
||||
|
||||
path = root + stringJoin(pathArray, '/');
|
||||
if (! FileSystem::exists(path, false)) {
|
||||
FileSystem::createDirectory(path);
|
||||
}
|
||||
|
||||
FILE* file = FileSystem::fopen(filename.c_str(), "wb");
|
||||
|
||||
debugAssert(file);
|
||||
|
||||
fwrite(str.c_str(), str.size(), 1, file);
|
||||
|
||||
if (flush) {
|
||||
fflush(file);
|
||||
}
|
||||
|
||||
FileSystem::fclose(file);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
Creates the directory (which may optionally end in a /)
|
||||
and any parents needed to reach it.
|
||||
*/
|
||||
void createDirectory(
|
||||
const std::string& dir) {
|
||||
|
||||
if (dir == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string d;
|
||||
|
||||
// Add a trailing / if there isn't one.
|
||||
switch (dir[dir.size() - 1]) {
|
||||
case '/':
|
||||
case '\\':
|
||||
d = dir;
|
||||
break;
|
||||
|
||||
default:
|
||||
d = dir + "/";
|
||||
}
|
||||
|
||||
// If it already exists, do nothing
|
||||
if (FileSystem::exists(d.substr(0, d.size() - 1))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the name apart
|
||||
std::string root, base, ext;
|
||||
Array<std::string> path;
|
||||
|
||||
std::string lead;
|
||||
parseFilename(d, root, path, base, ext);
|
||||
debugAssert(base == "");
|
||||
debugAssert(ext == "");
|
||||
|
||||
// Begin with an extra period so "c:\" becomes "c:\.\" after
|
||||
// appending a path and "c:" becomes "c:.\", not root: "c:\"
|
||||
std::string p = root + ".";
|
||||
|
||||
// Create any intermediate that doesn't exist
|
||||
for (int i = 0; i < path.size(); ++i) {
|
||||
p += "/" + path[i];
|
||||
if (! FileSystem::exists(p)) {
|
||||
// Windows only requires one argument to mkdir,
|
||||
// where as unix also requires the permissions.
|
||||
# ifndef G3D_WIN32
|
||||
mkdir(p.c_str(), 0777);
|
||||
# else
|
||||
_mkdir(p.c_str());
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
/* Helper methods for zipfileExists()*/
|
||||
// Given a string (the drive) and an array (the path), computes the directory
|
||||
static void _zip_resolveDirectory(std::string& completeDir, const std::string& drive, const Array<std::string>& path, const int length){
|
||||
completeDir = drive;
|
||||
int tempLength;
|
||||
// if the given length is longer than the array, we correct it
|
||||
if(length > path.length()){
|
||||
tempLength = path.length();
|
||||
} else{
|
||||
tempLength = length;
|
||||
}
|
||||
|
||||
for(int t = 0; t < tempLength; ++t){
|
||||
if(t > 0){
|
||||
completeDir += "/";
|
||||
}
|
||||
completeDir += path[t];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// assumes that zipDir references a .zip file
|
||||
static bool _zip_zipContains(const std::string& zipDir, const std::string& desiredFile){
|
||||
struct zip *z = zip_open( zipDir.c_str(), ZIP_CHECKCONS, NULL );
|
||||
//the last parameter, an int, determines case sensitivity:
|
||||
//1 is sensitive, 2 is not, 0 is default
|
||||
int test = zip_name_locate( z, desiredFile.c_str(), ZIP_FL_NOCASE );
|
||||
zip_close( z );
|
||||
if(test == -1){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// If no zipfile exists, outZipfile and outInternalFile are unchanged
|
||||
bool zipfileExists(const std::string& filename, std::string& outZipfile,
|
||||
std::string& outInternalFile){
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
Array<std::string> path;
|
||||
std::string drive, base, ext, zipfile, infile;
|
||||
parseFilename(filename, drive, path, base, ext);
|
||||
|
||||
// Put the filename back together
|
||||
if ((base != "") && (ext != "")) {
|
||||
infile = base + "." + ext;
|
||||
} else {
|
||||
infile = base + ext;
|
||||
}
|
||||
|
||||
// Remove "." from path
|
||||
for (int i = 0; i < path.length(); ++i) {
|
||||
if (path[i] == ".") {
|
||||
path.remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove ".." from path
|
||||
for (int i = 1; i < path.length(); ++i) {
|
||||
if ((path[i] == "..") && (i > 0) && (path[i - 1] != "..")) {
|
||||
// Remove both i and i - 1
|
||||
path.remove(i - 1, 2);
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Walk the path backwards, accumulating pieces onto the infile until
|
||||
// we find a zipfile that contains it
|
||||
for (int t = 0; t < path.length(); ++t){
|
||||
_zip_resolveDirectory(zipfile, drive, path, path.length() - t);
|
||||
if (t > 0) {
|
||||
infile = path[path.length() - t] + "/" + infile;
|
||||
}
|
||||
|
||||
if (endsWith(zipfile, "..")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FileSystem::exists(zipfile)) {
|
||||
// test if it actually is a zipfile
|
||||
// if not, return false, a bad
|
||||
// directory structure has been given,
|
||||
// not a .zip
|
||||
if (FileSystem::isZipfile(zipfile)){
|
||||
|
||||
if (_zip_zipContains(zipfile, infile)){
|
||||
outZipfile = zipfile;
|
||||
outInternalFile = infile;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// the directory structure was valid but did not point to a .zip
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
// not a valid directory structure ever,
|
||||
// obviously no .zip was found within the path
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string generateFilenameBase(const std::string& prefix, const std::string& suffix) {
|
||||
Array<std::string> exist;
|
||||
|
||||
// Note "template" is a reserved word in C++
|
||||
std::string templat = prefix + System::currentDateString() + "_";
|
||||
FileSystem::getFiles(templat + "*", exist);
|
||||
|
||||
// Remove extensions
|
||||
for (int i = 0; i < exist.size(); ++i) {
|
||||
exist[i] = filenameBase(exist[i]);
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
std::string result;
|
||||
templat += "%03d" + suffix;
|
||||
do {
|
||||
result = format(templat.c_str(), num);
|
||||
++num;
|
||||
} while (exist.contains(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void copyFile(
|
||||
const std::string& source,
|
||||
const std::string& dest) {
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
CopyFileA(source.c_str(), dest.c_str(), FALSE);
|
||||
#else
|
||||
// TODO: don't use BinaryInput and BinaryOutput
|
||||
// Read it all in, then dump it out
|
||||
BinaryInput in(source, G3D_LITTLE_ENDIAN);
|
||||
BinaryOutput out(dest, G3D_LITTLE_ENDIAN);
|
||||
out.writeBytes(in.getCArray(), in.size());
|
||||
out.commit(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void parseFilename(
|
||||
const std::string& filename,
|
||||
std::string& root,
|
||||
Array<std::string>& path,
|
||||
std::string& base,
|
||||
std::string& ext) {
|
||||
|
||||
std::string f = filename;
|
||||
|
||||
root = "";
|
||||
path.clear();
|
||||
base = "";
|
||||
ext = "";
|
||||
|
||||
if (f == "") {
|
||||
// Empty filename
|
||||
return;
|
||||
}
|
||||
|
||||
// See if there is a root/drive spec.
|
||||
if ((f.size() >= 2) && (f[1] == ':')) {
|
||||
|
||||
if ((f.size() > 2) && isSlash(f[2])) {
|
||||
|
||||
// e.g. c:\foo
|
||||
root = f.substr(0, 3);
|
||||
f = f.substr(3, f.size() - 3);
|
||||
|
||||
} else {
|
||||
|
||||
// e.g. c:foo
|
||||
root = f.substr(2);
|
||||
f = f.substr(2, f.size() - 2);
|
||||
|
||||
}
|
||||
|
||||
} else if ((f.size() >= 2) & isSlash(f[0]) && isSlash(f[1])) {
|
||||
|
||||
// e.g. //foo
|
||||
root = f.substr(0, 2);
|
||||
f = f.substr(2, f.size() - 2);
|
||||
|
||||
} else if (isSlash(f[0])) {
|
||||
|
||||
root = f.substr(0, 1);
|
||||
f = f.substr(1, f.size() - 1);
|
||||
|
||||
}
|
||||
|
||||
// Pull the extension off
|
||||
{
|
||||
// Find the period
|
||||
size_t i = f.rfind('.');
|
||||
|
||||
if (i != std::string::npos) {
|
||||
// Make sure it is after the last slash!
|
||||
size_t j = iMax(f.rfind('/'), f.rfind('\\'));
|
||||
if ((j == std::string::npos) || (i > j)) {
|
||||
ext = f.substr(i + 1, f.size() - i - 1);
|
||||
f = f.substr(0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pull the basename off
|
||||
{
|
||||
// Find the last slash
|
||||
size_t i = iMax(f.rfind('/'), f.rfind('\\'));
|
||||
|
||||
if (i == std::string::npos) {
|
||||
|
||||
// There is no slash; the basename is the whole thing
|
||||
base = f;
|
||||
f = "";
|
||||
|
||||
} else if ((i != std::string::npos) && (i < f.size() - 1)) {
|
||||
|
||||
base = f.substr(i + 1, f.size() - i - 1);
|
||||
f = f.substr(0, i);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Parse what remains into path.
|
||||
size_t prev, cur = 0;
|
||||
|
||||
while (cur < f.size()) {
|
||||
prev = cur;
|
||||
|
||||
// Allow either slash
|
||||
size_t i = f.find('/', prev + 1);
|
||||
size_t j = f.find('\\', prev + 1);
|
||||
if (i == std::string::npos) {
|
||||
i = f.size();
|
||||
}
|
||||
|
||||
if (j == std::string::npos) {
|
||||
j = f.size();
|
||||
}
|
||||
|
||||
cur = iMin(i, j);
|
||||
|
||||
if (cur == std::string::npos) {
|
||||
cur = f.size();
|
||||
}
|
||||
|
||||
path.append(f.substr(prev, cur - prev));
|
||||
++cur;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Helper for getFileList and getDirectoryList.
|
||||
|
||||
@param wantFiles If false, returns the directories, otherwise
|
||||
returns the files.
|
||||
@param includePath If true, the names include paths
|
||||
*/
|
||||
static void getFileOrDirListNormal
|
||||
(const std::string& filespec,
|
||||
Array<std::string>& files,
|
||||
bool wantFiles,
|
||||
bool includePath) {
|
||||
|
||||
bool test = wantFiles ? true : false;
|
||||
|
||||
std::string path = "";
|
||||
|
||||
// Find the place where the path ends and the file-spec begins
|
||||
size_t i = filespec.rfind('/');
|
||||
size_t j = filespec.rfind('\\');
|
||||
|
||||
// Drive letters on Windows can separate a path
|
||||
size_t k = filespec.rfind(':');
|
||||
|
||||
if (((j != std::string::npos) && (j > i)) ||
|
||||
(i == std::string::npos)) {
|
||||
i = j;
|
||||
}
|
||||
|
||||
if (((k != std::string::npos) && (k > i)) ||
|
||||
(i == std::string::npos)) {
|
||||
i = k;
|
||||
}
|
||||
|
||||
// If there is a path, pull it off
|
||||
if (i != std::string::npos) {
|
||||
path = filespec.substr(0, i + 1);
|
||||
}
|
||||
|
||||
std::string prefix = path;
|
||||
|
||||
if (path.size() > 0) {
|
||||
// Strip the trailing character
|
||||
path = path.substr(0, path.size() - 1);
|
||||
}
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
{
|
||||
struct _finddata_t fileinfo;
|
||||
|
||||
long handle = _findfirst(filespec.c_str(), &fileinfo);
|
||||
int result = handle;
|
||||
|
||||
while (result != -1) {
|
||||
if ((((fileinfo.attrib & _A_SUBDIR) == 0) == test) &&
|
||||
strcmp(fileinfo.name, ".") &&
|
||||
strcmp(fileinfo.name, "..")) {
|
||||
|
||||
if (includePath) {
|
||||
files.append(prefix + fileinfo.name);
|
||||
} else {
|
||||
files.append(fileinfo.name);
|
||||
}
|
||||
}
|
||||
|
||||
result = _findnext(handle, &fileinfo);
|
||||
}
|
||||
}
|
||||
# else
|
||||
{
|
||||
if (path == "") {
|
||||
// Empty paths don't work on Unix
|
||||
path = ".";
|
||||
}
|
||||
|
||||
// Unix implementation
|
||||
DIR* dir = opendir(path.c_str());
|
||||
|
||||
if (dir != NULL) {
|
||||
struct dirent* entry = readdir(dir);
|
||||
|
||||
while (entry != NULL) {
|
||||
|
||||
// Exclude '.' and '..'
|
||||
if ((strcmp(entry->d_name, ".") != 0) &&
|
||||
(strcmp(entry->d_name, "..") != 0)) {
|
||||
|
||||
// Form a name with a path
|
||||
std::string filename = prefix + entry->d_name;
|
||||
// See if this is a file or a directory
|
||||
struct _stat st;
|
||||
bool exists = _stat(filename.c_str(), &st) != -1;
|
||||
|
||||
if (exists &&
|
||||
|
||||
// Make sure it has the correct type
|
||||
(((st.st_mode & S_IFDIR) == 0) == test) &&
|
||||
|
||||
// Make sure it matches the wildcard
|
||||
(fnmatch(filespec.c_str(),
|
||||
filename.c_str(),
|
||||
FNM_PATHNAME) == 0)) {
|
||||
|
||||
if (includePath) {
|
||||
files.append(filename);
|
||||
} else {
|
||||
files.append(entry->d_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entry = readdir(dir);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
/**
|
||||
@param path The zipfile name (no trailing slash)
|
||||
@param prefix Directory inside the zipfile. No leading slash, must have trailing slash if non-empty.
|
||||
@param file Name inside the zipfile that we are testing to see if it matches prefix + "*"
|
||||
*/
|
||||
static void _zip_addEntry(const std::string& path,
|
||||
const std::string& prefix,
|
||||
const std::string& file,
|
||||
Set<std::string>& files,
|
||||
bool wantFiles,
|
||||
bool includePath) {
|
||||
|
||||
// Make certain we are within the desired parent folder (prefix)
|
||||
if (beginsWith(file, prefix)) {
|
||||
// validityTest was prefix/file
|
||||
|
||||
// Extract everything to the right of the prefix
|
||||
std::string s = file.substr(prefix.length());
|
||||
|
||||
if (s == "") {
|
||||
// This was the name of the prefix
|
||||
return;
|
||||
}
|
||||
|
||||
// See if there are any slashes
|
||||
size_t slashPos = s.find('/');
|
||||
|
||||
bool add = false;
|
||||
|
||||
if (slashPos == std::string::npos) {
|
||||
// No slashes, so s must be a file
|
||||
add = wantFiles;
|
||||
} else if (! wantFiles) {
|
||||
// Not all zipfiles list directories as explicit entries.
|
||||
// Because of this, if we're looking for directories and see
|
||||
// any path longer than prefix, we must add the subdirectory.
|
||||
// The Set will fix duplicates for us.
|
||||
s = s.substr(0, slashPos);
|
||||
add = true;
|
||||
}
|
||||
|
||||
if (add) {
|
||||
if (includePath) {
|
||||
files.insert(path + "/" + prefix + s);
|
||||
} else {
|
||||
files.insert(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void getFileOrDirListZip(const std::string& path,
|
||||
const std::string& prefix,
|
||||
Array<std::string>& files,
|
||||
bool wantFiles,
|
||||
bool includePath){
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
struct zip *z = zip_open( path.c_str(), ZIP_CHECKCONS, NULL );
|
||||
|
||||
Set<std::string> fileSet;
|
||||
|
||||
int count = zip_get_num_files( z );
|
||||
for( int i = 0; i < count; ++i ) {
|
||||
struct zip_stat info;
|
||||
zip_stat_init( &info ); // TODO: Docs unclear if zip_stat_init is required.
|
||||
zip_stat_index( z, i, ZIP_FL_NOCASE, &info );
|
||||
_zip_addEntry(path, prefix, info.name, fileSet, wantFiles, includePath);
|
||||
}
|
||||
|
||||
zip_close( z );
|
||||
|
||||
fileSet.getMembers(files);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void determineFileOrDirList(
|
||||
const std::string& filespec,
|
||||
Array<std::string>& files,
|
||||
bool wantFiles,
|
||||
bool includePath) {
|
||||
|
||||
// if it is a .zip, prefix will specify the folder within
|
||||
// whose contents we want to see
|
||||
std::string prefix = "";
|
||||
std::string path = filenamePath(filespec);
|
||||
|
||||
if ((path.size() > 0) && isSlash(path[path.size() - 1])) {
|
||||
// Strip the trailing slash
|
||||
path = path.substr(0, path.length() -1);
|
||||
}
|
||||
|
||||
if ((path == "") || FileSystem::exists(path)) {
|
||||
if ((path != "") && FileSystem::isZipfile(path)) {
|
||||
// .zip should only work if * is specified as the Base + Ext
|
||||
// Here, we have been asked for the root's contents
|
||||
debugAssertM(filenameBaseExt(filespec) == "*", "Can only call getFiles/getDirs on zipfiles using '*' wildcard");
|
||||
getFileOrDirListZip(path, prefix, files, wantFiles, includePath);
|
||||
} else {
|
||||
// It is a normal directory
|
||||
getFileOrDirListNormal(filespec, files, wantFiles, includePath);
|
||||
}
|
||||
} else if (zipfileExists(filenamePath(filespec), path, prefix)) {
|
||||
// .zip should only work if * is specified as the Base + Ext
|
||||
// Here, we have been asked for the contents of a folder within the .zip
|
||||
debugAssertM(filenameBaseExt(filespec) == "*", "Can only call getFiles/getDirs on zipfiles using '*' wildcard");
|
||||
getFileOrDirListZip(path, prefix, files, wantFiles, includePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void getFiles(const std::string& filespec,
|
||||
Array<std::string>& files,
|
||||
bool includePath) {
|
||||
|
||||
determineFileOrDirList(filespec, files, true, includePath);
|
||||
}
|
||||
|
||||
|
||||
void getDirs(
|
||||
const std::string& filespec,
|
||||
Array<std::string>& files,
|
||||
bool includePath) {
|
||||
|
||||
determineFileOrDirList(filespec, files, false, includePath);
|
||||
}
|
||||
|
||||
|
||||
std::string filenameBaseExt(const std::string& filename) {
|
||||
int i = filename.rfind("/");
|
||||
int j = filename.rfind("\\");
|
||||
|
||||
if ((j > i) && (j >= 0)) {
|
||||
i = j;
|
||||
}
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
j = filename.rfind(":");
|
||||
if ((i == -1) && (j >= 0)) {
|
||||
i = j;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (i == -1) {
|
||||
return filename;
|
||||
} else {
|
||||
return filename.substr(i + 1, filename.length() - i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string filenameBase(const std::string& s) {
|
||||
std::string drive;
|
||||
std::string base;
|
||||
std::string ext;
|
||||
Array<std::string> path;
|
||||
|
||||
parseFilename(s, drive, path, base, ext);
|
||||
return base;
|
||||
}
|
||||
|
||||
|
||||
std::string filenameExt(const std::string& filename) {
|
||||
int i = filename.rfind(".");
|
||||
if (i >= 0) {
|
||||
return filename.substr(i + 1, filename.length() - i);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string filenamePath(const std::string& filename) {
|
||||
int i = filename.rfind("/");
|
||||
int j = filename.rfind("\\");
|
||||
|
||||
if ((j > i) && (j >= 0)) {
|
||||
i = j;
|
||||
}
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
j = filename.rfind(":");
|
||||
if ((i == -1) && (j >= 0)) {
|
||||
i = j;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (i == -1) {
|
||||
return "";
|
||||
} else {
|
||||
return filename.substr(0, i+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool isZipfile(const std::string& filename) {
|
||||
|
||||
FILE* f = fopen(filename.c_str(), "r");
|
||||
if (f == NULL) {
|
||||
return false;
|
||||
}
|
||||
uint8 header[4];
|
||||
fread(header, 4, 1, f);
|
||||
|
||||
const uint8 zipHeader[4] = {0x50, 0x4b, 0x03, 0x04};
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (header[i] != zipHeader[i]) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool isDirectory(const std::string& filename) {
|
||||
struct _stat st;
|
||||
bool exists = _stat(filename.c_str(), &st) != -1;
|
||||
return exists && ((st.st_mode & S_IFDIR) != 0);
|
||||
}
|
||||
|
||||
|
||||
bool filenameContainsWildcards(const std::string& filename) {
|
||||
return (filename.find('*') != std::string::npos) || (filename.find('?') != std::string::npos);
|
||||
}
|
||||
|
||||
|
||||
bool fileIsNewer(const std::string& src, const std::string& dst) {
|
||||
struct _stat sts;
|
||||
bool sexists = _stat(src.c_str(), &sts) != -1;
|
||||
|
||||
struct _stat dts;
|
||||
bool dexists = _stat(dst.c_str(), &dts) != -1;
|
||||
|
||||
return sexists && ((! dexists) || (sts.st_mtime > dts.st_mtime));
|
||||
}
|
||||
|
||||
|
||||
Array<std::string> filesUsed() {
|
||||
Array<std::string> f;
|
||||
_internal::currentFilesUsed.getMembers(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifndef G3D_WIN32
|
||||
#undef _stat
|
||||
#endif
|
||||
32
modules/acore/deps/g3dlite/source/filter.cpp
Normal file
32
modules/acore/deps/g3dlite/source/filter.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
@file filter.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2007-03-01
|
||||
@edited 2007-03-01
|
||||
|
||||
Copyright 2000-2007, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
#include "G3D/filter.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void gaussian1D(Array<float>& coeff, int N, float std) {
|
||||
coeff.resize(N);
|
||||
float sum = 0.0f;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
float x = i - (N - 1) / 2.0f;
|
||||
float p = -square(x / std) / 2.0f;
|
||||
float y = exp(p);
|
||||
coeff[i] = y;
|
||||
sum += y;
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
coeff[i] /= sum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
164
modules/acore/deps/g3dlite/source/format.cpp
Normal file
164
modules/acore/deps/g3dlite/source/format.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
@file format.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2000-09-09
|
||||
@edited 2006-08-14
|
||||
*/
|
||||
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// disable: "C++ exception handler used"
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable : 4530)
|
||||
#endif // _MSC_VER
|
||||
|
||||
// If your platform does not have vsnprintf, you can find a
|
||||
// implementation at http://www.ijs.si/software/snprintf/
|
||||
|
||||
namespace G3D {
|
||||
|
||||
std::string __cdecl format(const char* fmt,...) {
|
||||
va_list argList;
|
||||
va_start(argList,fmt);
|
||||
std::string result = vformat(fmt, argList);
|
||||
va_end(argList);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
// Both MSVC seems to use the non-standard vsnprintf
|
||||
// so we are using vscprintf to determine buffer size, however
|
||||
// only MSVC7 and up headers include vscprintf for some reason.
|
||||
std::string vformat(const char *fmt, va_list argPtr) {
|
||||
// We draw the line at a 1MB string.
|
||||
const int maxSize = 1000000;
|
||||
|
||||
// If the string is less than 161 characters,
|
||||
// allocate it on the stack because this saves
|
||||
// the malloc/free time.
|
||||
const int bufSize = 161;
|
||||
char stackBuffer[bufSize];
|
||||
|
||||
// MSVC does not support va_copy
|
||||
int actualSize = _vscprintf(fmt, argPtr) + 1;
|
||||
|
||||
if (actualSize > bufSize) {
|
||||
|
||||
// Now use the heap.
|
||||
char* heapBuffer = NULL;
|
||||
|
||||
if (actualSize < maxSize) {
|
||||
|
||||
heapBuffer = (char*)System::malloc(maxSize + 1);
|
||||
_vsnprintf(heapBuffer, maxSize, fmt, argPtr);
|
||||
heapBuffer[maxSize] = '\0';
|
||||
} else {
|
||||
heapBuffer = (char*)System::malloc(actualSize);
|
||||
vsprintf(heapBuffer, fmt, argPtr);
|
||||
}
|
||||
|
||||
std::string formattedString(heapBuffer);
|
||||
System::free(heapBuffer);
|
||||
return formattedString;
|
||||
} else {
|
||||
|
||||
vsprintf(stackBuffer, fmt, argPtr);
|
||||
return std::string(stackBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER) && (_MSC_VER < 1300)
|
||||
|
||||
std::string vformat(const char *fmt, va_list argPtr) {
|
||||
// We draw the line at a 1MB string.
|
||||
const int maxSize = 1000000;
|
||||
|
||||
// If the string is less than 161 characters,
|
||||
// allocate it on the stack because this saves
|
||||
// the malloc/free time.
|
||||
const int bufSize = 161;
|
||||
char stackBuffer[bufSize];
|
||||
|
||||
// MSVC6 doesn't support va_copy, however it also seems to compile
|
||||
// correctly if we just pass our argument list along. Note that
|
||||
// this whole code block is only compiled if we're on MSVC6 anyway
|
||||
int actualWritten = _vsnprintf(stackBuffer, bufSize, fmt, argPtr);
|
||||
|
||||
// Not a big enough buffer, bufSize characters written
|
||||
if (actualWritten == -1) {
|
||||
|
||||
int heapSize = 512;
|
||||
double powSize = 1.0;
|
||||
char* heapBuffer = (char*)System::malloc(heapSize);
|
||||
|
||||
while ((_vsnprintf(heapBuffer, heapSize, fmt, argPtr) == -1) &&
|
||||
(heapSize < maxSize)) {
|
||||
|
||||
heapSize = iCeil(heapSize * ::pow((double)2.0, powSize++));
|
||||
heapBuffer = (char*)System::realloc(heapBuffer, heapSize);
|
||||
}
|
||||
|
||||
heapBuffer[heapSize-1] = '\0';
|
||||
|
||||
std::string heapString(heapBuffer);
|
||||
System::free(heapBuffer);
|
||||
|
||||
return heapString;
|
||||
} else {
|
||||
|
||||
return std::string(stackBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// glibc 2.1 has been updated to the C99 standard
|
||||
std::string vformat(const char* fmt, va_list argPtr) {
|
||||
// If the string is less than 161 characters,
|
||||
// allocate it on the stack because this saves
|
||||
// the malloc/free time. The number 161 is chosen
|
||||
// to support two lines of text on an 80 character
|
||||
// console (plus the null terminator).
|
||||
const int bufSize = 161;
|
||||
char stackBuffer[bufSize];
|
||||
|
||||
va_list argPtrCopy;
|
||||
va_copy(argPtrCopy, argPtr);
|
||||
int numChars = vsnprintf(stackBuffer, bufSize, fmt, argPtrCopy);
|
||||
va_end(argPtrCopy);
|
||||
|
||||
if (numChars >= bufSize) {
|
||||
// We didn't allocate a big enough string.
|
||||
char* heapBuffer = (char*)System::malloc((numChars + 1) * sizeof(char));
|
||||
|
||||
debugAssert(heapBuffer);
|
||||
int numChars2 = vsnprintf(heapBuffer, numChars + 1, fmt, argPtr);
|
||||
debugAssert(numChars2 == numChars);
|
||||
(void)numChars2;
|
||||
|
||||
std::string result(heapBuffer);
|
||||
|
||||
System::free(heapBuffer);
|
||||
|
||||
return result;
|
||||
|
||||
} else {
|
||||
|
||||
return std::string(stackBuffer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
223
modules/acore/deps/g3dlite/source/g3dfnmatch.cpp
Normal file
223
modules/acore/deps/g3dlite/source/g3dfnmatch.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/* $Id: g3dfnmatch.cpp,v 1.3 2010/03/15 05:01:23 morgan3d Exp $ */
|
||||
|
||||
/* $OpenBSD: fnmatch.c,v 1.7 2000/03/23 19:13:51 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Guido van Rossum.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#include "G3D/g3dfnmatch.h"
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
#define EOS '\0'
|
||||
|
||||
#define RANGE_MATCH 1
|
||||
#define RANGE_NOMATCH 0
|
||||
#define RANGE_ERROR (-1)
|
||||
|
||||
static int rangematch(const char *, char, int, char **);
|
||||
|
||||
int
|
||||
g3dfnmatch(const char *pattern, const char *string, int flags)
|
||||
{
|
||||
const char *stringstart;
|
||||
char *newp;
|
||||
char c, test;
|
||||
|
||||
for (stringstart = string;;)
|
||||
switch (c = *pattern++) {
|
||||
case EOS:
|
||||
if ((flags & FNM_LEADING_DIR) && *string == '/')
|
||||
return (0);
|
||||
return (*string == EOS ? 0 : FNM_NOMATCH);
|
||||
case '?':
|
||||
if (*string == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '/' && (flags & FNM_PATHNAME))
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
++string;
|
||||
break;
|
||||
case '*':
|
||||
c = *pattern;
|
||||
/* Collapse multiple stars. */
|
||||
while (c == '*')
|
||||
c = *++pattern;
|
||||
|
||||
if (*string == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
/* Optimize for pattern with * at end or before /. */
|
||||
if (c == EOS) {
|
||||
if (flags & FNM_PATHNAME)
|
||||
return ((flags & FNM_LEADING_DIR) ||
|
||||
strchr(string, '/') == NULL ?
|
||||
0 : FNM_NOMATCH);
|
||||
else
|
||||
return (0);
|
||||
} else if (c == '/' && (flags & FNM_PATHNAME)) {
|
||||
if ((string = strchr(string, '/')) == NULL)
|
||||
return (FNM_NOMATCH);
|
||||
break;
|
||||
}
|
||||
|
||||
/* General case, use recursion. */
|
||||
while ((test = *string) != EOS) {
|
||||
if (!g3dfnmatch(pattern, string, flags & ~FNM_PERIOD))
|
||||
return (0);
|
||||
if (test == '/' && (flags & FNM_PATHNAME))
|
||||
break;
|
||||
++string;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
case '[':
|
||||
if (*string == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '/' && (flags & FNM_PATHNAME))
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
switch (rangematch(pattern, *string, flags, &newp)) {
|
||||
case RANGE_ERROR:
|
||||
/* not a good range, treat as normal text */
|
||||
goto normal;
|
||||
case RANGE_MATCH:
|
||||
pattern = newp;
|
||||
break;
|
||||
case RANGE_NOMATCH:
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
++string;
|
||||
break;
|
||||
case '\\':
|
||||
if (!(flags & FNM_NOESCAPE)) {
|
||||
if ((c = *pattern++) == EOS) {
|
||||
c = '\\';
|
||||
--pattern;
|
||||
}
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
normal:
|
||||
if (c != *string && !((flags & FNM_CASEFOLD) &&
|
||||
(tolower((unsigned char)c) ==
|
||||
tolower((unsigned char)*string))))
|
||||
return (FNM_NOMATCH);
|
||||
++string;
|
||||
break;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static int
|
||||
rangematch(const char *pattern, char test, int flags, char **newp)
|
||||
{
|
||||
int negate, ok;
|
||||
char c, c2;
|
||||
|
||||
/*
|
||||
* A bracket expression starting with an unquoted circumflex
|
||||
* character produces unspecified results (IEEE 1003.2-1992,
|
||||
* 3.13.2). This implementation treats it like '!', for
|
||||
* consistency with the regular expression syntax.
|
||||
* J.T. Conklin (conklin@ngai.kaleida.com)
|
||||
*/
|
||||
if ((negate = (*pattern == '!' || *pattern == '^')))
|
||||
++pattern;
|
||||
|
||||
if (flags & FNM_CASEFOLD)
|
||||
test = tolower((unsigned char)test);
|
||||
|
||||
/*
|
||||
* A right bracket shall lose its special meaning and represent
|
||||
* itself in a bracket expression if it occurs first in the list.
|
||||
* -- POSIX.2 2.8.3.2
|
||||
*/
|
||||
ok = 0;
|
||||
c = *pattern++;
|
||||
do {
|
||||
if (c == '\\' && !(flags & FNM_NOESCAPE))
|
||||
c = *pattern++;
|
||||
if (c == EOS)
|
||||
return (RANGE_ERROR);
|
||||
if (c == '/' && (flags & FNM_PATHNAME))
|
||||
return (RANGE_NOMATCH);
|
||||
if ((flags & FNM_CASEFOLD))
|
||||
c = tolower((unsigned char)c);
|
||||
if (*pattern == '-'
|
||||
&& (c2 = *(pattern+1)) != EOS && c2 != ']') {
|
||||
pattern += 2;
|
||||
if (c2 == '\\' && !(flags & FNM_NOESCAPE))
|
||||
c2 = *pattern++;
|
||||
if (c2 == EOS)
|
||||
return (RANGE_ERROR);
|
||||
if (flags & FNM_CASEFOLD)
|
||||
c2 = tolower((unsigned char)c2);
|
||||
if (c <= test && test <= c2)
|
||||
ok = 1;
|
||||
} else if (c == test)
|
||||
ok = 1;
|
||||
} while ((c = *pattern++) != ']');
|
||||
|
||||
*newp = (char *)pattern;
|
||||
return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace G3D {
|
||||
int g3dfnmatch(const char * a, const char *b, int c) {
|
||||
return fnmatch(a, b, c);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
109
modules/acore/deps/g3dlite/source/g3dmath.cpp
Normal file
109
modules/acore/deps/g3dlite/source/g3dmath.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
@file g3dmath.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2004-02-24
|
||||
*/
|
||||
|
||||
#include "G3D/g3dmath.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace G3D {
|
||||
|
||||
float gaussRandom(float mean, float stdev) {
|
||||
|
||||
// Using Box-Mueller method from http://www.taygeta.com/random/gaussian.html
|
||||
// Modified to specify standard deviation and mean of distribution
|
||||
float w, x1, x2;
|
||||
|
||||
// Loop until w is less than 1 so that log(w) is negative
|
||||
do {
|
||||
x1 = uniformRandom(-1.0, 1.0);
|
||||
x2 = uniformRandom(-1.0, 1.0);
|
||||
|
||||
w = float(square(x1) + square(x2));
|
||||
} while (w > 1.0f);
|
||||
|
||||
// Transform to gassian distribution
|
||||
// Multiply by sigma (stdev ^ 2) and add mean.
|
||||
return x2 * (float)square(stdev) * sqrtf((-2.0f * logf(w) ) / w) + mean;
|
||||
}
|
||||
|
||||
/**
|
||||
This value should not be tested against directly, instead
|
||||
G3D::isNan() and G3D::isFinite() will return reliable results. */
|
||||
double inf() {
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
bool isNaN(float x) {
|
||||
static const float n = fnan();
|
||||
return memcmp(&x, &n, sizeof(float)) == 0;
|
||||
}
|
||||
|
||||
bool isNaN(double x) {
|
||||
static const double n = nan();
|
||||
return memcmp(&x, &n, sizeof(double)) == 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This value should not be tested against directly, instead
|
||||
G3D::isNan() and G3D::isFinite() will return reliable results. */
|
||||
float finf() {
|
||||
return std::numeric_limits<float>::infinity();
|
||||
}
|
||||
|
||||
/** This value should not be tested against directly, instead
|
||||
G3D::isNan() and G3D::isFinite() will return reliable results. */
|
||||
double nan() {
|
||||
// double is a standard type and should have quiet NaN
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
float fnan() {
|
||||
// double is a standard type and should have quiet NaN
|
||||
return std::numeric_limits<float>::quiet_NaN();
|
||||
}
|
||||
|
||||
|
||||
int highestBit(uint32 x) {
|
||||
// Binary search.
|
||||
int base = 0;
|
||||
|
||||
if (x & 0xffff0000) {
|
||||
base = 16;
|
||||
x >>= 16;
|
||||
}
|
||||
if (x & 0x0000ff00) {
|
||||
base += 8;
|
||||
x >>= 8;
|
||||
}
|
||||
if (x & 0x000000f0) {
|
||||
base += 4;
|
||||
x >>= 4;
|
||||
}
|
||||
|
||||
static const int lut[] = {-1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3};
|
||||
return base + lut[x];
|
||||
}
|
||||
|
||||
|
||||
int iRandom(int low, int high) {
|
||||
int r = iFloor(low + (high - low + 1) * (double)rand() / RAND_MAX);
|
||||
|
||||
// There is a *very small* chance of generating
|
||||
// a number larger than high.
|
||||
if (r > high) {
|
||||
return high;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
73
modules/acore/deps/g3dlite/source/license.cpp
Normal file
73
modules/acore/deps/g3dlite/source/license.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
@file license.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2004-04-15
|
||||
@edited 2004-04-15
|
||||
*/
|
||||
|
||||
#include "G3D/format.h"
|
||||
#include <string>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
std::string license() {
|
||||
return format(
|
||||
|
||||
"This software is based in part on the PNG Reference Library which is\n"
|
||||
"Copyright (c) 2004 Glenn Randers-Pehrson\n\n"
|
||||
"This software is based in part on the work of the Independent JPEG Group.\n\n"
|
||||
"This software is based on part on the FFmpeg libavformat and libavcodec libraries\n"
|
||||
"(\"FFmpeg\", http://ffmpeg.mplayerhq.hu), which are included under the terms of the\n"
|
||||
"GNU Lesser General Public License (LGPL), (http://www.gnu.org/copyleft/lesser.html).\n\n"
|
||||
"%s"
|
||||
"This program uses the G3D Library (http://g3d.sf.net), which\n"
|
||||
"is licensed under the \"Modified BSD\" Open Source license. The G3D library\n"
|
||||
"source code is Copyright © 2000-2010, Morgan McGuire, All rights reserved.\n"
|
||||
"This program uses The OpenGL Extension Wrangler Library, which \n"
|
||||
"is licensed under the \"Modified BSD\" Open Source license. \n"
|
||||
"The OpenGL Extension Wrangler Library source code is\n"
|
||||
"Copyright (C) 2002-2008, Milan Ikits <milan ikits[]ieee org>\n"
|
||||
"Copyright (C) 2002-2008, Marcelo E. Magallon <mmagallo[]debian org>\n"
|
||||
"Copyright (C) 2002, Lev Povalahev\n"
|
||||
"All rights reserved.\n\n"
|
||||
"The Modified BSD license is below, and requires the following statement:\n"
|
||||
"\n"
|
||||
"Redistribution and use in source and binary forms, with or without \n"
|
||||
"modification, are permitted provided that the following conditions are met:\n"
|
||||
"\n"
|
||||
"* Redistributions of source code must retain the above copyright notice, \n"
|
||||
" this list of conditions and the following disclaimer.\n"
|
||||
"* Redistributions in binary form must reproduce the above copyright notice, \n"
|
||||
" this list of conditions and the following disclaimer in the documentation \n"
|
||||
" and/or other materials provided with the distribution.\n"
|
||||
"* The name of the author may be used to endorse or promote products \n"
|
||||
" derived from this software without specific prior written permission.\n"
|
||||
"\n"
|
||||
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" \n"
|
||||
"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \n"
|
||||
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
|
||||
"ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE \n"
|
||||
"LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR \n"
|
||||
"CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF \n"
|
||||
"SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
|
||||
"INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
|
||||
"CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
|
||||
"ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n"
|
||||
"THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||
"\n\n"
|
||||
"G3D VERSION %d\n",
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
"" // Win32 doesn't use SDL
|
||||
#else
|
||||
"This software uses the Simple DirectMedia Layer library (\"SDL\",\n"
|
||||
"http://www.libsdl.org), which is included under the terms of the\n"
|
||||
"GNU Lesser General Public License, (http://www.gnu.org/copyleft/lesser.html).\n\n"
|
||||
#endif
|
||||
,
|
||||
G3D_VER);
|
||||
}
|
||||
|
||||
}
|
||||
738
modules/acore/deps/g3dlite/source/prompt.cpp
Normal file
738
modules/acore/deps/g3dlite/source/prompt.cpp
Normal file
@@ -0,0 +1,738 @@
|
||||
/**
|
||||
@file prompt.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@cite Windows dialog interface by Max McGuire, mmcguire@ironlore.com
|
||||
@cite Font setting code by Kurt Miller, kurt@flipcode.com
|
||||
|
||||
@created 2000-08-26
|
||||
@edited 2005-01-14
|
||||
*/
|
||||
|
||||
#include "G3D/prompt.h"
|
||||
#include "G3D/platform.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
# include <sstream>
|
||||
# include <conio.h>
|
||||
#else
|
||||
# define _getch getchar
|
||||
#endif
|
||||
|
||||
#if 0 /* G3DFIX: exclude GUI prompt code */
|
||||
#ifdef G3D_OSX
|
||||
|
||||
/*#ifdef __LP64__
|
||||
# undef __LP64__
|
||||
#endif
|
||||
*/
|
||||
|
||||
# include <Carbon/Carbon.h>
|
||||
|
||||
/*
|
||||
#ifdef G3D_64BIT
|
||||
# define __LP64__
|
||||
#endif
|
||||
*/
|
||||
|
||||
#endif
|
||||
#endif /* G3DFIX: exclude GUI prompt code */
|
||||
|
||||
namespace G3D {
|
||||
|
||||
#if 0 /* G3DFIX: exclude GUI prompt code */
|
||||
#ifdef G3D_WIN32
|
||||
|
||||
namespace _internal {
|
||||
/**
|
||||
Generic Win32 dialog facility.
|
||||
@author Max McGuire
|
||||
*/
|
||||
class DialogTemplate {
|
||||
public:
|
||||
|
||||
DialogTemplate(LPCSTR caption, DWORD style,
|
||||
int x, int y, int w, int h,
|
||||
LPCSTR font = NULL, WORD fontSize = 8) {
|
||||
|
||||
usedBufferLength = sizeof(DLGTEMPLATE);
|
||||
totalBufferLength = usedBufferLength;
|
||||
|
||||
dialogTemplate = (DLGTEMPLATE*)malloc(totalBufferLength);
|
||||
|
||||
dialogTemplate->style = style;
|
||||
|
||||
if (font != NULL) {
|
||||
dialogTemplate->style |= DS_SETFONT;
|
||||
}
|
||||
|
||||
dialogTemplate->x = (short)x;
|
||||
dialogTemplate->y = (short)y;
|
||||
dialogTemplate->cx = (short)w;
|
||||
dialogTemplate->cy = (short)h;
|
||||
dialogTemplate->cdit = 0;
|
||||
|
||||
dialogTemplate->dwExtendedStyle = 0;
|
||||
|
||||
// The dialog box doesn't have a menu or a special class
|
||||
AppendData("\0", 2);
|
||||
AppendData("\0", 2);
|
||||
|
||||
// Add the dialog's caption to the template
|
||||
|
||||
AppendString(caption);
|
||||
|
||||
if (font != NULL) {
|
||||
AppendData(&fontSize, sizeof(WORD));
|
||||
AppendString(font);
|
||||
}
|
||||
}
|
||||
|
||||
void AddComponent(LPCSTR type, LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
|
||||
|
||||
DLGITEMTEMPLATE item;
|
||||
|
||||
item.style = style;
|
||||
item.x = (short)x;
|
||||
item.y = (short)y;
|
||||
item.cx = (short)w;
|
||||
item.cy = (short)h;
|
||||
item.id = id;
|
||||
|
||||
item.dwExtendedStyle = exStyle;
|
||||
|
||||
AppendData(&item, sizeof(DLGITEMTEMPLATE));
|
||||
|
||||
AppendString(type);
|
||||
AppendString(caption);
|
||||
|
||||
WORD creationDataLength = 0;
|
||||
AppendData(&creationDataLength, sizeof(WORD));
|
||||
|
||||
// Increment the component count
|
||||
dialogTemplate->cdit++;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void AddButton(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
|
||||
|
||||
AddStandardComponent(0x0080, caption, style, exStyle, x, y, w, h, id);
|
||||
|
||||
WORD creationDataLength = 0;
|
||||
AppendData(&creationDataLength, sizeof(WORD));
|
||||
|
||||
}
|
||||
|
||||
|
||||
void AddEditBox(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
|
||||
|
||||
AddStandardComponent(0x0081, caption, style, exStyle, x, y, w, h, id);
|
||||
|
||||
WORD creationDataLength = 0;
|
||||
AppendData(&creationDataLength, sizeof(WORD));
|
||||
|
||||
}
|
||||
|
||||
|
||||
void AddStatic(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
|
||||
|
||||
AddStandardComponent(0x0082, caption, style, exStyle, x, y, w, h, id);
|
||||
|
||||
WORD creationDataLength = 0;
|
||||
AppendData(&creationDataLength, sizeof(WORD));
|
||||
|
||||
}
|
||||
|
||||
|
||||
void AddListBox(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
|
||||
|
||||
AddStandardComponent(0x0083, caption, style, exStyle, x, y, w, h, id);
|
||||
|
||||
WORD creationDataLength = sizeof(WORD) + 5 * sizeof(WCHAR);
|
||||
AppendData(&creationDataLength, sizeof(WORD));
|
||||
|
||||
AppendString("TEST");
|
||||
|
||||
}
|
||||
|
||||
|
||||
void AddScrollBar(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
|
||||
|
||||
AddStandardComponent(0x0084, caption, style, exStyle, x, y, w, h, id);
|
||||
|
||||
WORD creationDataLength = 0;
|
||||
AppendData(&creationDataLength, sizeof(WORD));
|
||||
|
||||
}
|
||||
|
||||
|
||||
void AddComboBox(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
|
||||
|
||||
AddStandardComponent(0x0085, caption, style, exStyle, x, y, w, h, id);
|
||||
|
||||
WORD creationDataLength = 0;
|
||||
AppendData(&creationDataLength, sizeof(WORD));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns a pointer to the Win32 dialog template which the object
|
||||
* represents. This pointer may become invalid if additional components
|
||||
* are added to the template.
|
||||
*
|
||||
*/
|
||||
operator const DLGTEMPLATE*() const {
|
||||
return dialogTemplate;
|
||||
}
|
||||
|
||||
virtual ~DialogTemplate() {
|
||||
free(dialogTemplate);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void AddStandardComponent(WORD type, LPCSTR caption, DWORD style, DWORD exStyle,
|
||||
int x, int y, int w, int h, WORD id, LPSTR font = NULL, WORD fontSize = 8) {
|
||||
|
||||
DLGITEMTEMPLATE item;
|
||||
|
||||
// DWORD align the beginning of the component data
|
||||
|
||||
AlignData(sizeof(DWORD));
|
||||
|
||||
item.style = style;
|
||||
if (font != NULL) {
|
||||
item.style |= DS_SETFONT;
|
||||
}
|
||||
item.x = (short)x;
|
||||
item.y = (short)y;
|
||||
item.cx = (short)w;
|
||||
item.cy = (short)h;
|
||||
item.id = id;
|
||||
|
||||
item.dwExtendedStyle = exStyle;
|
||||
|
||||
AppendData(&item, sizeof(DLGITEMTEMPLATE));
|
||||
|
||||
WORD preType = 0xFFFF;
|
||||
|
||||
AppendData(&preType, sizeof(WORD));
|
||||
AppendData(&type, sizeof(WORD));
|
||||
|
||||
AppendString(caption);
|
||||
|
||||
if (font != NULL) {
|
||||
AppendData(&fontSize, sizeof(WORD));
|
||||
AppendString(font);
|
||||
}
|
||||
|
||||
// Increment the component count
|
||||
dialogTemplate->cdit++;
|
||||
}
|
||||
|
||||
|
||||
void AlignData(int size) {
|
||||
|
||||
int paddingSize = usedBufferLength % size;
|
||||
|
||||
if (paddingSize != 0) {
|
||||
EnsureSpace(paddingSize);
|
||||
usedBufferLength += paddingSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AppendString(LPCSTR string) {
|
||||
|
||||
int length = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0);
|
||||
|
||||
WCHAR* wideString = (WCHAR*)malloc(sizeof(WCHAR) * length);
|
||||
MultiByteToWideChar(CP_ACP, 0, string, -1, wideString, length);
|
||||
|
||||
AppendData(wideString, length * sizeof(WCHAR));
|
||||
free(wideString);
|
||||
|
||||
}
|
||||
|
||||
void AppendData(const void* data, int dataLength) {
|
||||
|
||||
EnsureSpace(dataLength);
|
||||
|
||||
memcpy((char*)dialogTemplate + usedBufferLength, data, dataLength);
|
||||
usedBufferLength += dataLength;
|
||||
|
||||
}
|
||||
|
||||
void EnsureSpace(int length) {
|
||||
if (length + usedBufferLength > totalBufferLength) {
|
||||
totalBufferLength += length * 2;
|
||||
|
||||
void* newBuffer = malloc(totalBufferLength);
|
||||
memcpy(newBuffer, dialogTemplate, usedBufferLength);
|
||||
|
||||
free(dialogTemplate);
|
||||
dialogTemplate = (DLGTEMPLATE*)newBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DLGTEMPLATE* dialogTemplate;
|
||||
|
||||
int totalBufferLength;
|
||||
int usedBufferLength;
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct PromptParams {
|
||||
const char* message;
|
||||
const char* title;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constants for controls.
|
||||
*/
|
||||
#define IDC_MESSAGE 1000
|
||||
#define IDC_BUTTON0 2000
|
||||
|
||||
INT_PTR CALLBACK PromptDlgProc(HWND hDlg, UINT msg,
|
||||
WPARAM wParam, LPARAM lParam) {
|
||||
switch(msg) {
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
PromptParams *params = (PromptParams*)lParam;
|
||||
::SetWindowTextA(::GetDlgItem(hDlg, IDC_MESSAGE), params->message);
|
||||
|
||||
::SetFocus(::GetDlgItem(hDlg, IDC_BUTTON0));
|
||||
|
||||
SetWindowTextA(hDlg, params->title);
|
||||
|
||||
HFONT hfont =
|
||||
CreateFontA(16, 0, 0, 0, FW_NORMAL,
|
||||
FALSE, FALSE, FALSE,
|
||||
ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
|
||||
PROOF_QUALITY, FIXED_PITCH | FF_MODERN, "Courier New");
|
||||
|
||||
SendDlgItemMessage(hDlg, IDC_MESSAGE, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE,0));
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_COMMAND:
|
||||
{
|
||||
int choiceNumber = LOWORD(wParam) - IDC_BUTTON0;
|
||||
if ((choiceNumber >= 0) && (choiceNumber < 10)) {
|
||||
EndDialog(hDlg, choiceNumber);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WM_NCDESTROY:
|
||||
// Under SDL 1.2.6 we get a NCDESTROY message for no reason and the
|
||||
// window is immediately closed. This is here to debug the problem.
|
||||
(void)0;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}; // namespace _internal
|
||||
|
||||
|
||||
using namespace _internal;
|
||||
|
||||
/**
|
||||
* Show a dialog prompt.
|
||||
*/
|
||||
static int guiPrompt(
|
||||
const char* windowTitle,
|
||||
const char* prompt,
|
||||
const char** choice,
|
||||
int numChoices) {
|
||||
|
||||
int width = 280;
|
||||
int height = 128;
|
||||
|
||||
const int buttonSpacing = 2;
|
||||
const int buttonWidth =
|
||||
(width - buttonSpacing * 2 -
|
||||
buttonSpacing * (numChoices - 1)) / numChoices;
|
||||
const int buttonHeight = 13;
|
||||
|
||||
|
||||
DialogTemplate dialogTemplate(
|
||||
windowTitle,
|
||||
WS_CAPTION | DS_CENTER | WS_SYSMENU,
|
||||
10, 10, width, height,
|
||||
"Tahoma");
|
||||
|
||||
dialogTemplate.AddEditBox(
|
||||
"Edit", WS_VISIBLE | ES_READONLY | ES_OEMCONVERT | ES_MULTILINE | WS_TABSTOP, WS_EX_STATICEDGE,
|
||||
2, 2, width - 4, height - buttonHeight - 7, IDC_MESSAGE);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < numChoices; i++) {
|
||||
|
||||
int x = buttonSpacing + i * (buttonWidth + buttonSpacing);
|
||||
int y = height - buttonHeight - buttonSpacing;
|
||||
|
||||
dialogTemplate.AddButton(choice[i], WS_VISIBLE | WS_TABSTOP, 0,
|
||||
x, y, buttonWidth, buttonHeight, IDC_BUTTON0 + (WORD)i);
|
||||
|
||||
}
|
||||
|
||||
// Convert all single \n characters to \r\n for proper printing
|
||||
int strLen = 0;
|
||||
const char* pStr = prompt;
|
||||
|
||||
while (*pStr != '\0') {
|
||||
if ((*pStr == '\n') && (pStr != prompt)) {
|
||||
if (*(pStr - 1) != '\r') {
|
||||
++strLen;
|
||||
}
|
||||
}
|
||||
++strLen;
|
||||
++pStr;
|
||||
}
|
||||
|
||||
char* newStr = (char*)malloc(strLen + 1);
|
||||
|
||||
const char* pStr2 = prompt;
|
||||
char* pNew = newStr;
|
||||
|
||||
while (*pStr2 != '\0') {
|
||||
if ((*pStr2 == '\n') && (pStr2 != prompt)) {
|
||||
if (*(pStr2 - 1) != '\r') {
|
||||
*pNew = '\r';
|
||||
++pNew;
|
||||
}
|
||||
}
|
||||
*pNew = *pStr2;
|
||||
++pNew;
|
||||
++pStr2;
|
||||
}
|
||||
|
||||
*pNew = '\0';
|
||||
|
||||
PromptParams params;
|
||||
params.message = newStr;;
|
||||
params.title = windowTitle;
|
||||
|
||||
HMODULE module = GetModuleHandle(0);
|
||||
int ret = DialogBoxIndirectParam(module, dialogTemplate, NULL, (DLGPROC) PromptDlgProc, (DWORD)¶ms);
|
||||
|
||||
free(newStr);
|
||||
|
||||
/*
|
||||
For debugging when DialogBoxIndirectParam fails:
|
||||
|
||||
// The last error value. (Which is preserved across the call).
|
||||
DWORD lastErr = GetLastError();
|
||||
|
||||
// The decoded message from FormatMessage
|
||||
LPTSTR formatMsg = NULL;
|
||||
|
||||
if (NULL == formatMsg) {
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
lastErr,
|
||||
0,
|
||||
(LPTSTR)&formatMsg,
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
// Make sure the message got translated into something.
|
||||
LPTSTR realLastErr;
|
||||
if (NULL != formatMsg) {
|
||||
realLastErr = formatMsg;
|
||||
} else {
|
||||
realLastErr = "Last error code does not exist.";
|
||||
}
|
||||
|
||||
// Get rid of the allocated memory from FormatMessage.
|
||||
if (NULL != formatMsg) {
|
||||
LocalFree((LPVOID)formatMsg);
|
||||
}
|
||||
*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* G3DFIX: exclude GUI prompt code */
|
||||
|
||||
|
||||
/**
|
||||
* Show a prompt on stdout
|
||||
*/
|
||||
static int textPrompt(
|
||||
const char* windowTitle,
|
||||
const char* prompt,
|
||||
const char** choice,
|
||||
int numChoices) {
|
||||
|
||||
printf("\n___________________________________________________\n");
|
||||
printf("%s\n", windowTitle);
|
||||
printf("%s", prompt);
|
||||
|
||||
if (numChoices > 10) {
|
||||
numChoices = 10;
|
||||
}
|
||||
|
||||
int c = -1;
|
||||
if (numChoices > 1) {
|
||||
printf("\n");
|
||||
printf("Choose an option by number:");
|
||||
|
||||
while ((c < 0) || (c >= numChoices)) {
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < numChoices; i++) {
|
||||
if (numChoices <= 3) {
|
||||
printf(" (%d) %s ", i, choice[i]);
|
||||
} else {
|
||||
printf(" (%d) %s\n", i, choice[i]);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n> ");
|
||||
c = _getch() - '0';
|
||||
|
||||
if ((c < 0) || (c >= numChoices)) {
|
||||
printf("'%d' is not a valid choice.", c);
|
||||
} else {
|
||||
printf("%d", c);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (numChoices == 1) {
|
||||
|
||||
printf("\nPress any key for '%s'...", choice[0]);
|
||||
_getch();
|
||||
c = 0;
|
||||
|
||||
} else {
|
||||
|
||||
printf("\nPress any key...");
|
||||
_getch();
|
||||
c = 0;
|
||||
}
|
||||
|
||||
printf("\n___________________________________________________\n");
|
||||
return c;
|
||||
}
|
||||
|
||||
#if 0 /* G3DFIX: exclude GUI prompt code */
|
||||
|
||||
#ifdef G3D_OSX
|
||||
|
||||
// See http://developer.apple.com/documentation/Carbon/Reference/Carbon_Event_Manager_Ref/index.html
|
||||
|
||||
#define CARBON_COMMANDID_START 128
|
||||
#define CARBON_BUTTON_SPACING 12
|
||||
#define CARBON_BUTTON_HEIGHT 20
|
||||
#define CARBON_BUTTON_MINWIDTH 69
|
||||
#define CARBON_WINDOW_PADDING 20
|
||||
|
||||
struct CallbackData {
|
||||
WindowRef refWindow;
|
||||
|
||||
/** Index of this particular button */
|
||||
int myIndex;
|
||||
|
||||
/** Buttons store their index into here when pressed. */
|
||||
int* whichButton;
|
||||
};
|
||||
|
||||
/**
|
||||
Assumes that userData is a pointer to a carbon_evt_data_t.
|
||||
|
||||
*/
|
||||
static pascal OSStatus DoCommandEvent(EventHandlerCallRef handlerRef, EventRef event, void* userData) {
|
||||
// See http://developer.apple.com/documentation/Carbon/Conceptual/HandlingWindowsControls/index.html
|
||||
|
||||
CallbackData& callbackData = *(CallbackData*)userData;
|
||||
|
||||
# pragma unused(handlerRef)
|
||||
|
||||
callbackData.whichButton[0] = callbackData.myIndex;
|
||||
|
||||
// If we get here we can close the window
|
||||
::QuitAppModalLoopForWindow(callbackData.refWindow);
|
||||
|
||||
// Return noErr to indicate that we handled the event
|
||||
return noErr;
|
||||
}
|
||||
|
||||
static int guiPrompt
|
||||
(const char* windowTitle,
|
||||
const char* prompt,
|
||||
const char** choice,
|
||||
int numChoices) {
|
||||
|
||||
WindowRef window;
|
||||
|
||||
int iNumButtonRows = 0;
|
||||
int iButtonWidth = -1;
|
||||
OSStatus err = noErr;
|
||||
|
||||
// Determine number of rows of buttons
|
||||
while (iButtonWidth < CARBON_BUTTON_MINWIDTH) {
|
||||
++iNumButtonRows;
|
||||
iButtonWidth =
|
||||
(550 - (CARBON_WINDOW_PADDING*2 +
|
||||
(CARBON_BUTTON_SPACING*numChoices))) /
|
||||
(numChoices/iNumButtonRows);
|
||||
}
|
||||
|
||||
// Window Variables
|
||||
Rect rectWin = {0, 0, 200 + ((iNumButtonRows-1) * (CARBON_BUTTON_HEIGHT+CARBON_BUTTON_SPACING)), 550}; // top, left, bottom, right
|
||||
CFStringRef szWindowTitle = CFStringCreateWithCString(kCFAllocatorDefault, windowTitle, kCFStringEncodingUTF8);
|
||||
|
||||
window = NULL;
|
||||
|
||||
err = CreateNewWindow(kMovableAlertWindowClass, kWindowStandardHandlerAttribute|kWindowCompositingAttribute, &rectWin, &window);
|
||||
err = SetWindowTitleWithCFString(window, szWindowTitle);
|
||||
err = SetThemeWindowBackground(window, kThemeBrushAlertBackgroundActive, false);
|
||||
assert(err == noErr);
|
||||
|
||||
// Event Handler Variables
|
||||
EventTypeSpec buttonSpec[] = {{ kEventClassControl, kEventControlHit }, { kEventClassCommand, kEventCommandProcess }};
|
||||
EventHandlerUPP buttonHandler = NewEventHandlerUPP(DoCommandEvent);
|
||||
|
||||
// Static Text Variables
|
||||
Rect rectStatic = {20, 20, 152, 530};
|
||||
CFStringRef szStaticText = CFStringCreateWithCString(kCFAllocatorDefault, prompt, kCFStringEncodingUTF8);
|
||||
ControlRef refStaticText = NULL;
|
||||
err = CreateStaticTextControl(window, &rectStatic, szStaticText, NULL, &refStaticText);
|
||||
|
||||
// Button Variables
|
||||
Rect bounds[numChoices];
|
||||
CFStringRef caption[numChoices];
|
||||
ControlRef button[numChoices];
|
||||
|
||||
int whichButton=-1;
|
||||
CallbackData callbackData[numChoices];
|
||||
|
||||
// Create the Buttons and assign event handlers
|
||||
for (int i = 0; i < numChoices; ++i) {
|
||||
bounds[i].top = 160 + ((CARBON_BUTTON_HEIGHT+CARBON_BUTTON_SPACING)*(i%iNumButtonRows));
|
||||
bounds[i].right = 530 - ((iButtonWidth+CARBON_BUTTON_SPACING)*(i/iNumButtonRows));
|
||||
bounds[i].left = bounds[i].right - iButtonWidth;
|
||||
bounds[i].bottom = bounds[i].top + CARBON_BUTTON_HEIGHT;
|
||||
|
||||
// Convert the button captions to Apple strings
|
||||
caption[i] = CFStringCreateWithCString(kCFAllocatorDefault, choice[i], kCFStringEncodingUTF8);
|
||||
|
||||
err = CreatePushButtonControl(window, &bounds[i], caption[i], &button[i]);
|
||||
assert(err == noErr);
|
||||
|
||||
err = SetControlCommandID(button[i], CARBON_COMMANDID_START + i);
|
||||
assert(err == noErr);
|
||||
|
||||
callbackData[i].refWindow = window;
|
||||
callbackData[i].myIndex = i;
|
||||
callbackData[i].whichButton = &whichButton;
|
||||
|
||||
err = InstallControlEventHandler(button[i], buttonHandler,
|
||||
GetEventTypeCount(buttonSpec), buttonSpec,
|
||||
&callbackData[i], NULL);
|
||||
assert(err == noErr);
|
||||
}
|
||||
|
||||
// Show Dialog
|
||||
err = RepositionWindow(window, NULL, kWindowCenterOnMainScreen);
|
||||
ShowWindow(window);
|
||||
BringToFront(window);
|
||||
err = ActivateWindow(window, true);
|
||||
|
||||
// Hack to get our window/process to the front...
|
||||
ProcessSerialNumber psn = { 0, kCurrentProcess};
|
||||
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
||||
SetFrontProcess (&psn);
|
||||
|
||||
// Run in Modal State
|
||||
err = RunAppModalLoopForWindow(window);
|
||||
|
||||
// Dispose of Button Related Data
|
||||
for (int i = 0; i < numChoices; ++i) {
|
||||
// Dispose of controls
|
||||
DisposeControl(button[i]);
|
||||
|
||||
// Release CFStrings
|
||||
CFRelease(caption[i]);
|
||||
}
|
||||
|
||||
// Dispose of Other Controls
|
||||
DisposeControl(refStaticText);
|
||||
|
||||
// Dispose of Event Handlers
|
||||
DisposeEventHandlerUPP(buttonHandler);
|
||||
|
||||
// Dispose of Window
|
||||
DisposeWindow(window);
|
||||
|
||||
// Release CFStrings
|
||||
CFRelease(szWindowTitle);
|
||||
CFRelease(szStaticText);
|
||||
|
||||
// Return Selection
|
||||
return whichButton;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* G3DFIX: exclude GUI prompt code */
|
||||
|
||||
int prompt(
|
||||
const char* windowTitle,
|
||||
const char* prompt,
|
||||
const char** choice,
|
||||
int numChoices,
|
||||
bool useGui) {
|
||||
#if 0 /* G3DFIX: exclude GUI prompt code */
|
||||
#ifdef G3D_WIN32
|
||||
if (useGui) {
|
||||
// Build the message box
|
||||
return guiPrompt(windowTitle, prompt, choice, numChoices);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef G3D_OSX
|
||||
if (useGui){
|
||||
//Will default to text prompt if numChoices > 4
|
||||
return guiPrompt(windowTitle, prompt, choice, numChoices);
|
||||
}
|
||||
#endif
|
||||
#endif /* G3DFIX: exclude GUI prompt code */
|
||||
return textPrompt(windowTitle, prompt, choice, numChoices);
|
||||
}
|
||||
|
||||
|
||||
void msgBox(
|
||||
const std::string& message,
|
||||
const std::string& title) {
|
||||
|
||||
const char *choice[] = {"Ok"};
|
||||
prompt(title.c_str(), message.c_str(), choice, 1, true);
|
||||
}
|
||||
|
||||
#ifndef G3D_WIN32
|
||||
#undef _getch
|
||||
#endif
|
||||
|
||||
};// namespace
|
||||
|
||||
275
modules/acore/deps/g3dlite/source/stringutils.cpp
Normal file
275
modules/acore/deps/g3dlite/source/stringutils.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/**
|
||||
@file stringutils.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2000-09-09
|
||||
@edited 2008-01-10
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// disable: "C++ exception handler used"
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable : 4530)
|
||||
#endif
|
||||
#ifdef G3D_WIN32
|
||||
const char* NEWLINE = "\r\n";
|
||||
#else
|
||||
const char* NEWLINE = "\n";
|
||||
static bool iswspace(int ch) { return (ch==' ' || ch=='\t' || ch=='\n' || ch=='\r'); }
|
||||
#endif
|
||||
|
||||
void parseCommaSeparated(const std::string s, Array<std::string>& array, bool stripQuotes) {
|
||||
array.fastClear();
|
||||
if (s == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t begin = 0;
|
||||
const char delimiter = ',';
|
||||
const char quote = '\"';
|
||||
do {
|
||||
size_t end = begin;
|
||||
// Find the next comma, or the end of the string
|
||||
bool inQuotes = false;
|
||||
while ((end < s.length()) && (inQuotes || (s[end] != delimiter))) {
|
||||
if (s[end] == quote) {
|
||||
if ((end < s.length() - 2) && (s[end + 1] == quote) && (s[end + 2]) == quote) {
|
||||
// Skip over the superquote
|
||||
end += 2;
|
||||
}
|
||||
inQuotes = ! inQuotes;
|
||||
}
|
||||
++end;
|
||||
}
|
||||
array.append(s.substr(begin, end - begin));
|
||||
begin = end + 1;
|
||||
} while (begin < s.length());
|
||||
|
||||
if (stripQuotes) {
|
||||
for (int i = 0; i < array.length(); ++i) {
|
||||
std::string& t = array[i];
|
||||
int L = t.length();
|
||||
if ((L > 1) && (t[0] == quote) && (t[L - 1] == quote)) {
|
||||
if ((L > 6) && (t[1] == quote) && (t[2] == quote) && (t[L - 3] == quote) && (t[L - 2] == quote)) {
|
||||
// Triple-quote
|
||||
t = t.substr(3, L - 6);
|
||||
} else {
|
||||
// Double-quote
|
||||
t = t.substr(1, L - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool beginsWith(
|
||||
const std::string& test,
|
||||
const std::string& pattern) {
|
||||
|
||||
if (test.size() >= pattern.size()) {
|
||||
for (int i = 0; i < (int)pattern.size(); ++i) {
|
||||
if (pattern[i] != test[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool endsWith(
|
||||
const std::string& test,
|
||||
const std::string& pattern) {
|
||||
|
||||
if (test.size() >= pattern.size()) {
|
||||
int te = test.size() - 1;
|
||||
int pe = pattern.size() - 1;
|
||||
for (int i = pattern.size() - 1; i >= 0; --i) {
|
||||
if (pattern[pe - i] != test[te - i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string wordWrap(
|
||||
const std::string& input,
|
||||
int numCols) {
|
||||
|
||||
std::string output;
|
||||
size_t c = 0;
|
||||
int len;
|
||||
|
||||
// Don't make lines less than this length
|
||||
int minLength = numCols / 4;
|
||||
size_t inLen = input.size();
|
||||
|
||||
bool first = true;
|
||||
while (c < inLen) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
output += NEWLINE;
|
||||
}
|
||||
|
||||
if ((int)inLen - (int)c - 1 < numCols) {
|
||||
// The end
|
||||
output += input.substr(c, inLen - c);
|
||||
break;
|
||||
}
|
||||
|
||||
len = numCols;
|
||||
|
||||
// Look at character c + numCols, see if it is a space.
|
||||
while ((len > minLength) &&
|
||||
(input[c + len] != ' ')) {
|
||||
len--;
|
||||
}
|
||||
|
||||
if (len == minLength) {
|
||||
// Just crop
|
||||
len = numCols;
|
||||
|
||||
}
|
||||
|
||||
output += input.substr(c, len);
|
||||
c += len;
|
||||
if (c < input.size()) {
|
||||
// Collapse multiple spaces.
|
||||
while ((input[c] == ' ') && (c < input.size())) {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
int stringCompare(
|
||||
const std::string& s1,
|
||||
const std::string& s2) {
|
||||
|
||||
return stringPtrCompare(&s1, &s2);
|
||||
}
|
||||
|
||||
|
||||
int stringPtrCompare(
|
||||
const std::string* s1,
|
||||
const std::string* s2) {
|
||||
|
||||
return s1->compare(*s2);
|
||||
}
|
||||
|
||||
|
||||
std::string toUpper(const std::string& x) {
|
||||
std::string result = x;
|
||||
std::transform(result.begin(), result.end(), result.begin(), toupper);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::string toLower(const std::string& x) {
|
||||
std::string result = x;
|
||||
std::transform(result.begin(), result.end(), result.begin(), tolower);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Array<std::string> stringSplit(
|
||||
const std::string& x,
|
||||
char splitChar) {
|
||||
|
||||
Array<std::string> out;
|
||||
|
||||
// Pointers to the beginning and end of the substring
|
||||
const char* start = x.c_str();
|
||||
const char* stop = start;
|
||||
|
||||
while ((stop = strchr(start, splitChar))) {
|
||||
out.append(std::string(start, stop - start));
|
||||
start = stop + 1;
|
||||
}
|
||||
|
||||
// Append the last one
|
||||
out.append(std::string(start));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
std::string stringJoin(
|
||||
const Array<std::string>& a,
|
||||
char joinChar) {
|
||||
|
||||
std::string out;
|
||||
|
||||
for (int i = 0; i < (int)a.size() - 1; ++i) {
|
||||
out += a[i] + joinChar;
|
||||
}
|
||||
|
||||
if (a.size() > 0) {
|
||||
return out + a.last();
|
||||
} else {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string stringJoin(
|
||||
const Array<std::string>& a,
|
||||
const std::string& joinStr) {
|
||||
|
||||
std::string out;
|
||||
|
||||
for (int i = 0; i < (int)a.size() - 1; ++i) {
|
||||
out += a[i] + joinStr;
|
||||
}
|
||||
|
||||
if (a.size() > 0) {
|
||||
return out + a.last();
|
||||
} else {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string trimWhitespace(
|
||||
const std::string& s) {
|
||||
|
||||
size_t left = 0;
|
||||
|
||||
// Trim from left
|
||||
while ((left < s.length()) && iswspace(s[left])) {
|
||||
++left;
|
||||
}
|
||||
|
||||
int right = s.length() - 1;
|
||||
// Trim from right
|
||||
while ((right > (int)left) && iswspace(s[right])) {
|
||||
--right;
|
||||
}
|
||||
|
||||
return s.substr(left, right - left + 1);
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
#undef NEWLINE
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
155
modules/acore/deps/g3dlite/source/uint128.cpp
Normal file
155
modules/acore/deps/g3dlite/source/uint128.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
@file uint128.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@author Kyle Whitson
|
||||
|
||||
@created 2008-07-17
|
||||
@edited 2008-07-17
|
||||
*/
|
||||
|
||||
#include "G3D/uint128.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
/** Adds two 64-bit integers, placing the result and the overflow into 64-bit integers.*/
|
||||
static void addAndCarry(const uint64& _a, const uint64& _b, uint64& carry, uint64& result) {
|
||||
|
||||
// Break each number into 4 32-bit chunks. Since we are using uints, right-shifting will fill with zeros.
|
||||
// This eliminates the need to and with 0xFFFFFFFF.
|
||||
uint32 a [2] = {_a & 0xFFFFFFFF, _a >> 32};
|
||||
uint32 b [2] = {_b & 0xFFFFFFFF, _b >> 32};
|
||||
|
||||
uint64 tmp = uint64(a[0]) + b[0];
|
||||
|
||||
result = tmp & 0xFFFFFFFF;
|
||||
uint32 c = tmp >> 32;
|
||||
|
||||
tmp = uint64(c) + a[1] + b[1];
|
||||
result += tmp << 32;
|
||||
carry = (tmp >> 32);
|
||||
}
|
||||
|
||||
/** Multiplies two unsigned 64-bit integers, placing the result into one 64-bit int and the overflow into another.*/
|
||||
void multiplyAndCarry(const uint64& _a, const uint64& _b, uint64& carry, uint64& result) {
|
||||
|
||||
// Break each number into 4 32-bit chunks. Since we are using uints, right-shifting will fill with zeros.
|
||||
// This eliminates the need to and with 0xFFFFFFFF.
|
||||
uint32 a [2] = {_a & 0xFFFFFFFF, _a >> 32};
|
||||
uint32 b [2] = {_b & 0xFFFFFFFF, _b >> 32};
|
||||
|
||||
uint64 prod [2][2];
|
||||
for(int i = 0; i < 2; ++i) {
|
||||
for(int j = 0; j < 2; ++j) {
|
||||
prod[i][j] = uint64(a[i]) * b[j];
|
||||
}
|
||||
}
|
||||
|
||||
// The product of the low bits of a and b will always fit into the result
|
||||
result = prod[0][0];
|
||||
|
||||
// The product of the high bits of a and b will never fit into the result
|
||||
carry = prod[1][1];
|
||||
|
||||
// The high 32 bits of prod[0][1] and prod[1][0] will never fit into the result
|
||||
carry += prod[0][1] >> 32;
|
||||
carry += prod[1][0] >> 32;
|
||||
|
||||
uint64 tmp;
|
||||
addAndCarry(result, (prod[0][1] << 32), tmp, result);
|
||||
carry += tmp;
|
||||
addAndCarry(result, (prod[1][0] << 32), tmp, result);
|
||||
carry += tmp;
|
||||
}
|
||||
|
||||
|
||||
uint128::uint128(const uint64& hi, const uint64& lo) : hi(hi), lo(lo) {
|
||||
}
|
||||
|
||||
uint128::uint128(const uint64& lo) : hi(0), lo(lo) {
|
||||
}
|
||||
|
||||
uint128& uint128::operator+=(const uint128& x) {
|
||||
|
||||
G3D::uint64 carry;
|
||||
addAndCarry(lo, x.lo, carry, lo);
|
||||
|
||||
// Adding the carry will change hi. Save the old hi bits in case this == x.
|
||||
const uint64 xHi = x.hi;
|
||||
hi += carry;
|
||||
hi += xHi;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator*=(const uint128& x) {
|
||||
|
||||
// The low bits will get overwritten when doing the multiply, so back up both (in case &x == this)
|
||||
const uint64 oldLo = lo;
|
||||
const uint64 oldXLo = x.lo;
|
||||
|
||||
G3D::uint64 carry;
|
||||
multiplyAndCarry(oldLo, oldXLo, carry, lo);
|
||||
|
||||
// Overflow doesn't matter here because the result is going into hi - any overflow will exceed the capacity of a 128-bit number
|
||||
// Note: hi * x.hi will always overflow, since (x * 2^64) * (y * 2^64) = x*y*(2^128). The largest number expressable in 128 bits is
|
||||
// 2^128 - 1.
|
||||
hi = carry + (oldLo * x.hi) + (hi * oldXLo);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator^=(const uint128& x) {
|
||||
hi ^= x.hi;
|
||||
lo ^= x.lo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator&=(const uint128& x) {
|
||||
hi &= x.hi;
|
||||
lo &= x.lo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator|=(const uint128& x) {
|
||||
hi |= x.hi;
|
||||
lo |= x.lo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool uint128::operator==(const uint128& x) {
|
||||
return (hi == x.hi) && (lo == x.lo);
|
||||
}
|
||||
|
||||
uint128& uint128::operator>>=(const int x) {
|
||||
|
||||
//Before shifting, mask out the bits that will be shifted out of hi.
|
||||
//Put a 1 in the first bit that will not be lost in the shift, then subtract 1 to get the mask.
|
||||
uint64 mask = ((uint64)1L << x) - 1;
|
||||
uint64 tmp = hi & mask;
|
||||
hi >>= x;
|
||||
|
||||
//Shift lo and add the bits shifted down from hi
|
||||
lo = (lo >> x) + (tmp << (64 - x));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator<<=(const int x) {
|
||||
|
||||
//Before shifting, mask out the bits that will be shifted out of lo.
|
||||
//Put a 1 in the last bit that will be lost in the shift, then subtract 1 to get the logical inverse of the mask.
|
||||
//A bitwise NOT will then produce the correct mask.
|
||||
uint64 mask = ~((((uint64)1L) << (64 - x)) - 1);
|
||||
uint64 tmp = lo & mask;
|
||||
lo <<= x;
|
||||
|
||||
//Shift hi and add the bits shifted up from lo
|
||||
hi = (hi << x) + (tmp >> (64 - x));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128 uint128::operator&(const uint128& x) {
|
||||
return uint128(hi & x.hi, lo & x.lo);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user