mirror of
https://github.com/mangosfour/server.git
synced 2025-12-14 16:37:01 +00:00
[10097] Update G3D up to v8.0b4
+ Got rid of zip lib requirement in G3D...
Still can re-enable code by defining _HAVE_ZIP...
+ Remove silly X11 lib dependency from G3D
Code doesn't seem to do anything yet anyway, and even if, we don't want it :p
+ Fix another weird G3D build problem...
+ Remove some __asm usage in g3d, which is not available on Win64
My editor also decided to remove a ton of trailing white spaces...tss...
+ Reapply G3D fixes for 64bit VC
+ not use SSE specific header when SSE not enabled in *nix
+ Updated project files
+ New vmap_assembler VC90/VC80 Project
+ vmap assembler binaries updates
NOTE: Old vmap fikes expected work (as tests show) with new library version.
But better use new generated versions. Its different in small parts to bad or good...
(based on Lynx3d's repo commit 44798d3)
Signed-off-by: VladimirMangos <vladimir@getmangos.com>
This commit is contained in:
parent
2f3c518935
commit
ae3ad10bcf
235 changed files with 58189 additions and 4547 deletions
|
|
@ -1,32 +1,60 @@
|
|||
/**
|
||||
@file AABox.cpp
|
||||
|
||||
@maintainer Morgan McGuire, matrix@graphics3d.com
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2004-01-10
|
||||
@edited 2006-01-11
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
# if defined(_MSC_VER) && (_MSC_VER <= 1200)
|
||||
// VC6 std:: has signed/unsigned problems
|
||||
# pragma warning (disable : 4018)
|
||||
# endif
|
||||
|
||||
#include <assert.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 {
|
||||
|
||||
Box AABox::toBox() const {
|
||||
return Box(lo, hi);
|
||||
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
|
||||
|
|
@ -44,17 +72,17 @@ void AABox::split(const Vector3::Axis& axis, float location, AABox& low, AABox&
|
|||
high.hi[axis] = H;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
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)random(0, aXY + aYZ + aZX);
|
||||
float r = (float)uniformRandom(0.0f, aXY + aYZ + aZX);
|
||||
|
||||
// Choose evenly between positive and negative face planes
|
||||
float d = ((float)random(0, 1) < 0.5f) ? 0.0f : 1.0f;
|
||||
float d = ((float)uniformRandom(0, 1) < 0.5f) ? 0.0f : 1.0f;
|
||||
|
||||
// The probability of choosing a given face is proportional to
|
||||
// its area.
|
||||
|
|
@ -62,34 +90,33 @@ Vector3 AABox::randomSurfacePoint() const {
|
|||
return
|
||||
lo +
|
||||
Vector3(
|
||||
(float)random(0, extent.x),
|
||||
(float)random(0, extent.y),
|
||||
(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)random(0, extent.y),
|
||||
(float)random(0, extent.z));
|
||||
(float)uniformRandom(0, extent.y),
|
||||
(float)uniformRandom(0, extent.z));
|
||||
} else {
|
||||
return
|
||||
lo +
|
||||
Vector3(
|
||||
(float)random(0, extent.x),
|
||||
(float)uniformRandom(0, extent.x),
|
||||
d * extent.y,
|
||||
(float)random(0, extent.z));
|
||||
(float)uniformRandom(0, extent.z));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector3 AABox::randomInteriorPoint() const {
|
||||
return Vector3(
|
||||
(float)random(lo.x, hi.x),
|
||||
(float)random(lo.y, hi.y),
|
||||
(float)random(lo.z, hi.z));
|
||||
(float)uniformRandom(lo.x, hi.x),
|
||||
(float)uniformRandom(lo.y, hi.y),
|
||||
(float)uniformRandom(lo.z, hi.z));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool AABox::intersects(const AABox& other) const {
|
||||
|
|
@ -110,52 +137,30 @@ bool AABox::intersects(const AABox& other) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool AABox::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlaneIndex,
|
||||
const uint32 inMask,
|
||||
uint32& outMask) const {
|
||||
|
||||
return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask, outMask);
|
||||
}
|
||||
|
||||
|
||||
bool AABox::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlaneIndex,
|
||||
const uint32 inMask) const {
|
||||
|
||||
return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask);
|
||||
}
|
||||
|
||||
|
||||
int AABox::dummy = 0;
|
||||
|
||||
|
||||
bool AABox::culledBy(
|
||||
const class Plane* plane,
|
||||
int numPlanes,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask,
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask,
|
||||
uint32& childMask) const {
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(numPlanes < 31);
|
||||
uint32 inMask = _inMask;
|
||||
assert(plane.size() < 31);
|
||||
|
||||
childMask = 0;
|
||||
|
||||
const bool finite =
|
||||
(abs(lo.x) < G3D::inf()) &&
|
||||
(abs(hi.x) < G3D::inf()) &&
|
||||
(abs(lo.y) < G3D::inf()) &&
|
||||
(abs(hi.y) < G3D::inf()) &&
|
||||
(abs(lo.z) < G3D::inf()) &&
|
||||
(abs(hi.z) < G3D::inf());
|
||||
(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 < numPlanes; p++) {
|
||||
for (int p = 0; p < plane.size(); ++p) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
|
|
@ -215,25 +220,24 @@ bool AABox::culledBy(
|
|||
|
||||
|
||||
bool AABox::culledBy(
|
||||
const class Plane* plane,
|
||||
int numPlanes,
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask) const {
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(numPlanes < 31);
|
||||
assert(plane.size() < 31);
|
||||
|
||||
const bool finite =
|
||||
(abs(lo.x) < G3D::inf()) &&
|
||||
(abs(hi.x) < G3D::inf()) &&
|
||||
(abs(lo.y) < G3D::inf()) &&
|
||||
(abs(hi.y) < G3D::inf()) &&
|
||||
(abs(lo.z) < G3D::inf()) &&
|
||||
(abs(hi.z) < G3D::inf());
|
||||
(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 < numPlanes; p++) {
|
||||
for (int p = 0; p < plane.size(); ++p) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
|
|
@ -295,5 +299,68 @@ bool AABox::intersects(const class Sphere& sphere) const {
|
|||
return d <= square(sphere.radius);
|
||||
}
|
||||
|
||||
Vector3 AABox::corner(int index) const {
|
||||
|
||||
} // namespace
|
||||
// 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
dep/src/g3dlite/Any.cpp
Normal file
1237
dep/src/g3dlite/Any.cpp
Normal file
File diff suppressed because it is too large
Load diff
1379
dep/src/g3dlite/AnyVal.cpp
Normal file
1379
dep/src/g3dlite/AnyVal.cpp
Normal file
File diff suppressed because it is too large
Load diff
87
dep/src/g3dlite/AreaMemoryManager.cpp
Normal file
87
dep/src/g3dlite/AreaMemoryManager.cpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
@file AreaMemoryManager.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2009-01-20
|
||||
@edited 2009-01-20
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/AreaMemoryManager.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
AreaMemoryManager::Buffer::Buffer(size_t size) : m_size(size), m_used(0) {
|
||||
// Allocate space for a lot of buffers.
|
||||
m_first = (uint8*)::malloc(m_size);
|
||||
}
|
||||
|
||||
|
||||
AreaMemoryManager::Buffer::~Buffer() {
|
||||
::free(m_first);
|
||||
}
|
||||
|
||||
|
||||
void* AreaMemoryManager::Buffer::alloc(size_t s) {
|
||||
if (s + m_used > m_size) {
|
||||
return NULL;
|
||||
} else {
|
||||
void* old = m_first + m_used;
|
||||
m_used += s;
|
||||
return old;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AreaMemoryManager::isThreadsafe() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
AreaMemoryManager::Ref AreaMemoryManager::create(size_t sizeHint) {
|
||||
return new AreaMemoryManager(sizeHint);
|
||||
}
|
||||
|
||||
|
||||
AreaMemoryManager::AreaMemoryManager(size_t sizeHint) : m_sizeHint(sizeHint) {
|
||||
debugAssert(sizeHint > 0);
|
||||
}
|
||||
|
||||
|
||||
AreaMemoryManager::~AreaMemoryManager() {
|
||||
deallocateAll();
|
||||
}
|
||||
|
||||
|
||||
size_t AreaMemoryManager::bytesAllocated() const {
|
||||
return m_sizeHint * m_bufferArray.size();
|
||||
}
|
||||
|
||||
|
||||
void* AreaMemoryManager::alloc(size_t s) {
|
||||
void* n = (m_bufferArray.size() > 0) ? m_bufferArray.last()->alloc(s) : NULL;
|
||||
if (n == NULL) {
|
||||
// This buffer is full
|
||||
m_bufferArray.append(new Buffer(max(s, m_sizeHint)));
|
||||
return m_bufferArray.last()->alloc(s);
|
||||
} else {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AreaMemoryManager::free(void* x) {
|
||||
// Intentionally empty; we block deallocate
|
||||
}
|
||||
|
||||
|
||||
void AreaMemoryManager::deallocateAll() {
|
||||
m_bufferArray.deleteAll();
|
||||
m_bufferArray.clear();
|
||||
}
|
||||
|
||||
}
|
||||
81
dep/src/g3dlite/BinaryFormat.cpp
Normal file
81
dep/src/g3dlite/BinaryFormat.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
@file BinaryFormat.cpp
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2005-06-10
|
||||
@edited 2005-06-10
|
||||
*/
|
||||
|
||||
#include "G3D/BinaryFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
int32 byteSize(BinaryFormat f) {
|
||||
switch (f) {
|
||||
case BOOL8_BINFMT:
|
||||
case UINT8_BINFMT:
|
||||
case INT8_BINFMT:
|
||||
return 1;
|
||||
|
||||
case UINT16_BINFMT:
|
||||
case INT16_BINFMT:
|
||||
return 2;
|
||||
|
||||
case FLOAT16_BINFMT:
|
||||
return 2;
|
||||
|
||||
case UINT32_BINFMT:
|
||||
case INT32_BINFMT:
|
||||
case FLOAT32_BINFMT:
|
||||
return 4;
|
||||
|
||||
case FLOAT64_BINFMT:
|
||||
case UINT64_BINFMT:
|
||||
case INT64_BINFMT:
|
||||
return 8;
|
||||
|
||||
case INT128_BINFMT:
|
||||
case UINT128_BINFMT:
|
||||
return 16;
|
||||
|
||||
case VECTOR2_BINFMT:
|
||||
return 2 * 4;
|
||||
|
||||
case VECTOR2INT16_BINFMT:
|
||||
return 2 * 2;
|
||||
|
||||
case VECTOR3_BINFMT:
|
||||
return 3 * 4;
|
||||
|
||||
case VECTOR3INT16_BINFMT:
|
||||
return 3 * 2;
|
||||
|
||||
case VECTOR4_BINFMT:
|
||||
return 4 * 4;
|
||||
|
||||
case VECTOR4INT16_BINFMT:
|
||||
return 4 * 4;
|
||||
|
||||
case COLOR3_BINFMT:
|
||||
return 3 * 4;
|
||||
|
||||
case COLOR3UINT8_BINFMT:
|
||||
return 3 * 1;
|
||||
|
||||
case COLOR3INT16_BINFMT:
|
||||
return 3 * 2;
|
||||
|
||||
case COLOR4_BINFMT:
|
||||
return 4 * 4;
|
||||
|
||||
case COLOR4UINT8_BINFMT:
|
||||
return 4 * 1;
|
||||
|
||||
case COLOR4INT16_BINFMT:
|
||||
return 4 * 2;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
568
dep/src/g3dlite/BinaryInput.cpp
Normal file
568
dep/src/g3dlite/BinaryInput.cpp
Normal 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
dep/src/g3dlite/BinaryOutput.cpp
Normal file
522
dep/src/g3dlite/BinaryOutput.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
@file Box.cpp
|
||||
Box class
|
||||
|
||||
@maintainer Morgan McGuire, matrix@graphics3d.com
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2006-02-05
|
||||
|
|
@ -32,6 +32,50 @@ 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,
|
||||
|
|
@ -45,6 +89,11 @@ 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);
|
||||
|
||||
|
|
@ -60,13 +109,27 @@ void Box::init(
|
|||
_axis[1] = Vector3::unitY();
|
||||
_axis[2] = Vector3::unitZ();
|
||||
|
||||
_volume = _extent.x * _extent.y * _extent.z;
|
||||
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) / 2;
|
||||
_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -75,7 +138,7 @@ float Box::volume() const {
|
|||
}
|
||||
|
||||
|
||||
float Box::surfaceArea() const {
|
||||
float Box::area() const {
|
||||
return _area;
|
||||
}
|
||||
|
||||
|
|
@ -130,42 +193,23 @@ void Box::getFaceCorners(int f, Vector3& v0, Vector3& v1, Vector3& v2, Vector3&
|
|||
}
|
||||
|
||||
|
||||
bool Box::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlaneIndex,
|
||||
const uint32 inMask,
|
||||
uint32& outMask) const {
|
||||
|
||||
return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask, outMask);
|
||||
}
|
||||
|
||||
int Box::dummy = 0;
|
||||
|
||||
bool Box::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlaneIndex,
|
||||
const uint32 inMask) const {
|
||||
|
||||
return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask);
|
||||
}
|
||||
|
||||
|
||||
int32 Box::dummy = 0;
|
||||
|
||||
bool Box::culledBy(
|
||||
const class Plane* plane,
|
||||
int numPlanes,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask,
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask,
|
||||
uint32& childMask) const {
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(numPlanes < 31);
|
||||
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 < numPlanes; p++) {
|
||||
for (int p = 0; p < plane.size(); ++p) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
|
|
@ -179,7 +223,7 @@ bool Box::culledBy(
|
|||
// 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(getCorner(v))) {
|
||||
if (plane[p].halfSpaceContains(_corner[v])) {
|
||||
++numContained;
|
||||
}
|
||||
}
|
||||
|
|
@ -213,17 +257,16 @@ bool Box::culledBy(
|
|||
|
||||
|
||||
bool Box::culledBy(
|
||||
const class Plane* plane,
|
||||
int numPlanes,
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask) const {
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(numPlanes < 31);
|
||||
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 < numPlanes; p++) {
|
||||
for (int p = 0; p < plane.size(); ++p) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
|
|
@ -236,7 +279,7 @@ bool Box::culledBy(
|
|||
// 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(getCorner(v));
|
||||
culled = ! plane[p].halfSpaceContains(corner(v));
|
||||
}
|
||||
|
||||
if (culled) {
|
||||
|
|
@ -286,32 +329,32 @@ bool Box::contains(
|
|||
|
||||
#undef setMany
|
||||
|
||||
#if 0
|
||||
|
||||
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)random(0, aXY + aYZ + aZX);
|
||||
float r = (float)uniformRandom(0, aXY + aYZ + aZX);
|
||||
|
||||
// Choose evenly between positive and negative face planes
|
||||
float d = (random(0, 1) < 0.5f) ? -1.0f : 1.0f;
|
||||
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)random(-0.5, 0.5) * _extent.x +
|
||||
_axis[1] * (float)random(-0.5, 0.5) * _extent.y +
|
||||
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)random(-0.5, 0.5) * _extent.y +
|
||||
_axis[2] * (float)random(-0.5, 0.5) * _extent.z +
|
||||
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)random(-0.5, 0.5) * _extent.z +
|
||||
_axis[0] *(float) random(-0.5, 0.5) * _extent.x +
|
||||
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;
|
||||
}
|
||||
|
|
@ -322,13 +365,15 @@ Vector3 Box::randomInteriorPoint() const {
|
|||
Vector3 sum = _center;
|
||||
|
||||
for (int a = 0; a < 3; ++a) {
|
||||
sum += _axis[a] * (float)random(-0.5, 0.5) * _extent[a];
|
||||
sum += _axis[a] * (float)uniformRandom(-0.5, 0.5) * _extent[a];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
#endif
|
||||
|
||||
Box Box::inf() {
|
||||
return Box(-Vector3::inf(), Vector3::inf());
|
||||
}
|
||||
|
||||
void Box::getBounds(class AABox& aabb) const {
|
||||
|
||||
|
|
|
|||
113
dep/src/g3dlite/Box2D.cpp
Normal file
113
dep/src/g3dlite/Box2D.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
@file Box.cpp
|
||||
Box class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2008-12-27
|
||||
*/
|
||||
|
||||
#include "G3D/Box2D.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Rect2D.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
bool Box2D::overlaps1Way(const Box2D& other) const {
|
||||
for (int a = 0; a < 2; ++a) {
|
||||
|
||||
float t = other.m_corner[0].dot(m_axisin[a]);
|
||||
|
||||
// Find the extent of box 2 on m_axisin a
|
||||
float tMin = t;
|
||||
float tMax = t;
|
||||
|
||||
for (int c = 1; c < 4; ++c) {
|
||||
t = other.m_corner[c].dot(m_axisin[a]);
|
||||
|
||||
if (t < tMin) {
|
||||
tMin = t;
|
||||
} else if (t > tMax) {
|
||||
tMax = t;
|
||||
}
|
||||
}
|
||||
|
||||
// We have to subtract off the origin
|
||||
|
||||
// See if [tMin, tMax] intersects [0, 1]
|
||||
if ((tMin > 1 + origin[a]) || (tMax < origin[a])) {
|
||||
// There was no intersection along this dimension;
|
||||
// the boxes cannot possibly overlap.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// There was no dimension along which there is no intersection.
|
||||
// Therefore the boxes overlap.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Box2D::computeAxes() {
|
||||
m_axis[0] = m_corner[1] - m_corner[0];
|
||||
m_axis[1] = m_corner[3] - m_corner[0];
|
||||
|
||||
// Make the length of each m_axisin = 1/edge length so we know any
|
||||
// dot product must be less than 1 to fall within the edge.
|
||||
float len[2];
|
||||
for (int a = 0; a < 2; ++a) {
|
||||
float lenSq = m_axis[a].squaredLength();
|
||||
m_axisin[a] = m_axis[a] / lenSq;
|
||||
origin[a] = m_corner[0].dot(m_axisin[a]);
|
||||
len[a] = sqrt(lenSq);
|
||||
m_axis[a] /= len[a];
|
||||
}
|
||||
|
||||
// w * h
|
||||
m_area = len[0] * len[1];
|
||||
|
||||
|
||||
m_center = (m_corner[0] + m_corner[2]) * 0.5f;
|
||||
}
|
||||
|
||||
|
||||
Box2D::Box2D(const Vector2& center, float w, float h, float angle) {
|
||||
Vector2 X( cos(angle), sin(angle));
|
||||
Vector2 Y(-sin(angle), cos(angle));
|
||||
|
||||
X *= w / 2;
|
||||
Y *= h / 2;
|
||||
|
||||
m_corner[0] = center - X - Y;
|
||||
m_corner[1] = center + X - Y;
|
||||
m_corner[2] = center + X + Y;
|
||||
m_corner[3] = center - X + Y;
|
||||
|
||||
computeAxes();
|
||||
}
|
||||
|
||||
|
||||
Box2D::Box2D(const AABox2D& b) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
m_corner[i] = b.corner(i);
|
||||
}
|
||||
|
||||
computeAxes();
|
||||
}
|
||||
|
||||
|
||||
Box2D::Box2D(const Vector2& min, const Vector2& max) {
|
||||
*this = Box2D(Rect2D::xyxy(min, max));
|
||||
}
|
||||
|
||||
|
||||
Box2D::Box2D(const CFrame& frame, Box2D& b) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
m_corner[i] = frame.pointToWorldSpace(Vector3(b.corner(i), 0)).xy();
|
||||
}
|
||||
computeAxes();
|
||||
}
|
||||
|
||||
|
||||
} // G3D
|
||||
43
dep/src/g3dlite/BumpMapPreprocess.cpp
Normal file
43
dep/src/g3dlite/BumpMapPreprocess.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
\file BumpMapPreprocess.cpp
|
||||
|
||||
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
\created 2010-01-28
|
||||
\edited 2010-01-28
|
||||
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
#include "G3D/BumpMapPreprocess.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
BumpMapPreprocess::BumpMapPreprocess(const Any& any) {
|
||||
*this = BumpMapPreprocess();
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "lowpassfilter") {
|
||||
lowPassFilter = it->value;
|
||||
} else if (key == "zextentpixels") {
|
||||
zExtentPixels = it->value;
|
||||
} else if (key == "scalezbynz") {
|
||||
scaleZByNz = it->value;
|
||||
} else {
|
||||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BumpMapPreprocess::operator Any() const {
|
||||
Any any(Any::TABLE, "BumpMapPreprocess");
|
||||
any["lowPassFilter"] = lowPassFilter;
|
||||
any["zExtentPixels"] = zExtentPixels;
|
||||
any["scaleZByNz"] = scaleZByNz;
|
||||
return any;
|
||||
}
|
||||
|
||||
}
|
||||
179
dep/src/g3dlite/Capsule.cpp
Normal file
179
dep/src/g3dlite/Capsule.cpp
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/**
|
||||
@file Capsule.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-02-07
|
||||
@edited 2005-08-18
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/Capsule.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/LineSegment.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Line.h"
|
||||
#include "G3D/AABox.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Capsule::Capsule(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
Capsule::Capsule() {
|
||||
}
|
||||
|
||||
|
||||
Capsule::Capsule(const Vector3& _p1, const Vector3& _p2, float _r)
|
||||
: p1(_p1), p2(_p2), _radius(_r) {
|
||||
}
|
||||
|
||||
|
||||
void Capsule::serialize(class BinaryOutput& b) const {
|
||||
p1.serialize(b);
|
||||
p2.serialize(b);
|
||||
b.writeFloat64(_radius);
|
||||
}
|
||||
|
||||
|
||||
void Capsule::deserialize(class BinaryInput& b) {
|
||||
p1.deserialize(b);
|
||||
p2.deserialize(b);
|
||||
_radius = b.readFloat64();
|
||||
}
|
||||
|
||||
|
||||
Line Capsule::axis() const {
|
||||
return Line::fromTwoPoints(p1, p2);
|
||||
}
|
||||
|
||||
|
||||
float Capsule::volume() const {
|
||||
return
|
||||
// Sphere volume
|
||||
pow(_radius, 3) * pi() * 4 / 3 +
|
||||
|
||||
// Cylinder volume
|
||||
pow(_radius, 2) * (p1 - p2).magnitude();
|
||||
}
|
||||
|
||||
|
||||
float Capsule::area() const {
|
||||
|
||||
return
|
||||
// Sphere area
|
||||
pow(_radius, 2) * 4 * pi() +
|
||||
|
||||
// Cylinder area
|
||||
twoPi() * _radius * (p1 - p2).magnitude();
|
||||
}
|
||||
|
||||
|
||||
void Capsule::getBounds(AABox& out) const {
|
||||
Vector3 min = p1.min(p2) - (Vector3(1, 1, 1) * _radius);
|
||||
Vector3 max = p1.max(p2) + (Vector3(1, 1, 1) * _radius);
|
||||
|
||||
out = AABox(min, max);
|
||||
}
|
||||
|
||||
|
||||
bool Capsule::contains(const Vector3& p) const {
|
||||
return LineSegment::fromTwoPoints(p1, p2).distanceSquared(p) <= square(radius());
|
||||
}
|
||||
|
||||
|
||||
void Capsule::getRandomSurfacePoint(Vector3& p, Vector3& N) const {
|
||||
float h = height();
|
||||
float r = radius();
|
||||
|
||||
// Create a random point on a standard capsule and then rotate to the global frame.
|
||||
|
||||
// Relative areas
|
||||
float capRelArea = sqrt(r) / 2.0f;
|
||||
float sideRelArea = r * h;
|
||||
|
||||
float r1 = uniformRandom(0, capRelArea * 2 + sideRelArea);
|
||||
|
||||
if (r1 < capRelArea * 2) {
|
||||
|
||||
// Select a point uniformly at random on a sphere
|
||||
N = Sphere(Vector3::zero(), 1).randomSurfacePoint();
|
||||
p = N * r;
|
||||
p.y += sign(p.y) * h / 2.0f;
|
||||
} else {
|
||||
// Side
|
||||
float a = uniformRandom(0, (float)twoPi());
|
||||
N.x = cos(a);
|
||||
N.y = 0;
|
||||
N.z = sin(a);
|
||||
p.x = N.x * r;
|
||||
p.z = N.y * r;
|
||||
p.y = uniformRandom(-h / 2.0f, h / 2.0f);
|
||||
}
|
||||
|
||||
// Transform to world space
|
||||
CoordinateFrame cframe;
|
||||
getReferenceFrame(cframe);
|
||||
|
||||
p = cframe.pointToWorldSpace(p);
|
||||
N = cframe.normalToWorldSpace(N);
|
||||
}
|
||||
|
||||
|
||||
void Capsule::getReferenceFrame(CoordinateFrame& cframe) const {
|
||||
cframe.translation = center();
|
||||
|
||||
Vector3 Y = (p1 - p2).direction();
|
||||
Vector3 X = (abs(Y.dot(Vector3::unitX())) > 0.9) ? Vector3::unitY() : Vector3::unitX();
|
||||
Vector3 Z = X.cross(Y).direction();
|
||||
X = Y.cross(Z);
|
||||
cframe.rotation.setColumn(0, X);
|
||||
cframe.rotation.setColumn(1, Y);
|
||||
cframe.rotation.setColumn(2, Z);
|
||||
}
|
||||
|
||||
|
||||
Vector3 Capsule::randomInteriorPoint() const {
|
||||
float h = height();
|
||||
float r = radius();
|
||||
|
||||
// Create a random point in a standard capsule and then rotate to the global frame.
|
||||
|
||||
Vector3 p;
|
||||
|
||||
float hemiVolume = pi() * (r*r*r) * 4 / 6.0;
|
||||
float cylVolume = pi() * square(r) * h;
|
||||
|
||||
float r1 = uniformRandom(0, 2.0 * hemiVolume + cylVolume);
|
||||
|
||||
if (r1 < 2.0 * hemiVolume) {
|
||||
|
||||
p = Sphere(Vector3::zero(), r).randomInteriorPoint();
|
||||
|
||||
p.y += sign(p.y) * h / 2.0f;
|
||||
|
||||
} else {
|
||||
|
||||
// Select a point uniformly at random on a disk
|
||||
float a = uniformRandom(0, (float)twoPi());
|
||||
float r2 = sqrt(uniformRandom(0, 1)) * r;
|
||||
|
||||
p = Vector3(cos(a) * r2,
|
||||
uniformRandom(-h / 2.0f, h / 2.0f),
|
||||
sin(a) * r2);
|
||||
}
|
||||
|
||||
// Transform to world space
|
||||
CoordinateFrame cframe;
|
||||
getReferenceFrame(cframe);
|
||||
|
||||
return cframe.pointToWorldSpace(p);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
2455
dep/src/g3dlite/CollisionDetection.cpp
Normal file
2455
dep/src/g3dlite/CollisionDetection.cpp
Normal file
File diff suppressed because it is too large
Load diff
58
dep/src/g3dlite/Color1.cpp
Normal file
58
dep/src/g3dlite/Color1.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
@file Color1.cpp
|
||||
|
||||
Color class.
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-30
|
||||
@edited 2009-03-27
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Color3.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
const Color1& Color1::one() {
|
||||
static const Color1 x(1.0f);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
const Color1& Color1::zero() {
|
||||
const static Color1 x(0.0f);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
Color1::Color1(BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
Color3 Color1::rgb() const {
|
||||
return Color3(value, value, value);
|
||||
}
|
||||
|
||||
|
||||
void Color1::deserialize(BinaryInput& bi) {
|
||||
value = bi.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Color1::serialize(BinaryOutput& bo) const {
|
||||
bo.writeFloat32(value);
|
||||
}
|
||||
|
||||
|
||||
Color1::Color1(const class Color1uint8& other) {
|
||||
value = other.value / 255.0f;
|
||||
}
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
38
dep/src/g3dlite/Color1uint8.cpp
Normal file
38
dep/src/g3dlite/Color1uint8.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
@file Color1uint8.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-30
|
||||
@edited 2007-01-30
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Color1uint8::Color1uint8(const class Color1& c) : value(iClamp(iFloor(c.value * 256), 0, 255)) {
|
||||
}
|
||||
|
||||
|
||||
Color1uint8::Color1uint8(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Color1uint8::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeUInt8(value);
|
||||
}
|
||||
|
||||
|
||||
void Color1uint8::deserialize(class BinaryInput& bi) {
|
||||
value = bi.readUInt8();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
384
dep/src/g3dlite/Color3.cpp
Normal file
384
dep/src/g3dlite/Color3.cpp
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
/**
|
||||
@file Color3.cpp
|
||||
|
||||
Color class.
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2010-01-28
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include <stdlib.h>
|
||||
#include "G3D/Color3.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Color3uint8.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Color3::Color3(const Any& any) {
|
||||
*this = Color3::zero();
|
||||
any.verifyName("Color3");
|
||||
std::string name = toLower(any.name());
|
||||
|
||||
switch (any.type()) {
|
||||
case Any::TABLE:
|
||||
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "r") {
|
||||
r = it->value;
|
||||
} else if (key == "g") {
|
||||
g = it->value;
|
||||
} else if (key == "b") {
|
||||
b = it->value;
|
||||
} else {
|
||||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Any::ARRAY:
|
||||
if (name == "color3") {
|
||||
any.verifySize(3);
|
||||
r = any[0];
|
||||
g = any[1];
|
||||
b = any[2];
|
||||
} else if (name == "color3::one") {
|
||||
any.verifySize(0);
|
||||
*this = one();
|
||||
} else if (name == "color3::zero") {
|
||||
any.verifySize(0);
|
||||
*this = zero();
|
||||
} else if (name == "color3::fromargb") {
|
||||
*this = Color3::fromARGB((int)any[0].number());
|
||||
} else {
|
||||
any.verify(false, "Expected Color3 constructor");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
any.verify(false, "Bad Color3 constructor");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Color3::operator Any() const {
|
||||
Any a(Any::ARRAY, "Color3");
|
||||
a.append(r, g, b);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
Color3 Color3::ansiMap(uint32 i) {
|
||||
static const Color3 map[] =
|
||||
{Color3::black(), Color3::red() * 0.75f, Color3::green() * 0.75f, Color3::yellow() * 0.75f,
|
||||
Color3::blue() * 0.75f, Color3::purple() * 0.75f, Color3::cyan() * 0.75f, Color3::white() * 0.75f,
|
||||
Color3::white() * 0.90f, Color3::red(), Color3::green(), Color3::yellow(), Color3::blue(),
|
||||
Color3::purple(), Color3::cyan(), Color3::white()};
|
||||
|
||||
return map[i & 15];
|
||||
}
|
||||
|
||||
|
||||
Color3 Color3::pastelMap(uint32 i) {
|
||||
uint32 x = Crypto::crc32(&i, sizeof(uint32));
|
||||
// Create fairly bright, saturated colors
|
||||
Vector3 v(((x >> 22) & 1023) / 1023.0f,
|
||||
(((x >> 11) & 2047) / 2047.0f) * 0.5f + 0.25f,
|
||||
((x & 2047) / 2047.0f) * 0.75f + 0.25f);
|
||||
return Color3::fromHSV(v);
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::red() {
|
||||
static Color3 c(1.0f, 0.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::green() {
|
||||
static Color3 c(0.0f, 1.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::blue() {
|
||||
static Color3 c(0.0f, 0.0f, 1.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::purple() {
|
||||
static Color3 c(0.7f, 0.0f, 1.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::cyan() {
|
||||
static Color3 c(0.0f, 0.7f, 1.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::yellow() {
|
||||
static Color3 c(1.0f, 1.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::brown() {
|
||||
static Color3 c(0.5f, 0.5f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::orange() {
|
||||
static Color3 c(1.0f, 0.5f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::black() {
|
||||
static Color3 c(0.0f, 0.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
const Color3& Color3::zero() {
|
||||
static Color3 c(0.0f, 0.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::one() {
|
||||
static Color3 c(1.0f, 1.0f, 1.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::gray() {
|
||||
static Color3 c(0.7f, 0.7f, 0.7f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::white() {
|
||||
static Color3 c(1, 1, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
bool Color3::isFinite() const {
|
||||
return G3D::isFinite(r) && G3D::isFinite(g) && G3D::isFinite(b);
|
||||
}
|
||||
|
||||
|
||||
Color3::Color3(BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Color3::deserialize(BinaryInput& bi) {
|
||||
r = bi.readFloat32();
|
||||
g = bi.readFloat32();
|
||||
b = bi.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Color3::serialize(BinaryOutput& bo) const {
|
||||
bo.writeFloat32(r);
|
||||
bo.writeFloat32(g);
|
||||
bo.writeFloat32(b);
|
||||
}
|
||||
|
||||
|
||||
const Color3& Color3::wheelRandom() {
|
||||
static const Color3 colorArray[8] =
|
||||
{Color3::blue(), Color3::red(), Color3::green(),
|
||||
Color3::orange(), Color3::yellow(),
|
||||
Color3::cyan(), Color3::purple(), Color3::brown()};
|
||||
|
||||
return colorArray[iRandom(0, 7)];
|
||||
}
|
||||
|
||||
|
||||
size_t Color3::hashCode() const {
|
||||
unsigned int rhash = (*(int*)(void*)(&r));
|
||||
unsigned int ghash = (*(int*)(void*)(&g));
|
||||
unsigned int bhash = (*(int*)(void*)(&b));
|
||||
|
||||
return rhash + (ghash * 37) + (bhash * 101);
|
||||
}
|
||||
|
||||
|
||||
Color3::Color3(const Vector3& v) {
|
||||
r = v.x;
|
||||
g = v.y;
|
||||
b = v.z;
|
||||
}
|
||||
|
||||
|
||||
Color3::Color3(const class Color3uint8& other) {
|
||||
r = other.r / 255.0f;
|
||||
g = other.g / 255.0f;
|
||||
b = other.b / 255.0f;
|
||||
}
|
||||
|
||||
|
||||
Color3 Color3::fromARGB(uint32 x) {
|
||||
return Color3((float)((x >> 16) & 0xFF), (float)((x >> 8) & 0xFF), (float)(x & 0xFF)) / 255.0f;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
Color3 Color3::random() {
|
||||
return Color3(uniformRandom(),
|
||||
uniformRandom(),
|
||||
uniformRandom()).direction();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Color3& Color3::operator/= (float fScalar) {
|
||||
if (fScalar != 0.0f) {
|
||||
float fInvScalar = 1.0f / fScalar;
|
||||
r *= fInvScalar;
|
||||
g *= fInvScalar;
|
||||
b *= fInvScalar;
|
||||
} else {
|
||||
r = (float)G3D::finf();
|
||||
g = (float)G3D::finf();
|
||||
b = (float)G3D::finf();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Color3::unitize (float fTolerance) {
|
||||
float fLength = length();
|
||||
|
||||
if ( fLength > fTolerance ) {
|
||||
float fInvLength = 1.0f / fLength;
|
||||
r *= fInvLength;
|
||||
g *= fInvLength;
|
||||
b *= fInvLength;
|
||||
} else {
|
||||
fLength = 0.0f;
|
||||
}
|
||||
|
||||
return fLength;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Color3 Color3::fromHSV(const Vector3& _hsv) {
|
||||
debugAssertM((_hsv.x <= 1.0f && _hsv.x >= 0.0f)
|
||||
&& (_hsv.y <= 1.0f && _hsv.y >= 0.0f)
|
||||
&& ( _hsv.z <= 1.0f && _hsv.z >= 0.0f), "H,S,V must be between [0,1]");
|
||||
const int i = iMin(5, G3D::iFloor(6.0 * _hsv.x));
|
||||
const float f = 6.0f * _hsv.x - i;
|
||||
const float m = _hsv.z * (1.0f - (_hsv.y));
|
||||
const float n = _hsv.z * (1.0f - (_hsv.y * f));
|
||||
const float k = _hsv.z * (1.0f - (_hsv.y * (1 - f)));
|
||||
switch(i) {
|
||||
case 0:
|
||||
return Color3(_hsv.z, k, m);
|
||||
|
||||
case 1:
|
||||
return Color3(n, _hsv.z, m);
|
||||
|
||||
case 2:
|
||||
return Color3(m, _hsv.z, k);
|
||||
|
||||
case 3:
|
||||
return Color3(m, n, _hsv.z);
|
||||
|
||||
case 4:
|
||||
return Color3(k, m, _hsv.z);
|
||||
|
||||
case 5:
|
||||
return Color3(_hsv.z, m, n);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "fell through switch..");
|
||||
}
|
||||
return Color3::black();
|
||||
}
|
||||
|
||||
|
||||
Vector3 Color3::toHSV(const Color3& _rgb) {
|
||||
debugAssertM((_rgb.r <= 1.0f && _rgb.r >= 0.0f)
|
||||
&& (_rgb.g <= 1.0f && _rgb.g >= 0.0f)
|
||||
&& (_rgb.b <= 1.0f && _rgb.b >= 0.0f), "R,G,B must be between [0,1]");
|
||||
Vector3 hsv = Vector3::zero();
|
||||
hsv.z = G3D::max(G3D::max(_rgb.r, _rgb.g), _rgb.b);
|
||||
if (G3D::fuzzyEq(hsv.z, 0.0f)) {
|
||||
return hsv;
|
||||
}
|
||||
|
||||
const float x = G3D::min(G3D::min(_rgb.r, _rgb.g), _rgb.b);
|
||||
hsv.y = (hsv.z - x) / hsv.z;
|
||||
|
||||
if (G3D::fuzzyEq(hsv.y, 0.0f)) {
|
||||
return hsv;
|
||||
}
|
||||
|
||||
Vector3 rgbN;
|
||||
rgbN.x = (hsv.z - _rgb.r) / (hsv.z - x);
|
||||
rgbN.y = (hsv.z - _rgb.g) / (hsv.z - x);
|
||||
rgbN.z = (hsv.z - _rgb.b) / (hsv.z - x);
|
||||
|
||||
if (_rgb.r == hsv.z) { // note from the max we know that it exactly equals one of the three.
|
||||
hsv.x = (_rgb.g == x)? 5.0f + rgbN.z : 1.0f - rgbN.y;
|
||||
} else if (_rgb.g == hsv.z) {
|
||||
hsv.x = (_rgb.b == x)? 1.0f + rgbN.x : 3.0f - rgbN.z;
|
||||
} else {
|
||||
hsv.x = (_rgb.r == x)? 3.0f + rgbN.y : 5.0f - rgbN.x;
|
||||
}
|
||||
|
||||
hsv.x /= 6.0f;
|
||||
|
||||
return hsv;
|
||||
}
|
||||
|
||||
Color3 Color3::jetColorMap(const float& val) {
|
||||
debugAssertM(val <= 1.0f && val >= 0.0f , "value should be in [0,1]");
|
||||
|
||||
//truncated triangles where sides have slope 4
|
||||
Color3 jet;
|
||||
|
||||
jet.r = G3D::min(4.0f * val - 1.5f,-4.0f * val + 4.5f) ;
|
||||
jet.g = G3D::min(4.0f * val - 0.5f,-4.0f * val + 3.5f) ;
|
||||
jet.b = G3D::min(4.0f * val + 0.5f,-4.0f * val + 2.5f) ;
|
||||
|
||||
|
||||
jet.r = G3D::clamp(jet.r, 0.0f, 1.0f);
|
||||
jet.g = G3D::clamp(jet.g, 0.0f, 1.0f);
|
||||
jet.b = G3D::clamp(jet.b, 0.0f, 1.0f);
|
||||
|
||||
return jet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
std::string Color3::toString() const {
|
||||
return G3D::format("(%g, %g, %g)", r, g, b);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Color3 Color3::rainbowColorMap(float hue) {
|
||||
return fromHSV(Vector3(hue, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
|
||||
}; // namespace
|
||||
|
||||
45
dep/src/g3dlite/Color3uint8.cpp
Normal file
45
dep/src/g3dlite/Color3uint8.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
@file Color3uint8.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-04-07
|
||||
@edited 2006-01-07
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Color3uint8.h"
|
||||
#include "G3D/Color3.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Color3uint8::Color3uint8(const class Color3& c) {
|
||||
r = iMin(255, iFloor(c.r * 256));
|
||||
g = iMin(255, iFloor(c.g * 256));
|
||||
b = iMin(255, iFloor(c.b * 256));
|
||||
}
|
||||
|
||||
|
||||
Color3uint8::Color3uint8(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Color3uint8::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeUInt8(r);
|
||||
bo.writeUInt8(g);
|
||||
bo.writeUInt8(b);
|
||||
}
|
||||
|
||||
|
||||
void Color3uint8::deserialize(class BinaryInput& bi) {
|
||||
r = bi.readUInt8();
|
||||
g = bi.readUInt8();
|
||||
b = bi.readUInt8();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
192
dep/src/g3dlite/Color4.cpp
Normal file
192
dep/src/g3dlite/Color4.cpp
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
/**
|
||||
@file Color4.cpp
|
||||
|
||||
Color class.
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@cite Portions by Laura Wollstadt, graphics3d.com
|
||||
@cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com
|
||||
|
||||
|
||||
@created 2002-06-25
|
||||
@edited 2009-11-10
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/Vector4.h"
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Color4::Color4(const Any& any) {
|
||||
*this = Color4::zero();
|
||||
any.verifyName("Color4");
|
||||
|
||||
if (any.type() == Any::TABLE) {
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "r") {
|
||||
r = it->value;
|
||||
} else if (key == "g") {
|
||||
g = it->value;
|
||||
} else if (key == "b") {
|
||||
b = it->value;
|
||||
} else if (key == "a") {
|
||||
a = it->value;
|
||||
} else {
|
||||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
} else if (toLower(any.name()) == "color4") {
|
||||
r = any[0];
|
||||
g = any[1];
|
||||
b = any[2];
|
||||
a = any[3];
|
||||
} else {
|
||||
any.verifyName("Color4::fromARGB");
|
||||
*this = Color4::fromARGB((int)any[0].number());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Color4::operator Any() const {
|
||||
Any any(Any::ARRAY, "Color4");
|
||||
any.append(r, g, b, a);
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
const Color4& Color4::one() {
|
||||
const static Color4 x(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
const Color4& Color4::zero() {
|
||||
static Color4 c(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color4& Color4::inf() {
|
||||
static Color4 c((float)G3D::finf(), (float)G3D::finf(), (float)G3D::finf(), (float)G3D::finf());
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color4& Color4::nan() {
|
||||
static Color4 c((float)G3D::fnan(), (float)G3D::fnan(), (float)G3D::fnan(), (float)G3D::fnan());
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const Color4& Color4::clear() {
|
||||
return Color4::zero();
|
||||
}
|
||||
|
||||
|
||||
Color4::Color4(const Vector4& v) {
|
||||
r = v.x;
|
||||
g = v.y;
|
||||
b = v.z;
|
||||
a = v.w;
|
||||
}
|
||||
|
||||
|
||||
Color4::Color4(const Color4uint8& c) : r(c.r), g(c.g), b(c.b), a(c.a) {
|
||||
*this /= 255.0f;
|
||||
}
|
||||
|
||||
size_t Color4::hashCode() const {
|
||||
unsigned int rhash = (*(int*)(void*)(&r));
|
||||
unsigned int ghash = (*(int*)(void*)(&g));
|
||||
unsigned int bhash = (*(int*)(void*)(&b));
|
||||
unsigned int ahash = (*(int*)(void*)(&a));
|
||||
|
||||
return rhash + (ghash * 37) + (bhash * 101) + (ahash * 241);
|
||||
}
|
||||
|
||||
Color4 Color4::fromARGB(uint32 x) {
|
||||
return Color4(
|
||||
(float)((x >> 16) & 0xFF),
|
||||
(float)((x >> 8) & 0xFF),
|
||||
(float)(x & 0xFF),
|
||||
(float)((x >> 24) & 0xFF)) / 255.0;
|
||||
}
|
||||
|
||||
|
||||
Color4::Color4(BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Color4::deserialize(BinaryInput& bi) {
|
||||
r = bi.readFloat32();
|
||||
g = bi.readFloat32();
|
||||
b = bi.readFloat32();
|
||||
a = bi.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Color4::serialize(BinaryOutput& bo) const {
|
||||
bo.writeFloat32(r);
|
||||
bo.writeFloat32(g);
|
||||
bo.writeFloat32(b);
|
||||
bo.writeFloat32(a);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Color4 Color4::operator/ (float fScalar) const {
|
||||
Color4 kQuot;
|
||||
|
||||
if (fScalar != 0.0f) {
|
||||
float fInvScalar = 1.0f / fScalar;
|
||||
kQuot.r = fInvScalar * r;
|
||||
kQuot.g = fInvScalar * g;
|
||||
kQuot.b = fInvScalar * b;
|
||||
kQuot.a = fInvScalar * a;
|
||||
return kQuot;
|
||||
|
||||
} else {
|
||||
|
||||
return Color4::inf();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Color4& Color4::operator/= (float fScalar) {
|
||||
if (fScalar != 0.0f) {
|
||||
float fInvScalar = 1.0f / fScalar;
|
||||
r *= fInvScalar;
|
||||
g *= fInvScalar;
|
||||
b *= fInvScalar;
|
||||
a *= fInvScalar;
|
||||
} else {
|
||||
r = (float)G3D::finf();
|
||||
g = (float)G3D::finf();
|
||||
b = (float)G3D::finf();
|
||||
a = (float)G3D::finf();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
std::string Color4::toString() const {
|
||||
return G3D::format("(%g, %g, %g, %g)", r, g, b, a);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace
|
||||
|
||||
47
dep/src/g3dlite/Color4uint8.cpp
Normal file
47
dep/src/g3dlite/Color4uint8.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
@file Color4uint8.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-04-07
|
||||
@edited 2006-01-07
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Color4uint8::Color4uint8(const class Color4& c) {
|
||||
r = iMin(255, iFloor(c.r * 256));
|
||||
g = iMin(255, iFloor(c.g * 256));
|
||||
b = iMin(255, iFloor(c.b * 256));
|
||||
a = iMin(255, iFloor(c.a * 256));
|
||||
}
|
||||
|
||||
|
||||
Color4uint8::Color4uint8(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Color4uint8::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeUInt8(r);
|
||||
bo.writeUInt8(g);
|
||||
bo.writeUInt8(b);
|
||||
bo.writeUInt8(a);
|
||||
}
|
||||
|
||||
|
||||
void Color4uint8::deserialize(class BinaryInput& bi) {
|
||||
r = bi.readUInt8();
|
||||
g = bi.readUInt8();
|
||||
b = bi.readUInt8();
|
||||
a = bi.readUInt8();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
79
dep/src/g3dlite/Cone.cpp
Normal file
79
dep/src/g3dlite/Cone.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
@file Cone.cpp
|
||||
|
||||
Cone class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-07-09
|
||||
@edited 2006-01-29
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Cone.h"
|
||||
#include "G3D/Line.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/Box.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Cone::Cone(const Vector3 &tip, const Vector3 &direction, float angle) {
|
||||
this->tip = tip;
|
||||
this->direction = direction.direction();
|
||||
this->angle = angle;
|
||||
|
||||
debugAssert(angle >= 0);
|
||||
debugAssert(angle <= pi());
|
||||
}
|
||||
|
||||
/**
|
||||
Forms the smallest cone that contains the box. Undefined if
|
||||
the tip is inside or on the box.
|
||||
*/
|
||||
Cone::Cone(const Vector3& tip, const Box& box) {
|
||||
this->tip = tip;
|
||||
this->direction = (box.center() - tip).direction();
|
||||
|
||||
// Find the biggest angle
|
||||
float smallestDotProduct = direction.dot((box.corner(0) - tip).direction());
|
||||
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
float dp = direction.dot((box.corner(i) - tip).direction());
|
||||
|
||||
debugAssert(dp > 0);
|
||||
|
||||
if (dp < smallestDotProduct) {
|
||||
smallestDotProduct = dp;
|
||||
}
|
||||
}
|
||||
|
||||
angle = acosf(smallestDotProduct);
|
||||
}
|
||||
|
||||
|
||||
bool Cone::intersects(const Sphere& b) const {
|
||||
// If the bounding sphere contains the tip, then
|
||||
// they definitely touch.
|
||||
if (b.contains(this->tip)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Move the tip backwards, effectively making the cone bigger
|
||||
// to account for the radius of the sphere.
|
||||
|
||||
Vector3 tip = this->tip - direction * b.radius / sinf(angle);
|
||||
|
||||
return Cone(tip, direction, angle).contains(b.center);
|
||||
}
|
||||
|
||||
|
||||
bool Cone::contains(const Vector3& v) const {
|
||||
|
||||
Vector3 d = (v - tip).direction();
|
||||
|
||||
float x = d.dot(direction);
|
||||
|
||||
return (x > 0) && (x >= cosf(angle));
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
457
dep/src/g3dlite/ConvexPolyhedron.cpp
Normal file
457
dep/src/g3dlite/ConvexPolyhedron.cpp
Normal file
|
|
@ -0,0 +1,457 @@
|
|||
/**
|
||||
@file ConvexPolyhedron.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-11-11
|
||||
@edited 2009-08-10
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/ConvexPolyhedron.h"
|
||||
#include "G3D/debug.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
ConvexPolygon::ConvexPolygon(const Array<Vector3>& __vertex) : _vertex(__vertex) {
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
|
||||
ConvexPolygon::ConvexPolygon(const Vector3& v0, const Vector3& v1, const Vector3& v2) {
|
||||
_vertex.append(v0, v1, v2);
|
||||
}
|
||||
|
||||
|
||||
bool ConvexPolygon::isEmpty() const {
|
||||
return (_vertex.length() == 0) || (getArea() <= fuzzyEpsilon);
|
||||
}
|
||||
|
||||
|
||||
float ConvexPolygon::getArea() const {
|
||||
|
||||
if (_vertex.length() < 3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float sum = 0;
|
||||
|
||||
int length = _vertex.length();
|
||||
// Split into triangle fan, compute individual area
|
||||
for (int v = 2; v < length; v++) {
|
||||
int i0 = 0;
|
||||
int i1 = v - 1;
|
||||
int i2 = v;
|
||||
|
||||
sum += (_vertex[i1] - _vertex[i0]).cross(_vertex[i2] - _vertex[i0]).magnitude() / 2;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
void ConvexPolygon::cut(const Plane& plane, ConvexPolygon &above, ConvexPolygon &below) {
|
||||
DirectedEdge edge;
|
||||
cut(plane, above, below, edge);
|
||||
}
|
||||
|
||||
void ConvexPolygon::cut(const Plane& plane, ConvexPolygon &above, ConvexPolygon &below, DirectedEdge &newEdge) {
|
||||
above._vertex.resize(0);
|
||||
below._vertex.resize(0);
|
||||
|
||||
if (isEmpty()) {
|
||||
//debugPrintf("Empty\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int v = 0;
|
||||
int length = _vertex.length();
|
||||
|
||||
|
||||
Vector3 polyNormal = normal();
|
||||
Vector3 planeNormal= plane.normal();
|
||||
|
||||
// See if the polygon is *in* the plane.
|
||||
if (planeNormal.fuzzyEq(polyNormal) || planeNormal.fuzzyEq(-polyNormal)) {
|
||||
// Polygon is parallel to the plane. It must be either above,
|
||||
// below, or in the plane.
|
||||
|
||||
double a, b, c, d;
|
||||
Vector3 pt = _vertex[0];
|
||||
|
||||
plane.getEquation(a,b,c,d);
|
||||
float r = (float)(a * pt.x + b * pt.y + c * pt.z + d);
|
||||
|
||||
if (fuzzyGe(r, 0)) {
|
||||
// The polygon is entirely in the plane.
|
||||
//debugPrintf("Entirely above\n");
|
||||
above = *this;
|
||||
return;
|
||||
} else {
|
||||
//debugPrintf("Entirely below (1)\n");
|
||||
below = *this;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Number of edges crossing the plane. Used for
|
||||
// debug assertions.
|
||||
int count = 0;
|
||||
|
||||
// True when the last _vertex we looked at was above the plane
|
||||
bool lastAbove = plane.halfSpaceContains(_vertex[v]);
|
||||
|
||||
if (lastAbove) {
|
||||
above._vertex.append(_vertex[v]);
|
||||
} else {
|
||||
below._vertex.append(_vertex[v]);
|
||||
}
|
||||
|
||||
for (v = 1; v < length; v++) {
|
||||
bool isAbove = plane.halfSpaceContains(_vertex[v]);
|
||||
|
||||
if (lastAbove ^ isAbove) {
|
||||
// Switched sides.
|
||||
// Create an interpolated point that lies
|
||||
// in the plane, between the two points.
|
||||
Line line = Line::fromTwoPoints(_vertex[v - 1], _vertex[v]);
|
||||
Vector3 interp = line.intersection(plane);
|
||||
|
||||
if (! interp.isFinite()) {
|
||||
|
||||
// Since the polygon is not in the plane (we checked above),
|
||||
// it must be the case that this edge (and only this edge)
|
||||
// is in the plane. This only happens when the polygon is
|
||||
// entirely below the plane except for one edge. This edge
|
||||
// forms a degenerate polygon, so just treat the whole polygon
|
||||
// as below the plane.
|
||||
below = *this;
|
||||
above._vertex.resize(0);
|
||||
//debugPrintf("Entirely below\n");
|
||||
return;
|
||||
}
|
||||
|
||||
above._vertex.append(interp);
|
||||
below._vertex.append(interp);
|
||||
if (lastAbove) {
|
||||
newEdge.stop = interp;
|
||||
} else {
|
||||
newEdge.start = interp;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
lastAbove = isAbove;
|
||||
if (lastAbove) {
|
||||
above._vertex.append(_vertex[v]);
|
||||
} else {
|
||||
below._vertex.append(_vertex[v]);
|
||||
}
|
||||
}
|
||||
|
||||
// Loop back to the first point, seeing if an interpolated point is
|
||||
// needed.
|
||||
bool isAbove = plane.halfSpaceContains(_vertex[0]);
|
||||
if (lastAbove ^ isAbove) {
|
||||
Line line = Line::fromTwoPoints(_vertex[length - 1], _vertex[0]);
|
||||
Vector3 interp = line.intersection(plane);
|
||||
if (! interp.isFinite()) {
|
||||
// Since the polygon is not in the plane (we checked above),
|
||||
// it must be the case that this edge (and only this edge)
|
||||
// is in the plane. This only happens when the polygon is
|
||||
// entirely below the plane except for one edge. This edge
|
||||
// forms a degenerate polygon, so just treat the whole polygon
|
||||
// as below the plane.
|
||||
below = *this;
|
||||
above._vertex.resize(0);
|
||||
//debugPrintf("Entirely below\n");
|
||||
return;
|
||||
}
|
||||
|
||||
above._vertex.append(interp);
|
||||
below._vertex.append(interp);
|
||||
debugAssertM(count < 2, "Convex polygons may only intersect planes at two edges.");
|
||||
if (lastAbove) {
|
||||
newEdge.stop = interp;
|
||||
} else {
|
||||
newEdge.start = interp;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
|
||||
debugAssertM((count == 2) || (count == 0), "Convex polygons may only intersect planes at two edges.");
|
||||
}
|
||||
|
||||
|
||||
ConvexPolygon ConvexPolygon::inverse() const {
|
||||
ConvexPolygon result;
|
||||
int length = _vertex.length();
|
||||
result._vertex.resize(length);
|
||||
|
||||
for (int v = 0; v < length; v++) {
|
||||
result._vertex[v] = _vertex[length - v - 1];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void ConvexPolygon::removeDuplicateVertices(){
|
||||
// Any valid polygon should have 3 or more vertices, but why take chances?
|
||||
if (_vertex.size() >= 2){
|
||||
|
||||
// Remove duplicate vertices.
|
||||
for (int i=0;i<_vertex.size()-1;++i){
|
||||
if (_vertex[i].fuzzyEq(_vertex[i+1])){
|
||||
_vertex.remove(i+1);
|
||||
--i; // Don't move forward.
|
||||
}
|
||||
}
|
||||
|
||||
// Check the last vertex against the first.
|
||||
if (_vertex[_vertex.size()-1].fuzzyEq(_vertex[0])){
|
||||
_vertex.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ConvexPolyhedron::ConvexPolyhedron(const Array<ConvexPolygon>& _face) : face(_face) {
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
|
||||
float ConvexPolyhedron::getVolume() const {
|
||||
|
||||
if (face.length() < 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The volume of any pyramid is 1/3 * h * base area.
|
||||
// Discussion at: http://nrich.maths.org/mathsf/journalf/oct01/art1/
|
||||
|
||||
float sum = 0;
|
||||
|
||||
// Choose the first _vertex of the first face as the origin.
|
||||
// This lets us skip one face, too, and avoids negative heights.
|
||||
Vector3 v0 = face[0]._vertex[0];
|
||||
for (int f = 1; f < face.length(); f++) {
|
||||
const ConvexPolygon& poly = face[f];
|
||||
|
||||
float height = (poly._vertex[0] - v0).dot(poly.normal());
|
||||
float base = poly.getArea();
|
||||
|
||||
sum += height * base;
|
||||
}
|
||||
|
||||
return sum / 3;
|
||||
}
|
||||
|
||||
bool ConvexPolyhedron::isEmpty() const {
|
||||
return (face.length() == 0) || (getVolume() <= fuzzyEpsilon);
|
||||
}
|
||||
|
||||
void ConvexPolyhedron::cut(const Plane& plane, ConvexPolyhedron &above, ConvexPolyhedron &below) {
|
||||
above.face.resize(0);
|
||||
below.face.resize(0);
|
||||
|
||||
Array<DirectedEdge> edge;
|
||||
|
||||
int f;
|
||||
|
||||
// See if the plane cuts this polyhedron at all. Detect when
|
||||
// the polyhedron is entirely to one side or the other.
|
||||
//{
|
||||
int numAbove = 0, numIn = 0, numBelow = 0;
|
||||
bool ruledOut = false;
|
||||
double d;
|
||||
Vector3 abc;
|
||||
plane.getEquation(abc, d);
|
||||
|
||||
// This number has to be fairly large to prevent precision problems down
|
||||
// the road.
|
||||
const float eps = 0.005f;
|
||||
for (f = face.length() - 1; (f >= 0) && (!ruledOut); f--) {
|
||||
const ConvexPolygon& poly = face[f];
|
||||
for (int v = poly._vertex.length() - 1; (v >= 0) && (!ruledOut); v--) {
|
||||
double r = abc.dot(poly._vertex[v]) + d;
|
||||
if (r > eps) {
|
||||
numAbove++;
|
||||
} else if (r < -eps) {
|
||||
numBelow++;
|
||||
} else {
|
||||
numIn++;
|
||||
}
|
||||
|
||||
ruledOut = (numAbove != 0) && (numBelow !=0);
|
||||
}
|
||||
}
|
||||
|
||||
if (numBelow == 0) {
|
||||
above = *this;
|
||||
return;
|
||||
} else if (numAbove == 0) {
|
||||
below = *this;
|
||||
return;
|
||||
}
|
||||
//}
|
||||
|
||||
// Clip each polygon, collecting split edges.
|
||||
for (f = face.length() - 1; f >= 0; f--) {
|
||||
ConvexPolygon a, b;
|
||||
DirectedEdge e;
|
||||
face[f].cut(plane, a, b, e);
|
||||
|
||||
bool aEmpty = a.isEmpty();
|
||||
bool bEmpty = b.isEmpty();
|
||||
|
||||
//debugPrintf("\n");
|
||||
if (! aEmpty) {
|
||||
//debugPrintf(" Above %f\n", a.getArea());
|
||||
above.face.append(a);
|
||||
}
|
||||
|
||||
if (! bEmpty) {
|
||||
//debugPrintf(" Below %f\n", b.getArea());
|
||||
below.face.append(b);
|
||||
}
|
||||
|
||||
if (! aEmpty && ! bEmpty) {
|
||||
//debugPrintf(" == Split\n");
|
||||
edge.append(e);
|
||||
} else {
|
||||
// Might be the case that the polygon is entirely on
|
||||
// one side of the plane yet there is an edge we need
|
||||
// because it touches the plane.
|
||||
//
|
||||
// Extract the non-empty _vertex list and examine it.
|
||||
// If we find exactly one edge in the plane, add that edge.
|
||||
const Array<Vector3>& _vertex = (aEmpty ? b._vertex : a._vertex);
|
||||
int L = _vertex.length();
|
||||
int count = 0;
|
||||
for (int v = 0; v < L; v++) {
|
||||
if (plane.fuzzyContains(_vertex[v]) && plane.fuzzyContains(_vertex[(v + 1) % L])) {
|
||||
e.start = _vertex[v];
|
||||
e.stop = _vertex[(v + 1) % L];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
edge.append(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (above.face.length() == 1) {
|
||||
// Only one face above means that this entire
|
||||
// polyhedron is below the plane. Move that face over.
|
||||
below.face.append(above.face[0]);
|
||||
above.face.resize(0);
|
||||
} else if (below.face.length() == 1) {
|
||||
// This shouldn't happen, but it arises in practice
|
||||
// from numerical imprecision.
|
||||
above.face.append(below.face[0]);
|
||||
below.face.resize(0);
|
||||
}
|
||||
|
||||
if ((above.face.length() > 0) && (below.face.length() > 0)) {
|
||||
// The polyhedron was actually cut; create a cap polygon
|
||||
ConvexPolygon cap;
|
||||
|
||||
// Collect the final polgyon by sorting the edges
|
||||
int numVertices = edge.length();
|
||||
/*debugPrintf("\n");
|
||||
for (int xx=0; xx < numVertices; xx++) {
|
||||
std::string s1 = edge[xx].start.toString();
|
||||
std::string s2 = edge[xx].stop.toString();
|
||||
debugPrintf("%s -> %s\n", s1.c_str(), s2.c_str());
|
||||
}
|
||||
*/
|
||||
|
||||
// Need at least three points to make a polygon
|
||||
debugAssert(numVertices >= 3);
|
||||
|
||||
Vector3 last_vertex = edge.last().stop;
|
||||
cap._vertex.append(last_vertex);
|
||||
|
||||
// Search for the next _vertex. Because of accumulating
|
||||
// numerical error, we have to find the closest match, not
|
||||
// just the one we expect.
|
||||
for (int v = numVertices - 1; v >= 0; v--) {
|
||||
// matching edge index
|
||||
int index = 0;
|
||||
int num = edge.length();
|
||||
double distance = (edge[index].start - last_vertex).squaredMagnitude();
|
||||
for (int e = 1; e < num; e++) {
|
||||
double d = (edge[e].start - last_vertex).squaredMagnitude();
|
||||
|
||||
if (d < distance) {
|
||||
// This is the new closest one
|
||||
index = e;
|
||||
distance = d;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't tolerate ridiculous error.
|
||||
debugAssertM(distance < 0.02, "Edge missing while closing polygon.");
|
||||
|
||||
last_vertex = edge[index].stop;
|
||||
cap._vertex.append(last_vertex);
|
||||
}
|
||||
|
||||
//debugPrintf("\n");
|
||||
//debugPrintf("Cap (both) %f\n", cap.getArea());
|
||||
above.face.append(cap);
|
||||
below.face.append(cap.inverse());
|
||||
}
|
||||
|
||||
// Make sure we put enough faces on each polyhedra
|
||||
debugAssert((above.face.length() == 0) || (above.face.length() >= 4));
|
||||
debugAssert((below.face.length() == 0) || (below.face.length() >= 4));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
|
||||
ConvexPolygon2D::ConvexPolygon2D(const Array<Vector2>& pts, bool reverse) : m_vertex(pts) {
|
||||
if (reverse) {
|
||||
m_vertex.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ConvexPolygon2D::contains(const Vector2& p, bool reverse) const {
|
||||
// Compute the signed area of each polygon from p to an edge.
|
||||
// If the area is non-negative for all polygons then p is inside
|
||||
// the polygon. (To adapt this algorithm for a concave polygon,
|
||||
// the *sum* of the areas must be non-negative).
|
||||
|
||||
float r = reverse ? -1 : 1;
|
||||
|
||||
for (int i0 = 0; i0 < m_vertex.size(); ++i0) {
|
||||
int i1 = (i0 + 1) % m_vertex.size();
|
||||
const Vector2& v0 = m_vertex[i0];
|
||||
const Vector2& v1 = m_vertex[i1];
|
||||
|
||||
Vector2 e0 = v0 - p;
|
||||
Vector2 e1 = v1 - p;
|
||||
|
||||
// Area = (1/2) cross product, negated to be ccw in
|
||||
// a 2D space; we neglect the 1/2
|
||||
float area = -(e0.x * e1.y - e0.y * e1.x);
|
||||
|
||||
if (area * r < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
436
dep/src/g3dlite/CoordinateFrame.cpp
Normal file
436
dep/src/g3dlite/CoordinateFrame.cpp
Normal 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
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
@file Crypto.cpp
|
||||
|
||||
@author Morgan McGuire, matrix@graphics3d.com
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
|
||||
@created 2006-03-28
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
#include "G3D/platform.h"
|
||||
#include "G3D/Crypto.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include <zlib.h>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
|
@ -63,84 +64,7 @@ int Crypto::numSmallPrimes() {
|
|||
}
|
||||
|
||||
uint32 Crypto::crc32(const void* byte, size_t numBytes) {
|
||||
static const uint32 crc32Table[256] = {
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
||||
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
|
||||
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
||||
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
||||
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
||||
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
||||
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
||||
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
||||
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
||||
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
||||
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
||||
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
||||
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
||||
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
||||
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
||||
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
|
||||
};
|
||||
|
||||
// By definition, initialize to all binary 1's
|
||||
uint32 value = 0xFFFFFFFF;
|
||||
|
||||
for (size_t i = 0; i < numBytes; ++i) {
|
||||
value = (value >> 8 ) ^ crc32Table[static_cast<const uint8*>(byte)[i] ^ (value & 0xFF)];
|
||||
}
|
||||
|
||||
return value;
|
||||
return ::crc32(::crc32(0, Z_NULL, 0), static_cast<const Bytef *>(byte), numBytes);
|
||||
}
|
||||
|
||||
} // G3D
|
||||
|
|
|
|||
471
dep/src/g3dlite/Crypto_md5.cpp
Normal file
471
dep/src/g3dlite/Crypto_md5.cpp
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
/**
|
||||
@file Crypto_md5.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
Copyright 2006-2007, Morgan McGuire. All rights reserved.
|
||||
|
||||
@created 2006-03-28
|
||||
@edited 2006-04-06
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Crypto.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
MD5Hash::MD5Hash(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void MD5Hash::deserialize(class BinaryInput& b) {
|
||||
b.readBytes(value, 16);
|
||||
}
|
||||
|
||||
|
||||
void MD5Hash::serialize(class BinaryOutput& b) const {
|
||||
b.writeBytes(value, 16);
|
||||
}
|
||||
|
||||
|
||||
typedef unsigned char md5_byte_t; /* 8-bit byte */
|
||||
typedef unsigned int md5_word_t; /* 32-bit word */
|
||||
|
||||
/* Define the state of the MD5 Algorithm. */
|
||||
typedef struct md5_state_s {
|
||||
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||
md5_word_t abcd[4]; /* digest buffer */
|
||||
md5_byte_t buf[64]; /* accumulate block */
|
||||
} md5_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Initialize the algorithm. */
|
||||
static void md5_init(md5_state_t *pms);
|
||||
|
||||
/* Append a string to the message. */
|
||||
static void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
|
||||
|
||||
/* Finish the message and return the digest. */
|
||||
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
MD5Hash Crypto::md5(const void* data, size_t n) {
|
||||
md5_state_t state;
|
||||
md5_init(&state);
|
||||
md5_append(&state, (const uint8*)data, (int)n);
|
||||
|
||||
MD5Hash h;
|
||||
md5_finish(&state, &(h[0]));
|
||||
return h;
|
||||
}
|
||||
|
||||
/*
|
||||
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.c is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
|
||||
either statically or dynamically; added missing #include <string.h>
|
||||
in library.
|
||||
2002-03-11 lpd Corrected argument list for main(), and added int return
|
||||
type, in test program and T value program.
|
||||
2002-02-21 lpd Added missing #include <stdio.h> in test program.
|
||||
2000-07-03 lpd Patched to eliminate warnings about "constant is
|
||||
unsigned in ANSI C, signed in traditional"; made test program
|
||||
self-checking.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This package supports both compile-time and run-time determination of CPU
|
||||
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
|
||||
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
|
||||
* defined as non-zero, the code will be compiled to run only on big-endian
|
||||
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
|
||||
* run on either big- or little-endian CPUs, but will run slightly less
|
||||
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
|
||||
*/
|
||||
|
||||
|
||||
#if defined(G3D_LINUX) || defined(G3D_OSX)
|
||||
# if defined(G3D_OSX_PPC)
|
||||
# include <ppc/endian.h>
|
||||
# elif defined(G3D_OSX_INTEL)
|
||||
# include <i386/endian.h>
|
||||
# elif defined(__linux__)
|
||||
# include <endian.h>
|
||||
# elif defined(__FreeBSD__)
|
||||
# include <sys/endian.h>
|
||||
# endif
|
||||
#else
|
||||
# define BYTE_ORDER 0
|
||||
#endif
|
||||
|
||||
#define T_MASK ((md5_word_t)~0)
|
||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||
#define T3 0x242070db
|
||||
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||
#define T6 0x4787c62a
|
||||
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||
#define T9 0x698098d8
|
||||
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
||||
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
||||
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
||||
#define T13 0x6b901122
|
||||
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||
#define T16 0x49b40821
|
||||
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||
#define T19 0x265e5a51
|
||||
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||
#define T22 0x02441453
|
||||
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||
#define T25 0x21e1cde6
|
||||
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||
#define T28 0x455a14ed
|
||||
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||
#define T31 0x676f02d9
|
||||
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
||||
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
||||
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
||||
#define T35 0x6d9d6122
|
||||
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||
#define T38 0x4bdecfa9
|
||||
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||
#define T41 0x289b7ec6
|
||||
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||
#define T44 0x04881d05
|
||||
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||
#define T47 0x1fa27cf8
|
||||
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||
#define T50 0x432aff97
|
||||
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||
#define T53 0x655b59c3
|
||||
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
||||
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
||||
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
||||
#define T57 0x6fa87e4f
|
||||
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||
#define T60 0x4e0811a1
|
||||
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
|
||||
static void
|
||||
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
||||
{
|
||||
md5_word_t
|
||||
a = pms->abcd[0], b = pms->abcd[1],
|
||||
c = pms->abcd[2], d = pms->abcd[3];
|
||||
md5_word_t t;
|
||||
#if BYTE_ORDER > 0
|
||||
/* Define storage only for big-endian CPUs. */
|
||||
md5_word_t X[16];
|
||||
#else
|
||||
/* Define storage for little-endian or both types of CPUs. */
|
||||
md5_word_t xbuf[16];
|
||||
const md5_word_t *X;
|
||||
#endif
|
||||
|
||||
{
|
||||
#if BYTE_ORDER == 0
|
||||
/*
|
||||
* Determine dynamically whether this is a big-endian or
|
||||
* little-endian machine, since we can use a more efficient
|
||||
* algorithm on the latter.
|
||||
*/
|
||||
static const int w = 1;
|
||||
|
||||
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER <= 0 /* little-endian */
|
||||
{
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!((data - (const md5_byte_t *)0) & 3)) {
|
||||
/* data are properly aligned */
|
||||
X = (const md5_word_t *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if BYTE_ORDER == 0
|
||||
else /* dynamic big-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER >= 0 /* big-endian */
|
||||
{
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const md5_byte_t *xp = data;
|
||||
int i;
|
||||
|
||||
# if BYTE_ORDER == 0
|
||||
X = xbuf; /* (dynamic only) */
|
||||
# else
|
||||
# define xbuf X /* (static only) */
|
||||
# endif
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + F(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + G(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + H(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + I(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
#undef SET
|
||||
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
pms->abcd[0] += a;
|
||||
pms->abcd[1] += b;
|
||||
pms->abcd[2] += c;
|
||||
pms->abcd[3] += d;
|
||||
}
|
||||
|
||||
void
|
||||
md5_init(md5_state_t *pms)
|
||||
{
|
||||
pms->count[0] = pms->count[1] = 0;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void
|
||||
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
|
||||
{
|
||||
const md5_byte_t *p = data;
|
||||
int left = nbytes;
|
||||
int offset = (pms->count[0] >> 3) & 63;
|
||||
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
pms->count[1] += nbytes >> 29;
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset) {
|
||||
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
|
||||
memcpy(pms->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(pms, pms->buf);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
void
|
||||
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
|
||||
{
|
||||
static const md5_byte_t pad[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
md5_byte_t data[8];
|
||||
int i;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
md5_append(pms, data, 8);
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
|
||||
}
|
||||
176
dep/src/g3dlite/Cylinder.cpp
Normal file
176
dep/src/g3dlite/Cylinder.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/**
|
||||
@file Cylinder.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-02-07
|
||||
@edited 2006-02-18
|
||||
|
||||
Copyright 2000-2006, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Cylinder.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/LineSegment.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Line.h"
|
||||
#include "G3D/AABox.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Cylinder::Cylinder(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
Cylinder::Cylinder() {
|
||||
}
|
||||
|
||||
|
||||
Cylinder::Cylinder(const Vector3& _p1, const Vector3& _p2, float _r)
|
||||
: p1(_p1), p2(_p2), mRadius(_r) {
|
||||
}
|
||||
|
||||
|
||||
void Cylinder::serialize(class BinaryOutput& b) const {
|
||||
p1.serialize(b);
|
||||
p2.serialize(b);
|
||||
b.writeFloat64(mRadius);
|
||||
}
|
||||
|
||||
|
||||
void Cylinder::deserialize(class BinaryInput& b) {
|
||||
p1.deserialize(b);
|
||||
p2.deserialize(b);
|
||||
mRadius = b.readFloat64();
|
||||
}
|
||||
|
||||
|
||||
Line Cylinder::axis() const {
|
||||
return Line::fromTwoPoints(p1, p2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
float Cylinder::radius() const {
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
|
||||
float Cylinder::volume() const {
|
||||
return
|
||||
(float)pi() * square(mRadius) * (p1 - p2).magnitude();
|
||||
}
|
||||
|
||||
|
||||
float Cylinder::area() const {
|
||||
return
|
||||
// Sides
|
||||
(twoPi() * mRadius) * height() +
|
||||
|
||||
// Caps
|
||||
twoPi() * square(mRadius);
|
||||
}
|
||||
|
||||
void Cylinder::getBounds(AABox& out) const {
|
||||
Vector3 min = p1.min(p2) - (Vector3(1, 1, 1) * mRadius);
|
||||
Vector3 max = p1.max(p2) + (Vector3(1, 1, 1) * mRadius);
|
||||
out = AABox(min, max);
|
||||
}
|
||||
|
||||
bool Cylinder::contains(const Vector3& p) const {
|
||||
return LineSegment::fromTwoPoints(p1, p2).distanceSquared(p) <= square(mRadius);
|
||||
}
|
||||
|
||||
|
||||
void Cylinder::getReferenceFrame(CoordinateFrame& cframe) const {
|
||||
cframe.translation = center();
|
||||
|
||||
Vector3 Y = (p1 - p2).direction();
|
||||
Vector3 X = (abs(Y.dot(Vector3::unitX())) > 0.9) ? Vector3::unitY() : Vector3::unitX();
|
||||
Vector3 Z = X.cross(Y).direction();
|
||||
X = Y.cross(Z);
|
||||
cframe.rotation.setColumn(0, X);
|
||||
cframe.rotation.setColumn(1, Y);
|
||||
cframe.rotation.setColumn(2, Z);
|
||||
}
|
||||
|
||||
|
||||
void Cylinder::getRandomSurfacePoint(Vector3& p, Vector3& N) const {
|
||||
float h = height();
|
||||
float r = radius();
|
||||
|
||||
// Create a random point on a standard cylinder and then rotate to the global frame.
|
||||
|
||||
// Relative areas (factor of 2PI already taken out)
|
||||
float capRelArea = square(r) / 2.0f;
|
||||
float sideRelArea = r * h;
|
||||
|
||||
float r1 = uniformRandom(0, capRelArea * 2 + sideRelArea);
|
||||
|
||||
if (r1 < capRelArea * 2) {
|
||||
|
||||
// Select a point uniformly at random on a disk
|
||||
// @cite http://mathworld.wolfram.com/DiskPointPicking.html
|
||||
float a = uniformRandom(0, (float)twoPi());
|
||||
float r2 = sqrt(uniformRandom(0, 1)) * r;
|
||||
p.x = cos(a) * r2;
|
||||
p.z = sin(a) * r2;
|
||||
|
||||
N.x = 0;
|
||||
N.z = 0;
|
||||
if (r1 < capRelArea) {
|
||||
// Top
|
||||
p.y = h / 2.0f;
|
||||
N.y = 1;
|
||||
} else {
|
||||
// Bottom
|
||||
p.y = -h / 2.0f;
|
||||
N.y = -1;
|
||||
}
|
||||
} else {
|
||||
// Side
|
||||
float a = uniformRandom(0, (float)twoPi());
|
||||
N.x = cos(a);
|
||||
N.y = 0;
|
||||
N.z = sin(a);
|
||||
p.x = N.x * r;
|
||||
p.z = N.y * r;
|
||||
p.y = uniformRandom(-h / 2.0f, h / 2.0f);
|
||||
}
|
||||
|
||||
// Transform to world space
|
||||
CoordinateFrame cframe;
|
||||
getReferenceFrame(cframe);
|
||||
|
||||
p = cframe.pointToWorldSpace(p);
|
||||
N = cframe.normalToWorldSpace(N);
|
||||
}
|
||||
|
||||
|
||||
Vector3 Cylinder::randomInteriorPoint() const {
|
||||
float h = height();
|
||||
float r = radius();
|
||||
|
||||
// Create a random point in a standard cylinder and then rotate to the global frame.
|
||||
|
||||
// Select a point uniformly at random on a disk
|
||||
// @cite http://mathworld.wolfram.com/DiskPointPicking.html
|
||||
float a = uniformRandom(0, (float)twoPi());
|
||||
float r2 = sqrt(uniformRandom(0, 1)) * r;
|
||||
|
||||
Vector3 p( cos(a) * r2,
|
||||
uniformRandom(-h / 2.0f, h / 2.0f),
|
||||
sin(a) * r2);
|
||||
|
||||
// Transform to world space
|
||||
CoordinateFrame cframe;
|
||||
getReferenceFrame(cframe);
|
||||
|
||||
return cframe.pointToWorldSpace(p);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
502
dep/src/g3dlite/GCamera.cpp
Normal file
502
dep/src/g3dlite/GCamera.cpp
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
/**
|
||||
@file GCamera.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@author Jeff Marsceill, 08jcm@williams.edu
|
||||
|
||||
@created 2005-07-20
|
||||
@edited 2009-11-24
|
||||
*/
|
||||
#include "G3D/GCamera.h"
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Rect2D.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Ray.h"
|
||||
#include "G3D/Matrix4.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
GCamera::GCamera(const Any& any) {
|
||||
any.verifyName("GCamera");
|
||||
any.verifyType(Any::TABLE);
|
||||
*this = GCamera();
|
||||
|
||||
const Any::AnyTable& table = any.table();
|
||||
Any::AnyTable::Iterator it = table.begin();
|
||||
while (it.hasMore()) {
|
||||
const std::string& k = toUpper(it->key);
|
||||
if (k == "FOVDIRECTION") {
|
||||
const std::string& v = toUpper(it->value);
|
||||
if (v == "HORIZONTAL") {
|
||||
m_direction = HORIZONTAL;
|
||||
} else if (v == "VERTICAL") {
|
||||
m_direction = VERTICAL;
|
||||
} else {
|
||||
any.verify(false, "fovDirection must be \"HORIZONTAL\" or \"VERTICAL\"");
|
||||
}
|
||||
} else if (k == "COORDINATEFRAME") {
|
||||
m_cframe = it->value;
|
||||
} else if (k == "FOVDEGREES") {
|
||||
m_fieldOfView = toRadians(it->value.number());
|
||||
} else if (k == "NEARPLANEZ") {
|
||||
m_nearPlaneZ = it->value;
|
||||
} else if (k == "FARPLANEZ") {
|
||||
m_farPlaneZ = it->value;
|
||||
} else {
|
||||
any.verify(false, std::string("Illegal key in table: ") + it->key);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GCamera::operator Any() const {
|
||||
Any any(Any::TABLE, "GCamera");
|
||||
|
||||
any.set("fovDirection", std::string((m_direction == HORIZONTAL) ? "HORIZONTAL" : "VERTICAL"));
|
||||
any.set("fovDegrees", toDegrees(m_fieldOfView));
|
||||
any.set("nearPlaneZ", nearPlaneZ());
|
||||
any.set("farPlaneZ", farPlaneZ());
|
||||
any.set("coordinateFrame", coordinateFrame());
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
GCamera::GCamera() {
|
||||
setNearPlaneZ(-0.2f);
|
||||
setFarPlaneZ(-100.0f);
|
||||
setFieldOfView((float)toRadians(90.0f), HORIZONTAL);
|
||||
}
|
||||
|
||||
|
||||
GCamera::GCamera(const Matrix4& proj, const CFrame& frame) {
|
||||
float left, right, bottom, top, nearval, farval;
|
||||
proj.getPerspectiveProjectionParameters(left, right, bottom, top, nearval, farval);
|
||||
setNearPlaneZ(-nearval);
|
||||
setFarPlaneZ(-farval);
|
||||
float x = right;
|
||||
|
||||
// Assume horizontal field of view
|
||||
setFieldOfView(atan2(x, -m_nearPlaneZ) * 2.0f, HORIZONTAL);
|
||||
setCoordinateFrame(frame);
|
||||
}
|
||||
|
||||
|
||||
GCamera::~GCamera() {
|
||||
}
|
||||
|
||||
|
||||
void GCamera::getCoordinateFrame(CoordinateFrame& c) const {
|
||||
c = m_cframe;
|
||||
}
|
||||
|
||||
|
||||
void GCamera::setCoordinateFrame(const CoordinateFrame& c) {
|
||||
m_cframe = c;
|
||||
}
|
||||
|
||||
|
||||
void GCamera::setFieldOfView(float angle, FOVDirection dir) {
|
||||
debugAssert((angle < pi()) && (angle > 0));
|
||||
|
||||
m_fieldOfView = angle;
|
||||
m_direction = dir;
|
||||
}
|
||||
|
||||
|
||||
float GCamera::imagePlaneDepth() const{
|
||||
return -m_nearPlaneZ;
|
||||
}
|
||||
|
||||
float GCamera::viewportWidth(const Rect2D& viewport) const {
|
||||
// Compute the side of a square at the near plane based on our field of view
|
||||
float s = 2.0f * -m_nearPlaneZ * tan(m_fieldOfView * 0.5f);
|
||||
|
||||
if (m_direction == VERTICAL) {
|
||||
s *= viewport.width() / viewport.height();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
float GCamera::viewportHeight(const Rect2D& viewport) const {
|
||||
// Compute the side of a square at the near plane based on our field of view
|
||||
float s = 2.0f * -m_nearPlaneZ * tan(m_fieldOfView * 0.5f);
|
||||
|
||||
debugAssert(m_fieldOfView < toRadians(180));
|
||||
if (m_direction == HORIZONTAL) {
|
||||
s *= viewport.height() / viewport.width();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Ray GCamera::worldRay(float x, float y, const Rect2D& viewport) const {
|
||||
|
||||
int screenWidth = iFloor(viewport.width());
|
||||
int screenHeight = iFloor(viewport.height());
|
||||
|
||||
Vector3 origin = m_cframe.translation;
|
||||
|
||||
float cx = screenWidth / 2.0f;
|
||||
float cy = screenHeight / 2.0f;
|
||||
|
||||
float vw = viewportWidth(viewport);
|
||||
float vh = viewportHeight(viewport);
|
||||
|
||||
Vector3 direction = Vector3( (x - cx) * vw / screenWidth,
|
||||
-(y - cy) * vh / screenHeight,
|
||||
m_nearPlaneZ);
|
||||
|
||||
direction = m_cframe.vectorToWorldSpace(direction);
|
||||
|
||||
// Normalize the direction (we didn't do it before)
|
||||
direction = direction.direction();
|
||||
|
||||
return Ray::fromOriginAndDirection(origin, direction);
|
||||
}
|
||||
|
||||
|
||||
void GCamera::getProjectPixelMatrix(const Rect2D& viewport, Matrix4& P) const {
|
||||
getProjectUnitMatrix(viewport, P);
|
||||
float screenWidth = viewport.width();
|
||||
float screenHeight = viewport.height();
|
||||
|
||||
float sx = screenWidth / 2.0;
|
||||
float sy = screenHeight / 2.0;
|
||||
|
||||
P = Matrix4(sx, 0, 0, sx + viewport.x0(),
|
||||
0, -sy, 0, sy + viewport.y0(),
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1) * P;
|
||||
}
|
||||
|
||||
|
||||
void GCamera::getProjectUnitMatrix(const Rect2D& viewport, Matrix4& P) const {
|
||||
|
||||
float screenWidth = viewport.width();
|
||||
float screenHeight = viewport.height();
|
||||
|
||||
float r, l, t, b, n, f, x, y;
|
||||
|
||||
if (m_direction == VERTICAL) {
|
||||
y = -m_nearPlaneZ * tan(m_fieldOfView / 2);
|
||||
x = y * (screenWidth / screenHeight);
|
||||
} else { //m_direction == HORIZONTAL
|
||||
x = -m_nearPlaneZ * tan(m_fieldOfView / 2);
|
||||
y = x * (screenHeight / screenWidth);
|
||||
}
|
||||
|
||||
n = -m_nearPlaneZ;
|
||||
f = -m_farPlaneZ;
|
||||
r = x;
|
||||
l = -x;
|
||||
t = y;
|
||||
b = -y;
|
||||
|
||||
P = Matrix4::perspectiveProjection(l, r, b, t, n, f);
|
||||
}
|
||||
|
||||
Vector3 GCamera::projectUnit(const Vector3& point, const Rect2D& viewport) const {
|
||||
Matrix4 M;
|
||||
getProjectUnitMatrix(viewport, M);
|
||||
|
||||
Vector4 cameraSpacePoint(coordinateFrame().pointToObjectSpace(point), 1.0f);
|
||||
const Vector4& screenSpacePoint = M * cameraSpacePoint;
|
||||
|
||||
return Vector3(screenSpacePoint.xyz() / screenSpacePoint.w);
|
||||
}
|
||||
|
||||
Vector3 GCamera::project(const Vector3& point,
|
||||
const Rect2D& viewport) const {
|
||||
|
||||
// Find the point in the homogeneous cube
|
||||
const Vector3& cube = projectUnit(point, viewport);
|
||||
|
||||
return convertFromUnitToNormal(cube, viewport);
|
||||
}
|
||||
|
||||
Vector3 GCamera::unprojectUnit(const Vector3& v, const Rect2D& viewport) const {
|
||||
|
||||
const Vector3& projectedPoint = convertFromUnitToNormal(v, viewport);
|
||||
|
||||
return unproject(projectedPoint, viewport);
|
||||
}
|
||||
|
||||
|
||||
Vector3 GCamera::unproject(const Vector3& v, const Rect2D& viewport) const {
|
||||
|
||||
const float n = m_nearPlaneZ;
|
||||
const float f = m_farPlaneZ;
|
||||
|
||||
float z;
|
||||
|
||||
if (-f >= finf()) {
|
||||
// Infinite far plane
|
||||
z = 1.0f / (((-1.0f / n) * v.z) + 1.0f / n);
|
||||
} else {
|
||||
z = 1.0f / ((((1.0f / f) - (1.0f / n)) * v.z) + 1.0f / n);
|
||||
}
|
||||
|
||||
const Ray& ray = worldRay(v.x, v.y, viewport);
|
||||
|
||||
// Find out where the ray reaches the specified depth.
|
||||
const Vector3& out = ray.origin() + ray.direction() * -z / (ray.direction().dot(m_cframe.lookVector()));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
float GCamera::worldToScreenSpaceArea(float area, float z, const Rect2D& viewport) const {
|
||||
(void)viewport;
|
||||
if (z >= 0) {
|
||||
return finf();
|
||||
}
|
||||
return area * (float)square(imagePlaneDepth() / z);
|
||||
}
|
||||
|
||||
|
||||
void GCamera::getClipPlanes(
|
||||
const Rect2D& viewport,
|
||||
Array<Plane>& clip) const {
|
||||
|
||||
Frustum fr;
|
||||
frustum(viewport, fr);
|
||||
clip.resize(fr.faceArray.size(), DONT_SHRINK_UNDERLYING_ARRAY);
|
||||
for (int f = 0; f < clip.size(); ++f) {
|
||||
clip[f] = fr.faceArray[f].plane;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GCamera::Frustum GCamera::frustum(const Rect2D& viewport) const {
|
||||
Frustum f;
|
||||
frustum(viewport, f);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
void GCamera::frustum(const Rect2D& viewport, Frustum& fr) const {
|
||||
|
||||
// The volume is the convex hull of the vertices definining the view
|
||||
// frustum and the light source point at infinity.
|
||||
|
||||
const float x = viewportWidth(viewport) / 2;
|
||||
const float y = viewportHeight(viewport) / 2;
|
||||
const float zn = m_nearPlaneZ;
|
||||
const float zf = m_farPlaneZ;
|
||||
float xx, zz, yy;
|
||||
|
||||
float halfFOV = m_fieldOfView * 0.5f;
|
||||
|
||||
// This computes the normal, which is based on the complement of the
|
||||
// halfFOV angle, so the equations are "backwards"
|
||||
if (m_direction == VERTICAL) {
|
||||
yy = -cosf(halfFOV);
|
||||
xx = yy * viewport.height() / viewport.width();
|
||||
zz = -sinf(halfFOV);
|
||||
} else {
|
||||
xx = -cosf(halfFOV);
|
||||
yy = xx * viewport.width() / viewport.height();
|
||||
zz = -sinf(halfFOV);
|
||||
}
|
||||
|
||||
// Near face (ccw from UR)
|
||||
fr.vertexPos.append(
|
||||
Vector4( x, y, zn, 1),
|
||||
Vector4(-x, y, zn, 1),
|
||||
Vector4(-x, -y, zn, 1),
|
||||
Vector4( x, -y, zn, 1));
|
||||
|
||||
// Far face (ccw from UR, from origin)
|
||||
if (m_farPlaneZ == -finf()) {
|
||||
fr.vertexPos.append(Vector4( x, y, zn, 0),
|
||||
Vector4(-x, y, zn, 0),
|
||||
Vector4(-x, -y, zn, 0),
|
||||
Vector4( x, -y, zn, 0));
|
||||
} else {
|
||||
// Finite
|
||||
const float s = zf / zn;
|
||||
fr.vertexPos.append(Vector4( x * s, y * s, zf, 1),
|
||||
Vector4(-x * s, y * s, zf, 1),
|
||||
Vector4(-x * s, -y * s, zf, 1),
|
||||
Vector4( x * s, -y * s, zf, 1));
|
||||
}
|
||||
|
||||
Frustum::Face face;
|
||||
|
||||
// Near plane (wind backwards so normal faces into frustum)
|
||||
// Recall that nearPlane, farPlane are positive numbers, so
|
||||
// we need to negate them to produce actual z values.
|
||||
face.plane = Plane(Vector3(0,0,-1), Vector3(0,0,m_nearPlaneZ));
|
||||
face.vertexIndex[0] = 3;
|
||||
face.vertexIndex[1] = 2;
|
||||
face.vertexIndex[2] = 1;
|
||||
face.vertexIndex[3] = 0;
|
||||
fr.faceArray.append(face);
|
||||
|
||||
// Right plane
|
||||
face.plane = Plane(Vector3(xx, 0, zz), Vector3::zero());
|
||||
face.vertexIndex[0] = 0;
|
||||
face.vertexIndex[1] = 4;
|
||||
face.vertexIndex[2] = 7;
|
||||
face.vertexIndex[3] = 3;
|
||||
fr.faceArray.append(face);
|
||||
|
||||
// Left plane
|
||||
face.plane = Plane(Vector3(-fr.faceArray.last().plane.normal().x, 0, fr.faceArray.last().plane.normal().z), Vector3::zero());
|
||||
face.vertexIndex[0] = 5;
|
||||
face.vertexIndex[1] = 1;
|
||||
face.vertexIndex[2] = 2;
|
||||
face.vertexIndex[3] = 6;
|
||||
fr.faceArray.append(face);
|
||||
|
||||
// Top plane
|
||||
face.plane = Plane(Vector3(0, yy, zz), Vector3::zero());
|
||||
face.vertexIndex[0] = 1;
|
||||
face.vertexIndex[1] = 5;
|
||||
face.vertexIndex[2] = 4;
|
||||
face.vertexIndex[3] = 0;
|
||||
fr.faceArray.append(face);
|
||||
|
||||
// Bottom plane
|
||||
face.plane = Plane(Vector3(0, -fr.faceArray.last().plane.normal().y, fr.faceArray.last().plane.normal().z), Vector3::zero());
|
||||
face.vertexIndex[0] = 2;
|
||||
face.vertexIndex[1] = 3;
|
||||
face.vertexIndex[2] = 7;
|
||||
face.vertexIndex[3] = 6;
|
||||
fr.faceArray.append(face);
|
||||
|
||||
// Far plane
|
||||
if (-m_farPlaneZ < finf()) {
|
||||
face.plane = Plane(Vector3(0, 0, 1), Vector3(0, 0, m_farPlaneZ));
|
||||
face.vertexIndex[0] = 4;
|
||||
face.vertexIndex[1] = 5;
|
||||
face.vertexIndex[2] = 6;
|
||||
face.vertexIndex[3] = 7;
|
||||
fr.faceArray.append(face);
|
||||
}
|
||||
|
||||
// Transform vertices to world space
|
||||
for (int v = 0; v < fr.vertexPos.size(); ++v) {
|
||||
fr.vertexPos[v] = m_cframe.toWorldSpace(fr.vertexPos[v]);
|
||||
}
|
||||
|
||||
// Transform planes to world space
|
||||
for (int p = 0; p < fr.faceArray.size(); ++p) {
|
||||
// Since there is no scale factor, we don't have to
|
||||
// worry about the inverse transpose of the normal.
|
||||
Vector3 normal;
|
||||
float d;
|
||||
|
||||
fr.faceArray[p].plane.getEquation(normal, d);
|
||||
|
||||
Vector3 newNormal = m_cframe.rotation * normal;
|
||||
|
||||
if (isFinite(d)) {
|
||||
d = (newNormal * -d + m_cframe.translation).dot(newNormal);
|
||||
fr.faceArray[p].plane = Plane(newNormal, newNormal * d);
|
||||
} else {
|
||||
// When d is infinite, we can't multiply 0's by it without
|
||||
// generating NaNs.
|
||||
fr.faceArray[p].plane = Plane::fromEquation(newNormal.x, newNormal.y, newNormal.z, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GCamera::getNearViewportCorners
|
||||
(const Rect2D& viewport,
|
||||
Vector3& outUR,
|
||||
Vector3& outUL,
|
||||
Vector3& outLL,
|
||||
Vector3& outLR) const {
|
||||
|
||||
// Must be kept in sync with getFrustum()
|
||||
const float w = viewportWidth(viewport) / 2.0f;
|
||||
const float h = viewportHeight(viewport) / 2.0f;
|
||||
const float z = nearPlaneZ();
|
||||
|
||||
// Compute the points
|
||||
outUR = Vector3( w, h, z);
|
||||
outUL = Vector3(-w, h, z);
|
||||
outLL = Vector3(-w, -h, z);
|
||||
outLR = Vector3( w, -h, z);
|
||||
|
||||
// Take to world space
|
||||
outUR = m_cframe.pointToWorldSpace(outUR);
|
||||
outUL = m_cframe.pointToWorldSpace(outUL);
|
||||
outLR = m_cframe.pointToWorldSpace(outLR);
|
||||
outLL = m_cframe.pointToWorldSpace(outLL);
|
||||
}
|
||||
|
||||
void GCamera::getFarViewportCorners(
|
||||
const Rect2D& viewport,
|
||||
Vector3& outUR,
|
||||
Vector3& outUL,
|
||||
Vector3& outLL,
|
||||
Vector3& outLR) const {
|
||||
|
||||
// Must be kept in sync with getFrustum()
|
||||
const float w = viewportWidth(viewport) * m_farPlaneZ / m_nearPlaneZ;
|
||||
const float h = viewportHeight(viewport) * m_farPlaneZ / m_nearPlaneZ;
|
||||
const float z = m_farPlaneZ;
|
||||
|
||||
// Compute the points
|
||||
outUR = Vector3( w/2, h/2, z);
|
||||
outUL = Vector3(-w/2, h/2, z);
|
||||
outLL = Vector3(-w/2, -h/2, z);
|
||||
outLR = Vector3( w/2, -h/2, z);
|
||||
|
||||
// Take to world space
|
||||
outUR = m_cframe.pointToWorldSpace(outUR);
|
||||
outUL = m_cframe.pointToWorldSpace(outUL);
|
||||
outLR = m_cframe.pointToWorldSpace(outLR);
|
||||
outLL = m_cframe.pointToWorldSpace(outLL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GCamera::setPosition(const Vector3& t) {
|
||||
m_cframe.translation = t;
|
||||
}
|
||||
|
||||
|
||||
void GCamera::lookAt(const Vector3& position, const Vector3& up) {
|
||||
m_cframe.lookAt(position, up);
|
||||
}
|
||||
|
||||
|
||||
void GCamera::serialize(BinaryOutput& bo) const {
|
||||
bo.writeFloat32(m_fieldOfView);
|
||||
bo.writeFloat32(imagePlaneDepth());
|
||||
debugAssert(nearPlaneZ() < 0.0f);
|
||||
bo.writeFloat32(nearPlaneZ());
|
||||
debugAssert(farPlaneZ() < 0.0f);
|
||||
bo.writeFloat32(farPlaneZ());
|
||||
m_cframe.serialize(bo);
|
||||
bo.writeInt8(m_direction);
|
||||
}
|
||||
|
||||
|
||||
void GCamera::deserialize(BinaryInput& bi) {
|
||||
m_fieldOfView = bi.readFloat32();
|
||||
m_nearPlaneZ = bi.readFloat32();
|
||||
debugAssert(m_nearPlaneZ < 0.0f);
|
||||
m_farPlaneZ = bi.readFloat32();
|
||||
debugAssert(m_farPlaneZ < 0.0f);
|
||||
m_cframe.deserialize(bi);
|
||||
m_direction = (FOVDirection)bi.readInt8();
|
||||
}
|
||||
|
||||
|
||||
Vector3 GCamera::convertFromUnitToNormal(const Vector3& in, const Rect2D& viewport) const{
|
||||
return (in + Vector3(1,1,1)) * 0.5 * Vector3(viewport.width(), -viewport.height(), 1) +
|
||||
Vector3(viewport.x0(), viewport.y1(), 0);
|
||||
}
|
||||
} // namespace
|
||||
1166
dep/src/g3dlite/GImage.cpp
Normal file
1166
dep/src/g3dlite/GImage.cpp
Normal file
File diff suppressed because it is too large
Load diff
298
dep/src/g3dlite/GImage_bayer.cpp
Normal file
298
dep/src/g3dlite/GImage_bayer.cpp
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
/**
|
||||
@file GImage_bayer.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2006-05-10
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void GImage::BAYER_G8B8_R8G8_to_Quarter_R8G8B8(int width, int height, const uint8* in, uint8* out) {
|
||||
debugAssert(in != out);
|
||||
|
||||
int halfHeight = height / 2;
|
||||
int halfWidth = width / 2;
|
||||
|
||||
int dst_off = 0;
|
||||
for (int y = 0; y < halfHeight; ++y) {
|
||||
for (int x = 0; x < halfWidth; ++x) {
|
||||
// GBRG
|
||||
int src_off = x*2 + y*2*width;
|
||||
out[dst_off] = in[src_off+width]; // red
|
||||
out[dst_off+1] = ((int)in[src_off] + (int)in[src_off+width+1])/2; // green
|
||||
out[dst_off+2] = in[src_off+1]; // blue
|
||||
|
||||
dst_off = dst_off + 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GImage::Quarter_R8G8B8_to_BAYER_G8B8_R8G8(int inWidth, int inHeight, const uint8* in, uint8* out) {
|
||||
// Undo quarter-size Bayer as best we can. This code isn't very efficient, but it
|
||||
// also isn't used very frequently.
|
||||
|
||||
debugAssert(out != in);
|
||||
|
||||
int outWidth = 2 * inWidth;
|
||||
int outHeight = 2 * inHeight;
|
||||
|
||||
for (int y = 0; y < outHeight; ++y) {
|
||||
for (int x = 0; x < outWidth; ++x) {
|
||||
const Color3uint8* inp = ((const Color3uint8*)in) + ((x/2) + (y/2)* inWidth);
|
||||
uint8* outp = out + x + y * outWidth;
|
||||
|
||||
if (isEven(y)) {
|
||||
// GB row
|
||||
if (isEven(x)) {
|
||||
// Green
|
||||
*outp = inp->g;
|
||||
} else {
|
||||
// Blue
|
||||
*outp = inp->b;
|
||||
}
|
||||
} else {
|
||||
// RG row
|
||||
if (isEven(x)) {
|
||||
// Red
|
||||
*outp = inp->r;
|
||||
} else {
|
||||
// Green
|
||||
*outp = inp->g;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Applies a 5x5 filter to monochrome image I (wrapping at the boundaries) */
|
||||
static uint8 applyFilter(
|
||||
const uint8* I,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h,
|
||||
const float filter[5][5]) {
|
||||
|
||||
debugAssert(isEven(w));
|
||||
debugAssert(isEven(h));
|
||||
|
||||
float sum = 0.0f;
|
||||
float denom = 0.0f;
|
||||
|
||||
for (int dy = 0; dy < 5; ++dy) {
|
||||
int offset = ((y + dy + h - 2) % h) * w;
|
||||
|
||||
for (int dx = 0; dx < 5; ++dx) {
|
||||
float f = filter[dy][dx];
|
||||
sum += f * I[((x + dx + w - 2) % w) + offset];
|
||||
denom += f;
|
||||
}
|
||||
}
|
||||
|
||||
return (uint8)iClamp(iRound(sum / denom), 0, 255);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bayer conversions
|
||||
//
|
||||
|
||||
// There are two kinds of rows (GR and BG).
|
||||
// In each row, there are two kinds of pixels (G/R, B/G).
|
||||
// We express the four kinds of INPUT pixels as:
|
||||
// GRG, GRG, BGB, BGG
|
||||
//
|
||||
// There are three kinds of OUTPUT pixels: R, G, B.
|
||||
// Thus there are nominally 12 different I/O combinations,
|
||||
// but several are impulses because needed output at that
|
||||
// location *is* the input (e.g., G_GRG and G_BGG).
|
||||
//
|
||||
// The following 5x5 row-major filters are named as output_input.
|
||||
|
||||
// Green
|
||||
static const float G_GRR[5][5] =
|
||||
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
||||
{ -1.0f, 2.0f, 4.0f, 2.0f, -1.0f},
|
||||
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
|
||||
|
||||
static const float G_BGB[5][5] =
|
||||
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
||||
{ -1.0f, 2.0f, 4.0f, 2.0f, -1.0f},
|
||||
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
|
||||
|
||||
// Red
|
||||
//(the caption in the paper is wrong for this case:
|
||||
// "R row B column really means R row G column"
|
||||
static const float R_GRG[5][5] =
|
||||
{{ 0.0f, 0.0f, 0.5f, 0.0f, 0.0f},
|
||||
{ 0.0f, -1.0f, 0.0f, -1.0f, 0.0f},
|
||||
{ -1.0f, 4.0f, 5.0f, 4.0f, -1.0f},
|
||||
{ 0.0f, -1.0f, 0.0f, -1.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, 0.5f, 0.0f, 0.0f}};
|
||||
|
||||
static const float R_BGG[5][5] =
|
||||
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, -1.0f, 4.0f, -1.0f, 0.0f},
|
||||
{ 0.5f, 0.0f, 5.0f, 0.0f, 0.5f},
|
||||
{ 0.0f, -1.0f, 4.0f, -1.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
|
||||
|
||||
static const float R_BGB[5][5] =
|
||||
{{ 0.0f, 0.0f, -3.0f/2.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 2.0f, 0.0f, 2.0f, 0.0f},
|
||||
{-3.0f/2.0f, 0.0f, 6.0f, 0.0f, -3.0f/2.0f},
|
||||
{ 0.0f, 2.0f, 0.0f, 2.0f, 0.0f},
|
||||
{ 0.0f, 0.0f, -3.0f/2.0f, 0.0f, 0.0f}};
|
||||
|
||||
|
||||
// Blue
|
||||
//(the caption in the paper is wrong for this case:
|
||||
// "B row R column really means B row G column")
|
||||
#define B_BGG R_GRG
|
||||
#define B_GRG R_BGG
|
||||
#define B_GRR R_BGB
|
||||
|
||||
|
||||
void GImage::BAYER_R8G8_G8B8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
|
||||
debugAssert(in != _out);
|
||||
|
||||
Color3uint8* out = (Color3uint8*)_out;
|
||||
|
||||
for (int y = 0; y < h; ++y) {
|
||||
|
||||
// Row beginning in the input array.
|
||||
int offset = y * w;
|
||||
|
||||
// RG row
|
||||
for (int x = 0; x < w; ++x, ++out) {
|
||||
// R pixel
|
||||
{
|
||||
out->r = in[x + offset];
|
||||
out->g = applyFilter(in, x, y, w, h, G_GRR);
|
||||
out->b = applyFilter(in, x, y, w, h, B_GRR);
|
||||
}
|
||||
++x; ++out;
|
||||
|
||||
// G pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_GRG);
|
||||
out->g = in[x + offset];
|
||||
out->b = applyFilter(in, x, y, w, h, B_GRG);
|
||||
}
|
||||
}
|
||||
|
||||
++y;
|
||||
offset += w;
|
||||
|
||||
// GB row
|
||||
for (int x = 0; x < w; ++x, ++out) {
|
||||
// G pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_BGG);
|
||||
out->g = in[x + offset];
|
||||
out->b = applyFilter(in, x, y, w, h, B_BGG);
|
||||
}
|
||||
++x; ++out;
|
||||
|
||||
// B pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_BGB);
|
||||
out->g = applyFilter(in, x, y, w, h, G_BGB);
|
||||
out->b = in[x + offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void swapRedAndBlue(int N, Color3uint8* out) {
|
||||
for (int i = N - 1; i >= 0; --i) {
|
||||
uint8 tmp = out[i].r;
|
||||
out[i].r = out[i].b;
|
||||
out[i].b = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void GImage::BAYER_G8R8_B8G8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
|
||||
// Run the equivalent function for red
|
||||
BAYER_G8B8_R8G8_to_R8G8B8_MHC(w, h, in, _out);
|
||||
|
||||
// Now swap red and blue
|
||||
swapRedAndBlue(w * h, (Color3uint8*)_out);
|
||||
}
|
||||
|
||||
|
||||
void GImage::BAYER_B8G8_G8R8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
|
||||
// Run the equivalent function for red
|
||||
BAYER_R8G8_G8B8_to_R8G8B8_MHC(w, h, in, _out);
|
||||
|
||||
// Now swap red and blue
|
||||
swapRedAndBlue(w * h, (Color3uint8*)_out);
|
||||
}
|
||||
|
||||
|
||||
void GImage::BAYER_G8B8_R8G8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
|
||||
|
||||
debugAssert(in != _out);
|
||||
|
||||
Color3uint8* out = (Color3uint8*)_out;
|
||||
|
||||
for (int y = 0; y < h; ++y) {
|
||||
|
||||
// Row beginning in the input array.
|
||||
int offset = y * w;
|
||||
|
||||
// GB row
|
||||
for (int x = 0; x < w; ++x, ++out) {
|
||||
// G pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_BGG);
|
||||
out->g = in[x + offset];
|
||||
out->b = applyFilter(in, x, y, w, h, B_BGG);
|
||||
}
|
||||
++x; ++out;
|
||||
|
||||
// B pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_BGB);
|
||||
out->g = applyFilter(in, x, y, w, h, G_BGB);
|
||||
out->b = in[x + offset];
|
||||
}
|
||||
}
|
||||
|
||||
++y;
|
||||
offset += w;
|
||||
|
||||
// RG row
|
||||
for (int x = 0; x < w; ++x, ++out) {
|
||||
// R pixel
|
||||
{
|
||||
out->r = in[x + offset];
|
||||
out->g = applyFilter(in, x, y, w, h, G_GRR);
|
||||
out->b = applyFilter(in, x, y, w, h, B_GRR);
|
||||
}
|
||||
++x; ++out;
|
||||
|
||||
// G pixel
|
||||
{
|
||||
out->r = applyFilter(in, x, y, w, h, R_GRG);
|
||||
out->g = in[x + offset];
|
||||
out->b = applyFilter(in, x, y, w, h, B_GRG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#undef B_BGG
|
||||
#undef B_GRG
|
||||
#undef B_GRR
|
||||
|
||||
}
|
||||
717
dep/src/g3dlite/GImage_bmp.cpp
Normal file
717
dep/src/g3dlite/GImage_bmp.cpp
Normal file
|
|
@ -0,0 +1,717 @@
|
|||
/**
|
||||
@file GImage_bmp.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2006-05-10
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Log.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
#ifndef G3D_WIN32
|
||||
/**
|
||||
This is used by the Windows bitmap I/O.
|
||||
*/
|
||||
static const int BI_RGB = 0;
|
||||
#endif
|
||||
|
||||
void GImage::encodeBMP(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
debugAssert(m_channels == 1 || m_channels == 3);
|
||||
out.setEndian(G3D_LITTLE_ENDIAN);
|
||||
|
||||
uint8 red;
|
||||
uint8 green;
|
||||
uint8 blue;
|
||||
int pixelBufferSize = m_width * m_height * 3;
|
||||
int fileHeaderSize = 14;
|
||||
int infoHeaderSize = 40;
|
||||
int BMScanWidth;
|
||||
int BMPadding;
|
||||
|
||||
// First write the BITMAPFILEHEADER
|
||||
//
|
||||
// WORD bfType;
|
||||
// DWORD bfSize;
|
||||
// WORD bfReserved1;
|
||||
// WORD bfReserved2;
|
||||
// DWORD bfOffBits;
|
||||
|
||||
// Type
|
||||
out.writeUInt8('B');
|
||||
out.writeUInt8('M');
|
||||
|
||||
// File size
|
||||
out.writeUInt32(fileHeaderSize + infoHeaderSize + pixelBufferSize);
|
||||
|
||||
// Two reserved fields set to zero
|
||||
out.writeUInt16(0);
|
||||
out.writeUInt16(0);
|
||||
|
||||
// The offset, in bytes, from the BITMAPFILEHEADER structure
|
||||
// to the bitmap bits.
|
||||
out.writeUInt32(infoHeaderSize + fileHeaderSize);
|
||||
|
||||
// Now the BITMAPINFOHEADER
|
||||
//
|
||||
// DWORD biSize;
|
||||
// LONG biWidth;
|
||||
// LONG biHeight;
|
||||
// WORD biPlanes;
|
||||
// WORD biBitCount
|
||||
// DWORD biCompression;
|
||||
// DWORD biSizeImage;
|
||||
// LONG biXPelsPerMeter;
|
||||
// LONG biYPelsPerMeter;
|
||||
// DWORD biClrUsed;
|
||||
// DWORD biClrImportant;
|
||||
|
||||
// Size of the info header
|
||||
out.writeUInt32(infoHeaderSize);
|
||||
|
||||
// Width and height of the image
|
||||
out.writeUInt32(m_width);
|
||||
out.writeUInt32(m_height);
|
||||
|
||||
// Planes ("must be set to 1")
|
||||
out.writeUInt16(1);
|
||||
|
||||
// BitCount and CompressionType
|
||||
out.writeUInt16(24);
|
||||
out.writeUInt32(BI_RGB);
|
||||
|
||||
// Image size ("may be zero for BI_RGB bitmaps")
|
||||
out.writeUInt32(0);
|
||||
|
||||
// biXPelsPerMeter
|
||||
out.writeUInt32(0);
|
||||
// biYPelsPerMeter
|
||||
out.writeUInt32(0);
|
||||
|
||||
// biClrUsed
|
||||
out.writeUInt32(0);
|
||||
|
||||
// biClrImportant
|
||||
out.writeUInt32(0);
|
||||
|
||||
BMScanWidth = m_width * 3;
|
||||
|
||||
if (BMScanWidth & 3) {
|
||||
BMPadding = 4 - (BMScanWidth & 3);
|
||||
} else {
|
||||
BMPadding = 0;
|
||||
}
|
||||
|
||||
int hStart = m_height - 1;
|
||||
int hEnd = -1;
|
||||
int hDir = -1;
|
||||
int dest;
|
||||
|
||||
// Write the pixel data
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
dest = m_channels * h * m_width;
|
||||
for (int w = 0; w < m_width; ++w) {
|
||||
|
||||
if (m_channels == 3) {
|
||||
red = m_byte[dest];
|
||||
green = m_byte[dest + 1];
|
||||
blue = m_byte[dest + 2];
|
||||
} else {
|
||||
red = m_byte[dest];
|
||||
green = m_byte[dest];
|
||||
blue = m_byte[dest];
|
||||
}
|
||||
|
||||
out.writeUInt8(blue);
|
||||
out.writeUInt8(green);
|
||||
out.writeUInt8(red);
|
||||
|
||||
dest += m_channels;
|
||||
}
|
||||
|
||||
if (BMPadding > 0) {
|
||||
out.skip(BMPadding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodeBMP(
|
||||
BinaryInput& input) {
|
||||
|
||||
// The BMP decoding uses these flags.
|
||||
static const uint16 PICTURE_NONE = 0x0000;
|
||||
static const uint16 PICTURE_BITMAP = 0x1000;
|
||||
|
||||
// Compression Flags
|
||||
static const uint16 PICTURE_UNCOMPRESSED = 0x0100;
|
||||
static const uint16 PICTURE_MONOCHROME = 0x0001;
|
||||
static const uint16 PICTURE_4BIT = 0x0002;
|
||||
static const uint16 PICTURE_8BIT = 0x0004;
|
||||
static const uint16 PICTURE_16BIT = 0x0008;
|
||||
static const uint16 PICTURE_24BIT = 0x0010;
|
||||
static const uint16 PICTURE_32BIT = 0x0020;
|
||||
|
||||
(void)PICTURE_16BIT;
|
||||
(void)PICTURE_32BIT;
|
||||
|
||||
// This is a simple BMP loader that can handle uncompressed BMP files.
|
||||
// Verify this is a BMP file by looking for the BM tag.
|
||||
input.reset();
|
||||
std::string tag = input.readString(2);
|
||||
if (tag != "BM") {
|
||||
throw Error("Not a BMP file", input.getFilename());
|
||||
}
|
||||
|
||||
m_channels = 3;
|
||||
// Skip to the BITMAPINFOHEADER's width and height
|
||||
input.skip(16);
|
||||
|
||||
m_width = input.readUInt32();
|
||||
m_height = input.readUInt32();
|
||||
|
||||
// Skip to the bit count and compression type
|
||||
input.skip(2);
|
||||
|
||||
uint16 bitCount = input.readUInt16();
|
||||
uint32 compressionType = input.readUInt32();
|
||||
|
||||
uint8 red;
|
||||
uint8 green;
|
||||
uint8 blue;
|
||||
uint8 blank;
|
||||
|
||||
// Only uncompressed bitmaps are supported by this code
|
||||
if ((int32)compressionType != BI_RGB) {
|
||||
throw Error("BMP images must be uncompressed", input.getFilename());
|
||||
}
|
||||
|
||||
uint8* palette = NULL;
|
||||
|
||||
// Create the palette if needed
|
||||
if (bitCount <= 8) {
|
||||
|
||||
// Skip to the palette color count in the header
|
||||
input.skip(12);
|
||||
|
||||
int numColors = input.readUInt32();
|
||||
|
||||
palette = (uint8*)System::malloc(numColors * 3);
|
||||
debugAssert(palette);
|
||||
|
||||
// Skip past the end of the header to the palette info
|
||||
input.skip(4);
|
||||
|
||||
int c;
|
||||
for(c = 0; c < numColors * 3; c += 3) {
|
||||
// Palette information in bitmaps is stored in BGR_ format.
|
||||
// That means it's blue-green-red-blank, for each entry.
|
||||
blue = input.readUInt8();
|
||||
green = input.readUInt8();
|
||||
red = input.readUInt8();
|
||||
blank = input.readUInt8();
|
||||
|
||||
palette[c] = red;
|
||||
palette[c + 1] = green;
|
||||
palette[c + 2] = blue;
|
||||
}
|
||||
}
|
||||
|
||||
int hStart = 0;
|
||||
int hEnd = 0;
|
||||
int hDir = 0;
|
||||
|
||||
if (m_height < 0) {
|
||||
m_height = -m_height;
|
||||
hStart = 0;
|
||||
hEnd = m_height;
|
||||
hDir = 1;
|
||||
} else {
|
||||
//height = height;
|
||||
hStart = m_height - 1;
|
||||
hEnd = -1;
|
||||
hDir = -1;
|
||||
}
|
||||
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * 3);
|
||||
debugAssert(m_byte);
|
||||
|
||||
int BMScanWidth;
|
||||
int BMPadding;
|
||||
uint8 BMGroup;
|
||||
uint8 BMPixel8;
|
||||
int currPixel;
|
||||
int dest;
|
||||
int flags = PICTURE_NONE;
|
||||
|
||||
if (bitCount == 1) {
|
||||
// Note that this file is not necessarily grayscale, since it's possible
|
||||
// the palette is blue-and-white, or whatever. But of course most image
|
||||
// programs only write 1-bit images if they're black-and-white.
|
||||
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_MONOCHROME;
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
BMScanWidth = (m_width + 7) >> 3;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
// Powers of 2
|
||||
int pow2[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
dest = 3 * h * m_width;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; ++w) {
|
||||
|
||||
BMGroup = input.readUInt8();
|
||||
|
||||
// Now we read the pixels. Usually there are eight pixels per byte,
|
||||
// since each pixel is represented by one bit, but if the width
|
||||
// is not a multiple of eight, the last byte will have some bits
|
||||
// set, with the others just being extra. Plus there's the
|
||||
// dword-alignment padding. So we keep checking to see if we've
|
||||
// already read "width" number of pixels.
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
if (currPixel < m_width) {
|
||||
int src = 3 * ((BMGroup & pow2[i]) >> i);
|
||||
|
||||
m_byte[dest] = palette[src];
|
||||
m_byte[dest + 1] = palette[src + 1];
|
||||
m_byte[dest + 2] = palette[src + 2];
|
||||
|
||||
++currPixel;
|
||||
dest += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitCount == 4) {
|
||||
|
||||
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_4BIT;
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
int BMScanWidth = (m_width + 1) >> 1;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
dest = 3 * h * m_width;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; w++) {
|
||||
|
||||
BMGroup = input.readUInt8();
|
||||
int src[2];
|
||||
src[0] = 3 * ((BMGroup & 0xF0) >> 4);
|
||||
src[1] = 3 * (BMGroup & 0x0F);
|
||||
|
||||
// Now we read the pixels. Usually there are two pixels per byte,
|
||||
// since each pixel is represented by four bits, but if the width
|
||||
// is not a multiple of two, the last byte will have only four bits
|
||||
// set, with the others just being extra. Plus there's the
|
||||
// dword-alignment padding. So we keep checking to see if we've
|
||||
// already read "Width" number of pixels.
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (currPixel < m_width) {
|
||||
int tsrc = src[i];
|
||||
|
||||
m_byte[dest] = palette[tsrc];
|
||||
m_byte[dest + 1] = palette[tsrc + 1];
|
||||
m_byte[dest + 2] = palette[tsrc + 2];
|
||||
|
||||
++currPixel;
|
||||
dest += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitCount == 8) {
|
||||
|
||||
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_8BIT;
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
BMScanWidth = m_width;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; ++w) {
|
||||
|
||||
BMPixel8 = input.readUInt8();
|
||||
|
||||
if (currPixel < m_width) {
|
||||
dest = 3 * ((h * m_width) + currPixel);
|
||||
int src = 3 * BMPixel8;
|
||||
|
||||
m_byte[dest] = palette[src];
|
||||
m_byte[dest + 1] = palette[src + 1];
|
||||
m_byte[dest + 2] = palette[src + 2];
|
||||
|
||||
++currPixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitCount == 16) {
|
||||
|
||||
m_memMan->free(m_byte);
|
||||
m_byte = NULL;
|
||||
System::free(palette);
|
||||
palette = NULL;
|
||||
throw Error("16-bit bitmaps not supported", input.getFilename());
|
||||
|
||||
} else if (bitCount == 24) {
|
||||
input.skip(20);
|
||||
|
||||
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_24BIT;
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
BMScanWidth = m_width * 3;
|
||||
|
||||
if (BMScanWidth & 3) {
|
||||
BMPadding = 4 - (BMScanWidth & 3);
|
||||
} else {
|
||||
BMPadding = 0;
|
||||
}
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
dest = 3 * h * m_width;
|
||||
for (int w = 0; w < m_width; ++w) {
|
||||
|
||||
blue = input.readUInt8();
|
||||
green = input.readUInt8();
|
||||
red = input.readUInt8();
|
||||
|
||||
m_byte[dest] = red;
|
||||
m_byte[dest + 1] = green;
|
||||
m_byte[dest + 2] = blue;
|
||||
|
||||
dest += 3;
|
||||
}
|
||||
|
||||
if (BMPadding) {
|
||||
input.skip(2);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitCount == 32) {
|
||||
|
||||
m_memMan->free(m_byte);
|
||||
m_byte = NULL;
|
||||
System::free(palette);
|
||||
palette = NULL;
|
||||
throw Error("32 bit bitmaps not supported", input.getFilename());
|
||||
|
||||
} else {
|
||||
// We support all possible bit depths, so if the
|
||||
// code gets here, it's not even a real bitmap.
|
||||
m_memMan->free(m_byte);
|
||||
m_byte = NULL;
|
||||
throw Error("Not a bitmap!", input.getFilename());
|
||||
}
|
||||
|
||||
System::free(palette);
|
||||
palette = NULL;
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodeICO(
|
||||
BinaryInput& input) {
|
||||
|
||||
// Header
|
||||
uint16 r = input.readUInt16();
|
||||
debugAssert(r == 0);
|
||||
r = input.readUInt16();
|
||||
debugAssert(r == 1);
|
||||
|
||||
// Read the number of icons, although we'll only load the
|
||||
// first one.
|
||||
int count = input.readUInt16();
|
||||
|
||||
m_channels = 4;
|
||||
|
||||
debugAssert(count > 0);
|
||||
|
||||
const uint8* headerBuffer = input.getCArray() + input.getPosition();
|
||||
int maxWidth = 0, maxHeight = 0;
|
||||
int maxHeaderNum = 0;
|
||||
for (int currentHeader = 0; currentHeader < count; ++currentHeader) {
|
||||
|
||||
const uint8* curHeaderBuffer = headerBuffer + (currentHeader * 16);
|
||||
int tmpWidth = curHeaderBuffer[0];
|
||||
int tmpHeight = curHeaderBuffer[1];
|
||||
// Just in case there is a non-square icon, checking area
|
||||
if ((tmpWidth * tmpHeight) > (maxWidth * maxHeight)) {
|
||||
maxWidth = tmpWidth;
|
||||
maxHeight = tmpHeight;
|
||||
maxHeaderNum = currentHeader;
|
||||
}
|
||||
}
|
||||
|
||||
input.skip(maxHeaderNum * 16);
|
||||
|
||||
m_width = input.readUInt8();
|
||||
m_height = input.readUInt8();
|
||||
int numColors = input.readUInt8();
|
||||
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * m_channels);
|
||||
debugAssert(m_byte);
|
||||
|
||||
// Bit mask for packed bits
|
||||
int mask = 0;
|
||||
|
||||
int bitsPerPixel = 8;
|
||||
|
||||
switch (numColors) {
|
||||
case 2:
|
||||
mask = 0x01;
|
||||
bitsPerPixel = 1;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
mask = 0x0F;
|
||||
bitsPerPixel = 4;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
numColors = 256;
|
||||
mask = 0xFF;
|
||||
bitsPerPixel = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Error("Unsupported ICO color count.", input.getFilename());
|
||||
}
|
||||
|
||||
input.skip(5);
|
||||
// Skip 'size' unused
|
||||
input.skip(4);
|
||||
|
||||
int offset = input.readUInt32();
|
||||
|
||||
// Skip over any other icon descriptions
|
||||
input.setPosition(offset);
|
||||
|
||||
// Skip over bitmap header; it is redundant
|
||||
input.skip(40);
|
||||
|
||||
Array<Color4uint8> palette;
|
||||
palette.resize(numColors, true);
|
||||
for (int c = 0; c < numColors; ++c) {
|
||||
palette[c].b = input.readUInt8();
|
||||
palette[c].g = input.readUInt8();
|
||||
palette[c].r = input.readUInt8();
|
||||
palette[c].a = input.readUInt8();
|
||||
}
|
||||
|
||||
// The actual image and mask follow
|
||||
|
||||
// The XOR Bitmap is stored as 1-bit, 4-bit or 8-bit uncompressed Bitmap
|
||||
// using the same encoding as BMP files. The AND Bitmap is stored in as
|
||||
// 1-bit uncompressed Bitmap.
|
||||
//
|
||||
// Pixels are stored bottom-up, left-to-right. Pixel lines are padded
|
||||
// with zeros to end on a 32bit (4byte) boundary. Every line will have the
|
||||
// same number of bytes. Color indices are zero based, meaning a pixel color
|
||||
// of 0 represents the first color table entry, a pixel color of 255 (if there
|
||||
// are that many) represents the 256th entry.
|
||||
/*
|
||||
int bitsPerRow = width * bitsPerPixel;
|
||||
int bytesPerRow = iCeil((double)bitsPerRow / 8);
|
||||
// Rows are padded to 32-bit boundaries
|
||||
bytesPerRow += bytesPerRow % 4;
|
||||
|
||||
// Read the XOR values into the color channel
|
||||
for (int y = height - 1; y >= 0; --y) {
|
||||
int x = 0;
|
||||
// Read the row
|
||||
for (int i = 0; i < bytesPerRow; ++i) {
|
||||
uint8 byte = input.readUInt8();
|
||||
for (int j = 0; (j < 8) && (x < width); ++x, j += bitsPerPixel) {
|
||||
int bit = ((byte << j) >> (8 - bitsPerPixel)) & mask;
|
||||
pixel4(x, y) = colorTable[bit];
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
int hStart = 0;
|
||||
int hEnd = 0;
|
||||
int hDir = 0;
|
||||
|
||||
if (m_height < 0) {
|
||||
m_height = -m_height;
|
||||
hStart = 0;
|
||||
hEnd = m_height;
|
||||
hDir = 1;
|
||||
} else {
|
||||
//height = height;
|
||||
hStart = m_height - 1;
|
||||
hEnd = -1;
|
||||
hDir = -1;
|
||||
}
|
||||
|
||||
int BMScanWidth;
|
||||
uint8 BMGroup;
|
||||
uint8 BMPixel8;
|
||||
int currPixel;
|
||||
int dest;
|
||||
|
||||
if (bitsPerPixel == 1) {
|
||||
// Note that this file is not necessarily grayscale, since it's possible
|
||||
// the palette is blue-and-white, or whatever. But of course most image
|
||||
// programs only write 1-bit images if they're black-and-white.
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
BMScanWidth = (m_width + 7) >> 3;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
// Powers of 2
|
||||
int pow2[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
dest = 3 * h * m_width;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; ++w) {
|
||||
|
||||
BMGroup = input.readUInt8();
|
||||
|
||||
// Now we read the pixels. Usually there are eight pixels per byte,
|
||||
// since each pixel is represented by one bit, but if the width
|
||||
// is not a multiple of eight, the last byte will have some bits
|
||||
// set, with the others just being extra. Plus there's the
|
||||
// dword-alignment padding. So we keep checking to see if we've
|
||||
// already read "width" number of pixels.
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
if (currPixel < m_width) {
|
||||
int src = ((BMGroup & pow2[i]) >> i);
|
||||
|
||||
m_byte[dest] = palette[src].r;
|
||||
m_byte[dest + 1] = palette[src].g;
|
||||
m_byte[dest + 2] = palette[src].b;
|
||||
|
||||
++currPixel;
|
||||
dest += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitsPerPixel == 4) {
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
int BMScanWidth = (m_width + 1) >> 1;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
dest = 4 * h * m_width;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; w++) {
|
||||
|
||||
BMGroup = input.readUInt8();
|
||||
int src[2];
|
||||
src[0] = ((BMGroup & 0xF0) >> 4);
|
||||
src[1] = (BMGroup & 0x0F);
|
||||
|
||||
// Now we read the pixels. Usually there are two pixels per byte,
|
||||
// since each pixel is represented by four bits, but if the width
|
||||
// is not a multiple of two, the last byte will have only four bits
|
||||
// set, with the others just being extra. Plus there's the
|
||||
// dword-alignment padding. So we keep checking to see if we've
|
||||
// already read "Width" number of pixels.
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (currPixel < m_width) {
|
||||
int tsrc = src[i];
|
||||
|
||||
m_byte[dest] = palette[tsrc].r;
|
||||
m_byte[dest + 1] = palette[tsrc].g;
|
||||
m_byte[dest + 2] = palette[tsrc].b;
|
||||
|
||||
++currPixel;
|
||||
dest += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (bitsPerPixel == 8) {
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
BMScanWidth = m_width;
|
||||
if (BMScanWidth & 3) {
|
||||
BMScanWidth += 4 - (BMScanWidth & 3);
|
||||
}
|
||||
|
||||
for (int h = hStart; h != hEnd; h += hDir) {
|
||||
|
||||
currPixel = 0;
|
||||
|
||||
for (int w = 0; w < BMScanWidth; ++w) {
|
||||
|
||||
BMPixel8 = input.readUInt8();
|
||||
|
||||
if (currPixel < m_width) {
|
||||
dest = 4 * ((h * m_width) + currPixel);
|
||||
int src = BMPixel8;
|
||||
|
||||
m_byte[dest] = palette[src].r;
|
||||
m_byte[dest + 1] = palette[src].g;
|
||||
m_byte[dest + 2] = palette[src].b;
|
||||
|
||||
++currPixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read the mask into the alpha channel
|
||||
int bitsPerRow = m_width;
|
||||
int bytesPerRow = iCeil((double)bitsPerRow / 8);
|
||||
|
||||
// For bitmaps, each scanline is dword-aligned.
|
||||
//BMScanWidth = (width + 1) >> 1;
|
||||
if (bytesPerRow & 3) {
|
||||
bytesPerRow += 4 - (bytesPerRow & 3);
|
||||
}
|
||||
|
||||
for (int y = m_height - 1; y >= 0; --y) {
|
||||
int x = 0;
|
||||
// Read the row
|
||||
for (int i = 0; i < bytesPerRow; ++i) {
|
||||
uint8 byte = input.readUInt8();
|
||||
for (int j = 0; (j < 8) && (x < m_width); ++x, ++j) {
|
||||
int bit = (byte >> (7 - j)) & 0x01;
|
||||
pixel4(x, y).a = (1 - bit) * 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
446
dep/src/g3dlite/GImage_jpeg.cpp
Normal file
446
dep/src/g3dlite/GImage_jpeg.cpp
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
/**
|
||||
@file GImage_jpeg.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2009-04-20
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
#ifdef G3D_LINUX
|
||||
# include <jconfig.h>
|
||||
# include <jpeglib.h>
|
||||
#else
|
||||
# include "jconfig.h"
|
||||
# include "jpeglib.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
const int jpegQuality = 96;
|
||||
|
||||
/**
|
||||
The IJG library needs special setup for compress/decompressing
|
||||
from memory. These classes provide them.
|
||||
|
||||
The format of this class is defined by the IJG library; do not
|
||||
change it.
|
||||
*/
|
||||
class memory_destination_mgr {
|
||||
public:
|
||||
struct jpeg_destination_mgr pub;
|
||||
JOCTET* buffer;
|
||||
int size;
|
||||
int count;
|
||||
};
|
||||
|
||||
typedef memory_destination_mgr* mem_dest_ptr;
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void init_destination (
|
||||
j_compress_ptr cinfo) {
|
||||
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = dest->size;
|
||||
dest->count=0;
|
||||
}
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static boolean empty_output_buffer (
|
||||
j_compress_ptr cinfo) {
|
||||
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = dest->size;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void term_destination (
|
||||
j_compress_ptr cinfo) {
|
||||
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
dest->count = dest->size - dest->pub.free_in_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void jpeg_memory_dest (
|
||||
j_compress_ptr cinfo,
|
||||
JOCTET* buffer,
|
||||
int size) {
|
||||
|
||||
mem_dest_ptr dest;
|
||||
|
||||
if (cinfo->dest == NULL) {
|
||||
// First time for this JPEG object; call the
|
||||
// IJG allocator to get space.
|
||||
cinfo->dest = (struct jpeg_destination_mgr*)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
|
||||
JPOOL_PERMANENT,
|
||||
sizeof(memory_destination_mgr));
|
||||
}
|
||||
|
||||
dest = (mem_dest_ptr) cinfo->dest;
|
||||
dest->size = size;
|
||||
dest->buffer = buffer;
|
||||
dest->pub.init_destination = init_destination;
|
||||
dest->pub.empty_output_buffer = empty_output_buffer;
|
||||
dest->pub.term_destination = term_destination;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define INPUT_BUF_SIZE 4096
|
||||
|
||||
/**
|
||||
Structure dictated by IJG.
|
||||
*/
|
||||
class memory_source_mgr {
|
||||
public:
|
||||
struct jpeg_source_mgr pub;
|
||||
int source_size;
|
||||
unsigned char* source_data;
|
||||
boolean start_of_data;
|
||||
JOCTET* buffer;
|
||||
};
|
||||
|
||||
|
||||
typedef memory_source_mgr* mem_src_ptr;
|
||||
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void init_source(
|
||||
j_decompress_ptr cinfo) {
|
||||
|
||||
mem_src_ptr src = (mem_src_ptr) cinfo->src;
|
||||
|
||||
src->start_of_data = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static boolean fill_input_buffer(
|
||||
j_decompress_ptr cinfo) {
|
||||
|
||||
mem_src_ptr src = (mem_src_ptr) cinfo->src;
|
||||
|
||||
size_t bytes_read = 0;
|
||||
|
||||
if (src->source_size > INPUT_BUF_SIZE)
|
||||
bytes_read = INPUT_BUF_SIZE;
|
||||
else
|
||||
bytes_read = src->source_size;
|
||||
|
||||
memcpy (src->buffer, src->source_data, bytes_read);
|
||||
|
||||
src->source_data += bytes_read;
|
||||
src->source_size -= bytes_read;
|
||||
|
||||
src->pub.next_input_byte = src->buffer;
|
||||
src->pub.bytes_in_buffer = bytes_read;
|
||||
src->start_of_data = FALSE;
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void skip_input_data(
|
||||
j_decompress_ptr cinfo,
|
||||
long num_bytes) {
|
||||
|
||||
mem_src_ptr src = (mem_src_ptr)cinfo->src;
|
||||
|
||||
if (num_bytes > 0) {
|
||||
while (num_bytes > (long) src->pub.bytes_in_buffer) {
|
||||
num_bytes -= (long) src->pub.bytes_in_buffer;
|
||||
boolean s = fill_input_buffer(cinfo);
|
||||
debugAssert(s); (void)s;
|
||||
}
|
||||
|
||||
src->pub.next_input_byte += (size_t) num_bytes;
|
||||
src->pub.bytes_in_buffer -= (size_t) num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void term_source (
|
||||
j_decompress_ptr cinfo) {
|
||||
(void)cinfo;
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void jpeg_memory_src (
|
||||
j_decompress_ptr cinfo,
|
||||
JOCTET* buffer,
|
||||
int size) {
|
||||
|
||||
mem_src_ptr src;
|
||||
|
||||
if (cinfo->src == NULL) {
|
||||
// First time for this JPEG object
|
||||
cinfo->src = (struct jpeg_source_mgr*)
|
||||
(*cinfo->mem->alloc_small)(
|
||||
(j_common_ptr) cinfo,
|
||||
JPOOL_PERMANENT,
|
||||
sizeof(memory_source_mgr));
|
||||
|
||||
src = (mem_src_ptr)cinfo->src;
|
||||
|
||||
src->buffer = (JOCTET*)
|
||||
(*cinfo->mem->alloc_small)(
|
||||
(j_common_ptr) cinfo,
|
||||
JPOOL_PERMANENT,
|
||||
INPUT_BUF_SIZE * sizeof(JOCTET));
|
||||
}
|
||||
|
||||
src = (mem_src_ptr)cinfo->src;
|
||||
src->pub.init_source = init_source;
|
||||
src->pub.fill_input_buffer = fill_input_buffer;
|
||||
src->pub.skip_input_data = skip_input_data;
|
||||
|
||||
// use default method
|
||||
src->pub.resync_to_restart = jpeg_resync_to_restart;
|
||||
src->pub.term_source = term_source;
|
||||
src->source_data = buffer;
|
||||
src->source_size = size;
|
||||
|
||||
// forces fill_input_buffer on first read
|
||||
src->pub.bytes_in_buffer = 0;
|
||||
|
||||
// until buffer loaded
|
||||
src->pub.next_input_byte = NULL;
|
||||
}
|
||||
|
||||
|
||||
void GImage::encodeJPEG(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
if (m_channels != 3) {
|
||||
// Convert to three channel
|
||||
GImage tmp = *this;
|
||||
tmp.convertToRGB();
|
||||
tmp.encodeJPEG(out);
|
||||
return;
|
||||
}
|
||||
|
||||
debugAssert(m_channels == 3);
|
||||
out.setEndian(G3D_LITTLE_ENDIAN);
|
||||
|
||||
// Allocate and initialize a compression object
|
||||
jpeg_compress_struct cinfo;
|
||||
jpeg_error_mgr jerr;
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&cinfo);
|
||||
|
||||
// Specify the destination for the compressed data.
|
||||
// (Overestimate the size)
|
||||
int buffer_size = m_width * m_height * 3 + 200;
|
||||
JOCTET* compressed_data = (JOCTET*)System::malloc(buffer_size);
|
||||
jpeg_memory_dest(&cinfo, compressed_data, buffer_size);
|
||||
|
||||
|
||||
cinfo.image_width = m_width;
|
||||
cinfo.image_height = m_height;
|
||||
|
||||
// # of color components per pixel
|
||||
cinfo.input_components = 3;
|
||||
|
||||
// colorspace of input image
|
||||
cinfo.in_color_space = JCS_RGB;
|
||||
cinfo.input_gamma = 1.0;
|
||||
|
||||
// Set parameters for compression, including image size & colorspace
|
||||
jpeg_set_defaults(&cinfo);
|
||||
jpeg_set_quality(&cinfo, jpegQuality, false);
|
||||
cinfo.smoothing_factor = 0;
|
||||
cinfo.optimize_coding = TRUE;
|
||||
// cinfo.dct_method = JDCT_FLOAT;
|
||||
cinfo.dct_method = JDCT_ISLOW;
|
||||
cinfo.jpeg_color_space = JCS_YCbCr;
|
||||
|
||||
// Initialize the compressor
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
// Iterate over all scanlines from top to bottom
|
||||
// pointer to a single row
|
||||
JSAMPROW row_pointer[1];
|
||||
|
||||
// JSAMPLEs per row in image_buffer
|
||||
int row_stride = cinfo.image_width * 3;
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
row_pointer[0] = &(m_byte[cinfo.next_scanline * row_stride]);
|
||||
jpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||
}
|
||||
|
||||
// Shut down the compressor
|
||||
jpeg_finish_compress(&cinfo);
|
||||
|
||||
// Figure out how big the result was.
|
||||
int outLength = ((mem_dest_ptr)cinfo.dest)->count;
|
||||
|
||||
// Release the JPEG compression object
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
// Copy into an appropriately sized output buffer.
|
||||
out.writeBytes(compressed_data, outLength);
|
||||
|
||||
// Free the conservative buffer.
|
||||
System::free(compressed_data);
|
||||
compressed_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodeJPEG(
|
||||
BinaryInput& input) {
|
||||
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
int loc = 0;
|
||||
|
||||
m_channels = 3;
|
||||
// We have to set up the error handler, in case initialization fails.
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
|
||||
// Initialize the JPEG decompression object.
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
// Specify data source (eg, a file, for us, memory)
|
||||
jpeg_memory_src(&cinfo, const_cast<uint8*>(input.getCArray()), input.size());
|
||||
|
||||
// Read the parameters with jpeg_read_header()
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
|
||||
// Set parameters for decompression
|
||||
// (We do nothing here since the defaults are fine)
|
||||
|
||||
// Start decompressor
|
||||
jpeg_start_decompress(&cinfo);
|
||||
|
||||
// Get and set the values of interest to this object
|
||||
m_width = cinfo.output_width;
|
||||
m_height = cinfo.output_height;
|
||||
|
||||
// Prepare the pointer object for the pixel data
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * 3);
|
||||
|
||||
// JSAMPLEs per row in output buffer
|
||||
int bpp = cinfo.output_components;
|
||||
int row_stride = cinfo.output_width * bpp;
|
||||
|
||||
// Make a one-row-high sample array that will go away when done with image
|
||||
JSAMPARRAY temp = (*cinfo.mem->alloc_sarray)
|
||||
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
|
||||
|
||||
// Read data on a scanline by scanline basis
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
|
||||
// We may need to adjust the output based on the
|
||||
// number of channels it has.
|
||||
switch (bpp) {
|
||||
case 1:
|
||||
// Grayscale; decompress to temp.
|
||||
jpeg_read_scanlines(&cinfo, temp, 1);
|
||||
|
||||
// Expand to three channels
|
||||
{
|
||||
uint8* scan = &(m_byte[loc * 3]);
|
||||
uint8* endScan = scan + (m_width * 3);
|
||||
uint8* t = *temp;
|
||||
|
||||
while (scan < endScan) {
|
||||
uint8 value = t[0];
|
||||
|
||||
// Spread the value 3x.
|
||||
scan[0] = value;
|
||||
scan[1] = value;
|
||||
scan[2] = value;
|
||||
|
||||
scan += 3;
|
||||
t += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// Read directly into the array
|
||||
{
|
||||
// Need one extra level of indirection.
|
||||
uint8* scan = m_byte + loc;
|
||||
JSAMPARRAY ptr = &scan;
|
||||
jpeg_read_scanlines(&cinfo, ptr, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// RGBA; decompress to temp.
|
||||
jpeg_read_scanlines(&cinfo, temp, 1);
|
||||
|
||||
// Drop the 3rd channel
|
||||
{
|
||||
uint8* scan = &(m_byte[loc * 3]);
|
||||
uint8* endScan = scan + m_width * 3;
|
||||
uint8* t = *temp;
|
||||
|
||||
while (scan < endScan) {
|
||||
scan[0] = t[0];
|
||||
scan[1] = t[1];
|
||||
scan[2] = t[2];
|
||||
|
||||
scan += 3;
|
||||
t += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Error("Unexpected number of channels.", input.getFilename());
|
||||
}
|
||||
|
||||
loc += row_stride;
|
||||
}
|
||||
|
||||
// Finish decompression
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
|
||||
alwaysAssertM(this, "Corrupt GImage");
|
||||
// Release JPEG decompression object
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
266
dep/src/g3dlite/GImage_png.cpp
Normal file
266
dep/src/g3dlite/GImage_png.cpp
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/**
|
||||
@file GImage_png.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2009-04-20
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Log.h"
|
||||
#include <png.h>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
//libpng required function signature
|
||||
static void png_read_data(
|
||||
png_structp png_ptr,
|
||||
png_bytep data,
|
||||
png_size_t length) {
|
||||
|
||||
|
||||
debugAssert( png_ptr->io_ptr != NULL );
|
||||
debugAssert( length >= 0 );
|
||||
debugAssert( data != NULL );
|
||||
|
||||
((BinaryInput*)png_ptr->io_ptr)->readBytes(data, length);
|
||||
}
|
||||
|
||||
//libpng required function signature
|
||||
static void png_write_data(png_structp png_ptr,
|
||||
png_bytep data,
|
||||
png_size_t length) {
|
||||
|
||||
debugAssert( png_ptr->io_ptr != NULL );
|
||||
debugAssert( data != NULL );
|
||||
|
||||
((BinaryOutput*)png_ptr->io_ptr)->writeBytes(data, length);
|
||||
}
|
||||
|
||||
//libpng required function signature
|
||||
static void png_flush_data(
|
||||
png_structp png_ptr) {
|
||||
(void)png_ptr;
|
||||
//Do nothing.
|
||||
}
|
||||
|
||||
//libpng required function signature
|
||||
static void png_error(
|
||||
png_structp png_ptr,
|
||||
png_const_charp error_msg) {
|
||||
|
||||
(void)png_ptr;
|
||||
debugAssert( error_msg != NULL );
|
||||
throw GImage::Error(error_msg, "PNG");
|
||||
}
|
||||
|
||||
|
||||
//libpng required function signature
|
||||
void png_warning(
|
||||
png_structp png_ptr,
|
||||
png_const_charp warning_msg) {
|
||||
|
||||
(void)png_ptr;
|
||||
debugAssert( warning_msg != NULL );
|
||||
Log::common()->println(warning_msg);
|
||||
}
|
||||
|
||||
|
||||
void GImage::encodePNG(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
debugAssert( m_channels == 1 || m_channels == 3 || m_channels == 4 );
|
||||
|
||||
if (m_height > (int)(PNG_UINT_32_MAX / png_sizeof(png_bytep)))
|
||||
throw GImage::Error("Unsupported PNG height.", out.getFilename());
|
||||
|
||||
out.setEndian(G3D_LITTLE_ENDIAN);
|
||||
|
||||
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_error, png_warning);
|
||||
if (! png_ptr) {
|
||||
throw GImage::Error("Unable to initialize PNG encoder.", out.getFilename());
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (! info_ptr) {
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
throw GImage::Error("Unable to initialize PNG encoder.", out.getFilename());
|
||||
}
|
||||
|
||||
//setup libpng write handler so can use BinaryOutput
|
||||
png_set_write_fn(png_ptr, (void*)&out, png_write_data, png_flush_data);
|
||||
png_color_8_struct sig_bit;
|
||||
|
||||
switch (m_channels) {
|
||||
case 1:
|
||||
png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 8, PNG_COLOR_TYPE_GRAY,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
sig_bit.red = 0;
|
||||
sig_bit.green = 0;
|
||||
sig_bit.blue = 0;
|
||||
sig_bit.alpha = 0;
|
||||
sig_bit.gray = 8;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 8, PNG_COLOR_TYPE_RGB,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
|
||||
sig_bit.red = 8;
|
||||
sig_bit.green = 8;
|
||||
sig_bit.blue = 8;
|
||||
sig_bit.alpha = 0;
|
||||
sig_bit.gray = 0;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 8, PNG_COLOR_TYPE_RGBA,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
sig_bit.red = 8;
|
||||
sig_bit.green = 8;
|
||||
sig_bit.blue = 8;
|
||||
sig_bit.alpha = 8;
|
||||
sig_bit.gray = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
throw GImage::Error("Unsupported number of channels for PNG.", out.getFilename());
|
||||
}
|
||||
|
||||
|
||||
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
|
||||
|
||||
//write the png header
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
png_bytepp row_pointers = new png_bytep[m_height];
|
||||
|
||||
for (int i=0; i < m_height; ++i) {
|
||||
row_pointers[i] = (png_bytep)&m_byte[m_width * m_channels * i];
|
||||
}
|
||||
|
||||
png_write_image(png_ptr, row_pointers);
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
|
||||
delete[] row_pointers;
|
||||
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodePNG(
|
||||
BinaryInput& input) {
|
||||
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error, png_warning);
|
||||
if (png_ptr == NULL) {
|
||||
throw GImage::Error("Unable to initialize PNG decoder.", input.getFilename());
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == NULL) {
|
||||
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
|
||||
throw GImage::Error("Unable to initialize PNG decoder.", input.getFilename());
|
||||
}
|
||||
|
||||
png_infop end_info = png_create_info_struct(png_ptr);
|
||||
if (end_info == NULL) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||||
throw GImage::Error("Unable to initialize PNG decoder.", input.getFilename());
|
||||
}
|
||||
|
||||
// now that the libpng structures are setup, change the error handlers and read routines
|
||||
// to use G3D functions so that BinaryInput can be used.
|
||||
|
||||
png_set_read_fn(png_ptr, (png_voidp)&input, png_read_data);
|
||||
|
||||
// read in sequentially so that three copies of the file are not in memory at once
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
png_uint_32 png_width, png_height;
|
||||
int bit_depth, color_type, interlace_type;
|
||||
// this will validate the data it extracts from info_ptr
|
||||
png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &bit_depth, &color_type,
|
||||
&interlace_type, int_p_NULL, int_p_NULL);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
throw GImage::Error("Unsupported PNG color type - PNG_COLOR_TYPE_GRAY_ALPHA.", input.getFilename());
|
||||
}
|
||||
|
||||
m_width = static_cast<uint32>(png_width);
|
||||
m_height = static_cast<uint32>(png_height);
|
||||
|
||||
//swap bytes of 16 bit files to least significant byte first
|
||||
png_set_swap(png_ptr);
|
||||
|
||||
png_set_strip_16(png_ptr);
|
||||
|
||||
//Expand paletted colors into true RGB triplets
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
}
|
||||
|
||||
//Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
|
||||
png_set_gray_1_2_4_to_8(png_ptr);
|
||||
}
|
||||
|
||||
//Expand paletted or RGB images with transparency to full alpha channels
|
||||
//so the data will be available as RGBA quartets.
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
|
||||
png_set_tRNS_to_alpha(png_ptr);
|
||||
}
|
||||
|
||||
// Fix sub-8 bit_depth to 8bit
|
||||
if (bit_depth < 8) {
|
||||
png_set_packing(png_ptr);
|
||||
}
|
||||
|
||||
if ((color_type == PNG_COLOR_TYPE_RGBA) ||
|
||||
((color_type == PNG_COLOR_TYPE_PALETTE) && (png_ptr->num_trans > 0)) ) {
|
||||
|
||||
m_channels = 4;
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * 4);
|
||||
|
||||
} else if ((color_type == PNG_COLOR_TYPE_RGB) ||
|
||||
(color_type == PNG_COLOR_TYPE_PALETTE)) {
|
||||
|
||||
m_channels = 3;
|
||||
m_byte = (uint8*)System::malloc(m_width * m_height * 3);
|
||||
|
||||
} else if (color_type == PNG_COLOR_TYPE_GRAY) {
|
||||
|
||||
m_channels = 1;
|
||||
|
||||
// Round up to the nearest 8 rows to avoid a bug in the PNG decoder
|
||||
int h = iCeil(m_height / 8) * 8;
|
||||
int sz = m_width * h;
|
||||
m_byte = (uint8*)m_memMan->alloc(sz);
|
||||
|
||||
} else {
|
||||
throw GImage::Error("Unsupported PNG bit-depth or type.", input.getFilename());
|
||||
}
|
||||
|
||||
//since we are reading row by row, required to handle interlacing
|
||||
uint32 number_passes = png_set_interlace_handling(png_ptr);
|
||||
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
for (uint32 pass = 0; pass < number_passes; ++pass) {
|
||||
for (uint32 y = 0; y < (uint32)m_height; ++y) {
|
||||
png_bytep rowPointer = &m_byte[m_width * m_channels * y];
|
||||
png_read_rows(png_ptr, &rowPointer, png_bytepp_NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// png_read_image(png_ptr, &_byte);
|
||||
png_read_end(png_ptr, info_ptr);
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
}
|
||||
|
||||
}
|
||||
217
dep/src/g3dlite/GImage_ppm.cpp
Normal file
217
dep/src/g3dlite/GImage_ppm.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/**
|
||||
@file GImage_ppm.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2006-05-10
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/TextInput.h"
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/Log.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void GImage::encodePPMASCII(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
TextOutput::Settings ppmOptions;
|
||||
ppmOptions.convertNewlines = false;
|
||||
ppmOptions.numColumns = 70;
|
||||
ppmOptions.wordWrap = TextOutput::Settings::WRAP_WITHOUT_BREAKING;
|
||||
TextOutput ppm(ppmOptions);
|
||||
|
||||
switch (m_channels) {
|
||||
case 1:
|
||||
{
|
||||
ppm.printf("P2\n%d %d\n255\n", m_width, m_height);
|
||||
|
||||
const Color1uint8* c = this->pixel1();
|
||||
// Insert newlines every 70 characters max
|
||||
for (uint32 i = 0; i < (uint32)(m_width * m_height); ++i) {
|
||||
ppm.printf("%d%c", c[i].value, (i % (70/4) == 0) ? '\n' : ' ');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
ppm.printf("P3\n%d %d\n255\n", m_width, m_height);
|
||||
|
||||
const Color3uint8* c = this->pixel3();
|
||||
// Insert newlines every 70 characters max
|
||||
for (uint32 i = 0; i < (uint32)(m_width * m_height); ++i) {
|
||||
ppm.printf("%d %d %d%c", c[i].r, c[i].g, c[i].b,
|
||||
(i % (70/12) == 0) ?
|
||||
'\n' : ' ');
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
alwaysAssertM(false, "PPM requires either 1 or 3 channels exactly.");
|
||||
}
|
||||
|
||||
const std::string& s = ppm.commitString();
|
||||
out.writeBytes(s.c_str(), s.length());
|
||||
}
|
||||
|
||||
|
||||
void GImage::encodePPM(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
// http://netpbm.sourceforge.net/doc/ppm.html
|
||||
if (m_channels == 3) {
|
||||
std::string header = format("P6 %d %d 255 ", m_width, m_height);
|
||||
out.writeBytes(header.c_str(), header.size());
|
||||
out.writeBytes(this->pixel3(), m_width * m_height * 3);
|
||||
} else if (m_channels == 1) {
|
||||
std::string header = format("P5 %d %d 255 ", m_width, m_height);
|
||||
out.writeBytes(header.c_str(), header.size());
|
||||
out.writeBytes(this->pixel1(), m_width * m_height);
|
||||
} else {
|
||||
alwaysAssertM(false, "PPM requires either 1 or 3 channels exactly.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodePPMASCII(
|
||||
BinaryInput& input) {
|
||||
|
||||
int ppmWidth;
|
||||
int ppmHeight;
|
||||
|
||||
double maxColor;
|
||||
|
||||
// Create a TextInput object to parse ascii format
|
||||
// Mixed binary/ascii formats will require more
|
||||
|
||||
const std::string inputStr = input.readString();
|
||||
|
||||
TextInput::Settings ppmOptions;
|
||||
ppmOptions.cppLineComments = false;
|
||||
ppmOptions.otherCommentCharacter = '#';
|
||||
ppmOptions.signedNumbers = true;
|
||||
ppmOptions.singleQuotedStrings = false;
|
||||
|
||||
TextInput ppmInput(TextInput::FROM_STRING, inputStr, ppmOptions);
|
||||
|
||||
//Skip first line in header P#
|
||||
std::string ppmType = ppmInput.readSymbol();
|
||||
|
||||
ppmWidth = (int)ppmInput.readNumber();
|
||||
ppmHeight = (int)ppmInput.readNumber();
|
||||
|
||||
// Everything but a PBM will have a max color value
|
||||
if (ppmType != "P2") {
|
||||
maxColor = ppmInput.readNumber();
|
||||
} else {
|
||||
maxColor = 255;
|
||||
}
|
||||
|
||||
if ((ppmWidth < 0) ||
|
||||
(ppmHeight < 0) ||
|
||||
(maxColor <= 0)) {
|
||||
throw GImage::Error("Invalid PPM Header.", input.getFilename());
|
||||
}
|
||||
|
||||
// I don't think it's proper to scale values less than 255
|
||||
if (maxColor <= 255.0) {
|
||||
maxColor = 255.0;
|
||||
}
|
||||
|
||||
m_width = ppmWidth;
|
||||
m_height = ppmHeight;
|
||||
m_channels = 3;
|
||||
// always scale down to 1 byte per channel
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * 3);
|
||||
|
||||
// Read in the image data. I am not validating if the values match the maxColor
|
||||
// requirements. I only scale if needed to fit within the byte available.
|
||||
for (uint32 i = 0; i < (uint32)(m_width * m_height); ++i) {
|
||||
// read in color and scale to max pixel defined in header
|
||||
// A max color less than 255 might need to be left alone and not scaled.
|
||||
Color3uint8& curPixel = *(pixel3() + i);
|
||||
|
||||
if (ppmType == "P3") {
|
||||
curPixel.r = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
|
||||
curPixel.g = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
|
||||
curPixel.b = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
|
||||
} else if (ppmType == "P2") {
|
||||
uint8 pixel = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
|
||||
curPixel.r = pixel;
|
||||
curPixel.g = pixel;
|
||||
curPixel.b = pixel;
|
||||
} else if (ppmType == "P1") {
|
||||
int pixel = (uint8)(ppmInput.readNumber() * maxColor);
|
||||
curPixel.r = pixel;
|
||||
curPixel.g = pixel;
|
||||
curPixel.b = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Consumes whitespace up to and including a number, but not the following character */
|
||||
static int scanUInt(BinaryInput& input) {
|
||||
char c = input.readUInt8();
|
||||
while (isWhiteSpace(c)) {
|
||||
c = input.readUInt8();
|
||||
}
|
||||
|
||||
std::string s;
|
||||
s += c;
|
||||
c = input.readUInt8();
|
||||
while (!isWhiteSpace(c)) {
|
||||
s += c;
|
||||
c = input.readUInt8();
|
||||
}
|
||||
|
||||
// Back up one to avoid consuming the last character
|
||||
input.setPosition(input.getPosition() - 1);
|
||||
|
||||
int x;
|
||||
sscanf(s.c_str(), "%d", &x);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodePPM(
|
||||
BinaryInput& input) {
|
||||
|
||||
char head[2];
|
||||
int w, h;
|
||||
|
||||
input.readBytes(head, 2);
|
||||
if (head[0] != 'P' || (head[1] != '6') && (head[1] != '5')) {
|
||||
throw GImage::Error("Invalid PPM Header.", input.getFilename());
|
||||
}
|
||||
|
||||
w = scanUInt(input);
|
||||
h = scanUInt(input);
|
||||
|
||||
// Skip the max color specifier
|
||||
scanUInt(input);
|
||||
|
||||
if ((w < 0) ||
|
||||
(h < 0) ||
|
||||
(w > 100000) ||
|
||||
(h > 100000)) {
|
||||
throw GImage::Error("Invalid PPM size in header.", input.getFilename());
|
||||
}
|
||||
|
||||
// Trailing whitespace
|
||||
input.readUInt8();
|
||||
|
||||
if (head[1] == '6') {
|
||||
// 3 channel
|
||||
resize(w, h, 3);
|
||||
input.readBytes(m_byte, m_width * m_height * 3);
|
||||
} else if (head[1] == '5') {
|
||||
// 1 channel
|
||||
resize(w, h, 1);
|
||||
input.readBytes(m_byte, m_width * m_height);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
193
dep/src/g3dlite/GImage_tga.cpp
Normal file
193
dep/src/g3dlite/GImage_tga.cpp
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/**
|
||||
@file GImage_tga.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
@edited 2009-05-10
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Log.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void GImage::encodeTGA(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
out.setEndian(G3D_LITTLE_ENDIAN);
|
||||
|
||||
// ID length
|
||||
out.writeUInt8(0);
|
||||
|
||||
// Color map Type
|
||||
out.writeUInt8(0);
|
||||
|
||||
// Type
|
||||
out.writeUInt8(2);
|
||||
|
||||
// Color map
|
||||
out.skip(5);
|
||||
|
||||
// x, y offsets
|
||||
out.writeUInt16(0);
|
||||
out.writeUInt16(0);
|
||||
|
||||
// Width & height
|
||||
out.writeUInt16(m_width);
|
||||
out.writeUInt16(m_height);
|
||||
|
||||
// Color depth
|
||||
if (m_channels == 1) {
|
||||
// Force RGB mode
|
||||
out.writeUInt8(8 * 3);
|
||||
} else {
|
||||
out.writeUInt8(8 * m_channels);
|
||||
}
|
||||
|
||||
// Image descriptor
|
||||
if (m_channels < 4) {
|
||||
// 0 alpha bits
|
||||
out.writeUInt8(0);
|
||||
} else {
|
||||
// 8 alpha bits
|
||||
out.writeUInt8(8);
|
||||
}
|
||||
|
||||
// Image ID (zero length)
|
||||
|
||||
if (m_channels == 1) {
|
||||
// Pixels are upside down in BGR format.
|
||||
for (int y = m_height - 1; y >= 0; --y) {
|
||||
for (int x = 0; x < m_width; ++x) {
|
||||
uint8 p = (m_byte[(y * m_width + x)]);
|
||||
out.writeUInt8(p);
|
||||
out.writeUInt8(p);
|
||||
out.writeUInt8(p);
|
||||
}
|
||||
}
|
||||
} else if (m_channels == 3) {
|
||||
// Pixels are upside down in BGR format.
|
||||
for (int y = m_height - 1; y >= 0; --y) {
|
||||
for (int x = 0; x < m_width; ++x) {
|
||||
uint8* p = &(m_byte[3 * (y * m_width + x)]);
|
||||
out.writeUInt8(p[2]);
|
||||
out.writeUInt8(p[1]);
|
||||
out.writeUInt8(p[0]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Pixels are upside down in BGRA format.
|
||||
for (int y = m_height - 1; y >= 0; --y) {
|
||||
for (int x = 0; x < m_width; ++x) {
|
||||
uint8* p = &(m_byte[4 * (y * m_width + x)]);
|
||||
out.writeUInt8(p[2]);
|
||||
out.writeUInt8(p[1]);
|
||||
out.writeUInt8(p[0]);
|
||||
out.writeUInt8(p[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write "TRUEVISION-XFILE " 18 bytes from the end
|
||||
// (with null termination)
|
||||
out.writeString("TRUEVISION-XFILE ");
|
||||
}
|
||||
|
||||
|
||||
void GImage::decodeTGA(
|
||||
BinaryInput& input) {
|
||||
|
||||
// This is a simple TGA loader that can handle uncompressed
|
||||
// truecolor TGA files (TGA type 2).
|
||||
// Verify this is a TGA file by looking for the TRUEVISION tag.
|
||||
int pos = input.getPosition();
|
||||
input.setPosition(input.size() - 18);
|
||||
std::string tag = input.readString(16);
|
||||
if (tag != "TRUEVISION-XFILE") {
|
||||
throw Error("Not a TGA file", input.getFilename());
|
||||
}
|
||||
|
||||
input.setPosition(pos);
|
||||
|
||||
int IDLength = input.readUInt8();
|
||||
int colorMapType = input.readUInt8();
|
||||
int imageType = input.readUInt8();
|
||||
|
||||
(void)colorMapType;
|
||||
|
||||
// 2 is the type supported by this routine.
|
||||
if (imageType != 2) {
|
||||
throw Error("TGA images must be type 2 (Uncompressed truecolor)", input.getFilename());
|
||||
}
|
||||
|
||||
// Color map specification
|
||||
input.skip(5);
|
||||
|
||||
// Image specification
|
||||
|
||||
// Skip x and y offsets
|
||||
input.skip(4);
|
||||
|
||||
m_width = input.readInt16();
|
||||
m_height = input.readInt16();
|
||||
|
||||
int colorDepth = input.readUInt8();
|
||||
|
||||
if ((colorDepth != 24) && (colorDepth != 32)) {
|
||||
throw Error("TGA files must be 24 or 32 bit.", input.getFilename());
|
||||
}
|
||||
|
||||
if (colorDepth == 32) {
|
||||
m_channels = 4;
|
||||
} else {
|
||||
m_channels = 3;
|
||||
}
|
||||
|
||||
// Image descriptor contains overlay data as well
|
||||
// as data indicating where the origin is
|
||||
int imageDescriptor = input.readUInt8();
|
||||
(void)imageDescriptor;
|
||||
|
||||
// Image ID
|
||||
input.skip(IDLength);
|
||||
|
||||
m_byte = (uint8*)m_memMan->alloc(m_width * m_height * m_channels);
|
||||
debugAssert(m_byte);
|
||||
|
||||
// Pixel data
|
||||
int x;
|
||||
int y;
|
||||
|
||||
if (m_channels == 3) {
|
||||
for (y = m_height - 1; y >= 0; --y) {
|
||||
for (x = 0; x < m_width; ++x) {
|
||||
int b = input.readUInt8();
|
||||
int g = input.readUInt8();
|
||||
int r = input.readUInt8();
|
||||
|
||||
int i = (x + y * m_width) * 3;
|
||||
m_byte[i + 0] = r;
|
||||
m_byte[i + 1] = g;
|
||||
m_byte[i + 2] = b;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = m_height - 1; y >= 0; --y) {
|
||||
for (x = 0; x < m_width; ++x) {
|
||||
int b = input.readUInt8();
|
||||
int g = input.readUInt8();
|
||||
int r = input.readUInt8();
|
||||
int a = input.readUInt8();
|
||||
|
||||
int i = (x + y * m_width) * 4;
|
||||
m_byte[i + 0] = r;
|
||||
m_byte[i + 1] = g;
|
||||
m_byte[i + 2] = b;
|
||||
m_byte[i + 3] = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
267
dep/src/g3dlite/GLight.cpp
Normal file
267
dep/src/g3dlite/GLight.cpp
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
/**
|
||||
@file GLight.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-11-12
|
||||
@edited 2009-11-16
|
||||
*/
|
||||
#include "G3D/GLight.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
GLight::GLight(const Any& any) {
|
||||
any.verifyName("GLight");
|
||||
|
||||
if (any.type() == Any::TABLE) {
|
||||
*this = GLight();
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "position") {
|
||||
position = it->value;
|
||||
} else if (key == "rightdirection") {
|
||||
rightDirection = it->value;
|
||||
} else if (key == "spotdirection") {
|
||||
spotDirection = it->value;
|
||||
} else if (key == "spotcutoff") {
|
||||
spotCutoff = it->value.number();
|
||||
} else if (key == "spotsquare") {
|
||||
spotSquare = it->value.boolean();
|
||||
} else if (key == "attenuation") {
|
||||
attenuation[0] = it->value[0].number();
|
||||
attenuation[1] = it->value[1].number();
|
||||
attenuation[2] = it->value[2].number();
|
||||
} else if (key == "color") {
|
||||
color = it->value;
|
||||
} else if (key == "enabled") {
|
||||
enabled = it->value.boolean();
|
||||
} else if (key == "specular") {
|
||||
specular = it->value.boolean();
|
||||
} else if (key == "diffuse") {
|
||||
diffuse = it->value.boolean();
|
||||
} else {
|
||||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
} else if (toLower(any.name()) == "glight::directional") {
|
||||
|
||||
*this = directional(any[0], any[1],
|
||||
(any.size() > 2) ? any[2] : Any(true),
|
||||
(any.size() > 3) ? any[3] : Any(true));
|
||||
|
||||
} else if (toLower(any.name()) == "glight::point") {
|
||||
|
||||
*this = point(any[0], any[1],
|
||||
(any.size() > 2) ? any[2] : Any(1),
|
||||
(any.size() > 3) ? any[3] : Any(0),
|
||||
(any.size() > 4) ? any[4] : Any(0.5f),
|
||||
(any.size() > 5) ? any[5] : Any(true),
|
||||
(any.size() > 6) ? any[6] : Any(true));
|
||||
|
||||
} else if (toLower(any.name()) == "glight::spot") {
|
||||
|
||||
*this = spot(any[0], any[1], any[2], any[3],
|
||||
(any.size() > 4) ? any[4] : Any(1),
|
||||
(any.size() > 5) ? any[5] : Any(0),
|
||||
(any.size() > 6) ? any[6] : Any(0.5f),
|
||||
(any.size() > 7) ? any[5] : Any(true),
|
||||
(any.size() > 8) ? any[6] : Any(true));
|
||||
} else {
|
||||
any.verify(false, "Unrecognized name");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GLight::operator Any() const {
|
||||
Any a(Any::TABLE, "GLight");
|
||||
a.set("position", position.operator Any());
|
||||
a.set("rightDirection", rightDirection.operator Any());
|
||||
a.set("spotDirection", spotDirection.operator Any());
|
||||
a.set("spotCutoff", spotCutoff);
|
||||
a.set("spotSquare", spotSquare);
|
||||
|
||||
Any att(Any::ARRAY);
|
||||
att.append(attenuation[0], attenuation[1], attenuation[2]);
|
||||
a.set("attenuation", att);
|
||||
a.set("color", color.operator Any());
|
||||
a.set("enabled", enabled);
|
||||
a.set("specular", specular);
|
||||
a.set("diffuse", diffuse);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
GLight::GLight() :
|
||||
position(0, 0, 0, 0),
|
||||
rightDirection(0,0,0),
|
||||
spotDirection(0, 0, -1),
|
||||
spotCutoff(180),
|
||||
spotSquare(false),
|
||||
color(Color3::white()),
|
||||
enabled(false),
|
||||
specular(true),
|
||||
diffuse(true) {
|
||||
|
||||
attenuation[0] = 1.0;
|
||||
attenuation[1] = 0.0;
|
||||
attenuation[2] = 0.0;
|
||||
}
|
||||
|
||||
|
||||
GLight GLight::directional(const Vector3& toLight, const Color3& color, bool s, bool d) {
|
||||
GLight L;
|
||||
L.position = Vector4(toLight.direction(), 0);
|
||||
L.color = color;
|
||||
L.specular = s;
|
||||
L.diffuse = d;
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
GLight GLight::point(const Vector3& pos, const Color3& color, float constAtt, float linAtt, float quadAtt, bool s, bool d) {
|
||||
GLight L;
|
||||
L.position = Vector4(pos, 1);
|
||||
L.color = color;
|
||||
L.attenuation[0] = constAtt;
|
||||
L.attenuation[1] = linAtt;
|
||||
L.attenuation[2] = quadAtt;
|
||||
L.specular = s;
|
||||
L.diffuse = d;
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
GLight GLight::spot(const Vector3& pos, const Vector3& pointDirection, float cutOffAngleDegrees, const Color3& color, float constAtt, float linAtt, float quadAtt, bool s, bool d) {
|
||||
GLight L;
|
||||
L.position = Vector4(pos, 1.0f);
|
||||
L.spotDirection = pointDirection.direction();
|
||||
debugAssert(cutOffAngleDegrees <= 90);
|
||||
L.spotCutoff = cutOffAngleDegrees;
|
||||
L.color = color;
|
||||
L.attenuation[0] = constAtt;
|
||||
L.attenuation[1] = linAtt;
|
||||
L.attenuation[2] = quadAtt;
|
||||
L.specular = s;
|
||||
L.diffuse = d;
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
bool GLight::operator==(const GLight& other) const {
|
||||
return (position == other.position) &&
|
||||
(rightDirection == other.rightDirection) &&
|
||||
(spotDirection == other.spotDirection) &&
|
||||
(spotCutoff == other.spotCutoff) &&
|
||||
(spotSquare == other.spotSquare) &&
|
||||
(attenuation[0] == other.attenuation[0]) &&
|
||||
(attenuation[1] == other.attenuation[1]) &&
|
||||
(attenuation[2] == other.attenuation[2]) &&
|
||||
(color == other.color) &&
|
||||
(enabled == other.enabled) &&
|
||||
(specular == other.specular) &&
|
||||
(diffuse == other.diffuse);
|
||||
}
|
||||
|
||||
|
||||
bool GLight::operator!=(const GLight& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
Sphere GLight::effectSphere(float cutoff) const {
|
||||
if (position.w == 0) {
|
||||
// Directional light
|
||||
return Sphere(Vector3::zero(), finf());
|
||||
} else {
|
||||
// Avoid divide by zero
|
||||
cutoff = max(cutoff, 0.00001f);
|
||||
float maxIntensity = max(color.r, max(color.g, color.b));
|
||||
|
||||
float radius = finf();
|
||||
|
||||
if (attenuation[2] != 0) {
|
||||
|
||||
// Solve I / attenuation.dot(1, r, r^2) < cutoff for r
|
||||
//
|
||||
// a[0] + a[1] r + a[2] r^2 > I/cutoff
|
||||
//
|
||||
|
||||
float a = attenuation[2];
|
||||
float b = attenuation[1];
|
||||
float c = attenuation[0] - maxIntensity / cutoff;
|
||||
|
||||
float discrim = square(b) - 4 * a * c;
|
||||
|
||||
if (discrim >= 0) {
|
||||
discrim = sqrt(discrim);
|
||||
|
||||
float r1 = (-b + discrim) / (2 * a);
|
||||
float r2 = (-b - discrim) / (2 * a);
|
||||
|
||||
if (r1 < 0) {
|
||||
if (r2 > 0) {
|
||||
radius = r2;
|
||||
}
|
||||
} else if (r2 > 0) {
|
||||
radius = min(r1, r2);
|
||||
} else {
|
||||
radius = r1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (attenuation[1] != 0) {
|
||||
|
||||
// Solve I / attenuation.dot(1, r) < cutoff for r
|
||||
//
|
||||
// r * a[1] + a[0] = I / cutoff
|
||||
// r = (I / cutoff - a[0]) / a[1]
|
||||
|
||||
float radius = (maxIntensity / cutoff - attenuation[0]) / attenuation[1];
|
||||
radius = max(radius, 0.0f);
|
||||
}
|
||||
|
||||
return Sphere(position.xyz(), radius);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame GLight::frame() const {
|
||||
CoordinateFrame f;
|
||||
if (rightDirection == Vector3::zero()) {
|
||||
// No specified right direction; choose one automatically
|
||||
if (position.w == 0) {
|
||||
// Directional light
|
||||
f.lookAt(-position.xyz());
|
||||
} else {
|
||||
// Spot light
|
||||
f.lookAt(spotDirection);
|
||||
}
|
||||
} else {
|
||||
const Vector3& Z = -spotDirection.direction();
|
||||
Vector3 X = rightDirection.direction();
|
||||
|
||||
// Ensure the vectors are not too close together
|
||||
while (abs(X.dot(Z)) > 0.9f) {
|
||||
X = Vector3::random();
|
||||
}
|
||||
|
||||
// Ensure perpendicular
|
||||
X -= Z * Z.dot(X);
|
||||
const Vector3& Y = Z.cross(X);
|
||||
|
||||
f.rotation.setColumn(Vector3::X_AXIS, X);
|
||||
f.rotation.setColumn(Vector3::Y_AXIS, Y);
|
||||
f.rotation.setColumn(Vector3::Z_AXIS, Z);
|
||||
}
|
||||
f.translation = position.xyz();
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
} // G3D
|
||||
229
dep/src/g3dlite/GThread.cpp
Normal file
229
dep/src/g3dlite/GThread.cpp
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
/**
|
||||
@file GThread.cpp
|
||||
|
||||
GThread class.
|
||||
|
||||
@created 2005-09-24
|
||||
@edited 2005-10-22
|
||||
*/
|
||||
|
||||
#include "G3D/GThread.h"
|
||||
#include "G3D/System.h"
|
||||
#include "G3D/debugAssert.h"
|
||||
#include "G3D/GMutex.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
namespace _internal {
|
||||
|
||||
class BasicThread: public GThread {
|
||||
public:
|
||||
BasicThread(const std::string& name, void (*proc)(void*), void* param):
|
||||
GThread(name), m_wrapperProc(proc), m_param(param) { }
|
||||
protected:
|
||||
virtual void threadMain() {
|
||||
m_wrapperProc(m_param);
|
||||
}
|
||||
|
||||
private:
|
||||
void (*m_wrapperProc)(void*);
|
||||
|
||||
void* m_param;
|
||||
};
|
||||
|
||||
} // namespace _internal
|
||||
|
||||
|
||||
GThread::GThread(const std::string& name):
|
||||
m_status(STATUS_CREATED),
|
||||
m_name(name) {
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
m_event = NULL;
|
||||
#endif
|
||||
|
||||
// system-independent clear of handle
|
||||
System::memset(&m_handle, 0, sizeof(m_handle));
|
||||
}
|
||||
|
||||
GThread::~GThread() {
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( push )
|
||||
# pragma warning( disable : 4127 )
|
||||
#endif
|
||||
alwaysAssertM(m_status != STATUS_RUNNING, "Deleting thread while running.");
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
if (m_event) {
|
||||
::CloseHandle(m_event);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GThreadRef GThread::create(const std::string& name, void (*proc)(void*), void* param) {
|
||||
return new _internal::BasicThread(name, proc, param);
|
||||
}
|
||||
|
||||
|
||||
bool GThread::started() const {
|
||||
return m_status != STATUS_CREATED;
|
||||
}
|
||||
|
||||
bool GThread::start(SpawnBehavior behavior) {
|
||||
|
||||
debugAssertM(! started(), "Thread has already executed.");
|
||||
if (started()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_status = STATUS_STARTED;
|
||||
|
||||
if (behavior == USE_CURRENT_THREAD) {
|
||||
// Run on this thread
|
||||
m_status = STATUS_RUNNING;
|
||||
threadMain();
|
||||
m_status = STATUS_COMPLETED;
|
||||
return true;
|
||||
}
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
DWORD threadId;
|
||||
|
||||
m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
debugAssert(m_event);
|
||||
|
||||
m_handle = ::CreateThread(NULL, 0, &internalThreadProc, this, 0, &threadId);
|
||||
|
||||
if (m_handle == NULL) {
|
||||
::CloseHandle(m_event);
|
||||
m_event = NULL;
|
||||
}
|
||||
|
||||
return (m_handle != NULL);
|
||||
# else
|
||||
if (!pthread_create(&m_handle, NULL, &internalThreadProc, this)) {
|
||||
return true;
|
||||
} else {
|
||||
// system-independent clear of handle
|
||||
System::memset(&m_handle, 0, sizeof(m_handle));
|
||||
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
void GThread::terminate() {
|
||||
if (m_handle) {
|
||||
# ifdef G3D_WIN32
|
||||
::TerminateThread(m_handle, 0);
|
||||
# else
|
||||
pthread_kill(m_handle, SIGSTOP);
|
||||
# endif
|
||||
// system-independent clear of handle
|
||||
System::memset(&m_handle, 0, sizeof(m_handle));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool GThread::running() const{
|
||||
return (m_status == STATUS_RUNNING);
|
||||
}
|
||||
|
||||
|
||||
bool GThread::completed() const {
|
||||
return (m_status == STATUS_COMPLETED);
|
||||
}
|
||||
|
||||
|
||||
void GThread::waitForCompletion() {
|
||||
if (m_status == STATUS_COMPLETED) {
|
||||
// Must be done
|
||||
return;
|
||||
}
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
debugAssert(m_event);
|
||||
::WaitForSingleObject(m_event, INFINITE);
|
||||
# else
|
||||
debugAssert(m_handle);
|
||||
pthread_join(m_handle, NULL);
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
DWORD WINAPI GThread::internalThreadProc(LPVOID param) {
|
||||
GThread* current = reinterpret_cast<GThread*>(param);
|
||||
debugAssert(current->m_event);
|
||||
current->m_status = STATUS_RUNNING;
|
||||
current->threadMain();
|
||||
current->m_status = STATUS_COMPLETED;
|
||||
::SetEvent(current->m_event);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
void* GThread::internalThreadProc(void* param) {
|
||||
GThread* current = reinterpret_cast<GThread*>(param);
|
||||
current->m_status = STATUS_RUNNING;
|
||||
current->threadMain();
|
||||
current->m_status = STATUS_COMPLETED;
|
||||
return (void*)NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//GMutex implementation
|
||||
GMutex::GMutex() {
|
||||
#ifdef G3D_WIN32
|
||||
::InitializeCriticalSection(&m_handle);
|
||||
#else
|
||||
int ret = pthread_mutexattr_init(&m_attr);
|
||||
debugAssert(ret == 0);
|
||||
ret = pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
debugAssert(ret == 0);
|
||||
ret = pthread_mutex_init(&m_handle, &m_attr);
|
||||
debugAssert(ret == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
GMutex::~GMutex() {
|
||||
//TODO: Debug check for locked
|
||||
#ifdef G3D_WIN32
|
||||
::DeleteCriticalSection(&m_handle);
|
||||
#else
|
||||
int ret = pthread_mutex_destroy(&m_handle);
|
||||
debugAssert(ret == 0);
|
||||
ret = pthread_mutexattr_destroy(&m_attr);
|
||||
debugAssert(ret == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GMutex::tryLock() {
|
||||
#ifdef G3D_WIN32
|
||||
return (::TryEnterCriticalSection(&m_handle) != 0);
|
||||
#else
|
||||
return (pthread_mutex_trylock(&m_handle) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GMutex::lock() {
|
||||
#ifdef G3D_WIN32
|
||||
::EnterCriticalSection(&m_handle);
|
||||
#else
|
||||
pthread_mutex_lock(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GMutex::unlock() {
|
||||
#ifdef G3D_WIN32
|
||||
::LeaveCriticalSection(&m_handle);
|
||||
#else
|
||||
pthread_mutex_unlock(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace G3D
|
||||
78
dep/src/g3dlite/GUniqueID.cpp
Normal file
78
dep/src/g3dlite/GUniqueID.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
@file GUniqueID.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
*/
|
||||
#include "G3D/GUniqueID.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/TextInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/NetworkDevice.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void GUniqueID::serialize(BinaryOutput& b) const {
|
||||
b.writeUInt64(id);
|
||||
}
|
||||
|
||||
|
||||
void GUniqueID::deserialize(BinaryInput& b) {
|
||||
id = b.readUInt64();
|
||||
}
|
||||
|
||||
void GUniqueID::serialize(TextOutput& t) const {
|
||||
t.writeSymbol("(");
|
||||
t.writeNumber((double)(id >> 32));
|
||||
t.writeNumber((double)(id & 0xFFFFFFFF));
|
||||
t.writeSymbol(")");
|
||||
}
|
||||
|
||||
void GUniqueID::deserialize(TextInput& t) {
|
||||
t.readSymbol("(");
|
||||
id = (((uint64)t.readNumber()) << 32) + (uint64)t.readNumber();
|
||||
t.readSymbol(")");
|
||||
}
|
||||
|
||||
|
||||
GUniqueID GUniqueID::create(uint16 tag) {
|
||||
static uint64 counter = 0;
|
||||
static uint64 systemID = 0;
|
||||
|
||||
if (systemID == 0) {
|
||||
// Create a unique ID for this machine/program instance
|
||||
|
||||
// TODO: see ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr)
|
||||
Array<NetAddress> addr;
|
||||
NetworkDevice::instance()->localHostAddresses(addr);
|
||||
if (addr.size() > 0) {
|
||||
systemID |= addr[0].ip();
|
||||
}
|
||||
|
||||
union {
|
||||
float64 ft;
|
||||
uint64 ut;
|
||||
};
|
||||
ft = System::time();
|
||||
systemID = ut << 22;
|
||||
systemID ^= ((uint64)iRandom(0, 32768)) << 8;
|
||||
|
||||
systemID &= ~((uint64)1023 << 54);
|
||||
|
||||
// Ensure that the systemID is non-zero (vanishingly small probability)
|
||||
if (systemID == 0) {
|
||||
systemID = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// No need for modulo; we'll all be dead before this counter
|
||||
// overflows 54 bits
|
||||
++counter;
|
||||
|
||||
GUniqueID i;
|
||||
|
||||
i.id = (((uint64)(tag & 1023)) << 54) | (counter ^ systemID);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
} // G3D
|
||||
224
dep/src/g3dlite/Image1.cpp
Normal file
224
dep/src/g3dlite/Image1.cpp
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/**
|
||||
@file Image1.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2007-01-31
|
||||
*/
|
||||
|
||||
|
||||
#include "G3D/Image1.h"
|
||||
#include "G3D/Image1uint8.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image1::Image1(int w, int h, WrapMode wrap) : Map2D<Color1, Color1>(w, h, wrap) {
|
||||
setAll(Color1(0.0f));
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromImage1uint8(const ReferenceCountedPointer<Image1uint8>& im) {
|
||||
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
|
||||
out->resize(im->width(), im->height());
|
||||
|
||||
int N = im->width() * im->height();
|
||||
const Color1uint8* src = reinterpret_cast<Color1uint8*>(im->getCArray());
|
||||
for (int i = 0; i < N; ++i) {
|
||||
out->data[i] = Color1(src[i]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Type(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename, fmt);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image1::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1::Ref Image1::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
void Image1::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color3uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color1* dst = data.getCArray();
|
||||
// Convert int8 -> float
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1(Color3(src[i]).average());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color4uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color1* dst = data.getCArray();
|
||||
|
||||
// Strip alpha and convert
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1(Color3(src[i].rgb()).average());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), src, w * h * sizeof(Color1));
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color1* dst = data.getCArray();
|
||||
|
||||
// Strip alpha
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1(src[i].rgb().average());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color1uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i]= Color1(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1(src[i].average());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image1::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 1);
|
||||
|
||||
int N = im.width() * im.height();
|
||||
Color1uint8* dst = im.pixel1();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1uint8(data[i]);
|
||||
}
|
||||
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* Image1::format() const {
|
||||
return ImageFormat::L32F();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
212
dep/src/g3dlite/Image1uint8.cpp
Normal file
212
dep/src/g3dlite/Image1uint8.cpp
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/**
|
||||
@file Image1uint8.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2008-01-13
|
||||
*/
|
||||
|
||||
#include "G3D/Image1uint8.h"
|
||||
#include "G3D/Image3uint8.h"
|
||||
#include "G3D/Image1.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image1uint8::Image1uint8(int w, int h, WrapMode wrap) : Map2D<Color1uint8, Color1>(w, h, wrap) {
|
||||
setAll(Color1uint8(0));
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromImage3uint8(const ReferenceCountedPointer<class Image3uint8>& im) {
|
||||
return fromArray(im->getCArray(), im->width(), im->height(), im->wrapMode());
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromImage1(const ReferenceCountedPointer<Image1>& im) {
|
||||
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
|
||||
out->copyArray(im->getCArray(), im->width(), im->height());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Type(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename, fmt);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image1uint8::Ref Image1uint8::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyArray(const Color3uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].value = (src[i].r + src[i].g + src[i].b) / 3;
|
||||
}
|
||||
}
|
||||
|
||||
void Image1uint8::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1uint8(Color1(src[i].average()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyArray(const Color1uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), ptr, w * h);
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1uint8(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyArray(const Color4uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].value = (ptr[i].r + ptr[i].g + ptr[i].b) / 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image1uint8::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color1uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color1uint8(Color1(src[i].rgb().average()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image1uint8::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 1);
|
||||
System::memcpy(im.byte(), getCArray(), width() * height());
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* Image1uint8::format() const {
|
||||
return ImageFormat::L8();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
225
dep/src/g3dlite/Image3.cpp
Normal file
225
dep/src/g3dlite/Image3.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
@file Image3.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2007-01-31
|
||||
*/
|
||||
|
||||
|
||||
#include "G3D/Image3.h"
|
||||
#include "G3D/Image3uint8.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image3::Image3(int w, int h, WrapMode wrap) : Map2D<Color3, Color3>(w, h, wrap) {
|
||||
setAll(Color3::black());
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromImage3uint8(const ReferenceCountedPointer<Image3uint8>& im) {
|
||||
Ref out = createEmpty(im->wrapMode());
|
||||
out->resize(im->width(), im->height());
|
||||
|
||||
int N = im->width() * im->height();
|
||||
const Color3uint8* src = reinterpret_cast<Color3uint8*>(im->getCArray());
|
||||
for (int i = 0; i < N; ++i) {
|
||||
out->data[i] = Color3(src[i]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Image3(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename, fmt);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image3::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3::Ref Image3::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color3uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color3* dst = data.getCArray();
|
||||
// Convert int8 -> float
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color3(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color4uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color3* dst = data.getCArray();
|
||||
|
||||
// Strip alpha and convert
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color3(src[i].rgb());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), src, w * h * sizeof(Color3));
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color3* dst = data.getCArray();
|
||||
|
||||
// Strip alpha
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = src[i].rgb();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color1uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = Color1(src[i]).value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = src[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image3::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 3);
|
||||
|
||||
int N = im.width() * im.height();
|
||||
Color3uint8* dst = im.pixel3();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color3uint8(data[i]);
|
||||
}
|
||||
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* Image3::format() const {
|
||||
return ImageFormat::RGB32F();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
225
dep/src/g3dlite/Image3uint8.cpp
Normal file
225
dep/src/g3dlite/Image3uint8.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
@file Image3uint8.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2008-01-08
|
||||
*/
|
||||
|
||||
#include "G3D/Image1uint8.h"
|
||||
#include "G3D/Image3uint8.h"
|
||||
#include "G3D/Image3.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromImage1uint8(const ReferenceCountedPointer<class Image1uint8>& im) {
|
||||
return fromArray(im->getCArray(), im->width(), im->height(), im->wrapMode());
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Image3uint8(int w, int h, WrapMode wrap) : Map2D<Color3uint8>(w, h, wrap) {
|
||||
setAll(Color3::black());
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromImage3(const ReferenceCountedPointer<Image3>& im) {
|
||||
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
|
||||
out->copyArray(im->getCArray(), im->width(), im->height());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Type(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename, fmt);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image3uint8::Ref Image3uint8::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyArray(const Color1uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = src[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
void Image3uint8::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = Color1uint8(src[i]).value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyArray(const Color3uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), ptr, w * h * 3);
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color3uint8(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyArray(const Color4uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
// Copy 3/4 bytes
|
||||
GImage::RGBAtoRGB((const uint8*)ptr, (uint8*)getCArray(), w * h);
|
||||
}
|
||||
|
||||
|
||||
void Image3uint8::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color3uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color3uint8(src[i].rgb());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image3uint8::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 3);
|
||||
System::memcpy(im.byte(), getCArray(), width() * height() * 3);
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
|
||||
ReferenceCountedPointer<class Image1uint8> Image3uint8::getChannel(int c) const {
|
||||
debugAssert(c >= 0 && c <= 2);
|
||||
|
||||
Image1uint8Ref dst = Image1uint8::createEmpty(width(), height(), wrapMode());
|
||||
const Color3uint8* srcArray = getCArray();
|
||||
Color1uint8* dstArray = dst->getCArray();
|
||||
|
||||
const int N = width() * height();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dstArray[i] = Color1uint8(srcArray[i][c]);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* Image3uint8::format() const {
|
||||
return ImageFormat::RGB8();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
226
dep/src/g3dlite/Image4.cpp
Normal file
226
dep/src/g3dlite/Image4.cpp
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
/**
|
||||
@file Image4.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2008-07-27
|
||||
*/
|
||||
|
||||
|
||||
#include "G3D/Image4.h"
|
||||
#include "G3D/Image4uint8.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color3.h"
|
||||
#include "G3D/Color3uint8.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image4::Image4(int w, int h, WrapMode wrap) : Map2D<Color4, Color4>(w, h, wrap) {
|
||||
setAll(Color4::zero());
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromImage4uint8(const ReferenceCountedPointer<Image4uint8>& im) {
|
||||
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
|
||||
out->resize(im->width(), im->height());
|
||||
|
||||
int N = im->width() * im->height();
|
||||
const Color4uint8* src = reinterpret_cast<Color4uint8*>(im->getCArray());
|
||||
for (int i = 0; i < N; ++i) {
|
||||
out->data[i] = Color4(src[i]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Type(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image4::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4::Ref Image4::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color4uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color4* dst = data.getCArray();
|
||||
// Convert int8 -> float
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color3uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color4* dst = data.getCArray();
|
||||
|
||||
// Add alpha and convert
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4(Color3(src[i]), 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), src, w * h * sizeof(Color4));
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
int N = w * h;
|
||||
Color4* dst = data.getCArray();
|
||||
|
||||
// Add alpha
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4(src[i], 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color1uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = Color1(src[i]).value;
|
||||
dst[i].a = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = src[i].value;
|
||||
dst[i].a = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image4::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 4);
|
||||
|
||||
int N = im.width() * im.height();
|
||||
Color4uint8* dst = im.pixel4();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4uint8(data[i]);
|
||||
}
|
||||
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
const ImageFormat* Image4::format() const {
|
||||
return ImageFormat::RGBA32F();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
222
dep/src/g3dlite/Image4uint8.cpp
Normal file
222
dep/src/g3dlite/Image4uint8.cpp
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/**
|
||||
@file Image4uint8.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-01-31
|
||||
@edited 2008-07-31
|
||||
*/
|
||||
|
||||
#include "G3D/Image4uint8.h"
|
||||
#include "G3D/Image4.h"
|
||||
#include "G3D/Image3uint8.h"
|
||||
#include "G3D/Image3.h"
|
||||
#include "G3D/GImage.h"
|
||||
#include "G3D/Color1.h"
|
||||
#include "G3D/Color1uint8.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Image4uint8::Image4uint8(int w, int h, WrapMode wrap) : Map2D<Color4uint8, Color4>(w, h, wrap) {
|
||||
setAll(Color4::zero());
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromGImage(const GImage& im, WrapMode wrap) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
return fromArray(im.pixel1(), im.width(), im.height(), wrap);
|
||||
|
||||
case 3:
|
||||
return fromArray(im.pixel3(), im.width(), im.height(), wrap);
|
||||
|
||||
case 4:
|
||||
return fromArray(im.pixel4(), im.width(), im.height(), wrap);
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromImage4(const ReferenceCountedPointer<Image4>& im) {
|
||||
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
|
||||
out->copyArray(im->getCArray(), im->width(), im->height());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::createEmpty(int width, int height, WrapMode wrap) {
|
||||
return new Type(width, height, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::createEmpty(WrapMode wrap) {
|
||||
return createEmpty(0, 0, wrap);
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->load(filename, fmt);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Image4uint8::Ref Image4uint8::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
|
||||
Ref out = createEmpty(wrap);
|
||||
out->copyArray(ptr, w, h);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::load(const std::string& filename, GImage::Format fmt) {
|
||||
copyGImage(GImage(filename, fmt));
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyGImage(const GImage& im) {
|
||||
switch (im.channels()) {
|
||||
case 1:
|
||||
copyArray(im.pixel1(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
copyArray(im.pixel3(), im.width(), im.height());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
copyArray(im.pixel4(), im.width(), im.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyArray(const Color1uint8* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = src[i].value;
|
||||
dst[i].a = 255;
|
||||
}
|
||||
}
|
||||
|
||||
void Image4uint8::copyArray(const Color1* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i].r = dst[i].g = dst[i].b = Color1uint8(src[i]).value;
|
||||
dst[i].a = 255;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyArray(const Color4uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
System::memcpy(getCArray(), ptr, w * h * 4);
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyArray(const Color4* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4uint8(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyArray(const Color3uint8* ptr, int w, int h) {
|
||||
resize(w, h);
|
||||
|
||||
GImage::RGBtoRGBA((const uint8*)ptr, (uint8*)getCArray(), w * h);
|
||||
}
|
||||
|
||||
|
||||
void Image4uint8::copyArray(const Color3* src, int w, int h) {
|
||||
resize(w, h);
|
||||
int N = w * h;
|
||||
|
||||
Color4uint8* dst = getCArray();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dst[i] = Color4uint8(Color4(src[i], 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Saves in any of the formats supported by G3D::GImage. */
|
||||
void Image4uint8::save(const std::string& filename, GImage::Format fmt) {
|
||||
GImage im(width(), height(), 4);
|
||||
System::memcpy(im.byte(), getCArray(), width() * height() * 4);
|
||||
im.save(filename, fmt);
|
||||
}
|
||||
|
||||
|
||||
ReferenceCountedPointer<class Image1uint8> Image4uint8::getChannel(int c) const {
|
||||
debugAssert(c >= 0 && c <= 3);
|
||||
|
||||
Image1uint8Ref dst = Image1uint8::createEmpty(width(), height(), wrapMode());
|
||||
const Color4uint8* srcArray = getCArray();
|
||||
Color1uint8* dstArray = dst->getCArray();
|
||||
|
||||
const int N = width() * height();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
dstArray[i] = Color1uint8(srcArray[i][c]);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* Image4uint8::format() const {
|
||||
return ImageFormat::RGBA8();
|
||||
}
|
||||
|
||||
} // G3D
|
||||
567
dep/src/g3dlite/ImageFormat.cpp
Normal file
567
dep/src/g3dlite/ImageFormat.cpp
Normal file
|
|
@ -0,0 +1,567 @@
|
|||
/**
|
||||
@file ImageFormat.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-05-23
|
||||
@edited 2009-12-10
|
||||
*/
|
||||
|
||||
#include "GLG3D/glheaders.h"
|
||||
#include "G3D/ImageFormat.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
ImageFormat::ImageFormat(
|
||||
int _numComponents,
|
||||
bool _compressed,
|
||||
int _glFormat,
|
||||
int _glBaseFormat,
|
||||
int _luminanceBits,
|
||||
int _alphaBits,
|
||||
int _redBits,
|
||||
int _greenBits,
|
||||
int _blueBits,
|
||||
int _depthBits,
|
||||
int _stencilBits,
|
||||
int _hardwareBitsPerTexel,
|
||||
int _packedBitsPerTexel,
|
||||
int glDataFormat,
|
||||
bool _opaque,
|
||||
bool _floatingPoint,
|
||||
Code _code,
|
||||
ColorSpace _colorSpace,
|
||||
BayerPattern _bayerPattern) :
|
||||
|
||||
numComponents(_numComponents),
|
||||
compressed(_compressed),
|
||||
code(_code),
|
||||
colorSpace(_colorSpace),
|
||||
bayerPattern(_bayerPattern),
|
||||
openGLFormat(_glFormat),
|
||||
openGLBaseFormat(_glBaseFormat),
|
||||
luminanceBits(_luminanceBits),
|
||||
alphaBits(_alphaBits),
|
||||
redBits(_redBits),
|
||||
greenBits(_greenBits),
|
||||
blueBits(_blueBits),
|
||||
stencilBits(_stencilBits),
|
||||
depthBits(_depthBits),
|
||||
cpuBitsPerPixel(_packedBitsPerTexel),
|
||||
packedBitsPerTexel(_packedBitsPerTexel),
|
||||
openGLBitsPerPixel(_hardwareBitsPerTexel),
|
||||
hardwareBitsPerTexel(_hardwareBitsPerTexel),
|
||||
openGLDataFormat(glDataFormat),
|
||||
opaque(_opaque),
|
||||
floatingPoint(_floatingPoint) {
|
||||
|
||||
debugAssert(_packedBitsPerTexel <= _hardwareBitsPerTexel);
|
||||
}
|
||||
|
||||
const ImageFormat* ImageFormat::depth(int depthBits) {
|
||||
|
||||
switch (depthBits) {
|
||||
case 16:
|
||||
return DEPTH16();
|
||||
|
||||
case 24:
|
||||
return DEPTH24();
|
||||
|
||||
case 32:
|
||||
return DEPTH32();
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Depth must be 16, 24, or 32.");
|
||||
return DEPTH32();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* ImageFormat::stencil(int bits) {
|
||||
switch (bits) {
|
||||
case 1:
|
||||
return STENCIL1();
|
||||
|
||||
case 4:
|
||||
return STENCIL4();
|
||||
|
||||
case 8:
|
||||
return STENCIL8();
|
||||
|
||||
case 16:
|
||||
return STENCIL16();
|
||||
|
||||
default:
|
||||
debugAssertM(false, "Stencil must be 1, 4, 8 or 16.");
|
||||
return STENCIL16();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const std::string nameArray[] =
|
||||
{
|
||||
"L8",
|
||||
"L16",
|
||||
"L16F",
|
||||
"L32F",
|
||||
|
||||
"A8",
|
||||
"A16",
|
||||
"A16F",
|
||||
"A32F",
|
||||
|
||||
"LA4",
|
||||
"LA8",
|
||||
"LA16",
|
||||
"LA16F",
|
||||
"LA32F",
|
||||
|
||||
"RGB5",
|
||||
"RGB5A1",
|
||||
"RGB8",
|
||||
"RGB10",
|
||||
"RGB10A2",
|
||||
"RGB16",
|
||||
"RGB16F",
|
||||
"RGB32F",
|
||||
"R11G11B10F",
|
||||
"RGB9E10F",
|
||||
|
||||
"RGB8I",
|
||||
"RGB8UI",
|
||||
|
||||
"ARGB8",
|
||||
"BGR8",
|
||||
|
||||
"RG8",
|
||||
"RG8I",
|
||||
"RG8UI",
|
||||
|
||||
"RGBA8",
|
||||
"RGBA16",
|
||||
"RGBA16F",
|
||||
"RGBA32F",
|
||||
|
||||
"RGBA32UI",
|
||||
|
||||
"BAYER_RGGB8",
|
||||
"BAYER_GRBG8",
|
||||
"BAYER_GBRG8",
|
||||
"BAYER_BGGR8",
|
||||
"BAYER_RGGB32F",
|
||||
"BAYER_GRBG32F",
|
||||
"BAYER_GBRG32F",
|
||||
"BAYER_BGGR32F",
|
||||
|
||||
"HSV8",
|
||||
"HSV32F",
|
||||
|
||||
"YUV420_PLANAR",
|
||||
"YUV422",
|
||||
"YUV444",
|
||||
|
||||
"RGB_DXT1",
|
||||
"RGBA_DXT1",
|
||||
"RGBA_DXT3",
|
||||
"RGBA_DXT5",
|
||||
|
||||
"SRGB8",
|
||||
"SRGBA8",
|
||||
|
||||
"SL8",
|
||||
"SLA8",
|
||||
|
||||
"SRGB_DXT1",
|
||||
"SRGBA_DXT1",
|
||||
"SRGBA_DXT3",
|
||||
"SRGBA_DXT5",
|
||||
|
||||
"DEPTH16",
|
||||
"DEPTH24",
|
||||
"DEPTH32",
|
||||
"DEPTH32F",
|
||||
|
||||
"STENCIL1",
|
||||
"STENCIL4",
|
||||
"STENCIL8",
|
||||
"STENCIL16",
|
||||
|
||||
"DEPTH24_STENCIL8",
|
||||
""
|
||||
};
|
||||
|
||||
const std::string& ImageFormat::name() const {
|
||||
debugAssert(code < CODE_NUM);
|
||||
return nameArray[code];
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* ImageFormat::fromString(const std::string& s) {
|
||||
|
||||
for (int i = 0; ! nameArray[i].empty(); ++i) {
|
||||
if (s == nameArray[i]) {
|
||||
return fromCode(ImageFormat::Code(i));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
|
||||
switch (code) {
|
||||
case ImageFormat::CODE_L8:
|
||||
return ImageFormat::L8();
|
||||
|
||||
case ImageFormat::CODE_L16:
|
||||
return ImageFormat::L16();
|
||||
|
||||
case ImageFormat::CODE_L16F:
|
||||
return ImageFormat::L16F();
|
||||
|
||||
case ImageFormat::CODE_L32F:
|
||||
return ImageFormat::L32F();
|
||||
|
||||
case ImageFormat::CODE_A8:
|
||||
return ImageFormat::A8();
|
||||
|
||||
case ImageFormat::CODE_A16:
|
||||
return ImageFormat::A16();
|
||||
|
||||
case ImageFormat::CODE_A16F:
|
||||
return ImageFormat::A16F();
|
||||
|
||||
case ImageFormat::CODE_A32F:
|
||||
return ImageFormat::A32F();
|
||||
|
||||
case ImageFormat::CODE_LA4:
|
||||
return ImageFormat::LA4();
|
||||
|
||||
case ImageFormat::CODE_LA8:
|
||||
return ImageFormat::LA8();
|
||||
|
||||
case ImageFormat::CODE_LA16:
|
||||
return ImageFormat::LA16();
|
||||
|
||||
case ImageFormat::CODE_LA16F:
|
||||
return ImageFormat::LA16F();
|
||||
break;
|
||||
case ImageFormat::CODE_LA32F:
|
||||
return ImageFormat::LA32F();
|
||||
|
||||
case ImageFormat::CODE_RGB5:
|
||||
return ImageFormat::RGB5();
|
||||
|
||||
case ImageFormat::CODE_RGB5A1:
|
||||
return ImageFormat::RGB5A1();
|
||||
|
||||
case ImageFormat::CODE_RGB8:
|
||||
return ImageFormat::RGB8();
|
||||
|
||||
case ImageFormat::CODE_RGB10:
|
||||
return ImageFormat::RGB10();
|
||||
|
||||
case ImageFormat::CODE_RGB10A2:
|
||||
return ImageFormat::RGB10A2();
|
||||
|
||||
case ImageFormat::CODE_RGB16:
|
||||
return ImageFormat::RGB16();
|
||||
|
||||
case ImageFormat::CODE_RGB32F:
|
||||
return ImageFormat::RGB32F();
|
||||
|
||||
case ImageFormat::CODE_R11G11B10F:
|
||||
return ImageFormat::R11G11B10F();
|
||||
|
||||
case ImageFormat::CODE_RGB9E5F:
|
||||
return ImageFormat::RGB9E5F();
|
||||
|
||||
case ImageFormat::CODE_RGB8I:
|
||||
return ImageFormat::RGB8I();
|
||||
|
||||
case ImageFormat::CODE_RGB8UI:
|
||||
return ImageFormat::RGB8UI();
|
||||
|
||||
case ImageFormat::CODE_ARGB8:
|
||||
return NULL;
|
||||
|
||||
case ImageFormat::CODE_BGR8:
|
||||
return ImageFormat::BGR8();
|
||||
|
||||
case ImageFormat::CODE_RG8:
|
||||
return ImageFormat::RG8();
|
||||
|
||||
case ImageFormat::CODE_RG8I:
|
||||
return ImageFormat::RG8I();
|
||||
|
||||
case ImageFormat::CODE_RG8UI:
|
||||
return ImageFormat::RG8UI();
|
||||
|
||||
case ImageFormat::CODE_RGBA8:
|
||||
return ImageFormat::RGBA8();
|
||||
|
||||
case ImageFormat::CODE_RGBA16:
|
||||
return ImageFormat::RGBA16();
|
||||
|
||||
case ImageFormat::CODE_RGBA16F:
|
||||
return ImageFormat::RGBA16F();
|
||||
|
||||
case ImageFormat::CODE_RGBA32F:
|
||||
return ImageFormat::RGBA32F();
|
||||
|
||||
case ImageFormat::CODE_RGBA32UI:
|
||||
return ImageFormat::RGBA32UI();
|
||||
|
||||
case ImageFormat::CODE_BAYER_RGGB8:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_GRBG8:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_GBRG8:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_BGGR8:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_RGGB32F:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_GRBG32F:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_GBRG32F:
|
||||
// TODO
|
||||
case ImageFormat::CODE_BAYER_BGGR32F:
|
||||
// TODO
|
||||
|
||||
case ImageFormat::CODE_HSV8:
|
||||
// TODO
|
||||
case ImageFormat::CODE_HSV32F:
|
||||
// TODO
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_RGB_DXT1:
|
||||
return ImageFormat::RGB_DXT1();
|
||||
break;
|
||||
case ImageFormat::CODE_RGBA_DXT1:
|
||||
return ImageFormat::RGBA_DXT1();
|
||||
break;
|
||||
case ImageFormat::CODE_RGBA_DXT3:
|
||||
return ImageFormat::RGBA_DXT3();
|
||||
break;
|
||||
case ImageFormat::CODE_RGBA_DXT5:
|
||||
return ImageFormat::RGBA_DXT5();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGB8:
|
||||
return ImageFormat::SRGB8();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGBA8:
|
||||
return ImageFormat::SRGBA8();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SL8:
|
||||
return ImageFormat::SL8();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SLA8:
|
||||
return ImageFormat::SLA8();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGB_DXT1:
|
||||
return ImageFormat::SRGB_DXT1();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGBA_DXT1:
|
||||
return ImageFormat::SRGBA_DXT1();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGBA_DXT3:
|
||||
return ImageFormat::SRGBA_DXT3();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_SRGBA_DXT5:
|
||||
return ImageFormat::SRGBA_DXT5();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_DEPTH16:
|
||||
return ImageFormat::DEPTH16();
|
||||
break;
|
||||
case ImageFormat::CODE_DEPTH24:
|
||||
return ImageFormat::DEPTH24();
|
||||
break;
|
||||
case ImageFormat::CODE_DEPTH32:
|
||||
return ImageFormat::DEPTH32();
|
||||
break;
|
||||
case ImageFormat::CODE_DEPTH32F:
|
||||
return ImageFormat::DEPTH32F();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_STENCIL1:
|
||||
return ImageFormat::STENCIL1();
|
||||
break;
|
||||
case ImageFormat::CODE_STENCIL4:
|
||||
return ImageFormat::STENCIL4();
|
||||
break;
|
||||
case ImageFormat::CODE_STENCIL8:
|
||||
return ImageFormat::STENCIL8();
|
||||
break;
|
||||
case ImageFormat::CODE_STENCIL16:
|
||||
return ImageFormat::STENCIL16();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_DEPTH24_STENCIL8:
|
||||
return ImageFormat::DEPTH24_STENCIL8();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_YUV420_PLANAR:
|
||||
return ImageFormat::YUV420_PLANAR();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_YUV422:
|
||||
return ImageFormat::YUV422();
|
||||
break;
|
||||
|
||||
case ImageFormat::CODE_YUV444:
|
||||
return ImageFormat::YUV444();
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper variables for defining texture formats
|
||||
|
||||
// Is floating point format
|
||||
static const bool FLOAT_FORMAT = true;
|
||||
static const bool INT_FORMAT = false;
|
||||
|
||||
// Is opaque format (no alpha)
|
||||
static const bool OPAQUE_FORMAT = true;
|
||||
static const bool CLEAR_FORMAT = false;
|
||||
|
||||
// Is compressed format (not raw component data)
|
||||
static const bool COMP_FORMAT = true;
|
||||
static const bool UNCOMP_FORMAT = false;
|
||||
|
||||
#define DEFINE_TEXTUREFORMAT_METHOD(enumname, cmpnts, cmprssd, glf, glbf, lb, ab, rb, gb, bb, db, sb, hbpt, pbpt, gldf, opq, fp, code, cs) \
|
||||
const ImageFormat* ImageFormat::enumname() { \
|
||||
static const ImageFormat format(cmpnts, cmprssd, glf, glbf, lb, ab, rb, gb, bb, db, sb, hbpt, pbpt, gldf, opq, fp, code, cs); \
|
||||
return &format; }
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(L8, 1, UNCOMP_FORMAT, GL_LUMINANCE8, GL_LUMINANCE, 8, 0, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, CODE_L8, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(L16, 1, UNCOMP_FORMAT, GL_LUMINANCE16, GL_LUMINANCE, 16, 0, 0, 0, 0, 0, 0, 16, 16,GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INT_FORMAT, CODE_L16, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(L16F, 1, UNCOMP_FORMAT, GL_LUMINANCE16F_ARB,GL_LUMINANCE, 16, 0, 0, 0, 0, 0, 0, 16, 16, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, CODE_L16F, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(L32F, 1, UNCOMP_FORMAT, GL_LUMINANCE32F_ARB,GL_LUMINANCE, 32, 0, 0, 0, 0, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, CODE_L32F, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(A8, 1, UNCOMP_FORMAT, GL_ALPHA8, GL_ALPHA, 0, 8, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, CODE_A8, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(A16, 1, UNCOMP_FORMAT, GL_ALPHA16, GL_ALPHA, 0, 16, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, CODE_A16, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(A16F, 1, UNCOMP_FORMAT, GL_ALPHA16F_ARB, GL_ALPHA, 0, 16, 0, 0, 0, 0, 0, 16, 16, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, CODE_A16F, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(A32F, 1, UNCOMP_FORMAT, GL_ALPHA32F_ARB, GL_ALPHA, 0, 32, 0, 0, 0, 0, 0, 32, 32, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, CODE_A32F, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(LA4, 2, UNCOMP_FORMAT, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE_ALPHA, 4, 4, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, CODE_LA4, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(LA8, 2, UNCOMP_FORMAT, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, 8, 8, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, CODE_LA8, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(LA16, 2, UNCOMP_FORMAT, GL_LUMINANCE16_ALPHA16, GL_LUMINANCE_ALPHA, 16, 16, 0, 0, 0, 0, 0, 16*2, 16*2, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, CODE_LA16, COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(LA16F, 2, UNCOMP_FORMAT, GL_LUMINANCE_ALPHA16F_ARB, GL_LUMINANCE_ALPHA, 16, 16, 0, 0, 0, 0, 0, 16*2, 16*2, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_LA16F, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(LA32F, 2, UNCOMP_FORMAT, GL_LUMINANCE_ALPHA32F_ARB, GL_LUMINANCE_ALPHA, 32, 32, 0, 0, 0, 0, 0, 32*2, 32*2, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_LA32F, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(BGR8, 3, UNCOMP_FORMAT, GL_RGB8, GL_BGR, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_BGR8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8, 2, UNCOMP_FORMAT, GL_RG8, GL_RG, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8I, 2, UNCOMP_FORMAT, GL_RG8I, GL_RG, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8I, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8UI, 2, UNCOMP_FORMAT, GL_RG8UI, GL_RG, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB5, 3, UNCOMP_FORMAT, GL_RGB5, GL_RGBA, 0, 0, 5, 5, 5, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB5, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB5A1, 4, UNCOMP_FORMAT, GL_RGB5_A1, GL_RGBA, 0, 1, 5, 5, 5, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB5A1, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB8, 3, UNCOMP_FORMAT, GL_RGB8, GL_RGB, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB10, 3, UNCOMP_FORMAT, GL_RGB10, GL_RGB, 0, 0, 10, 10, 10, 0, 0, 32, 10*3, GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB10, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB10A2, 4, UNCOMP_FORMAT, GL_RGB10_A2, GL_RGBA, 0, 2, 10, 10, 10, 0, 0, 32, 32, GL_UNSIGNED_INT_10_10_10_2, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB10A2, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB16, 3, UNCOMP_FORMAT, GL_RGB16, GL_RGB, 0, 0, 16, 16, 16, 0, 0, 16*3, 16*3, GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB16, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB16F, 3, UNCOMP_FORMAT, GL_RGB16F_ARB, GL_RGB, 0, 0, 16, 16, 16, 0, 0, 16*3, 16*3, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGB16F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB32F, 3, UNCOMP_FORMAT, GL_RGB32F_ARB, GL_RGB, 0, 0, 32, 32, 32, 0, 0, 32*3, 32*3, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGB32F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA8, 4, UNCOMP_FORMAT, GL_RGBA8, GL_RGBA, 0, 8, 8, 8, 8, 0, 0, 32, 32, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA16, 4, UNCOMP_FORMAT, GL_RGBA16, GL_RGBA, 0, 16, 16, 16, 16, 0, 0, 16*4, 16*4, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA16, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA16F, 4, UNCOMP_FORMAT, GL_RGBA16F_ARB, GL_RGBA, 0, 16, 16, 16, 16, 0, 0, 16*4, 16*4, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGBA16F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA32F, 4, UNCOMP_FORMAT, GL_RGBA32F_ARB, GL_RGBA, 0, 32, 32, 32, 32, 0, 0, 32*4, 32*4, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGBA32F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA32UI, 4, UNCOMP_FORMAT, GL_RGBA32UI, GL_RGBA, 0, 32, 32, 32, 32, 0, 0, 32*4, 32*4, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA32UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
// Unsigned
|
||||
DEFINE_TEXTUREFORMAT_METHOD(R11G11B10F, 3, UNCOMP_FORMAT, GL_R11F_G11F_B10F_EXT, GL_RGB, 0, 0, 11, 11, 10, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_R11G11B10F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
// Unsigned
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB9E5F, 3, UNCOMP_FORMAT, GL_RGB9_E5_EXT, GL_RGB, 0, 0, 14, 14, 14, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGB9E5F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB8I, 3, UNCOMP_FORMAT, GL_RGB8I_EXT, GL_RGB, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8I, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB8UI, 3, UNCOMP_FORMAT, GL_RGB8UI_EXT, GL_RGB, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB_DXT1, 3, COMP_FORMAT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB_DXT1, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA_DXT1, 4, COMP_FORMAT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA_DXT1, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA_DXT3, 4, COMP_FORMAT, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 128, 128, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA_DXT3, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA_DXT5, 4, COMP_FORMAT, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 128, 128, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA_DXT5, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGB8, 3, UNCOMP_FORMAT, GL_SRGB8, GL_RGB, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGB8, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGBA8, 4, UNCOMP_FORMAT, GL_SRGB8_ALPHA8, GL_RGBA, 0, 8, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGBA8, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SL8, 1, UNCOMP_FORMAT, GL_SLUMINANCE8, GL_LUMINANCE, 8, 0, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_SL8, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SLA8, 2, UNCOMP_FORMAT, GL_SLUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, 8, 8, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_SLA8, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGB_DXT1, 3, COMP_FORMAT, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGB, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGB_DXT1, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGBA_DXT1, 4, COMP_FORMAT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGBA_DXT1, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGBA_DXT3, 4, COMP_FORMAT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 128, 128, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGBA_DXT3, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(SRGBA_DXT5, 4, COMP_FORMAT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 128, 128, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_SRGBA_DXT5, ImageFormat::COLOR_SPACE_SRGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(DEPTH16, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT16_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 16, 0, 16, 16, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH16, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(DEPTH24, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT24_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 24, 0, 32, 24, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH24, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(DEPTH32, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT32_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 32, 0, 32, 32, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH32, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(DEPTH32F, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT32_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 32, 0, 32, 32, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_DEPTH32F, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
// These formats are for use with Renderbuffers only!
|
||||
DEFINE_TEXTUREFORMAT_METHOD(STENCIL1, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX1_EXT, GL_STENCIL_INDEX, 0, 0, 0, 0, 0, 0, 1, 1, 1, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL1, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(STENCIL4, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX4_EXT, GL_STENCIL_INDEX, 0, 0, 0, 0, 0, 0, 4, 4, 4, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL4, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(STENCIL8, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX8_EXT, GL_STENCIL_INDEX, 0, 0, 0, 0, 0, 0, 8, 8, 8, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL8, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(STENCIL16, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX16_EXT, GL_STENCIL_INDEX, 0, 0, 0, 0, 0, 0, 16, 16, 16, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL16, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(DEPTH24_STENCIL8, 2, UNCOMP_FORMAT, GL_DEPTH24_STENCIL8_EXT, GL_DEPTH_STENCIL_EXT,0, 0, 0, 0, 0, 24, 8, 32, 32, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH24_STENCIL8, ImageFormat::COLOR_SPACE_NONE);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(YUV420_PLANAR, 3, UNCOMP_FORMAT, GL_NONE, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 12, 12, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_YUV420_PLANAR, ImageFormat::COLOR_SPACE_YUV);
|
||||
DEFINE_TEXTUREFORMAT_METHOD(YUV422, 3, UNCOMP_FORMAT, GL_NONE, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_YUV422, ImageFormat::COLOR_SPACE_YUV);
|
||||
DEFINE_TEXTUREFORMAT_METHOD(YUV444, 3, UNCOMP_FORMAT, GL_NONE, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 24, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_YUV444, ImageFormat::COLOR_SPACE_YUV);
|
||||
|
||||
}
|
||||
1307
dep/src/g3dlite/ImageFormat_convert.cpp
Normal file
1307
dep/src/g3dlite/ImageFormat_convert.cpp
Normal file
File diff suppressed because it is too large
Load diff
844
dep/src/g3dlite/Intersect.cpp
Normal file
844
dep/src/g3dlite/Intersect.cpp
Normal file
|
|
@ -0,0 +1,844 @@
|
|||
/**
|
||||
@file Intersect.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2009-06-29
|
||||
@edited 2009-06-29
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
|
||||
From the G3D Innovation Engine
|
||||
http://g3d.sf.net
|
||||
*/
|
||||
#include "G3D/Intersect.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Turn on fast floating-point optimizations
|
||||
#pragma float_control( push )
|
||||
#pragma fp_contract( on )
|
||||
#pragma fenv_access( off )
|
||||
#pragma float_control( except, off )
|
||||
#pragma float_control( precise, off )
|
||||
#endif
|
||||
|
||||
bool __fastcall Intersect::rayAABox(const Ray& ray, const AABox& box) {
|
||||
switch (ray.classification) {
|
||||
case Ray::MMM:
|
||||
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MMP:
|
||||
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MPM:
|
||||
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MPP:
|
||||
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PMM:
|
||||
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PMP:
|
||||
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PPM:
|
||||
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PPP:
|
||||
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::OMM:
|
||||
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::OMP:
|
||||
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::OPM:
|
||||
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::OPP:
|
||||
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MOM:
|
||||
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MOP:
|
||||
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::POM:
|
||||
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::POP:
|
||||
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MMO:
|
||||
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MPO:
|
||||
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PMO:
|
||||
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::PPO:
|
||||
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::MOO:
|
||||
|
||||
if((ray.m_origin.x < box.lo.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::POO:
|
||||
|
||||
if((ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Ray::OMO:
|
||||
|
||||
if((ray.m_origin.y < box.lo.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
)
|
||||
return false;
|
||||
|
||||
case Ray::OPO:
|
||||
|
||||
if((ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
)
|
||||
return false;
|
||||
|
||||
case Ray::OOM:
|
||||
|
||||
if((ray.m_origin.z < box.lo.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
)
|
||||
return false;
|
||||
|
||||
case Ray::OOP:
|
||||
|
||||
if((ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool __fastcall Intersect::rayAABox(const Ray& ray, const AABox& box, float& time) {
|
||||
|
||||
switch (ray.classification) {
|
||||
case Ray::MMM:
|
||||
{
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// compute the intersection distance
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::MMP:
|
||||
{
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::MPM:
|
||||
{
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::MPP:
|
||||
{
|
||||
if ((ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::PMM:
|
||||
{
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::PMP:
|
||||
{
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::PPM:
|
||||
{
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::PPP:
|
||||
{
|
||||
if ((ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OMM:
|
||||
{
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyk * box.lo.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.hi.z + ray.c_yz > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OMP:
|
||||
{
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyk * box.hi.z - box.hi.y + ray.c_zy > 0)
|
||||
|| (ray.kbyj * box.lo.y - box.lo.z + ray.c_yz < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OPM:
|
||||
{
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y > box.hi.y) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.jbyk * box.lo.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.hi.z + ray.c_yz > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OPP:
|
||||
{
|
||||
if((ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y > box.hi.y) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.jbyk * box.hi.z - box.lo.y + ray.c_zy < 0)
|
||||
|| (ray.kbyj * box.hi.y - box.lo.z + ray.c_yz < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::MOM:
|
||||
{
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.kbyi * box.lo.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::MOP:
|
||||
{
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.kbyi * box.lo.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.hi.x + ray.c_zx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::POM:
|
||||
{
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.z < box.lo.z)
|
||||
|| (ray.kbyi * box.hi.x - box.hi.z + ray.c_xz > 0)
|
||||
|| (ray.ibyk * box.lo.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::POP:
|
||||
{
|
||||
if((ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.kbyi * box.hi.x - box.lo.z + ray.c_xz < 0)
|
||||
|| (ray.ibyk * box.hi.z - box.lo.x + ray.c_zx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t2 = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
if (t2 > time) {
|
||||
time = t2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::MMO:
|
||||
{
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.y < box.lo.y)
|
||||
|| (ray.jbyi * box.lo.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.hi.x + ray.c_yx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::MPO:
|
||||
{
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.jbyi * box.lo.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.hi.x + ray.c_yx > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::PMO:
|
||||
{
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.y < box.lo.y)
|
||||
|| (ray.jbyi * box.hi.x - box.hi.y + ray.c_xy > 0)
|
||||
|| (ray.ibyj * box.lo.y - box.lo.x + ray.c_yx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::PPO:
|
||||
{
|
||||
if((ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x > box.hi.x) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.jbyi * box.hi.x - box.lo.y + ray.c_xy < 0)
|
||||
|| (ray.ibyj * box.hi.y - box.lo.x + ray.c_yx < 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
float t1 = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
if (t1 > time) {
|
||||
time = t1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::MOO:
|
||||
{
|
||||
if((ray.m_origin.x < box.lo.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::POO:
|
||||
{
|
||||
if ((ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.x - ray.m_origin.x) * ray.m_invDirection.x;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OMO:
|
||||
{
|
||||
if ((ray.m_origin.y < box.lo.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OPO:
|
||||
{
|
||||
if ((ray.m_origin.y > box.hi.y)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.z < box.lo.z) || (ray.m_origin.z > box.hi.z)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.y - ray.m_origin.y) * ray.m_invDirection.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case Ray::OOM:
|
||||
{
|
||||
if ((ray.m_origin.z < box.lo.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Ray::OOP:
|
||||
{
|
||||
if ((ray.m_origin.z > box.hi.z)
|
||||
|| (ray.m_origin.x < box.lo.x) || (ray.m_origin.x > box.hi.x)
|
||||
|| (ray.m_origin.y < box.lo.y) || (ray.m_origin.y > box.hi.y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = (box.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Turn off fast floating-point optimizations
|
||||
#pragma float_control( pop )
|
||||
#endif
|
||||
|
||||
}
|
||||
89
dep/src/g3dlite/Line.cpp
Normal file
89
dep/src/g3dlite/Line.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
@file Line.cpp
|
||||
|
||||
Line class
|
||||
|
||||
@maintainer Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2006-01-28
|
||||
*/
|
||||
|
||||
#include "G3D/Line.h"
|
||||
#include "G3D/Plane.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector3 Line::intersection(const Plane& plane) const {
|
||||
float d;
|
||||
Vector3 normal = plane.normal();
|
||||
plane.getEquation(normal, d);
|
||||
float rate = _direction.dot(normal);
|
||||
|
||||
if (rate == 0) {
|
||||
|
||||
return Vector3::inf();
|
||||
|
||||
} else {
|
||||
float t = -(d + _point.dot(normal)) / rate;
|
||||
|
||||
return _point + _direction * t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Line::Line(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Line::serialize(class BinaryOutput& b) const {
|
||||
_point.serialize(b);
|
||||
_direction.serialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Line::deserialize(class BinaryInput& b) {
|
||||
_point.deserialize(b);
|
||||
_direction.deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
Vector3 Line::closestPoint(const Vector3& pt) const {
|
||||
float t = _direction.dot(pt - _point);
|
||||
return _point + _direction * t;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Line::point() const {
|
||||
return _point;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Line::direction() const {
|
||||
return _direction;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Line::closestPoint(const Line& B, float& minDist) const {
|
||||
const Vector3& P1 = _point;
|
||||
const Vector3& U1 = _direction;
|
||||
|
||||
Vector3 P2 = B.point();
|
||||
Vector3 U2 = B.direction();
|
||||
|
||||
const Vector3& P21 = P2 - P1;
|
||||
const Vector3& M = U2.cross(U1);
|
||||
float m2 = M.length();
|
||||
|
||||
Vector3 R = P21.cross(M) / m2;
|
||||
|
||||
float t1 = R.dot(U2);
|
||||
|
||||
minDist = abs(P21.dot(M)) / sqrt(m2);
|
||||
|
||||
return P1 + t1 * U1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
236
dep/src/g3dlite/LineSegment.cpp
Normal file
236
dep/src/g3dlite/LineSegment.cpp
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
/**
|
||||
@file LineSegment.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-02-08
|
||||
@edited 2008-02-02
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/LineSegment.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/debug.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
Vector3 LineSegment::closestPoint(const Vector3& p) const {
|
||||
|
||||
// The vector from the end of the capsule to the point in question.
|
||||
Vector3 v(p - _point);
|
||||
|
||||
// Projection of v onto the line segment scaled by
|
||||
// the length of direction.
|
||||
float t = direction.dot(v);
|
||||
|
||||
// Avoid some square roots. Derivation:
|
||||
// t/direction.length() <= direction.length()
|
||||
// t <= direction.squaredLength()
|
||||
|
||||
if ((t >= 0) && (t <= direction.squaredMagnitude())) {
|
||||
|
||||
// The point falls within the segment. Normalize direction,
|
||||
// divide t by the length of direction.
|
||||
return _point + direction * t / direction.squaredMagnitude();
|
||||
|
||||
} else {
|
||||
|
||||
// The point does not fall within the segment; see which end is closer.
|
||||
|
||||
// Distance from 0, squared
|
||||
float d0Squared = v.squaredMagnitude();
|
||||
|
||||
// Distance from 1, squared
|
||||
float d1Squared = (v - direction).squaredMagnitude();
|
||||
|
||||
if (d0Squared < d1Squared) {
|
||||
|
||||
// Point 0 is closer
|
||||
return _point;
|
||||
|
||||
} else {
|
||||
|
||||
// Point 1 is closer
|
||||
return _point + direction;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vector3 LineSegment::point(int i) const {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return _point;
|
||||
|
||||
case 1:
|
||||
return _point + direction;
|
||||
|
||||
default:
|
||||
debugAssertM(i == 0 || i == 1, "Argument to point must be 0 or 1");
|
||||
return _point;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LineSegment::intersectsSolidSphere(const class Sphere& s) const {
|
||||
return distanceSquared(s.center) <= square(s.radius);
|
||||
}
|
||||
|
||||
|
||||
LineSegment::LineSegment(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void LineSegment::serialize(class BinaryOutput& b) const {
|
||||
_point.serialize(b);
|
||||
direction.serialize(b);
|
||||
}
|
||||
|
||||
|
||||
void LineSegment::deserialize(class BinaryInput& b) {
|
||||
_point.deserialize(b);
|
||||
direction.deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
Vector3 LineSegment::randomPoint() const {
|
||||
return _point + uniformRandom(0, 1) * direction;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LineSegment2D LineSegment2D::fromTwoPoints(const Vector2& p0, const Vector2& p1) {
|
||||
LineSegment2D s;
|
||||
s.m_origin = p0;
|
||||
s.m_direction = p1 - p0;
|
||||
s.m_length = s.m_direction.length();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Vector2 LineSegment2D::point(int i) const {
|
||||
debugAssert(i == 0 || i == 1);
|
||||
if (i == 0) {
|
||||
return m_origin;
|
||||
} else {
|
||||
return m_direction + m_origin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector2 LineSegment2D::closestPoint(const Vector2& Q) const {
|
||||
// Two constants that appear in the result
|
||||
const Vector2 k1(m_origin - Q);
|
||||
const Vector2& k2 = m_direction;
|
||||
|
||||
if (fuzzyEq(m_length, 0)) {
|
||||
// This line segment has no length
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
// Time [0, 1] at which we hit the closest point travelling from p0 to p1.
|
||||
// Derivation can be obtained by minimizing the expression
|
||||
// ||P0 + (P1 - P0)t - Q||.
|
||||
const float t = -k1.dot(k2) / (m_length * m_length);
|
||||
|
||||
if (t < 0) {
|
||||
// Clipped to low end point
|
||||
return m_origin;
|
||||
} else if (t > 1) {
|
||||
// Clipped to high end point
|
||||
return m_origin + m_direction;
|
||||
} else {
|
||||
// Subsitute into the line equation to find
|
||||
// the point on the segment.
|
||||
return m_origin + k2 * t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float LineSegment2D::distance(const Vector2& p) const {
|
||||
Vector2 closest = closestPoint(p);
|
||||
return (closest - p).length();
|
||||
}
|
||||
|
||||
|
||||
float LineSegment2D::length() const {
|
||||
return m_length;
|
||||
}
|
||||
|
||||
|
||||
Vector2 LineSegment2D::intersection(const LineSegment2D& other) const {
|
||||
|
||||
if ((m_origin == other.m_origin) ||
|
||||
(m_origin == other.m_origin + other.m_direction)) {
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
if (m_origin + m_direction == other.m_origin) {
|
||||
return other.m_origin;
|
||||
}
|
||||
|
||||
// Note: Now that we've checked the endpoints, all other parallel lines can now be assumed
|
||||
// to not intersect (within numerical precision)
|
||||
|
||||
Vector2 dir1 = m_direction;
|
||||
Vector2 dir2 = other.m_direction;
|
||||
Vector2 origin1 = m_origin;
|
||||
Vector2 origin2 = other.m_origin;
|
||||
|
||||
if (dir1.x == 0) {
|
||||
// Avoid an upcoming divide by zero
|
||||
dir1 = dir1.yx();
|
||||
dir2 = dir2.yx();
|
||||
origin1 = origin1.yx();
|
||||
origin2 = origin2.yx();
|
||||
}
|
||||
|
||||
// t1 = ((other.m_origin.x - m_origin.x) + other.m_direction.x * t2) / m_direction.x
|
||||
//
|
||||
// ((other.m_origin.x - m_origin.x) + other.m_direction.x * t2) * m_direction.y / m_direction.x =
|
||||
// (other.m_origin.y - m_origin.y) + other.m_direction.y * t2
|
||||
//
|
||||
// m = m_direction.y / m_direction.x
|
||||
// d = other.m_origin - m_origin
|
||||
//
|
||||
// (d.x + other.m_direction.x * t2) * m = d.y + other.m_direction.y * t2
|
||||
//
|
||||
// d.x * m + other.m_direction.x * m * t2 = d.y + other.m_direction.y * t2
|
||||
//
|
||||
// d.x * m - d.y = (other.m_direction.y - other.m_direction.x * m) * t2
|
||||
//
|
||||
// (d.x * m - d.y) / (other.m_direction.y - other.m_direction.x * m) = t2
|
||||
//
|
||||
|
||||
Vector2 d = origin2 - origin1;
|
||||
float m = dir1.y / dir1.x;
|
||||
|
||||
float t2 = (d.x * m - d.y) / (dir2.y - dir2.x * m);
|
||||
if (! isFinite(t2)) {
|
||||
// Parallel lines: no intersection
|
||||
return Vector2::inf();
|
||||
}
|
||||
|
||||
if ((t2 < 0.0f) || (t2 > 1.0f)) {
|
||||
// Intersection occurs past the end of the line segments
|
||||
return Vector2::inf();
|
||||
}
|
||||
|
||||
float t1 = (d.x + dir2.x * t2) / dir1.x;
|
||||
if ((t1 < 0.0f) || (t1 > 1.0f)) {
|
||||
// Intersection occurs past the end of the line segments
|
||||
return Vector2::inf();
|
||||
}
|
||||
|
||||
// Return the intersection point (computed from non-transposed
|
||||
// variables even if we flipped above)
|
||||
return m_origin + m_direction * t1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
146
dep/src/g3dlite/Log.cpp
Normal file
146
dep/src/g3dlite/Log.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -33,7 +33,35 @@ libg3dlite_a_SOURCES = \
|
|||
System.cpp \
|
||||
Triangle.cpp \
|
||||
Vector3.cpp \
|
||||
Vector4.cpp
|
||||
Vector4.cpp \
|
||||
debugAssert.cpp \
|
||||
fileutils.cpp \
|
||||
g3dmath.cpp \
|
||||
g3dfnmatch.cpp \
|
||||
prompt.cpp \
|
||||
stringutils.cpp \
|
||||
Any.cpp \
|
||||
BinaryFormat.cpp \
|
||||
BinaryInput.cpp \
|
||||
BinaryOutput.cpp \
|
||||
Capsule.cpp \
|
||||
CollisionDetection.cpp \
|
||||
CoordinateFrame.cpp \
|
||||
Cylinder.cpp \
|
||||
Line.cpp \
|
||||
LineSegment.cpp \
|
||||
Log.cpp \
|
||||
Matrix4.cpp \
|
||||
MemoryManager.cpp \
|
||||
Quat.cpp \
|
||||
Random.cpp \
|
||||
Ray.cpp \
|
||||
ReferenceCount.cpp \
|
||||
Sphere.cpp \
|
||||
TextInput.cpp \
|
||||
TextOutput.cpp \
|
||||
UprightFrame.cpp \
|
||||
Vector2.cpp
|
||||
|
||||
EXTRA_DIST = \
|
||||
license.html
|
||||
|
|
|
|||
1802
dep/src/g3dlite/Matrix.cpp
Normal file
1802
dep/src/g3dlite/Matrix.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -6,21 +6,51 @@
|
|||
@author Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2006-04-06
|
||||
@edited 2009-11-15
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/format.h"
|
||||
#include <memory.h>
|
||||
#include <assert.h>
|
||||
#include "G3D/Matrix3.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Quat.h"
|
||||
#include "G3D/Any.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
const float Matrix3::EPSILON = 1e-06f;
|
||||
|
||||
Matrix3::Matrix3(const Any& any) {
|
||||
any.verifyName("Matrix3");
|
||||
any.verifyType(Any::ARRAY);
|
||||
any.verifySize(9);
|
||||
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
elt[r][c] = any[r * 3 + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Matrix3::operator Any() const {
|
||||
Any any(Any::ARRAY, "Matrix3");
|
||||
any.resize(9);
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
any[r * 3 + c] = elt[r][c];
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
const Matrix3& Matrix3::zero() {
|
||||
static Matrix3 m(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
return m;
|
||||
|
|
@ -31,13 +61,14 @@ const Matrix3& Matrix3::identity() {
|
|||
return m;
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
const Matrix3 Matrix3::ZERO(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
const Matrix3 Matrix3::IDENTITY(1, 0, 0, 0, 1, 0, 0, 0, 1);
|
||||
|
||||
const float Matrix3::ms_fSvdEpsilon = 1e-04f;
|
||||
const int Matrix3::ms_iSvdMaxIterations = 32;
|
||||
|
||||
Matrix3::Matrix3(BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
bool Matrix3::fuzzyEq(const Matrix3& b) const {
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
|
|
@ -50,10 +81,22 @@ bool Matrix3::fuzzyEq(const Matrix3& b) const {
|
|||
}
|
||||
|
||||
|
||||
bool Matrix3::isRightHanded() const{
|
||||
|
||||
const Vector3& X = column(0);
|
||||
const Vector3& Y = column(1);
|
||||
const Vector3& Z = column(2);
|
||||
|
||||
const Vector3& W = X.cross(Y);
|
||||
|
||||
return W.dot(Z) > 0.0f;
|
||||
}
|
||||
|
||||
|
||||
bool Matrix3::isOrthonormal() const {
|
||||
Vector3 X = getColumn(0);
|
||||
Vector3 Y = getColumn(1);
|
||||
Vector3 Z = getColumn(2);
|
||||
const Vector3& X = column(0);
|
||||
const Vector3& Y = column(1);
|
||||
const Vector3& Z = column(2);
|
||||
|
||||
return
|
||||
(G3D::fuzzyEq(X.dot(Y), 0.0f) &&
|
||||
|
|
@ -68,7 +111,8 @@ bool Matrix3::isOrthonormal() const {
|
|||
Matrix3::Matrix3(const Quat& _q) {
|
||||
// Implementation from Watt and Watt, pg 362
|
||||
// See also http://www.flipcode.com/documents/matrfaq.html#Q54
|
||||
Quat q = _q.unitize();
|
||||
Quat q = _q;
|
||||
q.unitize();
|
||||
float xx = 2.0f * q.x * q.x;
|
||||
float xy = 2.0f * q.x * q.y;
|
||||
float xz = 2.0f * q.x * q.z;
|
||||
|
|
@ -124,17 +168,40 @@ void Matrix3::set(
|
|||
}
|
||||
|
||||
|
||||
void Matrix3::deserialize(BinaryInput& b) {
|
||||
int r,c;
|
||||
for (c = 0; c < 3; ++c) {
|
||||
for (r = 0; r < 3; ++r) {
|
||||
elt[r][c] = b.readFloat32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Matrix3::serialize(BinaryOutput& b) const {
|
||||
int r,c;
|
||||
for (c = 0; c < 3; ++c) {
|
||||
for (r = 0; r < 3; ++r) {
|
||||
b.writeFloat32(elt[r][c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Vector3 Matrix3::getColumn (int iCol) const {
|
||||
Vector3 Matrix3::column (int iCol) const {
|
||||
assert((0 <= iCol) && (iCol < 3));
|
||||
return Vector3(elt[0][iCol], elt[1][iCol],
|
||||
elt[2][iCol]);
|
||||
}
|
||||
|
||||
Vector3 Matrix3::getRow (int iRow) const {
|
||||
return Vector3(elt[iRow][0], elt[iRow][1], elt[iRow][2]);
|
||||
|
||||
const Vector3& Matrix3::row (int iRow) const {
|
||||
assert((0 <= iRow) && (iRow < 3));
|
||||
return *reinterpret_cast<const Vector3*>(elt[iRow]);
|
||||
}
|
||||
|
||||
|
||||
void Matrix3::setColumn(int iCol, const Vector3 &vector) {
|
||||
debugAssert((iCol >= 0) && (iCol < 3));
|
||||
elt[0][iCol] = vector.x;
|
||||
|
|
@ -273,6 +340,21 @@ Matrix3 Matrix3::operator* (float fScalar) const {
|
|||
return kProd;
|
||||
}
|
||||
|
||||
Matrix3& Matrix3::operator/= (float fScalar) {
|
||||
return *this *= (1.0f / fScalar);
|
||||
}
|
||||
|
||||
Matrix3& Matrix3::operator*= (float fScalar) {
|
||||
|
||||
for (int iRow = 0; iRow < 3; iRow++) {
|
||||
for (int iCol = 0; iCol < 3; iCol++) {
|
||||
elt[iRow][iCol] *= fScalar;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Matrix3 operator* (double fScalar, const Matrix3& rkMatrix) {
|
||||
Matrix3 kProd;
|
||||
|
|
@ -918,6 +1000,97 @@ void Matrix3::qDUDecomposition (Matrix3& kQ,
|
|||
kU[2] = kR[1][2] / kD[1];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Matrix3::polarDecomposition(Matrix3 &R, Matrix3 &S) const{
|
||||
/*
|
||||
Polar decomposition of a matrix. Based on pseudocode from
|
||||
Nicholas J Higham, "Computing the Polar Decomposition -- with
|
||||
Applications Siam Journal of Science and Statistical Computing, Vol 7, No. 4,
|
||||
October 1986.
|
||||
|
||||
Decomposes A into R*S, where R is orthogonal and S is symmetric.
|
||||
|
||||
Ken Shoemake's "Matrix animation and polar decomposition"
|
||||
in Proceedings of the conference on Graphics interface '92
|
||||
seems to be better known in the world of graphics, but Higham's version
|
||||
uses a scaling constant that can lead to faster convergence than
|
||||
Shoemake's when the initial matrix is far from orthogonal.
|
||||
*/
|
||||
|
||||
Matrix3 X = *this;
|
||||
Matrix3 tmp = X.inverse();
|
||||
Matrix3 Xit = tmp.transpose();
|
||||
int iter = 0;
|
||||
|
||||
const int MAX_ITERS = 100;
|
||||
|
||||
const double eps = 50 * std::numeric_limits<float>::epsilon();
|
||||
const float BigEps = 50 * eps;
|
||||
|
||||
/* Higham suggests using OneNorm(Xit-X) < eps * OneNorm(X)
|
||||
* as the convergence criterion, but OneNorm(X) should quickly
|
||||
* settle down to something between 1 and 1.7, so just comparing
|
||||
* with eps seems sufficient.
|
||||
*--------------------------------------------------------------- */
|
||||
|
||||
double resid = X.diffOneNorm(Xit);
|
||||
while (resid > eps && iter < MAX_ITERS) {
|
||||
|
||||
tmp = X.inverse();
|
||||
Xit = tmp.transpose();
|
||||
|
||||
if (resid < BigEps) {
|
||||
// close enough use simple iteration
|
||||
X += Xit;
|
||||
X *= 0.5f;
|
||||
}
|
||||
else {
|
||||
// not close to convergence, compute acceleration factor
|
||||
float gamma = sqrt( sqrt(
|
||||
(Xit.l1Norm()* Xit.lInfNorm())/(X.l1Norm()*X.lInfNorm()) ) );
|
||||
|
||||
X *= 0.5f * gamma;
|
||||
tmp = Xit;
|
||||
tmp *= 0.5f / gamma;
|
||||
X += tmp;
|
||||
}
|
||||
|
||||
resid = X.diffOneNorm(Xit);
|
||||
iter++;
|
||||
}
|
||||
|
||||
R = X;
|
||||
tmp = R.transpose();
|
||||
|
||||
S = tmp * (*this);
|
||||
|
||||
// S := (S + S^t)/2 one more time to make sure it is symmetric
|
||||
tmp = S.transpose();
|
||||
|
||||
S += tmp;
|
||||
S *= 0.5f;
|
||||
|
||||
#ifdef G3D_DEBUG
|
||||
// Check iter limit
|
||||
assert(iter < MAX_ITERS);
|
||||
|
||||
// Check A = R*S
|
||||
tmp = R*S;
|
||||
resid = tmp.diffOneNorm(*this);
|
||||
assert(resid < eps);
|
||||
|
||||
// Check R is orthogonal
|
||||
tmp = R*R.transpose();
|
||||
resid = tmp.diffOneNorm(Matrix3::identity());
|
||||
assert(resid < eps);
|
||||
|
||||
// Check that S is symmetric
|
||||
tmp = S.transpose();
|
||||
resid = tmp.diffOneNorm(S);
|
||||
assert(resid < eps);
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Matrix3::maxCubicRoot (float afCoeff[3]) {
|
||||
// Spectral norm is for A^T*A, so characteristic polynomial
|
||||
|
|
@ -1010,10 +1183,75 @@ float Matrix3::spectralNorm () const {
|
|||
return fNorm;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Matrix3::squaredFrobeniusNorm() const {
|
||||
float norm2 = 0;
|
||||
const float* e = &elt[0][0];
|
||||
|
||||
for (int i = 0; i < 9; ++i){
|
||||
norm2 += (*e) * (*e);
|
||||
}
|
||||
|
||||
return norm2;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Matrix3::frobeniusNorm() const {
|
||||
return sqrtf(squaredFrobeniusNorm());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Matrix3::l1Norm() const {
|
||||
// The one norm of a matrix is the max column sum in absolute value.
|
||||
float oneNorm = 0;
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
|
||||
float f = fabs(elt[0][c])+ fabs(elt[1][c]) + fabs(elt[2][c]);
|
||||
|
||||
if (f > oneNorm) {
|
||||
oneNorm = f;
|
||||
}
|
||||
}
|
||||
return oneNorm;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Matrix3::lInfNorm() const {
|
||||
// The infinity norm of a matrix is the max row sum in absolute value.
|
||||
float infNorm = 0;
|
||||
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
|
||||
float f = fabs(elt[r][0]) + fabs(elt[r][1])+ fabs(elt[r][2]);
|
||||
|
||||
if (f > infNorm) {
|
||||
infNorm = f;
|
||||
}
|
||||
}
|
||||
return infNorm;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Matrix3::diffOneNorm(const Matrix3 &y) const{
|
||||
float oneNorm = 0;
|
||||
|
||||
for (int c = 0; c < 3; ++c){
|
||||
|
||||
float f = fabs(elt[0][c] - y[0][c]) + fabs(elt[1][c] - y[1][c])
|
||||
+ fabs(elt[2][c] - y[2][c]);
|
||||
|
||||
if (f > oneNorm) {
|
||||
oneNorm = f;
|
||||
}
|
||||
}
|
||||
return oneNorm;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Matrix3::toAxisAngle (Vector3& rkAxis, float& rfRadians) const {
|
||||
//
|
||||
// Let (x,y,z) be the unit-length axis and let A be an angle of rotation.
|
||||
// The rotation matrix is R = I + sin(A)*P + (1-cos(A))*P^2 where
|
||||
// The rotation matrix is R = I + sin(A)*P + (1-cos(A))*P^2 (Rodrigues' formula) where
|
||||
// I is the identity and
|
||||
//
|
||||
// +- -+
|
||||
|
|
@ -1035,11 +1273,11 @@ void Matrix3::toAxisAngle (Vector3& rkAxis, float& rfRadians) const {
|
|||
// it does not matter which sign you choose on the square roots.
|
||||
|
||||
float fTrace = elt[0][0] + elt[1][1] + elt[2][2];
|
||||
float fCos = 0.5 * (fTrace - 1.0);
|
||||
float fCos = 0.5f * (fTrace - 1.0f);
|
||||
rfRadians = G3D::aCos(fCos); // in [0,PI]
|
||||
|
||||
if ( rfRadians > 0.0 ) {
|
||||
if ( rfRadians < G3D_PI ) {
|
||||
if ( rfRadians < pi() ) {
|
||||
rkAxis.x = elt[2][1] - elt[1][2];
|
||||
rkAxis.y = elt[0][2] - elt[2][0];
|
||||
rkAxis.z = elt[1][0] - elt[0][1];
|
||||
|
|
@ -1094,28 +1332,31 @@ void Matrix3::toAxisAngle (Vector3& rkAxis, float& rfRadians) const {
|
|||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Matrix3 Matrix3::fromAxisAngle (const Vector3& rkAxis, float fRadians) {
|
||||
Matrix3 m;
|
||||
Matrix3 Matrix3::fromAxisAngle (const Vector3& _axis, float fRadians) {
|
||||
Vector3 axis = _axis.direction();
|
||||
|
||||
float fCos = cos(fRadians);
|
||||
float fSin = sin(fRadians);
|
||||
Matrix3 m;
|
||||
float fCos = cos(fRadians);
|
||||
float fSin = sin(fRadians);
|
||||
float fOneMinusCos = 1.0 - fCos;
|
||||
float fX2 = rkAxis.x * rkAxis.x;
|
||||
float fY2 = rkAxis.y * rkAxis.y;
|
||||
float fZ2 = rkAxis.z * rkAxis.z;
|
||||
float fXYM = rkAxis.x * rkAxis.y * fOneMinusCos;
|
||||
float fXZM = rkAxis.x * rkAxis.z * fOneMinusCos;
|
||||
float fYZM = rkAxis.y * rkAxis.z * fOneMinusCos;
|
||||
float fXSin = rkAxis.x * fSin;
|
||||
float fYSin = rkAxis.y * fSin;
|
||||
float fZSin = rkAxis.z * fSin;
|
||||
float fX2 = square(axis.x);
|
||||
float fY2 = square(axis.y);
|
||||
float fZ2 = square(axis.z);
|
||||
float fXYM = axis.x * axis.y * fOneMinusCos;
|
||||
float fXZM = axis.x * axis.z * fOneMinusCos;
|
||||
float fYZM = axis.y * axis.z * fOneMinusCos;
|
||||
float fXSin = axis.x * fSin;
|
||||
float fYSin = axis.y * fSin;
|
||||
float fZSin = axis.z * fSin;
|
||||
|
||||
m.elt[0][0] = fX2 * fOneMinusCos + fCos;
|
||||
m.elt[0][1] = fXYM - fZSin;
|
||||
m.elt[0][2] = fXZM + fYSin;
|
||||
|
||||
m.elt[1][0] = fXYM + fZSin;
|
||||
m.elt[1][1] = fY2 * fOneMinusCos + fCos;
|
||||
m.elt[1][2] = fYZM - fXSin;
|
||||
|
||||
m.elt[2][0] = fXZM - fYSin;
|
||||
m.elt[2][1] = fYZM + fXSin;
|
||||
m.elt[2][2] = fZ2 * fOneMinusCos + fCos;
|
||||
|
|
@ -1139,14 +1380,14 @@ bool Matrix3::toEulerAnglesXYZ (float& rfXAngle, float& rfYAngle,
|
|||
} else {
|
||||
// WARNING. Not unique. XA - ZA = -atan2(r10,r11)
|
||||
rfXAngle = -G3D::aTan2(elt[1][0], elt[1][1]);
|
||||
rfYAngle = -(float)G3D_HALF_PI;
|
||||
rfYAngle = -(float)halfPi();
|
||||
rfZAngle = 0.0f;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
|
||||
rfXAngle = G3D::aTan2(elt[1][0], elt[1][1]);
|
||||
rfYAngle = (float)G3D_HALF_PI;
|
||||
rfYAngle = (float)halfPi();
|
||||
rfZAngle = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1168,14 +1409,14 @@ bool Matrix3::toEulerAnglesXZY (float& rfXAngle, float& rfZAngle,
|
|||
} else {
|
||||
// WARNING. Not unique. XA - YA = atan2(r20,r22)
|
||||
rfXAngle = G3D::aTan2(elt[2][0], elt[2][2]);
|
||||
rfZAngle = (float)G3D_HALF_PI;
|
||||
rfZAngle = (float)halfPi();
|
||||
rfYAngle = 0.0;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// WARNING. Not unique. XA + YA = atan2(-r20,r22)
|
||||
rfXAngle = G3D::aTan2( -elt[2][0], elt[2][2]);
|
||||
rfZAngle = -(float)G3D_HALF_PI;
|
||||
rfZAngle = -(float)halfPi();
|
||||
rfYAngle = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1197,14 +1438,14 @@ bool Matrix3::toEulerAnglesYXZ (float& rfYAngle, float& rfXAngle,
|
|||
} else {
|
||||
// WARNING. Not unique. YA - ZA = atan2(r01,r00)
|
||||
rfYAngle = G3D::aTan2(elt[0][1], elt[0][0]);
|
||||
rfXAngle = (float)G3D_HALF_PI;
|
||||
rfXAngle = (float)halfPi();
|
||||
rfZAngle = 0.0;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// WARNING. Not unique. YA + ZA = atan2(-r01,r00)
|
||||
rfYAngle = G3D::aTan2( -elt[0][1], elt[0][0]);
|
||||
rfXAngle = -(float)G3D_HALF_PI;
|
||||
rfXAngle = -(float)halfPi();
|
||||
rfZAngle = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1226,14 +1467,14 @@ bool Matrix3::toEulerAnglesYZX (float& rfYAngle, float& rfZAngle,
|
|||
} else {
|
||||
// WARNING. Not unique. YA - XA = -atan2(r21,r22);
|
||||
rfYAngle = -G3D::aTan2(elt[2][1], elt[2][2]);
|
||||
rfZAngle = -(float)G3D_HALF_PI;
|
||||
rfZAngle = -(float)halfPi();
|
||||
rfXAngle = 0.0;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// WARNING. Not unique. YA + XA = atan2(r21,r22)
|
||||
rfYAngle = G3D::aTan2(elt[2][1], elt[2][2]);
|
||||
rfZAngle = (float)G3D_HALF_PI;
|
||||
rfZAngle = (float)halfPi();
|
||||
rfXAngle = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1255,14 +1496,14 @@ bool Matrix3::toEulerAnglesZXY (float& rfZAngle, float& rfXAngle,
|
|||
} else {
|
||||
// WARNING. Not unique. ZA - YA = -atan(r02,r00)
|
||||
rfZAngle = -G3D::aTan2(elt[0][2], elt[0][0]);
|
||||
rfXAngle = -(float)G3D_HALF_PI;
|
||||
rfXAngle = -(float)halfPi();
|
||||
rfYAngle = 0.0f;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// WARNING. Not unique. ZA + YA = atan2(r02,r00)
|
||||
rfZAngle = G3D::aTan2(elt[0][2], elt[0][0]);
|
||||
rfXAngle = (float)G3D_HALF_PI;
|
||||
rfXAngle = (float)halfPi();
|
||||
rfYAngle = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1284,14 +1525,14 @@ bool Matrix3::toEulerAnglesZYX (float& rfZAngle, float& rfYAngle,
|
|||
} else {
|
||||
// WARNING. Not unique. ZA - XA = -atan2(r01,r02)
|
||||
rfZAngle = -G3D::aTan2(elt[0][1], elt[0][2]);
|
||||
rfYAngle = (float)G3D_HALF_PI;
|
||||
rfYAngle = (float)halfPi();
|
||||
rfXAngle = 0.0f;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// WARNING. Not unique. ZA + XA = atan2(-r01,-r02)
|
||||
rfZAngle = G3D::aTan2( -elt[0][1], -elt[0][2]);
|
||||
rfYAngle = -(float)G3D_HALF_PI;
|
||||
rfYAngle = -(float)halfPi();
|
||||
rfXAngle = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
523
dep/src/g3dlite/Matrix4.cpp
Normal file
523
dep/src/g3dlite/Matrix4.cpp
Normal 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
dep/src/g3dlite/MemoryManager.cpp
Normal file
91
dep/src/g3dlite/MemoryManager.cpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
@file MemoryManager.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2009-04-20
|
||||
@edited 2009-05-29
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/MemoryManager.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
MemoryManager::MemoryManager() {}
|
||||
|
||||
|
||||
void* MemoryManager::alloc(size_t s) {
|
||||
return System::malloc(s);
|
||||
}
|
||||
|
||||
|
||||
void MemoryManager::free(void* ptr) {
|
||||
System::free(ptr);
|
||||
}
|
||||
|
||||
|
||||
bool MemoryManager::isThreadsafe() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
MemoryManager::Ref MemoryManager::create() {
|
||||
static MemoryManager::Ref m = new MemoryManager();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
AlignedMemoryManager::AlignedMemoryManager() {}
|
||||
|
||||
|
||||
void* AlignedMemoryManager::alloc(size_t s) {
|
||||
return System::alignedMalloc(s, 16);
|
||||
}
|
||||
|
||||
|
||||
void AlignedMemoryManager::free(void* ptr) {
|
||||
System::alignedFree(ptr);
|
||||
}
|
||||
|
||||
|
||||
bool AlignedMemoryManager::isThreadsafe() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
AlignedMemoryManager::Ref AlignedMemoryManager::create() {
|
||||
static AlignedMemoryManager::Ref m = new AlignedMemoryManager();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
CRTMemoryManager::CRTMemoryManager() {}
|
||||
|
||||
|
||||
void* CRTMemoryManager::alloc(size_t s) {
|
||||
return ::malloc(s);
|
||||
}
|
||||
|
||||
|
||||
void CRTMemoryManager::free(void* ptr) {
|
||||
return ::free(ptr);
|
||||
}
|
||||
|
||||
|
||||
bool CRTMemoryManager::isThreadsafe() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
CRTMemoryManager::Ref CRTMemoryManager::create() {
|
||||
static CRTMemoryManager::Ref m = new CRTMemoryManager();
|
||||
return m;
|
||||
}
|
||||
}
|
||||
637
dep/src/g3dlite/MeshAlg.cpp
Normal file
637
dep/src/g3dlite/MeshAlg.cpp
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
/**
|
||||
@file MeshAlg.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2003-09-14
|
||||
@edited 2008-09-03
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "G3D/MeshAlg.h"
|
||||
#include "G3D/Table.h"
|
||||
#include "G3D/Set.h"
|
||||
#include "G3D/Box.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/vectorMath.h"
|
||||
#include "G3D/AABox.h"
|
||||
#include "G3D/Image1.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
const int MeshAlg::Face::NONE = INT_MIN;
|
||||
|
||||
void MeshAlg::generateGrid(
|
||||
Array<Vector3>& vertex,
|
||||
Array<Vector2>& texCoord,
|
||||
Array<int>& index,
|
||||
int wCells,
|
||||
int hCells,
|
||||
const Vector2& textureScale,
|
||||
bool spaceCentered,
|
||||
bool twoSided,
|
||||
const CoordinateFrame& xform,
|
||||
const Image1::Ref& height) {
|
||||
|
||||
vertex.fastClear();
|
||||
texCoord.fastClear();
|
||||
index.fastClear();
|
||||
|
||||
// Generate vertices
|
||||
for (int z = 0; z <= hCells; ++z) {
|
||||
for (int x = 0; x <= wCells; ++x) {
|
||||
Vector3 v(x / (float)wCells, 0, z / (float)hCells);
|
||||
|
||||
Vector2 t = v.xz() * textureScale;
|
||||
|
||||
texCoord.append(t);
|
||||
|
||||
if (height.notNull()) {
|
||||
v.y = height->nearest(v.x * (height->width() - 1), v.z * (height->height() - 1)).value;
|
||||
}
|
||||
if (spaceCentered) {
|
||||
v -= Vector3(0.5f, 0, 0.5f);
|
||||
}
|
||||
v = xform.pointToWorldSpace(v);
|
||||
vertex.append(v);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate indices
|
||||
for (int z = 0; z < hCells; ++z) {
|
||||
for (int x = 0; x < wCells; ++x) {
|
||||
int A = x + z * (wCells + 1);
|
||||
int B = A + 1;
|
||||
int C = A + (wCells + 1);
|
||||
int D = C + 1;
|
||||
|
||||
// A B
|
||||
// *-----*
|
||||
// | \ |
|
||||
// | \ |
|
||||
// *-----*
|
||||
// C D
|
||||
|
||||
index.append(A, D, B);
|
||||
index.append(A, C, D);
|
||||
}
|
||||
}
|
||||
|
||||
if (twoSided) {
|
||||
// The index array needs to have reversed winding for the bottom
|
||||
// and offset by the original number of vertices
|
||||
Array<int> ti = index;
|
||||
ti.reverse();
|
||||
for (int i = 0; i < ti.size(); ++i) {
|
||||
ti[i] += vertex.size();
|
||||
}
|
||||
index.append(ti);
|
||||
|
||||
// Duplicate the arrays
|
||||
vertex.append(Array<Vector3>(vertex));
|
||||
texCoord.append(Array<Vector2>(texCoord));
|
||||
}
|
||||
}
|
||||
|
||||
MeshAlg::Face::Face() {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
edgeIndex[i] = 0;
|
||||
vertexIndex[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MeshAlg::Edge::Edge() {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
vertexIndex[i] = 0;
|
||||
// Negative face indices are faces that don't exist
|
||||
faceIndex[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MeshAlg::Geometry& MeshAlg::Geometry::operator=(const MeshAlg::Geometry& src) {
|
||||
vertexArray.resize(src.vertexArray.size());
|
||||
normalArray.resize(src.vertexArray.size());
|
||||
|
||||
System::memcpy(vertexArray.getCArray(), src.vertexArray.getCArray(), sizeof(Vector3)*vertexArray.size());
|
||||
System::memcpy(normalArray.getCArray(), src.normalArray.getCArray(), sizeof(Vector3)*normalArray.size());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeNormals(
|
||||
Geometry& geometry,
|
||||
const Array<int>& indexArray) {
|
||||
|
||||
Array<Face> faceArray;
|
||||
Array<Vertex> vertexArray;
|
||||
Array<Edge> edgeArray;
|
||||
Array<Vector3> faceNormalArray;
|
||||
|
||||
computeAdjacency(geometry.vertexArray, indexArray, faceArray, edgeArray, vertexArray);
|
||||
|
||||
computeNormals(geometry.vertexArray, faceArray, vertexArray,
|
||||
geometry.normalArray, faceNormalArray);
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeNormals(
|
||||
const Array<Vector3>& vertexGeometry,
|
||||
const Array<Face>& faceArray,
|
||||
const Array< Array<int> >& adjacentFaceArray,
|
||||
Array<Vector3>& vertexNormalArray,
|
||||
Array<Vector3>& faceNormalArray) {
|
||||
|
||||
// Construct a fake vertex array for backwards compatibility
|
||||
Array<Vertex> fakeVertexArray;
|
||||
fakeVertexArray.resize(adjacentFaceArray.size());
|
||||
|
||||
for (int v = 0; v < adjacentFaceArray.size(); ++v) {
|
||||
fakeVertexArray[v].faceIndex.resize(adjacentFaceArray[v].size());
|
||||
for (int i = 0; i < fakeVertexArray[v].faceIndex.size(); ++i) {
|
||||
fakeVertexArray[v].faceIndex[i] = adjacentFaceArray[v][i];
|
||||
}
|
||||
// We leave out the edges because they aren't used to compute normals
|
||||
}
|
||||
|
||||
computeNormals(vertexGeometry, faceArray, fakeVertexArray,
|
||||
vertexNormalArray, faceNormalArray);
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeNormals(
|
||||
const Array<Vector3>& vertexGeometry,
|
||||
const Array<Face>& faceArray,
|
||||
const Array<Vertex>& vertexArray,
|
||||
Array<Vector3>& vertexNormalArray,
|
||||
Array<Vector3>& faceNormalArray) {
|
||||
|
||||
// Face normals (not unit length)
|
||||
faceNormalArray.resize(faceArray.size());
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
const Face& face = faceArray[f];
|
||||
|
||||
Vector3 vertex[3];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
vertex[j] = vertexGeometry[face.vertexIndex[j]];
|
||||
debugAssert(vertex[j].isFinite());
|
||||
}
|
||||
|
||||
faceNormalArray[f] = (vertex[1] - vertex[0]).cross(vertex[2] - vertex[0]);
|
||||
# ifdef G3D_DEBUG
|
||||
const Vector3& N = faceNormalArray[f];
|
||||
debugAssert(N.isFinite());
|
||||
# endif
|
||||
}
|
||||
|
||||
// Per-vertex normals, computed by averaging
|
||||
vertexNormalArray.resize(vertexGeometry.size());
|
||||
for (int v = 0; v < vertexNormalArray.size(); ++v) {
|
||||
Vector3 sum = Vector3::zero();
|
||||
for (int k = 0; k < vertexArray[v].faceIndex.size(); ++k) {
|
||||
const int f = vertexArray[v].faceIndex[k];
|
||||
sum += faceNormalArray[f];
|
||||
}
|
||||
vertexNormalArray[v] = sum.directionOrZero();
|
||||
# ifdef G3D_DEBUG
|
||||
const Vector3& N = vertexNormalArray[v];
|
||||
debugAssert(N.isUnit() || N.isZero());
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
faceNormalArray[f] = faceNormalArray[f].directionOrZero();
|
||||
# ifdef G3D_DEBUG
|
||||
const Vector3& N = faceNormalArray[f];
|
||||
debugAssert(N.isUnit() || N.isZero());
|
||||
# endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeFaceNormals(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<MeshAlg::Face>& faceArray,
|
||||
Array<Vector3>& faceNormals,
|
||||
bool normalize) {
|
||||
|
||||
faceNormals.resize(faceArray.size());
|
||||
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
const MeshAlg::Face& face = faceArray[f];
|
||||
|
||||
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
|
||||
const Vector3& v1 = vertexArray[face.vertexIndex[1]];
|
||||
const Vector3& v2 = vertexArray[face.vertexIndex[2]];
|
||||
|
||||
faceNormals[f] = (v1 - v0).cross(v2 - v0);
|
||||
}
|
||||
|
||||
if (normalize) {
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
faceNormals[f] = faceNormals[f].direction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::identifyBackfaces(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<MeshAlg::Face>& faceArray,
|
||||
const Vector4& HP,
|
||||
Array<bool>& backface) {
|
||||
|
||||
Vector3 P = HP.xyz();
|
||||
|
||||
backface.resize(faceArray.size());
|
||||
|
||||
if (fuzzyEq(HP.w, 0.0)) {
|
||||
// Infinite case
|
||||
for (int f = faceArray.size() - 1; f >= 0; --f) {
|
||||
const MeshAlg::Face& face = faceArray[f];
|
||||
|
||||
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
|
||||
const Vector3& v1 = vertexArray[face.vertexIndex[1]];
|
||||
const Vector3& v2 = vertexArray[face.vertexIndex[2]];
|
||||
|
||||
const Vector3 N = (v1 - v0).cross(v2 - v0);
|
||||
|
||||
backface[f] = N.dot(P) < 0;
|
||||
}
|
||||
} else {
|
||||
// Finite case
|
||||
for (int f = faceArray.size() - 1; f >= 0; --f) {
|
||||
const MeshAlg::Face& face = faceArray[f];
|
||||
|
||||
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
|
||||
const Vector3& v1 = vertexArray[face.vertexIndex[1]];
|
||||
const Vector3& v2 = vertexArray[face.vertexIndex[2]];
|
||||
|
||||
const Vector3 N = (v1 - v0).cross(v2 - v0);
|
||||
|
||||
backface[f] = N.dot(P - v0) < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::identifyBackfaces(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<MeshAlg::Face>& faceArray,
|
||||
const Vector4& HP,
|
||||
Array<bool>& backface,
|
||||
const Array<Vector3>& faceNormals) {
|
||||
|
||||
Vector3 P = HP.xyz();
|
||||
|
||||
backface.resize(faceArray.size());
|
||||
|
||||
if (fuzzyEq(HP.w, 0.0)) {
|
||||
// Infinite case
|
||||
for (int f = faceArray.size() - 1; f >= 0; --f) {
|
||||
const Vector3& N = faceNormals[f];
|
||||
backface[f] = N.dot(P) < 0;
|
||||
}
|
||||
} else {
|
||||
// Finite case
|
||||
for (int f = faceArray.size() - 1; f >= 0; --f) {
|
||||
const MeshAlg::Face& face = faceArray[f];
|
||||
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
|
||||
const Vector3& N = faceNormals[f];
|
||||
|
||||
backface[f] = N.dot(P - v0) < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::createIndexArray(int n, Array<int>& array, int start, int run, int skip) {
|
||||
debugAssert(skip >= 0);
|
||||
debugAssert(run >= 0);
|
||||
|
||||
array.resize(n);
|
||||
if (skip == 0) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
array[i] = start + i;
|
||||
}
|
||||
} else {
|
||||
int rcount = 0;
|
||||
int j = start;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
array[i] = j;
|
||||
|
||||
++j;
|
||||
++rcount;
|
||||
|
||||
if (rcount == run) {
|
||||
rcount = 0;
|
||||
j += skip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeAreaStatistics(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<int>& indexArray,
|
||||
double& minEdgeLength,
|
||||
double& meanEdgeLength,
|
||||
double& medianEdgeLength,
|
||||
double& maxEdgeLength,
|
||||
double& minFaceArea,
|
||||
double& meanFaceArea,
|
||||
double& medianFaceArea,
|
||||
double& maxFaceArea) {
|
||||
|
||||
debugAssert(indexArray.size() % 3 == 0);
|
||||
|
||||
Array<double> area;
|
||||
area.resize(indexArray.size() / 3);
|
||||
Array<double> magnitude;
|
||||
magnitude.resize(indexArray.size());
|
||||
|
||||
for (int i = 0; i < indexArray.size(); i += 3) {
|
||||
const Vector3& v0 = vertexArray[indexArray[i]];
|
||||
const Vector3& v1 = vertexArray[indexArray[i + 1]];
|
||||
const Vector3& v2 = vertexArray[indexArray[i + 2]];
|
||||
|
||||
area[i / 3] = (v1 - v0).cross(v2 - v0).magnitude() / 2.0;
|
||||
magnitude[i] = (v1 - v0).magnitude();
|
||||
magnitude[i + 1] = (v2 - v1).magnitude();
|
||||
magnitude[i + 2] = (v0 - v2).magnitude();
|
||||
}
|
||||
|
||||
area.sort();
|
||||
magnitude.sort();
|
||||
|
||||
minEdgeLength = max(0.0, magnitude[0]);
|
||||
maxEdgeLength = max(0.0, magnitude.last());
|
||||
medianEdgeLength = max(0.0, magnitude[magnitude.size() / 2]);
|
||||
meanEdgeLength = 0;
|
||||
for (int i = 0; i < magnitude.size(); ++i) {
|
||||
meanEdgeLength += magnitude[i];
|
||||
}
|
||||
meanEdgeLength /= magnitude.size();
|
||||
|
||||
minFaceArea = max(0.0, area[0]);
|
||||
maxFaceArea = max(0.0, area.last());
|
||||
medianFaceArea = max(0.0, area[area.size() / 2]);
|
||||
meanFaceArea = 0;
|
||||
for (int i = 0; i < area.size(); ++i) {
|
||||
meanFaceArea += area[i];
|
||||
}
|
||||
meanFaceArea /= area.size();
|
||||
|
||||
|
||||
// Make sure round-off hasn't pushed values less than zero
|
||||
meanFaceArea = max(0.0, meanFaceArea);
|
||||
meanEdgeLength = max(0.0, meanEdgeLength);
|
||||
}
|
||||
|
||||
|
||||
int MeshAlg::countBoundaryEdges(const Array<MeshAlg::Edge>& edgeArray) {
|
||||
int b = 0;
|
||||
|
||||
for (int i = 0; i < edgeArray.size(); ++i) {
|
||||
if ((edgeArray[i].faceIndex[0] == MeshAlg::Face::NONE) !=
|
||||
(edgeArray[i].faceIndex[1] == MeshAlg::Face::NONE)) {
|
||||
++b;
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void MeshAlg::computeBounds(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<int>& indexArray,
|
||||
AABox& box,
|
||||
Sphere& sphere) {
|
||||
|
||||
Array<Vector3> newArray;
|
||||
newArray.resize(indexArray.size());
|
||||
for (int i = 0; i < indexArray.size(); ++i) {
|
||||
newArray[i] = vertexArray[indexArray[i]];
|
||||
}
|
||||
computeBounds(newArray, box, sphere);
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeBounds(
|
||||
const Array<Vector3>& vertexArray,
|
||||
AABox& box,
|
||||
Sphere& sphere) {
|
||||
|
||||
Vector3 xmin, xmax, ymin, ymax, zmin, zmax;
|
||||
|
||||
// FIRST PASS: find 6 minima/maxima points
|
||||
xmin.x = ymin.y = zmin.z = finf();
|
||||
xmax.x = ymax.y = zmax.z = -finf();
|
||||
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
const Vector3& vertex = vertexArray[v];
|
||||
|
||||
if (vertex.x < xmin.x) {
|
||||
xmin = vertex;
|
||||
}
|
||||
|
||||
if (vertex.x > xmax.x) {
|
||||
xmax = vertex;
|
||||
}
|
||||
|
||||
if (vertex.y < ymin.y) {
|
||||
ymin = vertex;
|
||||
}
|
||||
|
||||
if (vertex.y > ymax.y) {
|
||||
ymax = vertex;
|
||||
}
|
||||
|
||||
if (vertex.z < zmin.z) {
|
||||
zmin = vertex;
|
||||
}
|
||||
|
||||
if (vertex.z > zmax.z) {
|
||||
zmax = vertex;
|
||||
}
|
||||
}
|
||||
|
||||
// Set points dia1 & dia2 to the maximally separated pair
|
||||
Vector3 dia1 = xmin;
|
||||
Vector3 dia2 = xmax;
|
||||
{
|
||||
// Set xspan = distance between the 2 points xmin & xmax (squared)
|
||||
double xspan = (xmax - xmin).squaredMagnitude();
|
||||
|
||||
// Same for y & z spans
|
||||
double yspan = (ymax - ymin).squaredMagnitude();
|
||||
double zspan = (zmax - zmin).squaredMagnitude();
|
||||
|
||||
double maxspan = xspan;
|
||||
|
||||
if (yspan > maxspan) {
|
||||
maxspan = yspan;
|
||||
dia1 = ymin;
|
||||
dia2 = ymax;
|
||||
}
|
||||
|
||||
if (zspan > maxspan) {
|
||||
maxspan = zspan;
|
||||
dia1 = zmin;
|
||||
dia2 = zmax;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// dia1, dia2 is a diameter of initial sphere
|
||||
|
||||
// calc initial center
|
||||
Vector3 center = (dia1 + dia2) / 2.0;
|
||||
|
||||
// calculate initial radius^2 and radius
|
||||
Vector3 d = dia2 - sphere.center;
|
||||
|
||||
double radSq = d.squaredMagnitude();
|
||||
double rad = sqrt(radSq);
|
||||
|
||||
// SECOND PASS: increment current sphere
|
||||
double old_to_p, old_to_new;
|
||||
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
const Vector3& vertex = vertexArray[v];
|
||||
|
||||
d = vertex - center;
|
||||
|
||||
double old_to_p_sq = d.squaredMagnitude();
|
||||
|
||||
// do r^2 test first
|
||||
if (old_to_p_sq > radSq) {
|
||||
// this point is outside of current sphere
|
||||
old_to_p = sqrt(old_to_p_sq);
|
||||
|
||||
// calc radius of new sphere
|
||||
rad = (rad + old_to_p) / 2.0;
|
||||
|
||||
// for next r^2 compare
|
||||
radSq = rad * rad;
|
||||
old_to_new = old_to_p - rad;
|
||||
|
||||
// calc center of new sphere
|
||||
center = (rad * center + old_to_new * vertex) / old_to_p;
|
||||
}
|
||||
}
|
||||
|
||||
const Vector3 min(xmin.x, ymin.y, zmin.z);
|
||||
const Vector3 max(xmax.x, ymax.y, zmax.z);
|
||||
|
||||
box = AABox(min, max);
|
||||
|
||||
const float boxRadSq = (max - min).squaredMagnitude() * 0.25f;
|
||||
|
||||
if (boxRadSq >= radSq){
|
||||
if (isNaN(center.x) || ! isFinite(rad)) {
|
||||
sphere = Sphere(Vector3::zero(), finf());
|
||||
} else {
|
||||
sphere = Sphere(center, rad);
|
||||
}
|
||||
} else {
|
||||
sphere = Sphere((max + min) * 0.5f, sqrt(boxRadSq));
|
||||
}
|
||||
}
|
||||
|
||||
void MeshAlg::computeTangentSpaceBasis(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector2>& texCoordArray,
|
||||
const Array<Vector3>& vertexNormalArray,
|
||||
const Array<Face>& faceArray,
|
||||
Array<Vector3>& tangent,
|
||||
Array<Vector3>& binormal) {
|
||||
|
||||
debugAssertM(faceArray.size() != 0, "Unable to calculate valid tangent space without faces.");
|
||||
|
||||
tangent.resize(vertexArray.size());
|
||||
binormal.resize(vertexArray.size());
|
||||
|
||||
// Zero the output arrays.
|
||||
System::memset(tangent.getCArray(), 0, sizeof(Vector3) * tangent.size());
|
||||
System::memset(binormal.getCArray(), 0, sizeof(Vector3) * binormal.size());
|
||||
|
||||
// Iterate over faces, computing the tangent vectors for each
|
||||
// vertex. Accumulate those into the tangent and binormal arrays
|
||||
// and then orthonormalize at the end.
|
||||
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
const Face& face = faceArray[f];
|
||||
|
||||
const int i0 = face.vertexIndex[0];
|
||||
const int i1 = face.vertexIndex[1];
|
||||
const int i2 = face.vertexIndex[2];
|
||||
|
||||
const Vector3& v0 = vertexArray[i0];
|
||||
const Vector3& v1 = vertexArray[i1];
|
||||
const Vector3& v2 = vertexArray[i2];
|
||||
|
||||
const Vector2& t0 = texCoordArray[i0];
|
||||
const Vector2& t1 = texCoordArray[i1];
|
||||
const Vector2& t2 = texCoordArray[i2];
|
||||
|
||||
// See http://www.terathon.com/code/tangent.html for a derivation of the following code
|
||||
|
||||
// vertex edges
|
||||
Vector3 ve1 = v1 - v0;
|
||||
Vector3 ve2 = v2 - v0;
|
||||
|
||||
// texture edges
|
||||
Vector2 te1 = t1 - t0;
|
||||
Vector2 te2 = t2 - t0;
|
||||
|
||||
Vector3 n(ve1.cross(ve2).direction());
|
||||
Vector3 t, b;
|
||||
|
||||
float r = te1.x * te2.y - te1.y * te2.x;
|
||||
if (r == 0.0) {
|
||||
// degenerate case
|
||||
Vector3::generateOrthonormalBasis(t, b, n, true);
|
||||
} else {
|
||||
r = 1.0f / r;
|
||||
t = (te2.y * ve1 - te1.y * ve2) * r;
|
||||
b = (te2.x * ve1 - te1.x * ve2) * r;
|
||||
}
|
||||
|
||||
for (int v = 0; v < 3; ++v) {
|
||||
int i = face.vertexIndex[v];
|
||||
tangent[i] += t;
|
||||
binormal[i] += b;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize the basis vectors
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
// Remove the component parallel to the normal
|
||||
const Vector3& N = vertexNormalArray[v];
|
||||
Vector3& T = tangent[v];
|
||||
Vector3& B = binormal[v];
|
||||
|
||||
debugAssertM(N.isUnit() || N.isZero(), "Input normals must have unit length");
|
||||
|
||||
T -= T.dot(N) * N;
|
||||
B -= B.dot(N) * N;
|
||||
|
||||
// Normalize
|
||||
T = T.directionOrZero();
|
||||
B = B.directionOrZero();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // G3D namespace
|
||||
739
dep/src/g3dlite/MeshAlgAdjacency.cpp
Normal file
739
dep/src/g3dlite/MeshAlgAdjacency.cpp
Normal file
|
|
@ -0,0 +1,739 @@
|
|||
/**
|
||||
@file MeshAlgAdjacency.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2003-09-14
|
||||
@edited 2009-04-26
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "G3D/Table.h"
|
||||
#include "G3D/MeshAlg.h"
|
||||
#include "G3D/Set.h"
|
||||
#include "G3D/Stopwatch.h"
|
||||
#include "G3D/SmallArray.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
/** Two-level table mapping index 0 -> index 1 -> list of face indices */
|
||||
class MeshEdgeTable {
|
||||
public:
|
||||
|
||||
/** We expect 2 faces per edge. */
|
||||
typedef SmallArray<int, 2> FaceIndexArray;
|
||||
|
||||
class Edge {
|
||||
public:
|
||||
int i1;
|
||||
|
||||
FaceIndexArray faceIndexArray;
|
||||
};
|
||||
|
||||
/** We expect at most 6 edges per vertex; that matches a typical regular grid mesh */
|
||||
typedef SmallArray<Edge, 6> EdgeArray;
|
||||
|
||||
typedef Array< EdgeArray > ET;
|
||||
|
||||
private:
|
||||
|
||||
ET table;
|
||||
|
||||
public:
|
||||
|
||||
void clear() {
|
||||
table.clear();
|
||||
}
|
||||
|
||||
void resize(int maxV) {
|
||||
table.resize(maxV);
|
||||
}
|
||||
|
||||
/**
|
||||
Inserts the faceIndex into the edge's face list.
|
||||
The index may be a negative number indicating a backface.
|
||||
|
||||
\param v0 Vertex index 0
|
||||
\param v1 Vertex index 1
|
||||
*/
|
||||
void insert(int v0, int v1, int faceIndex) {
|
||||
|
||||
debugAssert(v0 <= v1);
|
||||
EdgeArray& edgeArray = table[v0];
|
||||
for (int i = 0; i < edgeArray.size(); ++i) {
|
||||
if (edgeArray[i].i1 == v1) {
|
||||
edgeArray[i].faceIndexArray.push(faceIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Edge& p = edgeArray.next();
|
||||
p.i1 = v1;
|
||||
p.faceIndexArray.push(faceIndex);
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
friend class MeshEdgeTable;
|
||||
private:
|
||||
|
||||
int m_i0;
|
||||
/** Pair index */
|
||||
int m_p;
|
||||
ET& m_array;
|
||||
EdgeArray* m_edgeArray;
|
||||
bool m_end;
|
||||
|
||||
public:
|
||||
|
||||
int i0() const {
|
||||
return m_i0;
|
||||
}
|
||||
|
||||
int i1() const {
|
||||
return (*m_edgeArray)[m_p].i1;
|
||||
}
|
||||
|
||||
FaceIndexArray& faceIndex() {
|
||||
return (*m_edgeArray)[m_p].faceIndexArray;
|
||||
}
|
||||
|
||||
Iterator& operator++() {
|
||||
if ((m_i0 >= 0) && (m_p < m_edgeArray->size() - 1)) {
|
||||
++m_p;
|
||||
} else {
|
||||
// Skip over elements with no face array
|
||||
do {
|
||||
++m_i0;
|
||||
if (m_i0 == m_array.size()) {
|
||||
m_end = true;
|
||||
return *this;
|
||||
} else {
|
||||
m_edgeArray = &m_array[m_i0];
|
||||
m_p = 0;
|
||||
}
|
||||
} while (m_edgeArray->size() == 0);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool hasMore() const {
|
||||
return ! m_end;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Iterator(ET& a) : m_i0(-1), m_p(-1), m_array(a), m_edgeArray(NULL), m_end(false) {
|
||||
++(*this);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Iterator begin() {
|
||||
return Iterator(table);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Assigns the edge index into the next unassigned edge
|
||||
index. The edge index may be negative, indicating
|
||||
a reverse edge.
|
||||
*/
|
||||
static void assignEdgeIndex(MeshAlg::Face& face, int e) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (face.edgeIndex[i] == MeshAlg::Face::NONE) {
|
||||
face.edgeIndex[i] = e;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
debugAssertM(false, "Face has already been assigned 3 edges");
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeAdjacency(
|
||||
const Array<Vector3>& vertexGeometry,
|
||||
const Array<int>& indexArray,
|
||||
Array<Face>& faceArray,
|
||||
Array<Edge>& edgeArray,
|
||||
Array< Array<int> >& adjacentFaceArray) {
|
||||
|
||||
Array<Vertex> vertexArray;
|
||||
|
||||
computeAdjacency(vertexGeometry, indexArray, faceArray, edgeArray, vertexArray);
|
||||
|
||||
// Convert the vertexArray into adjacentFaceArray
|
||||
adjacentFaceArray.clear();
|
||||
adjacentFaceArray.resize(vertexArray.size());
|
||||
for (int v = 0; v < adjacentFaceArray.size(); ++v) {
|
||||
const SmallArray<int, 6>& src = vertexArray[v].faceIndex;
|
||||
Array<int>& dst = adjacentFaceArray[v];
|
||||
dst.resize(src.size());
|
||||
for (int f = 0; f < dst.size(); ++f) {
|
||||
dst[f] = src[f];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::computeAdjacency(
|
||||
const Array<Vector3>& vertexGeometry,
|
||||
const Array<int>& indexArray,
|
||||
Array<Face>& faceArray,
|
||||
Array<Edge>& edgeArray,
|
||||
Array<Vertex>& vertexArray) {
|
||||
|
||||
MeshEdgeTable edgeTable;
|
||||
|
||||
edgeArray.clear();
|
||||
vertexArray.clear();
|
||||
faceArray.clear();
|
||||
|
||||
// Face normals
|
||||
Array<Vector3> faceNormal;
|
||||
faceNormal.resize(indexArray.size() / 3);
|
||||
faceArray.resize(faceNormal.size());
|
||||
|
||||
// This array has the same size as the vertex array
|
||||
vertexArray.resize(vertexGeometry.size());
|
||||
|
||||
edgeTable.resize(vertexArray.size());
|
||||
|
||||
// Iterate through the triangle list
|
||||
for (int q = 0, f = 0; q < indexArray.size(); ++f, q += 3) {
|
||||
|
||||
Vector3 vertex[3];
|
||||
MeshAlg::Face& face = faceArray[f];
|
||||
|
||||
// Construct the face
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
int v = indexArray[q + j];
|
||||
face.vertexIndex[j] = v;
|
||||
face.edgeIndex[j] = Face::NONE;
|
||||
|
||||
// Store back pointers in the vertices
|
||||
vertexArray[v].faceIndex.append(f);
|
||||
|
||||
// We'll need these vertices to find the face normal
|
||||
vertex[j] = vertexGeometry[v];
|
||||
}
|
||||
|
||||
// Compute the face normal
|
||||
const Vector3& N = (vertex[1] - vertex[0]).cross(vertex[2] - vertex[0]);
|
||||
faceNormal[f] = N.directionOrZero();
|
||||
|
||||
static const int nextIndex[] = {1, 2, 0};
|
||||
|
||||
// Add each edge to the edge table.
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
const int i0 = indexArray[q + j];
|
||||
const int i1 = indexArray[q + nextIndex[j]];
|
||||
|
||||
if (i0 < i1) {
|
||||
// The edge was directed in the same manner as in the face
|
||||
edgeTable.insert(i0, i1, f);
|
||||
} else {
|
||||
// The edge was directed in the opposite manner as in the face
|
||||
edgeTable.insert(i1, i0, ~f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For each edge in the edge table, create an edge in the edge array.
|
||||
// Collapse every 2 edges from adjacent faces.
|
||||
|
||||
MeshEdgeTable::Iterator cur = edgeTable.begin();
|
||||
|
||||
Array<Edge> tempEdgeArray;
|
||||
while (cur.hasMore()) {
|
||||
MeshEdgeTable::FaceIndexArray& faceIndexArray = cur.faceIndex();
|
||||
|
||||
// Process this edge
|
||||
while (faceIndexArray.size() > 0) {
|
||||
|
||||
// Remove the last index
|
||||
int f0 = faceIndexArray.pop();
|
||||
|
||||
// Find the normal to that face
|
||||
const Vector3& n0 = faceNormal[(f0 >= 0) ? f0 : ~f0];
|
||||
|
||||
bool found = false;
|
||||
|
||||
// We try to find the matching face with the closest
|
||||
// normal. This ensures that we don't introduce a lot
|
||||
// of artificial ridges into flat parts of a mesh.
|
||||
float ndotn = -2;
|
||||
int f1 = -1, i1 = -1;
|
||||
|
||||
// Try to find the face with the matching edge
|
||||
for (int i = faceIndexArray.size() - 1; i >= 0; --i) {
|
||||
int f = faceIndexArray[i];
|
||||
|
||||
if ((f >= 0) != (f0 >= 0)) {
|
||||
// This face contains the oppositely oriented edge
|
||||
// and has not been assigned too many edges
|
||||
|
||||
const Vector3& n1 = faceNormal[(f >= 0) ? f : ~f];
|
||||
float d = n1.dot(n0);
|
||||
|
||||
if (found) {
|
||||
// We previously found a good face; see if this
|
||||
// one is better.
|
||||
if (d > ndotn) {
|
||||
// This face is better.
|
||||
ndotn = d;
|
||||
f1 = f;
|
||||
i1 = i;
|
||||
}
|
||||
} else {
|
||||
// This is the first face we've found
|
||||
found = true;
|
||||
ndotn = d;
|
||||
f1 = f;
|
||||
i1 = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the new edge
|
||||
int e = tempEdgeArray.size();
|
||||
Edge& edge = tempEdgeArray.next();
|
||||
|
||||
edge.vertexIndex[0] = cur.i0();
|
||||
edge.vertexIndex[1] = cur.i1();
|
||||
|
||||
if (f0 >= 0) {
|
||||
edge.faceIndex[0] = f0;
|
||||
edge.faceIndex[1] = Face::NONE;
|
||||
assignEdgeIndex(faceArray[f0], e);
|
||||
} else {
|
||||
// The face indices above are two's complemented.
|
||||
// this code restores them to regular indices.
|
||||
debugAssert((~f0) >= 0);
|
||||
edge.faceIndex[1] = ~f0;
|
||||
edge.faceIndex[0] = Face::NONE;
|
||||
|
||||
// The edge index *does* need to be inverted, however.
|
||||
assignEdgeIndex(faceArray[~f0], ~e);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
// We found a matching face; remove both
|
||||
// faces from the active list.
|
||||
faceIndexArray.fastRemove(i1);
|
||||
|
||||
if (f1 >= 0) {
|
||||
edge.faceIndex[0] = f1;
|
||||
assignEdgeIndex(faceArray[f1], e);
|
||||
} else {
|
||||
edge.faceIndex[1] = ~f1;
|
||||
assignEdgeIndex(faceArray[~f1], ~e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++cur;
|
||||
}
|
||||
|
||||
edgeTable.clear();
|
||||
|
||||
// Move boundary edges to the end of the list and then
|
||||
// clean up the face references into them
|
||||
{
|
||||
// Map old edge indices to new edge indices
|
||||
Array<int> newIndex;
|
||||
newIndex.resize(tempEdgeArray.size());
|
||||
|
||||
// Index of the start and end of the edge array
|
||||
int i = 0;
|
||||
int j = tempEdgeArray.size() - 1;
|
||||
|
||||
edgeArray.resize(tempEdgeArray.size());
|
||||
for (int e = 0; e < tempEdgeArray.size(); ++e) {
|
||||
if (tempEdgeArray[e].boundary()) {
|
||||
newIndex[e] = j;
|
||||
--j;
|
||||
} else {
|
||||
newIndex[e] = i;
|
||||
++i;
|
||||
}
|
||||
edgeArray[newIndex[e]] = tempEdgeArray[e];
|
||||
}
|
||||
|
||||
debugAssertM(i == j + 1, "Counting from front and back of array did not match");
|
||||
|
||||
// Fix the faces
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
Face& face = faceArray[f];
|
||||
for (int q = 0; q < 3; ++q) {
|
||||
int e = face.edgeIndex[q];
|
||||
if (e < 0) {
|
||||
// Backwards edge; twiddle before and after conversion
|
||||
face.edgeIndex[q] = ~newIndex[~e];
|
||||
} else {
|
||||
// Regular edge; remap the index
|
||||
face.edgeIndex[q] = newIndex[e];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now order the edge indices inside the faces correctly.
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
Face& face = faceArray[f];
|
||||
int e0 = face.edgeIndex[0];
|
||||
int e1 = face.edgeIndex[1];
|
||||
int e2 = face.edgeIndex[2];
|
||||
|
||||
// e0 will always remain first. The only
|
||||
// question is whether e1 and e2 should be swapped.
|
||||
|
||||
// See if e1 begins at the vertex where e1 ends.
|
||||
const int e0End = (e0 < 0) ?
|
||||
edgeArray[~e0].vertexIndex[0] :
|
||||
edgeArray[e0].vertexIndex[1];
|
||||
|
||||
const int e1Begin = (e1 < 0) ?
|
||||
edgeArray[~e1].vertexIndex[1] :
|
||||
edgeArray[e1].vertexIndex[0];
|
||||
|
||||
if (e0End != e1Begin) {
|
||||
// We must swap e1 and e2
|
||||
face.edgeIndex[1] = e2;
|
||||
face.edgeIndex[2] = e1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill out the edge adjacency information in the vertex array
|
||||
for (int e = 0; e < edgeArray.size(); ++e) {
|
||||
const Edge& edge = edgeArray[e];
|
||||
vertexArray[edge.vertexIndex[0]].edgeIndex.append(e);
|
||||
vertexArray[edge.vertexIndex[1]].edgeIndex.append(~e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::weldBoundaryEdges(
|
||||
Array<Face>& faceArray,
|
||||
Array<Edge>& edgeArray,
|
||||
Array<Vertex>& vertexArray) {
|
||||
|
||||
// Copy over the original edge array
|
||||
Array<Edge> oldEdgeArray = edgeArray;
|
||||
|
||||
// newEdgeIndex[e] is the new index of the old edge with index e
|
||||
// Note that newEdgeIndex[e] might be negative, indicating that
|
||||
// the edge switched direction between the arrays.
|
||||
Array<int> newEdgeIndex;
|
||||
newEdgeIndex.resize(edgeArray.size());
|
||||
edgeArray.resize(0);
|
||||
|
||||
// boundaryEdgeIndices[v_low] is an array of the indices of
|
||||
// all boundary edges whose lower vertex is v_low.
|
||||
Table<int, Array<int> > boundaryEdgeIndices;
|
||||
|
||||
// Copy over non-boundary edges to the new array
|
||||
for (int e = 0; e < oldEdgeArray.size(); ++e) {
|
||||
if (oldEdgeArray[e].boundary()) {
|
||||
|
||||
// Add to the boundary table
|
||||
const int v_low = iMin(oldEdgeArray[e].vertexIndex[0], oldEdgeArray[e].vertexIndex[1]);
|
||||
if (! boundaryEdgeIndices.containsKey(v_low)) {
|
||||
boundaryEdgeIndices.set(v_low, Array<int>());
|
||||
}
|
||||
boundaryEdgeIndices[v_low].append(e);
|
||||
|
||||
// We'll fill out newEdgeIndex[e] later, when we find pairs
|
||||
|
||||
} else {
|
||||
|
||||
// Copy the edge to the new array
|
||||
newEdgeIndex[e] = edgeArray.size();
|
||||
edgeArray.append(oldEdgeArray[e]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove all edges from the table that have pairs.
|
||||
Table<int, Array<int> >::Iterator cur = boundaryEdgeIndices.begin();
|
||||
Table<int, Array<int> >::Iterator end = boundaryEdgeIndices.end();
|
||||
while (cur != end) {
|
||||
Array<int>& boundaryEdge = cur->value;
|
||||
|
||||
for (int i = 0; i < boundaryEdge.size(); ++i) {
|
||||
int ei = boundaryEdge[i];
|
||||
const Edge& edgei = oldEdgeArray[ei];
|
||||
|
||||
for (int j = i + 1; j < boundaryEdge.size(); ++j) {
|
||||
int ej = boundaryEdge[j];
|
||||
const Edge& edgej = oldEdgeArray[ej];
|
||||
|
||||
// See if edge ei is the reverse (match) of edge ej.
|
||||
|
||||
// True if the edges match
|
||||
bool match = false;
|
||||
|
||||
// True if edgej's vertex indices are reversed from
|
||||
// edgei's (usually true).
|
||||
bool reversej = false;
|
||||
|
||||
int u = edgei.vertexIndex[0];
|
||||
int v = edgei.vertexIndex[1];
|
||||
|
||||
if (edgei.faceIndex[0] != Face::NONE) {
|
||||
// verts|faces
|
||||
// edgei = [u v A /]
|
||||
|
||||
if (edgej.faceIndex[0] != Face::NONE) {
|
||||
if ((edgej.vertexIndex[0] == v) && (edgej.vertexIndex[1] == u)) {
|
||||
// This is the most common of the four cases
|
||||
|
||||
// edgej = [v u B /]
|
||||
match = true;
|
||||
reversej = true;
|
||||
}
|
||||
} else {
|
||||
if ((edgej.vertexIndex[0] == u) && (edgej.vertexIndex[1] == v)) {
|
||||
// edgej = [u v / B]
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// edgei = [u v / A]
|
||||
if (edgej.faceIndex[0] != Face::NONE) {
|
||||
if ((edgej.vertexIndex[0] == u) && (edgej.vertexIndex[1] == v)) {
|
||||
// edgej = [u v B /]
|
||||
match = true;
|
||||
}
|
||||
} else {
|
||||
if ((edgej.vertexIndex[0] == v) && (edgej.vertexIndex[1] == u)) {
|
||||
// edgej = [v u / B]
|
||||
match = true;
|
||||
reversej = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
// ei and ej can be paired as a single edge
|
||||
int e = edgeArray.size();
|
||||
Edge& edge = edgeArray.next();
|
||||
|
||||
// Follow the direction of edgei.
|
||||
edge = edgei;
|
||||
newEdgeIndex[ei] = e;
|
||||
|
||||
// Insert the face index for edgej.
|
||||
int fj = edgej.faceIndex[0];
|
||||
if (fj == Face::NONE) {
|
||||
fj = edgej.faceIndex[1];
|
||||
}
|
||||
|
||||
if (edge.faceIndex[0] == Face::NONE) {
|
||||
edge.faceIndex[0] = fj;
|
||||
} else {
|
||||
edge.faceIndex[1] = fj;
|
||||
}
|
||||
|
||||
if (reversej) {
|
||||
// The new edge is backwards of the old edge for ej
|
||||
newEdgeIndex[ej] = ~e;
|
||||
} else {
|
||||
newEdgeIndex[ej] = e;
|
||||
}
|
||||
|
||||
// Remove both ei and ej from being candidates for future pairing.
|
||||
// Remove ej first since it comes later in the list (removing
|
||||
// ei would decrease the index of ej to j - 1).
|
||||
boundaryEdge.fastRemove(j);
|
||||
boundaryEdge.fastRemove(i);
|
||||
|
||||
// Re-process element i, which is now a new edge index
|
||||
--i;
|
||||
|
||||
// Jump out of the j for-loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
++cur;
|
||||
}
|
||||
|
||||
// Anything remaining in the table is a real boundary edge; just copy it to
|
||||
// the end of the array.
|
||||
cur = boundaryEdgeIndices.begin();
|
||||
end = boundaryEdgeIndices.end();
|
||||
while (cur != end) {
|
||||
Array<int>& boundaryEdge = cur->value;
|
||||
|
||||
for (int b = 0; b < boundaryEdge.size(); ++b) {
|
||||
const int e = boundaryEdge[b];
|
||||
|
||||
newEdgeIndex[e] = edgeArray.size();
|
||||
edgeArray.append(oldEdgeArray[e]);
|
||||
}
|
||||
|
||||
++cur;
|
||||
}
|
||||
|
||||
// Finally, fix up edge indices in the face and vertex arrays
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
Face& face = faceArray[f];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
int e = face.edgeIndex[i];
|
||||
|
||||
if (e < 0) {
|
||||
face.edgeIndex[i] = ~newEdgeIndex[~e];
|
||||
} else {
|
||||
face.edgeIndex[i] = newEdgeIndex[e];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
Vertex& vertex = vertexArray[v];
|
||||
for (int i = 0; i < vertex.edgeIndex.size(); ++i) {
|
||||
int e = vertex.edgeIndex[i];
|
||||
|
||||
if (e < 0) {
|
||||
vertex.edgeIndex[i] = ~newEdgeIndex[~e];
|
||||
} else {
|
||||
vertex.edgeIndex[i] = newEdgeIndex[e];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::weldAdjacency(
|
||||
const Array<Vector3>& originalGeometry,
|
||||
Array<Face>& faceArray,
|
||||
Array<Edge>& edgeArray,
|
||||
Array<Vertex>& vertexArray,
|
||||
double radius) {
|
||||
|
||||
// Num vertices
|
||||
const int n = originalGeometry.size();
|
||||
|
||||
// canonical[v] = first occurance of any vertex near oldVertexArray[v]
|
||||
Array<int> canonical;
|
||||
canonical.resize(n);
|
||||
|
||||
Array<int> toNew, toOld;
|
||||
// Throw away the new vertex array
|
||||
Array<Vector3> dummy;
|
||||
computeWeld(originalGeometry, dummy, toNew, toOld, radius);
|
||||
|
||||
for (int v = 0; v < canonical.size(); ++v) {
|
||||
// Round-trip through the toNew/toOld process. This will give
|
||||
// us the original vertex.
|
||||
canonical[v] = toOld[toNew[v]];
|
||||
}
|
||||
|
||||
// Destroy vertexArray (we reconstruct it below)
|
||||
vertexArray.clear();
|
||||
vertexArray.resize(n);
|
||||
|
||||
bool hasBoundaryEdges = false;
|
||||
|
||||
// Fix edge vertex indices
|
||||
for (int e = 0; e < edgeArray.size(); ++e) {
|
||||
Edge& edge = edgeArray[e];
|
||||
|
||||
const int v0 = canonical[edge.vertexIndex[0]];
|
||||
const int v1 = canonical[edge.vertexIndex[1]];
|
||||
|
||||
edge.vertexIndex[0] = v0;
|
||||
edge.vertexIndex[1] = v1;
|
||||
|
||||
vertexArray[v0].edgeIndex.append(e);
|
||||
vertexArray[v1].edgeIndex.append(~e);
|
||||
|
||||
hasBoundaryEdges = hasBoundaryEdges || edge.boundary();
|
||||
}
|
||||
|
||||
// Fix face vertex indices
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
Face& face = faceArray[f];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const int v = canonical[face.vertexIndex[i]];
|
||||
|
||||
face.vertexIndex[i] = v;
|
||||
|
||||
// Add the back pointer
|
||||
vertexArray[v].faceIndex.append(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasBoundaryEdges) {
|
||||
// As a result of the welding, some of the boundary edges at
|
||||
// the end of the array may now have mates and no longer be
|
||||
// boundaries. Try to pair these up.
|
||||
|
||||
weldBoundaryEdges(faceArray, edgeArray, vertexArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshAlg::debugCheckConsistency(
|
||||
const Array<Face>& faceArray,
|
||||
const Array<Edge>& edgeArray,
|
||||
const Array<Vertex>& vertexArray) {
|
||||
|
||||
#ifdef _DEBUG
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
const MeshAlg::Vertex& vertex = vertexArray[v];
|
||||
|
||||
for (int i = 0; i < vertex.edgeIndex.size(); ++i) {
|
||||
const int e = vertex.edgeIndex[i];
|
||||
debugAssert(edgeArray[(e >= 0) ? e : ~e].containsVertex(v));
|
||||
}
|
||||
|
||||
for (int i = 0; i < vertex.faceIndex.size(); ++i) {
|
||||
const int f = vertex.faceIndex[i];
|
||||
debugAssert(faceArray[f].containsVertex(v));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (int e = 0; e < edgeArray.size(); ++e) {
|
||||
const MeshAlg::Edge& edge = edgeArray[e];
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
debugAssert((edge.faceIndex[i] == MeshAlg::Face::NONE) ||
|
||||
faceArray[edge.faceIndex[i]].containsEdge(e));
|
||||
|
||||
debugAssert(vertexArray[edge.vertexIndex[i]].inEdge(e));
|
||||
}
|
||||
}
|
||||
|
||||
// Every face's edge must be on that face
|
||||
for (int f = 0; f < faceArray.size(); ++f) {
|
||||
const MeshAlg::Face& face = faceArray[f];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
int e = face.edgeIndex[i];
|
||||
int ei = (e >= 0) ? e : ~e;
|
||||
debugAssert(edgeArray[ei].inFace(f));
|
||||
|
||||
// Make sure the edge is oriented appropriately
|
||||
if (e >= 0) {
|
||||
debugAssert(edgeArray[ei].faceIndex[0] == (int)f);
|
||||
} else {
|
||||
debugAssert(edgeArray[ei].faceIndex[1] == (int)f);
|
||||
}
|
||||
|
||||
debugAssert(vertexArray[face.vertexIndex[i]].inFace(f));
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)faceArray;
|
||||
(void)edgeArray;
|
||||
(void)vertexArray;
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
} // G3D namespace
|
||||
213
dep/src/g3dlite/MeshAlgWeld.cpp
Normal file
213
dep/src/g3dlite/MeshAlgWeld.cpp
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/**
|
||||
@file MeshAlgWeld.cpp
|
||||
|
||||
The MeshAlg::computeWeld method.
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2003-10-22
|
||||
@edited 2005-02-24
|
||||
|
||||
Copyright 2000-2003, Morgan McGuire.
|
||||
All rights reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "G3D/MeshAlg.h"
|
||||
#include "G3D/Table.h"
|
||||
#include "G3D/Set.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
namespace _internal {
|
||||
|
||||
class Welder {
|
||||
private:
|
||||
|
||||
// Intentionally illegal
|
||||
Welder& operator=(const Welder& w);
|
||||
|
||||
public:
|
||||
/** Indices of newVertexArray elements in <B>or near</B> a grid cell. */
|
||||
typedef Array<int> List;
|
||||
|
||||
enum {GRID_RES = 32};
|
||||
|
||||
List grid[GRID_RES][GRID_RES][GRID_RES];
|
||||
|
||||
const Array<Vector3>& oldVertexArray;
|
||||
Array<Vector3>& newVertexArray;
|
||||
Array<int>& toNew;
|
||||
Array<int>& toOld;
|
||||
|
||||
/** Must be less than one grid cell, not checked */
|
||||
const double radius;
|
||||
|
||||
/** (oldVertexArray[i] - offset) * scale is on the range [0, 1] */
|
||||
Vector3 offset;
|
||||
Vector3 scale;
|
||||
|
||||
Welder(
|
||||
const Array<Vector3>& _oldVertexArray,
|
||||
Array<Vector3>& _newVertexArray,
|
||||
Array<int>& _toNew,
|
||||
Array<int>& _toOld,
|
||||
double _radius);
|
||||
|
||||
/**
|
||||
Computes the grid index from an ordinate.
|
||||
*/
|
||||
void toGridCoords(Vector3 v, int& x, int& y, int& z) const;
|
||||
|
||||
/** Gets the index of a vertex, adding it to
|
||||
newVertexArray if necessary. */
|
||||
int getIndex(const Vector3& vertex);
|
||||
|
||||
void weld();
|
||||
};
|
||||
|
||||
} // namespace _internal
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
template<> struct HashTrait<G3D::_internal::Welder::List*> {
|
||||
static size_t hashCode(const G3D::_internal::Welder::List* key) { return reinterpret_cast<size_t>(key); }
|
||||
};
|
||||
|
||||
namespace G3D {
|
||||
namespace _internal {
|
||||
|
||||
Welder::Welder(
|
||||
const Array<Vector3>& _oldVertexArray,
|
||||
Array<Vector3>& _newVertexArray,
|
||||
Array<int>& _toNew,
|
||||
Array<int>& _toOld,
|
||||
double _radius) :
|
||||
oldVertexArray(_oldVertexArray),
|
||||
newVertexArray(_newVertexArray),
|
||||
toNew(_toNew),
|
||||
toOld(_toOld),
|
||||
radius(_radius) {
|
||||
|
||||
// Compute a scale factor that moves the range
|
||||
// of all ordinates to [0, 1]
|
||||
Vector3 minBound = Vector3::inf();
|
||||
Vector3 maxBound = -minBound;
|
||||
|
||||
for (int i = 0; i < oldVertexArray.size(); ++i) {
|
||||
minBound = minBound.min(oldVertexArray[i]);
|
||||
maxBound = maxBound.max(oldVertexArray[i]);
|
||||
}
|
||||
|
||||
offset = minBound;
|
||||
scale = maxBound - minBound;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
// The model might have zero extent along some axis
|
||||
if (fuzzyEq(scale[i], 0.0)) {
|
||||
scale[i] = 1.0;
|
||||
} else {
|
||||
scale[i] = 1.0 / scale[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Welder::toGridCoords(Vector3 v, int& x, int& y, int& z) const {
|
||||
v = (v - offset) * scale;
|
||||
x = iClamp(iFloor(v.x * GRID_RES), 0, GRID_RES - 1);
|
||||
y = iClamp(iFloor(v.y * GRID_RES), 0, GRID_RES - 1);
|
||||
z = iClamp(iFloor(v.z * GRID_RES), 0, GRID_RES - 1);
|
||||
}
|
||||
|
||||
|
||||
int Welder::getIndex(const Vector3& vertex) {
|
||||
|
||||
int closestIndex = -1;
|
||||
double distanceSquared = inf();
|
||||
|
||||
int ix, iy, iz;
|
||||
toGridCoords(vertex, ix, iy, iz);
|
||||
|
||||
// Check against all vertices within radius of this grid cube
|
||||
const List& list = grid[ix][iy][iz];
|
||||
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
double d = (newVertexArray[list[i]] - vertex).squaredMagnitude();
|
||||
|
||||
if (d < distanceSquared) {
|
||||
distanceSquared = d;
|
||||
closestIndex = list[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (distanceSquared <= radius * radius) {
|
||||
|
||||
return closestIndex;
|
||||
|
||||
} else {
|
||||
|
||||
// This is a new vertex
|
||||
int newIndex = newVertexArray.size();
|
||||
newVertexArray.append(vertex);
|
||||
|
||||
// Create a new vertex and store its index in the
|
||||
// neighboring grid cells (usually, only 1 neighbor)
|
||||
|
||||
Set<List*> neighbors;
|
||||
|
||||
for (float dx = -1; dx <= +1; ++dx) {
|
||||
for (float dy = -1; dy <= +1; ++dy) {
|
||||
for (float dz = -1; dz <= +1; ++dz) {
|
||||
int ix, iy, iz;
|
||||
toGridCoords(vertex + Vector3(dx, dy, dz) * radius, ix, iy, iz);
|
||||
neighbors.insert(&(grid[ix][iy][iz]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<List*>::Iterator neighbor(neighbors.begin());
|
||||
Set<List*>::Iterator none(neighbors.end());
|
||||
|
||||
while (neighbor != none) {
|
||||
(*neighbor)->append(newIndex);
|
||||
++neighbor;
|
||||
}
|
||||
|
||||
return newIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Welder::weld() {
|
||||
newVertexArray.resize(0);
|
||||
|
||||
// Prime the vertex positions
|
||||
for (int i = 0; i < oldVertexArray.size(); ++i) {
|
||||
getIndex(oldVertexArray[i]);
|
||||
}
|
||||
|
||||
// Now create the official remapping by snapping to
|
||||
// nearby vertices.
|
||||
toNew.resize(oldVertexArray.size());
|
||||
toOld.resize(newVertexArray.size());
|
||||
|
||||
for (int oi = 0; oi < oldVertexArray.size(); ++oi) {
|
||||
toNew[oi] = getIndex(oldVertexArray[oi]);
|
||||
toOld[toNew[oi]] = oi;
|
||||
}
|
||||
}
|
||||
|
||||
} // internal namespace
|
||||
|
||||
|
||||
void MeshAlg::computeWeld(
|
||||
const Array<Vector3>& oldVertexArray,
|
||||
Array<Vector3>& newVertexArray,
|
||||
Array<int>& toNew,
|
||||
Array<int>& toOld,
|
||||
double radius) {
|
||||
|
||||
_internal::Welder welder(oldVertexArray, newVertexArray, toNew, toOld, radius);
|
||||
welder.weld();
|
||||
}
|
||||
|
||||
} // G3D namespace
|
||||
113
dep/src/g3dlite/MeshBuilder.cpp
Normal file
113
dep/src/g3dlite/MeshBuilder.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
@file MeshBuilder.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2002-02-27
|
||||
@edited 2005-02-24
|
||||
*/
|
||||
|
||||
#include "G3D/MeshBuilder.h"
|
||||
#include "G3D/MeshAlg.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void MeshBuilder::setName(const std::string& n) {
|
||||
name = n;
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::commit(std::string& n, Array<int>& indexArray, Array<Vector3>& outvertexArray) {
|
||||
n = name;
|
||||
|
||||
// Make the data fit in a unit cube
|
||||
centerTriList();
|
||||
|
||||
Array<int> toNew, toOld;
|
||||
|
||||
if (close == MeshBuilder::AUTO_WELD) {
|
||||
Array<int> index;
|
||||
MeshAlg::createIndexArray(triList.size(), index);
|
||||
double minEdgeLen, maxEdgeLen, meanEdgeLen, medianEdgeLen;
|
||||
double minFaceArea, maxFaceArea, meanFaceArea, medianFaceArea;
|
||||
MeshAlg::computeAreaStatistics(triList, index,
|
||||
minEdgeLen, meanEdgeLen, medianEdgeLen, maxEdgeLen,
|
||||
minFaceArea, meanFaceArea, medianFaceArea, maxFaceArea);
|
||||
close = minEdgeLen * 0.1;
|
||||
}
|
||||
|
||||
MeshAlg::computeWeld(triList, outvertexArray, toNew, toOld, close);
|
||||
|
||||
// Construct triangles
|
||||
for (int t = 0; t < triList.size(); t += 3) {
|
||||
int index[3];
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
index[i] = toNew[t + i];
|
||||
}
|
||||
|
||||
// Throw out zero size triangles
|
||||
if ((index[0] != index[1]) &&
|
||||
(index[1] != index[2]) &&
|
||||
(index[2] != index[0])) {
|
||||
indexArray.append(index[0], index[1], index[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::centerTriList() {
|
||||
// Compute the range of the vertices
|
||||
Vector3 vmin, vmax;
|
||||
|
||||
computeBounds(vmin, vmax);
|
||||
|
||||
Vector3 diagonal = vmax - vmin;
|
||||
double scale = max(max(diagonal.x, diagonal.y), diagonal.z) / 2;
|
||||
debugAssert(scale > 0);
|
||||
|
||||
Vector3 translation = vmin + diagonal / 2;
|
||||
|
||||
// Center and scale all vertices in the input list
|
||||
int v;
|
||||
|
||||
//Matrix3 rot90 = Matrix3::fromAxisAngle(Vector3::UNIT_Y, toRadians(180)) * Matrix3::fromAxisAngle(Vector3::UNIT_X, toRadians(90));
|
||||
for (v = 0; v < triList.size(); ++v) {
|
||||
triList[v] = (triList[v] - translation) / scale;
|
||||
//triList[v] = rot90 * triList[v];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::computeBounds(Vector3& min, Vector3& max) {
|
||||
min = Vector3::inf();
|
||||
max = -min;
|
||||
|
||||
int v;
|
||||
for (v = 0; v < triList.size(); ++v) {
|
||||
min = min.min(triList[v]);
|
||||
max = max.max(triList[v]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::addTriangle(const Vector3& a, const Vector3& b, const Vector3& c) {
|
||||
triList.append(a, b, c);
|
||||
|
||||
if (_twoSided) {
|
||||
triList.append(c, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::addQuad(const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d) {
|
||||
addTriangle(a, b, c);
|
||||
addTriangle(a, c, d);
|
||||
}
|
||||
|
||||
|
||||
void MeshBuilder::addTriangle(const Triangle& t) {
|
||||
addTriangle(t.vertex(0), t.vertex(1), t.vertex(2));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
164
dep/src/g3dlite/NetAddress.cpp
Normal file
164
dep/src/g3dlite/NetAddress.cpp
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/**
|
||||
@file NetMessage.cpp
|
||||
|
||||
@maintainer Morgan McGuire, morgan@cs.brown.edu
|
||||
@created 2005-02-06
|
||||
@edited 2005-02-06
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/NetAddress.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/Array.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/System.h"
|
||||
#include "G3D/NetworkDevice.h"
|
||||
|
||||
#if defined(G3D_LINUX) || defined(G3D_OSX)
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#define _alloca alloca
|
||||
|
||||
# ifndef SOCKADDR_IN
|
||||
# define SOCKADDR_IN struct sockaddr_in
|
||||
# endif
|
||||
# ifndef SOCKET
|
||||
# define SOCKET int
|
||||
# endif
|
||||
|
||||
// SOCKADDR_IN is supposed to be defined in NetAddress.h
|
||||
#ifndef SOCKADDR_IN
|
||||
# error Network headers included in wrong order
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
namespace G3D {
|
||||
|
||||
NetAddress::NetAddress() {
|
||||
System::memset(&addr, 0, sizeof(addr));
|
||||
}
|
||||
|
||||
void NetAddress::init(uint32 host, uint16 port) {
|
||||
if ((host != 0) || (port != 0)) {
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
if (host == 0) {
|
||||
host = INADDR_ANY;
|
||||
}
|
||||
addr.sin_addr.s_addr = htonl(host);
|
||||
} else {
|
||||
System::memset(&addr, 0, sizeof(addr));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NetAddress::NetAddress(
|
||||
const std::string& hostname,
|
||||
uint16 port) {
|
||||
init(hostname, port);
|
||||
}
|
||||
|
||||
|
||||
void NetAddress::init(
|
||||
const std::string& hostname,
|
||||
uint16 port) {
|
||||
|
||||
uint32 addr;
|
||||
|
||||
if (hostname == "") {
|
||||
addr = INADDR_NONE;
|
||||
} else {
|
||||
addr = inet_addr(hostname.c_str());
|
||||
}
|
||||
|
||||
// The address wasn't in numeric form, resolve it
|
||||
if (addr == INADDR_NONE) {
|
||||
// Get the IP address of the server and store it in host
|
||||
struct hostent* host = gethostbyname(hostname.c_str());
|
||||
|
||||
if (host == NULL) {
|
||||
init(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
System::memcpy(&addr, host->h_addr_list[0], host->h_length);
|
||||
}
|
||||
|
||||
if (addr != INADDR_NONE) {
|
||||
addr = ntohl(addr);
|
||||
}
|
||||
init(addr, port);
|
||||
}
|
||||
|
||||
|
||||
NetAddress::NetAddress(uint32 hostip, uint16 port) {
|
||||
init(hostip, port);
|
||||
}
|
||||
|
||||
|
||||
NetAddress NetAddress::broadcastAddress(uint16 port) {
|
||||
return NetAddress(NetworkDevice::instance()->broadcastAddressArray()[0], port);
|
||||
}
|
||||
|
||||
|
||||
NetAddress::NetAddress(const std::string& hostnameAndPort) {
|
||||
|
||||
Array<std::string> part = stringSplit(hostnameAndPort, ':');
|
||||
|
||||
debugAssert(part.length() == 2);
|
||||
init(part[0], atoi(part[1].c_str()));
|
||||
}
|
||||
|
||||
|
||||
NetAddress::NetAddress(const SOCKADDR_IN& a) {
|
||||
addr = a;
|
||||
}
|
||||
|
||||
|
||||
NetAddress::NetAddress(const struct in_addr& addr, uint16 port) {
|
||||
#ifdef G3D_WIN32
|
||||
init(ntohl(addr.S_un.S_addr), port);
|
||||
#else
|
||||
init(htonl(addr.s_addr), port);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NetAddress::serialize(class BinaryOutput& b) const {
|
||||
b.writeUInt32(ip());
|
||||
b.writeUInt16(port());
|
||||
}
|
||||
|
||||
|
||||
void NetAddress::deserialize(class BinaryInput& b) {
|
||||
uint32 i;
|
||||
uint16 p;
|
||||
|
||||
i = b.readUInt32();
|
||||
p = b.readUInt16();
|
||||
|
||||
init(i, p);
|
||||
}
|
||||
|
||||
|
||||
bool NetAddress::ok() const {
|
||||
return addr.sin_family != 0;
|
||||
}
|
||||
|
||||
|
||||
std::string NetAddress::ipString() const {
|
||||
return format("%s", inet_ntoa(*(in_addr*)&(addr.sin_addr)));
|
||||
}
|
||||
|
||||
|
||||
std::string NetAddress::toString() const {
|
||||
return ipString() + format(":%d", ntohs(addr.sin_port));
|
||||
}
|
||||
|
||||
}
|
||||
1362
dep/src/g3dlite/NetworkDevice.cpp
Normal file
1362
dep/src/g3dlite/NetworkDevice.cpp
Normal file
File diff suppressed because it is too large
Load diff
77
dep/src/g3dlite/PhysicsFrame.cpp
Normal file
77
dep/src/g3dlite/PhysicsFrame.cpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
@file PhysicsFrame.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2002-07-09
|
||||
@edited 2006-01-25
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/PhysicsFrame.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
PhysicsFrame::PhysicsFrame() {
|
||||
translation = Vector3::zero();
|
||||
rotation = Quat();
|
||||
}
|
||||
|
||||
|
||||
PhysicsFrame::PhysicsFrame(
|
||||
const CoordinateFrame& coordinateFrame) {
|
||||
|
||||
translation = coordinateFrame.translation;
|
||||
rotation = Quat(coordinateFrame.rotation);
|
||||
}
|
||||
|
||||
|
||||
PhysicsFrame PhysicsFrame::operator*(const PhysicsFrame& other) const {
|
||||
PhysicsFrame result;
|
||||
|
||||
result.rotation = rotation * other.rotation;
|
||||
result.translation = translation + rotation.toRotationMatrix() * other.translation;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame PhysicsFrame::toCoordinateFrame() const {
|
||||
CoordinateFrame f;
|
||||
|
||||
f.translation = translation;
|
||||
f.rotation = rotation.toRotationMatrix();
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
PhysicsFrame PhysicsFrame::lerp(
|
||||
const PhysicsFrame& other,
|
||||
float alpha) const {
|
||||
|
||||
PhysicsFrame result;
|
||||
|
||||
result.translation = translation.lerp(other.translation, alpha);
|
||||
result.rotation = rotation.slerp(other.rotation, alpha);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void PhysicsFrame::deserialize(class BinaryInput& b) {
|
||||
translation.deserialize(b);
|
||||
rotation.deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void PhysicsFrame::serialize(class BinaryOutput& b) const {
|
||||
translation.serialize(b);
|
||||
rotation.serialize(b);
|
||||
}
|
||||
|
||||
|
||||
}; // namespace
|
||||
|
||||
|
|
@ -1,19 +1,37 @@
|
|||
/**
|
||||
@file Plane.cpp
|
||||
|
||||
@maintainer Morgan McGuire, matrix@graphics3d.com
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-02-06
|
||||
@edited 2006-01-29
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/format.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,
|
||||
|
|
@ -75,7 +93,7 @@ Plane::Plane(
|
|||
const Vector3& __normal,
|
||||
const Vector3& point) {
|
||||
|
||||
_normal = __normal.direction();
|
||||
_normal = __normal.direction();
|
||||
_distance = _normal.dot(point);
|
||||
}
|
||||
|
||||
|
|
|
|||
125
dep/src/g3dlite/PrecomputedRandom.cpp
Normal file
125
dep/src/g3dlite/PrecomputedRandom.cpp
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
@file PrecomputedRandom.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2009-03-31
|
||||
@edited 2009-07-01
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/PrecomputedRandom.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
PrecomputedRandom::PrecomputedRandom(int dataSize, uint32 seed) :
|
||||
Random((void*)NULL),
|
||||
m_hemiUniform(NULL),
|
||||
m_sphereBits(NULL),
|
||||
m_modMask(dataSize - 1),
|
||||
m_freeData(true) {
|
||||
|
||||
alwaysAssertM(isPow2(dataSize), "dataSize must be a power of 2");
|
||||
m_index = seed & m_modMask;
|
||||
|
||||
HemiUniformData* h;
|
||||
SphereBitsData* s;
|
||||
m_hemiUniform = h = (HemiUniformData*) System::malloc(sizeof(HemiUniformData) * dataSize);
|
||||
m_sphereBits = s = (SphereBitsData*) System::malloc(sizeof(SphereBitsData) * dataSize);
|
||||
|
||||
Random r;
|
||||
|
||||
for (int i = 0; i < dataSize; ++i) {
|
||||
h[i].uniform = r.uniform();
|
||||
r.cosHemi(h[i].cosHemiX, h[i].cosHemiY, h[i].cosHemiZ);
|
||||
|
||||
s[i].bits = r.bits();
|
||||
r.sphere(s[i].sphereX, s[i].sphereY, s[i].sphereZ);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
PrecomputedRandom::PrecomputedRandom(const HemiUniformData* data1, const SphereBitsData* data2, int dataSize, uint32 seed) :
|
||||
Random((void*)NULL),
|
||||
m_hemiUniform(data1),
|
||||
m_sphereBits(data2),
|
||||
m_modMask(dataSize - 1),
|
||||
m_freeData(false) {
|
||||
|
||||
m_index = seed & m_modMask;
|
||||
alwaysAssertM(isPow2(dataSize), "dataSize must be a power of 2");
|
||||
}
|
||||
|
||||
|
||||
PrecomputedRandom::~PrecomputedRandom() {
|
||||
if (m_freeData) {
|
||||
System::free(const_cast<HemiUniformData*>(m_hemiUniform));
|
||||
System::free(const_cast<SphereBitsData*>(m_sphereBits));
|
||||
}
|
||||
}
|
||||
|
||||
float PrecomputedRandom::uniform(float low, float high) {
|
||||
m_index = (m_index + 1) & m_modMask;
|
||||
return low + m_hemiUniform[m_index].uniform * (high - low);
|
||||
}
|
||||
|
||||
|
||||
float PrecomputedRandom::uniform() {
|
||||
m_index = (m_index + 1) & m_modMask;
|
||||
return m_hemiUniform[m_index].uniform;
|
||||
}
|
||||
|
||||
|
||||
void PrecomputedRandom::cosHemi(float& x, float& y, float& z) {
|
||||
m_index = (m_index + 1) & m_modMask;
|
||||
x = m_hemiUniform[m_index].cosHemiX;
|
||||
y = m_hemiUniform[m_index].cosHemiY;
|
||||
z = m_hemiUniform[m_index].cosHemiZ;
|
||||
}
|
||||
|
||||
void PrecomputedRandom::cosPowHemi(const float k, float& x, float& y, float& z) {
|
||||
// Computing a cosPowHemi costs 4 slow functions (pow, sqrt, sin,
|
||||
// cos). We can do it with two, given a cosHemi sample, basically
|
||||
// saving the cost of sin and cos and making a single 128-byte
|
||||
// memory read (for a vector) instead of two (for adjacent uniform
|
||||
// floats).
|
||||
|
||||
// cos^1 distribution sample
|
||||
float cos1;
|
||||
cosHemi(x, y, cos1);
|
||||
|
||||
// Fix the distribution by adjusting the cosine:
|
||||
// rnd(cos^k t) = (rnd(cos(t))^2)^(1/k)
|
||||
|
||||
// produces cos^k distribution sample
|
||||
z = pow(cos1, 2.0f / (1.0f + k));
|
||||
|
||||
// Rescale x and y by sqrt(1.0f - square(z)) / sqrt(x*x + y*y).
|
||||
// Add a very tiny offset to handle the (almost impossibly unlikely) case where
|
||||
// z = 1 and x^2+y^2 = 0.
|
||||
static const float eps = 0.000001f;
|
||||
const float s = sqrt((1.0f + eps - square(z)) / (square(x) + square(y) + eps));
|
||||
|
||||
x *= s;
|
||||
y *= s;
|
||||
}
|
||||
|
||||
|
||||
uint32 PrecomputedRandom::bits() {
|
||||
m_index = (m_index + 1) & m_modMask;
|
||||
return m_sphereBits[m_index].bits;
|
||||
}
|
||||
|
||||
|
||||
void PrecomputedRandom::sphere(float& x, float& y, float& z) {
|
||||
m_index = (m_index + 1) & m_modMask;
|
||||
x = m_sphereBits[m_index].sphereX;
|
||||
y = m_sphereBits[m_index].sphereY;
|
||||
z = m_sphereBits[m_index].sphereZ;
|
||||
}
|
||||
|
||||
}
|
||||
583
dep/src/g3dlite/Quat.cpp
Normal file
583
dep/src/g3dlite/Quat.cpp
Normal 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
dep/src/g3dlite/Random.cpp
Normal file
212
dep/src/g3dlite/Random.cpp
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/**
|
||||
@file Random.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2009-01-02
|
||||
@edited 2009-03-29
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
#include "G3D/Random.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Random& Random::common() {
|
||||
static Random r;
|
||||
return r;
|
||||
}
|
||||
|
||||
Random::Random(void* x) : state(NULL), m_threadsafe(false) {
|
||||
(void)x;
|
||||
}
|
||||
|
||||
|
||||
Random::Random(uint32 seed, bool threadsafe) : m_threadsafe(threadsafe) {
|
||||
const uint32 X = 1812433253UL;
|
||||
|
||||
state = new uint32[N];
|
||||
state[0] = seed;
|
||||
for (index = 1; index < (int)N; ++index) {
|
||||
state[index] = X * (state[index - 1] ^ (state[index - 1] >> 30)) + index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Random::~Random() {
|
||||
delete[] state;
|
||||
state = NULL;
|
||||
}
|
||||
|
||||
|
||||
uint32 Random::bits() {
|
||||
// See http://en.wikipedia.org/wiki/Mersenne_twister
|
||||
|
||||
// Make a local copy of the index variable to ensure that it
|
||||
// is not out of bounds
|
||||
int localIndex = index;
|
||||
|
||||
// Automatically checks for index < 0 if corrupted
|
||||
// by unsynchronized threads.
|
||||
if ((unsigned int)localIndex >= (unsigned int)N) {
|
||||
generate();
|
||||
localIndex = 0;
|
||||
}
|
||||
// Increment the global index. It may go out of bounds on
|
||||
// multiple threads, but the above check ensures that the
|
||||
// array index actually used never goes out of bounds.
|
||||
// It doesn't matter if we grab the same array index twice
|
||||
// on two threads, since the distribution of random numbers
|
||||
// will still be uniform.
|
||||
++index;
|
||||
// Return the next random in the sequence
|
||||
uint32 r = state[localIndex];
|
||||
|
||||
// Temper the result
|
||||
r ^= r >> U;
|
||||
r ^= (r << S) & B;
|
||||
r ^= (r << T) & C;
|
||||
r ^= r >> L;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/** Generate the next N ints, and store them for readback later */
|
||||
void Random::generate() {
|
||||
// Lower R bits
|
||||
static const uint32 LOWER_MASK = (1LU << R) - 1;
|
||||
|
||||
// Upper (32 - R) bits
|
||||
static const uint32 UPPER_MASK = 0xFFFFFFFF << R;
|
||||
static const uint32 mag01[2] = {0UL, (uint32)A};
|
||||
|
||||
if (m_threadsafe) {
|
||||
bool contention = ! lock.lock();
|
||||
if (contention) {
|
||||
// Another thread just generated a set of numbers; no need for
|
||||
// this thread to do it too
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// First N - M
|
||||
for (unsigned int i = 0; i < N - M; ++i) {
|
||||
uint32 x = (state[i] & UPPER_MASK) | (state[i + 1] & LOWER_MASK);
|
||||
state[i] = state[i + M] ^ (x >> 1) ^ mag01[x & 1];
|
||||
}
|
||||
|
||||
// Rest
|
||||
for (unsigned int i = N - M + 1; i < N - 1; ++i) {
|
||||
uint32 x = (state[i] & UPPER_MASK) | (state[i + 1] & LOWER_MASK);
|
||||
state[i] = state[i + (M - N)] ^ (x >> 1) ^ mag01[x & 1];
|
||||
}
|
||||
|
||||
uint32 y = (state[N - 1] & UPPER_MASK) | (state[0] & LOWER_MASK);
|
||||
state[N - 1] = state[M - 1] ^ (y >> 1) ^ mag01[y & 1];
|
||||
index = 0;
|
||||
|
||||
if (m_threadsafe) {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Random::integer(int low, int high) {
|
||||
int r = iFloor(low + (high - low + 1) * (double)bits() / 0xFFFFFFFFUL);
|
||||
|
||||
// There is a *very small* chance of generating
|
||||
// a number larger than high.
|
||||
if (r > high) {
|
||||
return high;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float Random::gaussian(float mean, float stdev) {
|
||||
|
||||
// Using Box-Mueller method from http://www.taygeta.com/random/gaussian.html
|
||||
// Modified to specify standard deviation and mean of distribution
|
||||
float w, x1, x2;
|
||||
|
||||
// Loop until w is less than 1 so that log(w) is negative
|
||||
do {
|
||||
x1 = uniform(-1.0, 1.0);
|
||||
x2 = uniform(-1.0, 1.0);
|
||||
|
||||
w = float(square(x1) + square(x2));
|
||||
} while (w > 1.0f);
|
||||
|
||||
// Transform to gassian distribution
|
||||
// Multiply by sigma (stdev ^ 2) and add mean.
|
||||
return x2 * (float)square(stdev) * sqrtf((-2.0f * logf(w) ) / w) + mean;
|
||||
}
|
||||
|
||||
|
||||
void Random::cosHemi(float& x, float& y, float& z) {
|
||||
const float e1 = uniform();
|
||||
const float e2 = uniform();
|
||||
|
||||
// Jensen's method
|
||||
const float sin_theta = sqrtf(1.0f - e1);
|
||||
const float cos_theta = sqrtf(e1);
|
||||
const float phi = 6.28318531f * e2;
|
||||
|
||||
x = cos(phi) * sin_theta;
|
||||
y = sin(phi) * sin_theta;
|
||||
z = cos_theta;
|
||||
|
||||
// We could also use Malley's method (pbrt p.657), since they are the same cost:
|
||||
//
|
||||
// r = sqrt(e1);
|
||||
// t = 2*pi*e2;
|
||||
// x = cos(t)*r;
|
||||
// y = sin(t)*r;
|
||||
// z = sqrt(1.0 - x*x + y*y);
|
||||
}
|
||||
|
||||
|
||||
void Random::cosPowHemi(const float k, float& x, float& y, float& z) {
|
||||
const float e1 = uniform();
|
||||
const float e2 = uniform();
|
||||
|
||||
const float cos_theta = pow(e1, 1.0f / (k + 1.0f));
|
||||
const float sin_theta = sqrtf(1.0f - square(cos_theta));
|
||||
const float phi = 6.28318531f * e2;
|
||||
|
||||
x = cos(phi) * sin_theta;
|
||||
y = sin(phi) * sin_theta;
|
||||
z = cos_theta;
|
||||
}
|
||||
|
||||
|
||||
void Random::hemi(float& x, float& y, float& z) {
|
||||
sphere(x, y, z);
|
||||
z = fabsf(z);
|
||||
}
|
||||
|
||||
|
||||
void Random::sphere(float& x, float& y, float& z) {
|
||||
// Squared magnitude
|
||||
float m2;
|
||||
|
||||
// Rejection sample
|
||||
do {
|
||||
x = uniform() * 2.0f - 1.0f,
|
||||
y = uniform() * 2.0f - 1.0f,
|
||||
z = uniform() * 2.0f - 1.0f;
|
||||
m2 = x*x + y*y + z*z;
|
||||
} while (m2 >= 1.0f);
|
||||
|
||||
// Divide by magnitude to produce a unit vector
|
||||
float s = rsqrt(m2);
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
}
|
||||
|
||||
} // G3D
|
||||
218
dep/src/g3dlite/Ray.cpp
Normal file
218
dep/src/g3dlite/Ray.cpp
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/**
|
||||
@file Ray.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2002-07-12
|
||||
@edited 2004-03-19
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Ray.h"
|
||||
#include "G3D/Plane.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/CollisionDetection.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void Ray::set(const Vector3& origin, const Vector3& direction) {
|
||||
m_origin = origin;
|
||||
m_direction = direction;
|
||||
debugAssert(direction.isUnit());
|
||||
|
||||
m_invDirection = Vector3::one() / direction;
|
||||
|
||||
// ray slope
|
||||
ibyj = m_direction.x * m_invDirection.y;
|
||||
jbyi = m_direction.y * m_invDirection.x;
|
||||
jbyk = m_direction.y * m_invDirection.z;
|
||||
kbyj = m_direction.z * m_invDirection.y;
|
||||
ibyk = m_direction.x * m_invDirection.z;
|
||||
kbyi = m_direction.z * m_invDirection.x;
|
||||
|
||||
// precomputed terms
|
||||
c_xy = m_origin.y - jbyi * m_origin.x;
|
||||
c_xz = m_origin.z - kbyi * m_origin.x;
|
||||
c_yx = m_origin.x - ibyj * m_origin.y;
|
||||
c_yz = m_origin.z - kbyj * m_origin.y;
|
||||
c_zx = m_origin.x - ibyk * m_origin.z;
|
||||
c_zy = m_origin.y - jbyk * m_origin.z;
|
||||
|
||||
//ray slope classification
|
||||
if (m_direction.x < 0) {
|
||||
if (m_direction.y < 0) {
|
||||
if (m_direction.z < 0) {
|
||||
classification = MMM;
|
||||
} else if (m_direction.z > 0) {
|
||||
classification = MMP;
|
||||
} else { //(m_direction.z >= 0)
|
||||
classification = MMO;
|
||||
}
|
||||
} else { //(m_direction.y >= 0)
|
||||
if (m_direction.z < 0) {
|
||||
if (m_direction.y == 0) {
|
||||
classification = MOM;
|
||||
} else {
|
||||
classification = MPM;
|
||||
}
|
||||
} else { //(m_direction.z >= 0)
|
||||
if ((m_direction.y == 0) && (m_direction.z == 0)) {
|
||||
classification = MOO;
|
||||
} else if (m_direction.z == 0) {
|
||||
classification = MPO;
|
||||
} else if (m_direction.y == 0) {
|
||||
classification = MOP;
|
||||
} else {
|
||||
classification = MPP;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //(m_direction.x >= 0)
|
||||
if (m_direction.y < 0) {
|
||||
if (m_direction.z < 0) {
|
||||
if (m_direction.x == 0) {
|
||||
classification = OMM;
|
||||
} else {
|
||||
classification = PMM;
|
||||
}
|
||||
} else { //(m_direction.z >= 0)
|
||||
if ((m_direction.x == 0) && (m_direction.z == 0)) {
|
||||
classification = OMO;
|
||||
} else if (m_direction.z == 0) {
|
||||
classification = PMO;
|
||||
} else if (m_direction.x == 0) {
|
||||
classification = OMP;
|
||||
} else {
|
||||
classification = PMP;
|
||||
}
|
||||
}
|
||||
} else { //(m_direction.y >= 0)
|
||||
if (m_direction.z < 0) {
|
||||
if ((m_direction.x == 0) && (m_direction.y == 0)) {
|
||||
classification = OOM;
|
||||
} else if (m_direction.x == 0) {
|
||||
classification = OPM;
|
||||
} else if (m_direction.y == 0) {
|
||||
classification = POM;
|
||||
} else {
|
||||
classification = PPM;
|
||||
}
|
||||
} else { //(m_direction.z > 0)
|
||||
if (m_direction.x == 0) {
|
||||
if (m_direction.y == 0) {
|
||||
classification = OOP;
|
||||
} else if (m_direction.z == 0) {
|
||||
classification = OPO;
|
||||
} else {
|
||||
classification = OPP;
|
||||
}
|
||||
} else {
|
||||
if ((m_direction.y == 0) && (m_direction.z == 0)) {
|
||||
classification = POO;
|
||||
} else if (m_direction.y == 0) {
|
||||
classification = POP;
|
||||
} else if (m_direction.z == 0) {
|
||||
classification = PPO;
|
||||
} else {
|
||||
classification = PPP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ray::Ray(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Ray::serialize(class BinaryOutput& b) const {
|
||||
m_origin.serialize(b);
|
||||
m_direction.serialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Ray::deserialize(class BinaryInput& b) {
|
||||
m_origin.deserialize(b);
|
||||
m_direction.deserialize(b);
|
||||
set(m_origin, m_direction);
|
||||
}
|
||||
|
||||
|
||||
Ray Ray::refract(
|
||||
const Vector3& newOrigin,
|
||||
const Vector3& normal,
|
||||
float iInside,
|
||||
float iOutside) const {
|
||||
|
||||
Vector3 D = m_direction.refractionDirection(normal, iInside, iOutside);
|
||||
return Ray(newOrigin + (m_direction + normal * (float)sign(m_direction.dot(normal))) * 0.001f, D);
|
||||
}
|
||||
|
||||
|
||||
Ray Ray::reflect(
|
||||
const Vector3& newOrigin,
|
||||
const Vector3& normal) const {
|
||||
|
||||
Vector3 D = m_direction.reflectionDirection(normal);
|
||||
return Ray(newOrigin + (D + normal) * 0.001f, D);
|
||||
}
|
||||
|
||||
|
||||
Vector3 Ray::intersection(const Plane& plane) const {
|
||||
float d;
|
||||
Vector3 normal = plane.normal();
|
||||
plane.getEquation(normal, d);
|
||||
float rate = m_direction.dot(normal);
|
||||
|
||||
if (rate >= 0.0f) {
|
||||
return Vector3::inf();
|
||||
} else {
|
||||
float t = -(d + m_origin.dot(normal)) / rate;
|
||||
return m_origin + m_direction * t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float Ray::intersectionTime(const class Sphere& sphere, bool solid) const {
|
||||
Vector3 dummy;
|
||||
return CollisionDetection::collisionTimeForMovingPointFixedSphere(
|
||||
m_origin, m_direction, sphere, dummy, dummy, solid);
|
||||
}
|
||||
|
||||
|
||||
float Ray::intersectionTime(const class Plane& plane) const {
|
||||
Vector3 dummy;
|
||||
return CollisionDetection::collisionTimeForMovingPointFixedPlane(
|
||||
m_origin, m_direction, plane, dummy);
|
||||
}
|
||||
|
||||
|
||||
float Ray::intersectionTime(const class Box& box) const {
|
||||
Vector3 dummy;
|
||||
float time = CollisionDetection::collisionTimeForMovingPointFixedBox(
|
||||
m_origin, m_direction, box, dummy);
|
||||
|
||||
if ((time == finf()) && (box.contains(m_origin))) {
|
||||
return 0.0f;
|
||||
} else {
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float Ray::intersectionTime(const class AABox& box) const {
|
||||
Vector3 dummy;
|
||||
bool inside;
|
||||
float time = CollisionDetection::collisionTimeForMovingPointFixedAABox(
|
||||
m_origin, m_direction, box, dummy, inside);
|
||||
|
||||
if ((time == finf()) && inside) {
|
||||
return 0.0f;
|
||||
} else {
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
41
dep/src/g3dlite/Rect2D.cpp
Normal file
41
dep/src/g3dlite/Rect2D.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
@file Rect2D.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-11-13
|
||||
@created 2009-11-16
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Rect2D.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
/** \param any Must either Rect2D::xywh(#, #, #, #) or Rect2D::xyxy(#, #, #, #)*/
|
||||
Rect2D::Rect2D(const Any& any) {
|
||||
any.verifyName("Rect2D");
|
||||
any.verifyType(Any::ARRAY);
|
||||
any.verifySize(4);
|
||||
if (toUpper(any.name()) == "RECT2D::XYWH") {
|
||||
*this = Rect2D::xywh(any[0], any[1], any[2], any[3]);
|
||||
} else {
|
||||
any.verifyName("Rect2D::xyxy");
|
||||
*this = Rect2D::xyxy(any[0], any[1], any[2], any[3]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Converts the Rect2D to an Any. */
|
||||
Rect2D::operator Any() const {
|
||||
Any any(Any::ARRAY, "Rect2D::xywh");
|
||||
any.append(x0(), y0(), width(), height());
|
||||
return any;
|
||||
}
|
||||
|
||||
}
|
||||
61
dep/src/g3dlite/ReferenceCount.cpp
Normal file
61
dep/src/g3dlite/ReferenceCount.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
@file ReferenceCount.cpp
|
||||
|
||||
Reference Counting Garbage Collector for C++
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@cite Adapted and extended from Justin Miller's "RGC" class that appeared in BYTE magazine.
|
||||
@cite See also http://www.jelovic.com/articles/cpp_without_memory_errors_slides.htm
|
||||
|
||||
@created 2001-10-23
|
||||
@edited 2009-04-25
|
||||
*/
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/ReferenceCount.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
ReferenceCountedObject::ReferenceCountedObject() :
|
||||
ReferenceCountedObject_refCount(0),
|
||||
ReferenceCountedObject_weakPointer(0) {
|
||||
|
||||
debugAssertM(isValidHeapPointer(this),
|
||||
"Reference counted objects must be allocated on the heap.");
|
||||
}
|
||||
|
||||
void ReferenceCountedObject::ReferenceCountedObject_zeroWeakPointers() {
|
||||
// Tell all of my weak pointers that I'm gone.
|
||||
|
||||
_WeakPtrLinkedList* node = ReferenceCountedObject_weakPointer;
|
||||
|
||||
while (node != NULL) {
|
||||
// Notify the weak pointer that it is going away
|
||||
node->weakPtr->objectCollected();
|
||||
|
||||
// Free the node and advance
|
||||
_WeakPtrLinkedList* tmp = node;
|
||||
node = node->next;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
ReferenceCountedObject::~ReferenceCountedObject() {}
|
||||
|
||||
|
||||
ReferenceCountedObject::ReferenceCountedObject(const ReferenceCountedObject& notUsed) :
|
||||
ReferenceCountedObject_refCount(0),
|
||||
ReferenceCountedObject_weakPointer(0) {
|
||||
(void)notUsed;
|
||||
debugAssertM(G3D::isValidHeapPointer(this),
|
||||
"Reference counted objects must be allocated on the heap.");
|
||||
}
|
||||
|
||||
ReferenceCountedObject& ReferenceCountedObject::operator=(const ReferenceCountedObject& other) {
|
||||
(void)other;
|
||||
// Nothing changes when I am assigned; the reference count on
|
||||
// both objects is the same (although my super-class probably
|
||||
// changes).
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // G3D
|
||||
290
dep/src/g3dlite/RegistryUtil.cpp
Normal file
290
dep/src/g3dlite/RegistryUtil.cpp
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
/**
|
||||
@file RegistryUtil.cpp
|
||||
|
||||
@created 2006-04-06
|
||||
@edited 2006-04-24
|
||||
|
||||
Copyright 2000-2006, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
|
||||
// This file is only used on Windows
|
||||
#ifdef G3D_WIN32
|
||||
|
||||
#include "G3D/RegistryUtil.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
// static helpers
|
||||
static HKEY getRootKeyFromString(const char* str, size_t length);
|
||||
|
||||
|
||||
bool RegistryUtil::keyExists(const std::string& key) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
|
||||
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
RegCloseKey(openKey);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RegistryUtil::valueExists(const std::string& key, const std::string& value) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if ( hkey == NULL ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
uint32 dataSize = 0;
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, NULL, reinterpret_cast<LPDWORD>(&dataSize));
|
||||
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
bool RegistryUtil::readInt32(const std::string& key, const std::string& value, int32& data) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if ( hkey == NULL ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
uint32 dataSize = sizeof(int32);
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(&data), reinterpret_cast<LPDWORD>(&dataSize));
|
||||
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
|
||||
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegistryUtil::readBytes(const std::string& key, const std::string& value, uint8* data, uint32& dataSize) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
if (data == NULL) {
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, NULL, reinterpret_cast<LPDWORD>(&dataSize));
|
||||
} else {
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(&data), reinterpret_cast<LPDWORD>(&dataSize));
|
||||
}
|
||||
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
|
||||
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegistryUtil::readString(const std::string& key, const std::string& value, std::string& data) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
uint32 dataSize = 0;
|
||||
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, NULL, reinterpret_cast<LPDWORD>(&dataSize));
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
|
||||
|
||||
// increment datasize to allow for non null-terminated strings in registry
|
||||
dataSize += 1;
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
char* tmpStr = static_cast<char*>(System::malloc(dataSize));
|
||||
System::memset(tmpStr, 0, dataSize);
|
||||
|
||||
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(tmpStr), reinterpret_cast<LPDWORD>(&dataSize));
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
data = tmpStr;
|
||||
}
|
||||
|
||||
RegCloseKey(openKey);
|
||||
System::free(tmpStr);
|
||||
}
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegistryUtil::writeInt32(const std::string& key, const std::string& value, int32 data) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_WRITE, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
result = RegSetValueExA(openKey, value.c_str(), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&data), sizeof(int32));
|
||||
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not write registry key value.");
|
||||
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegistryUtil::writeBytes(const std::string& key, const std::string& value, const uint8* data, uint32 dataSize) {
|
||||
debugAssert(data);
|
||||
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_WRITE, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
if (data) {
|
||||
result = RegSetValueExA(openKey, value.c_str(), 0, REG_BINARY, reinterpret_cast<const BYTE*>(data), dataSize);
|
||||
}
|
||||
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not write registry key value.");
|
||||
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegistryUtil::writeString(const std::string& key, const std::string& value, const std::string& data) {
|
||||
size_t pos = key.find('\\', 0);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
|
||||
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY openKey;
|
||||
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_WRITE, &openKey);
|
||||
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
result = RegSetValueExA(openKey, value.c_str(), 0, REG_SZ, reinterpret_cast<const BYTE*>(data.c_str()), (data.size() + 1));
|
||||
debugAssertM(result == ERROR_SUCCESS, "Could not write registry key value.");
|
||||
|
||||
RegCloseKey(openKey);
|
||||
}
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
// static helpers
|
||||
static HKEY getRootKeyFromString(const char* str, size_t length) {
|
||||
debugAssert(str);
|
||||
|
||||
if (str) {
|
||||
if ( strncmp(str, "HKEY_CLASSES_ROOT", length) == 0 ) {
|
||||
return HKEY_CLASSES_ROOT;
|
||||
} else if ( strncmp(str, "HKEY_CURRENT_CONFIG", length) == 0 ) {
|
||||
return HKEY_CURRENT_CONFIG;
|
||||
} else if ( strncmp(str, "HKEY_CURRENT_USER", length) == 0 ) {
|
||||
return HKEY_CURRENT_USER;
|
||||
} else if ( strncmp(str, "HKEY_LOCAL_MACHINE", length) == 0 ) {
|
||||
return HKEY_LOCAL_MACHINE;
|
||||
} else if ( strncmp(str, "HKEY_PERFORMANCE_DATA", length) == 0 ) {
|
||||
return HKEY_PERFORMANCE_DATA;
|
||||
} else if ( strncmp(str, "HKEY_PERFORMANCE_NLSTEXT", length) == 0 ) {
|
||||
return HKEY_PERFORMANCE_NLSTEXT;
|
||||
} else if ( strncmp(str, "HKEY_PERFORMANCE_TEXT", length) == 0 ) {
|
||||
return HKEY_PERFORMANCE_TEXT;
|
||||
} else if ( strncmp(str, "HKEY_CLASSES_ROOT", length) == 0 ) {
|
||||
return HKEY_CLASSES_ROOT;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
#endif // G3D_WIN32
|
||||
223
dep/src/g3dlite/Sphere.cpp
Normal file
223
dep/src/g3dlite/Sphere.cpp
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/**
|
||||
@file Sphere.cpp
|
||||
|
||||
Sphere class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-04-17
|
||||
@edited 2009-01-20
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/AABox.h"
|
||||
#include "G3D/Plane.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
int32 Sphere::dummy;
|
||||
|
||||
Sphere::Sphere(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Sphere::serialize(class BinaryOutput& b) const {
|
||||
center.serialize(b);
|
||||
b.writeFloat64(radius);
|
||||
}
|
||||
|
||||
|
||||
void Sphere::deserialize(class BinaryInput& b) {
|
||||
center.deserialize(b);
|
||||
radius = (float)b.readFloat64();
|
||||
}
|
||||
|
||||
|
||||
std::string Sphere::toString() const {
|
||||
return format("Sphere(<%g, %g, %g>, %g)",
|
||||
center.x, center.y, center.z, radius);
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::contains(const Vector3& point) const {
|
||||
float distance = (center - point).squaredMagnitude();
|
||||
return distance <= square(radius);
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::contains(const Sphere& other) const {
|
||||
float distance = (center - other.center).squaredMagnitude();
|
||||
return (radius >= other.radius) && (distance <= square(radius - other.radius));
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::intersects(const Sphere& other) const {
|
||||
return (other.center - center).length() <= (radius + other.radius);
|
||||
}
|
||||
|
||||
|
||||
void Sphere::merge(const Sphere& other) {
|
||||
if (other.contains(*this)) {
|
||||
*this = other;
|
||||
} else if (! contains(other)) {
|
||||
// The farthest distance is along the axis between the centers, which
|
||||
// must not be colocated since neither contains the other.
|
||||
Vector3 toMe = center - other.center;
|
||||
// Get a point on the axis from each
|
||||
toMe = toMe.direction();
|
||||
const Vector3& A = center + toMe * radius;
|
||||
const Vector3& B = other.center - toMe * other.radius;
|
||||
|
||||
// Now just bound the A->B segment
|
||||
center = (A + B) * 0.5f;
|
||||
radius = (A - B).length();
|
||||
}
|
||||
// (if this contains other, we're done)
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlaneIndex,
|
||||
const uint32 inMask,
|
||||
uint32& outMask) const {
|
||||
|
||||
return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask, outMask);
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::culledBy(
|
||||
const Array<Plane>& plane,
|
||||
int& cullingPlaneIndex,
|
||||
const uint32 inMask) const {
|
||||
|
||||
return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask);
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::culledBy(
|
||||
const class Plane* plane,
|
||||
int numPlanes,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask,
|
||||
uint32& childMask) const {
|
||||
|
||||
if (radius == finf()) {
|
||||
// No plane can cull the infinite box
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(numPlanes < 31);
|
||||
|
||||
childMask = 0;
|
||||
|
||||
// See if there is one plane for which all of the
|
||||
// vertices are in the negative half space.
|
||||
for (int p = 0; p < numPlanes; p++) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
|
||||
bool culledLow = ! plane[p].halfSpaceContainsFinite(center + plane[p].normal() * radius);
|
||||
bool culledHigh = ! plane[p].halfSpaceContainsFinite(center - plane[p].normal() * radius);
|
||||
|
||||
if (culledLow) {
|
||||
// Plane p culled the sphere
|
||||
cullingPlane = p;
|
||||
|
||||
// The caller should not recurse into the children,
|
||||
// since the parent is culled. If they do recurse,
|
||||
// make them only test against this one plane, which
|
||||
// will immediately cull the volume.
|
||||
childMask = 1 << p;
|
||||
return true;
|
||||
|
||||
} else if (culledHigh) {
|
||||
// The bounding volume straddled the plane; we have
|
||||
// to keep testing against this plane
|
||||
childMask |= (1 << p);
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next bit.
|
||||
inMask = inMask >> 1;
|
||||
}
|
||||
|
||||
// None of the planes could cull this box
|
||||
cullingPlane = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::culledBy(
|
||||
const class Plane* plane,
|
||||
int numPlanes,
|
||||
int& cullingPlane,
|
||||
const uint32 _inMask) const {
|
||||
|
||||
uint32 inMask = _inMask;
|
||||
assert(numPlanes < 31);
|
||||
|
||||
// See if there is one plane for which all of the
|
||||
// vertices are in the negative half space.
|
||||
for (int p = 0; p < numPlanes; p++) {
|
||||
|
||||
// Only test planes that are not masked
|
||||
if ((inMask & 1) != 0) {
|
||||
bool culled = ! plane[p].halfSpaceContains(center + plane[p].normal() * radius);
|
||||
if (culled) {
|
||||
// Plane p culled the sphere
|
||||
cullingPlane = p;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next bit.
|
||||
inMask = inMask >> 1;
|
||||
}
|
||||
|
||||
// None of the planes could cull this box
|
||||
cullingPlane = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Sphere::randomSurfacePoint() const {
|
||||
return Vector3::random() * radius + center;
|
||||
}
|
||||
|
||||
|
||||
Vector3 Sphere::randomInteriorPoint() const {
|
||||
Vector3 result;
|
||||
do {
|
||||
result = Vector3(uniformRandom(-1, 1),
|
||||
uniformRandom(-1, 1),
|
||||
uniformRandom(-1, 1));
|
||||
} while (result.squaredMagnitude() >= 1.0f);
|
||||
|
||||
return result * radius + center;
|
||||
}
|
||||
|
||||
|
||||
float Sphere::volume() const {
|
||||
return (float)pi() * (4.0f / 3.0f) * powf((float)radius, 3.0f);
|
||||
}
|
||||
|
||||
|
||||
float Sphere::area() const {
|
||||
return (float)pi() * 4.0f * powf((float)radius, 2.0f);
|
||||
}
|
||||
|
||||
|
||||
void Sphere::getBounds(AABox& out) const {
|
||||
Vector3 extent(radius, radius, radius);
|
||||
out = AABox(center - extent, center + extent);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
162
dep/src/g3dlite/SplineBase.cpp
Normal file
162
dep/src/g3dlite/SplineBase.cpp
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
#include "G3D/platform.h"
|
||||
#include "G3D/Spline.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
float SplineBase::getFinalInterval() const {
|
||||
if (! cyclic) {
|
||||
return 0;
|
||||
} else if (finalInterval <= 0) {
|
||||
int N = time.size();
|
||||
if (N >= 2) {
|
||||
return (time[1] - time[0] + time[N - 1] - time[N - 2]) * 0.5f;
|
||||
} else {
|
||||
return 1.0f;
|
||||
}
|
||||
} else {
|
||||
return finalInterval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Matrix4 SplineBase::computeBasis() {
|
||||
// The standard Catmull-Rom spline basis (e.g., Watt & Watt p108)
|
||||
// is for [u^3 u^2 u^1 u^0] * B * [p[0] p[1] p[2] p[3]]^T.
|
||||
// We need a basis formed for:
|
||||
//
|
||||
// U * C * [2*p'[1] p[1] p[2] 2*p'[2]]^T
|
||||
//
|
||||
// U * C * [p2-p0 p1 p2 p3-p1]^T
|
||||
//
|
||||
// To make this transformation, compute the differences of columns in C:
|
||||
// For [p0 p1 p2 p3]
|
||||
Matrix4 basis =
|
||||
Matrix4( -1, 3, -3, 1,
|
||||
2, -5, 4, -1,
|
||||
-1, 0, 1, 0,
|
||||
0, 2, 0, 0) * 0.5f;
|
||||
|
||||
// For [-p0 p1 p2 p3]^T
|
||||
basis.setColumn(0, -basis.column(0));
|
||||
|
||||
// For [-p0 p1 p2 p3-p1]^T
|
||||
basis.setColumn(1, basis.column(1) + basis.column(3));
|
||||
|
||||
// For [p2-p0 p1 p2 p3-p1]^T
|
||||
basis.setColumn(2, basis.column(2) - basis.column(0));
|
||||
|
||||
return basis;
|
||||
}
|
||||
|
||||
|
||||
float SplineBase::duration() const {
|
||||
if (time.size() == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return time.last() - time[0] + getFinalInterval();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SplineBase::computeIndexInBounds(float s, int& i, float& u) const {
|
||||
int N = time.size();
|
||||
float t0 = time[0];
|
||||
float tn = time[N - 1];
|
||||
|
||||
i = iFloor((N - 1) * (s - t0) / (tn - t0));
|
||||
|
||||
// Inclusive bounds for binary search
|
||||
int hi = N - 1;
|
||||
int lo = 0;
|
||||
|
||||
while ((time[i] > s) || (time[i + 1] <= s)) {
|
||||
|
||||
if (time[i] > s) {
|
||||
// too big
|
||||
hi = i - 1;
|
||||
} else if (time[i + 1] <= s) {
|
||||
// too small
|
||||
lo = i + 1;
|
||||
}
|
||||
|
||||
i = (hi + lo) / 2;
|
||||
}
|
||||
|
||||
// Having exited the above loop, i must be correct, so compute u.
|
||||
u = (s - time[i]) / (time[i + 1] - time[i]);
|
||||
}
|
||||
|
||||
|
||||
void SplineBase::computeIndex(float s, int& i, float& u) const {
|
||||
int N = time.size();
|
||||
debugAssertM(N > 0, "No control points");
|
||||
float t0 = time[0];
|
||||
float tn = time[N - 1];
|
||||
|
||||
if (N < 2) {
|
||||
// No control points to work with
|
||||
i = 0;
|
||||
u = 0.0;
|
||||
} else if (cyclic) {
|
||||
float fi = getFinalInterval();
|
||||
|
||||
// Cyclic spline
|
||||
if ((s < t0) || (s >= tn + fi)) {
|
||||
// Cyclic, off the bottom or top
|
||||
|
||||
// Compute offset and reduce to the in-bounds case
|
||||
|
||||
float d = duration();
|
||||
// Number of times we wrapped around the cyclic array
|
||||
int wraps = iFloor((s - t0) / d);
|
||||
|
||||
debugAssert(s - d * wraps >= t0);
|
||||
debugAssert(s - d * wraps < tn + getFinalInterval());
|
||||
|
||||
computeIndex(s - d * wraps, i, u);
|
||||
i += wraps * N;
|
||||
|
||||
} else if (s >= tn) {
|
||||
debugAssert(s < tn + fi);
|
||||
// Cyclic, off the top but before the end of the last interval
|
||||
i = N - 1;
|
||||
u = (s - tn) / fi;
|
||||
|
||||
} else {
|
||||
// Cyclic, in bounds
|
||||
computeIndexInBounds(s, i, u);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Non-cyclic
|
||||
|
||||
if (s < t0) {
|
||||
// Non-cyclic, off the bottom. Assume points are spaced
|
||||
// following the first time interval.
|
||||
|
||||
float dt = time[1] - t0;
|
||||
float x = (s - t0) / dt;
|
||||
i = iFloor(x);
|
||||
u = x - i;
|
||||
|
||||
} else if (s >= tn) {
|
||||
// Non-cyclic, off the top. Assume points are spaced following
|
||||
// the last time interval.
|
||||
|
||||
float dt = tn - time[N - 2];
|
||||
float x = N - 1 + (s - tn) / dt;
|
||||
i = iFloor(x);
|
||||
u = x - i;
|
||||
|
||||
} else {
|
||||
// In bounds, non-cyclic. Assume a regular
|
||||
// distribution (which gives O(1) for uniform spacing)
|
||||
// and then binary search to handle the general case
|
||||
// efficiently.
|
||||
computeIndexInBounds(s, i, u);
|
||||
|
||||
} // if in bounds
|
||||
} // if cyclic
|
||||
}
|
||||
|
||||
}
|
||||
119
dep/src/g3dlite/Stopwatch.cpp
Normal file
119
dep/src/g3dlite/Stopwatch.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/**
|
||||
@file Stopwatch.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2005-10-05
|
||||
@edited 2009-03-14
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/Stopwatch.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Stopwatch::Stopwatch(const std::string& myName) :
|
||||
myName(myName),
|
||||
inBetween(false), lastTockTime(-1),
|
||||
lastDuration(0), lastCycleCount(0), m_fps(0), emwaFPS(0),
|
||||
m_smoothFPS(0), emwaDuration(0) {
|
||||
computeOverhead();
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
void Stopwatch::computeOverhead() {
|
||||
cycleOverhead = 0;
|
||||
tick();
|
||||
tock();
|
||||
cycleOverhead = elapsedCycles();
|
||||
}
|
||||
|
||||
|
||||
void Stopwatch::tick() {
|
||||
// This is 'alwaysAssert' instead of 'debugAssert'
|
||||
// since people rarely profile in debug mode.
|
||||
alwaysAssertM(! inBetween, "Stopwatch::tick() called twice in a row.");
|
||||
inBetween = true;
|
||||
|
||||
// We read RDTSC twice here, but it is more abstract to implement this
|
||||
// way and at least we're reading the cycle count last.
|
||||
timeStart = System::time();
|
||||
System::beginCycleCount(cycleStart);
|
||||
}
|
||||
|
||||
|
||||
void Stopwatch::tock() {
|
||||
System::endCycleCount(cycleStart);
|
||||
RealTime now = System::time();
|
||||
lastDuration = now - timeStart;
|
||||
if (abs(emwaDuration - lastDuration) > max(emwaDuration, lastDuration) * 0.50) {
|
||||
// Off by more than 50%
|
||||
emwaDuration = lastDuration;
|
||||
} else {
|
||||
emwaDuration = lastDuration * 0.05 + emwaDuration * 0.95;
|
||||
}
|
||||
|
||||
lastCycleCount = cycleStart - cycleOverhead;
|
||||
if (lastCycleCount < 0) {
|
||||
lastCycleCount = 0;
|
||||
}
|
||||
|
||||
if (lastTockTime != -1.0) {
|
||||
m_fps = 1.0 / (now - lastTockTime);
|
||||
|
||||
const double blend = 0.01;
|
||||
emwaFPS = m_fps * blend + emwaFPS * (1.0 - blend);
|
||||
|
||||
double maxDiscrepancyPercentage = 0.25;
|
||||
if (abs(emwaFPS - m_fps) > max(emwaFPS, m_fps) * maxDiscrepancyPercentage) {
|
||||
// The difference between emwa and m_fps is way off, so
|
||||
// update emwa directly.
|
||||
emwaFPS = m_fps * 0.20 + emwaFPS * 0.80;
|
||||
}
|
||||
|
||||
// Update m_smoothFPS only when the value varies significantly.
|
||||
// We round so as to not mislead the user as to the accuracy of
|
||||
// the number.
|
||||
if (m_smoothFPS == 0) {
|
||||
m_smoothFPS = m_fps;
|
||||
} else if (emwaFPS <= 20) {
|
||||
if (::fabs(m_smoothFPS - emwaFPS) > 0.75) {
|
||||
// Small number and display is off by more than 0.75; round to the nearest 0.1
|
||||
m_smoothFPS = floor(emwaFPS * 10.0 + 0.5) / 10.0;
|
||||
}
|
||||
} else if (::fabs(m_smoothFPS - emwaFPS) > 1.25) {
|
||||
// Large number and display is off by more than 1.25; round to the nearest 1.0
|
||||
m_smoothFPS = floor(emwaFPS + 0.5);
|
||||
}
|
||||
}
|
||||
lastTockTime = now;
|
||||
|
||||
alwaysAssertM(inBetween, "Stopwatch::tock() called without matching tick.");
|
||||
inBetween = false;
|
||||
}
|
||||
|
||||
|
||||
void Stopwatch::reset() {
|
||||
prevTime = startTime = System::time();
|
||||
prevMark = "start";
|
||||
}
|
||||
|
||||
|
||||
void Stopwatch::after(const std::string& s) {
|
||||
RealTime now = System::time();
|
||||
debugPrintf("%s: %10s - %8fs since %s (%fs since start)\n",
|
||||
myName.c_str(),
|
||||
s.c_str(),
|
||||
now - prevTime,
|
||||
prevMark.c_str(),
|
||||
now - startTime);
|
||||
prevTime = now;
|
||||
prevMark = s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load diff
1136
dep/src/g3dlite/TextInput.cpp
Normal file
1136
dep/src/g3dlite/TextInput.cpp
Normal file
File diff suppressed because it is too large
Load diff
452
dep/src/g3dlite/TextOutput.cpp
Normal file
452
dep/src/g3dlite/TextOutput.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
166
dep/src/g3dlite/ThreadSet.cpp
Normal file
166
dep/src/g3dlite/ThreadSet.cpp
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
#include "G3D/ThreadSet.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
int ThreadSet::size() const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
me->m_lock.lock();
|
||||
int s = m_thread.size();
|
||||
me->m_lock.unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int ThreadSet::numStarted() const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
me->m_lock.lock();
|
||||
int count = 0;
|
||||
for (int i = 0; i < m_thread.size(); ++i) {
|
||||
if (m_thread[i]->started()) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
me->m_lock.unlock();
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
void ThreadSet::start(GThread::SpawnBehavior lastBehavior) const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
|
||||
Array<GThreadRef> unstarted;
|
||||
me->m_lock.lock();
|
||||
// Find the unstarted threads
|
||||
for (int i = 0; i < m_thread.size(); ++i) {
|
||||
if (! m_thread[i]->started()) {
|
||||
unstarted.append(m_thread[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int last = unstarted.size();
|
||||
if (lastBehavior == GThread::USE_CURRENT_THREAD) {
|
||||
// Save the last unstarted for the current thread
|
||||
--last;
|
||||
}
|
||||
|
||||
for (int i = 0; i < last; ++i) {
|
||||
unstarted[i]->start(GThread::USE_NEW_THREAD);
|
||||
}
|
||||
|
||||
me->m_lock.unlock();
|
||||
|
||||
// Start the last one on my thread
|
||||
if ((unstarted.size() > 0) && (lastBehavior == GThread::USE_CURRENT_THREAD)) {
|
||||
unstarted.last()->start(GThread::USE_CURRENT_THREAD);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ThreadSet::terminate() const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
me->m_lock.lock();
|
||||
for (int i = 0; i < m_thread.size(); ++i) {
|
||||
if (m_thread[i]->started()) {
|
||||
m_thread[i]->terminate();
|
||||
}
|
||||
}
|
||||
me->m_lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
void ThreadSet::waitForCompletion() const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
me->m_lock.lock();
|
||||
for (int i = 0; i < m_thread.size(); ++i) {
|
||||
if (m_thread[i]->started()) {
|
||||
m_thread[i]->waitForCompletion();
|
||||
}
|
||||
}
|
||||
me->m_lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
int ThreadSet::removeCompleted() {
|
||||
m_lock.lock();
|
||||
for (int i = 0; i < m_thread.size(); ++i) {
|
||||
if (m_thread[i]->completed()) {
|
||||
m_thread.fastRemove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
int s = m_thread.size();
|
||||
m_lock.unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void ThreadSet::clear() {
|
||||
m_lock.lock();
|
||||
m_thread.clear();
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
int ThreadSet::insert(const ThreadRef& t) {
|
||||
m_lock.lock();
|
||||
bool found = false;
|
||||
for (int i = 0; i < m_thread.size() && ! found; ++i) {
|
||||
found = (m_thread[i] == t);
|
||||
}
|
||||
if (! found) {
|
||||
m_thread.append(t);
|
||||
}
|
||||
int s = m_thread.size();
|
||||
m_lock.unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
bool ThreadSet::remove(const ThreadRef& t) {
|
||||
m_lock.lock();
|
||||
bool found = false;
|
||||
for (int i = 0; i < m_thread.size() && ! found; ++i) {
|
||||
found = (m_thread[i] == t);
|
||||
if (found) {
|
||||
m_thread.fastRemove(i);
|
||||
}
|
||||
}
|
||||
m_lock.unlock();
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
bool ThreadSet::contains(const ThreadRef& t) const {
|
||||
ThreadSet* me = const_cast<ThreadSet*>(this);
|
||||
me->m_lock.lock();
|
||||
bool found = false;
|
||||
for (int i = 0; i < m_thread.size() && ! found; ++i) {
|
||||
found = (m_thread[i] == t);
|
||||
}
|
||||
me->m_lock.unlock();
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
ThreadSet::Iterator ThreadSet::begin() {
|
||||
return m_thread.begin();
|
||||
}
|
||||
|
||||
|
||||
ThreadSet::Iterator ThreadSet::end() {
|
||||
return m_thread.end();
|
||||
}
|
||||
|
||||
|
||||
ThreadSet::ConstIterator ThreadSet::begin() const {
|
||||
return m_thread.begin();
|
||||
}
|
||||
|
||||
|
||||
ThreadSet::ConstIterator ThreadSet::end() const {
|
||||
return m_thread.end();
|
||||
}
|
||||
|
||||
|
||||
} // namespace G3D
|
||||
|
|
@ -1,19 +1,23 @@
|
|||
/**
|
||||
@file Triangle.cpp
|
||||
|
||||
@maintainer Morgan McGuire, graphics3d.com
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-04-06
|
||||
@edited 2006-01-20
|
||||
@edited 2008-12-28
|
||||
|
||||
Copyright 2000-2006, Morgan McGuire.
|
||||
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 {
|
||||
|
||||
|
|
@ -28,8 +32,8 @@ void Triangle::init(const Vector3& v0, const Vector3& v1, const Vector3& 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();
|
||||
const Vector3& e = _vertex[next[i]] - _vertex[i];
|
||||
edgeMagnitude[i] = e.magnitude();
|
||||
|
||||
if (edgeMagnitude[i] == 0) {
|
||||
edgeDirection[i] = Vector3::zero();
|
||||
|
|
@ -38,12 +42,12 @@ void Triangle::init(const Vector3& v0, const Vector3& v1, const Vector3& v2) {
|
|||
}
|
||||
}
|
||||
|
||||
edge01 = _vertex[1] - _vertex[0];
|
||||
edge02 = _vertex[2] - _vertex[0];
|
||||
_edge01 = _vertex[1] - _vertex[0];
|
||||
_edge02 = _vertex[2] - _vertex[0];
|
||||
|
||||
_primaryAxis = _plane.normal().primaryAxis();
|
||||
_area = (float)edgeDirection[0].cross(edgeDirection[2]).magnitude() * (edgeMagnitude[0] * edgeMagnitude[2]);
|
||||
|
||||
_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());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -61,7 +65,27 @@ Triangle::~Triangle() {
|
|||
}
|
||||
|
||||
|
||||
double Triangle::area() const {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +117,7 @@ Vector3 Triangle::randomPoint() const {
|
|||
s = 1.0f - s;
|
||||
}
|
||||
|
||||
return edge01 * s + edge02 * t + _vertex[0];
|
||||
return _edge01 * s + _edge02 * t + _vertex[0];
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -109,4 +133,54 @@ void Triangle::getBounds(AABox& out) const {
|
|||
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
dep/src/g3dlite/UprightFrame.cpp
Normal file
132
dep/src/g3dlite/UprightFrame.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/**
|
||||
@file UprightFrame.cpp
|
||||
Box class
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-05-02
|
||||
@edited 2007-05-05
|
||||
*/
|
||||
|
||||
#include "G3D/UprightFrame.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
UprightFrame::UprightFrame(const CoordinateFrame& cframe) {
|
||||
Vector3 look = cframe.lookVector();
|
||||
|
||||
yaw = G3D::pi() + atan2(look.x, look.z);
|
||||
pitch = asin(look.y);
|
||||
|
||||
translation = cframe.translation;
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame UprightFrame::toCoordinateFrame() const {
|
||||
CoordinateFrame cframe;
|
||||
|
||||
Matrix3 P(Matrix3::fromAxisAngle(Vector3::unitX(), pitch));
|
||||
Matrix3 Y(Matrix3::fromAxisAngle(Vector3::unitY(), yaw));
|
||||
|
||||
cframe.rotation = Y * P;
|
||||
cframe.translation = translation;
|
||||
|
||||
return cframe;
|
||||
}
|
||||
|
||||
|
||||
UprightFrame UprightFrame::operator+(const UprightFrame& other) const {
|
||||
return UprightFrame(translation + other.translation, pitch + other.pitch, yaw + other.yaw);
|
||||
}
|
||||
|
||||
|
||||
UprightFrame UprightFrame::operator*(const float k) const {
|
||||
return UprightFrame(translation * k, pitch * k, yaw * k);
|
||||
}
|
||||
|
||||
|
||||
void UprightFrame::unwrapYaw(UprightFrame* a, int N) {
|
||||
// Use the first point to establish the wrapping convention
|
||||
for (int i = 1; i < N; ++i) {
|
||||
const float prev = a[i - 1].yaw;
|
||||
float& cur = a[i].yaw;
|
||||
|
||||
// No two angles should be more than pi (i.e., 180-degrees) apart.
|
||||
if (abs(cur - prev) > G3D::pi()) {
|
||||
// These angles must have wrapped at zero, causing them
|
||||
// to be interpolated the long way.
|
||||
|
||||
// Find canonical [0, 2pi] versions of these numbers
|
||||
float p = wrap(prev, twoPi());
|
||||
float c = wrap(cur, twoPi());
|
||||
|
||||
// Find the difference -pi < diff < pi between the current and previous values
|
||||
float diff = c - p;
|
||||
if (diff < -G3D::pi()) {
|
||||
diff += twoPi();
|
||||
} else if (diff > G3D::pi()) {
|
||||
diff -= twoPi();
|
||||
}
|
||||
|
||||
// Offset the current from the previous by the difference
|
||||
// between them.
|
||||
cur = prev + diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UprightFrame::serialize(class BinaryOutput& b) const {
|
||||
translation.serialize(b);
|
||||
b.writeFloat32(pitch);
|
||||
b.writeFloat32(yaw);
|
||||
}
|
||||
|
||||
|
||||
void UprightFrame::deserialize(class BinaryInput& b) {
|
||||
translation.deserialize(b);
|
||||
pitch = b.readFloat32();
|
||||
yaw = b.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void UprightSpline::serialize(class BinaryOutput& b) const {
|
||||
b.writeBool8(cyclic);
|
||||
|
||||
b.writeInt32(control.size());
|
||||
for (int i = 0; i < control.size(); ++i) {
|
||||
control[i].serialize(b);
|
||||
}
|
||||
b.writeInt32(time.size());
|
||||
for (int i = 0; i < time.size(); ++i) {
|
||||
b.writeFloat32(time[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UprightSpline::deserialize(class BinaryInput& b) {
|
||||
cyclic = b.readBool8();
|
||||
|
||||
control.resize(b.readInt32());
|
||||
for (int i = 0; i < control.size(); ++i) {
|
||||
control[i].deserialize(b);
|
||||
}
|
||||
|
||||
if (b.hasMore()) {
|
||||
time.resize(b.readInt32());
|
||||
for (int i = 0; i < time.size(); ++i) {
|
||||
time[i] = b.readFloat32();
|
||||
}
|
||||
debugAssert(time.size() == control.size());
|
||||
} else {
|
||||
// Import legacy path
|
||||
time.resize(control.size());
|
||||
for (int i = 0; i < time.size(); ++i) {
|
||||
time[i] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
224
dep/src/g3dlite/Vector2.cpp
Normal file
224
dep/src/g3dlite/Vector2.cpp
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/**
|
||||
@file Vector2.cpp
|
||||
|
||||
2D vector class, used for texture coordinates primarily.
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@cite Portions based on Dave Eberly'x Magic Software Library
|
||||
at http://www.magic-software.com
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2009-11-16
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include <stdlib.h>
|
||||
#include "G3D/Vector2.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/TextInput.h"
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/Any.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
Vector2::Vector2(const Any& any) {
|
||||
any.verifyName("Vector2");
|
||||
any.verifyType(Any::TABLE, Any::ARRAY);
|
||||
any.verifySize(2);
|
||||
|
||||
if (any.type() == Any::ARRAY) {
|
||||
x = any[0];
|
||||
y = any[1];
|
||||
} else {
|
||||
// Table
|
||||
x = any["x"];
|
||||
y = any["y"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector2::operator Any() const {
|
||||
Any any(Any::ARRAY, "Vector2");
|
||||
any.append(x, y);
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
const Vector2& Vector2::one() {
|
||||
static const Vector2 v(1, 1); return v;
|
||||
}
|
||||
|
||||
|
||||
const Vector2& Vector2::zero() {
|
||||
static Vector2 v(0, 0);
|
||||
return v;
|
||||
}
|
||||
|
||||
const Vector2& Vector2::unitX() {
|
||||
static Vector2 v(1, 0);
|
||||
return v;
|
||||
}
|
||||
|
||||
const Vector2& Vector2::unitY() {
|
||||
static Vector2 v(0, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
const Vector2& Vector2::inf() {
|
||||
static Vector2 v((float)G3D::finf(), (float)G3D::finf());
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
const Vector2& Vector2::nan() {
|
||||
static Vector2 v((float)G3D::fnan(), (float)G3D::fnan());
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
const Vector2& Vector2::minFinite() {
|
||||
static Vector2 v(-FLT_MAX, -FLT_MAX);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
const Vector2& Vector2::maxFinite() {
|
||||
static Vector2 v(FLT_MAX, FLT_MAX);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
size_t Vector2::hashCode() const {
|
||||
unsigned int xhash = (*(int*)(void*)(&x));
|
||||
unsigned int yhash = (*(int*)(void*)(&y));
|
||||
|
||||
return xhash + (yhash * 37);
|
||||
}
|
||||
|
||||
|
||||
Vector2::Vector2(BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
|
||||
void Vector2::deserialize(BinaryInput& b) {
|
||||
x = b.readFloat32();
|
||||
y = b.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Vector2::serialize(BinaryOutput& b) const {
|
||||
b.writeFloat32(x);
|
||||
b.writeFloat32(y);
|
||||
}
|
||||
|
||||
|
||||
void Vector2::deserialize(TextInput& t) {
|
||||
t.readSymbol("(");
|
||||
x = (float)t.readNumber();
|
||||
t.readSymbol(",");
|
||||
y = (float)t.readNumber();
|
||||
t.readSymbol(")");
|
||||
}
|
||||
|
||||
|
||||
void Vector2::serialize(TextOutput& t) const {
|
||||
t.writeSymbol("(");
|
||||
t.writeNumber(x);
|
||||
t.writeSymbol(",");
|
||||
t.writeNumber(y);
|
||||
t.writeSymbol(")");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Vector2 Vector2::random(G3D::Random& r) {
|
||||
Vector2 result;
|
||||
|
||||
do {
|
||||
result = Vector2(r.uniform(-1, 1), r.uniform(-1, 1));
|
||||
|
||||
} while (result.squaredLength() >= 1.0f);
|
||||
|
||||
result.unitize();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Vector2 Vector2::operator/ (float k) const {
|
||||
return *this * (1.0f / k);
|
||||
}
|
||||
|
||||
Vector2& Vector2::operator/= (float k) {
|
||||
this->x /= k;
|
||||
this->y /= k;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Vector2::unitize (float fTolerance) {
|
||||
float fLength = length();
|
||||
|
||||
if (fLength > fTolerance) {
|
||||
float fInvLength = 1.0f / fLength;
|
||||
x *= fInvLength;
|
||||
y *= fInvLength;
|
||||
} else {
|
||||
fLength = 0.0;
|
||||
}
|
||||
|
||||
return fLength;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
std::string Vector2::toString() const {
|
||||
return G3D::format("(%g, %g)", x, y);
|
||||
}
|
||||
|
||||
// 2-char swizzles
|
||||
|
||||
Vector2 Vector2::xx() const { return Vector2 (x, x); }
|
||||
Vector2 Vector2::yx() const { return Vector2 (y, x); }
|
||||
Vector2 Vector2::xy() const { return Vector2 (x, y); }
|
||||
Vector2 Vector2::yy() const { return Vector2 (y, y); }
|
||||
|
||||
// 3-char swizzles
|
||||
|
||||
Vector3 Vector2::xxx() const { return Vector3 (x, x, x); }
|
||||
Vector3 Vector2::yxx() const { return Vector3 (y, x, x); }
|
||||
Vector3 Vector2::xyx() const { return Vector3 (x, y, x); }
|
||||
Vector3 Vector2::yyx() const { return Vector3 (y, y, x); }
|
||||
Vector3 Vector2::xxy() const { return Vector3 (x, x, y); }
|
||||
Vector3 Vector2::yxy() const { return Vector3 (y, x, y); }
|
||||
Vector3 Vector2::xyy() const { return Vector3 (x, y, y); }
|
||||
Vector3 Vector2::yyy() const { return Vector3 (y, y, y); }
|
||||
|
||||
// 4-char swizzles
|
||||
|
||||
Vector4 Vector2::xxxx() const { return Vector4 (x, x, x, x); }
|
||||
Vector4 Vector2::yxxx() const { return Vector4 (y, x, x, x); }
|
||||
Vector4 Vector2::xyxx() const { return Vector4 (x, y, x, x); }
|
||||
Vector4 Vector2::yyxx() const { return Vector4 (y, y, x, x); }
|
||||
Vector4 Vector2::xxyx() const { return Vector4 (x, x, y, x); }
|
||||
Vector4 Vector2::yxyx() const { return Vector4 (y, x, y, x); }
|
||||
Vector4 Vector2::xyyx() const { return Vector4 (x, y, y, x); }
|
||||
Vector4 Vector2::yyyx() const { return Vector4 (y, y, y, x); }
|
||||
Vector4 Vector2::xxxy() const { return Vector4 (x, x, x, y); }
|
||||
Vector4 Vector2::yxxy() const { return Vector4 (y, x, x, y); }
|
||||
Vector4 Vector2::xyxy() const { return Vector4 (x, y, x, y); }
|
||||
Vector4 Vector2::yyxy() const { return Vector4 (y, y, x, y); }
|
||||
Vector4 Vector2::xxyy() const { return Vector4 (x, x, y, y); }
|
||||
Vector4 Vector2::yxyy() const { return Vector4 (y, x, y, y); }
|
||||
Vector4 Vector2::xyyy() const { return Vector4 (x, y, y, y); }
|
||||
Vector4 Vector2::yyyy() const { return Vector4 (y, y, y, y); }
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
47
dep/src/g3dlite/Vector2int16.cpp
Normal file
47
dep/src/g3dlite/Vector2int16.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
@file Vector2int16.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-08-09
|
||||
@edited 2006-01-29
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Vector2int16.h"
|
||||
#include "G3D/Vector2.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector2int16::Vector2int16(const class Vector2& v) {
|
||||
x = (int16)iFloor(v.x + 0.5);
|
||||
y = (int16)iFloor(v.y + 0.5);
|
||||
}
|
||||
|
||||
|
||||
Vector2int16::Vector2int16(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Vector2int16::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeInt16(x);
|
||||
bo.writeInt16(y);
|
||||
}
|
||||
|
||||
|
||||
void Vector2int16::deserialize(class BinaryInput& bi) {
|
||||
x = bi.readInt16();
|
||||
y = bi.readInt16();
|
||||
}
|
||||
|
||||
|
||||
Vector2int16 Vector2int16::clamp(const Vector2int16& lo, const Vector2int16& hi) {
|
||||
return Vector2int16(iClamp(x, lo.x, hi.x), iClamp(y, lo.y, hi.y));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -3,40 +3,80 @@
|
|||
|
||||
3D vector class
|
||||
|
||||
@maintainer Morgan McGuire, matrix@graphics3d.com
|
||||
@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 2006-01-30
|
||||
@edited 2009-11-27
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <stdlib.h>
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/format.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::dummy;
|
||||
Vector3::Vector3(const Any& any) {
|
||||
any.verifyName("Vector3");
|
||||
any.verifyType(Any::TABLE, Any::ARRAY);
|
||||
any.verifySize(3);
|
||||
|
||||
// Deprecated.
|
||||
const Vector3 Vector3::ZERO(0, 0, 0);
|
||||
const Vector3 Vector3::ZERO3(0, 0, 0);
|
||||
const Vector3 Vector3::UNIT_X(1, 0, 0);
|
||||
const Vector3 Vector3::UNIT_Y(0, 1, 0);
|
||||
const Vector3 Vector3::UNIT_Z(0, 0, 1);
|
||||
const Vector3 Vector3::INF3((float)G3D::inf(), (float)G3D::inf(), (float)G3D::inf());
|
||||
const Vector3 Vector3::NAN3((float)G3D::nan(), (float)G3D::nan(), (float)G3D::nan());
|
||||
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;
|
||||
|
|
@ -63,7 +103,7 @@ Vector3::Axis Vector3::primaryAxis() const {
|
|||
}
|
||||
|
||||
|
||||
unsigned int Vector3::hashCode() const {
|
||||
size_t Vector3::hashCode() const {
|
||||
unsigned int xhash = (*(int*)(void*)(&x));
|
||||
unsigned int yhash = (*(int*)(void*)(&y));
|
||||
unsigned int zhash = (*(int*)(void*)(&z));
|
||||
|
|
@ -82,6 +122,14 @@ 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;
|
||||
|
|
@ -90,57 +138,54 @@ Vector3::Vector3(const class Vector3int16& v) {
|
|||
}
|
||||
|
||||
|
||||
Vector3 Vector3::random() {
|
||||
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;
|
||||
|
||||
do {
|
||||
result = Vector3(uniformRandom(-1.0, 1.0),
|
||||
uniformRandom(-1.0, 1.0),
|
||||
uniformRandom(-1.0, 1.0));
|
||||
} while (result.squaredMagnitude() >= 1.0f);
|
||||
|
||||
result.unitize();
|
||||
|
||||
r.sphere(result.x, result.y, result.z);
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Vector3 Vector3::operator/ (float fScalar) const {
|
||||
Vector3 kQuot;
|
||||
|
||||
if ( fScalar != 0.0 ) {
|
||||
float fInvScalar = 1.0f / fScalar;
|
||||
kQuot.x = fInvScalar * x;
|
||||
kQuot.y = fInvScalar * y;
|
||||
kQuot.z = fInvScalar * z;
|
||||
return kQuot;
|
||||
} else {
|
||||
return Vector3::inf();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Vector3& Vector3::operator/= (float fScalar) {
|
||||
if (fScalar != 0.0) {
|
||||
float fInvScalar = 1.0f / fScalar;
|
||||
x *= fInvScalar;
|
||||
y *= fInvScalar;
|
||||
z *= fInvScalar;
|
||||
} else {
|
||||
x = (float)G3D::inf();
|
||||
y = (float)G3D::inf();
|
||||
z = (float)G3D::inf();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Vector3::unitize (float fTolerance) {
|
||||
float fMagnitude = magnitude();
|
||||
float Vector3::unitize(float fTolerance) {
|
||||
float fMagnitude = magnitude();
|
||||
|
||||
if (fMagnitude > fTolerance) {
|
||||
float fInvMagnitude = 1.0f / fMagnitude;
|
||||
float fInvMagnitude = 1.0f / fMagnitude;
|
||||
x *= fInvMagnitude;
|
||||
y *= fInvMagnitude;
|
||||
z *= fInvMagnitude;
|
||||
|
|
@ -151,10 +196,8 @@ float Vector3::unitize (float fTolerance) {
|
|||
return fMagnitude;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Vector3 Vector3::reflectAbout(const Vector3& normal) const {
|
||||
|
||||
Vector3 out;
|
||||
|
||||
Vector3 N = normal.direction();
|
||||
|
|
@ -163,36 +206,49 @@ Vector3 Vector3::reflectAbout(const Vector3& normal) const {
|
|||
return N * 2 * this->dot(N) - *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#if 0
|
||||
Vector3 Vector3::cosRandom(const Vector3& normal) {
|
||||
double e1 = G3D::random(0, 1);
|
||||
double e2 = G3D::random(0, 1);
|
||||
|
||||
// Angle from normal
|
||||
double theta = acos(sqrt(e1));
|
||||
Vector3 Vector3::cosHemiRandom(const Vector3& normal, Random& r) {
|
||||
debugAssertM(G3D::fuzzyEq(normal.length(), 1.0f),
|
||||
"cosHemiRandom requires its argument to have unit length");
|
||||
|
||||
// Angle about normal
|
||||
double phi = 2 * G3D_PI * e2;
|
||||
float x, y, z;
|
||||
r.cosHemi(x, y, z);
|
||||
|
||||
// Make a coordinate system
|
||||
Vector3 U = normal.direction();
|
||||
Vector3 V = Vector3::unitX();
|
||||
const Vector3& Z = normal;
|
||||
|
||||
if (abs(U.dot(V)) > .9) {
|
||||
V = Vector3::unitY();
|
||||
}
|
||||
Vector3 X, Y;
|
||||
normal.getTangents(X, Y);
|
||||
|
||||
Vector3 W = U.cross(V).direction();
|
||||
V = W.cross(U);
|
||||
|
||||
// Convert to rectangular form
|
||||
return cos(theta) * U + sin(theta) * (cos(phi) * V + sin(phi) * W);
|
||||
return
|
||||
x * X +
|
||||
y * Y +
|
||||
z * Z;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Vector3 Vector3::hemiRandom(const Vector3& normal) {
|
||||
Vector3 V = Vector3::random();
|
||||
|
||||
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;
|
||||
|
|
@ -200,7 +256,7 @@ Vector3 Vector3::hemiRandom(const Vector3& normal) {
|
|||
return V;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Vector3 Vector3::reflectionDirection(const Vector3& normal) const {
|
||||
|
|
@ -308,6 +364,14 @@ Matrix3 Vector3::cross() const {
|
|||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
49
dep/src/g3dlite/Vector3int16.cpp
Normal file
49
dep/src/g3dlite/Vector3int16.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
@file Vector3int16.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-04-07
|
||||
@edited 2006-01-17
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Vector3int16.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/format.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector3int16::Vector3int16(const class Vector3& v) {
|
||||
x = (int16)iFloor(v.x + 0.5);
|
||||
y = (int16)iFloor(v.y + 0.5);
|
||||
z = (int16)iFloor(v.z + 0.5);
|
||||
}
|
||||
|
||||
|
||||
Vector3int16::Vector3int16(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Vector3int16::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeInt16(x);
|
||||
bo.writeInt16(y);
|
||||
bo.writeInt16(z);
|
||||
}
|
||||
|
||||
|
||||
void Vector3int16::deserialize(class BinaryInput& bi) {
|
||||
x = bi.readInt16();
|
||||
y = bi.readInt16();
|
||||
z = bi.readInt16();
|
||||
}
|
||||
|
||||
std::string Vector3int16::toString() const {
|
||||
return G3D::format("(%d, %d, %d)", x, y, z);
|
||||
}
|
||||
|
||||
}
|
||||
57
dep/src/g3dlite/Vector3int32.cpp
Normal file
57
dep/src/g3dlite/Vector3int32.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
@file Vector3int32.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2008-07-01
|
||||
@edited 2008-07-01
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Vector3int32.h"
|
||||
#include "G3D/Vector3int16.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/format.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector3int32::Vector3int32(const class Vector3& v) {
|
||||
x = (int32)iFloor(v.x + 0.5);
|
||||
y = (int32)iFloor(v.y + 0.5);
|
||||
z = (int32)iFloor(v.z + 0.5);
|
||||
}
|
||||
|
||||
|
||||
Vector3int32::Vector3int32(const class Vector3int16& v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
}
|
||||
|
||||
|
||||
Vector3int32::Vector3int32(class BinaryInput& bi) {
|
||||
deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
void Vector3int32::serialize(class BinaryOutput& bo) const {
|
||||
bo.writeInt32(x);
|
||||
bo.writeInt32(y);
|
||||
bo.writeInt32(z);
|
||||
}
|
||||
|
||||
|
||||
void Vector3int32::deserialize(class BinaryInput& bi) {
|
||||
x = bi.readInt32();
|
||||
y = bi.readInt32();
|
||||
z = bi.readInt32();
|
||||
}
|
||||
|
||||
std::string Vector3int32::toString() const {
|
||||
return G3D::format("(%d, %d, %d)", x, y, z);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,23 +1,74 @@
|
|||
/**
|
||||
@file Vector4.cpp
|
||||
|
||||
@maintainer Morgan McGuire, matrix@graphics3d.com
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-07-09
|
||||
@edited 2003-09-29
|
||||
@edited 2009-11-29
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits>
|
||||
#include "G3D/Vector4.h"
|
||||
//#include "G3D/Color4.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/format.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 {
|
||||
|
||||
unsigned int Vector4::hashCode() const {
|
||||
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));
|
||||
|
|
@ -26,14 +77,13 @@ unsigned int Vector4::hashCode() const {
|
|||
return xhash + (yhash * 37) + (zhash * 101) + (whash * 241);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
Vector4::Vector4(const class Color4& c) {
|
||||
x = c.r;
|
||||
y = c.g;
|
||||
z = c.b;
|
||||
w = c.a;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Vector4::Vector4(const Vector2& v1, const Vector2& v2) {
|
||||
|
|
@ -51,8 +101,40 @@ Vector4::Vector4(const Vector2& v1, float fz, float fw) {
|
|||
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;
|
||||
|
||||
|
|
|
|||
58
dep/src/g3dlite/Vector4int8.cpp
Normal file
58
dep/src/g3dlite/Vector4int8.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
@file Vector4int8.cpp
|
||||
|
||||
Homogeneous vector class.
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2007-02-09
|
||||
@edited 2007-02-09
|
||||
|
||||
Copyright 2000-2007, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Vector4int8.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/Vector4.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include <string>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
Vector4int8::Vector4int8(const Vector4& source) {
|
||||
x = iClamp(iRound(source.x), -128, 127);
|
||||
y = iClamp(iRound(source.y), -128, 127);
|
||||
z = iClamp(iRound(source.z), -128, 127);
|
||||
w = iClamp(iRound(source.w), -128, 127);
|
||||
}
|
||||
|
||||
Vector4int8::Vector4int8(const Vector3& source, int8 w) : w(w) {
|
||||
x = iClamp(iRound(source.x), -128, 127);
|
||||
y = iClamp(iRound(source.y), -128, 127);
|
||||
z = iClamp(iRound(source.z), -128, 127);
|
||||
}
|
||||
|
||||
Vector4int8::Vector4int8(class BinaryInput& b) {
|
||||
deserialize(b);
|
||||
}
|
||||
|
||||
void Vector4int8::serialize(class BinaryOutput& b) const {
|
||||
// Intentionally write individual bytes to avoid endian issues
|
||||
b.writeInt8(x);
|
||||
b.writeInt8(y);
|
||||
b.writeInt8(z);
|
||||
b.writeInt8(w);
|
||||
}
|
||||
|
||||
void Vector4int8::deserialize(class BinaryInput& b) {
|
||||
x = b.readInt8();
|
||||
y = b.readInt8();
|
||||
z = b.readInt8();
|
||||
w = b.readInt8();
|
||||
}
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
416
dep/src/g3dlite/Welder.cpp
Normal file
416
dep/src/g3dlite/Welder.cpp
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
/**
|
||||
@file Welder.cpp
|
||||
|
||||
@author Morgan McGuire, Kyle Whitson, Corey Taylor
|
||||
|
||||
@created 2008-07-30
|
||||
@edited 2009-11-29
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Vector2.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/Sphere.h"
|
||||
#include "G3D/PointHashGrid.h"
|
||||
#include "G3D/Welder.h"
|
||||
#include "G3D/Stopwatch.h" // for profiling
|
||||
#include "G3D/AreaMemoryManager.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D { namespace _internal{
|
||||
|
||||
|
||||
/** Used by WeldHelper2::smoothNormals. */
|
||||
class VN {
|
||||
public:
|
||||
Vector3 vertex;
|
||||
Vector3 normal;
|
||||
|
||||
VN() {}
|
||||
VN(const Vector3& v, const Vector3& n) : vertex(v), normal(n) {}
|
||||
};
|
||||
|
||||
/** Used by WeldHelper::getIndex to maintain a list of vertices by location. */
|
||||
class VNTi {
|
||||
public:
|
||||
Vector3 vertex;
|
||||
Vector3 normal;
|
||||
Vector2 texCoord;
|
||||
int index;
|
||||
|
||||
VNTi() : index(0) {}
|
||||
|
||||
VNTi(const Vector3& v, const Vector3& n, const Vector2& t, int i) :
|
||||
vertex(v), normal(n), texCoord(t), index(i) {}
|
||||
};
|
||||
|
||||
|
||||
}} // G3D
|
||||
|
||||
template <> struct HashTrait <G3D::_internal::VN> {
|
||||
static size_t hashCode(const G3D::_internal::VN& k) { return static_cast<size_t>(k.vertex.hashCode()); }
|
||||
};
|
||||
template <> struct HashTrait <G3D::_internal::VNTi> {
|
||||
static size_t hashCode(const G3D::_internal::VNTi& k) { return static_cast<size_t>(k.vertex.hashCode()); }
|
||||
};
|
||||
|
||||
|
||||
template<> struct EqualsTrait <G3D::_internal::VN> {
|
||||
static bool equals(const G3D::_internal::VN& a, const G3D::_internal::VN& b) { return a.vertex == b.vertex; }
|
||||
};
|
||||
template<> struct EqualsTrait <G3D::_internal::VNTi> {
|
||||
static bool equals(const G3D::_internal::VNTi& a, const G3D::_internal::VNTi& b) { return a.vertex == b.vertex; }
|
||||
};
|
||||
|
||||
template<> struct PositionTrait<G3D::_internal::VN> {
|
||||
static void getPosition(const G3D::_internal::VN& v, G3D::Vector3& p) { p = v.vertex; }
|
||||
};
|
||||
template<> struct PositionTrait<G3D::_internal::VNTi> {
|
||||
static void getPosition(const G3D::_internal::VNTi& v, G3D::Vector3& p) { p = v.vertex; }
|
||||
};
|
||||
|
||||
namespace G3D { namespace _internal {
|
||||
|
||||
class WeldHelper {
|
||||
private:
|
||||
/** Used by getIndex and updateTriLists */
|
||||
PointHashGrid<VNTi> weldGrid;
|
||||
|
||||
Array<Vector3>* outputVertexArray;
|
||||
Array<Vector3>* outputNormalArray;
|
||||
Array<Vector2>* outputTexCoordArray;
|
||||
|
||||
float vertexWeldRadius;
|
||||
/** Squared radius allowed for welding similar normals. */
|
||||
float normalWeldRadius2;
|
||||
float texCoordWeldRadius2;
|
||||
|
||||
float normalSmoothingAngle;
|
||||
|
||||
/**
|
||||
Returns the index of the vertex in
|
||||
outputVertexArray/outputNormalArray/outputTexCoordArray
|
||||
that is within the global tolerances of v,n,t. If there
|
||||
is no such vertex, adds it to the arrays and returns that index.
|
||||
|
||||
Called from updateTriLists().
|
||||
*/
|
||||
int getIndex(const Vector3& v, const Vector3& n, const Vector2& t) {
|
||||
PointHashGrid<VNTi>::SphereIterator it =
|
||||
weldGrid.beginSphereIntersection(Sphere(v, vertexWeldRadius));
|
||||
|
||||
if (n.isZero()) {
|
||||
// Don't bother trying to match the surface normal, since this vertex has no surface normal.
|
||||
while (it.hasMore()) {
|
||||
if ((t - it->texCoord).squaredLength() <= texCoordWeldRadius2) {
|
||||
// This is the vertex
|
||||
return it->index;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
} else {
|
||||
while (it.hasMore()) {
|
||||
if (((n - it->normal).squaredLength() <= normalWeldRadius2) &&
|
||||
((t - it->texCoord).squaredLength() <= texCoordWeldRadius2)) {
|
||||
// This is the vertex
|
||||
return it->index;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Note that a sliver triangle processed before its neighbors may reach here
|
||||
// with a zero length normal.
|
||||
|
||||
// The vertex does not exist. Create it.
|
||||
const int i = outputVertexArray->size();
|
||||
outputVertexArray->append(v);
|
||||
outputNormalArray->append(n);
|
||||
outputTexCoordArray->append(t);
|
||||
|
||||
// Store in the grid so that it will be remembered.
|
||||
weldGrid.insert(VNTi(v, n, t, i));
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Updates each indexArray to refer to vertices in the
|
||||
outputVertexArray.
|
||||
|
||||
Called from process()
|
||||
*/
|
||||
void updateTriLists(
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector3>& normalArray,
|
||||
const Array<Vector2>& texCoordArray) {
|
||||
|
||||
// Compute a hash grid so that we can find neighbors quickly.
|
||||
// It begins empty and is extended as the tri lists are iterated
|
||||
// through.
|
||||
weldGrid.clear();
|
||||
|
||||
// Process all triLists
|
||||
int numTriLists = indexArrayArray.size();
|
||||
int u = 0;
|
||||
for (int t = 0; t < numTriLists; ++t) {
|
||||
Array<int>& triList = *(indexArrayArray[t]);
|
||||
|
||||
// For all vertices in this list
|
||||
for (int v = 0; v < triList.size(); ++v) {
|
||||
// This vertex mapped to u in the flatVertexArray
|
||||
triList[v] = getIndex(vertexArray[u], normalArray[u], texCoordArray[u]);
|
||||
|
||||
/*
|
||||
# ifdef G3D_DEBUG
|
||||
{
|
||||
int i = triList[v];
|
||||
Vector3 N = normalArray[i];
|
||||
debugAssertM(N.length() > 0.9f, "Produced non-unit normal");
|
||||
}
|
||||
# endif
|
||||
*/
|
||||
++u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Expands the indexed triangle lists into a triangle list.
|
||||
|
||||
Called from process() */
|
||||
void unroll(
|
||||
const Array<Array<int>*>& indexArrayArray,
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& unrolledVertexArray,
|
||||
Array<Vector2>& unrolledTexCoordArray) {
|
||||
|
||||
int numTriLists = indexArrayArray.size();
|
||||
for (int t = 0; t < numTriLists; ++t) {
|
||||
const Array<int>& triList = *(indexArrayArray[t]);
|
||||
for (int v = 0; v < triList.size(); ++v) {
|
||||
int i = triList[v];
|
||||
unrolledVertexArray.append(vertexArray[i]);
|
||||
unrolledTexCoordArray.append(texCoordArray[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** For every three vertices, compute the face normal and store it three times.
|
||||
Sliver triangles have a zero surface normal, which we will later take to
|
||||
match *any* surface normal. */
|
||||
void computeFaceNormals(
|
||||
const Array<Vector3>& vertexArray,
|
||||
Array<Vector3>& faceNormalArray) {
|
||||
|
||||
debugAssertM(vertexArray.size() % 3 == 0, "Input is not a triangle soup");
|
||||
debugAssertM(faceNormalArray.size() == 0, "Output must start empty.");
|
||||
|
||||
for (int v = 0; v < vertexArray.size(); v += 3) {
|
||||
const Vector3& e0 = vertexArray[v + 1] - vertexArray[v];
|
||||
const Vector3& e1 = vertexArray[v + 2] - vertexArray[v];
|
||||
|
||||
// Note that the length may be zero in the case of sliver polygons, e.g.,
|
||||
// those correcting a T-junction.
|
||||
const Vector3& n = e0.cross(e1).directionOrZero();
|
||||
|
||||
// Append the normal once per vertex.
|
||||
faceNormalArray.append(n, n, n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Computes @a smoothNormalArray, whose elements are those of normalArray averaged
|
||||
with neighbors within the angular cutoff.
|
||||
*/
|
||||
void smoothNormals(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector3>& normalArray,
|
||||
Array<Vector3>& smoothNormalArray) {
|
||||
|
||||
// Create an area memory manager for fast deallocation
|
||||
MemoryManager::Ref mm = AreaMemoryManager::create(iRound(sizeof(VN) * normalArray.size() * 1.5));
|
||||
|
||||
if (normalSmoothingAngle <= 0) {
|
||||
smoothNormalArray = normalArray;
|
||||
return;
|
||||
}
|
||||
|
||||
const float cosThresholdAngle = (float)cos(normalSmoothingAngle);
|
||||
|
||||
debugAssert(vertexArray.size() == normalArray.size());
|
||||
smoothNormalArray.resize(normalArray.size());
|
||||
|
||||
// Compute a hash grid so that we can find neighbors quickly.
|
||||
PointHashGrid<VN> grid(vertexWeldRadius, mm);
|
||||
for (int v = 0; v < normalArray.size(); ++v) {
|
||||
grid.insert(VN(vertexArray[v], normalArray[v]));
|
||||
}
|
||||
|
||||
for (int v = 0; v < normalArray.size(); ++v) {
|
||||
// Compute the sum of all nearby normals within the cutoff angle.
|
||||
// Search within the vertexWeldRadius, since those are the vertices
|
||||
// that will collapse to the same point.
|
||||
PointHashGrid<VN>::SphereIterator it =
|
||||
grid.beginSphereIntersection(Sphere(vertexArray[v], vertexWeldRadius));
|
||||
|
||||
Vector3 sum;
|
||||
|
||||
const Vector3& original = normalArray[v];
|
||||
while (it.hasMore()) {
|
||||
const Vector3& N = it->normal;
|
||||
const float cosAngle = N.dot(original);
|
||||
|
||||
if (cosAngle > cosThresholdAngle) {
|
||||
// This normal is close enough to consider
|
||||
sum += N;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
const Vector3& average = sum.directionOrZero();
|
||||
|
||||
const bool indeterminate = average.isZero();
|
||||
// Never "smooth" a normal so far that it points backwards
|
||||
const bool backFacing = original.dot(average) < 0;
|
||||
|
||||
if (indeterminate || backFacing) {
|
||||
// Revert to the face normal
|
||||
smoothNormalArray[v] = original;
|
||||
} else {
|
||||
// Average available normals
|
||||
smoothNormalArray[v] = average;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
Algorithm:
|
||||
|
||||
1. Unroll the indexed triangle list into a triangle list, where
|
||||
there are duplicated vertices.
|
||||
|
||||
2. Compute face normals for all triangles, and expand those into
|
||||
the triangle vertices.
|
||||
|
||||
3. At each vertex, average all normals that are within normalSmoothingAngle.
|
||||
|
||||
4. Generate output indexArrayArray. While doing so, merge all vertices where
|
||||
the distance between position, texCoord, and normal is within the thresholds.
|
||||
*/
|
||||
void process(
|
||||
Array<Vector3>& vertexArray,
|
||||
Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& normalArray,
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
float normAngle,
|
||||
float texRadius,
|
||||
float normRadius) {
|
||||
|
||||
normalSmoothingAngle = normAngle;
|
||||
normalWeldRadius2 = square(normRadius);
|
||||
texCoordWeldRadius2 = square(texRadius);
|
||||
|
||||
const bool hasTexCoords = (texCoordArray.size() > 0);
|
||||
|
||||
if (hasTexCoords) {
|
||||
debugAssertM(vertexArray.size() == texCoordArray.size(),
|
||||
"Input arrays are not parallel.");
|
||||
}
|
||||
|
||||
Array<Vector3> unrolledVertexArray;
|
||||
Array<Vector3> unrolledFaceNormalArray;
|
||||
Array<Vector3> unrolledSmoothNormalArray;
|
||||
Array<Vector2> unrolledTexCoordArray;
|
||||
|
||||
if (! hasTexCoords) {
|
||||
// Generate all zero texture coordinates
|
||||
texCoordArray.resize(vertexArray.size());
|
||||
}
|
||||
|
||||
// Generate a flat (unrolled) triangle list with texture coordinates.
|
||||
unroll(indexArrayArray, vertexArray, texCoordArray,
|
||||
unrolledVertexArray, unrolledTexCoordArray);
|
||||
|
||||
// Put the output back into the input slots.
|
||||
outputVertexArray = &vertexArray;
|
||||
outputNormalArray = &normalArray;
|
||||
outputTexCoordArray = &texCoordArray;
|
||||
outputVertexArray->fastClear();
|
||||
outputNormalArray->fastClear();
|
||||
outputTexCoordArray->fastClear();
|
||||
|
||||
// For every three vertices, generate their face normal and store it at
|
||||
// each vertex. The output array has the same length as the input.
|
||||
computeFaceNormals(unrolledVertexArray, unrolledFaceNormalArray);
|
||||
|
||||
// Compute smooth normals at vertices.
|
||||
if (unrolledFaceNormalArray.size() > 0) {
|
||||
smoothNormals(unrolledVertexArray, unrolledFaceNormalArray, unrolledSmoothNormalArray);
|
||||
unrolledFaceNormalArray.clear();
|
||||
}
|
||||
|
||||
// Regenerate the triangle lists
|
||||
updateTriLists(indexArrayArray, unrolledVertexArray, unrolledSmoothNormalArray, unrolledTexCoordArray);
|
||||
|
||||
if (! hasTexCoords) {
|
||||
// Throw away the generated texCoords
|
||||
texCoordArray.resize(0);
|
||||
}
|
||||
}
|
||||
|
||||
WeldHelper(float vertRadius) :
|
||||
weldGrid(vertRadius),
|
||||
vertexWeldRadius(vertRadius) {}
|
||||
|
||||
};
|
||||
} // Internal
|
||||
|
||||
void Welder::weld(
|
||||
Array<Vector3>& vertexArray,
|
||||
Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& normalArray,
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
const Welder::Settings& settings) {
|
||||
|
||||
_internal::WeldHelper(settings.vertexWeldRadius).process(
|
||||
vertexArray, texCoordArray, normalArray, indexArrayArray,
|
||||
settings.normalSmoothingAngle, settings.textureWeldRadius, settings.normalWeldRadius);
|
||||
}
|
||||
|
||||
|
||||
Welder::Settings::Settings(const Any& any) {
|
||||
*this = Settings();
|
||||
any.verifyName("Welder::Settings");
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "normalsmoothingangle") {
|
||||
normalSmoothingAngle = it->value;
|
||||
} else if (key == "vertexweldradius") {
|
||||
vertexWeldRadius = it->value;
|
||||
} else if (key == "textureweldradius") {
|
||||
textureWeldRadius = it->value;
|
||||
} else if (key == "normalweldradius") {
|
||||
normalWeldRadius = it->value;
|
||||
} else {
|
||||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Welder::Settings::operator Any() const {
|
||||
Any a(Any::TABLE, "Welder::Settings");
|
||||
a.set("normalSmoothingAngle", normalSmoothingAngle);
|
||||
a.set("vertexWeldRadius", vertexWeldRadius);
|
||||
a.set("textureWeldRadius", textureWeldRadius);
|
||||
a.set("normalWeldRadius", normalWeldRadius);
|
||||
return a;
|
||||
}
|
||||
|
||||
} // G3D
|
||||
159
dep/src/g3dlite/WinMain.cpp
Normal file
159
dep/src/g3dlite/WinMain.cpp
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
Dervied from SDL_main.c, which was placed in the public domain by Sam Lantinga 4/13/98
|
||||
|
||||
The WinMain function -- calls your program's main() function
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cctype>
|
||||
|
||||
#ifdef main
|
||||
# ifndef _WIN32_WCE_EMULATION
|
||||
# undef main
|
||||
# endif /* _WIN32_WCE_EMULATION */
|
||||
#endif /* main */
|
||||
|
||||
#if defined(_WIN32_WCE) && _WIN32_WCE < 300
|
||||
/* seems to be undefined in Win CE although in online help */
|
||||
#define isspace(a) (((CHAR)a == ' ') || ((CHAR)a == '\t'))
|
||||
#endif /* _WIN32_WCE < 300 */
|
||||
|
||||
// Turn off the G3D for loop scoping for C++
|
||||
#ifdef for
|
||||
# undef for
|
||||
#endif
|
||||
|
||||
extern int main(int argc, const char** argv);
|
||||
|
||||
/* Parse a command line buffer into arguments */
|
||||
static int ParseCommandLine(char *cmdline, char **argv) {
|
||||
char *bufp;
|
||||
int argc;
|
||||
|
||||
argc = 0;
|
||||
for (bufp = cmdline; *bufp;) {
|
||||
/* Skip leading whitespace */
|
||||
while (isspace(*bufp)) {
|
||||
++bufp;
|
||||
}
|
||||
/* Skip over argument */
|
||||
if (*bufp == '"') {
|
||||
++bufp;
|
||||
if (*bufp) {
|
||||
if (argv) {
|
||||
argv[argc] = bufp;
|
||||
}
|
||||
++argc;
|
||||
}
|
||||
/* Skip over word */
|
||||
while (*bufp && (*bufp != '"')) {
|
||||
++bufp;
|
||||
}
|
||||
} else {
|
||||
if (*bufp) {
|
||||
if (argv) {
|
||||
argv[argc] = bufp;
|
||||
}
|
||||
++argc;
|
||||
}
|
||||
/* Skip over word */
|
||||
while (*bufp && !isspace(*bufp)) {
|
||||
++bufp;
|
||||
}
|
||||
}
|
||||
if (*bufp) {
|
||||
if (argv) {
|
||||
*bufp = '\0';
|
||||
}
|
||||
++bufp;
|
||||
}
|
||||
}
|
||||
if (argv) {
|
||||
argv[argc] = NULL;
|
||||
}
|
||||
return (argc);
|
||||
}
|
||||
|
||||
/* Show an error message */
|
||||
static void ShowError(const char *title, const char *message) {
|
||||
/* If USE_MESSAGEBOX is defined, you need to link with user32.lib */
|
||||
#ifdef USE_MESSAGEBOX
|
||||
MessageBox(NULL, message, title, MB_ICONEXCLAMATION | MB_OK);
|
||||
#else
|
||||
fprintf(stderr, "%s: %s\n", title, message);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pop up an out of memory message, returns to Windows */
|
||||
static BOOL OutOfMemory(void) {
|
||||
ShowError("Fatal Error", "Out of memory - aborting");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int WINAPI G3D_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {
|
||||
char **argv;
|
||||
int argc;
|
||||
int status;
|
||||
char *cmdline;
|
||||
# ifdef _WIN32_WCE
|
||||
wchar_t *bufp;
|
||||
int nLen;
|
||||
# else
|
||||
char *bufp;
|
||||
size_t nLen;
|
||||
# endif
|
||||
(void)sw;
|
||||
(void)szCmdLine;
|
||||
(void)hInst;
|
||||
(void)hPrev;
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
#error WinCE not supported
|
||||
/*
|
||||
nLen = wcslen(szCmdLine) + 128 + 1;
|
||||
bufp = SDL_stack_alloc(wchar_t, nLen * 2);
|
||||
wcscpy(bufp, TEXT("\""));
|
||||
GetModuleFileName(NULL, bufp + 1, 128 - 3);
|
||||
wcscpy(bufp + wcslen(bufp), TEXT("\" "));
|
||||
wcsncpy(bufp + wcslen(bufp), szCmdLine, nLen - wcslen(bufp));
|
||||
nLen = wcslen(bufp) + 1;
|
||||
cmdline = SDL_stack_alloc(char, nLen);
|
||||
if (cmdline == NULL) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL);
|
||||
*/
|
||||
#else
|
||||
/* Grab the command line */
|
||||
bufp = GetCommandLineA();
|
||||
nLen = strlen(bufp) + 1;
|
||||
cmdline = (char*)malloc(sizeof(char) * nLen);
|
||||
if (cmdline == NULL) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
strncpy(cmdline, bufp, nLen);
|
||||
#endif
|
||||
|
||||
/* Parse it into argv and argc */
|
||||
argc = ParseCommandLine(cmdline, NULL);
|
||||
argv = (char**)malloc(sizeof(char*) * (argc + 1));
|
||||
if (argv == NULL) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
ParseCommandLine(cmdline, argv);
|
||||
|
||||
/* Run the main program */
|
||||
status = main(argc, (const char**)argv);
|
||||
free(argv);
|
||||
free(cmdline);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif // if Win32
|
||||
82
dep/src/g3dlite/constants.cpp
Normal file
82
dep/src/g3dlite/constants.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
@file constants.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2009-05-20
|
||||
@edited 2010-01-29
|
||||
*/
|
||||
#include "G3D/constants.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
const std::string MirrorQuality::str[] = {"NONE", "STATIC_ENV", "DYNAMIC_PLANAR", "DYNAMIC_ENV", "BEST"};
|
||||
const MirrorQuality::Value MirrorQuality::enm[] = {MirrorQuality::NONE, MirrorQuality::STATIC_ENV,
|
||||
MirrorQuality::DYNAMIC_PLANAR, MirrorQuality::DYNAMIC_ENV, MirrorQuality::BEST};
|
||||
|
||||
MirrorQuality::MirrorQuality(const class Any& any) {
|
||||
*this = any;
|
||||
}
|
||||
|
||||
|
||||
MirrorQuality& MirrorQuality::operator=(const Any& any) {
|
||||
const std::string& s = toUpper(any.string());
|
||||
|
||||
for (int i = 0; ! str[i].empty(); ++i) {
|
||||
if (s == str[i]) {
|
||||
value = enm[i];
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
any.verify(false, "Unrecognized MirrorQuality constant");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
MirrorQuality::operator Any() const {
|
||||
return toString();
|
||||
}
|
||||
|
||||
|
||||
const std::string& MirrorQuality::toString() const {
|
||||
return str[value];
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const std::string RefractionQuality::str[] = {"NONE", "STATIC_ENV", "DYNAMIC_FLAT", "DYNAMIC_FLAT_MULTILAYER", "DYNAMIC_ENV", "BEST"};
|
||||
const RefractionQuality::Value RefractionQuality::enm[] = {RefractionQuality::NONE, RefractionQuality::STATIC_ENV,
|
||||
RefractionQuality::DYNAMIC_FLAT, RefractionQuality::DYNAMIC_FLAT_MULTILAYER, RefractionQuality::DYNAMIC_ENV, RefractionQuality::BEST};
|
||||
|
||||
RefractionQuality::RefractionQuality(const class Any& any) {
|
||||
*this = any;
|
||||
}
|
||||
|
||||
|
||||
RefractionQuality& RefractionQuality::operator=(const Any& any) {
|
||||
const std::string& s = toUpper(any.string());
|
||||
|
||||
for (int i = 0; ! str[i].empty(); ++i) {
|
||||
if (s == str[i]) {
|
||||
value = enm[i];
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
any.verify(false, "Unrecognized RefractionQuality constant");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
RefractionQuality::operator Any() const {
|
||||
return toString();
|
||||
}
|
||||
|
||||
|
||||
const std::string& RefractionQuality::toString() const {
|
||||
return str[value];
|
||||
}
|
||||
|
||||
} // G3D
|
||||
389
dep/src/g3dlite/debugAssert.cpp
Normal file
389
dep/src/g3dlite/debugAssert.cpp
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
/**
|
||||
@file debugAssert.cpp
|
||||
|
||||
Windows implementation of assertion routines.
|
||||
|
||||
@maintainer Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2001-08-26
|
||||
@edited 2009-06-02
|
||||
*/
|
||||
|
||||
#include "G3D/debugAssert.h"
|
||||
#include "G3D/platform.h"
|
||||
#ifdef G3D_WIN32
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/prompt.h"
|
||||
#include <string>
|
||||
#include "G3D/debugPrintf.h"
|
||||
#include "G3D/Log.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// disable: "C++ exception handler used"
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable : 4530)
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace G3D { namespace _internal {
|
||||
|
||||
ConsolePrintHook _consolePrintHook;
|
||||
AssertionHook _debugHook = _handleDebugAssert_;
|
||||
AssertionHook _failureHook = _handleErrorCheck_;
|
||||
|
||||
#ifdef G3D_LINUX
|
||||
#if 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
dep/src/g3dlite/fileutils.cpp
Normal file
1165
dep/src/g3dlite/fileutils.cpp
Normal file
File diff suppressed because it is too large
Load diff
32
dep/src/g3dlite/filter.cpp
Normal file
32
dep/src/g3dlite/filter.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
@file filter.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2007-03-01
|
||||
@edited 2007-03-01
|
||||
|
||||
Copyright 2000-2007, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
#include "G3D/filter.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
void gaussian1D(Array<float>& coeff, int N, float std) {
|
||||
coeff.resize(N);
|
||||
float sum = 0.0f;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
float x = i - (N - 1) / 2.0f;
|
||||
float p = -square(x / std) / 2.0f;
|
||||
float y = exp(p);
|
||||
coeff[i] = y;
|
||||
sum += y;
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
coeff[i] /= sum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
|
@ -4,22 +4,13 @@
|
|||
@author Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2000-09-09
|
||||
@edited 2006-04-30
|
||||
@edited 2006-08-14
|
||||
*/
|
||||
|
||||
#include "G3D/format.h"
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/System.h"
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
#include <math.h>
|
||||
#define vsnprintf _vsnprintf
|
||||
#define NEWLINE "\r\n"
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#define NEWLINE "\n"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// disable: "C++ exception handler used"
|
||||
# pragma warning (push)
|
||||
|
|
@ -31,7 +22,7 @@
|
|||
|
||||
namespace G3D {
|
||||
|
||||
std::string format(const char* fmt,...) {
|
||||
std::string __cdecl format(const char* fmt,...) {
|
||||
va_list argList;
|
||||
va_start(argList,fmt);
|
||||
std::string result = vformat(fmt, argList);
|
||||
|
|
@ -40,10 +31,10 @@ std::string format(const char* fmt,...) {
|
|||
return result;
|
||||
}
|
||||
|
||||
#if defined(G3D_WIN32) && (_MSC_VER >= 1300)
|
||||
// Both MSVC6 and 7 seem to use the non-standard vsnprintf
|
||||
#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 headers include vscprintf for some reason.
|
||||
// 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;
|
||||
|
|
@ -54,6 +45,7 @@ std::string vformat(const char *fmt, va_list argPtr) {
|
|||
const int bufSize = 161;
|
||||
char stackBuffer[bufSize];
|
||||
|
||||
// MSVC does not support va_copy
|
||||
int actualSize = _vscprintf(fmt, argPtr) + 1;
|
||||
|
||||
if (actualSize > bufSize) {
|
||||
|
|
@ -64,7 +56,7 @@ std::string vformat(const char *fmt, va_list argPtr) {
|
|||
if (actualSize < maxSize) {
|
||||
|
||||
heapBuffer = (char*)System::malloc(maxSize + 1);
|
||||
vsnprintf(heapBuffer, maxSize, fmt, argPtr);
|
||||
_vsnprintf(heapBuffer, maxSize, fmt, argPtr);
|
||||
heapBuffer[maxSize] = '\0';
|
||||
} else {
|
||||
heapBuffer = (char*)System::malloc(actualSize);
|
||||
|
|
@ -81,7 +73,7 @@ std::string vformat(const char *fmt, va_list argPtr) {
|
|||
}
|
||||
}
|
||||
|
||||
#elif defined(G3D_WIN32) && (_MSC_VER < 1300)
|
||||
#elif defined(_MSC_VER) && (_MSC_VER < 1300)
|
||||
|
||||
std::string vformat(const char *fmt, va_list argPtr) {
|
||||
// We draw the line at a 1MB string.
|
||||
|
|
@ -93,7 +85,10 @@ std::string vformat(const char *fmt, va_list argPtr) {
|
|||
const int bufSize = 161;
|
||||
char stackBuffer[bufSize];
|
||||
|
||||
int actualWritten = vsnprintf(stackBuffer, bufSize, fmt, argPtr);
|
||||
// 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) {
|
||||
|
|
@ -102,7 +97,7 @@ std::string vformat(const char *fmt, va_list argPtr) {
|
|||
double powSize = 1.0;
|
||||
char* heapBuffer = (char*)System::malloc(heapSize);
|
||||
|
||||
while ((vsnprintf(heapBuffer, heapSize, fmt, argPtr) == -1) &&
|
||||
while ((_vsnprintf(heapBuffer, heapSize, fmt, argPtr) == -1) &&
|
||||
(heapSize < maxSize)) {
|
||||
|
||||
heapSize = iCeil(heapSize * ::pow((double)2.0, powSize++));
|
||||
|
|
@ -133,15 +128,19 @@ std::string vformat(const char* fmt, va_list argPtr) {
|
|||
const int bufSize = 161;
|
||||
char stackBuffer[bufSize];
|
||||
|
||||
int numChars = vsnprintf(stackBuffer, bufSize, fmt, argPtr);
|
||||
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));
|
||||
|
||||
assert(heapBuffer);
|
||||
debugAssert(heapBuffer);
|
||||
int numChars2 = vsnprintf(heapBuffer, numChars + 1, fmt, argPtr);
|
||||
assert(numChars2 == numChars);
|
||||
debugAssert(numChars2 == numChars);
|
||||
(void)numChars2;
|
||||
|
||||
std::string result(heapBuffer);
|
||||
|
||||
|
|
@ -160,12 +159,6 @@ std::string vformat(const char* fmt, va_list argPtr) {
|
|||
|
||||
} // namespace
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
# undef vsnprintf
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#undef NEWLINE
|
||||
|
|
|
|||
204
dep/src/g3dlite/g3dfnmatch.cpp
Normal file
204
dep/src/g3dlite/g3dfnmatch.cpp
Normal 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
dep/src/g3dlite/g3dmath.cpp
Normal file
108
dep/src/g3dlite/g3dmath.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
73
dep/src/g3dlite/license.cpp
Normal file
73
dep/src/g3dlite/license.cpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
@file license.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2004-04-15
|
||||
@edited 2004-04-15
|
||||
*/
|
||||
|
||||
#include "G3D/format.h"
|
||||
#include <string>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
std::string license() {
|
||||
return format(
|
||||
|
||||
"This software is based in part on the PNG Reference Library which is\n"
|
||||
"Copyright (c) 2004 Glenn Randers-Pehrson\n\n"
|
||||
"This software is based in part on the work of the Independent JPEG Group.\n\n"
|
||||
"This software is based on part on the FFmpeg libavformat and libavcodec libraries\n"
|
||||
"(\"FFmpeg\", http://ffmpeg.mplayerhq.hu), which are included under the terms of the\n"
|
||||
"GNU Lesser General Public License (LGPL), (http://www.gnu.org/copyleft/lesser.html).\n\n"
|
||||
"%s"
|
||||
"This program uses the G3D Library (http://g3d.sf.net), which\n"
|
||||
"is licensed under the \"Modified BSD\" Open Source license. The G3D library\n"
|
||||
"source code is Copyright © 2000-2010, Morgan McGuire, All rights reserved.\n"
|
||||
"This program uses The OpenGL Extension Wrangler Library, which \n"
|
||||
"is licensed under the \"Modified BSD\" Open Source license. \n"
|
||||
"The OpenGL Extension Wrangler Library source code is\n"
|
||||
"Copyright (C) 2002-2008, Milan Ikits <milan ikits[]ieee org>\n"
|
||||
"Copyright (C) 2002-2008, Marcelo E. Magallon <mmagallo[]debian org>\n"
|
||||
"Copyright (C) 2002, Lev Povalahev\n"
|
||||
"All rights reserved.\n\n"
|
||||
"The Modified BSD license is below, and requires the following statement:\n"
|
||||
"\n"
|
||||
"Redistribution and use in source and binary forms, with or without \n"
|
||||
"modification, are permitted provided that the following conditions are met:\n"
|
||||
"\n"
|
||||
"* Redistributions of source code must retain the above copyright notice, \n"
|
||||
" this list of conditions and the following disclaimer.\n"
|
||||
"* Redistributions in binary form must reproduce the above copyright notice, \n"
|
||||
" this list of conditions and the following disclaimer in the documentation \n"
|
||||
" and/or other materials provided with the distribution.\n"
|
||||
"* The name of the author may be used to endorse or promote products \n"
|
||||
" derived from this software without specific prior written permission.\n"
|
||||
"\n"
|
||||
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" \n"
|
||||
"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \n"
|
||||
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
|
||||
"ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE \n"
|
||||
"LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR \n"
|
||||
"CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF \n"
|
||||
"SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
|
||||
"INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
|
||||
"CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
|
||||
"ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n"
|
||||
"THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||
"\n\n"
|
||||
"G3D VERSION %d\n",
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
"" // Win32 doesn't use SDL
|
||||
#else
|
||||
"This software uses the Simple DirectMedia Layer library (\"SDL\",\n"
|
||||
"http://www.libsdl.org), which is included under the terms of the\n"
|
||||
"GNU Lesser General Public License, (http://www.gnu.org/copyleft/lesser.html).\n\n"
|
||||
#endif
|
||||
,
|
||||
G3D_VER);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,107 +3,113 @@
|
|||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
|
||||
<title>G3D: License</title>
|
||||
<title>G3D Innovation Engine: License</title>
|
||||
<link href="stylesheet.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
span.menu_tab a {
|
||||
background: #FFE183;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #FFB143;
|
||||
padding: 5px;
|
||||
margin: 0px;
|
||||
margin-left: 2px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
font-family: arial;
|
||||
color: #000000;
|
||||
position: relative;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
span.menu_tab a:link, a:visited {
|
||||
text-decoration: none;
|
||||
}
|
||||
span.menu_tab a:hover {
|
||||
background: #FDEFA0;
|
||||
color: #000000;
|
||||
text-decoration: none;
|
||||
}
|
||||
.widthadjust {
|
||||
min-width: 800px;
|
||||
width: 80%;
|
||||
background: #FFFFFF;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
* html .widthadjust {
|
||||
width: expression(document.body.clientWidth < 1000? "1000px": "auto";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="width: 100%; background: #aaaaaa">
|
||||
<table class="widthadjust" align=center><tr><td>
|
||||
<table style="height: 44px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #FFc161;" width=100% cellspacing=0 cellpadding=0>
|
||||
|
||||
<tr>
|
||||
<td rowspan="2" valign="bottom" style="width: 51;">
|
||||
<a href="index.html">
|
||||
<img src="G3D-small-shadow.jpg" border="0" align="left">
|
||||
</a>
|
||||
</td>
|
||||
<td style="width: 65%;" nowrap="true" valign="bottom">
|
||||
<font size="2">
|
||||
<center>
|
||||
<a href="http://groups.google.com/group/g3d-users/topics">Support Forum</a>
|
||||
<a href="http://g3d.cvs.sourceforge.net/g3d/G3D/">Library Source</a>
|
||||
<a href="http://sourceforge.net/projects/g3d/">SourceForge Page</a>
|
||||
<a href="http://g3d.sf.net/">Web Page</a>
|
||||
</center>
|
||||
</font>
|
||||
</td>
|
||||
</tr>
|
||||
<tr cellspacing=0 cellpadding=0>
|
||||
<td style="width: 70%;" nowrap=true>
|
||||
<img src="G3D-small-shadow.jpg">
|
||||
<span class="menu_tab"><a href="index.html">Contents</a></span>
|
||||
<span class="menu_tab"><a href="globals_func.html">Functions</a></span>
|
||||
<span class="menu_tab"><a href="classes.html">Classes</a></span>
|
||||
<span class="menu_tab"><a href="indexedbytopic.html">Topics</a></span>
|
||||
<span class="menu_tab"><a href="http://sourceforge.net/forum/forum.php?forum_id=262426">User Forum</a></span>
|
||||
<span class="menu_tab"><a href="http://cvs.sourceforge.net/viewcvs.py/g3d-cpp/cpp/">CVS</a></span>
|
||||
</td>
|
||||
<td style="width: 65%;" nowrap=true valign=bottom>
|
||||
|
||||
<span class="menu_tab">
|
||||
<a href="http://sourceforge.net/apps/mediawiki/g3d/index.php?title=Main_Page">Wiki Doc</a>
|
||||
</span>
|
||||
<span class="menu_tab">
|
||||
<a href="dataindex.html">Data</a>
|
||||
</span>
|
||||
<span class="menu_tab">
|
||||
<a href="annotated.html">API Index</a>
|
||||
</span>
|
||||
<span class="menu_tab">
|
||||
<a href="apiindex.html">APIs by Level</a>
|
||||
</span>
|
||||
<span class="menu_tab">
|
||||
<a href="topicindex.html">APIs by Task</a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<table cellspacing=0 cellpadding=0 width=100% >
|
||||
<tr><td>
|
||||
<!-- code goes here -->
|
||||
|
||||
<!-- Generated by Doxygen 1.4.6-NO -->
|
||||
<h1><a class="anchor" name="license">License</a></h1>
|
||||
<TABLE BORDER=0 WIDTH=80%><TR><TD><I><FONT FACE="Arial">
|
||||
<A HREF="guideintro.html"><IMG SRC="backarrow.gif" BORDER=0 ALIGN=MIDDLE>
|
||||
Introduction</A></I></FONT></TD><TD ALIGN=RIGHT><FONT FACE="Arial"><I>
|
||||
<A HREF="guideinstall.html">
|
||||
Installation <IMG SRC="forwardarrow.gif" BORDER=0 ALIGN=MIDDLE></A></I></FONT></TD></TR></TABLE>
|
||||
<h2><a class="anchor" name="intent">
|
||||
|
||||
<!-- Generated by Doxygen 1.6.1 -->
|
||||
<div class="contents">
|
||||
|
||||
|
||||
<h1><a class="anchor" id="license">License </a></h1><h2><a class="anchor" id="intent">
|
||||
Intent of License</a></h2>
|
||||
(This section is informal and not legally binding.)<p>
|
||||
<br>
|
||||
This library is free code-- you can use it without charge and it is minimally legally encumbered. Unlike some other free libraries, we <u>do not</u> require you to release your source code or make your own program open source.<p>
|
||||
I intend the license (below) to protect me and the other contributors from liability and allow you to use the source however you want. You can make your own closed or open-source programs, sell them, give them away, whatever.<p>
|
||||
You have an obligation to say "this software is based in part on the work of the Independent JPEG Group" in your documentation or application help if you use the <a class="el" href="classG3D_1_1GImage.html">G3D::GImage</a> class because it is based on the IJG library. The OpenGL headers and ZLib headers included may be freely distributed provided their copyright notices remain intact.<p>
|
||||
For convenience, <a class="el" href="namespaceG3D.html#2d6bccd0c2fa5b44882b7d0c732e2712">G3D::license</a> is a function that returns the license string you must put in your documentation. <a class="el" href="classG3D_1_1GApp.html">G3D::GApp</a> will automatically write a file (g3d-license.txt) to disk with the contents of this license unless you tell it not to.<p>
|
||||
Most of the data resources have either entered the public domain and have been in several published papers or are data that I have explicitly received permission to distribute with <a class="el" href="namespaceG3D.html">G3D</a>. The <a class="el" href="namespaceG3D.html">G3D</a> fonts are actually font images, not TrueType font descriptions and may be freely distributed. As a rule of thumb, you can freely use and distribute anything you find in the data directory but may need permission to use it in a commercial product. Check the various copyright.txt files in the data directories for specific information.<p>
|
||||
You are required by the BSD license to acknowledge <a class="el" href="namespaceG3D.html">G3D</a> in your documentation. This can be as minimal as a note buried in the fine print at the end of a manual or a text file accompanying your program. I appreciate it if you acknowledged the library more publicly but you aren't required to.<p>
|
||||
Likewise, you are encouraged but not required to submit patches to improve the library for the benefit of all. E-mail me with bugs, patches, and questions.<p>
|
||||
-Morgan McGuire <<em><a href="mailto:matrix@graphics3d.com">matrix@graphics3d.com</a></em>><p>
|
||||
<hr>
|
||||
<h2><a class="anchor" name="reallicense">
|
||||
<p>(This section is informal and not legally binding.)</p>
|
||||
<p><br/>
|
||||
This library is free code-- you can use it without charge and it is minimally legally encumbered. Unlike some other free libraries, we <b>do not</b> require you to release your source code or make your own program open source.</p>
|
||||
<p>I intend the license (below) to protect me and the other contributors from liability and allow you to use the source however you want. You can make your own closed or open-source programs, sell them, give them away, whatever.</p>
|
||||
<p>The license for <a class="el" href="namespace_g3_d.html">G3D</a> itself and the libaries included in the <a class="el" href="namespace_g3_d.html">G3D</a> distribution create certain documentation obligations for you. For convenience, <a class="el" href="namespace_g3_d.html#a2d6bccd0c2fa5b44882b7d0c732e2712" title="G3D, SDL, and IJG libraries require license documentation to be distributed with...">G3D::license</a> is a function that returns the license string you must put in your documentation. <a class="el" href="class_g3_d_1_1_g_app.html" title="For each frame, the GApp has several tasks that can be implemented by overriding...">G3D::GApp</a> will automatically write a file (g3d-license.txt) to disk with the contents of this license unless you tell it not to, thus automatically satisfying your documentation requirement after the first time you run a <a class="el" href="namespace_g3_d.html">G3D</a> program.</p>
|
||||
<p>Most of the data resources have either entered the public domain and have been in several published papers or are data that I have explicitly received permission to distribute with <a class="el" href="namespace_g3_d.html">G3D</a>. The <a class="el" href="namespace_g3_d.html">G3D</a> fonts are actually font images, not TrueType font descriptions and may be freely distributed. As a rule of thumb, you can freely use and distribute anything you find in the data directory but may need permission to use it in a commercial product. Check the various copyright.txt files in the data directories for specific information.</p>
|
||||
<p>You are required by the BSD license to acknowledge <a class="el" href="namespace_g3_d.html">G3D</a> in your documentation. This can be as minimal as a note buried in the fine print at the end of a manual or a text file accompanying your program. I appreciate it if you acknowledged the library more publicly but you aren't required to.</p>
|
||||
<p>Likewise, you are encouraged but not required to submit patches to improve the library for the benefit of all. Post bugs, patches, and questions to the g3d-users forum linked at the top of this page. </p>
|
||||
<p>-Morgan McGuire <<em><a href="mailto:morgan@cs.williams.edu">morgan@cs.williams.edu</a></em>></p>
|
||||
<hr/>
|
||||
<h2><a class="anchor" id="reallicense">
|
||||
License</a></h2>
|
||||
<em><a class="el" href="namespaceG3D.html">G3D</a> is licensed under the <a href="http://www.opensource.org/licenses/bsd-license.php">BSD license</a>, with portions controlled by the <a href="IJG-README.TXT">IJG license</a> and <a href="libpng-LICENSE.txt">PNG Reference Library license</a></em><p>
|
||||
<code> <div align="center">
|
||||
<img src="http://opensource.org/trademarks/osi-certified/web/osi-certified-120x100.gif" alt="osi-certified-120x100.gif">
|
||||
<p><em><a class="el" href="namespace_g3_d.html">G3D</a> is licensed under the <a href="http://www.opensource.org/licenses/bsd-license.php">BSD license</a>, with portions controlled by the <a href="IJG-README.TXT">IJG license</a>, <a href="libpng-LICENSE.txt">PNG Reference Library license</a>.</em></p>
|
||||
<p><code> </p>
|
||||
<div align="center">
|
||||
<img src="http://opensource.org/trademarks/osi-certified/web/osi-certified-120x100.gif" alt="osi-certified-120x100.gif"/>
|
||||
</div>
|
||||
</code><p>
|
||||
<code>This product uses software from the <a class="el" href="namespaceG3D.html">G3D</a> project (<a href="http://g3d-cpp.sf.net">http://g3d-cpp.sf.net</a>) </code><p>
|
||||
<code>Copyright © 2000-2006, Morgan McGuire </code><p>
|
||||
<code>All rights reserved. </code><p>
|
||||
<code> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: </code><p>
|
||||
<code> Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. </code><p>
|
||||
<code> 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. </code><p>
|
||||
<code> Neither the name of Morgan McGuire, Williams College, Brown University, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. </code><p>
|
||||
<code> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. </code><p>
|
||||
You must also agree to be bound by the terms of the Independent JPEG Group license for the portions of this library that are based on the work of the Independent JPEG Group, <b>if you use those portions</b>. Note: if you do not use the <a class="el" href="classG3D_1_1GImage.html">G3D::GImage</a> class, this clause does not apply to you because the linker will strip that code from your project. The <a href="IJG-README.TXT"
|
||||
>IJG-README.TXT</a> file contains the Independent JPEG Group license.</A>
|
||||
<p> </code></p>
|
||||
<p><code>This product uses software from the <a class="el" href="namespace_g3_d.html">G3D</a> project (<a href="http://g3d.sf.net">http://g3d.sf.net</a>) </code></p>
|
||||
<p><code>Copyright © 2000-2010, Morgan McGuire </code></p>
|
||||
<p><code>All rights reserved. </code></p>
|
||||
<p><code> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: </code></p>
|
||||
<p><code> Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. </code></p>
|
||||
<p><code> 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. </code></p>
|
||||
<p><code> Neither the name of Morgan McGuire, Williams College, Brown University, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. </code></p>
|
||||
<p><code> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. </code> </p>
|
||||
</div>
|
||||
</A>
|
||||
<hr><address style="align: right;"><small>
|
||||
Generated on Tue Jul 18 12:05:54 2006 for G3D by <a href="http://www.doxygen.org/index.html">
|
||||
G3D Innovation Engine documentation generated on Thu Mar 25 14:54:30 2010 using <a href="http://www.doxygen.org/index.html">
|
||||
<img src="doxygen.png" alt="doxygen" align="middle" border=0 width=55 height=26>
|
||||
</a> 1.4.6-NO</small></address>
|
||||
</a> 1.6.1</small></address>
|
||||
<!-- Removed to make page loading faster
|
||||
Hosted by <A href="http://sourceforge.net"> <IMG src="http://sourceforge.net/sflogo.php?group_id=76879&type=5" width="210" height="62" border="0" alt="SourceForge.net Logo"></A>
|
||||
-->
|
||||
|
||||
<!-- Piwik -->
|
||||
<script type="text/javascript">
|
||||
var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/g3d/" : "http://apps.sourceforge.net/piwik/g3d/");
|
||||
document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
piwik_action_name = '';
|
||||
piwik_idsite = 2;
|
||||
piwik_url = pkBaseURL + "piwik.php";
|
||||
piwik_log(piwik_action_name, piwik_idsite, piwik_url);
|
||||
</script>
|
||||
<object><noscript><p><img src="http://apps.sourceforge.net/piwik/g3d/piwik.php?idsite=2" alt="piwik"/></p></noscript></object>
|
||||
<!-- End Piwik Tag -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
729
dep/src/g3dlite/prompt.cpp
Normal file
729
dep/src/g3dlite/prompt.cpp
Normal 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)¶ms);
|
||||
|
||||
free(newStr);
|
||||
|
||||
/*
|
||||
For debugging when DialogBoxIndirectParam fails:
|
||||
|
||||
// The last error value. (Which is preserved across the call).
|
||||
DWORD lastErr = GetLastError();
|
||||
|
||||
// The decoded message from FormatMessage
|
||||
LPTSTR formatMsg = NULL;
|
||||
|
||||
if (NULL == formatMsg) {
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
lastErr,
|
||||
0,
|
||||
(LPTSTR)&formatMsg,
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
// Make sure the message got translated into something.
|
||||
LPTSTR realLastErr;
|
||||
if (NULL != formatMsg) {
|
||||
realLastErr = formatMsg;
|
||||
} else {
|
||||
realLastErr = "Last error code does not exist.";
|
||||
}
|
||||
|
||||
// Get rid of the allocated memory from FormatMessage.
|
||||
if (NULL != formatMsg) {
|
||||
LocalFree((LPVOID)formatMsg);
|
||||
}
|
||||
*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* 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
dep/src/g3dlite/stringutils.cpp
Normal file
275
dep/src/g3dlite/stringutils.cpp
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
/**
|
||||
@file stringutils.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2000-09-09
|
||||
@edited 2008-01-10
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// disable: "C++ exception handler used"
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable : 4530)
|
||||
#endif
|
||||
#ifdef G3D_WIN32
|
||||
const char* NEWLINE = "\r\n";
|
||||
#else
|
||||
const char* NEWLINE = "\n";
|
||||
static bool iswspace(int ch) { return (ch==' ' || ch=='\t' || ch=='\n' || ch=='\r'); }
|
||||
#endif
|
||||
|
||||
void parseCommaSeparated(const std::string s, Array<std::string>& array, bool stripQuotes) {
|
||||
array.fastClear();
|
||||
if (s == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t begin = 0;
|
||||
const char delimiter = ',';
|
||||
const char quote = '\"';
|
||||
do {
|
||||
size_t end = begin;
|
||||
// Find the next comma, or the end of the string
|
||||
bool inQuotes = false;
|
||||
while ((end < s.length()) && (inQuotes || (s[end] != delimiter))) {
|
||||
if (s[end] == quote) {
|
||||
if ((end < s.length() - 2) && (s[end + 1] == quote) && (s[end + 2]) == quote) {
|
||||
// Skip over the superquote
|
||||
end += 2;
|
||||
}
|
||||
inQuotes = ! inQuotes;
|
||||
}
|
||||
++end;
|
||||
}
|
||||
array.append(s.substr(begin, end - begin));
|
||||
begin = end + 1;
|
||||
} while (begin < s.length());
|
||||
|
||||
if (stripQuotes) {
|
||||
for (int i = 0; i < array.length(); ++i) {
|
||||
std::string& t = array[i];
|
||||
int L = t.length();
|
||||
if ((L > 1) && (t[0] == quote) && (t[L - 1] == quote)) {
|
||||
if ((L > 6) && (t[1] == quote) && (t[2] == quote) && (t[L - 3] == quote) && (t[L - 2] == quote)) {
|
||||
// Triple-quote
|
||||
t = t.substr(3, L - 6);
|
||||
} else {
|
||||
// Double-quote
|
||||
t = t.substr(1, L - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool beginsWith(
|
||||
const std::string& test,
|
||||
const std::string& pattern) {
|
||||
|
||||
if (test.size() >= pattern.size()) {
|
||||
for (int i = 0; i < (int)pattern.size(); ++i) {
|
||||
if (pattern[i] != test[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool endsWith(
|
||||
const std::string& test,
|
||||
const std::string& pattern) {
|
||||
|
||||
if (test.size() >= pattern.size()) {
|
||||
int te = test.size() - 1;
|
||||
int pe = pattern.size() - 1;
|
||||
for (int i = pattern.size() - 1; i >= 0; --i) {
|
||||
if (pattern[pe - i] != test[te - i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string wordWrap(
|
||||
const std::string& input,
|
||||
int numCols) {
|
||||
|
||||
std::string output;
|
||||
size_t c = 0;
|
||||
int len;
|
||||
|
||||
// Don't make lines less than this length
|
||||
int minLength = numCols / 4;
|
||||
size_t inLen = input.size();
|
||||
|
||||
bool first = true;
|
||||
while (c < inLen) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
output += NEWLINE;
|
||||
}
|
||||
|
||||
if ((int)inLen - (int)c - 1 < numCols) {
|
||||
// The end
|
||||
output += input.substr(c, inLen - c);
|
||||
break;
|
||||
}
|
||||
|
||||
len = numCols;
|
||||
|
||||
// Look at character c + numCols, see if it is a space.
|
||||
while ((len > minLength) &&
|
||||
(input[c + len] != ' ')) {
|
||||
len--;
|
||||
}
|
||||
|
||||
if (len == minLength) {
|
||||
// Just crop
|
||||
len = numCols;
|
||||
|
||||
}
|
||||
|
||||
output += input.substr(c, len);
|
||||
c += len;
|
||||
if (c < input.size()) {
|
||||
// Collapse multiple spaces.
|
||||
while ((input[c] == ' ') && (c < input.size())) {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
int stringCompare(
|
||||
const std::string& s1,
|
||||
const std::string& s2) {
|
||||
|
||||
return stringPtrCompare(&s1, &s2);
|
||||
}
|
||||
|
||||
|
||||
int stringPtrCompare(
|
||||
const std::string* s1,
|
||||
const std::string* s2) {
|
||||
|
||||
return s1->compare(*s2);
|
||||
}
|
||||
|
||||
|
||||
std::string toUpper(const std::string& x) {
|
||||
std::string result = x;
|
||||
std::transform(result.begin(), result.end(), result.begin(), toupper);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::string toLower(const std::string& x) {
|
||||
std::string result = x;
|
||||
std::transform(result.begin(), result.end(), result.begin(), tolower);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Array<std::string> stringSplit(
|
||||
const std::string& x,
|
||||
char splitChar) {
|
||||
|
||||
Array<std::string> out;
|
||||
|
||||
// Pointers to the beginning and end of the substring
|
||||
const char* start = x.c_str();
|
||||
const char* stop = start;
|
||||
|
||||
while ((stop = strchr(start, splitChar))) {
|
||||
out.append(std::string(start, stop - start));
|
||||
start = stop + 1;
|
||||
}
|
||||
|
||||
// Append the last one
|
||||
out.append(std::string(start));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
std::string stringJoin(
|
||||
const Array<std::string>& a,
|
||||
char joinChar) {
|
||||
|
||||
std::string out;
|
||||
|
||||
for (int i = 0; i < (int)a.size() - 1; ++i) {
|
||||
out += a[i] + joinChar;
|
||||
}
|
||||
|
||||
if (a.size() > 0) {
|
||||
return out + a.last();
|
||||
} else {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string stringJoin(
|
||||
const Array<std::string>& a,
|
||||
const std::string& joinStr) {
|
||||
|
||||
std::string out;
|
||||
|
||||
for (int i = 0; i < (int)a.size() - 1; ++i) {
|
||||
out += a[i] + joinStr;
|
||||
}
|
||||
|
||||
if (a.size() > 0) {
|
||||
return out + a.last();
|
||||
} else {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string trimWhitespace(
|
||||
const std::string& s) {
|
||||
|
||||
size_t left = 0;
|
||||
|
||||
// Trim from left
|
||||
while ((left < s.length()) && iswspace(s[left])) {
|
||||
++left;
|
||||
}
|
||||
|
||||
int right = s.length() - 1;
|
||||
// Trim from right
|
||||
while ((right > (int)left) && iswspace(s[right])) {
|
||||
--right;
|
||||
}
|
||||
|
||||
return s.substr(left, right - left + 1);
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
#undef NEWLINE
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
155
dep/src/g3dlite/uint128.cpp
Normal file
155
dep/src/g3dlite/uint128.cpp
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/**
|
||||
@file uint128.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@author Kyle Whitson
|
||||
|
||||
@created 2008-07-17
|
||||
@edited 2008-07-17
|
||||
*/
|
||||
|
||||
#include "G3D/uint128.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
/** Adds two 64-bit integers, placing the result and the overflow into 64-bit integers.*/
|
||||
static void addAndCarry(const uint64& _a, const uint64& _b, uint64& carry, uint64& result) {
|
||||
|
||||
// Break each number into 4 32-bit chunks. Since we are using uints, right-shifting will fill with zeros.
|
||||
// This eliminates the need to and with 0xFFFFFFFF.
|
||||
uint32 a [2] = {_a & 0xFFFFFFFF, _a >> 32};
|
||||
uint32 b [2] = {_b & 0xFFFFFFFF, _b >> 32};
|
||||
|
||||
uint64 tmp = uint64(a[0]) + b[0];
|
||||
|
||||
result = tmp & 0xFFFFFFFF;
|
||||
uint32 c = tmp >> 32;
|
||||
|
||||
tmp = uint64(c) + a[1] + b[1];
|
||||
result += tmp << 32;
|
||||
carry = (tmp >> 32);
|
||||
}
|
||||
|
||||
/** Multiplies two unsigned 64-bit integers, placing the result into one 64-bit int and the overflow into another.*/
|
||||
void multiplyAndCarry(const uint64& _a, const uint64& _b, uint64& carry, uint64& result) {
|
||||
|
||||
// Break each number into 4 32-bit chunks. Since we are using uints, right-shifting will fill with zeros.
|
||||
// This eliminates the need to and with 0xFFFFFFFF.
|
||||
uint32 a [2] = {_a & 0xFFFFFFFF, _a >> 32};
|
||||
uint32 b [2] = {_b & 0xFFFFFFFF, _b >> 32};
|
||||
|
||||
uint64 prod [2][2];
|
||||
for(int i = 0; i < 2; ++i) {
|
||||
for(int j = 0; j < 2; ++j) {
|
||||
prod[i][j] = uint64(a[i]) * b[j];
|
||||
}
|
||||
}
|
||||
|
||||
// The product of the low bits of a and b will always fit into the result
|
||||
result = prod[0][0];
|
||||
|
||||
// The product of the high bits of a and b will never fit into the result
|
||||
carry = prod[1][1];
|
||||
|
||||
// The high 32 bits of prod[0][1] and prod[1][0] will never fit into the result
|
||||
carry += prod[0][1] >> 32;
|
||||
carry += prod[1][0] >> 32;
|
||||
|
||||
uint64 tmp;
|
||||
addAndCarry(result, (prod[0][1] << 32), tmp, result);
|
||||
carry += tmp;
|
||||
addAndCarry(result, (prod[1][0] << 32), tmp, result);
|
||||
carry += tmp;
|
||||
}
|
||||
|
||||
|
||||
uint128::uint128(const uint64& hi, const uint64& lo) : hi(hi), lo(lo) {
|
||||
}
|
||||
|
||||
uint128::uint128(const uint64& lo) : hi(0), lo(lo) {
|
||||
}
|
||||
|
||||
uint128& uint128::operator+=(const uint128& x) {
|
||||
|
||||
G3D::uint64 carry;
|
||||
addAndCarry(lo, x.lo, carry, lo);
|
||||
|
||||
// Adding the carry will change hi. Save the old hi bits in case this == x.
|
||||
const uint64 xHi = x.hi;
|
||||
hi += carry;
|
||||
hi += xHi;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator*=(const uint128& x) {
|
||||
|
||||
// The low bits will get overwritten when doing the multiply, so back up both (in case &x == this)
|
||||
const uint64 oldLo = lo;
|
||||
const uint64 oldXLo = x.lo;
|
||||
|
||||
G3D::uint64 carry;
|
||||
multiplyAndCarry(oldLo, oldXLo, carry, lo);
|
||||
|
||||
// Overflow doesn't matter here because the result is going into hi - any overflow will exceed the capacity of a 128-bit number
|
||||
// Note: hi * x.hi will always overflow, since (x * 2^64) * (y * 2^64) = x*y*(2^128). The largest number expressable in 128 bits is
|
||||
// 2^128 - 1.
|
||||
hi = carry + (oldLo * x.hi) + (hi * oldXLo);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator^=(const uint128& x) {
|
||||
hi ^= x.hi;
|
||||
lo ^= x.lo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator&=(const uint128& x) {
|
||||
hi &= x.hi;
|
||||
lo &= x.lo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator|=(const uint128& x) {
|
||||
hi |= x.hi;
|
||||
lo |= x.lo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool uint128::operator==(const uint128& x) {
|
||||
return (hi == x.hi) && (lo == x.lo);
|
||||
}
|
||||
|
||||
uint128& uint128::operator>>=(const int x) {
|
||||
|
||||
//Before shifting, mask out the bits that will be shifted out of hi.
|
||||
//Put a 1 in the first bit that will not be lost in the shift, then subtract 1 to get the mask.
|
||||
uint64 mask = ((uint64)1L << x) - 1;
|
||||
uint64 tmp = hi & mask;
|
||||
hi >>= x;
|
||||
|
||||
//Shift lo and add the bits shifted down from hi
|
||||
lo = (lo >> x) + (tmp << (64 - x));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator<<=(const int x) {
|
||||
|
||||
//Before shifting, mask out the bits that will be shifted out of lo.
|
||||
//Put a 1 in the last bit that will be lost in the shift, then subtract 1 to get the logical inverse of the mask.
|
||||
//A bitwise NOT will then produce the correct mask.
|
||||
uint64 mask = ~((((uint64)1L) << (64 - x)) - 1);
|
||||
uint64 tmp = lo & mask;
|
||||
lo <<= x;
|
||||
|
||||
//Shift hi and add the bits shifted up from lo
|
||||
hi = (hi << x) + (tmp >> (64 - x));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128 uint128::operator&(const uint128& x) {
|
||||
return uint128(hi & x.hi, lo & x.lo);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue