Get g3dlib, zlib and jemalloc to build again

--HG--
branch : trunk
rename : opt/cleanup/tab2spaces.sh => contrib/cleanup/tab2spaces.sh
rename : opt/cleanup/whitespace.sh => contrib/cleanup/whitespace.sh
rename : opt/conf_merge/README => contrib/conf_merge/README
rename : opt/conf_merge/index.php => contrib/conf_merge/index.php
rename : opt/conf_merge/merge.php => contrib/conf_merge/merge.php
rename : doc/AuctionHouseBot.txt => docs/AuctionHouseBot.txt
rename : doc/DocStructure.dox => docs/DocStructure.dox
rename : doc/Doxyfile.in => docs/Doxyfile.in
rename : doc/EventAI.txt => docs/EventAI.txt
rename : doc/HowToScript.txt => docs/HowToScript.txt
rename : doc/TextTables.txt => docs/TextTables.txt
rename : doc/UnixInstall.txt => docs/UnixInstall.txt
rename : externals/jemalloc/include/internal/arena.h => externals/jemalloc/jemalloc/internal/arena.h
rename : externals/jemalloc/include/internal/base.h => externals/jemalloc/jemalloc/internal/base.h
rename : externals/jemalloc/include/internal/chunk.h => externals/jemalloc/jemalloc/internal/chunk.h
rename : externals/jemalloc/include/internal/chunk_dss.h => externals/jemalloc/jemalloc/internal/chunk_dss.h
rename : externals/jemalloc/include/internal/chunk_mmap.h => externals/jemalloc/jemalloc/internal/chunk_mmap.h
rename : externals/jemalloc/include/internal/chunk_swap.h => externals/jemalloc/jemalloc/internal/chunk_swap.h
rename : externals/jemalloc/include/internal/ckh.h => externals/jemalloc/jemalloc/internal/ckh.h
rename : externals/jemalloc/include/internal/ctl.h => externals/jemalloc/jemalloc/internal/ctl.h
rename : externals/jemalloc/include/internal/extent.h => externals/jemalloc/jemalloc/internal/extent.h
rename : externals/jemalloc/include/internal/hash.h => externals/jemalloc/jemalloc/internal/hash.h
rename : externals/jemalloc/include/internal/huge.h => externals/jemalloc/jemalloc/internal/huge.h
rename : externals/jemalloc/include/internal/jemalloc_internal.h => externals/jemalloc/jemalloc/internal/jemalloc_internal.h
rename : externals/jemalloc/include/internal/jemalloc_internal.h.in => externals/jemalloc/jemalloc/internal/jemalloc_internal.h.in
rename : externals/jemalloc/include/internal/mb.h => externals/jemalloc/jemalloc/internal/mb.h
rename : externals/jemalloc/include/internal/mutex.h => externals/jemalloc/jemalloc/internal/mutex.h
rename : externals/jemalloc/include/internal/prof.h => externals/jemalloc/jemalloc/internal/prof.h
rename : externals/jemalloc/include/internal/ql.h => externals/jemalloc/jemalloc/internal/ql.h
rename : externals/jemalloc/include/internal/qr.h => externals/jemalloc/jemalloc/internal/qr.h
rename : externals/jemalloc/include/internal/rb.h => externals/jemalloc/jemalloc/internal/rb.h
rename : externals/jemalloc/include/internal/stats.h => externals/jemalloc/jemalloc/internal/stats.h
rename : externals/jemalloc/include/internal/tcache.h => externals/jemalloc/jemalloc/internal/tcache.h
rename : externals/jemalloc/include/internal/totally_not_p_r_n.h => externals/jemalloc/jemalloc/internal/totally_not_p_r_n.h
rename : externals/jemalloc/include/jemalloc.h => externals/jemalloc/jemalloc/jemalloc.h
rename : externals/jemalloc/include/jemalloc.h.in => externals/jemalloc/jemalloc/jemalloc.h.in
rename : externals/jemalloc/include/jemalloc_defs.h => externals/jemalloc/jemalloc/jemalloc_defs.h
rename : externals/jemalloc/include/jemalloc_defs.h.in => externals/jemalloc/jemalloc/jemalloc_defs.h.in
This commit is contained in:
click
2010-06-08 08:04:26 +02:00
parent c08a7d6348
commit f867f6d7a8
93 changed files with 19176 additions and 1813 deletions
+366
View File
@@ -0,0 +1,366 @@
/**
@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;
}
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;
}
}
+1237
View File
File diff suppressed because it is too large Load Diff
+81
View 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;
}
}
}
+568
View File
@@ -0,0 +1,568 @@
/**
@file BinaryInput.cpp
@author Morgan McGuire, graphics3d.com
Copyright 2001-2007, Morgan McGuire. All rights reserved.
@created 2001-08-09
@edited 2005-02-24
<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 <zlib.h>
#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 (! fileExists(m_filename, false)) {
std::string zipfile;
std::string internalfile;
if (zipfileExists(m_filename, zipfile, internalfile)) {
// Load from zipfile
void* v;
size_t s;
zipRead(filename, v, s);
m_buffer = reinterpret_cast<uint8*>(v);
m_bufferLength = m_length = s;
if (compressed) {
decompress();
}
m_freeBuffer = true;
} else {
Log::common()->printf("Warning: File not found: %s\n", m_filename.c_str());
}
return;
}
// Figure out how big the file is and verify that it exists.
m_length = fileLength(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);
}
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;
}
}
+522
View File
@@ -0,0 +1,522 @@
/**
@file BinaryOutput.cpp
@author Morgan McGuire, graphics3d.com
Copyright 2002-2007, Morgan McGuire, All rights reserved.
@created 2002-02-20
@edited 2008-01-07
*/
#include "G3D/platform.h"
#include "G3D/BinaryOutput.h"
#include "G3D/fileutils.h"
#include "G3D/stringutils.h"
#include "G3D/Array.h"
#include <zlib.h>
#include <cstring>
// 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 = 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 (! fileExists(path, false)) {
createDirectory(path);
}
const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb";
FILE* file = fopen(m_filename.c_str(), mode);
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);
}
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
View 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
+11
View File
@@ -0,0 +1,11 @@
file(GLOB sources *.cpp)
SET(g3dlib_STAT_SRCS
${sources}
)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
add_library(g3dlib STATIC ${g3dlib_STAT_SRCS})
+179
View 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
File diff suppressed because it is too large Load Diff
+436
View File
@@ -0,0 +1,436 @@
/**
@file CoordinateFrame.cpp
Coordinate frame class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-06-02
@edited 2009-11-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"
namespace G3D {
CoordinateFrame::CoordinateFrame(const Any& any) {
any.verifyName("CFrame");
if (toUpper(any.name()) == "CFRAME") {
any.verifyType(Any::TABLE, Any::ARRAY);
if (any.type() == Any::TABLE) {
rotation = any["rotation"];
translation = any["translation"];
} else {
any.verifySize(2);
rotation = any[0];
translation = any[1];
}
} else {
any.verifyName("CFrame::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 {
Quat q1 = Quat(this->rotation);
Quat q2 = Quat(other.rotation);
return CoordinateFrame(
q1.slerp(q2, alpha).toRotationMatrix(),
this->translation * (1 - alpha) + other.translation * alpha);
}
}
void CoordinateFrame::pointToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
vout.resize(v.size());
for (int i = v.size() - 1; i >= 0; --i) {
vout[i] = pointToWorldSpace(v[i]);
}
}
void CoordinateFrame::normalToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
vout.resize(v.size());
for (int i = v.size() - 1; i >= 0; --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
View 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
+176
View 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
+89
View 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
View 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;
}
}
+146
View File
@@ -0,0 +1,146 @@
/**
@file Log.cpp
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-08-04
@edited 2009-01-15
*/
#include "G3D/platform.h"
#include "G3D/Log.h"
#include "G3D/format.h"
#include "G3D/Array.h"
#include "G3D/fileutils.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 = 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 = 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);
}
}
+1927
View File
File diff suppressed because it is too large Load Diff
+523
View File
@@ -0,0 +1,523 @@
/**
@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 {
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
View 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;
}
}
+149
View 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);
}
}
+583
View File
@@ -0,0 +1,583 @@
/**
@file Quat.cpp
Quaternion implementation based on Watt & Watt page 363
@author Morgan McGuire, graphics3d.com
@created 2002-01-23
@edited 2006-01-31
*/
#include "G3D/Quat.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 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
View 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
View 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;
}
}
}
+61
View 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
+223
View 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
+1746
View File
File diff suppressed because it is too large Load Diff
+1136
View File
File diff suppressed because it is too large Load Diff
+452
View File
@@ -0,0 +1,452 @@
/**
@file TextOutput.cpp
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2004-06-21
@edited 2006-08-14
Copyright 2000-2006, Morgan McGuire.
All rights reserved.
*/
#include "G3D/TextOutput.h"
#include "G3D/Log.h"
#include "G3D/fileutils.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 (! fileExists(p, false)) {
createDirectory(p);
}
FILE* f = fopen(filename.c_str(), "wb");
debugAssertM(f, "Could not open \"" + filename + "\"");
fwrite(data.getCArray(), 1, data.size(), f);
if (flush) {
fflush(f);
}
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);
}
}
+186
View 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
View 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
View 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
+507
View File
@@ -0,0 +1,507 @@
/**
@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/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 {
unsigned int xhash = (*(int*)(void*)(&x));
unsigned int yhash = (*(int*)(void*)(&y));
unsigned int zhash = (*(int*)(void*)(&z));
return xhash + (yhash * 37) + (zhash * 101);
}
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
+520
View File
@@ -0,0 +1,520 @@
/**
@file Vector4.cpp
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-07-09
@edited 2009-11-29
*/
#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 {
unsigned int xhash = (*(int*)(void*)(&x));
unsigned int yhash = (*(int*)(void*)(&y));
unsigned int zhash = (*(int*)(void*)(&z));
unsigned int whash = (*(int*)(void*)(&w));
return xhash + (yhash * 37) + (zhash * 101) + (whash * 241);
}
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
+389
View 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 SOMEONE_MADE_THIS_USEFUL
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 SOMEONE_MADE_THIS_USEFUL
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
+1165
View File
File diff suppressed because it is too large Load Diff
+164
View 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
+204
View File
@@ -0,0 +1,204 @@
/*-
* Copyright (c) 1992, 1993
*The Regents of the University of California. All rights reserved.
*
* 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.
*
*@(#)fnmatch.h8.1 (Berkeley) 6/2/93
*
* From FreeBSD fnmatch.h 1.7
* $Id: g3dfnmatch.cpp,v 1.2 2010/02/06 10:03:24 corey_taylor Exp $
*/
#include "G3D/g3dfnmatch.h"
#ifdef G3D_WIN32
#include <ctype.h>
#include <string.h>
#include <stdio.h>
namespace G3D {
#define EOS '\0'
static const char *rangematch(const char *, char, int);
int g3dfnmatch(const char *pattern, const char *string, int flags)
{
const char *stringstart;
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 (!rangematch(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 ((pattern =
rangematch(pattern, *string, flags)) == NULL)
return (FNM_NOMATCH);
++string;
break;
case '\\':
if (!(flags & FNM_NOESCAPE)) {
if ((c = *pattern++) == EOS) {
c = '\\';
--pattern;
}
}
/* FALLTHROUGH */
default:
if (c == *string)
;
else if ((flags & FNM_CASEFOLD) &&
(tolower((unsigned char)c) ==
tolower((unsigned char)*string)))
;
else if ((flags & FNM_PREFIX_DIRS) && *string == EOS &&
((c == '/' && string != stringstart) ||
(string == stringstart+1 && *stringstart == '/')))
return (0);
else
return (FNM_NOMATCH);
string++;
break;
}
/* NOTREACHED */
}
static const char *
rangematch(const char *pattern, char test, int flags)
{
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);
for (ok = 0; (c = *pattern++) != ']';) {
if (c == '\\' && !(flags & FNM_NOESCAPE))
c = *pattern++;
if (c == EOS)
return (NULL);
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 (NULL);
if (flags & FNM_CASEFOLD)
c2 = tolower((unsigned char)c2);
if ((unsigned char)c <= (unsigned char)test &&
(unsigned char)test <= (unsigned char)c2)
ok = 1;
} else if (c == test)
ok = 1;
}
return (ok == negate ? NULL : pattern);
}
}
#else
namespace G3D {
int g3dfnmatch(const char * a, const char *b, int c) {
return fnmatch(a, b, c);
}
}
#endif
+108
View File
@@ -0,0 +1,108 @@
/**
@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 = nan();
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;
}
}
}
+729
View File
@@ -0,0 +1,729 @@
/**
@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
#ifdef G3D_OSX
/*#ifdef __LP64__
# undef __LP64__
#endif
*/
# include <Carbon/Carbon.h>
/*
#ifdef G3D_64BIT
# define __LP64__
#endif
*/
#endif
namespace G3D {
#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)&params);
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
/**
* 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;
}
#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
int prompt(
const char* windowTitle,
const char* prompt,
const char** choice,
int numChoices,
bool useGui) {
#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
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
View 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