diff --git a/deps/g3dlite/CMakeLists.txt b/deps/g3dlite/CMakeLists.txt index 8d18bda9b..0bcf37024 100644 --- a/deps/g3dlite/CMakeLists.txt +++ b/deps/g3dlite/CMakeLists.txt @@ -11,6 +11,7 @@ set(g3dlib_STAT_SRCS source/AABox.cpp source/Any.cpp + source/AnyTableReader.cpp source/BinaryFormat.cpp source/BinaryInput.cpp source/BinaryOutput.cpp @@ -26,6 +27,7 @@ set(g3dlib_STAT_SRCS source/format.cpp source/g3dfnmatch.cpp source/g3dmath.cpp + source/GThread.cpp source/Line.cpp source/LineSegment.cpp source/Log.cpp @@ -38,7 +40,6 @@ set(g3dlib_STAT_SRCS source/Quat.cpp source/Random.cpp source/Ray.cpp - source/ReferenceCount.cpp source/RegistryUtil.cpp source/Sphere.cpp source/stringutils.cpp @@ -55,9 +56,6 @@ set(g3dlib_STAT_SRCS add_library(g3dlib STATIC ${g3dlib_STAT_SRCS}) -# Group sources -GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) - target_include_directories(g3dlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) @@ -70,6 +68,6 @@ target_link_libraries(g3dlib threads) set_target_properties(g3dlib - PROPERTIES - FOLDER - "deps") \ No newline at end of file + PROPERTIES + FOLDER + "deps") diff --git a/deps/g3dlite/Readme.txt b/deps/g3dlite/Readme.txt index 7988d1f31..e94dbaabd 100644 --- a/deps/g3dlite/Readme.txt +++ b/deps/g3dlite/Readme.txt @@ -9,3 +9,11 @@ G3D-v8.0_hotfix5.diff - 2013-02-27 - fix compilation in cygwin environments G3D-v8.0_hotfix6.diff - 2013-03-08 - fix compilation in mingw G3D-v8.0_hotfix7.diff - 2013-08-31 - fix typo in Matrix4 == operator G3D-v8.0_hotfix8.diff - 2013-09-01 - fix typo in Vector3int32 += operator +G3D-v8.0_hotfix9.diff - 2014-06-01 - only VS < 10 don't ship inttypes.h +G3D-v9.0 hotfix1.diff - 2014-08-22 - updated to G3D9, reapplied previous patches and removed unneeded changes +G3D-v9.0 hotfix2.diff - 2014-08-23 - fix some -Wconversion warnings +G3D-v9.0 hotfix3.diff - 2015-06-28 - fix some warnings +G3D-v9.0 hotfix4.diff - 2015-07-02 - backport G3D10 fix +G3D-v9.0 hotfix5.diff - 2015-07-31 - fix MSVC 2015 warning: dep/g3dlite/include/G3D/Quat.h(352): warning C4458: declaration of 'x' hides class member +G3D-v9.0 hotfix6.diff - 2015-11-04 - fix adding std::shared_ptr, std::weak_ptr, std::dynamic_pointer_cast, std::static_pointer_cast and std::enable_shared_from_this to global namespace +G3D-v9.0 hotfix7.diff - 2016-10-10 - fix warning on clang 3.8 backported from G3D 10 diff --git a/deps/g3dlite/include/G3D/AABox.h b/deps/g3dlite/include/G3D/AABox.h index d57320d73..7a47ea63a 100644 --- a/deps/g3dlite/include/G3D/AABox.h +++ b/deps/g3dlite/include/G3D/AABox.h @@ -1,29 +1,31 @@ /** - @file AABox.h + \file G3D/AABox.h Axis-aligned box class - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2004-01-10 - @edited 2009-02-10 + \created 2004-01-10 + \edited 2013-04-13 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2013, Morgan McGuire. All rights reserved. */ -#ifndef G3D_AABOX_H -#define G3D_AABOX_H +#ifndef G3D_AABox_h +#define G3D_AABox_h #include "G3D/platform.h" -#include "G3D/Vector3.h" #include "G3D/debug.h" #include "G3D/Array.h" #include "G3D/Plane.h" #include "G3D/Sphere.h" +#include "G3D/Vector3.h" namespace G3D { +class Any; + /** An axis-aligned box. */ @@ -34,66 +36,109 @@ private: /** Optional argument placeholder */ static int dummy; - Vector3 lo; - Vector3 hi; + /** NaN if empty */ + Point3 lo; + + /** NaN if empty */ + Point3 hi; public: - /** Does not initialize the fields */ - inline AABox() {} + /** Creates the empty bounds, i.e., an empty set of points. */ + AABox() : lo(fnan(), fnan(), fnan()), hi(fnan(), fnan(), fnan()) {} /** - Constructs a zero-area AABox at v. + Constructs a zero-volume AABox at v. */ - inline explicit AABox(const Vector3& v) { + explicit AABox(const Point3& v) { lo = hi = v; } + /** Format is one of: + - AABox(lowpoint, highpoint) + - AABox(point) + - AABox::empty() + - AABox::inf() + */ + explicit AABox(const class Any& a); + + Any toAny() const; + + bool isEmpty() const { + return lo.isNaN(); + } + /** Assumes that low is less than or equal to high along each dimension. To have this automatically enforced, use AABox(low.min(high), low.max(high)); */ - inline AABox(const Vector3& low, const Vector3& high) { + AABox(const Point3& low, const Point3& high) { set(low, high); } + AABox operator*(float f) const { + if (f < 0) { + return AABox(hi * f, lo * f); + } else { + return AABox(lo * f, hi * f); + } + } + + AABox operator/(float f) const { + return *this * (1.0f / f); + } + /** Assumes that low is less than or equal to high along each dimension. */ - inline void set(const Vector3& low, const Vector3& high) { + inline void set(const Point3& low, const Point3& high) { debugAssert( (low.x <= high.x) && (low.y <= high.y) && (low.z <= high.z)); + debugAssert(! low.isNaN() && ! high.isNaN()); lo = low; hi = high; } /** - Grows to include the bounds of a + Grows to include the bounds of \a a */ inline void merge(const AABox& a) { - lo = lo.min(a.lo); - hi = hi.max(a.hi); + if (isEmpty()) { + lo = a.lo; + hi = a.hi; + } else if (! a.isEmpty()) { + lo = lo.min(a.lo); + hi = hi.max(a.hi); + } } - inline void merge(const Vector3& a) { - lo = lo.min(a); - hi = hi.max(a); + inline void merge(const Point3& a) { + if (isEmpty()) { + lo = hi = a; + } else { + lo = lo.min(a); + hi = hi.max(a); + } } + void merge(const class Box& b); + void serialize(class BinaryOutput& b) const; void deserialize(class BinaryInput& b); inline bool isFinite() const { - return lo.isFinite() && hi.isFinite(); + return isEmpty() || (lo.isFinite() && hi.isFinite()); } - inline const Vector3& low() const { + /** Returns not-a-number if empty */ + inline const Point3& low() const { return lo; } - inline const Vector3& high() const { + /** Returns not-a-number if empty */ + inline const Point3& high() const { return hi; } @@ -110,25 +155,33 @@ public: static const AABox& zero(); + static const AABox& empty(); + /** - Returns the centroid of the box. + Returns the centroid of the box (NaN if empty) */ - inline Vector3 center() const { + inline Point3 center() const { return (lo + hi) * 0.5; } - Vector3 corner(int index) const; + Point3 corner(int index) const; /** Distance from corner(0) to the next corner along axis a. */ inline float extent(int a) const { + if (isEmpty()) { + return 0.0f; + } debugAssert(a < 3); return hi[a] - lo[a]; } inline Vector3 extent() const { + if (isEmpty()) { + return Vector3::zero(); + } return hi - lo; } @@ -140,46 +193,46 @@ public: */ void split(const Vector3::Axis& axis, float location, AABox& low, AABox& high) const; - /** - Conservative culling test for up to 32 planes. - Returns true if there exists a plane[p] for + /** + Conservative culling test for up to 32 planes. + Returns true if there exists a plane[p] for which the entire object is in the negative half space (opposite the plane normal). - testMask and childMask - are used for optimizing bounding volume hierarchies. + testMask and childMask + are used for optimizing bounding volume hierarchies. The version of this method that produces childMask is slower than the version without; it should only be used for parent nodes. - @param cullingPlaneIndex The index of the first plane for which - the entire object is in the negative half-space. The function - exits early when one plane is found. -1 when the function - returns false (i.e. when no plane culls the whole object). + @param cullingPlaneIndex The index of the first plane for which + the entire object is in the negative half-space. The function + exits early when one plane is found. -1 when the function + returns false (i.e. when no plane culls the whole object). - @param testMask If bit p is 0, the - bounding volume automatically passes the culling test for - plane[p] (i.e. it is known that the volume - is entirely within the positive half space). The function + @param testMask If bit p is 0, the + bounding volume automatically passes the culling test for + plane[p] (i.e. it is known that the volume + is entirely within the positive half space). The function must return false if testMask is 0 and test all planes when testMask is -1 (0xFFFFFFFF). @param childMask Test mask for the children of this volume. - */ - bool culledBy( - const Array& plane, - int32& cullingPlaneIndex, - const uint32 testMask, - uint32& childMask) const; + */ + bool culledBy + (const Array& plane, + int32& cullingPlaneIndex, + const uint32 testMask, + uint32& childMask) const; /** Conservative culling test that does not produce a mask for children. */ - bool culledBy( - const Array& plane, - int32& cullingPlaneIndex = dummy, - const uint32 testMask = 0xFFFFFFFF) const; + bool culledBy + (const Array& plane, + int32& cullingPlaneIndex = dummy, + const uint32 testMask = 0xFFFFFFFF) const; /** less than or equal to containment */ inline bool contains(const AABox& other) const { @@ -192,8 +245,7 @@ public: (other.lo.z >= lo.z); } - inline bool contains( - const Vector3& point) const { + inline bool contains(const Point3& point) const { return (point.x >= lo.x) && (point.y >= lo.y) && @@ -204,31 +256,42 @@ public: } inline float area() const { + if (isEmpty()) { return 0; } Vector3 diag = hi - lo; return 2.0f * (diag.x * diag.y + diag.y * diag.z + diag.x * diag.z); } inline float volume() const { + if (isEmpty()) { return 0; } Vector3 diag = hi - lo; return diag.x * diag.y * diag.z; } - Vector3 randomInteriorPoint() const; + Point3 randomInteriorPoint() const; - Vector3 randomSurfacePoint() const; + Point3 randomSurfacePoint() const; /** Returns true if there is any overlap */ bool intersects(const AABox& other) const; /** Returns true if there is any overlap. @cite Jim Arvo's algorithm from Graphics Gems II*/ - bool intersects(const class Sphere& other) const; + bool intersects(const Sphere& other) const; /** Return the intersection of the two boxes */ AABox intersect(const AABox& other) const { - Vector3 H = hi.min(other.hi); - Vector3 L = lo.max(other.lo).min(H); - return AABox(L, H); + if (isEmpty() || other.isEmpty()) { + return empty(); + } + + const Point3& H = hi.min(other.hi); + const Point3& L = lo.max(other.lo).min(H); + + if (H.x < L.x && H.y < L.y && H.z < L.z) { + return empty(); + } else { + return AABox(L, H); + } } inline size_t hashCode() const { @@ -236,11 +299,19 @@ public: } inline bool operator==(const AABox& b) const { - return (lo == b.lo) && (hi == b.hi); + if (isEmpty() && b.isEmpty()) { + return true; + } else { + return (lo == b.lo) && (hi == b.hi); + } } inline bool operator!=(const AABox& b) const { - return !((lo == b.lo) && (hi == b.hi)); + if (isEmpty()) { + return b.isEmpty(); + } else { + return !((lo == b.lo) && (hi == b.hi)); + } } inline AABox operator+(const Vector3& v) const { diff --git a/deps/g3dlite/include/G3D/Any.h b/deps/g3dlite/include/G3D/Any.h index e2d0fbe7e..25af58d1e 100644 --- a/deps/g3dlite/include/G3D/Any.h +++ b/deps/g3dlite/include/G3D/Any.h @@ -1,13 +1,13 @@ /** - @file Any.h + \file Any.h - @author Morgan McGuire, Shawn Yarbrough, and Corey Taylor - @maintainer Morgan McGuire + \author Morgan McGuire, Shawn Yarbrough, and Corey Taylor + \maintainer Morgan McGuire - @created 2006-06-11 - @edited 2010-03-16 + \created 2006-06-11 + \edited 2013-03-29 - Copyright 2000-2010, Morgan McGuire. + Copyright 2000-2013, Morgan McGuire. All rights reserved. */ @@ -17,13 +17,13 @@ #include "G3D/platform.h" #include "G3D/Table.h" #include "G3D/Array.h" -#include "G3D/Set.h" #include "G3D/AtomicInt32.h" #include "G3D/stringutils.h" #include // needed for Token #include "G3D/TextInput.h" +#include "G3D/TextOutput.h" #ifdef verify #undef verify @@ -38,7 +38,8 @@ class TextOutput; Any encodes typed, structured data and can serialize it to a human readable format that is very similar to the Python language's data -syntax. It is well-suited for quickly creating human-readable file +syntax, and fully supports Python's data syntax as well. +It is well-suited for quickly creating human-readable file formats, especially since deserialization and serialization preserve comments and an Any can tell you what file and line it came from. The syntax allows most C++ editors to properly highlight Any files, and @@ -61,7 +62,7 @@ Sample File: position = Vector3(1.0, -1.0, 0.0), video = { format = "RGB8", size = (320, 200)}, - material = #include("rocks.mat") + material = \#include("rocks.mat") } @@ -79,7 +80,8 @@ The custom serialization format was chosen to be terse, easy for humans to read, and easy for machines to parse. It was specifically chosen over formats like XML, YAML, JSON, S-expressions, and Protocol Buffers, although there is no reason you could not write readers and -writers for G3D::Any that support those. +writers for G3D::Any that support those. Any also currently supports +the JSON format. G3D::Any assumes that structures do not contain cycles; it is an error to create a structure like: @@ -91,6 +93,17 @@ x.array().append(x); // don't do this! although no exception will be thrown at runtime during that append. +\section includes + +When parsing an Any from a file, the syntax +\#include(filename) allows subsitution of the contents of +filename for any single expression in an Any. The filename is interpreted +relative to the file being parsed, and inside of the included file, relative filenames +are interpreted with respect to the included file (and so on, recursively for nested +inclusion). + +Filenames are resolved with System::resolve and then System::findDataFile if not found, +so they may contain environment variables. \section Parsing @@ -117,24 +130,12 @@ Vector3::Vector3(const Any& any) { } -It is often convenient to iterate through the table portion: - -
-    for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
-        const std::string& k = toLower(it->key);
-        if (key == "hello") {
-           ...
-        } else if (key == "goodbye") {
-           ...
-        } else {
-           any.verify(false, "Unsupported key: " + it->key);
-        }
-    }
-
+It is often convenient to iterate through the table portion using G3D::AnyTableReader. \section BNF Serialized format BNF: +\htmlonly
 identifier  ::= (letter | "_") (letter | digit | "_")*
 identifier-op ::= "::" | "->" | "."
@@ -145,18 +146,19 @@ comment     ::= C++ single or multi-line comments
 separator   ::= "," | ";"
 
 number      ::= 
-string      ::= 
+string      ::= 
 boolean     ::= "True" | "False"
-none        ::= "None"
-array       ::= ("(" | "[") [ value (separator value)* [separator] ] (")" | "]")
-pair        ::= (identifier | string) "=" value
-table       ::= "{" [ pair (separator pair)* [separator] ] "}"
+nil         ::= "Nil"  | "None" 
+array       ::= ("(" | "[" | "{") [value (separator value)* [separator] ] (")" | "]" | "}")
+pair        ::= (identifier | string) ("=" | ":") value
+table       ::= ("(" | "[" | "{") [ pair (separator pair)* [separator] ] (")" | "]" | "}")
 named-array ::= identifier-exp array
 named-table ::= identifier-exp table
 include     ::= "#" "include" "(" string ")"
 
-value       ::= [comment] (none | number | boolean | string | array | table | named-array | named-table | include)
+value       ::= [comment] (nil | number | boolean | string | array | table | named-array | named-table | include)
 
+\endhtmlonly Except for single-line comments, whitespace is not significant. All parsing is case-insensitive. @@ -167,7 +169,7 @@ can only appear in the locations where a value is expected. This means that it cannot yield more than one element of an array and cannot serve as the pair in a table. -The deserializer allows the substitution of [] for () when writing +The deserializer allows the substitution of [] or {} for () when writing tuples and ";" for ",". These are convenient when mimicing a programming language, e.g., "[ printf("hello world."); clearScreen();]" parses as an array containing two named arrays within it. The @@ -176,11 +178,13 @@ which also convenient when commenting out the last element. The serializer indents four spaces for each level of nesting. Tables are written with the keys in alphabetic order. + +\sa G3D::AnyTableReader */ class Any { public: - enum Type {NONE, BOOLEAN, NUMBER, STRING, ARRAY, TABLE}; + enum Type {NIL, BOOLEAN, NUMBER, STRING, ARRAY, TABLE, EMPTY_CONTAINER}; static std::string toString(Type t); @@ -208,7 +212,7 @@ private: /** Called from deserialize() */ static void deserializeComment(TextInput& ti, Token& token, std::string& comment); - /** NONE, BOOLEAN, and NUMBER are stored directly in the Any */ + /** NIL, BOOLEAN, and NUMBER are stored directly in the Any */ union SimpleValue { bool b; double n; @@ -218,6 +222,11 @@ private: inline SimpleValue(double x) : n(x) {} }; + /** The three options for Data::bracket */ + static const char* PAREN; + static const char* BRACKET; + static const char* BRACE; + class Data { public: /** ARRAY, TABLE, or STRING value only. NULL otherwise. */ @@ -240,6 +249,16 @@ private: std::string name; + /** If this Any was created by parsing an #include expression and + has not been modified since, this is the original comment and + include statement, as + it originally appeared in the file (e.g., it may contain a relative + filename). If this is non-empty, then when serialized, this + Any will turn into an #include expression instead of unparsing + its contents of the any. + */ + std::string includeLine; + /** For STRING, ARRAY and TABLE types, m_value is shared between multiple instances. Mutation is allowed only if the reference count is exactly 1, otherwise the mutating instance must copy @@ -249,10 +268,16 @@ private: Source source; + /** Two-character string of "{}", "[]", or "()"; to be used when unparsing. */ + const char* bracket; + + /** ';' or ',' separator to be used when unparsing */ + char separator; + private: /** Called by create() */ - inline Data(Type t) : type(t), referenceCount(1) {} + inline Data(Type t, const char* b, char s) : type(t), referenceCount(1), bracket(b), separator(s) {} /** Called by destroy */ ~Data(); @@ -261,12 +286,11 @@ private: /** Clones the argument */ static Data* create(const Data* d); - static Data* create(Type t); + static Data* create(Type t, const char* b = NULL, char s = '\0'); /** Free d, invoking its destructor and freeing the memory for the value. */ static void destroy(Data* d); - }; /** If not empty, this Any was created from operator[] on a table @@ -283,12 +307,11 @@ private: SimpleValue m_simpleValue; mutable Data* m_data; - /** Called before every read operation to ensure that this object - is not a placeholder. */ + /** Called before every read operation. */ void beforeRead() const; - /** Called before every write operation to wipe the placeholder - status. */ + /** Called before every write operation to this Any. Wipes the placeholder + status and includedFrom entry. */ void beforeWrite(); /** Decrements the reference count (if there is one). If the @@ -316,43 +339,61 @@ private: /** Read the name of a named Array or Table. */ static void deserializeName(TextInput& ti, Token& token, std::string& name); - /** Read until a comma is consumed or a close paren is hit, and + /** Read until a separator is consumed or a close paren is hit, and return that token. Considers the passed in token to be the first value read. */ - static void readUntilCommaOrClose(TextInput& ti, Token& token); + static void readUntilSeparatorOrClose(TextInput& ti, Token& token); /** Construct an Any that is a proxy for a table fetch from \a data. This proxy can be copied exactly once on return from operator[].*/ Any(const std::string& key, Data* data); - inline bool isPlaceholder() const { + bool isPlaceholder() const { return ! m_placeholderName.empty(); } + + void _append(const Any& v0); + void _append(const Any& v0, const Any& v1); + void _append(const Any& v0, const Any& v1, const Any& v2); + void _append(const Any& v0, const Any& v1, const Any& v2, const Any& v3); + Any _get(const std::string& key, const Any& defaultVal) const; + void _set(const std::string& key, const Any& val); + + void _parse(const std::string& src); public: - /** Base class for all Any exceptions.*/ - class Exception { - public: - virtual ~Exception() {} - }; - /** Thrown by operator[] when a key is not present in a const table. */ class KeyNotFound : public ParseError { public: std::string key; + + KeyNotFound(const Data* data) { + if (data) { + filename = data->source.filename; + line = data->source.line; + character = data->source.character; + } + } }; /** Thrown by operator[] when an array index is not present. */ - class IndexOutOfBounds : public Exception { + class IndexOutOfBounds : public ParseError { public: int index; int size; - inline IndexOutOfBounds() : index(0), size(0) {} - inline IndexOutOfBounds(int i, int s) : index(i), size(s) {} + IndexOutOfBounds() : index(0), size(0) {} + IndexOutOfBounds(const Data* data, int i, int s) : index(i), size(s) { + if (data) { + filename = data->source.filename; + line = data->source.line; + character = data->source.character; + } + message = format("Index out of bounds: index = %d, array size = %d", i, s); + } }; - /** NONE constructor */ + /** NIL constructor */ Any(); /** Deserialize */ @@ -361,108 +402,133 @@ public: Any(const Any& x); /** NUMBER constructor */ - Any(double x); + explicit Any(double x); -#ifdef G3D_32BIT - /** NUMBER constructor */ - Any(int64 x); -#endif // G3D_32BIT + explicit Any(float x); -#if 0 + #if defined(G3D_32Bit) || defined(_MSC_VER) /** NUMBER constructor */ - Any(int32 x); -#endif // 0 + explicit Any(int64 x) : m_type(NUMBER), m_simpleValue((double)x), m_data(NULL) {} + #endif /** NUMBER constructor */ - Any(long x); + explicit Any(long x); /** NUMBER constructor */ - Any(int x); + explicit Any(int x); /** NUMBER constructor */ - Any(short x); + explicit Any(char x); + + /** NUMBER constructor */ + explicit Any(short x); /** BOOLEAN constructor */ - Any(bool x); + explicit Any(bool x); /** STRING constructor */ - Any(const std::string& x); + explicit Any(const std::string& x); /** STRING constructor */ - Any(const char* x); + explicit Any(const char* x); + + /** \a t must be ARRAY or TABLE + \param brackets must be "" (defaults to {} for table, () for array), "[]", "()", or "{}" + \param separator must be ';', ',', or '\0' (defaults to ',' for array and ';' for table) + */ + explicit Any(Type t, const std::string& name = "", const std::string& brackets = "", const char separator = '\0'); + + /** Extensible constructor: call the toAny() method of any class. */ + template + explicit Any(const T& v) : m_type(NIL), m_data(NULL) { + *this = v.toAny(); + } - /** \a t must be ARRAY or TABLE */ - Any(Type t, const std::string& name = ""); - ~Any(); /** Removes the comment and name */ Any& operator=(const Any& x); - /** Removes the comment and name */ - Any& operator=(double x); - - /** Removes the comment and name */ - Any& operator=(int x); - - /** Removes the comment and name */ - Any& operator=(bool x); - - /** Removes the comment and name */ - Any& operator=(const std::string& x); - - /** Removes the comment and name */ - Any& operator=(const char* x); - - /** \a t must be ARRAY, TABLE, or NONE. Removes the comment and name */ + /** \a t must be ARRAY, TABLE, or NIL. Removes the comment and name */ Any& operator=(Type t); + /** Assigns from an array. Assumes that T can be converted to Any. Removes the comment and name */ + template + Any& operator=(const Array& array) { + *this = Any::ARRAY; + resize(array.size()); + for (int i = 0; i < array.size(); ++i) { + this->operator [](i) = array[i]; + } + return *this; + } + + /** Removes the comment and name */ + template + Any& operator=(const T& v) { + *this = Any(v); + return *this; + } + Type type() const; /** Same as deserialize or load, but operates on a string instead of a stream or file. - \sa deserialize, load + \sa deserialize, load, unparse */ - void parse(const std::string& src); + static Any parse(const std::string& src); - std::string unparse() const; + std::string unparse(const TextOutput::Settings& s = TextOutput::Settings()) const; + + /** \param allowCoercion If false, throws an error if the Any uses features that are not + supported by JSON such as named arrays. Otherwise, silently coerces to JSON. */ + std::string unparseJSON(const TextOutput::Settings& s = TextOutput::Settings(), bool allowCoercion = true) const; /** Comments appear before values when they are in serialized form.*/ const std::string& comment() const; void setComment(const std::string& c); - /** True if this is the NONE value */ - bool isNone() const; + /** True if this is the NIL value */ + bool isNil() const; /** Throws a ParseError exception if this is not a number */ double number() const; + float floatValue() const; + const std::string& string() const; bool boolean() const; - /** If a valid string, takes the string value and creates a fully qualified filename. - If not found, the returned string is empty. + /** If a valid string, takes the string value and creates a fully + qualified filename. The file is searched for the following ways: - In the directory from which the Any was loaded. - By calling System::findDataFile as you would with other data files. + + Strings that begin with '<' and end with '>' are treated as + escape sequences and are returned unmodifed. */ - std::string resolveStringAsFilename() const; + std::string resolveStringAsFilename(bool errorIfNotFound = true) const; /** If this is named ARRAY or TABLE, returns the name. */ const std::string& name() const; - /** If this is named ARRAY or TABLE, returns true if the name begins with \a s. The comparision is case insensitive. */ + /** If this is named ARRAY or TABLE, returns true if the name + begins with \a s. The comparision is case insensitive. */ bool nameBeginsWith(const std::string& s) const; - /** If this is named ARRAY or TABLE, returns true if the name begins with \a s. The comparision is case insensitive. */ + /** If this is named ARRAY or TABLE, returns true if the name + begins with \a s. The comparision is case insensitive. */ bool nameBeginsWith(const char* s) const; - /** If this is named ARRAY or TABLE, returns true if the name is \a s. The comparision is case insensitive. */ + /** If this is named ARRAY or TABLE, returns true if the name is + \a s. The comparision is case insensitive. */ bool nameEquals(const std::string& s) const; - /** If this is named ARRAY or TABLE, returns true if the name is\a s. The comparision is case insensitive. */ + /** If this is named ARRAY or TABLE, returns true if the name is\a + s. The comparision is case insensitive. */ bool nameEquals(const char* s) const; /** \brief Set the name used when serializing an ARRAY or TABLE. @@ -504,12 +570,29 @@ public: /** Directly exposes the underlying data structure for an ARRAY. */ const Array& array() const; - void append(const Any& v0); - void append(const Any& v0, const Any& v1); - void append(const Any& v0, const Any& v1, const Any& v2); - void append(const Any& v0, const Any& v1, const Any& v2, const Any& v3); - /** Directly exposes the underlying data structure for table.*/ + template + void append(const T0& v0) { + _append(Any(v0)); + } + + template + void append(const T0& v0, const T1& v1) { + _append(Any(v0), Any(v1)); + } + + template + void append(const T0& v0, const T1& v1, const T2& v2) { + _append(Any(v0), Any(v1), Any(v2)); + } + + template + void append(const T0& v0, const T1& v1, const T2& v2, const T3& v3) { + _append(Any(v0), Any(v1), Any(v2), Any(v3)); + } + + /** Directly exposes the underlying data structure for table. + \sa G3D::AnyTableReader*/ const Table& table() const; /** For a table, returns the element for \a key. Throws KeyNotFound @@ -549,19 +632,25 @@ public: Any& operator[](const std::string& key); /** \copydoc Any::operator[](const std::string&) */ - Any& operator[](const char* key) { + inline Any& operator[](const char* key) { return operator[](std::string(key)); } /** For a table, returns the element for key \a x and \a defaultVal if it does not exist. */ - const Any& get(const std::string& key, const Any& defaultVal) const; + template + Any get(const std::string& key, const T& defaultVal) const { + return _get(key, Any(defaultVal)); + } /** Returns true if this key is in the TABLE. Illegal to call on an object that is not a TABLE. */ bool containsKey(const std::string& key) const; /** For a table, assigns the element for key k. */ - void set(const std::string& key, const Any& val); + template + void set(const std::string& key, const T& val) { + _set(key, Any(val)); + } /** for an ARRAY, resizes and returns the last element */ Any& next(); @@ -573,14 +662,64 @@ public: /** True if the Anys are exactly equal, ignoring comments. Applies deeply on arrays and tables. */ bool operator==(const Any& x) const; + + bool operator==(const std::string& s) const { + return *this == Any(s); + } + + bool operator==(const double& v) const { + return *this == Any(v); + } + + bool operator==(int v) const { + return *this == Any(v); + } + + bool operator==(bool v) const { + return *this == Any(v); + } + bool operator!=(const Any& x) const; + bool operator!=(const std::string& s) const { + return *this != Any(s); + } + + bool operator!=(const double& v) const { + return *this != Any(v); + } + + bool operator!=(int v) const { + return *this != Any(v); + } + + bool operator!=(bool v) const { + return *this != Any(v); + } + operator int() const; + operator uint32() const; operator float() const; operator double() const; operator bool() const; operator std::string() const; + operator char() const { + return char(int(*this)); + } + + operator uint8() const { + return uint8(int(*this)); + } + + operator int16() const { + return int16(int(*this)); + } + + operator uint16() const { + return uint16(int(*this)); + } + /** Resize to \a n elements, where new elements are NIL It is an error to call this method if this is not an Any::ARRAY */ void resize(int n); @@ -591,33 +730,88 @@ public: void clear(); /** Parse from a file. - \sa deserialize, parse */ + \sa deserialize, parse, fromFile, loadIfExists + */ void load(const std::string& filename); + /** Load a new Any from \a filename. \sa load, save, loadIfExists */ + static Any fromFile(const std::string& filename); + + /** Load \a filename file if it exists, otherwise do not modify this */ + void loadIfExists(const std::string& filename); + /** Uses the serialize method. */ void save(const std::string& filename) const; - void serialize(TextOutput& to) const; + void serialize(TextOutput& to, bool json = false, bool coerce = false) const; + + void serialize(class BinaryOutput& b) const; + /** Parse from a stream. \sa load, parse */ void deserialize(TextInput& ti); + void deserialize(class BinaryInput& b); + const Source& source() const; + /** Removes this key from the Any, which must be a table. */ + void remove(const std::string& key); + + /** Removes this key from the Any, which must be an array, and + shifts other elements down to maintain order. */ + void remove(int index); + /** Throws a ParseError if \a value is false. Useful for quickly creating parse rules in classes that deserialize from Any. */ void verify(bool value, const std::string& message = "") const; - /** Verifies that the name begins with identifier \a n (case insensitive). + /** Verifies that the name is identifier \a n (case sensitive). It may contain identifier operators after this */ void verifyName(const std::string& n) const; - /** Verifies that the name begins with identifier \a n or \a m (case insensitive). + /** Verifies that the name is identifier \a n or \a m (case sensitive). It may contain identifier operators after this */ void verifyName(const std::string& n, const std::string& m) const; + /** Verifies that the name is identifier \a n or \a m or \a p (case sensitive). + It may contain identifier operators after this */ + void verifyName(const std::string& n, const std::string& m, const std::string& p) const; + + /** Verifies that the name is identifier \a n or \a m or \a p or \a q (case sensitive). + It may contain identifier operators after this */ + void verifyName(const std::string& n, const std::string& m, const std::string& p, const std::string& q) const; + + /** Verifies that the name begins with identifier \a n (case sensitive). + It may contain identifier operators after this */ + void verifyNameBeginsWith(const std::string& n) const; + + /** Verifies that the name begins with identifier \a n or \a m (case sensitive). + It may contain identifier operators after this */ + void verifyNameBeginsWith(const std::string& n, const std::string& m) const; + + /** Verifies that the name begins with identifier \a n or \a m or \a p (case sensitive). + It may contain identifier operators after this */ + void verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p) const; + + /** Verifies that the name begins with identifier \a n or \a m or \a p or \a q (case sensitive). + It may contain identifier operators after this */ + void verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q) const; + + /** Verifies that the name begins with identifier \a n or \a m or \a p or \a q or \a r (case sensitive). + It may contain identifier operators after this */ + void verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q, const std::string& r) const; + + /** Verifies that the name begins with identifier \a n or \a m or \a p or \a q or \a r or \a s (case sensitive). + It may contain identifier operators after this */ + void verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q, const std::string& r, const std::string& s) const; + + /** Verifies that the name begins with identifier \a n or \a m or \a p or \a q or \a r or \a s or \a t(case sensitive). + It may contain identifier operators after this */ + void verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q, const std::string& r, const std::string& s, const std::string& t) const; + /** Verifies that the type is \a t. */ void verifyType(Type t) const; @@ -630,14 +824,49 @@ public: /** Verifies that the size is exactly \a s */ void verifySize(int s) const; + /** Assumes that Any(T) is well-defined, e.g., by T defining a + T::toAny() method. */ + template + explicit Any(const Array& array, const std::string& name = "") : m_type(ARRAY), m_data(NULL) { + setName(name); + resize(array.size()); + for (int i = 0; i < array.size(); ++i) { + (*this)[i] = Any(array[i]); + } + } + + /** Assumes that T defines T(const Any&) */ + template + void getArray(Array& array) const { + verifyType(ARRAY); + array.resize(size()); + for (int i = 0; i < array.size(); ++i) { + array[i] = T((*this)[i]); + } + } + + /** Assumes that T defines T(const Any&) */ + template + void getTable(Table& table) const { + verifyType(TABLE); + for (Table::Iterator it = this->table().begin(); it.isValid(); ++it) { + table.set(it.key(), T(it.value())); + } + } + private: void deserializeTable(TextInput& ti); void deserializeArray(TextInput& ti,const std::string& term); + /** Turns an empty container into a table or an array */ + void become(const Type& t); + }; // class Any + + /** Convenient iteration over the keys of a Any::TABLE, usually for implementing construction of an object from an Any. @@ -647,14 +876,14 @@ private: It is an error to consume the same element more than once from the same iterator. -
-    AnyKeyIterator r(a);
-    r.getIfPresent("enabled",            enabled);
-    r.getIfPresent("showSamples",        showSamples);
-    r.getIfPresent("showTiles",          showTiles);
+    \code
+    AnyTableReader r(a);
+    r.getIfPresent("enabled", enabled);
+    r.getIfPresent("showSamples", showSamples);
+    r.get("showTiles", showTiles);
 
     r.verifyDone();
-    
+ \endcode \beta */ @@ -665,44 +894,21 @@ private: public: /** Verifies that \a is a TABLE with the given \a name. */ - AnyTableReader(const std::string& name, const Any& a) : m_any(a) { - try { - m_any.verifyType(Any::TABLE); - m_any.verifyName(name); - } catch (const ParseError& e) { - // If an exception is thrown, the destructors will not be - // invoked automatically. - m_any.~Any(); - m_alreadyRead.~Set(); - throw e; - } - } + AnyTableReader(const std::string& name, const Any& a); /** Verifies that \a is a TABLE. */ - AnyTableReader(const Any& a) : m_any(a) { - try { - m_any.verifyType(Any::TABLE); - } catch (const ParseError& e) { - // If an exception is thrown, the destructors will not be - // invoked automatically. - m_any.~Any(); - m_alreadyRead.~Set(); - throw e; - } - } + AnyTableReader(const Any& a); bool hasMore() const { return m_any.size() > m_alreadyRead.size(); } /** Verifies that all keys have been read. */ - void verifyDone() const { - if (hasMore()) { - // Generate all keys - // Remove the ones we've read - // Assert the rest - // any.verify(""); - } + void verifyDone() const; + + /** Return the underlying Any. */ + const Any& any() const { + return m_any; } #if 0 @@ -714,30 +920,67 @@ public: AnyKeyIterator& operator++(); #endif + + /** \copydoc get(const std::string& s, ValueType& v) */ + void get(const std::string& s, std::string& v) { + v = m_any[s].string(); + m_alreadyRead.insert(s); + } + + /** \copydoc get(const std::string& s, ValueType& v) */ + void get(const std::string& s, uint8& v) { + v = uint8(m_any[s].number()); + m_alreadyRead.insert(s); + } + + /** \copydoc get(const std::string& s, ValueType& v) */ + void get(const std::string& s, uint16& v) { + v = uint16(m_any[s].number()); + m_alreadyRead.insert(s); + } + + /** Read an entire array at once.*/ + template + void get(const std::string& s, Array& v) { + m_any[s].getArray(v); + m_alreadyRead.insert(s); + } - /** If key \s appears in the any, reads its value into \a v and + template + void get(const std::string& s, Table& v) { + m_any[s].getTable(v); + m_alreadyRead.insert(s); + } + + /** If key \a s appears in the any, reads its value into \a v and removes that key from the ones available to iterate over. - If key \s does not appear in the any, throws a G3D::ParseError. + If key \a s does not appear in the any, throws a G3D::ParseError. - Assumes that if key \s appears in the any it has not already been extracted + Assumes that if key \a s appears in the any it has not already been extracted by this iterator. If it has been read before, an assertion will fail in debug mode. */ template void get(const std::string& s, ValueType& v) { - v = m_any[s]; - m_alreadyRead.insert(toLower(s)); + v = ValueType(m_any[s]); + m_alreadyRead.insert(s); + } + + /** Same as get() */ + const Any& operator[](const std::string& s) { + m_alreadyRead.insert(s); + return m_any[s]; } /** Get the value associated with a key only if the key is actually present. - If key \s appears in the any, reads its value into \a v and + If key \a s appears in the any, reads its value into \a v and removes that key from the ones available to iterate over. - If key \s does not appear in the any, does nothing. + If key \a s does not appear in the any, does nothing. - Assumes that if key \s appears in the any it has not already been extracted + Assumes that if key \a s appears in the any it has not already been extracted by this iterator. If it has been read before, an assertion will fail in debug mode. \return True if the value was read. @@ -745,7 +988,7 @@ public: template bool getIfPresent(const std::string& s, ValueType& v) { if (m_any.containsKey(s)) { - debugAssertM(! m_alreadyRead.contains(toLower(s)), "read twice"); + debugAssertM(! m_alreadyRead.contains(s), "read twice"); get(s, v); return true; @@ -753,8 +996,29 @@ public: return false; } } + + /** \return True if \a s is in the table and has not yet been read + using get() or getIfPresent(). */ + bool containsUnread(const std::string& s) const { + return m_any.containsKey(s) && ! m_alreadyRead.contains(s); + } + }; } // namespace G3D + +/** + \def PARSE_ANY(expression) + + \brief Create an G3D::Any from an unquoted string. + + e.g., + \code + Any x = PARSE_ANY( { a = 3.0; b = false; } ); + \endcode + */ +#define PARSE_ANY(x) Any::parse(#x) + + #endif diff --git a/deps/g3dlite/include/G3D/AreaMemoryManager.h b/deps/g3dlite/include/G3D/AreaMemoryManager.h index d8d8f7103..5ff46505b 100644 --- a/deps/g3dlite/include/G3D/AreaMemoryManager.h +++ b/deps/g3dlite/include/G3D/AreaMemoryManager.h @@ -1,12 +1,12 @@ /** - @file AreaMemoryManager.h + \file AreaMemoryManager.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2009-01-20 - @edited 2009-05-29 + \created 2009-01-20 + \edited 2010-10-29 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ @@ -57,7 +57,7 @@ private: public: - typedef ReferenceCountedPointer Ref; + typedef shared_ptr Ref; /** \param sizeHint Total amount of memory expected to be allocated. diff --git a/deps/g3dlite/include/G3D/Array.h b/deps/g3dlite/include/G3D/Array.h index cc9e1d9dd..c86b20fd7 100644 --- a/deps/g3dlite/include/G3D/Array.h +++ b/deps/g3dlite/include/G3D/Array.h @@ -1,13 +1,13 @@ /** - @file Array.h + \file Array.h - @maintainer Morgan McGuire, graphics3d.com - @cite Portions written by Aaron Orenstein, a@orenstein.name + \maintainer Morgan McGuire, graphics3d.com + \cite Portions written by Aaron Orenstein, a@orenstein.name - @created 2001-03-11 - @edited 2009-05-29 + \created 2001-03-11 + \edited 2013-01-28 - Copyright 2000-2009, Morgan McGuire, http://graphics.cs.williams.edu + Copyright 2000-2012, Morgan McGuire, http://graphics.cs.williams.edu All rights reserved. */ @@ -16,8 +16,8 @@ #include "G3D/platform.h" #include "G3D/debug.h" -#include "G3D/System.h" #include "G3D/MemoryManager.h" +#include "G3D/System.h" #ifdef G3D_DEBUG // For formatting error messages # include "G3D/format.h" @@ -47,6 +47,8 @@ const int SORT_INCREASING = 1; /** Constant for Array::sort */ const int SORT_DECREASING = -1; + + /** \brief Dynamic 1D array tuned for performance. @@ -89,22 +91,26 @@ const int SORT_DECREASING = -1; \sa G3D::SmallArray */ -template +template class Array { + private: + /** Once the array has been allocated, it will never deallocate the underlying + array unless MIN_ELEMENTS is set to 0, MIN_BYTES is 0, and the array is empty. */ + static const size_t MIN_BYTES = 32; + /** 0...num-1 are initialized elements, num...numAllocated-1 are not */ T* data; - int num; - int numAllocated; + size_t num; + size_t numAllocated; MemoryManager::Ref m_memoryManager; /** \param n Number of elements */ - void init(int n, const MemoryManager::Ref& m) { + void init(size_t n, const MemoryManager::Ref& m) { m_memoryManager = m; - debugAssert(n >= 0); this->num = 0; this->numAllocated = 0; data = NULL; @@ -117,7 +123,7 @@ private: void _copy(const Array &other) { init(other.num, MemoryManager::create()); - for (int i = 0; i < num; i++) { + for (size_t i = 0; i < num; ++i) { data[i] = other.data[i]; } } @@ -142,7 +148,7 @@ private: and then copies at most oldNum elements from the old array to it. Destructors are called for oldNum elements of the old array. */ - void realloc(int oldNum) { + void realloc(size_t oldNum) { T* oldData = data; // The allocation is separate from the constructor invocation because we don't want @@ -154,7 +160,7 @@ private: alwaysAssertM(data, "Memory manager returned NULL: out of memory?"); // Call the copy constructors - {const int N = G3D::min(oldNum, numAllocated); + {const size_t N = G3D::min(oldNum, numAllocated); const T* end = data + N; T* oldPtr = oldData; for (T* ptr = data; ptr < end; ++ptr, ++oldPtr) { @@ -177,6 +183,27 @@ private: m_memoryManager->free(oldData); } +public: + /** + Assignment operator. Will be private in a future release because this is slow and can be invoked by accident by novice C++ programmers. + If you really want to copy an Array, use the explicit copy constructor. + */ + Array& operator=(const Array& other) { + resize(other.num); + for (int i = 0; i < (int)num; ++i) { + data[i] = other[i]; + } + return *this; + } + + Array& operator=(const std::vector& other) { + resize(other.size()); + for (size_t i = 0; i < num; ++i) { + data[i] = other[i]; + } + return *this; + } + public: /** @@ -211,7 +238,7 @@ public: return data; } /** - C++ STL style iterator method. Returns one after the last iterator + C++ STL style iterator method. Returns one after the last valid iterator element. */ ConstIterator end() const { @@ -224,15 +251,27 @@ public: /** The array returned is only valid until the next append() or resize call, or - the Array is deallocated. + the Array is deallocated. */ T* getCArray() { return data; } + /** Exchanges all data between the two arrays, which are required to have a common MemoryManager. + This is a convenient + way to avoid large array copies when handing off data without involving reference counting + or manual memory management. Beware that pointers or references into the arrays will + access memory in the other array after the swap. */ + static void swap(Array& a, Array& b) { + alwaysAssertM(a.memoryManager() == b.memoryManager(), "The arrays are required to have the same memory manager"); + std::swap(a.data, b.data); + std::swap(a.num, b.num); + std::swap(a.numAllocated, b.numAllocated); + } + /** The array returned is only valid until the next append() or resize call, or - the Array is deallocated. + the Array is deallocated. */ const T* getCArray() const { return data; @@ -241,12 +280,11 @@ public: /** Creates a zero length array (no heap allocation occurs until resize). */ Array() : num(0) { init(0, MemoryManager::create()); - debugAssert(num >= 0); } /** Creates an array containing v0. */ - Array(const T& v0) { + explicit Array(const T& v0) { init(1, MemoryManager::create()); (*this)[0] = v0; } @@ -287,11 +325,60 @@ public: /** - Copy constructor + Copy constructor. Copying arrays is slow...perhaps you want to pass a reference or a pointer instead? */ - Array(const Array& other) : num(0) { + //TODO: patch rest of the API to prevent returning Arrays by value, then make explicit + Array(const Array& other) : num(0) { _copy(other); - debugAssert(num >= 0); + } + + explicit Array(const std::vector& other) : num(0), data(NULL) { + *this = other; + } + + + /* Sets this to hold the same contents as other, with num = numAllocated (no unused allocated space) */ + void copyFrom(const Array& other) { + resize(0); + append(other); + } + + + /** Resizes this to match the size of \a other and then copies the data from other using memcpy. This is only safe for POD types */ + void copyPOD(const Array& other) { + static_assert(std::is_pod::value, "copyPOD called on non-POD type"); + if (numAllocated < other.num) { + m_memoryManager->free(data); + data = NULL; + if (other.data) { + data = (T*)m_memoryManager->alloc(sizeof(T) * other.num); + } + numAllocated = other.num; + } + + num = other.num; + if (other.data && (num > 0)) { + System::memcpy(data, other.data, sizeof(T) * num); + } + } + + /** Resizes this to just barely match the size of \a other + itself and then copies the data to the end of the array from other using memcpy. + This is only safe for POD types */ + void appendPOD(const Array& other) { + static_assert(std::is_pod::value, "appendPOD called on non-POD type"); + const size_t oldSize = num; + num += other.num; + if (numAllocated < num) { + alwaysAssertM(other.data, "non-zero array with no allocated space"); + T* old = data; + data = (T*)m_memoryManager->alloc(sizeof(T) * num); + System::memcpy(data, old, sizeof(T) * oldSize); + m_memoryManager->free(old); + numAllocated = num; + } + if (other.data) { + System::memcpy((data + oldSize), other.data, sizeof(T) * other.num); + } } /** @@ -303,14 +390,14 @@ public: */ ~Array() { // Invoke the destructors on the elements - for (int i = 0; i < num; i++) { + for (size_t i = 0; i < num; ++i) { (data + i)->~T(); } m_memoryManager->free(data); // Set to 0 in case this Array is global and gets referenced during app exit data = NULL; - num = 0; + num = 0; numAllocated = 0; } @@ -335,26 +422,6 @@ public: clear(false); } - /** - Assignment operator. - */ - Array& operator=(const Array& other) { - debugAssert(num >= 0); - resize(other.num); for (int i = 0; i < num; ++i) { - data[i] = other[i]; - } - debugAssert(num >= 0); - return *this; - } - - Array& operator=(const std::vector& other) { - resize((int)other.size()); - for (int i = 0; i < num; ++i) { - data[i] = other[i]; - } - return *this; - } - inline MemoryManager::Ref memoryManager() const { return m_memoryManager; } @@ -363,7 +430,7 @@ public: Number of elements in the array. */ inline int size() const { - return num; + return (int)num; } /** @@ -379,8 +446,7 @@ public: shrinks the array by one. */ void fastRemove(int index, bool shrinkIfNecessary = false) { - debugAssert(index >= 0); - debugAssert(index < num); + debugAssert(index < (int)num); data[index] = data[num - 1]; resize(size() - 1, shrinkIfNecessary); } @@ -393,32 +459,52 @@ public: // Add space for the extra element resize(num + 1, false); - for (int i = num - 1; i > n; --i) { + for (size_t i = (size_t)(num - 1); i > (size_t)n; --i) { data[i] = data[i - 1]; } data[n] = value; } + /** Sets all elements currently in the array to \param value */ + void setAll(const T& value) { + for (size_t i = 0; i < num; ++i) { + data[i] = value; + } + } + + /** Resize this array to consume exactly the capacity required by its size. + \sa clear, resize, capacity, size + */ + void trimToSize() { + if (size() != capacity()) { + size_t oldNum = numAllocated; + numAllocated = size(); + realloc(oldNum); + } + } + /** @param shrinkIfNecessary if false, memory will never be reallocated when the array shrinks. This makes resizing much - faster but can waste memory. + faster but can waste memory. Default = true. + + \sa clear, trimToSize */ - void resize(int n, bool shrinkIfNecessary = true) { - debugAssert(n >= 0); + void resize(size_t n, bool shrinkIfNecessary = true) { + alwaysAssertM(n < 0xFFFFFFFF, "This implementation does not support arrays with more than 2^32 elements, although the size in memory may be larger."); if (num == n) { return; } - int oldNum = num; + size_t oldNum = num; num = n; // Call the destructors on newly hidden elements if there are any - for (int i = num; i < oldNum; ++i) { + for (size_t i = num; i < oldNum; ++i) { (data + i)->~T(); } // Once allocated, always maintain MIN_ELEMENTS elements or 32 bytes, whichever is higher. - const int minSize = std::max(MIN_ELEMENTS, (int)(MIN_BYTES / sizeof(T))); + const size_t minSize = G3D::max(MIN_ELEMENTS, (size_t)(MIN_BYTES / sizeof(T))); if ((MIN_ELEMENTS == 0) && (MIN_BYTES == 0) && (n == 0) && shrinkIfNecessary) { // Deallocate the array completely @@ -450,18 +536,21 @@ public: // // These numbers are tweaked according to performance tests. - float growFactor = 3.0; + double growFactor = 3.0f; - int oldSizeBytes = numAllocated * sizeof(T); - if (oldSizeBytes > 400000) { - // Avoid bloat - growFactor = 1.5; + size_t oldSizeBytes = numAllocated * sizeof(T); + if (oldSizeBytes > 10000000) { + // Conserve memory more tightly above 10 MB + growFactor = 1.2f; + } else if (oldSizeBytes > 400000) { + // Avoid bloat above 400k + growFactor = 1.5f; } else if (oldSizeBytes > 64000) { // This is what std:: uses at all times - growFactor = 2.0; + growFactor = 2.0f; } - numAllocated = (num - numAllocated) + (int)(numAllocated * growFactor); + numAllocated = (num - numAllocated) + (size_t)(numAllocated * growFactor); if (numAllocated < minSize) { numAllocated = minSize; @@ -476,14 +565,14 @@ public: // Only copy over old elements that still remain after resizing // (destructors were called for others if we're shrinking) - realloc(iMin(num, oldNum)); + realloc(min(num, oldNum)); } // Call the constructors on newly revealed elements. // Do not use parens because we don't want the intializer // invoked for POD types. - for (int i = oldNum; i < num; ++i) { + for (size_t i = oldNum; i < num; ++i) { new (data + i) T; } } @@ -583,6 +672,62 @@ public: } } + void append(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) { + if (inArray(&v1) || inArray(&v2) || inArray(&v3) || inArray(&v4) || inArray(&v5)) { + T t1 = v1; + T t2 = v2; + T t3 = v3; + T t4 = v4; + T t5 = v5; + append(t1, t2, t3, t4, t5); + } else if (num + 4 < numAllocated) { + // This is a simple situation; just stick it in the next free slot using + // the copy constructor. + new (data + num) T(v1); + new (data + num + 1) T(v2); + new (data + num + 2) T(v3); + new (data + num + 3) T(v4); + new (data + num + 4) T(v5); + num += 5; + } else { + resize(num + 5, DONT_SHRINK_UNDERLYING_ARRAY); + data[num - 5] = v1; + data[num - 4] = v2; + data[num - 3] = v3; + data[num - 2] = v4; + data[num - 1] = v5; + } + } + + void append(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6) { + if (inArray(&v1) || inArray(&v2) || inArray(&v3) || inArray(&v4) || inArray(&v5) || inArray(&v6)) { + T t1 = v1; + T t2 = v2; + T t3 = v3; + T t4 = v4; + T t5 = v5; + T t6 = v6; + append(t1, t2, t3, t4, t5, t6); + } else if (num + 5 < numAllocated) { + // This is a simple situation; just stick it in the next free slot using + // the copy constructor. + new (data + num) T(v1); + new (data + num + 1) T(v2); + new (data + num + 2) T(v3); + new (data + num + 3) T(v4); + new (data + num + 4) T(v5); + new (data + num + 5) T(v6); + num += 6; + } else { + resize(num + 6, DONT_SHRINK_UNDERLYING_ARRAY); + data[num - 6] = v1; + data[num - 5] = v2; + data[num - 4] = v3; + data[num - 3] = v4; + data[num - 2] = v5; + data[num - 1] = v6; + } + } /** Returns true if the given element is in the array. */ @@ -602,12 +747,12 @@ public: */ void append(const Array& array) { debugAssert(this != &array); - int oldNum = num; - int arrayLength = array.length(); + size_t oldNum = num; + size_t arrayLength = array.length(); resize(num + arrayLength, false); - for (int i = 0; i < arrayLength; i++) { + for (size_t i = 0; i < arrayLength; ++i) { data[oldNum + i] = array.data[i]; } } @@ -648,8 +793,8 @@ public: sequence, a value at least as large as size()" For compatibility with std::vector. */ - int capacity() const { - return numAllocated; + int capacity() const { + return (int)numAllocated; } /** @@ -723,27 +868,40 @@ public: Performs bounds checks in debug mode */ inline T& operator[](int n) { - debugAssertM((n >= 0) && (n < num), format("Array index out of bounds. n = %d, size() = %d", n, num)); + debugAssertM((n >= 0) && (n < (int)num), + format("Array index out of bounds. n = %d, size() = %d", (int)n, (int)num)); debugAssert(data!=NULL); return data[n]; } - inline T& operator[](unsigned int n) { - debugAssertM(n < (unsigned int)num, format("Array index out of bounds. n = %d, size() = %d", n, num)); - return data[n]; + inline T& operator[](uint32 n) { + debugAssertM(n < (uint32)num, format("Array index out of bounds. n = %d, size() = %d", + (int)n, (int)num)); + return data[n]; + } + + inline T& operator[](uint64 n) { + debugAssertM(n < (uint64)num, format("Array index out of bounds. n = %d, size() = %d", (int)n, (int)num)); + return data[n]; } /** Performs bounds checks in debug mode */ inline const T& operator[](int n) const { - debugAssert((n >= 0) && (n < num)); + debugAssert((n >= 0) && (n < (int)num)); + debugAssert(data != NULL); + return data[n]; + } + + inline const T& operator[](uint32 n) const { + debugAssert((n < (uint32)num)); debugAssert(data!=NULL); return data[n]; } - inline const T& operator[](unsigned int n) const { - debugAssert((n < (unsigned int)num)); + inline const T& operator[](uint64 n) const { + debugAssert((n < (uint64)num)); debugAssert(data!=NULL); return data[n]; } @@ -751,7 +909,7 @@ public: inline T& randomElement() { debugAssert(num > 0); debugAssert(data!=NULL); - return data[iRandom(0, num - 1)]; + return data[iRandom(0, (int)num - 1)]; } inline const T& randomElement() const { @@ -821,13 +979,18 @@ public: Calls delete on all objects[0...size-1] and sets the size to zero. */ - void deleteAll() { - for (int i = 0; i < num; i++) { + void invokeDeleteOnAllElements() { + for (size_t i = 0; i < num; ++i) { delete data[i]; } resize(0); } + /** \deprecated */ + void G3D_DEPRECATED deleteAll() { + invokeDeleteOnAllElements(); + } + /** Returns the index of (the first occurance of) an index or -1 if not found. Searches from the right. @@ -846,9 +1009,9 @@ public: not found. */ int findIndex(const T& value) const { - for (int i = 0; i < num; ++i) { + for (size_t i = 0; i < num; ++i) { if (data[i] == value) { - return i; + return (int)i; } } return -1; @@ -894,8 +1057,8 @@ public: } void remove(int index, int count = 1) { - debugAssert((index >= 0) && (index < num)); - debugAssert((count > 0) && (index + count <= num)); + debugAssert((index >= 0) && (index < (int)num)); + debugAssert((count > 0) && (index + count <= (int)num)); remove(begin() + index, count); } @@ -906,8 +1069,8 @@ public: void reverse() { T temp; - int n2 = num / 2; - for (int i = 0; i < n2; ++i) { + size_t n2 = num / 2; + for (size_t i = 0; i < n2; ++i) { temp = data[num - 1 - i]; data[num - 1 - i] = data[i]; data[i] = temp; @@ -917,29 +1080,29 @@ public: /** Sort using a specific less-than function, e.g.: -
+  \code
     bool __cdecl myLT(const MyClass& elem1, const MyClass& elem2) {
         return elem1.x < elem2.x;
     }
-    
+ \endcode Note that for pointer arrays, the const must come after the class name, e.g., Array uses: -
+  \code
     bool __cdecl myLT(MyClass*const& elem1, MyClass*const& elem2) {
         return elem1->x < elem2->x;
     }
-    
+ \endcode or a functor, e.g., -
+    \code
 bool
 less_than_functor::operator()( const double& lhs, const double& rhs ) const
 {
 return( lhs < rhs? true : false );
 }
-
+\endcode */ // void sort(bool (__cdecl *lessThan)(const T& elem1, const T& elem2)) { // std::sort(data, data + num, lessThan); @@ -955,14 +1118,14 @@ return( lhs < rhs? true : false ); Sorts the array in increasing order using the > or < operator. To invoke this method on Array, T must override those operator. You can overide these operators as follows: - + \code bool T::operator>(const T& other) const { return ...; } bool T::operator<(const T& other) const { return ...; } - + \endcode */ void sort(int direction = SORT_INCREASING) { if (direction == SORT_INCREASING) { @@ -1053,7 +1216,7 @@ return( lhs < rhs? true : false ); // Form a table of buckets for lt, eq, and gt Array* bucket[3] = {<Array, &eqArray, >Array}; - for (int i = 0; i < num; ++i) { + for (size_t i = 0; i < num; ++i) { int c = comparator(partitionElement, data[i]); debugAssertM(c >= -1 && c <= 1, "Comparator returned an illegal value."); @@ -1236,6 +1399,8 @@ return( lhs < rhs? true : false ); medianPartition(ltMedian, eqMedian, gtMedian, temp, DefaultComparator()); } + + /** Redistributes the elements so that the new order is statistically independent of the original order. O(n) time.*/ @@ -1252,6 +1417,35 @@ return( lhs < rhs? true : false ); } + /** Ensures that future append() calls can grow up to size \a n without allocating memory.*/ + void reserve(int n) { + debugAssert(n >= size()); + const int oldSize = size(); + resize(n); + resize(oldSize, false); + } + + /** Number of bytes used by the array object and the memory allocated for it's data pointer. Does *not* + * include the memory of objects pointed to by objects in the data array */ + size_t sizeInMemory() const { + return sizeof(Array) + (sizeof(T) * numAllocated); + } + + /** Remove all NULL elements in linear time without affecting order of the other elements. */ + void removeNulls() { + int nextNull = 0; + for (int i = 0; i < size(); ++i) { + if (notNull(data[i])) { + if (i > nextNull) { + // Move value i down to squeeze out NULLs + data[nextNull] = data[i]; + } + ++nextNull; + } + } + + resize(nextNull, false); + } }; diff --git a/deps/g3dlite/include/G3D/AtomicInt32.h b/deps/g3dlite/include/G3D/AtomicInt32.h index 2d63f9983..9824d426d 100644 --- a/deps/g3dlite/include/G3D/AtomicInt32.h +++ b/deps/g3dlite/include/G3D/AtomicInt32.h @@ -28,7 +28,7 @@ namespace G3D { */ class AtomicInt32 { private: -# if defined(G3D_WIN32) +# if defined(G3D_WINDOWS) volatile long m_value; # elif defined(G3D_OSX) int32_t m_value; @@ -70,18 +70,22 @@ public: /** Returns the old value, before the add. */ int32 add(const int32 x) { -# if defined(G3D_WIN32) +# if defined(G3D_WINDOWS) return InterlockedExchangeAdd(&m_value, x); # elif defined(G3D_LINUX) || defined(G3D_FREEBSD) - int32 old; - asm volatile ("lock; xaddl %0,%1" - : "=r"(old), "=m"(m_value) /* outputs */ - : "0"(x), "m"(m_value) /* inputs */ - : "memory", "cc"); - return old; +# if defined(__aarch64__) + return __sync_fetch_and_add(&m_value, x); +# else + int32 old; + asm volatile ("lock; xaddl %0,%1" + : "=r"(old), "=m"(m_value) /* outputs */ + : "0"(x), "m"(m_value) /* inputs */ + : "memory", "cc"); + return old; +# endif # elif defined(G3D_OSX) @@ -98,7 +102,7 @@ public: } void increment() { -# if defined(G3D_WIN32) +# if defined(G3D_WINDOWS) // Note: returns the newly incremented value InterlockedIncrement(&m_value); # elif defined(G3D_LINUX) || defined(G3D_FREEBSD) @@ -111,18 +115,22 @@ public: /** Returns zero if the result is zero after decrement, non-zero otherwise.*/ int32 decrement() { -# if defined(G3D_WIN32) +# if defined(G3D_WINDOWS) // Note: returns the newly decremented value return InterlockedDecrement(&m_value); # elif defined(G3D_LINUX) || defined(G3D_FREEBSD) - unsigned char nz; +# if defined(__aarch64__) + return __sync_sub_and_fetch(&m_value, 1); +# else + unsigned char nz; - asm volatile ("lock; decl %1;\n\t" - "setnz %%al" - : "=a" (nz) - : "m" (m_value) - : "memory", "cc"); - return nz; + asm volatile ("lock; decl %1;\n\t" + "setnz %%al" + : "=a" (nz) + : "m" (m_value) + : "memory", "cc"); + return nz; +# endif # elif defined(G3D_OSX) // Note: returns the newly decremented value return OSAtomicDecrement32(&m_value); @@ -140,20 +148,24 @@ public: Under VC6 the sign bit may be lost. */ int32 compareAndSet(const int32 comperand, const int32 exchange) { -# if defined(G3D_WIN32) +# if defined(G3D_WINDOWS) return InterlockedCompareExchange(&m_value, exchange, comperand); # elif defined(G3D_LINUX) || defined(G3D_FREEBSD) || defined(G3D_OSX) - // Based on Apache Portable Runtime - // http://koders.com/c/fid3B6631EE94542CDBAA03E822CA780CBA1B024822.aspx - int32 ret; - asm volatile ("lock; cmpxchgl %1, %2" - : "=a" (ret) - : "r" (exchange), "m" (m_value), "0"(comperand) - : "memory", "cc"); - return ret; +# if defined(__aarch64__) + return __sync_val_compare_and_swap(&m_value, comperand, exchange); +# else + // Based on Apache Portable Runtime + // http://koders.com/c/fid3B6631EE94542CDBAA03E822CA780CBA1B024822.aspx + int32 ret; + asm volatile ("lock; cmpxchgl %1, %2" + : "=a" (ret) + : "r" (exchange), "m" (m_value), "0"(comperand) + : "memory", "cc"); + return ret; - // Note that OSAtomicCompareAndSwap32 does not return a useful value for us - // so it can't satisfy the cmpxchgl contract. + // Note that OSAtomicCompareAndSwap32 does not return a useful value for us + // so it can't satisfy the cmpxchgl contract. +# endif # endif } diff --git a/deps/g3dlite/include/G3D/BIN.h b/deps/g3dlite/include/G3D/BIN.h new file mode 100644 index 000000000..e4c86768d --- /dev/null +++ b/deps/g3dlite/include/G3D/BIN.h @@ -0,0 +1,92 @@ +#ifndef G3D_BIN_h +#define G3D_BIN_h + +#define _BIT(N, K) (((N >> (3*K)) & 1) << K) + +#define _OCT_CODED_BIN(N) \ + (_BIT(N, 0) | _BIT(N, 1) | _BIT(N, 2) | _BIT(N, 3) | \ + _BIT(N, 4) | _BIT(N, 5) | _BIT(N, 6) | _BIT(N, 7) | \ + _BIT(N, | _BIT(N, 9) | _BIT(N, 10)) + +/** + \def BIN11() + + \brief Create a binary constant up to 11 digits long at compile time. + + \code + int i = BIN(01100101001) + \endcode + + \cite By Kaz Kylheku http://www.velocityreviews.com/forums/t620780-mathew-hendrys-macro-for-binary-integer-literals.html + \sa BIN8(), BIN11(), BIN16(), BIN32() +*/ +#define BIN11(N) _OCT_CODED_BIN(0 ## N ## UL) + + + +/* turn a numeric literal into a hex constant + (avoids problems with leading zeroes) + 8-bit constants max value 0x11111111, always fits in unsigned long +*/ +#define HEX__(n) 0x##n##LU + +/* 8-bit conversion function */ +#define B8__(x) ((x&0x0000000FLU)?1:0) \ ++((x&0x000000F0LU)?2:0) \ ++((x&0x00000F00LU)?4:0) \ ++((x&0x0000F000LU)?8:0) \ ++((x&0x000F0000LU)?16:0) \ ++((x&0x00F00000LU)?32:0) \ ++((x&0x0F000000LU)?64:0) \ ++((x&0xF0000000LU)?128:0) + +/** + \def BIN8() + \brief Generate a 16-bit constant in binary notation, in 8-bit strings. + + The most significant byte is first. + + \code + unsigned int i = BIN8(01010101); // 85 + \endcode + + \cite Tom Torfs http://groups.google.com/group/comp.arch.embedded/msg/9d430b6d3da12c8f + \sa BIN8(), BIN11(), BIN16(), BIN32() +*/ +#define BIN8(d) ((unsigned char)B8__(HEX__(d))) + +/** \def BIN16() + \brief Generate a 16-bit constant in binary notation, in 8-bit strings. + + The most significant byte is first. + + \code + unsigned int i = BIN16(10101010,01010101); // 43605 + \endcode + + \cite Tom Torfs http://groups.google.com/group/comp.arch.embedded/msg/9d430b6d3da12c8f + \sa BIN8(), BIN11(), BIN16(), BIN32() +*/ +#define BIN16(dmsb, dlsb) (((unsigned short)BIN8(dmsb) << 8) + BIN8(dlsb)) + + +/** + \def BIN32() + \brief Generate a 32-bit constant in binary notation, in 8-bit strings. + + The most significant byte is first. + + \code + unsigned int = BIN32(10000000,11111111,10101010,01010101); // 2164238933 + \endcode + + \cite Tom Torfs http://groups.google.com/group/comp.arch.embedded/msg/9d430b6d3da12c8f + \sa BIN8(), BIN11(), BIN16(), BIN32() +*/ +#define BIN32(dmsb,db2,db3,dlsb) \ + (((unsigned long)BIN8(dmsb) << 24) + \ + ((unsigned long)BIN8(db2) << 16) + \ + ((unsigned long)BIN8(db3) << 8) + \ + BIN8(dlsb)) + +#endif diff --git a/deps/g3dlite/include/G3D/BinaryInput.h b/deps/g3dlite/include/G3D/BinaryInput.h index e8a9b8861..e8335c681 100644 --- a/deps/g3dlite/include/G3D/BinaryInput.h +++ b/deps/g3dlite/include/G3D/BinaryInput.h @@ -1,12 +1,12 @@ /** - @file BinaryInput.h + \file G3D/BinaryInput.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2001-08-09 - @edited 2010-03-19 + \created 2001-08-09 + \edited 2013-01-03 - Copyright 2000-2010, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ @@ -26,6 +26,7 @@ #include #include #include "G3D/platform.h" +#include "G3D/unorm8.h" #include "G3D/Array.h" #include "G3D/Color4.h" #include "G3D/Color3.h" @@ -39,7 +40,7 @@ namespace G3D { -#if defined(G3D_WIN32) || defined(G3D_LINUX) +#if defined(G3D_WINDOWS) || defined(G3D_LINUX) // Allow writing of integers to non-word aligned locations. // This is legal on x86, but not on other platforms. #define G3D_ALLOW_UNALIGNED_WRITES @@ -69,8 +70,15 @@ class BinaryInput { private: // The initial buffer will be no larger than this, but - // may grow if a large memory read occurs. 50 MB - enum {INITIAL_BUFFER_LENGTH = 50000000}; + // may grow if a large memory read occurs. 750 MB + static const int64 + INITIAL_BUFFER_LENGTH = +#ifdef G3D_64BIT + 5000000000L // 5 GB +#else + 750000000 // 750 MB +#endif + ; /** is the file big or little endian @@ -94,6 +102,7 @@ private: /** When operating on huge files, we cannot load the whole file into memory. This is the file position to which buffer[0] corresponds. + Even 32-bit code can load 64-bit files in chunks, so this is not size_t */ int64 m_alreadyRead; @@ -122,14 +131,8 @@ private: void loadIntoMemory(int64 startPosition, int64 minLength = 0); /** Verifies that at least this number of bytes can be read.*/ - inline void prepareToRead(int64 nbytes) { - debugAssertM(m_length > 0, m_filename + " not found or corrupt."); - debugAssertM(m_pos + nbytes + m_alreadyRead <= m_length, "Read past end of file."); + void prepareToRead(int64 nbytes); - if (m_pos + nbytes > m_bufferLength) { - loadIntoMemory(m_pos + m_alreadyRead, nbytes); - } - } // Not implemented on purpose, don't use BinaryInput(const BinaryInput&); @@ -165,6 +168,7 @@ public: To decompress part of a file, you can follow the following paradigm: + \htmlonly
         BinaryInput master(...);
 
@@ -176,6 +180,7 @@ public:
 
         // Now read from subset (it is ok for master to go out of scope)
      
+ \endhtmlonly */ BinaryInput( const uint8* data, @@ -199,24 +204,13 @@ public: return m_filename; } - /** - Returns a pointer to the internal memory buffer. - May throw an exception for huge files. - */ - const uint8* getCArray() const { - if (m_alreadyRead > 0) { - throw "Cannot getCArray for a huge file"; - } - return m_buffer; - } - /** Performs bounds checks in debug mode. [] are relative to the start of the file, not the current position. Seeks to the new position before reading (and leaves that as the current position) */ - inline uint8 operator[](int64 n) { + uint8 operator[](int64 n) { setPosition(n); return readUInt8(); } @@ -224,11 +218,11 @@ public: /** Returns the length of the file in bytes. */ - inline int64 getLength() const { + int64 getLength() const { return m_length; } - inline int64 size() const { + int64 size() const { return getLength(); } @@ -236,15 +230,26 @@ public: Returns the current byte position in the file, where 0 is the beginning and getLength() - 1 is the end. */ - inline int64 getPosition() const { + int64 getPosition() const { return m_pos + m_alreadyRead; } + /** + Returns a pointer to the internal memory buffer. + May throw an exception for huge files. + */ + const uint8* getCArray() { + if (m_alreadyRead > 0 || m_bufferLength < m_length) { + throw "Cannot getCArray for a huge file"; + } + return m_buffer; + } + /** Sets the position. Cannot set past length. May throw a char* when seeking backwards more than 10 MB on a huge file. */ - inline void setPosition(int64 p) { + void setPosition(int64 p) { debugAssertM(p <= m_length, "Read past end of file"); m_pos = p - m_alreadyRead; if ((m_pos < 0) || (m_pos > m_bufferLength)) { @@ -255,25 +260,31 @@ public: /** Goes back to the beginning of the file. */ - inline void reset() { + void reset() { setPosition(0); } - inline int8 readInt8() { + void readBytes(void* bytes, int64 n); + + int8 readInt8() { prepareToRead(1); return m_buffer[m_pos++]; } - - inline bool readBool8() { + + bool readBool8() { return (readInt8() != 0); } - - inline uint8 readUInt8() { + + uint8 readUInt8() { prepareToRead(1); return ((uint8*)m_buffer)[m_pos++]; } + + unorm8 readUNorm8() { + return unorm8::fromBits(readUInt8()); + } - uint16 inline readUInt16() { + uint16 readUInt16() { prepareToRead(2); m_pos += 2; @@ -295,12 +306,12 @@ public: } - inline int16 readInt16() { + int16 readInt16() { uint16 a = readUInt16(); return *(int16*)&a; } - inline uint32 readUInt32() { + uint32 readUInt32() { prepareToRead(4); m_pos += 4; @@ -326,19 +337,19 @@ public: } - inline int32 readInt32() { + int32 readInt32() { uint32 a = readUInt32(); return *(int32*)&a; } uint64 readUInt64(); - inline int64 readInt64() { + int64 readInt64() { uint64 a = readUInt64(); return *(int64*)&a; } - inline float32 readFloat32() { + float32 readFloat32() { union { uint32 a; float32 b; @@ -347,7 +358,7 @@ public: return b; } - inline float64 readFloat64() { + float64 readFloat64() { union { uint64 a; float64 b; @@ -356,31 +367,34 @@ public: return b; } - void readBytes(void* bytes, int64 n); - /** - Reads an n character string. The string is not - required to end in NULL in the file but will - always be a proper std::string when returned. + Always consumes \a maxLength characters. Reads a string until NULL or \a maxLength characters. Does not require NULL termination. */ - std::string readString(int64 n); + std::string readString(int64 maxLength); /** - Reads until NULL or the end of the file is encountered. + Reads a string until NULL or end of file. */ std::string readString(); - /** Reads until \r, \r\n, \n\r, \n or the end of the file is encountered. Consumes the newline.*/ + /** Read a string (which may contain NULLs) of exactly numBytes bytes, including the final terminator if there is one. If there is a NULL in the string before + the end, then only the part up to the first NULL is returned although all bytes are read.*/ + std::string readFixedLengthString(int numBytes); + + /** + Reads a string until NULL, newline ("\r", "\n", "\r\n", "\n\r") or the end of the file is encountered. Consumes the newline. + */ std::string readStringNewline(); /** Reads until NULL or the end of the file is encountered. If the string has odd length (including NULL), reads - another byte. + another byte. This is a common format for 16-bit alignment + in files. */ std::string readStringEven(); - + /** Reads a uint32 and then calls readString(maxLength) with that value as the length. */ std::string readString32(); Vector4 readVector4(); @@ -393,15 +407,15 @@ public: /** Skips ahead n bytes. */ - inline void skip(int64 n) { + void skip(int64 n) { setPosition(m_pos + m_alreadyRead + n); } /** Returns true if the position is not at the end of the file */ - inline bool hasMore() const { - return m_pos + m_alreadyRead < m_length; + bool hasMore() const { + return m_pos + m_alreadyRead < m_length; } /** Prepares for bit reading via readBits. Only readBits can be diff --git a/deps/g3dlite/include/G3D/BinaryOutput.h b/deps/g3dlite/include/G3D/BinaryOutput.h index d81ec56a6..45e1124d7 100644 --- a/deps/g3dlite/include/G3D/BinaryOutput.h +++ b/deps/g3dlite/include/G3D/BinaryOutput.h @@ -1,17 +1,17 @@ /** - @file BinaryOutput.h + \file G3D/BinaryOutput.h - @maintainer Morgan McGuire, graphics3d.com + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2001-08-09 - @edited 2008-01-24 + \created 2001-08-09 + \edited 2011-08-24 - Copyright 2000-2006, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ -#ifndef G3D_BINARYOUTPUT_H -#define G3D_BINARYOUTPUT_H +#ifndef G3D_BinaryOutput_h +#define G3D_BinaryOutput_h #include "G3D/platform.h" #include @@ -19,6 +19,7 @@ #include #include #include +#include "G3D/unorm8.h" #include "G3D/Color4.h" #include "G3D/Color3.h" #include "G3D/Vector4.h" @@ -73,19 +74,19 @@ private: uint8* m_buffer; /** Size of the elements used */ - int m_bufferLen; + size_t m_bufferLen; /** Underlying size of memory allocaded */ - int m_maxBufferLen; + size_t m_maxBufferLen; /** Next byte in file */ - int m_pos; + int64 m_pos; /** is this initialized? */ bool m_init; - /** Number of bytes already written to the file.*/ - size_t m_alreadyWritten; + /** Number of bytes already written to the file. Even on 32-bit OS, this can be 64-bits*/ + int64 m_alreadyWritten; bool m_ok; @@ -97,11 +98,11 @@ private: Make sure at least bytes can be written, resizing if necessary. */ - inline void reserveBytes(int bytes) { + inline void reserveBytes(size_t bytes) { debugAssert(bytes > 0); - size_t oldBufferLen = (size_t)m_bufferLen; + size_t oldBufferLen = m_bufferLen; - m_bufferLen = iMax(m_bufferLen, (m_pos + bytes)); + m_bufferLen = max(m_bufferLen, (size_t)(m_pos + bytes)); if (m_bufferLen > m_maxBufferLen) { reallocBuffer(bytes, oldBufferLen); } @@ -138,8 +139,10 @@ public: Cannot be used for huge files (ones where the data was already written to disk)-- will throw char*. + + \param level Compression level. 0 = fast, low compression; 9 = slow, high compression */ - void compress(); + void compress(int level = 9); /** True if no errors have been encountered.*/ bool ok() const; @@ -190,11 +193,11 @@ public: void reset(); - inline int length() const { - return (int)m_bufferLen + (int)m_alreadyWritten; + inline int64 length() const { + return m_bufferLen + m_alreadyWritten; } - inline int size() const { + inline int64 size() const { return length(); } @@ -207,18 +210,18 @@ public: Throws char* when resetting a huge file to be shorter than its current length. */ - inline void setLength(int n) { - n = n - (int)m_alreadyWritten; + inline void setLength(int64 n) { + n = n - m_alreadyWritten; if (n < 0) { throw "Cannot resize huge files to be shorter."; } - if (n < m_bufferLen) { + if (n < (int64)m_bufferLen) { m_pos = n; } - if (n > m_bufferLen) { - reserveBytes(n - m_bufferLen); + if (n > (int64)m_bufferLen) { + reserveBytes((size_t)(n - m_bufferLen)); } } @@ -227,7 +230,7 @@ public: where 0 is the beginning and getLength() - 1 is the end. */ inline int64 position() const { - return (int64)m_pos + (int64)m_alreadyWritten; + return m_pos + m_alreadyWritten; } @@ -239,9 +242,9 @@ public: May throw a char* exception when seeking backwards on a huge file. */ inline void setPosition(int64 p) { - p = p - (int64)m_alreadyWritten; + p = p - m_alreadyWritten; - if (p > m_bufferLen) { + if (p > (int64)m_bufferLen) { setLength((int)(p + (int64)m_alreadyWritten)); } @@ -253,9 +256,9 @@ public: } - void writeBytes( - const void* b, - int count) { + void writeBytes + (const void* b, + size_t count) { reserveBytes(count); debugAssert(m_pos >= 0); @@ -270,7 +273,7 @@ public: inline void writeInt8(int8 i) { reserveBytes(1); m_buffer[m_pos] = *(uint8*)&i; - m_pos++; + ++m_pos; } inline void writeBool8(bool b) { @@ -280,7 +283,11 @@ public: inline void writeUInt8(uint8 i) { reserveBytes(1); m_buffer[m_pos] = i; - m_pos++; + ++m_pos; + } + + inline void writeUNorm8(unorm8 i) { + writeUInt8(i.bits()); } void writeUInt16(uint16 u); @@ -328,6 +335,20 @@ public: writeString(s.c_str()); } + /** Write a string that always consumes len bytes, truncating or padding as necessary*/ + inline void writeString(const std::string& s, int len) { + const int pad = len - ((int)s.length() + 1); + if (pad >= 0) { + writeString(s.c_str()); + for (int i = 0; i < pad; ++i) { + writeUInt8(0); + } + } else { + // Truncate + writeBytes(s.c_str(), len); + } + } + void writeString(const char* s); /** @@ -340,12 +361,11 @@ public: void writeStringEven(const char* s); - void writeString32(const char* s); /** - Write a string with a 32-bit length field in front - of it. + Write a NULL-terminated string with a 32-bit length field in front + of it. The NULL character is included in the length count. */ void writeString32(const std::string& s) { writeString32(s.c_str()); @@ -365,8 +385,8 @@ public: Skips ahead n bytes. */ inline void skip(int n) { - if (m_pos + n > m_bufferLen) { - setLength((int)m_pos + (int)m_alreadyWritten + n); + if (m_pos + n > (int64)m_bufferLen) { + setLength(m_pos + m_alreadyWritten + n); } m_pos += n; } diff --git a/deps/g3dlite/include/G3D/Box.h b/deps/g3dlite/include/G3D/Box.h index 82af9125b..5409af803 100644 --- a/deps/g3dlite/include/G3D/Box.h +++ b/deps/g3dlite/include/G3D/Box.h @@ -1,20 +1,20 @@ /** - @file Box.h + \file G3D/Box.h Box class - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \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 2007-06-05 + \cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com + \created 2001-06-02 + \edited 2013-04-13 - Copyright 2000-2006, Morgan McGuire. + Copyright 2000-2013, Morgan McGuire. All rights reserved. */ -#ifndef G3D_BOX_H -#define G3D_BOX_H +#ifndef G3D_Box_h +#define G3D_Box_h #include "G3D/platform.h" #include "G3D/Vector3.h" @@ -24,13 +24,12 @@ namespace G3D { class CoordinateFrame; +class Any; /** - An arbitrary 3D box, useful as a bounding box. - - - To construct a box from a coordinate frame, center and extent, use the idiom: + \brief An arbitrary (oriented) 3D box, useful as a bounding box. + To construct a box from a coordinate frame, center and extent, use the idiom: Box box = cframe.toObjectSpace(Box(center - extent/2, center + extent/2)); */ class Box { @@ -41,29 +40,14 @@ private: friend class CoordinateFrame; /** -
-       3    2       7    6
-    
-       0    1       4    5
-
-       front    back (seen through front)
-      
+ Axes with length equal to the 4 edges that run along each of them */ - Vector3 _corner[8]; - - /** - Unit axes. - */ - Vector3 _axis[3]; + Vector3 _edgeVector[3]; - Vector3 _center; - - /** - Extent along each axis. - */ - Vector3 _extent; + Point3 _center; float _area; + float _volume; void init( @@ -72,38 +56,47 @@ private: public: - /** - Does not initialize the fields. - */ Box(); + explicit Box(const Any& a); + /** Constructs a box from two opposite corners. */ - Box( - const Vector3& min, + Box(const Vector3& min, const Vector3& max); - static Box inf(); + Box(const Vector3& osMin, + const Vector3& osMax, + const CoordinateFrame& frame); - Box(class BinaryInput& b); + Box(class BinaryInput& b); Box(const class AABox& b); - void serialize(class BinaryOutput& b) const; - void deserialize(class BinaryInput& b); + explicit Box(const Point3& p); + static Box inf(); + + Any toAny() const; + + void serialize(class BinaryOutput& b) const; + void deserialize(class BinaryInput& b); + /** Returns the object to world transformation for - this box. localFrame().worldToObject(...) takes + this box, where the origin is the center of the box. localFrame().worldToObject(...) takes objects into the space where the box axes are (1,0,0), (0,1,0), (0,0,1). Note that there is no scaling in this transformation. */ CoordinateFrame localFrame() const; + /** \sa localFrame */ void getLocalFrame(CoordinateFrame& frame) const; + Box operator*(float f) const; + /** Returns the centroid of the box. */ @@ -111,18 +104,39 @@ public: return _center; } + /** + \htmlonly +
+		
 
-    inline Vector3 corner(int i) const {
-        debugAssert(i < 8);
-        return _corner[i];
-    }
+      2--------3
+     / :      /|
+    /  :     / |
+   6--------7  |
+   |   :    |  |
+   |   0....|..1
+   | /      | /
+   |/       |/
+   4--------5
+
+    y  
+    ^ 
+    |
+    |-->x
+  z/
+  
+
+      
+ \endhtmlonly + */ + Vector3 corner(int i) const; /** Unit length. */ inline Vector3 axis(int a) const { debugAssert(a < 3); - return _axis[a]; + return _edgeVector[a].direction(); } /** @@ -131,17 +145,43 @@ public: */ inline float extent(int a) const { debugAssert(a < 3); - return (float)_extent[a]; + return _edgeVector[a].length(); } inline Vector3 extent() const { - return _extent; + return Vector3(_edgeVector[0].length(), _edgeVector[1].length(), _edgeVector[2].length()); } /** Returns the four corners of a face (0 <= f < 6). - The corners are returned to form a counter clockwise quad facing outwards. - */ + The corners are returned to form a clockwise quad facing outwards. + + + + +--------+ + / : /| + / : / | + +--------+ | + | : | | + | +....|..+ + | / | / + |/ |/ + +--------+ + + y + ^ + | + |-->x +z/ + Faces are in the following order: + 0: -Z + 1: X + 2: Z + 3: Y + 4: -X + 5: -Y + + */ void getFaceCorners( int f, Vector3& v0, @@ -150,24 +190,24 @@ public: Vector3& v3) const; - /** + /** See AABox::culledBy - */ + */ bool culledBy ( - const Array& plane, - int32& cullingPlaneIndex, - const uint32 testMask, - uint32& childMask) const; + const Array& plane, + int32& cullingPlaneIndex, + const uint32 testMask, + uint32& childMask) const; /** Conservative culling test that does not produce a mask for children. */ bool culledBy ( - const Array& plane, - int32& cullingPlaneIndex = dummy, - const uint32 testMask = -1) const; + const Array& plane, + int32& cullingPlaneIndex = dummy, + const uint32 testMask = -1) const; bool contains( const Vector3& point) const; diff --git a/deps/g3dlite/include/G3D/BumpMapPreprocess.h b/deps/g3dlite/include/G3D/BumpMapPreprocess.h index 955f99e61..a2ddaf190 100644 --- a/deps/g3dlite/include/G3D/BumpMapPreprocess.h +++ b/deps/g3dlite/include/G3D/BumpMapPreprocess.h @@ -6,7 +6,7 @@ \created 2010-01-28 \edited 2010-01-28 - Copyright 2000-2010, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ @@ -20,7 +20,7 @@ class Any; /** Not in the BumpMap class to avoid a circular dependency between Texture and BumpMap. -G3D::GImage::computeNormalMap(). +G3D::Image::computeNormalMap(). */ class BumpMapPreprocess { public: @@ -46,7 +46,7 @@ public: BumpMapPreprocess(const Any& any); - operator Any() const; + Any toAny() const; bool operator==(const BumpMapPreprocess& other) const { return diff --git a/deps/g3dlite/include/G3D/Capsule.h b/deps/g3dlite/include/G3D/Capsule.h index baeea3aa8..3f10743cc 100644 --- a/deps/g3dlite/include/G3D/Capsule.h +++ b/deps/g3dlite/include/G3D/Capsule.h @@ -26,32 +26,32 @@ class AABox; */ class Capsule { private: - Vector3 p1; - Vector3 p2; + Vector3 p1; + Vector3 p2; - float _radius; + float _radius; public: /** Uninitialized */ Capsule(); Capsule(class BinaryInput& b); - Capsule(const Vector3& _p1, const Vector3& _p2, float _r); - void serialize(class BinaryOutput& b) const; - void deserialize(class BinaryInput& b); - - /** The line down the center of the capsule */ - Line axis() const; + Capsule(const Vector3& _p1, const Vector3& _p2, float _r); + void serialize(class BinaryOutput& b) const; + void deserialize(class BinaryInput& b); + + /** The line down the center of the capsule */ + Line axis() const; - inline float radius() const { - return _radius; - } + inline float radius() const { + return _radius; + } - /** Argument may be 0 or 1 */ - inline Vector3 point(int i) const { - debugAssert(i == 0 || i == 1); - return (i == 0) ? p1 : p2; - } + /** Argument may be 0 or 1 */ + inline Vector3 point(int i) const { + debugAssert(i == 0 || i == 1); + return (i == 0) ? p1 : p2; + } /** Distance between the sphere centers. The total extent of the cylinder is 2r + h. */ diff --git a/deps/g3dlite/include/G3D/CollisionDetection.h b/deps/g3dlite/include/G3D/CollisionDetection.h index c8fcf5534..906504ec5 100644 --- a/deps/g3dlite/include/G3D/CollisionDetection.h +++ b/deps/g3dlite/include/G3D/CollisionDetection.h @@ -1,5 +1,5 @@ /** - @file CollisionDetection.h + \file CollisionDetection.h Moving collision detection for simple primitives. @@ -12,15 +12,15 @@ Thanks to Max McGuire of Iron Lore for various bug fixes. Box-Triangle by Tomas Akenine-Moller - @created 2001-11-19 - @edited 2008-12-19 + \created 2001-11-19 + \edited 2010-11-10 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ -#ifndef G3D_COLLISIONDETECTION_H -#define G3D_COLLISIONDETECTION_H +#ifndef G3D_CollisionDetection_h +#define G3D_CollisionDetection_h #include "G3D/platform.h" #include "G3D/Vector3.h" @@ -68,16 +68,17 @@ namespace G3D { Static Collision Detection: (Neither object is moving) - - + + - + - +
Vector3LineSegmentRay *LinePlaneTriangleSphereCylinderCapsuleAABoxBox
Vector3\link Vector3::operator== V3::==\endlink \link Vector3::fuzzyEq V3::fuzzy \endlink \link G3D::distance distance \endlink
Point3LineSegmentRay *LinePlaneTriangleSphereCylinderCapsuleAABoxBox
Point3\link Vector3::operator== P3::==\endlink \link Vector3::fuzzyEq V3::fuzzy \endlink \link G3D::distance distance \endlink
LineSegment\link LineSegment::closestPoint LS::closestPoint\endlink \link LineSegment::distance LS::distance\endlink \link CollisionDetection::closestPointOnLineSegment CD\endlink
Ray *Ray::closestPoint Ray::distance
LineLine::closestPoint Line::distance\link CollisionDetection::closestPointsBetweenLineAndLine CD\endlink
Plane
Triangle
SphereSphere::contains\link CollisionDetection::collisionTimeForMovingPointFixedSphere CD \endlink, \link Ray::intersectionTime R::time\endlink
SphereSphere::contains\link CollisionDetection::collisionTimeForMovingPointFixedSphere CD \endlink, \link Ray::intersectionTime R::time\endlink\link G3D::CollisionDetection::fixedSolidSphereIntersectsFixedTriangle CD\endlink +\link G3D::CollisionDetection::penetrationDepthForFixedSphereFixedSphere CD\endlink
CylinderCylinder::contains
CapsuleCapsule::contains
CapsuleCapsule::contains \link G3D::CollisionDetection::collisionTimeForMovingSphereFixedTriangle CD\endlink
AABoxAABox::contains\link CollisionDetection::fixedSolidBoxIntersectsFixedTriangle CD\endlink
BoxBox::contains(treat as Ray)\link CollisionDetection::collisionTimeForMovingPointFixedBox CD\endlink(treat as Ray)\link CollisionDetection::penetrationDepthForFixedBoxFixedPlane CD \endlink\link CollisionDetection::penetrationDepthForFixedBoxFixedPlane CD\endlink\link CollisionDetection::penetrationDepthForFixedSphereFixedBox CD\endlinkNone (use OPCODE)\link CollisionDetection::movingSpherePassesThroughFixedBox CD \endlink\link CollisionDetection::penetrationDepthForFixedBoxFixedBox CD\endlink\link CollisionDetection::penetrationDepthForFixedBoxFixedBox CD\endlink
@@ -88,30 +89,29 @@ namespace G3D { * Note: Moving collision detection against certain primitives is equivalent to static collision detection against a bigger primitive. Ray, Line Segment == ``moving Point''; Capsule ==``moving Sphere''; Plane == ``moving Line'' - @deprecated Routines moving to the G3D::Intersect class in G3D 8.0 + @deprecated Routines moving to the G3D::Intersect class in G3D 9.0 */ class CollisionDetection { private: - /** - Default parameter if value passed to a function as reference is - not to be calculated. Must be explicitly supported by function. - */ - static Vector3 ignore; - - /** - Default parameter if value passed to a function as reference is - not to be calculated. Must be explicitly supported by function. - */ + /** + Default parameter if value passed to a function as reference is + not to be calculated. Must be explicitly supported by function. + */ + static Vector3 ignore; + + /** + Default parameter if value passed to a function as reference is + not to be calculated. Must be explicitly supported by function. + */ static bool ignoreBool; - /** - Default parameter if value passed to a function as reference is - not to be calculated. Must be explicitly supported by function. - */ + /** + Default parameter if value passed to a function as reference is + not to be calculated. Must be explicitly supported by function. + */ static Array ignoreArray; - // Static class! CollisionDetection() {} virtual ~CollisionDetection() {} @@ -123,32 +123,32 @@ public: Does not return normalized vector in the edge-edge case (indices 6 through 15). - @param separatingAxisIndex Separating axis. - @param box1 Box 1. - @param box2 Box 2. + @param separatingAxisIndex Separating axis. + @param box1 Box 1. + @param box2 Box 2. - @return Axis that separates the two boxes. - */ + @return Axis that separates the two boxes. + */ static Vector3 separatingAxisForSolidBoxSolidBox( const int separatingAxisIndex, const Box & box1, const Box & box2); /** - Tests whether two boxes have axes that are parallel to - each other. If they are, axis1 and axis2 are set to be - the parallel axes for both box1 and box2 respectively. + Tests whether two boxes have axes that are parallel to + each other. If they are, axis1 and axis2 are set to be + the parallel axes for both box1 and box2 respectively. - @param ca Dot products of each of the boxes axes - @param epsilon Fudge factor (small unit by which the dot - products may vary and still be considered - zero). - @param axis1 Parallel Axis 1. [Post Condition] - @param axis2 Parallel Axis 2. [Post Condition] + @param ca Dot products of each of the boxes axes + @param epsilon Fudge factor (small unit by which the dot + products may vary and still be considered + zero). + @param axis1 Parallel Axis 1. [Post Condition] + @param axis2 Parallel Axis 2. [Post Condition] - @return true - If boxes have a parallel axis - @return false - otherwise. - */ + @return true - If boxes have a parallel axis + @return false - otherwise. + */ static bool parallelAxisForSolidBoxSolidBox( const double* ca, const double epsilon, @@ -163,15 +163,15 @@ public: penetrationDepthForFixedSphereFixedBox() for more details @param separatingAxisIndex - @param a Box 1's bounding sphere vector - @param b Box 2's bounding sphere vector - @param D Vector between Box 1 and Box 2's center points - @param c Pointer to array of dot products of the axes of Box 1 - and Box 2. - @param ca Pointer to array of unsigned dot products of the axes - of Box 1 and Box 2. - @param ad Pointer to array of dot products of Box 1 axes and D. - @param bd Pointer to array of dot products of Box 2 axes and D. + @param a Box 1's bounding sphere vector + @param b Box 2's bounding sphere vector + @param D Vector between Box 1 and Box 2's center points + @param c Pointer to array of dot products of the axes of Box 1 + and Box 2. + @param ca Pointer to array of unsigned dot products of the axes + of Box 1 and Box 2. + @param ad Pointer to array of dot products of Box 1 axes and D. + @param bd Pointer to array of dot products of Box 2 axes and D. @return Projected distance between the two boxes along the specified separating axis. @@ -187,41 +187,41 @@ public: const double* bd); - /** - Creates a set of standard information about two boxes in order to - solve for their collision. This information includes a vector to - the radius of the bounding sphere for each box, the vector between - each boxes' center and a series of dot products between differing - important vectors. These dot products include those between the axes - of both boxes (signed and unsigned values), and the dot products - between all the axes of box1 and the boxes' center vector and box2 - and the boxes' center vector. + /** + Creates a set of standard information about two boxes in order to + solve for their collision. This information includes a vector to + the radius of the bounding sphere for each box, the vector between + each boxes' center and a series of dot products between differing + important vectors. These dot products include those between the axes + of both boxes (signed and unsigned values), and the dot products + between all the axes of box1 and the boxes' center vector and box2 + and the boxes' center vector. - @pre The following space requirements must be met: - - c[] 9 elements - - ca[] 9 elements - - ad[] 3 elements - - bd[] 3 elements + @pre The following space requirements must be met: + - c[] 9 elements + - ca[] 9 elements + - ad[] 3 elements + - bd[] 3 elements - @cite dobted from David Eberly's papers, variables used in this function + @cite dobted from David Eberly's papers, variables used in this function correspond to variables used in pages 6 and 7 in the pdf http://www.magic-software.com/Intersection.html http://www.magic-software.com/Documentation/DynamicCollisionDetection.pdf @note Links are out-dated. (Kept to preserve origin and authorship) - @param box1 Box 1 - @param box2 Box 2 - @param a Box 1's bounding sphere vector - @param b Box 2's bounding sphere vector - @param D Vector between Box 1 and Box 2's center points - @param c Pointer to array of dot products of the axes of Box 1 - and Box 2. - @param ca Pointer to array of unsigned dot products of the axes - of Box 1 and Box 2. - @param ad Pointer to array of dot products of Box 1 axes and D. - @param bd Pointer to array of dot products of Box 2 axes and D. - */ + @param box1 Box 1 + @param box2 Box 2 + @param a Box 1's bounding sphere vector + @param b Box 2's bounding sphere vector + @param D Vector between Box 1 and Box 2's center points + @param c Pointer to array of dot products of the axes of Box 1 + and Box 2. + @param ca Pointer to array of unsigned dot products of the axes + of Box 1 and Box 2. + @param ad Pointer to array of dot products of Box 1 axes and D. + @param bd Pointer to array of dot products of Box 2 axes and D. + */ static void fillSolidBoxSolidBoxInfo( const Box & box1, const Box & box2, @@ -233,70 +233,70 @@ public: double* ad, double* bd); - /** - Performs a simple bounding sphere check between two boxes to determine - whether these boxes could possibly intersect. This is a very - cheap operation (three dot products, two sqrts and a few others). If - it returns true, an intersection is possible, but not necessarily - guaranteed. + /** + Performs a simple bounding sphere check between two boxes to determine + whether these boxes could possibly intersect. This is a very + cheap operation (three dot products, two sqrts and a few others). If + it returns true, an intersection is possible, but not necessarily + guaranteed. - @param a Vector from box A's center to an outer vertex - @param b Vector from box B's center to an outer vertex - @param D Distance between the centers of the two boxes + @param a Vector from box A's center to an outer vertex + @param b Vector from box B's center to an outer vertex + @param D Distance between the centers of the two boxes - @return true - if possible intersection - @return false - otherwise (This does not guarantee an intersection) - */ + @return true - if possible intersection + @return false - otherwise (This does not guarantee an intersection) + */ static bool conservativeBoxBoxTest( const Vector3 & a, const Vector3 & b, const Vector3 & D); - /** - Determines whether two fixed solid boxes intersect. + /** + Determines whether two fixed solid boxes intersect. @note To speed up collision detection, the lastSeparatingAxis from the previous time step can be passed in and that plane can be checked first. If the separating axis was not saved, or if the two boxes intersected then lastSeparatingAxis should equal -1. - @cite Adobted from David Eberly's papers, variables used in this function + @cite Adobted from David Eberly's papers, variables used in this function correspond to variables used in pages 6 and 7 in the pdf http://www.magic-software.com/Intersection.html http://www.magic-software.com/Documentation/DynamicCollisionDetection.pdf - @param box1 Box 1. - @param box2 Box 2. - @param lastSeparatingAxis Last separating axis. - (optimization - see note) + @param box1 Box 1. + @param box2 Box 2. + @param lastSeparatingAxis Last separating axis. + (optimization - see note) - @return true - Intersection. - @return false - otherwise. - */ + @return true - Intersection. + @return false - otherwise. + */ static bool fixedSolidBoxIntersectsFixedSolidBox( const Box& box1, const Box& box2, const int lastSeparatingAxis = -1); /** - Calculates the closest points on two lines with each other. If the - lines are parallel then using the starting point, else calculate the - closest point on each line to the other. + Calculates the closest points on two lines with each other. If the + lines are parallel then using the starting point, else calculate the + closest point on each line to the other. - @note This is very similiar to calculating the intersection of two lines. - Logically then, the two points calculated would be identical if calculated - with inifinite precision, but with the finite precision of floating point - calculations, these values could (will) differ as the line slope approaches - zero or inifinity. + @note This is very similiar to calculating the intersection of two lines. + Logically then, the two points calculated would be identical if calculated + with inifinite precision, but with the finite precision of floating point + calculations, these values could (will) differ as the line slope approaches + zero or inifinity. - @cite variables and algorithm based on derivation at the following website: - http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm + @cite variables and algorithm based on derivation at the following website: + http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm - @param line1 Line 1. - @param line2 Line 2. - @param closest1 Closest point on line 1. - @param closest2 Closest point on line 2. - */ + @param line1 Line 1. + @param line2 Line 2. + @param closest1 Closest point on line 1. + @param closest2 Closest point on line 2. + */ static void closestPointsBetweenLineAndLine( const Line & line1, const Line & line2, @@ -304,7 +304,7 @@ public: Vector3 & closest2); /** - Calculates the depth of penetration between two fixed boxes. + Calculates the depth of penetration between two fixed boxes. Contact normal faces away from box1 and into box2. If there is contact, only one contact point is returned. The minimally violated separating plane is computed @@ -315,26 +315,26 @@ public: the contact point is the midpoint of the smallest line segment between the two edge lines - @note This is very similiar to calculating the intersection of two lines. - Logically then, the two points calculated would be identical if calculated - with inifinite precision, but with the finite precision of floating point - calculations, these values could (will) differ as the line slope approaches - zero or inifinity. + @note This is very similiar to calculating the intersection of two lines. + Logically then, the two points calculated would be identical if calculated + with inifinite precision, but with the finite precision of floating point + calculations, these values could (will) differ as the line slope approaches + zero or inifinity. - @cite adobted from David Eberly's papers, variables used in this function + @cite adobted from David Eberly's papers, variables used in this function correspond to variables used in pages 6 and 7 in the pdf http://www.magic-software.com/Intersection.html http://www.magic-software.com/Documentation/DynamicCollisionDetection.pdf - @param box1 Box 1 - @param box2 Box 2 - @param contactPoints Contact point between boxes. [Post Condition] - @param contactNormals Surface normal at contact point. [Post Condition] - @param lastSeparatingAxis Last separating axis. (Used for optimization) + @param box1 Box 1 + @param box2 Box 2 + @param contactPoints Contact point between boxes. [Post Condition] + @param contactNormals Surface normal at contact point. [Post Condition] + @param lastSeparatingAxis Last separating axis. (Used for optimization) - @return Depth of penetration between the two boxes. If there is no - intersection between the boxes, then a negative value is returned. - */ + @return Depth of penetration between the two boxes. If there is no + intersection between the boxes, then a negative value is returned. + */ static float penetrationDepthForFixedBoxFixedBox( const Box& box1, const Box& box2, @@ -343,21 +343,21 @@ public: const int lastSeparatingAxis = -1); /** - Calculates the depth of penetration between two fixed spheres as well - as the deepest point of Sphere A that penetrates Sphere B. The normal + Calculates the depth of penetration between two fixed spheres as well + as the deepest point of Sphere A that penetrates Sphere B. The normal returned points away from the object A, although it may represent a perpendicular to either the faces of object B or object A depending on their relative orientations. - @param sphereA Fixed Sphere A. - @param sphereB Fixed Sphere B. - @param contactPoints Sphere A's deepest point that penetrates Sphere B. - [Post Condition] - @param contactNormals Normal at penetration point. [Post Condition] + @param sphereA Fixed Sphere A. + @param sphereB Fixed Sphere B. + @param contactPoints Sphere A's deepest point that penetrates Sphere B. + [Post Condition] + @param contactNormals Normal at penetration point. [Post Condition] - @return Depth of penetration. If there is no intersection between the - objects then the depth will be a negative value. - */ + @return Depth of penetration. If there is no intersection between the + objects then the depth will be a negative value. + */ static float penetrationDepthForFixedSphereFixedSphere( const class Sphere& sphereA, const Sphere& sphereB, @@ -365,125 +365,125 @@ public: Array& contactNormals = ignoreArray); /** - Calculates the depth of penetration between a fixed sphere and a fixed - box as well as the deepest point of the sphere that penetrates the box - and the normal at that intersection. + Calculates the depth of penetration between a fixed sphere and a fixed + box as well as the deepest point of the sphere that penetrates the box + and the normal at that intersection. - @note There are three possible intersections between a sphere and box. - - Sphere completely contained in the box - - Sphere intersects one edge - - Sphere intersects one vertex + @note There are three possible intersections between a sphere and box. + - Sphere completely contained in the box + - Sphere intersects one edge + - Sphere intersects one vertex - The contact point and contact normal vary for each of these situations. - - Sphere contained in Box: - - Normal is based on side of least penetration (as is the depth calculation). - - Point is based on center of sphere - - Sphere intersects one edge - - Normal is based on vector from the box center to the point of depth. - - Point is closest point to the sphere on the line - - Sphere intersects one vertex - - Normal is based on vector from the box center to the vertex of penetration. - - Point is vertex of penetration. + The contact point and contact normal vary for each of these situations. + - Sphere contained in Box: + - Normal is based on side of least penetration (as is the depth calculation). + - Point is based on center of sphere + - Sphere intersects one edge + - Normal is based on vector from the box center to the point of depth. + - Point is closest point to the sphere on the line + - Sphere intersects one vertex + - Normal is based on vector from the box center to the vertex of penetration. + - Point is vertex of penetration. @cite Adapted from Jim Arvo's method in Graphics Gems See also http://www.win.tue.nl/~gino/solid/gdc2001depth.pdf - @param sphere Fixed Sphere. - @param box Fixed Box. - @param contactPoints Sphere point that penetrates the box. [Post Condition] - @param contactNormals Normal at the penetration point. [Post Condition] + @param sphere Fixed Sphere. + @param box Fixed Box. + @param contactPoints Sphere point that penetrates the box. [Post Condition] + @param contactNormals Normal at the penetration point. [Post Condition] - @return Depth of penetration. If there is no intersection between the - objects then the depth will be a negative value. - */ + @return Depth of penetration. If there is no intersection between the + objects then the depth will be a negative value. + */ static float penetrationDepthForFixedSphereFixedBox( const Sphere& sphere, const Box& box, Array& contactPoints, Array& contactNormals = ignoreArray); - /** - Calculates the depth of penetration between a Fixed Sphere and a Fixed - Plane as well as the deepest point of the sphere that penetrates the plane - and the plane normal at that intersection. + /** + Calculates the depth of penetration between a Fixed Sphere and a Fixed + Plane as well as the deepest point of the sphere that penetrates the plane + and the plane normal at that intersection. - @param sphereA Fixed Sphere. - @param planeB Fixed Plane. - @param contactPoints Sphere point that penetrates the plane. - [Post Condition] - @param contactNormals Normal at penetration point. [Post Condition] + @param sphereA Fixed Sphere. + @param planeB Fixed Plane. + @param contactPoints Sphere point that penetrates the plane. + [Post Condition] + @param contactNormals Normal at penetration point. [Post Condition] - @return Depth of penetration. If there is no intersection between the - objects then the depth will be a negative value. - */ + @return Depth of penetration. If there is no intersection between the + objects then the depth will be a negative value. + */ static float penetrationDepthForFixedSphereFixedPlane( const Sphere& sphereA, const class Plane& planeB, Array& contactPoints, Array& contactNormals = ignoreArray); - /** - Calculates the depth of penetration between a fixed box and a fixed - plane as well as the vertexes of the box that penetrate the plane - and the plane normals at those intersections. + /** + Calculates the depth of penetration between a fixed box and a fixed + plane as well as the vertexes of the box that penetrate the plane + and the plane normals at those intersections. - @param box Fixed Box. - @param plane Fixed Plane. - @param contactPoints Box points that penetrate the plane. - [Post Condition] - @param contactNormals Normals at penetration points [Post Condition] + @param box Fixed Box. + @param plane Fixed Plane. + @param contactPoints Box points that penetrate the plane. + [Post Condition] + @param contactNormals Normals at penetration points [Post Condition] - @return Depth of penetration. If there is no intersection between the - objects then the depth will be a negative value. - */ + @return Depth of penetration. If there is no intersection between the + objects then the depth will be a negative value. + */ static float penetrationDepthForFixedBoxFixedPlane( const Box& box, const Plane& plane, Array& contactPoints, Array& contactNormals = ignoreArray); - /** - Calculates time between the intersection of a moving point and a fixed - plane. + /** + Calculates time between the intersection of a moving point and a fixed + plane. - @note This is only a one sided collision test. The side defined by - the plane's surface normal is the only one tested. For a two sided - collision, call the function once for each side's surface normal. + @note This is only a one sided collision test. The side defined by + the plane's surface normal is the only one tested. For a two sided + collision, call the function once for each side's surface normal. - @param point Moving point. - @param velocity Point's velocity. - @param plane Fixed plane. - @param location Location of collision. [Post Condition] - (Infinite vector on no collision) - @param outNormal Plane's surface normal. [Post Condition] + @param point Moving point. + @param velocity Point's velocity. + @param plane Fixed plane. + @param outLocation Location of collision. [Post Condition] + (Infinite vector on no collision) + @param outNormal Plane's surface normal. [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ static float collisionTimeForMovingPointFixedPlane( - const Vector3& point, - const Vector3& velocity, - const class Plane& plane, - Vector3& outLocation, + const Vector3& point, + const Vector3& velocity, + const class Plane& plane, + Vector3& outLocation, Vector3& outNormal = ignore); - /** - Calculates time between the intersection of a moving point and a fixed - triangle. + /** + Calculates time between the intersection of a moving point and a fixed + triangle. - @note This is only a one sided collision test. The side defined by - the triangle's surface normal is the only one tested. For a two sided - collision, call the function once for each side's surface normal. + @note This is only a one sided collision test. The side defined by + the triangle's surface normal is the only one tested. For a two sided + collision, call the function once for each side's surface normal. - @param orig Moving point. - @param dir Point's velocity. - @param v0 Triangle vertex 1. - @param v1 Triangle vertex 2. - @param v2 Triangle vertex 3 + @param orig Moving point. + @param dir Point's velocity. + @param v0 Triangle vertex 1. + @param v1 Triangle vertex 2. + @param v2 Triangle vertex 3 - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ inline static float collisionTimeForMovingPointFixedTriangle( const Vector3& orig, const Vector3& dir, @@ -493,25 +493,25 @@ public: return Ray::fromOriginAndDirection(orig, dir).intersectionTime(v0, v1, v2); } - /** - Calculates time between the intersection of a moving point and a fixed - triangle. + /** + Calculates time between the intersection of a moving point and a fixed + triangle. - @note This is only a one sided collision test. The side defined by - the triangle's surface normal is the only one tested. For a two sided - collision, call the function once for each side's surface normal. + @note This is only a one sided collision test. The side defined by + the triangle's surface normal is the only one tested. For a two sided + collision, call the function once for each side's surface normal. - @param orig Moving point. - @param dir Point's velocity. - @param v0 Triangle vertex 1. - @param v1 Triangle vertex 2. - @param v2 Triangle vertex 3 - @param location Location of collision. [Post Condition] - (Infinite vector on no collision) + @param orig Moving point. + @param dir Point's velocity. + @param v0 Triangle vertex 1. + @param v1 Triangle vertex 2. + @param v2 Triangle vertex 3 + @param location Location of collision. [Post Condition] + (Infinite vector on no collision) - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ inline static float collisionTimeForMovingPointFixedTriangle( const Vector3& orig, const Vector3& dir, @@ -526,24 +526,24 @@ public: return t; } - /** - Calculates time between the intersection of a moving point and a fixed - triangle. + /** + Calculates time between the intersection of a moving point and a fixed + triangle. - @note This is only a one sided collision test. The side defined by - the triangle's surface normal is the only one tested. For a two sided - collision, call the function once for each side's surface normal. + @note This is only a one sided collision test. The side defined by + the triangle's surface normal is the only one tested. For a two sided + collision, call the function once for each side's surface normal. - @param orig Moving point. - @param dir Point's velocity. - @param tri Fixed triangle. - @param location Location of collision. [Post Condition] - (Infinite vector on no collision) - @param normal Triangle's surface normal. [Post Condition] + @param orig Moving point. + @param dir Point's velocity. + @param tri Fixed triangle. + @param location Location of collision. [Post Condition] + (Infinite vector on no collision) + @param normal Triangle's surface normal. [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ inline static float collisionTimeForMovingPointFixedTriangle( const Vector3& orig, const Vector3& dir, @@ -561,26 +561,26 @@ public: return t; } - /** - Calculates time between the intersection of a moving point and a fixed - triangle. + /** + Calculates time between the intersection of a moving point and a fixed + triangle. - @note This is only a one sided collision test. The side defined by - the triangle's surface normal is the only one tested. For a two sided - collision, call the function once for each side's surface normal. + @note This is only a one sided collision test. The side defined by + the triangle's surface normal is the only one tested. For a two sided + collision, call the function once for each side's surface normal. - @param orig Moving point. - @param dir Point's velocity. - @param v0 Triangle vertex 1. - @param v1 Triangle vertex 2. - @param v2 Triangle vertex 3 - @param location Location of collision. [Post Condition] - (Infinite vector on no collision) - @param normal Triangle's surface normal. [Post Condition] + @param orig Moving point. + @param dir Point's velocity. + @param v0 Triangle vertex 1. + @param v1 Triangle vertex 2. + @param v2 Triangle vertex 3 + @param location Location of collision. [Post Condition] + (Infinite vector on no collision) + @param normal Triangle's surface normal. [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ inline static float collisionTimeForMovingPointFixedTriangle( const Vector3& orig, const Vector3& dir, @@ -603,39 +603,39 @@ public: Beta API @cite Andrew Woo, from "Graphics Gems", Academic Press, 1990 - @cite Optimized code by Pierre Terdiman, 2000 (~20-30% faster on Celeron 500) + @cite Optimized code by Pierre Terdiman, 2000 (~20-30% faster on Celeron 500) @cite Epsilon value added by Klaus Hartmann @cite http://www.codercorner.com/RayAABB.cpp */ static float collisionTimeForMovingPointFixedAABox( - const Vector3& point, - const Vector3& velocity, + const Vector3& point, + const Vector3& velocity, const class AABox& box, - Vector3& outLocation, + Vector3& outLocation, bool& inside = ignoreBool, Vector3& outNormal = ignore); /** - Calculates time between the intersection of a moving point and a fixed - Axis-Aligned Box (AABox). + Calculates time between the intersection of a moving point and a fixed + Axis-Aligned Box (AABox). - @note Avoids the sqrt from collisionTimeForMovingPointFixedAABox. + @note Avoids the sqrt from collisionTimeForMovingPointFixedAABox. - @param point Moving point. - @param velocity Sphere's velocity. - @param box Fixed AAbox. - @param location Location of collision. [Post Condition] - @param Inside Does the ray originate inside the box? [Post Condition] - @param normal Box's surface normal to collision [Post Condition] + @param point Moving point. + @param velocity Sphere's velocity. + @param box Fixed AAbox. + @param outLocation Location of collision. [Post Condition] + @param inside Does the ray originate inside the box? [Post Condition] + @param normal Box's surface normal to collision [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ static bool collisionLocationForMovingPointFixedAABox( - const Vector3& point, - const Vector3& velocity, + const Vector3& point, + const Vector3& velocity, const class AABox& box, - Vector3& outLocation, + Vector3& outLocation, bool& inside = ignoreBool, Vector3& normal = ignore); @@ -648,8 +648,8 @@ public: early-out branches and operations optimized for Intel Core2 architecture. @param invDir 1/dir - @param location Location of collision. [Post Condition] - @param inside Does the ray originate inside the box? [Post Condition] + @param location Location of collision. [Post Condition] + @param inside Does the ray originate inside the box? [Post Condition] @return True if the ray hits the box */ @@ -663,194 +663,194 @@ public: bool& inside); /** - Calculates time between the intersection of a moving point and a fixed - sphere. + Calculates time between the intersection of a moving point and a fixed + sphere. - @note When ray is starts inside the rectangle, the exiting intersection - is detected. + @note When ray is starts inside the rectangle, the exiting intersection + is detected. - @param point Moving point. - @param velocity Point's velocity. - @param sphere Fixed Sphere. - @param outLocation Location of collision. [Post Condition] - @param outNormal Sphere's surface normal to collision [Post Condition] + @param point Moving point. + @param velocity Point's velocity. + @param sphere Fixed Sphere. + @param outLocation Location of collision. [Post Condition] + @param outNormal Sphere's surface normal to collision [Post Condition] \param solid If true, rays inside the sphere immediately intersect (good for collision detection). If false, they hit the opposite side of the sphere (good for ray tracing). - @return Time until collision. If there is no collision then the return - value will be inf(). - */ + @return Time until collision. If there is no collision then the return + value will be inf(). + */ static float collisionTimeForMovingPointFixedSphere( - const Vector3& point, - const Vector3& velocity, - const class Sphere& sphere, - Vector3& outLocation, + const Vector3& point, + const Vector3& velocity, + const class Sphere& sphere, + Vector3& outLocation, Vector3& outNormal = ignore, bool solid = false); /** - Calculates time between the intersection of a moving point and a fixed - box. + Calculates time between the intersection of a moving point and a fixed + box. - @note If the point is already inside the box, no collision: inf is returned. + @note If the point is already inside the box, no collision: inf is returned. - @param point Moving point. - @param velocity Sphere's velocity. - @param box Fixed box. - @param location Position of collision. [Post Condition] - @param outNormal Box's surface normal to collision [Post Condition] + @param point Moving point. + @param velocity Sphere's velocity. + @param box Fixed box. + @param outLocation Position of collision. [Post Condition] + @param outNormal Box's surface normal to collision [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ static float collisionTimeForMovingPointFixedBox( - const Vector3& point, - const Vector3& velocity, - const class Box& box, - Vector3& outLocation, + const Vector3& point, + const Vector3& velocity, + const class Box& box, + Vector3& outLocation, Vector3& outNormal = ignore); - /** - Calculates time between the intersection of a moving point and a fixed - rectangle defined by the points v0, v1, v2, & v3. + /** + Calculates time between the intersection of a moving point and a fixed + rectangle defined by the points v0, v1, v2, & v3. - @note This is only a one sided collision test. The side defined by - the rectangle's surface normal is the only one tested. For a two sided - collision, call the function once for each side's surface normal. + @note This is only a one sided collision test. The side defined by + the rectangle's surface normal is the only one tested. For a two sided + collision, call the function once for each side's surface normal. - @param point Moving point. - @param velocity Sphere's velocity. - @param v0 Rectangle vertex 1. - @param v1 Rectangle vertex 2. - @param v2 Rectangle vertex 3 - @param v3 Rectangle vertex 4. - @param location Location of collision [Post Condition] - @param outNormal Rectangle's surface normal. [Post Condition] + @param point Moving point. + @param velocity Sphere's velocity. + @param v0 Rectangle vertex 1. + @param v1 Rectangle vertex 2. + @param v2 Rectangle vertex 3 + @param v3 Rectangle vertex 4. + @param outLocation Location of collision [Post Condition] + @param outNormal Rectangle's surface normal. [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ static float collisionTimeForMovingPointFixedRectangle( - const Vector3& point, - const Vector3& velocity, - const Vector3& v0, - const Vector3& v1, - const Vector3& v2, - const Vector3& v3, - Vector3& outLocation, + const Vector3& point, + const Vector3& velocity, + const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& v3, + Vector3& outLocation, Vector3& outNormal = ignore); - /** - Calculates time between the intersection of a moving point and a fixed - capsule. + /** + Calculates time between the intersection of a moving point and a fixed + capsule. - @param point Moving point. - @param velocity Point's velocity. - @param capsule Fixed capsule. - @param outLocation Location of collision. [Post Condition] - @param outNormal Capsule's surface normal to collision [Post Condition] + @param point Moving point. + @param velocity Point's velocity. + @param capsule Fixed capsule. + @param outLocation Location of collision. [Post Condition] + @param outNormal Capsule's surface normal to collision [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ - static float collisionTimeForMovingPointFixedCapsule( - const Vector3& point, - const Vector3& velocity, - const class Capsule& capsule, - Vector3& outLocation, + @return Time til collision. If there is no collision then the return + value will be inf(). + */ + static float collisionTimeForMovingPointFixedCapsule( + const Vector3& point, + const Vector3& velocity, + const class Capsule& capsule, + Vector3& outLocation, Vector3& outNormal = ignore); - /** - Calculates time between the intersection of a moving sphere and a fixed - triangle. + /** + Calculates time between the intersection of a moving sphere and a fixed + triangle. - @param sphere Moving sphere. - @param velocity Sphere's velocity. - @param plane Fixed Plane. - @param outLocation Location of collision -- not center position of sphere - at the collision time. [Post Condition] - @param outNormal Box's surface normal to collision [Post Condition] + @param sphere Moving sphere. + @param velocity Sphere's velocity. + @param plane Fixed Plane. + @param outLocation Location of collision -- not center position of sphere + at the collision time. [Post Condition] + @param outNormal Box's surface normal to collision [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ static float collisionTimeForMovingSphereFixedPlane( - const class Sphere& sphere, - const Vector3& velocity, - const class Plane& plane, - Vector3& outLocation, + const class Sphere& sphere, + const Vector3& velocity, + const class Plane& plane, + Vector3& outLocation, Vector3& outNormal = ignore); - /** - Calculates time between the intersection of a moving sphere and a fixed - triangle. + /** + Calculates time between the intersection of a moving sphere and a fixed + triangle. - @param sphere Moving sphere. - @param velocity Sphere's velocity. - @param triangle Fixed Triangle. (collisions can happen on the back side of the triangle) - @param outLocation Location of collision, if collision occurs -- not center position of sphere - at the collision time. If there is interpenetration at the start, this point may be inside + @param sphere The moving sphere. + @param velocity The sphere's velocity. + @param triangle Single-sided fixed triangle. + @param outLocation Location of collision, if collision occurs -- not center position of sphere + at the collision time. If there is interpenetration at the start, this point may be inside the sphere. @param b Barycentric coordinates. These are not valid unless collision occurs. - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time until collision. If there is no collision then the return + value will be finf(). + */ static float collisionTimeForMovingSphereFixedTriangle( - const class Sphere& sphere, - const Vector3& velocity, + const class Sphere& sphere, + const Vector3& velocity, const Triangle& triangle, - Vector3& outLocation, + Vector3& outLocation, float b[3] = (float*)&ignore); - /** - Calculates time between the intersection of a moving sphere and a fixed - rectangle defined by the points v0, v1, v2, & v3. + /** + Calculates time between the intersection of a moving sphere and a fixed + rectangle defined by the points v0, v1, v2, & v3. - @param sphere Moving sphere. - @param velocity Sphere's velocity. - @param v0 Rectangle vertex 1. - @param v1 Rectangle vertex 2. - @param v2 Rectangle vertex 3 - @param v3 Rectangle vertex 4. - @param outLocation Location of collision -- not center position of sphere - at the collision time. [Post Condition] - @param outNormal Box's surface normal to collision [Post Condition] + @param sphere Moving sphere. + @param velocity Sphere's velocity. + @param v0 Rectangle vertex 1. + @param v1 Rectangle vertex 2. + @param v2 Rectangle vertex 3 + @param v3 Rectangle vertex 4. + @param outLocation Location of collision -- not center position of sphere + at the collision time. [Post Condition] + @param outNormal Box's surface normal to collision [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ static float collisionTimeForMovingSphereFixedRectangle( - const class Sphere& sphere, - const Vector3& velocity, - const Vector3& v0, - const Vector3& v1, - const Vector3& v2, - const Vector3& v3, - Vector3& outLocation, + const class Sphere& sphere, + const Vector3& velocity, + const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& v3, + Vector3& outLocation, Vector3& outNormal = ignore); - /** - Calculates time between the intersection of a moving sphere and a fixed - box. + /** + Calculates time between the intersection of a moving sphere and a fixed + box. - @note This function will not detect an intersection between a moving object - that is already interpenetrating the fixed object. + @note This function will not detect an intersection between a moving object + that is already interpenetrating the fixed object. - @param sphere Moving sphere. - @param velocity Sphere's velocity. - @param box Fixed box. - @param location Location of collision -- not center position of sphere - at the collision time. [Post Condition] - @param outNormal Box's surface normal to collision [Post Condition] + @param sphere Moving sphere. + @param velocity Sphere's velocity. + @param box Fixed box. + @param outLocation Location of collision -- not center position of sphere + at the collision time. [Post Condition] + @param outNormal Box's surface normal to collision [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ + @return Time til collision. If there is no collision then the return + value will be inf(). + */ static float collisionTimeForMovingSphereFixedBox( - const class Sphere& sphere, - const Vector3& velocity, - const class Box& box, - Vector3& outLocation, + const class Sphere& sphere, + const Vector3& velocity, + const class Box& box, + Vector3& outLocation, Vector3& outNormal = ignore); /** Calculates time between the intersection of a moving sphere @@ -860,199 +860,199 @@ public: location is the closest point on the surface of the fixed sphere to the center of the moving sphere. - @param sphere Moving sphere. + @param sphere Moving sphere. @param velocity Sphere's velocity. - @param fixedSphere Fixed Sphere. - @param outLocation Location of collision -- not center position of sphere + @param fixedSphere Fixed Sphere. + @param outLocation Location of collision -- not center position of sphere at the collision time. [Post Condition] - @param outNormal Moving sphere's surface normal to collision [Post Condition] + @param outNormal Moving sphere's surface normal to collision [Post Condition] @return Time until collision. If there is no collision then the return value will be inf(). */ static float collisionTimeForMovingSphereFixedSphere( - const Sphere& sphere, - const Vector3& velocity, - const Sphere& fixedSphere, - Vector3& outLocation, + const Sphere& sphere, + const Vector3& velocity, + const Sphere& fixedSphere, + Vector3& outLocation, Vector3& outNormal = ignore); /** - Calculates time between the intersection of a moving sphere and a fixed - capsule. + Calculates time between the intersection of a moving sphere and a fixed + capsule. - @note This won't detect a collision if the sphere is already - interpenetrating the capsule. + @note This won't detect a collision if the sphere is already + interpenetrating the capsule. - @param sphere Moving sphere. - @param velocity Sphere's velocity. - @param capsule Fixed capsule. - @param location Location of collision -- not center position of sphere - at the collision time. [Post Condition] - @param outNormal Capsule's surface normal to the collision [Post Condition] + @param sphere Moving sphere. + @param velocity Sphere's velocity. + @param capsule Fixed capsule. + @param outLocation Location of collision -- not center position of sphere + at the collision time. [Post Condition] + @param outNormal Capsule's surface normal to the collision [Post Condition] - @return Time til collision. If there is no collision then the return - value will be inf(). - */ - static float collisionTimeForMovingSphereFixedCapsule( - const class Sphere& sphere, - const Vector3& velocity, - const class Capsule& capsule, - Vector3& outLocation, + @return Time til collision. If there is no collision then the return + value will be inf(). + */ + static float collisionTimeForMovingSphereFixedCapsule( + const class Sphere& sphere, + const Vector3& velocity, + const class Capsule& capsule, + Vector3& outLocation, Vector3& outNormal = ignore); /** - Finds the direction of bounce that a sphere would have when it - intersects an object with the given time of collision, the - collision location and the collision normal. + Finds the direction of bounce that a sphere would have when it + intersects an object with the given time of collision, the + collision location and the collision normal. - @note This function works like a pong style ball bounce. + @note This function works like a pong style ball bounce. - @param sphere Moving sphere. - @param velocity Sphere's velocity. - @param collisionTime Time of collision. - @param collisionLocation Collision location. - @param collisionNormal Surface collision normal. + @param sphere Moving sphere. + @param velocity Sphere's velocity. + @param collisionTime Time of collision. + @param collisionLocation Collision location. + @param collisionNormal Surface collision normal. - @return Direction of bounce. - */ + @return Direction of bounce. + */ static Vector3 bounceDirection( - const class Sphere& sphere, - const Vector3& velocity, - const float collisionTime, - const Vector3& collisionLocation, + const class Sphere& sphere, + const Vector3& velocity, + const float collisionTime, + const Vector3& collisionLocation, const Vector3& collisionNormal); /** - Finds the direction of slide given a moving sphere, its velocity, the - time of collision and the collision location. This function works as - if the sphere intersects the surface and continues to hug it. + Finds the direction of slide given a moving sphere, its velocity, the + time of collision and the collision location. This function works as + if the sphere intersects the surface and continues to hug it. - @note The result will work well for calculating the movement of a player - who collides with an object and continues moving along the object instead - of just bouncing off it. + @note The result will work well for calculating the movement of a player + who collides with an object and continues moving along the object instead + of just bouncing off it. - @param sphere Moving sphere. - @param velocity Sphere's velocity. - @param collisionTime Time of collision - @param collisionLocation Collision location. + @param sphere Moving sphere. + @param velocity Sphere's velocity. + @param collisionTime Time of collision + @param collisionLocation Collision location. - @return Direction of slide. - */ + @return Direction of slide. + */ static Vector3 slideDirection( - const class Sphere& sphere, - const Vector3& velocity, - const float collisionTime, - const Vector3& collisionLocation); - - /** - Finds the closest point on a line segment to a given point. - - @param v0 line vertex 1. - @param v1 line vertex 2. - @param point External point. - - @return Closests point to point on the line segment. - */ - static Vector3 closestPointOnLineSegment( - const Vector3& v0, - const Vector3& v1, - const Vector3& point); + const class Sphere& sphere, + const Vector3& velocity, + const float collisionTime, + const Vector3& collisionLocation); /** - Finds the closest point on a line segment to a given point. + Finds the closest point on a line segment to a given point. - @note This is an optimization to closestPointOnLineSegment. Edge length - and direction can be used in this function if already pre-calculated. This - prevents doing the same work twice. + @param v0 line vertex 1. + @param v1 line vertex 2. + @param point External point. - @param v0 line vertex 0. - @param v1 line vertex 1. + @return Closests point to point on the line segment. + */ + static Vector3 closestPointOnLineSegment( + const Vector3& v0, + const Vector3& v1, + const Vector3& point); + + /** + Finds the closest point on a line segment to a given point. + + @note This is an optimization to closestPointOnLineSegment. Edge length + and direction can be used in this function if already pre-calculated. This + prevents doing the same work twice. + + @param v0 line vertex 0. + @param v1 line vertex 1. @param edgeDirection The direction of the segment (unit length). @param edgeLength The length of the segment. @param point External point. - @return Closests point to point on the line segment. - */ + @return Closests point to point on the line segment. + */ static Vector3 closestPointOnLineSegment( - const Vector3& v0, - const Vector3& v1, + const Vector3& v0, + const Vector3& v1, const Vector3& edgeDirection, float edgeLength, - const Vector3& point); + const Vector3& point); /** - Finds the closest point on the perimeter of the triangle to an external point; - given a triangle defined by three points v0, v1, & v2, and the external point. + Finds the closest point on the perimeter of the triangle to an external point; + given a triangle defined by three points v0, v1, & v2, and the external point. - @param v0 Triangle vertex 0. - @param v1 Triangle vertex 1. - @param v2 Triangle vertex 2. - @param point External point. + @param v0 Triangle vertex 0. + @param v1 Triangle vertex 1. + @param v2 Triangle vertex 2. + @param point External point. - @return Closests point to point on the perimeter of the - triangle. - */ + @return Closests point to point on the perimeter of the + triangle. + */ static Vector3 closestPointOnTrianglePerimeter( - const Vector3& v0, - const Vector3& v1, - const Vector3& v2, - const Vector3& point); + const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& point); - /** - Finds the closest point on the perimeter of the triangle to an external point; - given a triangle defined by the array of points v, its edge directions and - their lengths, as well as the external point. + /** + Finds the closest point on the perimeter of the triangle to an external point; + given a triangle defined by the array of points v, its edge directions and + their lengths, as well as the external point. - @note This is an optimization to closestPointToTrianglePerimeter. Edge length - and direction can be used in this function if already pre-calculated. This - prevents doing the same work twice. + @note This is an optimization to closestPointToTrianglePerimeter. Edge length + and direction can be used in this function if already pre-calculated. This + prevents doing the same work twice. - @param v Triangle vertices. - @param point External point. + @param v Triangle vertices. + @param point External point. @param edgeIndex The point lies on the edge between v[edgeIndex] and v[(edgeIndex + 1) % 3] - @return Closest point to point on the perimeter of the - triangle. - */ + @return Closest point to point on the perimeter of the + triangle. + */ static Vector3 closestPointOnTrianglePerimeter( const Vector3 v[3], const Vector3 edgeDirection[3], const float edgeLength[3], - const Vector3& point, + const Vector3& point, int& edgeIndex); /** - Tests whether a point is contained within the triangle defined by - v0, v1, and v2 and its plane's normal. + Tests whether a point is contained within the triangle defined by + v0, v1, and v2 and its plane's normal. - @param v0 Triangle vertex 0. - @param v1 Triangle vertex 1. - @param v2 Triangle vertex 2. - @param normal Normal to triangle's plane. - @param point The point in question. - @param primaryAxis Primary axis of triangle. This will be detected - if not given. This parameter is provided as an optimization. + @param v0 Triangle vertex 0. + @param v1 Triangle vertex 1. + @param v2 Triangle vertex 2. + @param normal Normal to triangle's plane. + @param point The point in question. + @param primaryAxis Primary axis of triangle. This will be detected + if not given. This parameter is provided as an optimization. @param b Barycentric coordinates; b[i] is the weight on v[i] - @return true - if point is inside the triangle. - @return false - otherwise - */ + @return true - if point is inside the triangle. + @return false - otherwise + */ static bool isPointInsideTriangle( - const Vector3& v0, - const Vector3& v1, - const Vector3& v2, - const Vector3& normal, + const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& normal, const Vector3& point, float b[3], Vector3::Axis primaryAxis = Vector3::DETECT_AXIS); inline static bool isPointInsideTriangle( - const Vector3& v0, - const Vector3& v1, - const Vector3& v2, - const Vector3& normal, - const Vector3& point, + const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& normal, + const Vector3& point, Vector3::Axis primaryAxis = Vector3::DETECT_AXIS) { float b[3]; @@ -1060,70 +1060,70 @@ public: } /** - Tests for the intersection of a moving sphere and a fixed box in a - given time limit. + Tests for the intersection of a moving sphere and a fixed box in a + given time limit. - @note Returns true if any part of the sphere is inside the box - during the time period (inf means "ever"). Useful for - performing bounding-box collision detection. + @note Returns true if any part of the sphere is inside the box + during the time period (inf means "ever"). Useful for + performing bounding-box collision detection. - @param sphere Moving sphere. - @param velocity Velocity of moving sphere. - @param box Fixed box. - @param timeLimit Time limit for intersection test. + @param sphere Moving sphere. + @param velocity Velocity of moving sphere. + @param box Fixed box. + @param timeLimit Time limit for intersection test. - @return true - if the two objects will touch. - @return false - if there is no intersection. - */ + @return true - if the two objects will touch. + @return false - if there is no intersection. + */ static bool movingSpherePassesThroughFixedBox( const Sphere& sphere, const Vector3& velocity, const Box& box, double timeLimit = inf()); - /** - Tests for the intersection of a moving sphere and a fixed sphere in a - given time limit. + /** + Tests for the intersection of a moving sphere and a fixed sphere in a + given time limit. - @note This function will not detect an intersection between a moving object - that is already interpenetrating the fixed object. + @note This function will not detect an intersection between a moving object + that is already interpenetrating the fixed object. - @param sphere Moving sphere. - @param velocity Velocity of moving sphere. - @param fixedSphere Fixed sphere. - @param timeLimit Time limit for intersection test. + @param sphere Moving sphere. + @param velocity Velocity of moving sphere. + @param fixedSphere Fixed sphere. + @param timeLimit Time limit for intersection test. - @return true - if the two spheres will touch. - @return false - if there is no intersection. - */ + @return true - if the two spheres will touch. + @return false - if there is no intersection. + */ static bool movingSpherePassesThroughFixedSphere( const Sphere& sphere, const Vector3& velocity, const Sphere& fixedSphere, double timeLimit = inf()); - /** - Tests for the intersection of two fixed spheres. + /** + Tests for the intersection of two fixed spheres. - @param sphere1 Fixed sphere 1. - @param sphere2 Fixed sphere 2. + @param sphere1 Fixed sphere 1. + @param sphere2 Fixed sphere 2. - @return true - if the two spheres touch. - @return false - if there is no intersection. - */ + @return true - if the two spheres touch. + @return false - if there is no intersection. + */ static bool fixedSolidSphereIntersectsFixedSolidSphere( const Sphere& sphere1, const Sphere& sphere2); - /** - Tests for the intersection of a fixed sphere and a fixed box. + /** + Tests for the intersection of a fixed sphere and a fixed box. - @param sphere Fixed sphere. - @param box Fixed box. + @param sphere Fixed sphere. + @param box Fixed box. - @return true - if the two objects touch. - @return false - if there is no intersection. - */ + @return true - if the two objects touch. + @return false - if there is no intersection. + */ static bool fixedSolidSphereIntersectsFixedSolidBox( const Sphere& sphere, const Box& box); @@ -1137,67 +1137,67 @@ public: const Triangle& triangle); /** - Tests whether a point is inside a rectangle defined by the vertexes - v0, v1, v2, & v3, and the rectangle's plane normal. + Tests whether a point is inside a rectangle defined by the vertexes + v0, v1, v2, & v3, and the rectangle's plane normal. - @param v0 Rectangle vertex 1. - @param v1 Rectangle vertex 2. - @param v2 Rectangle vertex 3. - @param v3 Rectangle vertex 4. - @param normal Normal to rectangle's plane. - @param point The point in question. + @param v0 Rectangle vertex 1. + @param v1 Rectangle vertex 2. + @param v2 Rectangle vertex 3. + @param v3 Rectangle vertex 4. + @param normal Normal to rectangle's plane. + @param point The point in question. - @return true - if point is inside the rectangle. - @return false - otherwise - */ + @return true - if point is inside the rectangle. + @return false - otherwise + */ static bool isPointInsideRectangle( - const Vector3& v0, - const Vector3& v1, - const Vector3& v2, - const Vector3& v3, - const Vector3& normal, - const Vector3& point); + const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& v3, + const Vector3& normal, + const Vector3& point); /** - Finds the closest point on the perimeter of the rectangle to an - external point; given a rectangle defined by four points v0, v1, - v2, & v3, and the external point. + Finds the closest point on the perimeter of the rectangle to an + external point; given a rectangle defined by four points v0, v1, + v2, & v3, and the external point. - @param v0 Rectangle vertex 1. - @param v1 Rectangle vertex 2. - @param v2 Rectangle vertex 3. - @param v3 Rectangle vertex 4. - @param point External point. + @param v0 Rectangle vertex 1. + @param v1 Rectangle vertex 2. + @param v2 Rectangle vertex 3. + @param v3 Rectangle vertex 4. + @param point External point. - @return Closests point to point on the perimeter of the - rectangle. - */ + @return Closests point to point on the perimeter of the + rectangle. + */ static Vector3 closestPointToRectanglePerimeter( - const Vector3& v0, - const Vector3& v1, - const Vector3& v2, - const Vector3& v3, - const Vector3& point); + const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& v3, + const Vector3& point); /** - Finds the closest point in the rectangle to an external point; Given - a rectangle defined by four points v0, v1, v2, & v3, and the external - point. + Finds the closest point in the rectangle to an external point; Given + a rectangle defined by four points v0, v1, v2, & v3, and the external + point. - @param v0 Rectangle vertex 1. - @param v1 Rectangle vertex 2. - @param v2 Rectangle vertex 3 - @param v3 Rectangle vertex 4. - @param point External point. + @param v0 Rectangle vertex 1. + @param v1 Rectangle vertex 2. + @param v2 Rectangle vertex 3 + @param v3 Rectangle vertex 4. + @param point External point. @return Closet point in the rectangle to the external point. - */ - static Vector3 closestPointToRectangle( - const Vector3& v0, - const Vector3& v1, - const Vector3& v2, - const Vector3& v3, - const Vector3& point); + */ + static Vector3 closestPointToRectangle( + const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& v3, + const Vector3& point); }; } // namespace diff --git a/deps/g3dlite/include/G3D/Color1.h b/deps/g3dlite/include/G3D/Color1.h index 0f68c84b3..6066fdcb7 100644 --- a/deps/g3dlite/include/G3D/Color1.h +++ b/deps/g3dlite/include/G3D/Color1.h @@ -1,30 +1,29 @@ /** - @file Color1.h + \file G3D/Color1.h Monochrome Color class - @maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2007-01-31 - @edited 2009-03-20 + \maintainer Morgan McGuire, http://graphics.cs.williams.edu + \created 2007-01-31 + \edited 2011-08-20 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ -#ifndef G3D_COLOR1_H -#define G3D_COLOR1_H +#ifndef G3D_Color1_h +#define G3D_Color1_h #include "G3D/platform.h" #include "G3D/g3dmath.h" +#include "G3D/unorm8.h" #include "G3D/HashTrait.h" #include namespace G3D { /** - Monochrome color. This is just a float, but it has nice semantics - because a scaling by 255 automatically occurs when switching between - fixed point (Color1uint8) and floating point (Color1) formats. + Monochrome color. */ class Color1 { private: @@ -46,6 +45,9 @@ public: inline explicit Color1(float v) : value(v) { } + + inline explicit Color1(unorm8 v) : value(v) { + } inline bool isZero() const { return value == 0.0f; @@ -62,7 +64,7 @@ public: /** Returns the value three times */ class Color3 rgb() const; - Color1 (const class Color1uint8& other); + explicit Color1(const class Color1unorm8& other); void serialize(class BinaryOutput& bo) const; void deserialize(class BinaryInput& bi); @@ -71,6 +73,7 @@ public: return Color1(value + other.value); } + /** \deprecated */ Color1 operator+ (const float other) const { return Color1(value + other); } @@ -89,6 +92,7 @@ public: return Color1(value - other.value); } + /** \deprecated */ Color1 operator- (const float other) const { return Color1(value - other); } @@ -101,6 +105,26 @@ public: return Color1(value * other.value); } + Color1& operator*=(const Color1 other) { + value *= other.value; + return *this; + } + + Color1& operator*=(const float other) { + value *= other; + return *this; + } + + Color1& operator/=(const float other) { + value /= other; + return *this; + } + + Color1& operator/=(const Color1 other) { + value /= other.value; + return *this; + } + Color1 operator* (const float other) const { return Color1(value * other); } @@ -140,5 +164,8 @@ struct HashTrait { } }; +inline G3D::Color1 operator*(float f, G3D::Color1 c) { + return c * f; +} #endif diff --git a/deps/g3dlite/include/G3D/Color3.h b/deps/g3dlite/include/G3D/Color3.h index bffe434fc..e5c0abcb2 100644 --- a/deps/g3dlite/include/G3D/Color3.h +++ b/deps/g3dlite/include/G3D/Color3.h @@ -1,16 +1,16 @@ /** - @file Color3.h + \file Color3.h Color class - @maintainer Morgan McGuire, http://graphics.cs.williams.edu - @cite Portions based on Dave Eberly's Magic Software Library + \maintainer Morgan McGuire, http://graphics.cs.williams.edu + \cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com - @created 2001-06-02 - @edited 2009-04-28 + \created 2001-06-02 + \edited 2013-03-29 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2013, Morgan McGuire. All rights reserved. */ @@ -40,26 +40,41 @@ private: public: /** - Does not initialize fields. + \brief Initializes to all zero. */ - Color3(); + Color3() : r(0), g(0), b(0) {} + + bool nonZero() const { + return (r != 0) || (g != 0) || (b != 0); + } /** \param any Must be in one of the following forms: - Color3(#, #, #) + - Color3(#) - Color3::fromARGB(#) + - Color3::fromASRGB(#) - Color3{r = #, g = #, b = #) - Color3::one() - Color3::zero() + + In the current implementation, G3D::Power3, G3D::Radiance3, + and G3D::Irradiance3 are typedefs for Color3, so Color3 + accepts "Power3" and "Radiance3" as a prefixes as well, e.g., + Power3(1,0,0). */ - Color3(const Any& any); + explicit Color3(const Any& any); + Color3& operator=(const Any& a); + /** Converts the Color3 to an Any. */ - operator Any() const; + Any toAny() const; explicit Color3(class BinaryInput& bi); Color3(float r, float g, float b); - Color3(float v) : r(v), g(v), b(v) {} + + /** \brief Initializes all channels to \a v */ + explicit Color3(float v) : r(v), g(v), b(v) {} explicit Color3(const class Vector3& v); @@ -75,7 +90,7 @@ public: */ Color3 (const Color3& other); - Color3 (const class Color3uint8& other); + Color3 (const class Color3unorm8& other); inline bool isZero() const { return (r == 0.0f) && (g == 0.0f) && (b == 0.0f); @@ -92,6 +107,12 @@ public: */ static Color3 fromARGB(uint32); + /** + Initialize from an HTML-style color (e.g. 0xFF0000 == RED) by converting from sRGB to RGB. + + */ + static Color3 fromASRGB(uint32); + /** Returns one of the color wheel colors (e.g. RED, GREEN, CYAN). Does not include white, black, or gray. */ static const Color3& wheelRandom(); @@ -140,10 +161,15 @@ public: inline Color3 operator* (float s) const { return Color3(r * s, g * s, b * s); } + inline Color3 operator/ (const Color3& rkVector) const { + return Color3(r / rkVector.r, g / rkVector.g, b / rkVector.b); + } + Color3 operator* (const Color3& rkVector) const; inline Color3 operator/ (float fScalar) const { return (*this) * (1.0f / fScalar); } + Color3 operator- () const; // arithmetic updates @@ -161,7 +187,7 @@ public: Color3 direction() const; float squaredLength () const; float dot (const Color3& rkVector) const; - float unitize (float fTolerance = 1e-06); + float unitize (float fTolerance = 1e-06f); Color3 cross (const Color3& rkVector) const; Color3 unitCross (const Color3& rkVector) const; @@ -258,11 +284,11 @@ inline G3D::Color3 operator* (const G3D::Color3& c, G3D::Color1& s) { return c * s.value; } - -//---------------------------------------------------------------------------- -inline Color3::Color3 () { +inline G3D::Color3 operator/ (float s, const G3D::Color3& c) { + return c * (1.0f/s); } + //---------------------------------------------------------------------------- inline Color3::Color3(float fX, float fY, float fZ) { @@ -414,11 +440,36 @@ inline Color3 Color3::cross (const Color3& rkVector) const { inline Color3 Color3::unitCross (const Color3& rkVector) const { Color3 kCross(g*rkVector.b - b*rkVector.g, b*rkVector.r - r*rkVector.b, r*rkVector.g - g*rkVector.r); - kCross.unitize(); - return kCross; + return kCross.direction(); } +/** Radiance * measure(Solid Angle) between two points, measured at the receiver orthogonal to the axis between them; W/m^2 */ +typedef Color3 Biradiance3; + +/** Power per (measure(SolidAngle) * measure(Area)); W / (m^2 sr) */ +typedef Color3 Radiance3; + +/** Power per area; J / m^2 */ +typedef Color3 Radiosity3; + +/** Force * distance; J */ +typedef Color3 Energy3; + +/** Incident power per area; W/m^2*/ +typedef Color3 Irradiance3; + +/** Energy per time; W*/ +typedef Color3 Power3; + +#if 0 // Disabled to avoid taking these useful names from the namespace +typedef float Power; +typedef float Biradiance; +typedef float Radiance; +typedef float Radiosity; +typedef float Energy; +typedef float Irradiance; +#endif } // namespace diff --git a/deps/g3dlite/include/G3D/Color4.h b/deps/g3dlite/include/G3D/Color4.h index 0be0c2587..424e3289d 100644 --- a/deps/g3dlite/include/G3D/Color4.h +++ b/deps/g3dlite/include/G3D/Color4.h @@ -48,16 +48,16 @@ public: Color4(const Any& any); /** Converts the Color4 to an Any. */ - operator Any() const; + Any toAny() const; /** - * Does not initialize fields. + Initializes to all zero */ - Color4 (); + Color4() : r(0), g(0), b(0), a(0) {} Color4(const Color3& c3, float a = 1.0); - Color4(const class Color4uint8& c); + Color4(const class Color4unorm8& c); Color4(class BinaryInput& bi); @@ -191,12 +191,6 @@ inline Color4 operator*(const Color3& c3, const Color4& c4) { //---------------------------------------------------------------------------- -inline Color4::Color4 () { - // For efficiency in construction of large arrays of vectors, the - // default constructor does not initialize the vector. -} - -//---------------------------------------------------------------------------- inline Color4::Color4(const Color3& c3, float a) { r = c3.r; diff --git a/deps/g3dlite/include/G3D/Cone.h b/deps/g3dlite/include/G3D/Cone.h index d801a9b34..f521dc4dc 100644 --- a/deps/g3dlite/include/G3D/Cone.h +++ b/deps/g3dlite/include/G3D/Cone.h @@ -61,6 +61,19 @@ public: True if v is a point inside the cone. */ bool contains(const class Vector3& v) const; + + + /** Returns the solid angle (in steradians) subtended by a cone with half-angle \a halfAngle */ + static float solidAngleFromHalfAngle(float halfAngle); + static double solidAngleFromHalfAngle(double halfAngle); + + /** Returns the half-angle (in radians) of a cone that subtends \a solidAngle (in steradians) */ + static float halfAngleFromSolidAngle(float solidAngle); + static double halfAngleFromSolidAngle(double solidAngle); + + + Vector3 randomDirectionInCone(Random& rng) const; + }; } // namespace diff --git a/deps/g3dlite/include/G3D/ConvexPolyhedron.h b/deps/g3dlite/include/G3D/ConvexPolyhedron.h index a6fdd62cf..ea38c02ba 100644 --- a/deps/g3dlite/include/G3D/ConvexPolyhedron.h +++ b/deps/g3dlite/include/G3D/ConvexPolyhedron.h @@ -34,7 +34,7 @@ private: friend class ConvexPolyhedron; - Array _vertex; + Array _vertex; public: diff --git a/deps/g3dlite/include/G3D/CoordinateFrame.h b/deps/g3dlite/include/G3D/CoordinateFrame.h index c83754abb..a2cc1f1a2 100644 --- a/deps/g3dlite/include/G3D/CoordinateFrame.h +++ b/deps/g3dlite/include/G3D/CoordinateFrame.h @@ -1,12 +1,12 @@ /** - @file CoordinateFrame.h + \file G3D/CoordinateFrame.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2001-03-04 - @edited 2009-04-29 + \created 2001-03-04 + \edited 2012-07-29 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ @@ -33,9 +33,10 @@ namespace G3D { class Any; +class Frustum; /** - A rigid body RT (rotation-translation) transformation. +\brief A rigid body RT (rotation-translation) transformation. CoordinateFrame abstracts a 4x4 matrix that maps object space to world space: @@ -53,28 +54,28 @@ Convert to Matrix4 using CoordinateFrame::toMatrix4. You can construct a from a Matrix4 using Matrix4::approxCoordinateFrame, however, because a Matrix4 is more general than a CoordinateFrame, some information may be lost. -@sa G3D::UprightFrame, G3D::PhysicsFrame, G3D::Matrix4, G3D::Quat +\sa G3D::UprightFrame, G3D::PhysicsFrame, G3D::Matrix4, G3D::Quat */ class CoordinateFrame { public: /** Takes object space points to world space. */ - Matrix3 rotation; + Matrix3 rotation; - /** Takes object space points to world space. */ - Vector3 translation; + /** The origin of this coordinate frame in world space (or its parent's space, if nested). */ + Point3 translation; /** \param any Must be in one of the following forms: - - CFrame((matrix3 expr), (vector3 expr)) + - CFrame((matrix3 expr), (Point3 expr)) - CFrame::fromXYZYPRDegrees(#, #, #, #, #, #) - - CFrame { rotation = (matrix3 expr), translation = (vector3 expr) } - - Vector3( ... ) + - CFrame { rotation = (Matrix3 expr), translation = (Point3 expr) } + - Point3( ... ) - Matrix3( ... ) */ CoordinateFrame(const Any& any); /** Converts the CFrame to an Any. */ - operator Any() const; + Any toAny() const; inline bool operator==(const CoordinateFrame& other) const { return (translation == other.translation) && (rotation == other.rotation); @@ -95,16 +96,16 @@ public: */ CoordinateFrame(); - CoordinateFrame(const Vector3& _translation) : + CoordinateFrame(const Point3& _translation) : rotation(Matrix3::identity()), translation(_translation) { } - CoordinateFrame(const Matrix3 &rotation, const Vector3 &translation) : + CoordinateFrame(const Matrix3& rotation, const Point3& translation) : rotation(rotation), translation(translation) { } - CoordinateFrame(const Matrix3 &rotation) : - rotation(rotation), translation(Vector3::zero()) { + CoordinateFrame(const Matrix3& rotation) : + rotation(rotation), translation(Point3::zero()) { } CoordinateFrame(const class UprightFrame& f); @@ -187,26 +188,25 @@ public: /** Transforms the point into world space. */ - inline Vector3 pointToWorldSpace(const Vector3& v) const { - return Vector3( - rotation[0][0] * v[0] + rotation[0][1] * v[1] + rotation[0][2] * v[2] + translation[0], - rotation[1][0] * v[0] + rotation[1][1] * v[1] + rotation[1][2] * v[2] + translation[1], - rotation[2][0] * v[0] + rotation[2][1] * v[1] + rotation[2][2] * v[2] + translation[2]); + inline Point3 pointToWorldSpace(const Point3& v) const { + return Point3 + (rotation[0][0] * v[0] + rotation[0][1] * v[1] + rotation[0][2] * v[2] + translation[0], + rotation[1][0] * v[0] + rotation[1][1] * v[1] + rotation[1][2] * v[2] + translation[1], + rotation[2][0] * v[0] + rotation[2][1] * v[1] + rotation[2][2] * v[2] + translation[2]); } /** Transforms the point into object space. Assumes that the rotation matrix is orthonormal. */ - inline Vector3 pointToObjectSpace(const Vector3& v) const { + inline Point3 pointToObjectSpace(const Point3& v) const { float p[3]; p[0] = v[0] - translation[0]; p[1] = v[1] - translation[1]; p[2] = v[2] - translation[2]; - debugAssert(G3D::fuzzyEq(rotation.determinant(), 1.0f)); - return Vector3( - rotation[0][0] * p[0] + rotation[1][0] * p[1] + rotation[2][0] * p[2], - rotation[0][1] * p[0] + rotation[1][1] * p[1] + rotation[2][1] * p[2], - rotation[0][2] * p[0] + rotation[1][2] * p[1] + rotation[2][2] * p[2]); + debugAssert(G3D::fuzzyEq(fabsf(rotation.determinant()), 1.0f)); + return Point3(rotation[0][0] * p[0] + rotation[1][0] * p[1] + rotation[2][0] * p[2], + rotation[0][1] * p[0] + rotation[1][1] * p[1] + rotation[2][1] * p[2], + rotation[0][2] * p[0] + rotation[1][2] * p[1] + rotation[2][2] * p[2]); } /** @@ -224,6 +224,8 @@ public: Ray toWorldSpace(const Ray& r) const; + Frustum toWorldSpace(const Frustum& f) const; + /** Transforms the vector into object space (no translation). */ @@ -237,18 +239,20 @@ public: return v * rotation; } - void pointToWorldSpace(const Array& v, Array& vout) const; + void pointToWorldSpace(const Array& v, Array& vout) const; void normalToWorldSpace(const Array& v, Array& vout) const; void vectorToWorldSpace(const Array& v, Array& vout) const; - void pointToObjectSpace(const Array& v, Array& vout) const; + void pointToObjectSpace(const Array& v, Array& vout) const; void normalToObjectSpace(const Array& v, Array& vout) const; void vectorToObjectSpace(const Array& v, Array& vout) const; + void toWorldSpace(const class AABox& b, class AABox& result) const; + class Box toWorldSpace(const class AABox& b) const; class Box toWorldSpace(const class Box& b) const; @@ -260,7 +264,7 @@ public: class Plane toWorldSpace(const class Plane& p) const; class Sphere toWorldSpace(const class Sphere& b) const; - + class Triangle toWorldSpace(const class Triangle& t) const; class Box toObjectSpace(const AABox& b) const; @@ -287,17 +291,32 @@ public: return CoordinateFrame(rotation, translation - v); } - void lookAt(const Vector3& target); - void lookAt( - const Vector3& target, - Vector3 up); + /** + Transform this coordinate frame towards \a goal, but not past it, goverened by maximum + rotation and translations. This is a useful alternative to \a lerp, especially if the + goal is expected to change every transformation step so that constant start and end positions will + not be available. + + \param goal Step from this towards goal + \param maxTranslation Meters + \param maxRotation Radians + + \sa lerp + */ + void moveTowards(const CoordinateFrame& goal, float maxTranslation, float maxRotation); + + void lookAt(const Point3& target); + + void lookAt + (const Point3& target, + Vector3 up); /** The direction this camera is looking (its negative z axis)*/ - inline Vector3 lookVector() const { - return -rotation.column(2); - } - + inline Vector3 lookVector() const { + return -rotation.column(2); + } + /** Returns the ray starting at the camera origin travelling in direction CoordinateFrame::lookVector. */ class Ray lookRay() const; @@ -307,24 +326,26 @@ public: } inline Vector3 rightVector() const { - return rotation.column(0); - } + return rotation.column(0); + } /** If a viewer looks along the look vector, this is the viewer's "left". Useful for strafing motions and building alternative coordinate frames. */ inline Vector3 leftVector() const { - return -rotation.column(0); + return -rotation.column(0); } /** Linearly interpolates between two coordinate frames, using Quat::slerp for the rotations. + + \sa moveTowards */ - CoordinateFrame lerp( - const CoordinateFrame& other, - float alpha) const; + CoordinateFrame lerp + (const CoordinateFrame& other, + float alpha) const; }; diff --git a/deps/g3dlite/include/G3D/Crypto.h b/deps/g3dlite/include/G3D/Crypto.h index 56c816a49..d5c6f42ed 100644 --- a/deps/g3dlite/include/G3D/Crypto.h +++ b/deps/g3dlite/include/G3D/Crypto.h @@ -1,18 +1,19 @@ /** - @file Crypto.h + \file G3D/Crypto.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2006-03-29 - @edited 2006-04-06 + \created 2006-03-29 + \edited 2011-06-21 */ -#ifndef G3D_CRYPTO_H -#define G3D_CRYPTO_H +#ifndef G3D_Crypto_h +#define G3D_Crypto_h #include "G3D/platform.h" #include "G3D/g3dmath.h" +#include "G3D/System.h" #include namespace G3D { @@ -33,6 +34,24 @@ public: explicit MD5Hash(class BinaryInput& b); + /** Rotates the bytes once */ + void rotateBytes() { + uint8 temp = value[0]; + for (int i = 0; i < 15; ++i) { + value[i] = value[i + 1]; + } + value[15] = temp; + } + + /** Rotates by n bytes */ + void rotateBytes(int n) { + uint8 temp[16]; + System::memcpy(temp, value, 16); + for (int i = 0; i < 16; ++i) { + value[i] = value[(i + n) & 15]; + } + } + uint8& operator[](int i) { return value[i]; } @@ -56,6 +75,18 @@ public: void deserialize(class BinaryInput& b); void serialize(class BinaryOutput& b) const; + + static size_t hashCode(const MD5Hash& key) { + size_t h = 0; + for (int i = 0; i < 4; ++i) { + const int x = i * 4; + h ^= (((uint32)key.value[x + 0]) << 24) | + (((uint32)key.value[x + 1]) << 16) | + (((uint32)key.value[x + 2]) << 8) | + ((uint32)key.value[x + 3]); + } + return h; + } }; @@ -79,7 +110,7 @@ public: @cite Based on implementation by L. Peter Deutsch, ghost@aladdin.com */ - MD5Hash md5(const void* bytes, size_t numBytes); + static MD5Hash md5(const void* bytes, size_t numBytes); /** Returns the nth prime less than 2000 in constant time. The first prime has index diff --git a/deps/g3dlite/include/G3D/Cylinder.h b/deps/g3dlite/include/G3D/Cylinder.h index 85eba77b7..ef049e108 100644 --- a/deps/g3dlite/include/G3D/Cylinder.h +++ b/deps/g3dlite/include/G3D/Cylinder.h @@ -26,22 +26,22 @@ class AABox; */ class Cylinder { private: - Vector3 p1; - Vector3 p2; + Vector3 p1; + Vector3 p2; - float mRadius; + float mRadius; public: /** Uninitialized */ Cylinder(); Cylinder(class BinaryInput& b); - Cylinder(const Vector3& _p1, const Vector3& _p2, float _r); - void serialize(class BinaryOutput& b) const; - void deserialize(class BinaryInput& b); - - /** The line down the center of the Cylinder */ - Line axis() const; + Cylinder(const Vector3& _p1, const Vector3& _p2, float _r); + void serialize(class BinaryOutput& b) const; + void deserialize(class BinaryInput& b); + + /** The line down the center of the Cylinder */ + Line axis() const; /** A reference frame in which the center of mass is at the origin and diff --git a/deps/g3dlite/include/G3D/FileNotFound.h b/deps/g3dlite/include/G3D/FileNotFound.h new file mode 100644 index 000000000..dc756f329 --- /dev/null +++ b/deps/g3dlite/include/G3D/FileNotFound.h @@ -0,0 +1,32 @@ +/** + \file FileNotFound.h + + \maintainer Morgan McGuire, http://graphics.cs.williams.edu + \created 2011-12-31 + \edited 2011-12-31 + */ +#ifndef G3D_FileNotFound_h +#define G3D_FileNotFound_h + +#include "G3D/platform.h" +#include + +namespace G3D { + +/** Thrown by various file opening routines if the file is not found. + + \sa ParseError, System::findDataFile +*/ +class FileNotFound { +public: + std::string filename; + std::string message; + + FileNotFound() {} + FileNotFound(const std::string& f, const std::string& m) : filename(f), message(m) {} + virtual ~FileNotFound(){}; +}; + +} // G3D + +#endif diff --git a/deps/g3dlite/include/G3D/FileSystem.h b/deps/g3dlite/include/G3D/FileSystem.h index b2a6e8652..ae3239d9d 100644 --- a/deps/g3dlite/include/G3D/FileSystem.h +++ b/deps/g3dlite/include/G3D/FileSystem.h @@ -1,10 +1,10 @@ /** - @file FileSystem.h + \file FileSystem.h - @author Morgan McGuire, http://graphics.cs.williams.edu + \author Morgan McGuire, http://graphics.cs.williams.edu - @author 2002-06-06 - @edited 2010-02-05 + \author 2002-06-06 + \edited 2012-03-26 */ #ifndef G3D_FileSystem_h #define G3D_FileSystem_h @@ -12,6 +12,8 @@ #include "G3D/platform.h" #include "G3D/Array.h" #include "G3D/Table.h" +#include "G3D/Set.h" +#include "G3D/GMutex.h" namespace G3D { @@ -34,11 +36,12 @@ namespace G3D {
  • There are no nested zipfiles + All FileSystem routines invoke FilePath::expandEnvironmentVariables if the input contains a '$'. + The extension requirement allows G3D to quickly identify whether a path could enter a zipfile without forcing it to open all parent directories for reading. \sa FilePath - TODO: make threadsafe! */ class FileSystem { public: @@ -63,7 +66,7 @@ public: ListSettings() : files(true), directories(true), -# ifdef G3D_WIN32 +# ifdef G3D_WINDOWS caseSensitive(true), # else caseSensitive(false), @@ -111,8 +114,13 @@ private: /** When this entry was last updated */ double lastChecked; - /** Case-independent comparison on Windows */ - bool contains(const std::string& child) const; + bool contains(const std::string& child, bool caseSensitive = +#ifdef G3D_WINDOWS + false +#else + true +#endif +) const; /** Compute the contents of nodeArray from this zipfile. */ void computeZipListing(const std::string& zipfile, const std::string& pathInsideZipfile); @@ -132,116 +140,80 @@ private: FileSystem(); static FileSystem& instance(); + static GMutex mutex; -# ifdef G3D_WIN32 - /** On Windows, the drive letters that form the file system roots.*/ + +# ifdef G3D_WINDOWS + /** \copydoc drives */ const Array& _drives(); # endif - /** Returns true if some sub-path of \a path is a zipfile. - - If the path itself is a zipfile, returns false. - - \param zipfile The part of \a path that was the zipfile */ + /** \copydoc inZipfile */ bool _inZipfile(const std::string& path, std::string& zipfile); - /** Clears old cache entries so that exists() and list() will reflect recent changes to the file system. - \param path Clear only \a path and its subdirectories ("" means clear the entire cache) */ + /** \copydoc clearCache */ void _clearCache(const std::string& path); + /** \copydoc inZipfile */ bool _inZipfile(const std::string& path) { std::string ignore; return inZipfile(path, ignore); } - /** Set the cacheLifetime(). - \param t in seconds */ + /** \copydoc setCacheLifetime */ void _setCacheLifetime(float t); - /** A cache is used to optimize repeated calls. A cache entry is considered - valid for this many seconds after it has been checked. */ + /** \copydoc cacheLifetime */ float _cacheLifetime() const { return m_cacheLifetime; } - /** Creates the directory named, including any subdirectories - that do not already exist. - - The directory must not be inside a zipfile. - - Flushes the cache. - */ + /** \copydoc createDirectory */ void _createDirectory(const std::string& path); - /** Returns true if a node named \a f exists. + /** \copydoc exists */ + bool _exists(const std::string& f, bool trustCache = true, bool caseSensitive = +#ifdef G3D_WINDOWS + false +#else + true +#endif + ); - \param f If \a f contains wildcards, the function returns true if any file - matches those wildcards. Wildcards may only appear in the base or ext, not the - path. - - \param trustCache If true, uses the cache for optimizing repeated calls - in the same parent directory. - */ - bool _exists(const std::string& f, bool trustCache = true); - - /** Known bug: does not work inside zipfiles */ + /** \copydoc isDirectory */ bool _isDirectory(const std::string& path); - /** Known bug: does not work inside zipfiles */ + /** \copydoc isFile */ bool _isFile(const std::string& path) { return ! isDirectory(path); } - /** - \param srcPath Must name a file. - \param dstPath Must not contain a zipfile. - - Flushes the cache. - */ + /** \copydoc copyFile */ void _copyFile(const std::string& srcPath, const std::string& dstPath); - /** Fully qualifies a filename. - - The filename may contain wildcards, in which case the wildcards will be preserved in the returned value. - - \param cwd The directory to treat as the "current" directory when resolving a relative path. The default - value is the actual current directory. (G3D::Any::sourceDirectory is a common alternative) - */ + /** \copydoc resolve */ std::string _resolve(const std::string& path, const std::string& cwd = currentDirectory()); - /** Returns true if \param dst does not exist or \param src is newer than \param dst, - according to their time stamps. - - Known bug: does not work inside zipfiles. - */ + /** \copydoc isNewer */ bool _isNewer(const std::string& src, const std::string& dst); - /** The current working directory (cwd). Only ends in a slash if this is the root of the file system. */ + /** \copydoc currentDirectory */ std::string _currentDirectory(); - /** Returns the length of the file in bytes, or -1 if the file could not be opened. */ + /** \copydoc size */ int64 _size(const std::string& path); /** Called from list() */ void listHelper(const std::string& shortSpec, const std::string& parentPath, Array& result, const ListSettings& settings); - /** Appends all nodes matching \a spec to the \a result array. - - Wildcards can only appear to the right of the last slash in \a spec. - - The names will not contain parent paths unless \a includePath == true. - These may be relative to the current directory unless \a spec - is fully qualified (can be done with resolveFilename). - - */ + /** \copydoc list */ void _list(const std::string& spec, Array& result, const ListSettings& listSettings = ListSettings()); - /** Returns true if \a path is a file that is a zipfile. Note that G3D requires zipfiles to have - some extension, although it is not required to be "zip" */ + /** \copydoc isZipfile */ bool _isZipfile(const std::string& path); - /** list() files */ + /** \copydoc getFiles */ void _getFiles(const std::string& spec, Array& result, bool includeParentPath = false) { ListSettings set; set.includeParentPath = includeParentPath; @@ -250,7 +222,7 @@ private: return list(spec, result, set); } - /** list() directories */ + /** \copydoc getDirectories */ void _getDirectories(const std::string& spec, Array& result, bool includeParentPath = false) { ListSettings set; set.includeParentPath = includeParentPath; @@ -259,12 +231,13 @@ private: return list(spec, result, set); } - /** Same as the C standard library fopen, but updates the file cache - to acknowledge the new file on a write operation. */ + /** \copydoc fopen */ FILE* _fopen(const char* filename, const char* mode); -public: + /** \copydoc removeFile */ + void _removeFile(const std::string& path); +public: /** Create the common instance. */ static void init(); @@ -272,111 +245,267 @@ public: /** Destroy the common instance. */ static void cleanup(); -# ifdef G3D_WIN32 - /** \copydoc _drives */ +# ifdef G3D_WINDOWS + /** On Windows, the drive letters that form the file system roots.*/ static const Array& drives() { - return instance()._drives(); + mutex.lock(); + const Array& s = instance()._drives(); + mutex.unlock(); + return s; } # endif - /** \copydoc _inZipfile */ + /** Returns true if some sub-path of \a path is a zipfile. + + If the path itself is a zipfile, returns false. + + \param zipfile The part of \a path that was the zipfile + */ static bool inZipfile(const std::string& path, std::string& zipfile) { - return instance()._inZipfile(path, zipfile); + mutex.lock(); + bool b = instance()._inZipfile(path, zipfile); + mutex.unlock(); + return b; } - /** \copydoc _clearCache */ + /** Clears old cache entries so that exists() and list() will reflect recent changes to the file system. + \param path Clear only \a path and its subdirectories ("" means clear the entire cache) */ static void clearCache(const std::string& path = "") { + mutex.lock(); instance()._clearCache(path); + mutex.unlock(); } - /** \copydoc _fopen */ + + /** Same as the C standard library fopen, but updates the file cache + to acknowledge the new file on a write operation. */ static FILE* fopen(const char* filename, const char* mode) { - return instance()._fopen(filename, mode); + mutex.lock(); + FILE* f = instance()._fopen(filename, mode); + mutex.unlock(); + return f; } + static void fclose(FILE* f) { + mutex.lock(); ::fclose(f); + mutex.unlock(); } + /** Returns true if some sub-path of \a path is a zipfile. + + If the path itself is a zipfile, returns false. + */ static bool inZipfile(const std::string& path) { - return instance()._inZipfile(path); + mutex.lock(); + bool b = instance()._inZipfile(path); + mutex.unlock(); + return b; } - /** \copydoc isZipfile */ + + /** + \brief Delete this file. + No effect if \a path does not exist. + + \param path May contain wildcards. May not be inside a zipfile. + */ + static void removeFile(const std::string& path) { + mutex.lock(); + instance()._removeFile(path); + mutex.unlock(); + } + + + /** Returns true if \a path is a file that is a zipfile. Note that G3D requires zipfiles to have + some extension, although it is not required to be "zip" */ static bool isZipfile(const std::string& path) { - return instance()._isZipfile(path); + mutex.lock(); + bool b = instance()._isZipfile(path); + mutex.unlock(); + return b; } - /** \copydoc _setCacheLifetime */ + + /** Set the cacheLifetime(). + \param t in seconds */ void setCacheLifetime(float t) { + mutex.lock(); instance()._setCacheLifetime(t); + mutex.unlock(); } - /** \copydoc _cacheLifetime */ + /** A cache is used to optimize repeated calls. A cache entry is considered + valid for this many seconds after it has been checked. */ static float cacheLifetime() { - return instance()._cacheLifetime(); + mutex.lock(); + float f = instance()._cacheLifetime(); + mutex.unlock(); + return f; } - /** \copydoc _createDirectory */ + + /** Creates the directory named, including any subdirectories + that do not already exist. + + The directory must not be inside a zipfile. + + Flushes the cache. + */ static void createDirectory(const std::string& path) { + mutex.lock(); instance()._createDirectory(path); + mutex.unlock(); } - /** \copydoc _currentDirectory */ + + /** The current working directory (cwd). Only ends in a slash if this is the root of the file system. */ static std::string currentDirectory() { - return instance()._currentDirectory(); + mutex.lock(); + const std::string& s = instance()._currentDirectory(); + mutex.unlock(); + return s; } - /** \copydoc _copyFile */ + + /** + \param srcPath Must name a file. + \param dstPath Must not contain a zipfile. + + Flushes the cache. + */ static void copyFile(const std::string& srcPath, const std::string& dstPath) { + mutex.lock(); instance()._copyFile(srcPath, dstPath); + mutex.unlock(); } - /** \copydoc _exists */ - static bool exists(const std::string& f, bool trustCache = true) { - return instance()._exists(f, trustCache); + + + /** Returns true if a node named \a f exists. + + \param f If \a f contains wildcards, the function returns true if any file + matches those wildcards. Wildcards may only appear in the base or ext, not the + path. Environment variables beginning with dollar signs (e.g., in "$G3DDATA/cubemap"), + with optional parens ("$(G3DDATA)") are + automatically expanded in \a f. Default share names on Windows (e.g., "\\mycomputer\c$") + are correctly distinguished from empty environment variables. + + \param trustCache If true, uses the cache for optimizing repeated calls + in the same parent directory. + + \param caseSensitive If true, the match must have exactly the same case for the base and extension. If false, + case is ignored. The default on Windows is false and the default on other operating systems is true. + */ + static bool exists(const std::string& f, bool trustCache = true, bool caseSensitive = +#ifdef G3D_WINDOWS + false +#else + true +#endif + ) { + mutex.lock(); + bool e = instance()._exists(f, trustCache, caseSensitive); + mutex.unlock(); + return e; } - /** \copydoc _isDirectory */ + + /** Known bug: does not work inside zipfiles */ static bool isDirectory(const std::string& path) { - return instance()._isDirectory(path); + mutex.lock(); + bool b = instance()._isDirectory(path); + mutex.unlock(); + return b; } - /** \copydoc _isFile */ + + /** Known bug: does not work inside zipfiles */ static bool isFile(const std::string& path) { - return instance()._isFile(path); + mutex.lock(); + bool b = instance()._isFile(path); + mutex.unlock(); + return b; } - /** \copydoc _resolve */ + + /** Fully qualifies a filename. + + The filename may contain wildcards, in which case the wildcards will be preserved in the returned value. + + \param cwd The directory to treat as the "current" directory when resolving a relative path. The default + value is the actual current directory. (G3D::Any::sourceDirectory is a common alternative) + */ static std::string resolve(const std::string& path, const std::string& cwd = currentDirectory()) { - return instance()._resolve(path, cwd); + mutex.lock(); + const std::string& s = instance()._resolve(path, cwd); + mutex.unlock(); + return s; } - /** \copydoc _isNewer */ + + /** Returns true if \a dst does not exist or \a src is newer than \a dst, + according to their time stamps. + + Known bug: does not work inside zipfiles. + */ static bool isNewer(const std::string& src, const std::string& dst) { - return instance()._isNewer(src, dst); + mutex.lock(); + bool b = instance()._isNewer(src, dst); + mutex.unlock(); + return b; } - /** \copydoc _size */ + + /** Returns the length of the file in bytes, or -1 if the file could not be opened. */ static int64 size(const std::string& path) { - return instance()._size(path); + mutex.lock(); + int64 i = instance()._size(path); + mutex.unlock(); + return i; } - /** \copydoc _list */ + + /** Appends all nodes matching \a spec to the \a result array. + + Wildcards can only appear to the right of the last slash in \a spec. + + The names will not contain parent paths unless \a includePath == true. + These may be relative to the current directory unless \a spec + is fully qualified (can be done with resolveFilename). + + */ static void list(const std::string& spec, Array& result, const ListSettings& listSettings = ListSettings()) { - return instance()._list(spec, result, listSettings); + mutex.lock(); + instance()._list(spec, result, listSettings); + mutex.unlock(); } - /** \copydoc _getFiles */ + + /** list() files */ static void getFiles(const std::string& spec, Array& result, bool includeParentPath = false) { - return instance()._getFiles(spec, result, includeParentPath); + mutex.lock(); + instance()._getFiles(spec, result, includeParentPath); + mutex.unlock(); } - /** \copydoc getDirectories */ + + /** list() directories */ static void getDirectories(const std::string& spec, Array& result, bool includeParentPath = false) { - return instance()._getDirectories(spec, result, includeParentPath); + mutex.lock(); + instance()._getDirectories(spec, result, includeParentPath); + mutex.unlock(); } + + /** Adds \a filename to usedFiles(). This is called automatically by open() and all + G3D routines that open files. */ + static void markFileUsed(const std::string& filename); + + /** All files that have been marked by markFileUsed(). GApp automatically prints this list to log.txt. It is useful + for finding the dependencies of your program automatically.*/ + static const Set& usedFiles(); }; @@ -400,6 +529,11 @@ public: /** Appends file onto dirname, ensuring a / if needed. */ static std::string concat(const std::string& a, const std::string& b); + /** Returns true if \a f specifies a path that parses as root of the filesystem. + On OS X and other Unix-based operating systems, "/" is the only root. + On Windows, drive letters and shares are roots, e.g., "c:\", "\\foo\". + Does not check on Windows to see if the root is actually mounted or a legal + drive letter--this is a purely string based test. */ static bool isRoot(const std::string& f); /** Removes the trailing slash unless \a f is a filesystem root */ @@ -423,6 +557,11 @@ public: /** Convert all slashes to '/' */ static std::string canonicalize(std::string x); + /** \brief Replaces $VAR and $(VAR) patterns with the corresponding environment variable. + Throws std::string if the environment variable is not defined. + */ + static std::string expandEnvironmentVariables(const std::string& path); + /** Parses a filename into four useful pieces. @@ -454,11 +593,13 @@ public: std::string& base, std::string& ext); - /** Returns true if \a path matches \a pattern, with standard filesystem wildcards. */ static bool matches(const std::string& path, const std::string& pattern, bool caseSensitive = true); + + /** Replaces characters that are illegal in a filename with legal equivalents.*/ + static std::string makeLegalFilename(const std::string& f, size_t maxLength = 100000); }; } // namespace G3D diff --git a/deps/g3dlite/include/G3D/Frustum.h b/deps/g3dlite/include/G3D/Frustum.h new file mode 100644 index 000000000..6c2d2a413 --- /dev/null +++ b/deps/g3dlite/include/G3D/Frustum.h @@ -0,0 +1,57 @@ +/** + \file G3D/Frustum.h + + \maintainer Morgan McGuire, http://graphics.cs.williams.edu + + \created 2005-07-20 + \edited 2013-06-11 +*/ + +#ifndef G3D_Frustum_h +#define G3D_Frustum_h + +#include "G3D/platform.h" +#include "G3D/g3dmath.h" +#include "G3D/Plane.h" +#include "G3D/SmallArray.h" +#include "G3D/Vector4.h" + +namespace G3D { + +class Box; + +/** \see Projection */ +class Frustum { +public: + class Face { + public: + /** Counter clockwise indices into vertexPos */ + int vertexIndex[4]; + + /** The plane containing the face. */ + Plane plane; + }; + + /** The vertices, in homogeneous space. The order is that of + the near face, starting from the (object space) +x,+y corner + and proceeding CCW from the camera's point of view; followed + by the far face also in CCW order. + + If w == 0, + a vertex is at infinity. */ + SmallArray vertexPos; + + /** The faces in the frustum. When the + far plane is at infinity, there are 5 faces, + otherwise there are 6. The faces are in the order + N,R,L,B,T,[F]. + */ + SmallArray faceArray; + + /** \param minObjectSpaceDepth Smallest value permitted for the near plane Z - far plane Z (e.g., to force finite bounds)*/ + Box boundingBox(float minObjectSpaceDepth = finf()) const; +}; + +} // namespace G3D + +#endif diff --git a/deps/g3dlite/include/G3D/G3D.h b/deps/g3dlite/include/G3D/G3D.h index 082d64348..09a89b8b8 100644 --- a/deps/g3dlite/include/G3D/G3D.h +++ b/deps/g3dlite/include/G3D/G3D.h @@ -1,22 +1,23 @@ /** - @file G3D.h + \file G3D.h This header includes all of the G3D libraries in appropriate namespaces. - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2001-08-25 - @edited 2010-03-20 + \created 2001-08-25 + \edited 2013-03-24 - Copyright 2000-2010, Morgan McGuire. + Copyright 2000-2013, Morgan McGuire. All rights reserved. */ #ifndef G3D_G3D_h #define G3D_G3D_h - -#define NOMINMAX 1 +#ifndef NOMINMAX + #define NOMINMAX 1 +#endif #ifdef min #undef min #endif @@ -24,18 +25,30 @@ #undef max #endif +#include "G3D/HaltonSequence.h" #include "G3D/platform.h" +#include "G3D/Proxy.h" +#include "G3D/BIN.h" +#include "G3D/FileNotFound.h" #include "G3D/units.h" #include "G3D/ParseError.h" #include "G3D/Random.h" +#include "G3D/Noise.h" #include "G3D/Array.h" #include "G3D/SmallArray.h" #include "G3D/Queue.h" #include "G3D/Crypto.h" #include "G3D/format.h" #include "G3D/Vector2.h" +#include "G3D/Vector2int32.h" +#include "G3D/Vector2int16.h" +#include "G3D/Vector2unorm16.h" #include "G3D/Vector3.h" +#include "G3D/Vector3int16.h" +#include "G3D/Vector3int32.h" #include "G3D/Vector4.h" +#include "G3D/Vector4int16.h" +#include "G3D/Vector4int8.h" #include "G3D/Color1.h" #include "G3D/Color3.h" #include "G3D/Color4.h" @@ -43,6 +56,7 @@ #include "G3D/Matrix3.h" #include "G3D/Matrix4.h" #include "G3D/CoordinateFrame.h" +#include "G3D/Projection.h" #include "G3D/PhysicsFrame.h" #include "G3D/PhysicsFrameSpline.h" #include "G3D/Plane.h" @@ -53,6 +67,7 @@ #include "G3D/Box2D.h" #include "G3D/AABox.h" #include "G3D/WrapMode.h" +#include "G3D/CullFace.h" #include "G3D/Cone.h" #include "G3D/Quat.h" #include "G3D/stringutils.h" @@ -61,6 +76,7 @@ #include "G3D/FileSystem.h" #include "G3D/Set.h" #include "G3D/GUniqueID.h" +#include "G3D/RayGridIterator.h" #include "G3D/BinaryFormat.h" #include "G3D/BinaryInput.h" #include "G3D/BinaryOutput.h" @@ -68,6 +84,10 @@ #include "G3D/g3dfnmatch.h" #include "G3D/G3DGameUnits.h" #include "G3D/g3dmath.h" +#include "G3D/unorm8.h" +#include "G3D/unorm16.h" +#include "G3D/snorm8.h" +#include "G3D/snorm16.h" #include "G3D/uint128.h" #include "G3D/fileutils.h" #include "G3D/ReferenceCount.h" @@ -75,14 +95,19 @@ #include "G3D/GMutex.h" #include "G3D/PrecomputedRandom.h" #include "G3D/MemoryManager.h" +#include "G3D/BlockPoolMemoryManager.h" #include "G3D/AreaMemoryManager.h" #include "G3D/BumpMapPreprocess.h" +#include "G3D/CubeFace.h" +#include "G3D/Line2D.h" +#include "G3D/ThreadsafeQueue.h" +#include "G3D/network.h" -template struct HashTrait< G3D::ReferenceCountedPointer > { - static size_t hashCode(G3D::ReferenceCountedPointer key) { return reinterpret_cast( key.pointer() ); } +template struct HashTrait< shared_ptr > { + static size_t hashCode(shared_ptr key) { return reinterpret_cast( key.get() ); } }; -#include "G3D/GImage.h" +#include "G3D/Image.h" #include "G3D/CollisionDetection.h" #include "G3D/Intersect.h" #include "G3D/Log.h" @@ -98,18 +123,14 @@ template struct HashTrait< G3D::ReferenceCountedPointer > { #include "G3D/Capsule.h" #include "G3D/Cylinder.h" #include "G3D/Triangle.h" -#include "G3D/Color3uint8.h" -#include "G3D/Color4uint8.h" -#include "G3D/Vector2int16.h" -#include "G3D/Vector3int16.h" -#include "G3D/Vector3int32.h" -#include "G3D/Vector4int8.h" +#include "G3D/Color1unorm8.h" +#include "G3D/Color2unorm8.h" +#include "G3D/Color3unorm8.h" +#include "G3D/Color4unorm8.h" #include "G3D/ConvexPolyhedron.h" #include "G3D/MeshAlg.h" #include "G3D/vectorMath.h" #include "G3D/Rect2D.h" -#include "G3D/GCamera.h" -#include "G3D/GLight.h" #include "G3D/KDTree.h" #include "G3D/PointKDTree.h" #include "G3D/TextOutput.h" @@ -124,40 +145,82 @@ template struct HashTrait< G3D::ReferenceCountedPointer > { #include "G3D/PointHashGrid.h" #include "G3D/Map2D.h" #include "G3D/Image1.h" -#include "G3D/Image1uint8.h" +#include "G3D/Image1unorm8.h" #include "G3D/Image3.h" -#include "G3D/Image3uint8.h" +#include "G3D/Image3unorm8.h" #include "G3D/Image4.h" -#include "G3D/Image4uint8.h" +#include "G3D/Image4unorm8.h" #include "G3D/filter.h" #include "G3D/WeakCache.h" #include "G3D/Pointer.h" #include "G3D/Matrix.h" #include "G3D/ImageFormat.h" +#include "G3D/PixelTransferBuffer.h" +#include "G3D/typeutils.h" +#include "G3D/SpeedLoad.h" +#include "G3D/ParseMTL.h" +#include "G3D/ParseOBJ.h" +#include "G3D/ParsePLY.h" +#include "G3D/Parse3DS.h" +#include "G3D/PathDirection.h" +#include "G3D/FastPODTable.h" +#include "G3D/FastPointHashGrid.h" +#include "G3D/PixelTransferBuffer.h" +#include "G3D/CPUPixelTransferBuffer.h" +#include "G3D/CompassDirection.h" +#include "G3D/Access.h" + +namespace G3D { + + /** + Call from main() to initialize the G3D library state and register + shutdown memory managers. This does not initialize OpenGL. + + If you invoke initGLG3D, then it will automatically call initG3D. + It is safe to call this function more than once--it simply ignores + multiple calls. + + \see System, GLCaps, OSWindow, RenderDevice, initGLG3D. + + */ + void initG3D(const G3DSpecification& spec = G3DSpecification()); +} #ifdef _MSC_VER -# pragma comment(lib, "zlib") -# pragma comment(lib, "ws2_32") # pragma comment(lib, "winmm") # pragma comment(lib, "imagehlp") +# pragma comment(lib, "ws2_32") # pragma comment(lib, "gdi32") # pragma comment(lib, "user32") # pragma comment(lib, "kernel32") -# pragma comment(lib, "version") # pragma comment(lib, "advapi32") -# pragma comment(lib, "png") -# pragma comment(lib, "jpeg") -# pragma comment(lib, "zip") -# ifdef _DEBUG - // Don't link against G3D when building G3D itself. -# ifndef G3D_BUILDING_LIBRARY_DLL -# pragma comment(lib, "G3Dd.lib") -# endif +# pragma comment(lib, "shell32") +# pragma comment(lib, "version") +# ifdef G3D_64BIT +# pragma comment(lib, "zlib_x64") +# pragma comment(lib, "zip_x64") +# pragma comment(lib, "enet_x64") # else - // Don't link against G3D when building G3D itself. -# ifndef G3D_BUILDING_LIBRARY_DLL -# pragma comment(lib, "G3D.lib") -# endif +# pragma comment(lib, "zlib") +# pragma comment(lib, "zip") +# pragma comment(lib, "enet") +# endif +# if defined(_DEBUG) +# ifdef G3D_64BIT +# pragma comment(lib, "G3D_x64d") +# pragma comment(lib, "freeimage_x64d") +# else +# pragma comment(lib, "G3Dd") +# pragma comment(lib, "freeimaged") +# endif +# else +# ifdef G3D_64BIT +# pragma comment(lib, "G3D_x64") +# pragma comment(lib, "freeimage_x64") +# else +# pragma comment(lib, "G3D") +# pragma comment(lib, "freeimage") +# endif # endif #endif diff --git a/deps/g3dlite/include/G3D/G3DGameUnits.h b/deps/g3dlite/include/G3D/G3DGameUnits.h index e2bc2c811..a53819f6b 100644 --- a/deps/g3dlite/include/G3D/G3DGameUnits.h +++ b/deps/g3dlite/include/G3D/G3DGameUnits.h @@ -3,7 +3,7 @@ @maintainer Morgan McGuire, http://graphics.cs.williams.edu @created 2002-10-05 - @edited 2006-11-10 + @edited 2012-02-19 */ #ifndef G3D_GAMEUNITS_H @@ -12,14 +12,17 @@ #include "G3D/platform.h" namespace G3D { + +/** \deprecated use SimTime */ +typedef double GameTime; + /** Time, in seconds. */ -typedef double GameTime; typedef double SimTime; /** - Actual wall clock time in seconds. + Actual wall clock time in seconds (Unix time). */ typedef double RealTime; diff --git a/deps/g3dlite/include/G3D/GMutex.h b/deps/g3dlite/include/G3D/GMutex.h index 9fe098d10..5676aa458 100644 --- a/deps/g3dlite/include/G3D/GMutex.h +++ b/deps/g3dlite/include/G3D/GMutex.h @@ -1,8 +1,8 @@ /** - @file GMutex.h + \file G3D/GMutex.h - @created 2005-09-22 - @edited 2009-03-25 + \created 2005-09-22 + \edited 2013-04-03 */ #ifndef G3D_GMutex_h @@ -13,10 +13,13 @@ #include "G3D/debugAssert.h" #include -#ifndef G3D_WIN32 +#ifndef G3D_WINDOWS # include # include -# include +#endif + +#if defined(G3D_LINUX) || defined(G3D_OSX) +# include // For usleep #endif @@ -26,7 +29,7 @@ namespace G3D { \brief A mutual exclusion lock that busy-waits when locking. On a machine with one (significant) thread per processor core, - a spinlock may be substantially faster than a mutex. + a Spinlock may be substantially faster than a mutex. \sa G3D::GThread, G3D::GMutex, G3D::AtomicInt32 */ @@ -41,12 +44,16 @@ public: /** Busy waits until the lock is unlocked, then locks it exclusively. Returns true if the lock succeeded on the first - try (indicating no contention). */ + try (indicating no contention). + + Unlike a G3D::GMutex, a single thread cannot re-enter + Spinlock::lock() that it already locked. + */ inline bool lock() { bool first = true; while (x.compareAndSet(0, 1) == 1) { first = false; -# ifdef G3D_WIN32 +# ifdef G3D_WINDOWS Sleep(0); # else usleep(0); @@ -68,7 +75,7 @@ public: */ class GMutex { private: -# ifdef G3D_WIN32 +# ifdef G3D_WINDOWS CRITICAL_SECTION m_handle; # else pthread_mutex_t m_handle; diff --git a/deps/g3dlite/include/G3D/GThread.h b/deps/g3dlite/include/G3D/GThread.h index 58437efc3..8670fef4e 100644 --- a/deps/g3dlite/include/G3D/GThread.h +++ b/deps/g3dlite/include/G3D/GThread.h @@ -2,18 +2,21 @@ @file GThread.h @created 2005-09-22 - @edited 2007-01-31 + @edited 2010-09-10 */ -#ifndef G3D_GTHREAD_H -#define G3D_GTHREAD_H +#ifndef G3D_GThread_h +#define G3D_GThread_h #include "G3D/platform.h" #include "G3D/ReferenceCount.h" +#include "G3D/ThreadSet.h" +#include "G3D/Vector2int32.h" +#include "G3D/SpawnBehavior.h" #include -#ifndef G3D_WIN32 +#ifndef G3D_WINDOWS # include # include #endif @@ -21,7 +24,9 @@ namespace G3D { -typedef ReferenceCountedPointer GThreadRef; +typedef shared_ptr GThreadRef; + + /** Platform independent thread implementation. You can either subclass and @@ -32,11 +37,11 @@ typedef ReferenceCountedPointer GThreadRef; dropping all pointers (and causing deallocation) of a GThread does NOT stop the underlying process. - @sa G3D::GMutex, G3D::Spinlock, G3D::AtomicInt32 + \sa G3D::GMutex, G3D::Spinlock, G3D::AtomicInt32, G3D::ThreadSet */ class GThread : public ReferenceCountedObject { private: - // "Status" is a reserved work on FreeBSD + // "Status" is a reserved word on FreeBSD enum GStatus {STATUS_CREATED, STATUS_STARTED, STATUS_RUNNING, STATUS_COMPLETED}; // Not implemented on purpose, don't use @@ -44,21 +49,21 @@ private: GThread& operator=(const GThread&); bool operator==(const GThread&); -#ifdef G3D_WIN32 +#ifdef G3D_WINDOWS static DWORD WINAPI internalThreadProc(LPVOID param); #else static void* internalThreadProc(void* param); -#endif //G3D_WIN32 +#endif //G3D_WINDOWS volatile GStatus m_status; // Thread handle to hold HANDLE and pthread_t -#ifdef G3D_WIN32 +#ifdef G3D_WINDOWS HANDLE m_handle; HANDLE m_event; #else pthread_t m_handle; -#endif //G3D_WIN32 +#endif //G3D_WINDOWS std::string m_name; @@ -68,8 +73,11 @@ protected: virtual void threadMain() = 0; public: - typedef ReferenceCountedPointer Ref; - enum SpawnBehavior {USE_NEW_THREAD, USE_CURRENT_THREAD}; + + /** Returns System::numCores(); put here to break a dependence on System.h */ + static int numCores(); + + typedef shared_ptr Ref; GThread(const std::string& name); @@ -110,12 +118,153 @@ public: void waitForCompletion(); /** Returns thread name */ - inline const std::string& name() { + const std::string& name() { return m_name; } + + /** For backwards compatibility to G3D 8.xx */ + static const SpawnBehavior USE_CURRENT_THREAD = G3D::USE_CURRENT_THREAD; + /** For backwards compatibility to G3D 8.xx */ + static const SpawnBehavior USE_NEW_THREAD = G3D::USE_NEW_THREAD; + + enum { + /** Tells GThread::runConcurrently() and GThread::runConcurrently2D() to + use System::numCores() threads.*/ + NUM_CORES = -100 + }; + + /** + \brief Iterates over a 2D region using multiple threads and + blocks until all threads have completed.

    Evaluates \a + object->\a method(\a x, \a y) for every start.x <= x < + upTo.x and start.y <= y < upTo.y. + Iteration is row major, so each thread can expect to see + successive x values.

    + \param maxThreads + Maximum number of threads to use. By default at most one + thread per processor core will be used. + + Example: + + \code + class RayTracer { + public: + void trace(const Vector2int32& pixel) { + ... + } + + void traceAll() { + GThread::runConcurrently2D(Point2int32(0,0), Point2int32(w,h), this, &RayTracer::trace); + } + }; + \endcode + */ + template + static void runConcurrently2D + (const Vector2int32& start, + const Vector2int32& upTo, + Class* object, + void (Class::*method)(int x, int y), + int maxThreads = NUM_CORES) { + _internal_runConcurrently2DHelper(start, upTo, object, method, static_cast(NULL), maxThreads); + } + + /** Like the other version of runConcurrently2D, but tells the + method the thread index that it is running on. That enables + the caller to manage per-thread state. + */ + template + static void runConcurrently2D + (const Vector2int32& start, + const Vector2int32& upTo, + Class* object, + void (Class::*method)(int x, int y, int threadID), + int maxThreads = NUM_CORES) { + _internal_runConcurrently2DHelper(start, upTo, object, static_cast(NULL), method, maxThreads); + } + }; + + // Can't use an inherited class inside of its parent on g++ 4.2.1 if it is later a template parameter + + /** For use by runConcurrently2D. Designed for arbitrary iteration, although only used for + interlaced rows in the current implementation. */ + template + class _internalGThreadWorker : public GThread { + public: + /** Start for this thread, which differs from the others */ + const int threadID; + const Vector2int32 start; + const Vector2int32 upTo; + const Vector2int32 stride; + Class* object; + void (Class::*method1)(int x, int y); + void (Class::*method2)(int x, int y, int threadID); + + _internalGThreadWorker(int threadID, + const Vector2int32& start, + const Vector2int32& upTo, + Class* object, + void (Class::*method1)(int x, int y), + void (Class::*method2)(int x, int y, int threadID), + const Vector2int32& stride) : + GThread("runConcurrently2D worker"), + threadID(threadID), + start(start), + upTo(upTo), + stride(stride), + object(object), + method1(method1), + method2(method2) {} + + virtual void threadMain() { + for (int y = start.y; y < upTo.y; y += stride.y) { + // Run whichever method was provided + if (method1) { + for (int x = start.x; x < upTo.x; x += stride.x) { + (object->*method1)(x, y); + } + } else { + for (int x = start.x; x < upTo.x; x += stride.x) { + (object->*method2)(x, y, threadID); + } + } + } + } + }; + + + template + void _internal_runConcurrently2DHelper + (const Vector2int32& start, + const Vector2int32& upTo, + Class* object, + void (Class::*method1)(int x, int y), + void (Class::*method2)(int x, int y, int threadID), + int maxThreads) { + + // Create a group of threads + if (maxThreads == GThread::NUM_CORES) { + maxThreads = GThread::numCores(); + } + + const int numRows = upTo.y - start.y; + const int numThreads = min(maxThreads, numRows); + const Vector2int32 stride(1, numThreads); + ThreadSet threadSet; + for (int t = 0; t < numThreads; ++t) { + threadSet.insert(shared_ptr<_internalGThreadWorker >(new _internalGThreadWorker(t, start + Vector2int32(0, t), upTo, object, method1, method2, stride))); + } + + // Run the threads, reusing the current thread and blocking until + // all complete + threadSet.start(USE_CURRENT_THREAD); + threadSet.waitForCompletion(); + } + + } // namespace G3D #endif //G3D_GTHREAD_H diff --git a/deps/g3dlite/include/G3D/GUniqueID.h b/deps/g3dlite/include/G3D/GUniqueID.h index c8b775c2e..84204b945 100644 --- a/deps/g3dlite/include/G3D/GUniqueID.h +++ b/deps/g3dlite/include/G3D/GUniqueID.h @@ -1,16 +1,18 @@ /** - @file GUniqueID.h - @author Morgan McGuire, http://graphics.cs.williams.edu + \file G3D/GUniqueID.h + \author Morgan McGuire, http://graphics.cs.williams.edu */ -#ifndef G3D_GUNIQUEID_H -#define G3D_GUNIQUEID_H +#ifndef G3D_GUniqueID_h +#define G3D_GUniqueID_h #include "G3D/platform.h" #include "G3D/g3dmath.h" #include "G3D/Table.h" namespace G3D { - + +class Any; + /** Globally unique identifiers. The probability of two different programs generating the same value from UniqueID::create is vanishingly small. @@ -25,8 +27,27 @@ private: public: + /** \sa create */ GUniqueID() : id(0) {} + GUniqueID& operator=(const Any& a); + + /** \sa create */ + GUniqueID(const Any& a) { + *this = a; + } + + Any toAny() const; + + /** Returns a 16-character string equivalent to this GUniqueID's uint64 value. */ + std::string toString16() const; + + static GUniqueID fromString16(const std::string& s); + + /** Returns the ID that has the specified tag (so that it is not uninitialized), but + which is a common sentinel "none" value. */ + static GUniqueID NONE(uint16 tag); + bool uninitialized() const { return id == 0; } @@ -37,7 +58,7 @@ public: operator uint64() const { return id; - } + } bool operator==(const GUniqueID& other) const { return id == other.id; diff --git a/deps/g3dlite/include/G3D/HashTrait.h b/deps/g3dlite/include/G3D/HashTrait.h index 72de3da52..1de3777ba 100644 --- a/deps/g3dlite/include/G3D/HashTrait.h +++ b/deps/g3dlite/include/G3D/HashTrait.h @@ -1,11 +1,11 @@ /** - @file HashTrait.h + \file G3D/HashTrait.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2008-10-01 - @edited 2009-11-01 + \maintainer Morgan McGuire, http://graphics.cs.williams.edu + \created 2008-10-01 + \edited 2011-06-09 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ @@ -16,6 +16,88 @@ #include "G3D/Crypto.h" #include "G3D/g3dmath.h" #include "G3D/uint128.h" +#include + +#include +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +namespace G3D { +/** \brief A hash function that is faster than CRC32 for arbitrary long strings + \cite From http://www.azillionmonkeys.com/qed/hash.html by Paul Hsieh*/ +inline uint32_t superFastHash (const void* _data, size_t numBytes) { + const char* data = (const char*)_data; + uint32_t hash = (uint32_t)numBytes; + uint32_t tmp; + int rem; + + if ((numBytes <= 0) || (data == NULL)) { + return 0; + } + + rem = numBytes & 3; + numBytes >>= 2; + + /* Main loop */ + for (;numBytes > 0; --numBytes) { + hash += get16bits (data); + tmp = (get16bits (data+2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2*sizeof (uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) { + case 3: hash += get16bits (data); + hash ^= hash << 16; + hash ^= data[sizeof (uint16_t)] << 18; + hash += hash >> 11; + break; + case 2: hash += get16bits (data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: hash += *data; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + + +/** + Thomas Wang's 64-to-32-bit mix hash based on Robert Jenkin's hash http://www.concentric.net/~ttwang/tech/inthash.htm + + Found by Morgan to produce the best net performance for building tables from Vector4int16 +*/ +inline uint32_t wangHash6432Shift(int64 key) { + key = (~key) + (key << 18); // key = (key << 18) - key - 1; + key = key ^ (key >> 31); + key = key * 21; // key = (key + (key << 2)) + (key << 4); + key = key ^ (key >> 11); + key = key + (key << 6); + return uint32_t(key) ^ uint32_t(key >> 22); +} + +} +#undef get16bits /** Must be specialized for custom types. @see G3D::Table for specialization requirements. @@ -23,14 +105,19 @@ template struct HashTrait{}; template struct HashTrait { - static size_t hashCode(const void* k) { return reinterpret_cast(k); } + static size_t hashCode(const void* k) { return reinterpret_cast(k) >> 1; } }; -#if 0 -template <> struct HashTrait { - static size_t hashCode(int k) { return static_cast(k); } +/** For use with \code Table \endcode. */ +template <> struct HashTrait { + static size_t hashCode(const std::type_info* const t) { +# ifdef _MSC_VER + return t->hash_code(); +# else + return reinterpret_cast(t) >> 1; +# endif + } }; -#endif template <> struct HashTrait { static size_t hashCode(G3D::int16 k) { return static_cast(k); } @@ -40,10 +127,6 @@ template <> struct HashTrait { static size_t hashCode(G3D::uint16 k) { return static_cast(k); } }; -//template <> struct HashTrait { -// static size_t hashCode(int k) { return static_cast(k); } -//}; - template <> struct HashTrait { static size_t hashCode(G3D::int32 k) { return static_cast(k); } }; @@ -58,21 +141,30 @@ template <> struct HashTrait { }; #endif -template <> struct HashTrait { - static size_t hashCode(G3D::int64 k) { return static_cast(k); } -}; template <> struct HashTrait { - static size_t hashCode(G3D::uint64 k) { return static_cast(k); } + static size_t hashCode(G3D::uint64 k) { return static_cast(k) ^ static_cast(k >> 32); } }; +template <> struct HashTrait { + static size_t hashCode(G3D::int64 k) { return HashTrait::hashCode(G3D::uint64(k)); } +}; + + template <> struct HashTrait { - static size_t hashCode(const std::string& k) { return static_cast(G3D::Crypto::crc32(k.c_str(), k.size())); } + static size_t hashCode(const std::string& k) { + return G3D::superFastHash(k.c_str(), k.size()); + //return static_cast(G3D::Crypto::crc32(k.c_str(), k.size())); + } }; template <> struct HashTrait { - // Use the FNV-1 hash (http://isthe.com/chongo/tech/comp/fnv/#FNV-1). static size_t hashCode(G3D::uint128 key) { + return G3D::superFastHash(&key, sizeof(key)); + //return HashTrait::hashCode(key.hi) ^ HashTrait::hashCode(key.lo); + +#if 0 // Really slow under gcc + // Use the FNV-1 hash (http://isthe.com/chongo/tech/comp/fnv/#FNV-1). static const G3D::uint128 FNV_PRIME_128(1 << 24, 0x159); static const G3D::uint128 FNV_OFFSET_128(0xCF470AAC6CB293D2ULL, 0xF52F88BF32307F8FULL); @@ -83,9 +175,10 @@ template <> struct HashTrait { hash ^= (mask & key); key >>= 8; } - + G3D::uint64 foldedHash = hash.hi ^ hash.lo; return static_cast((foldedHash >> 32) ^ (foldedHash & 0xFFFFFFFF)); +#endif } }; diff --git a/deps/g3dlite/include/G3D/Image1.h b/deps/g3dlite/include/G3D/Image1.h index 711e83f20..615c0a8e2 100644 --- a/deps/g3dlite/include/G3D/Image1.h +++ b/deps/g3dlite/include/G3D/Image1.h @@ -1,35 +1,34 @@ /** - @file Image1.h + \file G3D/Image1.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2007-01-31 - @edited 2007-01-31 + \created 2007-01-31 + \edited 2011-08-31 */ -#ifndef G3D_IMAGE1_H -#define G3D_IMAGE1_H +#ifndef G3D_Image1_h +#define G3D_Image1_h #include "G3D/platform.h" #include "G3D/Map2D.h" #include "G3D/Color1.h" -#include "G3D/GImage.h" namespace G3D { -typedef ReferenceCountedPointer Image1Ref; +typedef shared_ptr Image1Ref; /** Luminance image with 32-bit floating point storage. - See also G3D::Image1uint8, G3D::GImage. + See also G3D::Image1unorm8, G3D::GImage. */ class Image1 : public Map2D { public: typedef Image1 Type; - typedef ReferenceCountedPointer Ref; + typedef shared_ptr Ref; typedef Color1 Storage; typedef Color1 Compute; @@ -41,9 +40,9 @@ protected: void copyArray(const Color1* src, int w, int h); void copyArray(const Color3* src, int w, int h); void copyArray(const Color4* src, int w, int h); - void copyArray(const Color1uint8* src, int w, int h); - void copyArray(const Color3uint8* src, int w, int h); - void copyArray(const Color4uint8* src, int w, int h); + void copyArray(const Color1unorm8* src, int w, int h); + void copyArray(const Color3unorm8* src, int w, int h); + void copyArray(const Color4unorm8* src, int w, int h); public: @@ -55,25 +54,28 @@ public: /** Creates a 0 x 0 image. */ static Ref createEmpty(WrapMode wrap = WrapMode::ERROR); - static Ref fromFile(const std::string& filename, WrapMode wrap = WrapMode::ERROR, GImage::Format fmt = GImage::AUTODETECT); + static Ref fromFile(const std::string& filename, WrapMode wrap = WrapMode::ERROR); - static Ref fromArray(const class Color1uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); - static Ref fromArray(const class Color3uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); - static Ref fromArray(const class Color4uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); + static Ref fromArray(const class Color1unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); + static Ref fromArray(const class Color3unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); + static Ref fromArray(const class Color4unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); static Ref fromArray(const class Color1* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); static Ref fromArray(const class Color3* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); static Ref fromArray(const class Color4* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); - static Ref fromImage1uint8(const ReferenceCountedPointer& im); + static Ref fromImage1unorm8(const shared_ptr& im); - static Ref fromGImage(const class GImage& im, WrapMode wrap = WrapMode::ERROR); + /** Loads from any of the file formats supported by G3D::Image. - /** Loads from any of the file formats supported by G3D::GImage. If there is an alpha channel on the input, - it is stripped. */ - void load(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT); + If there is an alpha channel on the input, it is stripped. + Values are automatically scaled to the range [0, 1]. */ + void load(const std::string& filename); - /** Saves in any of the formats supported by G3D::GImage. */ - void save(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT); + /** Saves in any of the formats supported by G3D::Image. + + The data values are assumed to be on the range [0, 1] and will + be scaled appropriately for the save format.*/ + void save(const std::string& filename); }; } // G3D diff --git a/deps/g3dlite/include/G3D/Image3.h b/deps/g3dlite/include/G3D/Image3.h index 13cb8fa7f..55b8e4c87 100644 --- a/deps/g3dlite/include/G3D/Image3.h +++ b/deps/g3dlite/include/G3D/Image3.h @@ -1,10 +1,10 @@ /** - @file Image3.h + \file G3D/Image3.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2007-01-31 - @edited 2007-01-31 + \created 2007-01-31 + \edited 2011-08-31 */ @@ -14,36 +14,32 @@ #include "G3D/platform.h" #include "G3D/Map2D.h" #include "G3D/Color3.h" -#include "G3D/GImage.h" namespace G3D { -typedef ReferenceCountedPointer Image3Ref; +typedef shared_ptr Image3Ref; /** RGB image with 32-bit floating point storage for each channel. - See also G3D::Image3uint8, G3D::GImage. + See also G3D::Image3unorm8, G3D::GImage. */ class Image3 : public Map2D { public: typedef Image3 Type; - typedef ReferenceCountedPointer Ref; - typedef Color3 Storage; - typedef Color3 Compute; + typedef shared_ptr Ref; protected: Image3(int w, int h, WrapMode wrap); - void copyGImage(const class GImage& im); void copyArray(const Color1* src, int w, int h); void copyArray(const Color3* src, int w, int h); void copyArray(const Color4* src, int w, int h); - void copyArray(const Color1uint8* src, int w, int h); - void copyArray(const Color3uint8* src, int w, int h); - void copyArray(const Color4uint8* src, int w, int h); + void copyArray(const Color1unorm8* src, int w, int h); + void copyArray(const Color3unorm8* src, int w, int h); + void copyArray(const Color4unorm8* src, int w, int h); public: @@ -55,25 +51,23 @@ public: /** Creates a 0 x 0 image. */ static Ref createEmpty(WrapMode wrap = WrapMode::ERROR); - static Ref fromFile(const std::string& filename, WrapMode wrap = WrapMode::ERROR, GImage::Format fmt = GImage::AUTODETECT); + static Ref fromFile(const std::string& filename, WrapMode wrap = WrapMode::ERROR); - static Ref fromArray(const class Color1uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); - static Ref fromArray(const class Color3uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); - static Ref fromArray(const class Color4uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); + static Ref fromArray(const class Color1unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); + static Ref fromArray(const class Color3unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); + static Ref fromArray(const class Color4unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); static Ref fromArray(const class Color1* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); static Ref fromArray(const class Color3* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); static Ref fromArray(const class Color4* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); - static Ref fromImage3uint8(const ReferenceCountedPointer& im); - - static Ref fromGImage(const class GImage& im, WrapMode wrap = WrapMode::ERROR); + static Ref fromImage3unorm8(const shared_ptr& im); /** Loads from any of the file formats supported by G3D::GImage. If there is an alpha channel on the input, - it is stripped. */ - void load(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT); + it is stripped. Converts 8-bit formats to the range (0, 1) */ + void load(const std::string& filename); - /** Saves in any of the formats supported by G3D::GImage. */ - void save(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT); + /** Saves in any of the formats supported by G3D::GImage. Assumes the data is on the range (0, 1) if saving to an 8-bit format.*/ + void save(const std::string& filename); }; } // G3D diff --git a/deps/g3dlite/include/G3D/Image4.h b/deps/g3dlite/include/G3D/Image4.h index 21d7f1e79..95e96d484 100644 --- a/deps/g3dlite/include/G3D/Image4.h +++ b/deps/g3dlite/include/G3D/Image4.h @@ -1,24 +1,23 @@ /** - @file Image4.h + \file G3D/Image4.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2007-01-31 - @edited 2007-01-31 + \created 2007-01-31 + \edited 2011-08-11 */ -#ifndef G3D_IMAGE4_H -#define G3D_IMAGE4_H +#ifndef G3D_Image4_h +#define G3D_Image4_h #include "G3D/platform.h" #include "G3D/Map2D.h" #include "G3D/Color4.h" -#include "G3D/GImage.h" namespace G3D { -typedef ReferenceCountedPointer Image4Ref; +typedef shared_ptr Image4Ref; /** RGBA image with 32-bit floating point storage for each channel. @@ -26,30 +25,27 @@ typedef ReferenceCountedPointer Image4Ref; Whenever a method needs to convert from RGB to RGBA, A=1 is assumed. Bilinear interpolation on Image4 is about 8x faster than on - Image4uint8 due to the large cost of converting int->float on modern + Image4unorm8 due to the large cost of converting int->float on modern machines. - @sa G3D::Image4uint8, G3D::GImage. + @sa G3D::Image4unorm8, G3D::GImage. */ class Image4 : public Map2D { public: typedef Image4 Type; - typedef ReferenceCountedPointer Ref; - typedef Color4 Storage; - typedef Color4 Compute; + typedef shared_ptr Ref; protected: Image4(int w, int h, WrapMode wrap); - void copyGImage(const class GImage& im); void copyArray(const Color1* src, int w, int h); void copyArray(const Color3* src, int w, int h); void copyArray(const Color4* src, int w, int h); - void copyArray(const Color1uint8* src, int w, int h); - void copyArray(const Color3uint8* src, int w, int h); - void copyArray(const Color4uint8* src, int w, int h); + void copyArray(const Color1unorm8* src, int w, int h); + void copyArray(const Color3unorm8* src, int w, int h); + void copyArray(const Color4unorm8* src, int w, int h); public: @@ -61,24 +57,22 @@ public: /** Creates a 0 x 0 image. */ static Ref createEmpty(WrapMode wrap = WrapMode::ERROR); - static Ref fromFile(const std::string& filename, WrapMode wrap = WrapMode::ERROR, GImage::Format fmt = GImage::AUTODETECT); + static Ref fromFile(const std::string& filename, WrapMode wrap = WrapMode::ERROR); - static Ref fromArray(const class Color1uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); - static Ref fromArray(const class Color3uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); - static Ref fromArray(const class Color4uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); + static Ref fromArray(const class Color1unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); + static Ref fromArray(const class Color3unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); + static Ref fromArray(const class Color4unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); static Ref fromArray(const class Color1* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); static Ref fromArray(const class Color3* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); static Ref fromArray(const class Color4* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR); - static Ref fromImage4uint8(const ReferenceCountedPointer& im); - - static Ref fromGImage(const class GImage& im, WrapMode wrap = WrapMode::ERROR); + static Ref fromImage4unorm8(const shared_ptr& im); /** Loads from any of the file formats supported by G3D::GImage. */ - void load(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT); + void load(const std::string& filename); /** Saves in any of the formats supported by G3D::GImage. */ - void save(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT); + void save(const std::string& filename); }; } // G3D diff --git a/deps/g3dlite/include/G3D/ImageFormat.h b/deps/g3dlite/include/G3D/ImageFormat.h index 15d256433..27a9f9443 100644 --- a/deps/g3dlite/include/G3D/ImageFormat.h +++ b/deps/g3dlite/include/G3D/ImageFormat.h @@ -1,14 +1,14 @@ /** - @file ImageFormat.h + \file G3D/ImageFormat.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2003-05-23 - @edited 2010-05-01 + \created 2003-05-23 + \edited 2013-06-06 */ -#ifndef GLG3D_ImageFormat_H -#define GLG3D_ImageFormat_H +#ifndef GLG3D_ImageFormat_h +#define GLG3D_ImageFormat_h #include "G3D/platform.h" #include "G3D/Table.h" @@ -17,16 +17,22 @@ namespace G3D { -/** Information about common image formats. - Don't construct these; use the methods provided. +/** Information about common image formats. Don't construct these; + use the methods provided to access the const instances. - For most formats, the number indicates the number of bits per channel and a suffix of "F" indicates - floating point. This does not hold for the YUV and DXT formats.*/ + For most formats, the number indicates the number of bits per + channel and a suffix of "F" indicates floating point (following + OpenGL conventions). This does not hold for the YUV and DXT + formats. + + \sa G3D::Image, G3D::Texture, G3D::ImageConvert +*/ class ImageFormat { public: // Must update ImageFormat::name() when this enum changes. enum Code { + CODE_AUTO = -2, CODE_NONE = -1, CODE_L8, CODE_L16, @@ -58,24 +64,57 @@ public: CODE_RGB8I, CODE_RGB8UI, + CODE_RGBA8I, CODE_RGBA8UI, + CODE_RGB8_SNORM, + CODE_RGBA8_SNORM, + CODE_RGB16_SNORM, + CODE_RGBA16_SNORM, + CODE_ARGB8, CODE_BGR8, + CODE_BGRA8, CODE_R8, + CODE_R8I, + CODE_R8UI, + + CODE_R16, + CODE_R16I, + CODE_R16UI, + + CODE_R32I, + CODE_R32UI, CODE_RG8, CODE_RG8I, CODE_RG8UI, + CODE_RG16, + CODE_RG16I, + CODE_RG16UI, + + CODE_R16F, CODE_RG16F, + CODE_RG32I, + CODE_RG32UI, + + CODE_R32F, + CODE_RG32F, + CODE_RGBA8, CODE_RGBA16, CODE_RGBA16F, CODE_RGBA32F, + CODE_RGBA16I, + CODE_RGBA16UI, + + CODE_RGB32I, + CODE_RGB32UI, + CODE_RGBA32I, CODE_RGBA32UI, CODE_BAYER_RGGB8, @@ -141,6 +180,14 @@ public: BAYER_PATTERN_BGGR }; + + enum NumberFormat { + FLOATING_POINT_FORMAT, + INTEGER_FORMAT, + NORMALIZED_FIXED_POINT_FORMAT, + OTHER // e.g. DXT + }; + /** Number of channels (1 for a depth texture). */ int numComponents; bool compressed; @@ -182,10 +229,6 @@ public: /** Amount of CPU memory per pixel when packed into an array, discounting any end-of-row padding. */ int cpuBitsPerPixel; - /** Amount of CPU memory per pixel when packed into an array, discounting any end-of-row padding. - @deprecated Use cpuBitsPerPixel*/ - int packedBitsPerTexel; - /** Amount of GPU memory per pixel on most graphics cards, for formats supported by OpenGL. This is only an estimate--the actual amount of memory may be different on your actual card. @@ -196,24 +239,38 @@ public: */ int openGLBitsPerPixel; - /** @deprecated Use openGLBitsPerPixel */ - int hardwareBitsPerTexel; - /** The OpenGL bytes (type) format of the data buffer used with this texture format, e.g., GL_UNSIGNED_BYTE */ int openGLDataFormat; /** True if there is no alpha channel for this texture. */ bool opaque; - /** True if the bit depths specified are for float formats. */ + + /** True if the bit depths specified are for float formats. TODO: Remove, replace with function keying off numberFormat */ bool floatingPoint; + /** Indicates whether this format treats numbers as integers, floating point, or normalized fixed point */ + NumberFormat numberFormat; + /** Human readable name of this format.*/ const std::string& name() const; + /** True if data in otherFormat is binary compatible */ + bool canInterpretAs(const ImageFormat* otherFormat) const; + + /** Returns ImageFormat representing the same channels as \a + otherFormat plus an alpha channel, all with at least the same + precision as \a otherFormat, or returns NULL if an equivalent + format is unavailable. Will return itself if already contains + an alpha channel. */ + static const ImageFormat* getFormatWithAlpha(const ImageFormat* otherFormat); + + static const ImageFormat* getSRGBFormat(const ImageFormat* otherFormat); + /** Takes the same values that name() returns */ static const ImageFormat* fromString(const std::string& s); + private: ImageFormat @@ -228,11 +285,11 @@ private: int blueBits, int depthBits, int stencilBits, - int hardwareBitsPerTexel, - int packedBitsPerTexel, + int openGLBitsPerPixel, + int cpuBitsPerPixel, int glDataFormat, bool opaque, - bool floatingPoint, + NumberFormat numberFormat, Code code, ColorSpace colorSpace, BayerPattern bayerPattern = BAYER_PATTERN_NONE); @@ -267,14 +324,36 @@ public: static const ImageFormat* BGR8(); + static const ImageFormat* BGRA8(); + static const ImageFormat* R8(); + static const ImageFormat* R8I(); + static const ImageFormat* R8UI(); + + static const ImageFormat* R16(); + static const ImageFormat* R16I(); + static const ImageFormat* R16UI(); + + static const ImageFormat* R32I(); + static const ImageFormat* R32UI(); static const ImageFormat* RG8(); static const ImageFormat* RG8I(); static const ImageFormat* RG8UI(); + static const ImageFormat* RG16(); + static const ImageFormat* RG16I(); + static const ImageFormat* RG16UI(); + + static const ImageFormat* R16F(); static const ImageFormat* RG16F(); + static const ImageFormat* RG32I(); + static const ImageFormat* RG32UI(); + + static const ImageFormat* R32F(); + static const ImageFormat* RG32F(); + static const ImageFormat* RGB5(); static const ImageFormat* RGB5A1(); @@ -299,6 +378,12 @@ public: static const ImageFormat* RGBA32F(); + static const ImageFormat* RGBA16I(); + static const ImageFormat* RGBA16UI(); + + static const ImageFormat* RGB32UI(); + static const ImageFormat* RGB32I(); + static const ImageFormat* RGBA32I(); static const ImageFormat* RGBA32UI(); static const ImageFormat* R11G11B10F(); @@ -309,8 +394,15 @@ public: static const ImageFormat* RGB8UI(); + static const ImageFormat* RGBA8I(); + static const ImageFormat* RGBA8UI(); - + + static const ImageFormat* RGB8_SNORM(); + static const ImageFormat* RGBA8_SNORM(); + static const ImageFormat* RGB16_SNORM(); + static const ImageFormat* RGBA16_SNORM(); + static const ImageFormat* RGB_DXT1(); static const ImageFormat* RGBA_DXT1(); @@ -359,7 +451,7 @@ public: static const ImageFormat* YUV444(); - /** + /** NULL pointer; indicates that the G3D::Texture class should choose either RGBA8 or RGB8 depending on the presence of an alpha channel in the input. @@ -381,7 +473,6 @@ public: static const ImageFormat* fromCode(ImageFormat::Code code); - /** For use with ImageFormat::convert. */ class BayerAlgorithm { public: @@ -418,13 +509,48 @@ public: YUV422 expects data in YUY2 format (Y, U, Y2, v). Most YUV formats require width and heights that are multiples of 2. Returns true if a conversion was available, false if none occurred. + + \deprecated + \sa G3D::ImageConvert */ static bool convert(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, - const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, - bool invertY = false, BayerAlgorithm bayerAlg = BayerAlgorithm::MHC); + const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, + bool invertY = false, BayerAlgorithm bayerAlg = BayerAlgorithm::MHC); - /* Checks if a conversion between two formats is available. */ + /** + Checks if a conversion between two formats is available. + \deprecated + \sa G3D::ImageConvert + */ static bool conversionAvailable(const ImageFormat* srcFormat, int srcRowPadBits, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY = false); + + /** Does this contain exactly one unorm8 component? */ + bool representableAsColor1unorm8() const; + + /** Does this contain exactly two unorm8 components? */ + bool representableAsColor2unorm8() const; + + /** Does this contain exactly three unorm8 components? */ + bool representableAsColor3unorm8() const; + + /** Does this contain exactly four unorm8 components? */ + bool representableAsColor4unorm8() const; + + /** Returns a Color4 that masks off unused components in the format, given in RGBA + For example, the mask for R32F is (1,0,0,0), for A32F is (0,0,0,1), for RGB32F is (1,1,1,0). + (Note that luminance is interpreted as using only the R channel, even though RGB would make more sense + to me...) + */ + Color4 channelMask() const; + + bool isIntegerFormat() const{ + return (numberFormat == INTEGER_FORMAT); + } + + /** Returns true if these formats have the same components + (possibly in different NumberFormat%s or sizes) */ + bool sameComponents(const ImageFormat* other) const; + }; typedef ImageFormat TextureFormat; diff --git a/deps/g3dlite/include/G3D/Intersect.h b/deps/g3dlite/include/G3D/Intersect.h index 8dc4d0c68..cc841d650 100644 --- a/deps/g3dlite/include/G3D/Intersect.h +++ b/deps/g3dlite/include/G3D/Intersect.h @@ -27,27 +27,27 @@ namespace G3D { class Intersect { public: - /** \brief Returns true if the intersection of the ray and the solid box is non-empty. + /** \brief Returns true if the intersection of the ray and the solid box is non-empty. \cite "Fast Ray / Axis-Aligned Bounding Box Overlap Tests using Ray Slopes" - by Martin Eisemann, Thorsten Grosch, Stefan M�ller and Marcus Magnor + by Martin Eisemann, Thorsten Grosch, Stefan Mller and Marcus Magnor Computer Graphics Lab, TU Braunschweig, Germany and University of Koblenz-Landau, Germany */ - static bool __fastcall rayAABox(const Ray& ray, const AABox& box); + static bool __fastcall rayAABox(const Ray& ray, const AABox& box); - /** \brief Returns true if the intersection of the ray and the solid box is non-empty. - + /** \brief Returns true if the intersection of the ray and the solid box is non-empty. + \param time If there is an intersection, set to the time to that intersection. If the ray origin is inside the box, this is a negative value indicating the distance backwards from the ray origin to the first intersection. \a time is not set if there is no intersection. \cite Slope-Mul method from "Fast Ray / Axis-Aligned Bounding Box Overlap Tests using Ray Slopes" - by Martin Eisemann, Thorsten Grosch, Stefan M�ller and Marcus Magnor + by Martin Eisemann, Thorsten Grosch, Stefan Mller and Marcus Magnor Computer Graphics Lab, TU Braunschweig, Germany and University of Koblenz-Landau, Germany */ - static bool __fastcall rayAABox(const Ray& ray, const AABox& box, float& time); + static bool __fastcall rayAABox(const Ray& ray, const AABox& box, float& time); }; } diff --git a/deps/g3dlite/include/G3D/KDTree.h b/deps/g3dlite/include/G3D/KDTree.h index 4785ef2ba..57b54acc5 100644 --- a/deps/g3dlite/include/G3D/KDTree.h +++ b/deps/g3dlite/include/G3D/KDTree.h @@ -10,8 +10,8 @@ All rights reserved. */ -#ifndef G3D_KDTREE_H -#define G3D_KDTREE_H +#ifndef G3D_KDTree_h +#define G3D_KDTree_h #include "G3D/platform.h" #include "G3D/Array.h" @@ -24,11 +24,10 @@ #include "G3D/Box.h" #include "G3D/Triangle.h" #include "G3D/Ray.h" -#include "G3D/GCamera.h" +#include "G3D/Frustum.h" #include "G3D/BinaryInput.h" #include "G3D/BinaryOutput.h" #include "G3D/CollisionDetection.h" -#include "G3D/GCamera.h" #include "G3D/BoundsTrait.h" #include @@ -260,11 +259,11 @@ protected: /** Compares centers */ class CenterComparator { public: - Vector3::Axis sortAxis; + Vector3::Axis sortAxis; - CenterComparator(Vector3::Axis a) : sortAxis(a) {} + CenterComparator(Vector3::Axis a) : sortAxis(a) {} - inline int operator()(Handle* A, const Handle* B) const { + inline int operator()(Handle* A, const Handle* B) const { float a = A->center[sortAxis]; float b = B->center[sortAxis]; @@ -275,18 +274,18 @@ protected: } else { return 0; } - } + } }; /** Compares bounds for strict >, <, or overlap*/ class BoundsComparator { public: - Vector3::Axis sortAxis; + Vector3::Axis sortAxis; - BoundsComparator(Vector3::Axis a) : sortAxis(a) {} + BoundsComparator(Vector3::Axis a) : sortAxis(a) {} - inline int operator()(Handle* A, const Handle* B) const { + inline int operator()(Handle* A, const Handle* B) const { const AABox& a = A->bounds; const AABox& b = B->bounds; @@ -297,34 +296,34 @@ protected: } else { return 0; } - } + } }; /** Compares bounds to the sort location */ class Comparator { public: - Vector3::Axis sortAxis; - float sortLocation; + Vector3::Axis sortAxis; + float sortLocation; - Comparator(Vector3::Axis a, float l) : sortAxis(a), sortLocation(l) {} + Comparator(Vector3::Axis a, float l) : sortAxis(a), sortLocation(l) {} - inline int operator()(Handle* ignore, const Handle* handle) const { + inline int operator()(Handle* ignore, const Handle* handle) const { (void)ignore; const AABox& box = handle->bounds; debugAssert(ignore == NULL); - if (box.high()[sortAxis] < sortLocation) { + if (box.high()[sortAxis] < sortLocation) { // Box is strictly below the sort location return -1; - } else if (box.low()[sortAxis] > sortLocation) { + } else if (box.low()[sortAxis] > sortLocation) { // Box is strictly above the sort location - return 1; - } else { + return 1; + } else { // Box overlaps the sort location - return 0; - } - } + return 0; + } + } }; // Using System::malloc with this class provided no speed improvement. @@ -433,8 +432,8 @@ protected: } void verifyNode(const Vector3& lo, const Vector3& hi) { - // debugPrintf("Verifying: split %d @ %f [%f, %f, %f], [%f, %f, %f]\n", - // splitAxis, splitLocation, lo.x, lo.y, lo.z, hi.x, hi.y, hi.z); + // debugPrintf("Verifying: split %d @ %f [%f, %f, %f], [%f, %f, %f]\n", + // splitAxis, splitLocation, lo.x, lo.y, lo.z, hi.x, hi.y, hi.z); debugAssertM(lo == splitBounds.low(), format("lo = %s, splitBounds.lo = %s", @@ -444,6 +443,7 @@ protected: for (int i = 0; i < valueArray.length(); ++i) { const AABox& b = valueArray[i]->bounds; debugAssert(b == boundsArray[i]); + (void)b; for(int axis = 0; axis < 3; ++axis) { debugAssert(b.low()[axis] <= b.high()[axis]); @@ -714,27 +714,27 @@ protected: int numMeanSplits, Array& temp) { - Node* node = NULL; - - if (source.size() <= valuesPerNode) { - // Make a new leaf node - node = new Node(source); - - // Set the pointers in the memberTable - for (int i = 0; i < source.size(); ++i) { - memberTable.set(Member(source[i]), node); - } + Node* node = NULL; + + if (source.size() <= valuesPerNode) { + // Make a new leaf node + node = new Node(source); + + // Set the pointers in the memberTable + for (int i = 0; i < source.size(); ++i) { + memberTable.set(Member(source[i]), node); + } source.clear(); - + } else { - // Make a new internal node - node = new Node(); - + // Make a new internal node + node = new Node(); + const AABox& bounds = computeBounds(source, 0, source.size() - 1); - const Vector3& extent = bounds.high() - bounds.low(); - - Vector3::Axis splitAxis = extent.primaryAxis(); - + const Vector3& extent = bounds.high() - bounds.low(); + + Vector3::Axis splitAxis = extent.primaryAxis(); + float splitLocation; // Arrays for holding the children @@ -829,20 +829,20 @@ protected: for (int i = 0; i < node->valueArray.size(); ++i) { Handle* v = node->valueArray[i]; node->boundsArray[i] = v->bounds; - memberTable.set(Member(v), node); + memberTable.set(Member(v), node); } - if (lt.size() > 0) { - node->child[0] = makeNode(lt, valuesPerNode, numMeanSplits - 1, temp); - } - - if (gt.size() > 0) { - node->child[1] = makeNode(gt, valuesPerNode, numMeanSplits - 1, temp); - } - - } - - return node; + if (lt.size() > 0) { + node->child[0] = makeNode(lt, valuesPerNode, numMeanSplits - 1, temp); + } + + if (gt.size() > 0) { + node->child[1] = makeNode(gt, valuesPerNode, numMeanSplits - 1, temp); + } + + } + + return node; } /** @@ -1211,7 +1211,7 @@ public: /** Typically used to find all visible - objects inside the view frustum (see also GCamera::getClipPlanes)... i.e. all objects + objects inside the view frustum (see also Camera::getClipPlanes)... i.e. all objects not culled by frustum. Example: @@ -1222,7 +1222,7 @@ public: @param members The results are appended to this array. */ - void getIntersectingMembers(const GCamera::Frustum& frustum, Array& members) const { + void getIntersectingMembers(const Frustum& frustum, Array& members) const { Array plane; for (int i = 0; i < frustum.faceArray.size(); ++i) { @@ -1232,7 +1232,7 @@ public: getIntersectingMembers(plane, members); } - void getIntersectingMembers(const GCamera::Frustum& frustum, Array& members) const { + void getIntersectingMembers(const Frustum& frustum, Array& members) const { Array temp; getIntersectingMembers(frustum, temp); for (int i = 0; i < temp.size(); ++i) { @@ -1450,49 +1450,50 @@ public: /** Invoke a callback for every member along a ray until the closest intersection is found. - @param callback either a function or an instance of a class with an overloaded operator() of the form: - - void callback(const Ray& ray, const T& object, float& distance). If the ray hits the object - before travelling distance distance, updates distance with the new distance to - the intersection, otherwise leaves it unmodified. A common example is: - + @param intersectCallback Either a function or an instance of a class with an overloaded operator() of the form: +
    +         void callback(const Ray& ray, const T& object, float& distance).
    +     
    + If the ray hits the object before travelling distance distance, updates + distance with the new distance to the intersection, otherwise leaves it + unmodified. A common example is: + \htmlonly
          class Entity {
          public:
    +         void intersect(const Ray& ray, float& maxDist, Vector3& outLocation, Vector3& outNormal) {
    +             float d = maxDist;
     
    -                void intersect(const Ray& ray, float& maxDist, Vector3& outLocation, Vector3& outNormal) {
    -                    float d = maxDist;
    +             // ... search for intersection distance d
     
    -                    // ... search for intersection distance d
    +             if ((d > 0) && (d < maxDist)) {
    +                 // Intersection occured
    +                 maxDist = d;
    +                 outLocation = ...;
    +                 outNormal = ...;
    +             }
    +         }
    +     };
     
    -                    if ((d > 0) && (d < maxDist)) {
    -                        // Intersection occured
    -                        maxDist = d;
    -                        outLocation = ...;
    -                        outNormal = ...;
    -                    }
    -                }
    -            };
    +     // Finds the surface normal and location of the first intersection with the scene
    +     class Intersection {
    +     public:
    +         Entity*     closestEntity;
    +         Vector3     hitLocation;
    +         Vector3     hitNormal;
     
    -            // Finds the surface normal and location of the first intersection with the scene
    -            class Intersection {
    -            public:
    -                Entity*     closestEntity;
    -                Vector3     hitLocation;
    -                Vector3     hitNormal;
    +         void operator()(const Ray& ray, const Entity* entity, float& distance) {
    +             entity->intersect(ray, distance, hitLocation, hitNormal);
    +         }
    +     };
     
    -                void operator()(const Ray& ray, const Entity* entity, float& distance) {
    -                    entity->intersect(ray, distance, hitLocation, hitNormal);
    -                }
    -            };
    -
    -            KDTree scene;
    -
    -            Intersection intersection;
    -            float distance = finf();
    -            scene.intersectRay(camera.worldRay(x, y), intersection, distance);
    -          
    + KDTree scene; + Intersection intersection; + float distance = finf(); + scene.intersectRay(camera.worldRay(x, y), intersection, distance); + + \endhtmlonly @param distance When the method is invoked, this is the maximum distance that the tree should search for an intersection. On diff --git a/deps/g3dlite/include/G3D/Line.h b/deps/g3dlite/include/G3D/Line.h index 3579a6bec..2686474c4 100644 --- a/deps/g3dlite/include/G3D/Line.h +++ b/deps/g3dlite/include/G3D/Line.h @@ -38,11 +38,11 @@ public: /** Undefined (provided for creating Array only) */ inline Line() {} - Line(class BinaryInput& b); + Line(class BinaryInput& b); - void serialize(class BinaryOutput& b) const; + void serialize(class BinaryOutput& b) const; - void deserialize(class BinaryInput& b); + void deserialize(class BinaryInput& b); virtual ~Line() {} diff --git a/deps/g3dlite/include/G3D/LineSegment.h b/deps/g3dlite/include/G3D/LineSegment.h index 70210ec7e..9d3b7e3d3 100644 --- a/deps/g3dlite/include/G3D/LineSegment.h +++ b/deps/g3dlite/include/G3D/LineSegment.h @@ -21,35 +21,39 @@ namespace G3D { class LineSegment { protected: - Vector3 _point; + Point3 _point; /** Not normalized */ Vector3 direction; - LineSegment(const Vector3& __point, const Vector3& _direction) : _point(__point), direction(_direction) { + LineSegment(const Point3& __point, const Vector3& _direction) : _point(__point), direction(_direction) { } public: - inline LineSegment() : _point(Vector3::zero()), direction(Vector3::zero()) {} + LineSegment() : _point(Point3::zero()), direction(Vector3::zero()) {} - LineSegment(class BinaryInput& b); - - void serialize(class BinaryOutput& b) const; - - void deserialize(class BinaryInput& b); + LineSegment(class BinaryInput& b); + + void serialize(class BinaryOutput& b) const; + + void deserialize(class BinaryInput& b); virtual ~LineSegment() {} - + /** * Constructs a line from two (not equal) points. */ - static LineSegment fromTwoPoints(const Vector3 &point1, const Vector3 &point2) { + static LineSegment fromTwoPoints(const Point3 &point1, const Point3 &point2) { return LineSegment(point1, point2 - point1); } - /** Call with 0 or 1 */ - Vector3 point(int i) const; + /** Call with 0 or 1 */ + Point3 point(int i) const; + + Point3 midpoint() const { + return _point + direction * 0.5f; + } inline float length() const { return direction.magnitude(); @@ -58,23 +62,23 @@ public: /** * Returns the closest point on the line segment to point. */ - Vector3 closestPoint(const Vector3 &point) const; + Point3 closestPoint(const Point3 &point) const; /** Returns the distance between point and the line */ - double distance(const Vector3& p) const { + double distance(const Point3& p) const { return (closestPoint(p) - p).magnitude(); } - double distanceSquared(const Vector3& p) const { + double distanceSquared(const Point3& p) const { return (closestPoint(p) - p).squaredMagnitude(); } /** Returns true if some part of this segment is inside the sphere */ bool intersectsSolidSphere(const class Sphere& s) const; - Vector3 randomPoint() const; + Point3 randomPoint() const; }; @@ -82,7 +86,7 @@ public: class LineSegment2D { private: - Vector2 m_origin; + Point2 m_origin; /** Not normalized */ Vector2 m_direction; @@ -94,17 +98,17 @@ public: LineSegment2D() {} - static LineSegment2D fromTwoPoints(const Vector2& p0, const Vector2& p1); + static LineSegment2D fromTwoPoints(const Point2& p0, const Vector2& p1); /** Returns the intersection of these segements (including - testing endpoints), or Vector2::inf() if they do not intersect. */ - Vector2 intersection(const LineSegment2D& other) const; + testing endpoints), or Point2::inf() if they do not intersect. */ + Point2 intersection(const LineSegment2D& other) const; - Vector2 point(int i) const; + Point2 point(int i) const; - Vector2 closestPoint(const Vector2& Q) const; + Point2 closestPoint(const Point2& Q) const; - float distance(const Vector2& p) const; + float distance(const Point2& p) const; float length() const; }; diff --git a/deps/g3dlite/include/G3D/Log.h b/deps/g3dlite/include/G3D/Log.h index d252d0c1a..c8a5d53f8 100644 --- a/deps/g3dlite/include/G3D/Log.h +++ b/deps/g3dlite/include/G3D/Log.h @@ -14,7 +14,7 @@ #include #include "G3D/platform.h" -#ifndef G3D_WIN32 +#ifndef G3D_WINDOWS #include #endif @@ -57,9 +57,9 @@ private: static Log* commonLog; +public: int stripFromStackBottom; -public: /** @param stripFromStackBottom Number of call stacks to strip from the diff --git a/deps/g3dlite/include/G3D/Map2D.h b/deps/g3dlite/include/G3D/Map2D.h index 9af9f7242..ec44c7ed9 100644 --- a/deps/g3dlite/include/G3D/Map2D.h +++ b/deps/g3dlite/include/G3D/Map2D.h @@ -87,7 +87,7 @@ namespace G3D { G3D::GImage - Supports file formats, fast, Color3uint8 and Color4uint8 formats. No interpolation. - G3D::Texture::Ref - Represents image on the graphics card (not directly readable on the CPU). Supports 2D, 3D, and a variety of interpolation methods, loads file formats. + G3D::shared_ptr - Represents image on the graphics card (not directly readable on the CPU). Supports 2D, 3D, and a variety of interpolation methods, loads file formats. G3D::Image3 - A subclass of Map2D that supports image loading and saving and conversion to Texture. @@ -181,7 +181,7 @@ public: typedef Storage StorageType; typedef Compute ComputeType; typedef Map2D Type; - typedef ReferenceCountedPointer Ref; + typedef shared_ptr Ref; protected: @@ -296,7 +296,7 @@ public: GMutex mutex; static Ref create(int w = 0, int h = 0, WrapMode wrap = WrapMode::ERROR) { - return new Map2D(w, h, wrap); + return Ref(new Map2D(w, h, wrap)); } /** Resizes without clearing, leaving garbage. @@ -372,7 +372,7 @@ public: // (we're returning a const reference so this is ok) return const_cast(this)->slowGet(x, y, wrap); } -# ifndef G3D_WIN32 +# ifndef G3D_WINDOWS // gcc gives a useless warning that the above code might reach the end of the function; // we use this line to supress the warning. return ZERO; @@ -393,7 +393,7 @@ public: inline Storage& get(int x, int y, WrapMode wrap) { return const_cast(const_cast(this)->get(x, y, wrap)); -# ifndef G3D_WIN32 +# ifndef G3D_WINDOWS // gcc gives a useless warning that the above code might reach the end of the function; // we use this line to supress the warning. return ZERO; @@ -402,7 +402,7 @@ public: inline Storage& get(int x, int y) { return const_cast(const_cast(this)->get(x, y)); -# ifndef G3D_WIN32 +# ifndef G3D_WINDOWS // gcc gives a useless warning that the above code might reach the end of the function; // we use this line to supress the warning. return ZERO; @@ -441,6 +441,19 @@ public: setChanged(true); } + /** Copy values from \a src, which must have the same size */ + template + void set(const shared_ptr >& src) { + debugAssert(src->width() == width()); + debugAssert(src->height() == height()); + const Array& s = src->data; + int N = w * h; + for (int i = 0; i < N; ++i) { + data[i] = s[i]; + } + setChanged(true); + } + /** flips if @a flip is true*/ void maybeFlipVertical(bool flip) { if (flip) { @@ -448,38 +461,38 @@ public: } } - virtual void flipVertical() { - int halfHeight = h/2; - Storage* d = data.getCArray(); - for (int y = 0; y < halfHeight; ++y) { - int o1 = y * w; - int o2 = (h - y - 1) * w; - for (int x = 0; x < (int)w; ++x) { - int i1 = o1 + x; - int i2 = o2 + x; - Storage temp = d[i1]; - d[i1] = d[i2]; - d[i2] = temp; - } - } + virtual void flipVertical() { + int halfHeight = h/2; + Storage* d = data.getCArray(); + for (int y = 0; y < halfHeight; ++y) { + int o1 = y * w; + int o2 = (h - y - 1) * w; + for (int x = 0; x < (int)w; ++x) { + int i1 = o1 + x; + int i2 = o2 + x; + Storage temp = d[i1]; + d[i1] = d[i2]; + d[i2] = temp; + } + } setChanged(true); - } - - virtual void flipHorizontal() { - int halfWidth = w / 2; - Storage* d = data.getCArray(); - for (int x = 0; x < halfWidth; ++x) { - for (int y = 0; y < (int)h; ++y) { - int i1 = y * w + x; - int i2 = y * w + (w - x - 1); - Storage temp = d[i1]; - d[i1] = d[i2]; - d[i2] = temp; - } - } + } + + virtual void flipHorizontal() { + int halfWidth = w / 2; + Storage* d = data.getCArray(); + for (int x = 0; x < halfWidth; ++x) { + for (int y = 0; y < (int)h; ++y) { + int i1 = y * w + x; + int i2 = y * w + (w - x - 1); + Storage temp = d[i1]; + d[i1] = d[i2]; + d[i2] = temp; + } + } setChanged(true); - } - + } + /** Crops this map so that it only contains pixels between (x, y) and (x + w - 1, y + h - 1) inclusive. */ diff --git a/deps/g3dlite/include/G3D/Matrix.h b/deps/g3dlite/include/G3D/Matrix.h index 3c5394d9a..3293a31a3 100644 --- a/deps/g3dlite/include/G3D/Matrix.h +++ b/deps/g3dlite/include/G3D/Matrix.h @@ -234,7 +234,7 @@ public: }; private: - typedef ReferenceCountedPointer ImplRef; + typedef shared_ptr ImplRef; ImplRef impl; @@ -501,10 +501,13 @@ public: } /** - (ATA)-1AT) computed - using SVD. + \brief Computes the Moore-Penrose pseudo inverse, equivalent to + (ATA)-1AT). The SVD method is used + for performance when the matrix has more than four rows or columns - @param tolerance Use -1 for automatic tolerance. + \cite http://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_pseudoinverse + + \param tolerance Use -1 for automatic tolerance. */ Matrix pseudoInverse(float tolerance = -1) const; @@ -576,7 +579,7 @@ public: /** Serializes in Matlab source format */ void serialize(TextOutput& t) const; - std::string toString(const std::string& name) const; + std::string toString(const std::string& name) const; std::string toString() const { static const std::string name = ""; diff --git a/deps/g3dlite/include/G3D/Matrix2.h b/deps/g3dlite/include/G3D/Matrix2.h index cab70c83e..bfae26e9d 100644 --- a/deps/g3dlite/include/G3D/Matrix2.h +++ b/deps/g3dlite/include/G3D/Matrix2.h @@ -9,7 +9,7 @@ namespace G3D { /** @beta */ class Matrix2 { private: - + // Row, column float data[2][2]; public: @@ -57,14 +57,22 @@ public: data[1][0] / f, data[1][1] / f); } - float* operator[](int i) { - debugAssert(i >= 0 && i <= 2); - return data[i]; + inline float* operator[] (int i) { + debugAssert(i >= 0 && i <= 1); + return (float*)&data[i][0]; } - const float* operator[](int i) const { + inline const float* operator[] (int i) const { debugAssert(i >= 0 && i <= 1); - return data[i]; + return (const float*)&data[i][0]; + } + + inline operator float* () { + return (float*)&data[0][0]; + } + + inline operator const float* () const{ + return (const float*)&data[0][0]; } }; diff --git a/deps/g3dlite/include/G3D/Matrix3.h b/deps/g3dlite/include/G3D/Matrix3.h index 8efb3de55..be2c3fac6 100644 --- a/deps/g3dlite/include/G3D/Matrix3.h +++ b/deps/g3dlite/include/G3D/Matrix3.h @@ -1,14 +1,14 @@ /** - @file Matrix3.h + \file Matrix3.h 3x3 matrix class - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com + \cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com - @created 2001-06-02 - @edited 2006-04-05 + \created 2001-06-02 + \edited 2011-05-05 */ #ifndef G3D_Matrix3_h @@ -32,11 +32,12 @@ namespace G3D { class Any; /** - 3x3 matrix. Do not subclass. + A 3x3 matrix. Do not subclass. Data is unitializd when default constructed. */ class Matrix3 { private: + // Row, column float elt[3][3]; // Hidden operators @@ -47,13 +48,39 @@ private: public: + /** Must be in one of the following forms: + - Matrix3(#, #, # .... #) + - Matrix3::fromAxisAngle(#, #) + - Matrix3::diagonal(#, #, #) + - Matrix3::identity() + */ Matrix3(const Any& any); - operator Any() const; + static Matrix3 fromColumns(const Vector3& c0, const Vector3& c1, const Vector3& c2) { + Matrix3 m; + for (int r = 0; r < 3; ++r) { + m.elt[r][0] = c0[r]; + m.elt[r][1] = c1[r]; + m.elt[r][2] = c2[r]; + } + return m; + } - /** Initial values are undefined for performance. See also - Matrix3::zero(), Matrix3::identity(), Matrix3::fromAxisAngle, etc.*/ - inline Matrix3() {} + static Matrix3 fromRows(const Vector3& r0, const Vector3& r1, const Vector3& r2) { + Matrix3 m; + for (int c = 0; c < 3; ++c) { + m.elt[0][c] = r0[c]; + m.elt[1][c] = r1[c]; + m.elt[2][c] = r2[c]; + } + return m; + } + + Any toAny() const; + + /** Initial values are undefined for performance. + \sa Matrix3::zero, Matrix3::identity, Matrix3::fromAxisAngle, etc.*/ + Matrix3() {} Matrix3 (class BinaryInput& b); Matrix3 (const float aafEntry[3][3]); @@ -62,13 +89,19 @@ public: float fEntry10, float fEntry11, float fEntry12, float fEntry20, float fEntry21, float fEntry22); - bool fuzzyEq(const Matrix3& b) const; + bool fuzzyEq(const Matrix3& b) const; /** Constructs a matrix from a quaternion. @cite Graphics Gems II, p. 351--354 - @cite Implementation from Watt and Watt, pg 362*/ + @cite Implementation from Watt and Watt, pg 362*/ Matrix3(const class Quat& q); + static Matrix3 diagonal(float e00, float e11, float e22) { + return Matrix3(e00, 0, 0, + 0, e11, 0, + 0, 0, e22); + } + void serialize(class BinaryOutput& b) const; void deserialize(class BinaryInput& b); @@ -83,7 +116,7 @@ public: float fEntry20, float fEntry21, float fEntry22); /** - * member access, allows use of construct mat[r][c] + Member access, allows use of construct mat[r][c] */ inline float* operator[] (int iRow) { debugAssert(iRow >= 0); @@ -209,8 +242,8 @@ public: bool isOrthonormal() const; Matrix3 transpose () const; - bool inverse (Matrix3& rkInverse, float fTolerance = 1e-06) const; - Matrix3 inverse (float fTolerance = 1e-06) const; + bool inverse (Matrix3& rkInverse, float fTolerance = 1e-06f) const; + Matrix3 inverse (float fTolerance = 1e-06f) const; float determinant () const; /** singular value decomposition */ @@ -267,8 +300,12 @@ public: 0, 0, d.z); } + /** \sa fromUnitAxisAngle */ static Matrix3 fromAxisAngle(const Vector3& rkAxis, float fRadians); + /** Assumes that rkAxis has unit length */ + static Matrix3 fromUnitAxisAngle(const Vector3& rkAxis, float fRadians); + /** * The matrix must be orthonormal. The decomposition is yaw*pitch*roll * where yaw is rotation about the Up vector, pitch is rotation about the @@ -312,7 +349,7 @@ public: // "You might be tempted to write [...] them as inline functions // inside their respective header files, but this is something you // must definitely not do. An inline function can be duplicated - // in every file in which it appears ���� and this duplication + // in every file in which it appears and this duplication // includes the static object definition. Because inline functions // automatically default to internal linkage, this would result in // having multiple static objects across the various translation diff --git a/deps/g3dlite/include/G3D/Matrix4.h b/deps/g3dlite/include/G3D/Matrix4.h index 6b810ba77..d33006a4a 100644 --- a/deps/g3dlite/include/G3D/Matrix4.h +++ b/deps/g3dlite/include/G3D/Matrix4.h @@ -5,8 +5,8 @@ @maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2003-10-02 - @edited 2009-10-20 + \created 2003-10-02 + \edited 2012-12-25 */ #ifndef G3D_Matrix4_h @@ -26,11 +26,12 @@ namespace G3D { class Any; +class Matrix2; /** - A 4x4 matrix. + A 4x4 matrix. Do not subclass. Data is initialized to 0 when default constructed. - See also G3D::CoordinateFrame, G3D::Matrix3, G3D::Quat + \sa G3D::CoordinateFrame, G3D::Matrix3, G3D::Quat */ class Matrix4 { private: @@ -50,10 +51,20 @@ private: bool operator>=(const Matrix4&) const; public: - /** Must be of the form: Matrix4(#, #, # .... #)*/ - Matrix4(const Any& any); - operator Any() const; + /** Must be in one of the following forms: + - Matrix4(#, #, # .... #) + - Matrix4::scale(#) + - Matrix4::scale(#, #, #) + - Matrix4::translation(#, #, #) + - Matrix4::identity() + - Matrix4::rollDegrees(#) + - Matrix4::pitchDegrees(#) + - Matrix4::yawDegrees(#) + */ + explicit Matrix4(const Any& any); + + Any toAny() const; Matrix4( float r1c1, float r1c2, float r1c3, float r1c4, @@ -66,17 +77,25 @@ public: */ Matrix4(const float* init); - /** - a is the upper left 3x3 submatrix and b is the upper right 3x1 submatrix. The last row of the created matrix is (0,0,0,1). - */ + /** + a is the upper left 3x3 submatrix and b is the upper right 3x1 submatrix. The last row of the created matrix is (0,0,0,1). + */ Matrix4(const class Matrix3& upper3x3, const class Vector3& lastCol = Vector3::zero()); Matrix4(const class CoordinateFrame& c); Matrix4(const double* init); + /** Matrix4::zero() */ Matrix4(); + static Matrix4 diagonal(float e00, float e11, float e22, float e33) { + return Matrix4(e00, 0, 0, 0, + 0, e11, 0, 0, + 0, 0, e22, 0, + 0, 0, 0, e33); + } + /** Produces an RT transformation that nearly matches this Matrix4. Because a Matrix4 may not be precisely a rotation and translation, this may introduce error. */ @@ -88,14 +107,19 @@ public: static const Matrix4& zero(); /** If this is a perspective projection matrix created by - Matrix4::perspectiveProjection, extract its parameters. */ + Matrix4::perspectiveProjection, extract its parameters. + + Uses double precision because the operations involved in + projection involve divisions that can significantly impact + precision. + */ void getPerspectiveProjectionParameters - (float& left, - float& right, - float& bottom, - float& top, - float& nearval, - float& farval, + (double& left, + double& right, + double& bottom, + double& top, + double& nearval, + double& farval, float updirection = -1.0f) const; inline float* operator[](int r) { @@ -110,6 +134,7 @@ public: return (const float*)&elt[r]; } + /** Returns a row-major pointer. */ inline operator float* () { return (float*)&elt[0][0]; } @@ -131,6 +156,8 @@ public: class Matrix3 upper3x3() const; + class Matrix2 upper2x2() const; + /** Homogeneous multiplication. Let k = M * [v w]^T. result = k.xyz() / k.w */ class Vector3 homoMul(const class Vector3& v, float w) const; @@ -151,7 +178,6 @@ public: float farval, float upDirection = -1.0f); - /** \param upDirection Use -1.0 for 2D Y increasing downwards (the G3D 8.x default convention), 1.0 for 2D Y increasing upwards (the G3D 7.x default and OpenGL convention) */ @@ -163,15 +189,18 @@ public: /** \param upDirection Use -1.0 for 2D Y increasing downwards (the G3D 8.x default convention), 1.0 for 2D Y increasing upwards (the G3D 7.x default and OpenGL convention) - */ + + Uses double precision because the operations involved in + projection involve divisions that can significantly impact + precision. */ static Matrix4 perspectiveProjection( - float left, - float right, - float bottom, - float top, - float nearval, - float farval, - float upDirection = -1.0f); + double left, + double right, + double bottom, + double top, + double nearval, + double farval, + float upDirection = -1.0f); void setRow(int r, const class Vector4& v); void setColumn(int c, const Vector4& v); @@ -248,6 +277,67 @@ public: }; +/** Double-precision 4x4 matrix */ +class Matrix4float64 { +private: + + double elt[4][4]; + +public: + + explicit Matrix4float64(const Matrix4& m); + + /** all zeros */ + Matrix4float64(); + + Matrix4float64( + double r1c1, double r1c2, double r1c3, double r1c4, + double r2c1, double r2c2, double r2c3, double r2c4, + double r3c1, double r3c2, double r3c3, double r3c4, + double r4c1, double r4c2, double r4c3, double r4c4); + + // Special values. + // Intentionally not inlined: see Matrix3::identity() for details. + static const Matrix4float64& identity(); + + static const Matrix4float64& zero(); + + bool operator!=(const Matrix4float64& other) const; + + bool operator==(const Matrix4float64& other) const; + + Vector4 operator*(const Vector4& vector) const; + + static Matrix4float64 perspectiveProjection( + double left, + double right, + double bottom, + double top, + double nearval, + double farval, + float upDirection = -1.0f); + + inline double* operator[](int r) { + debugAssert(r >= 0); + debugAssert(r < 4); + return (double*)&elt[r]; + } + + inline const double* operator[](int r) const { + debugAssert(r >= 0); + debugAssert(r < 4); + return (const double*)&elt[r]; + } + + inline operator double* () { + return (double*)&elt[0][0]; + } + + inline operator const double* () const { + return (const double*)&elt[0][0]; + } +}; + } // namespace diff --git a/deps/g3dlite/include/G3D/MemoryManager.h b/deps/g3dlite/include/G3D/MemoryManager.h index 15bf6d8be..be6f6400c 100644 --- a/deps/g3dlite/include/G3D/MemoryManager.h +++ b/deps/g3dlite/include/G3D/MemoryManager.h @@ -20,7 +20,7 @@ namespace G3D { Abstraction of memory management. Default implementation uses G3D::System::malloc and is threadsafe. - \sa CRTMemoryManager, AlignedMemoryManager, AreaMemoryManager */ + \sa LargePoolMemoryManager, CRTMemoryManager, AlignedMemoryManager, AreaMemoryManager */ class MemoryManager : public ReferenceCountedObject { protected: @@ -28,7 +28,7 @@ protected: public: - typedef ReferenceCountedPointer Ref; + typedef shared_ptr Ref; /** Return a pointer to \a s bytes of memory that are unused by the rest of the program. The contents of the memory are @@ -59,7 +59,7 @@ protected: public: - typedef ReferenceCountedPointer Ref; + typedef shared_ptr Ref; virtual void* alloc(size_t s); @@ -72,13 +72,14 @@ public: }; -/** MemoryManager implemented using the C runtime. */ +/** A MemoryManager implemented using the C runtime. Not recommended + for general use; this is largely for debugging. */ class CRTMemoryManager : public MemoryManager { protected: CRTMemoryManager(); public: - typedef ReferenceCountedPointer Ref; + typedef shared_ptr Ref; virtual void* alloc(size_t s); virtual void free(void* ptr); virtual bool isThreadsafe() const; diff --git a/deps/g3dlite/include/G3D/MeshAlg.h b/deps/g3dlite/include/G3D/MeshAlg.h index da55d1300..d0cdd528b 100644 --- a/deps/g3dlite/include/G3D/MeshAlg.h +++ b/deps/g3dlite/include/G3D/MeshAlg.h @@ -20,9 +20,10 @@ #include "G3D/constants.h" #include "G3D/Image1.h" -#ifdef G3D_WIN32 +#ifdef G3D_WINDOWS // Turn off "conditional expression is constant" warning; MSVC generates this // for debug assertions in inlined methods. +#pragma warning( push ) #pragma warning (disable : 4127) #endif @@ -444,7 +445,7 @@ public: Array& newVertexPositions, Array& toNew, Array& toOld, - double radius = fuzzyEpsilon); + float radius = fuzzyEpsilon32); /** Modifies the face, edge, and vertex arrays in place so that @@ -479,7 +480,7 @@ public: Array& faceArray, Array& edgeArray, Array& vertexArray, - double radius = fuzzyEpsilon); + float radius = fuzzyEpsilon32); /** @@ -535,7 +536,7 @@ public: /** Generates a unit square in the X-Z plane composed of a grid of wCells x hCells - squares and then transforms it by xform. + squares on the unit interval and then transforms it by xform. @param vertex Output vertices @param texCoord Output texture coordinates @@ -545,8 +546,8 @@ public: @param twoSided If true, matching top and bottom planes are generated. \param elevation If non-NULL, values from this image are used as elevations. Apply an \a xform to adjust the scale */ - static void generateGrid( - Array& vertex, + static void generateGrid + (Array& vertex, Array& texCoord, Array& index, int wCells = 10, @@ -555,7 +556,7 @@ public: bool spaceCentered = true, bool twoSided = true, const CoordinateFrame& xform = CoordinateFrame(), - const Image1::Ref& elevation = NULL); + const Image1::Ref& elevation = Image1::Ref()); /** Converts quadlist (QUADS), triangle fan (TRIANGLE_FAN), @@ -679,5 +680,11 @@ protected: int i0, int i1, int f, double area); }; } + + +#ifdef G3D_WINDOWS +#pragma warning( pop ) +#endif + #endif diff --git a/deps/g3dlite/include/G3D/MeshBuilder.h b/deps/g3dlite/include/G3D/MeshBuilder.h index 9920d59d7..b8a5f5bf1 100644 --- a/deps/g3dlite/include/G3D/MeshBuilder.h +++ b/deps/g3dlite/include/G3D/MeshBuilder.h @@ -34,6 +34,8 @@ private: typedef Array List; std::string name; + + bool scaleAndCenter; /** All of the triangles, as a long triangle list. @@ -43,14 +45,14 @@ private: void centerTriList(); void computeBounds(Vector3& min, Vector3& max); - bool _twoSided; + bool _twoSided; /** Collapse radius */ double close; public: - inline MeshBuilder(bool twoSided = false) : _twoSided(twoSided), close(AUTO_WELD) {} + inline MeshBuilder(bool twoSided = false, bool scaleAndCenter = true) : scaleAndCenter(scaleAndCenter), _twoSided(twoSided), close(AUTO_WELD) {} /** Writes the model to the arrays, which can then be used with G3D::IFSModel::save and G3D::MeshAlg */ diff --git a/deps/g3dlite/include/G3D/NetAddress.h b/deps/g3dlite/include/G3D/NetAddress.h index fd5a19959..f4bc03f45 100644 --- a/deps/g3dlite/include/G3D/NetAddress.h +++ b/deps/g3dlite/include/G3D/NetAddress.h @@ -1,3 +1,9 @@ +/** + \file G3D/NetAddress.h + + \created 2010-01-03 + \edited 2013-03-17 + */ #ifndef G3D_NetAddress_h #define G3D_NetAddress_h @@ -24,20 +30,31 @@ private: SOCKADDR_IN addr; public: + + enum { + /** + Use the host portion of the IP address of the default adapter on this machine. + */ + // Must match ENET_HOST_ANY + DEFAULT_ADAPTER_HOST = 0 + }; + /** - In host byte order + In host byte order. + + \sa DEFAULT_ADAPTER_HOST */ - NetAddress(uint32 host, uint16 port = 0); + explicit NetAddress(uint32 host, uint16 port = 0); /** @param port Specified in host byte order (i.e., don't worry about endian issues) - */ + */ NetAddress(const std::string& hostname, uint16 port); /** @param hostnameAndPort in the form "hostname:port" or "ip:port" */ - NetAddress(const std::string& hostnameAndPort); + explicit NetAddress(const std::string& hostnameAndPort); /** @deprecated Use G3D::NetworkDevice::broadcastAddressArray() @@ -56,6 +73,8 @@ public: NetAddress(); + static void localHostAddresses(Array& array); + void serialize(class BinaryOutput& b) const; void deserialize(class BinaryInput& b); @@ -76,6 +95,13 @@ public: std::string ipString() const; std::string toString() const; + /** Name of this address, without the domain. Performs reverse DNS lookup on this address. This may make a network + connection to a DNS server and block until that communication completes + if the address is one that has not been recently checked.*/ + std::string hostname() const; + + /** Name of the local machine machine, without the domain. The value is cached after the first call.*/ + static std::string localHostname(); }; std::ostream& operator<<(std::ostream& os, const NetAddress&); @@ -95,7 +121,7 @@ namespace G3D { they have different IP's. */ inline bool operator==(const NetAddress& a, const NetAddress& b) { - return (a.ip() == b.ip()) && (a.port() == b.port()); + return (a.ip() == b.ip()) && (a.port() == b.port()); } diff --git a/deps/g3dlite/include/G3D/NetworkDevice.h b/deps/g3dlite/include/G3D/NetworkDevice.h index 7a3f8ed4a..e60878cb8 100644 --- a/deps/g3dlite/include/G3D/NetworkDevice.h +++ b/deps/g3dlite/include/G3D/NetworkDevice.h @@ -1,6 +1,5 @@ /** @file NetworkDevice.h - These classes abstract networking from the socket level to a serialized messaging style that is more appropriate for games. The performance has been tuned for sending many small messages. The @@ -54,7 +53,7 @@ namespace G3D { class TextOutput; - +/** \deprecated */ class Conduit : public ReferenceCountedObject { protected: friend class NetworkDevice; @@ -134,7 +133,7 @@ public: bool ok() const; }; -typedef ReferenceCountedPointer ReliableConduitRef; +typedef shared_ptr ReliableConduitRef; #ifdef __GNUC__ // Workaround for a known bug in gcc 4.x where htonl produces @@ -164,7 +163,7 @@ uint32 gcchtonl(uint32); You will need the server's G3D::NetAddress. Consider using G3D::Discovery::Client to find it via broadcasting. - + \deprecated */ class ReliableConduit : public Conduit { private: @@ -209,7 +208,7 @@ private: // Reserve space for the 4 byte size header b.writeUInt32(0); - size_t L = b.length(); + size_t L = (size_t)b.length(); m.serialize(b); if ((size_t)b.length() == L) { // No data was created by serialization. @@ -218,7 +217,7 @@ private: b.writeUInt8(0xFF); } - uint32 len = b.size() - 8; + uint32 len = (uint32)b.size() - 8; // We send the length first to tell recv how much data to read. // Here we abuse BinaryOutput a bit and write directly into @@ -353,7 +352,7 @@ public: }; -typedef ReferenceCountedPointer LightweightConduitRef; +typedef shared_ptr LightweightConduitRef; /** Provides fast but unreliable transfer of messages. On a LAN, @@ -402,6 +401,8 @@ and a pointer to an instance of the message you want to send. it go out of scope and the conduit cleans itself up automatically. + +\deprecated */ class LightweightConduit : public Conduit { private: @@ -458,7 +459,7 @@ private: format("This LightweightConduit is limited to messages of " "%d bytes (Ethernet hardware limit; this is the " "'UDP MTU')", maxMessageSize()), - b.size() - 4, // Don't count the type header + (int)b.size() - 4, // Don't count the type header maxMessageSize()); } } @@ -512,13 +513,13 @@ public: bool receive(NetAddress& sender); template inline bool receive(NetAddress& sender, T& message) { - bool r = receive(sender); - if (r) { - BinaryInput b((messageBuffer.getCArray() + 4), - messageBuffer.size() - 4, - G3D_LITTLE_ENDIAN, BinaryInput::NO_COPY); - message.deserialize(b); - } + bool r = receive(sender); + if (r) { + BinaryInput b((messageBuffer.getCArray() + 4), + messageBuffer.size() - 4, + G3D_LITTLE_ENDIAN, BinaryInput::NO_COPY); + message.deserialize(b); + } return r; } @@ -536,10 +537,12 @@ public: /////////////////////////////////////////////////////////////////////////////// -typedef ReferenceCountedPointer NetListenerRef; +typedef shared_ptr NetListenerRef; /** Runs on the server listening for clients trying to make reliable connections. + + \deprecated */ class NetListener : public ReferenceCountedObject { private: @@ -600,6 +603,7 @@ public: values between these formats. G3D only ever exposes host byte order, so programmers rarely need to be aware of the distinction. + \deprecated */ class NetworkDevice { public: diff --git a/deps/g3dlite/include/G3D/ParseError.h b/deps/g3dlite/include/G3D/ParseError.h index f02948e3d..dc423d676 100644 --- a/deps/g3dlite/include/G3D/ParseError.h +++ b/deps/g3dlite/include/G3D/ParseError.h @@ -52,6 +52,9 @@ public: ParseError(const std::string& f, int64 b, const std::string& m) : filename (f), byte(b), line(UNKNOWN), character(UNKNOWN), message(m) {} + + /** If information is known, ends in ": ", otherwise empty */ + std::string formatFileInfo() const; }; } diff --git a/deps/g3dlite/include/G3D/PhysicsFrame.h b/deps/g3dlite/include/G3D/PhysicsFrame.h index 9aee5e5a8..ae36e312d 100644 --- a/deps/g3dlite/include/G3D/PhysicsFrame.h +++ b/deps/g3dlite/include/G3D/PhysicsFrame.h @@ -1,14 +1,14 @@ /** - @file PhysicsFrame.h + \file PhysicsFrame.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2002-07-08 - @edited 2006-01-10 + \created 2002-07-08 + \edited 2011-05-10 */ -#ifndef G3D_PHYSICSFRAME_H -#define G3D_PHYSICSFRAME_H +#ifndef G3D_PhysicsFrame_h +#define G3D_PhysicsFrame_h #include "G3D/platform.h" #include "G3D/Vector3.h" @@ -33,9 +33,9 @@ public: Quat rotation; /** - Takes object space points to world space. + Origin of this reference frame in its parent's frame. */ - Vector3 translation; + Point3 translation; /** Initializes to the identity frame. @@ -51,6 +51,13 @@ public: PhysicsFrame(const Matrix3& rot) : rotation(rot), translation(Vector3::zero()) {} PhysicsFrame(const CoordinateFrame& coordinateFrame); + PhysicsFrame& operator=(const PhysicsFrame& p) { + rotation = p.rotation; + translation = p.translation; + + return *this; + } + /** - PhysicsFrame( [quat], [vec3] ) - Vector3( ... ) @@ -59,6 +66,8 @@ public: */ PhysicsFrame(const class Any& any); + Any toAny() const; + /** Compose: create the transformation that is other followed by this.*/ PhysicsFrame operator*(const PhysicsFrame& other) const; @@ -100,6 +109,16 @@ public: translation += f.translation; return *this; } + + bool operator==(const PhysicsFrame& other) const { + return (translation == other.translation) && + ((rotation == other.rotation) || (rotation == -other.rotation)); + } + + bool operator!=(const PhysicsFrame& other) const { + return ! ((*this) == other); + } + }; typedef PhysicsFrame PFrame; diff --git a/deps/g3dlite/include/G3D/PhysicsFrameSpline.h b/deps/g3dlite/include/G3D/PhysicsFrameSpline.h index 4a21503df..75d3fea80 100644 --- a/deps/g3dlite/include/G3D/PhysicsFrameSpline.h +++ b/deps/g3dlite/include/G3D/PhysicsFrameSpline.h @@ -20,16 +20,31 @@ namespace G3D { */ class PhysicsFrameSpline : public Spline { public: + PhysicsFrameSpline(); /** Accepts a table of properties, or any valid PhysicsFrame specification for a single control*/ PhysicsFrameSpline(const Any& any); - /** Clear and then reset all values from the any */ - PhysicsFrameSpline& operator=(const Any& any); + bool operator==(const PhysicsFrameSpline& a) const; + + bool operator!=(const PhysicsFrameSpline& a) const { + return ! ((*this) == a); + } + + /** Mutates all underlying PhysicsFrames by scaling their translation by \param scaleFactor */ + void scaleControlPoints(float scaleFactor); virtual void correct(PhysicsFrame& frame) const; virtual void ensureShortestPath(PhysicsFrame* A, int N) const; + + virtual Any toAny(const std::string& myName) const override { + return Spline::toAny(myName); + } + + Any toAny() const { + return toAny("PFrameSpline"); + } }; } diff --git a/deps/g3dlite/include/G3D/Plane.h b/deps/g3dlite/include/G3D/Plane.h index 360bcd2bc..4c1a2487b 100644 --- a/deps/g3dlite/include/G3D/Plane.h +++ b/deps/g3dlite/include/G3D/Plane.h @@ -1,16 +1,16 @@ /** - @file Plane.h + \file Plane.h Plane class - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2001-06-02 - @edited 2004-07-18 + \created 2001-06-02 + \edited 2010-12-04 */ -#ifndef G3D_PLANE_H -#define G3D_PLANE_H +#ifndef G3D_Plane_h +#define G3D_Plane_h #include "G3D/platform.h" #include "G3D/Vector3.h" @@ -26,8 +26,8 @@ class Plane { private: /** normal.Dot(x,y,z) = distance */ - Vector3 _normal; - float _distance; + Vector3 _normal; + float _distance; /** Assumes the normal has unit length. @@ -40,43 +40,51 @@ public: Plane() : _normal(Vector3::unitY()), _distance(0) { } + /** Format is: + - Plane(normal, point) + */ + explicit Plane(const class Any& a); + + Any toAny() const; + /** Constructs a plane from three points. */ - Plane( - const Vector3& point0, - const Vector3& point1, - const Vector3& point2); + Plane + (const Point3& point0, + const Point3& point1, + const Point3& point2); /** Constructs a plane from three points, where at most two are at infinity (w = 0, not xyz = inf). */ Plane( - Vector4 point0, - Vector4 point1, - Vector4 point2); + Vector4 point0, + Vector4 point1, + Vector4 point2); /** The normal will be unitized. */ - Plane( - const Vector3& __normal, - const Vector3& point); + Plane + (const Vector3& normal, + const Point3& point); static Plane fromEquation(float a, float b, float c, float d); - Plane(class BinaryInput& b); - void serialize(class BinaryOutput& b) const; - void deserialize(class BinaryInput& b); + Plane(class BinaryInput& b); + void serialize(class BinaryOutput& b) const; + void deserialize(class BinaryInput& b); + virtual ~Plane() {} /** Returns true if point is on the side the normal points to or is in the plane. */ - inline bool halfSpaceContains(Vector3 point) const { + inline bool halfSpaceContains(Point3 point) const { // Clamp to a finite range for testing point = point.clamp(Vector3::minFinite(), Vector3::maxFinite()); @@ -101,7 +109,7 @@ public: Returns true if point is on the side the normal points to or is in the plane. Only call on finite points. Faster than halfSpaceContains. */ - inline bool halfSpaceContainsFinite(const Vector3& point) const { + inline bool halfSpaceContainsFinite(const Point3& point) const { debugAssert(point.isFinite()); return _normal.dot(point) >= _distance; } @@ -109,13 +117,13 @@ public: /** Returns true if the point is nearly in the plane. */ - inline bool fuzzyContains(const Vector3 &point) const { + inline bool fuzzyContains(const Point3& point) const { return fuzzyEq(point.dot(_normal), _distance); } - inline const Vector3& normal() const { - return _normal; - } + inline const Vector3& normal() const { + return _normal; + } /** Returns distance from point to plane. Distance is negative if point is behind (not in plane in direction opposite normal) the plane. @@ -124,7 +132,7 @@ public: return (_normal.dot(x) - _distance); } - inline Vector3 closestPoint(const Vector3& x) const { + inline Point3 closestPoint(const Point3& x) const { return x + (_normal * (-distance(x))); } @@ -144,8 +152,8 @@ public: normal.Dot(Vector3(x, y, z)) + d = 0 */ - void getEquation(Vector3 &normal, double& d) const; - void getEquation(Vector3 &normal, float& d) const; + void getEquation(Vector3& normal, double& d) const; + void getEquation(Vector3& normal, float& d) const; /** ax + by + cz + d = 0 diff --git a/deps/g3dlite/include/G3D/PointHashGrid.h b/deps/g3dlite/include/G3D/PointHashGrid.h index d0b60a88a..85c502296 100644 --- a/deps/g3dlite/include/G3D/PointHashGrid.h +++ b/deps/g3dlite/include/G3D/PointHashGrid.h @@ -1,11 +1,11 @@ /** - @file PointHashGrid.h + \file PointHashGrid.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2008-07-01 - @edited 2009-05-28 + \maintainer Morgan McGuire, http://graphics.cs.williams.edu + \created 2008-07-01 + \edited 2010-11-28 - Copyright 2000-2010, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ #ifndef G3D_PointHashGrid_h @@ -25,23 +25,23 @@ namespace G3D { /** - Storage of data in a sparse 3D grid of point-based data. The - space cost for n elements is O(n). For data with + \brief A sparse 3D grid of point-based data. + + The space cost for n elements is O(n). For data with approximately uniform density (with respect to the radius hint), the time cost of searching for neighbors is O(1). - Value must be supported by a G3D::PositionTrait and - G3D::EqualsTrait. Overloads are provided for - common G3D classes like G3D::Vector3. For example: - -
    -    class EqualsFunc {
    -    public:
    -        static bool equals(const Data& p, const Data& q) {
    -            return p == q;
    -        }
    -    };
    +    You can move members of the data set by first removing them and then
    +    adding them with a new location.
         
    +    Template argument \a PosFunc must provide a static getPosition method 
    +    and \a EqualsFunc must provide a static equals method, as described below.  
    +    You can either write classes that support these yourself, provide template specializations of
    +    G3D::PositionTrait and
    +    G3D::EqualsTrait, or rely on the default template specializations, which already exist for
    +    common G3D classes like G3D::Point3.  For example:
    +
    +    \code
         class PosFunc {
         public:
             static void getPosition(const Data& d, Vector3& pos) {
    @@ -49,14 +49,43 @@ namespace G3D {
             }
         };
     
    +    class EqualsFunc {
    +    public:
    +        static bool equals(const Data& p, const Data& q) {
    +            return p == q;
    +        }
    +    };
    +    
         PointHashGrid grid;
    -   
    + \endcode - If the Value class defines operator==, the Equalsfunc is optional: + If the \a Value class defines operator==, then the \a Equalsfunc is optional, so you can just write: -
    +   \code
         PointHashGrid grid;
    -   
    + \endcode + + The simplest way to define these is often to make them both methods + of the parameter class itself, e.g., + + \code + + class Data { + public: + Point3 location; + ... + + bool operator==(const Data& other) const { + return (location == other.location) && ...; + } + + static void getPosition(const Data& p, Vector3& pos) { + pos = p.location; + } + }; + + typedef PointHashGrid DataGrid; + \endcode */ template /** A value annotated with precomputed position and hash code.*/ class Entry { public: - Vector3 position; - Value value; + Point3 position; + Value value; }; /** One cell of the grid. */ typedef SmallArray Cell; - typedef Table CellTable; + typedef Table CellTable; /** The cube of +/-1 along each dimension. Initialized by initOffsetArray.*/ Vector3int32 m_offsetArray[3*3*3]; @@ -116,18 +145,19 @@ private: /** Locate the cell and index within that cell containing v. Called by remove() and contains(). */ - bool find(const Value& v, - Vector3int32& foundCellCoord, - Cell*& foundCell, - int& index) { + bool find + (const Value& v, + Point3int32& foundCellCoord, + Cell*& foundCell, + int& index) { - Vector3 pos; + Point3 pos; PosFunc::getPosition(v, pos); - Vector3int32 cellCoord; + Point3int32 cellCoord; getCellCoord(pos, cellCoord); for (int i = 0; i < 27; ++i) { - Vector3int32 c = cellCoord + m_offsetArray[i]; + Point3int32 c = cellCoord + m_offsetArray[i]; Cell* cell = m_data.getPointer(c); if (cell != NULL) { // The cell exists @@ -146,18 +176,25 @@ private: return false; } - /** Given a real-space position, returns the cell coord - containing it.*/ - inline void getCellCoord(const Vector3& pos, Vector3int32& cellCoord) const { +public: + + /** \brief Compute the grid cell index of a real position. + This is used extensively internally by PointHashGrid. + It is useful to calling code to determine when an object + is about to move between cells. + */ + inline void getCellCoord(const Point3& pos, Point3int32& cellCoord) const { for (int a = 0; a < 3; ++a) { cellCoord[a] = iFloor(pos[a] * m_invCellWidth); } } +protected: + /** Initializes m_offsetArray. */ void initOffsetArray() { int i = 0; - Vector3int32 d; + Point3int32 d; for (d.x = -1; d.x <= +1; ++d.x) { for (d.y = -1; d.y <= +1; ++d.y) { for (d.z = -1; d.z <= +1; ++d.z) { @@ -179,9 +216,10 @@ private: public: /** - @param radiusHint the radius that will typically be used with - beginSphereIntersection and beginBoxIntersection. If two Values are equal, - their positions must be within this radius as well. + \param radiusHint the radius that will typically be used with + beginBallIntersection and beginBoxIntersection. If two Values are equal, + their positions must be within this radius as well. You can later change this + value with clearAndSetRadiusHint(). */ PointHashGrid(float radiusHint, const MemoryManager::Ref& m = MemoryManager::create()) : m_size(0), m_memoryManager(m) { initOffsetArray(); @@ -192,23 +230,41 @@ public: m_invCellWidth = 1.0f / m_cellWidth; } + /** \sa clearAndSetRadiusHint() */ + float radiusHint() const { + return m_cellWidth; + } + + void clear(float radiusHint) { + debugAssertM(radiusHint > 0, "Cell radius must be positive"); + clear(); + m_cellWidth = radiusHint; + m_invCellWidth = 1.0f / m_cellWidth; + } + + void clearAndSetRadiusHint(float radiusHint) { + return clear(radiusHint); + } + /** - If radiusHint is negative, it is automatically chosen to put + If \a radiusHint is negative, it is automatically chosen to put about 5 values in each grid cell (which means about 27 * 5 values for each beginIntersection call). + + \sa clearAndSetRadiusHint() */ - PointHashGrid(const Array& init, float radiusHint = -1.0f, const MemoryManager::Ref& m = MemoryManager::create()) : m_size(0), m_memoryManager(m) { + PointHashGrid(const Array& init, float radiusHint = -1.0f, const MemoryManager::Ref& m = MemoryManager::create()) : m_size(0), m_memoryManager(m) { initOffsetArray(); m_data.clearAndSetMemoryManager(m_memoryManager); - Vector3 lo(Vector3::inf()); - Vector3 hi(-lo); + Point3 lo(Vector3::inf()); + Point3 hi(-lo); // Compute bounds Array entry(init.size()); for (int i = 0; i < entry.size(); ++i) { const Value& value = init[i]; - Vector3 pos; + Point3 pos; entry[i].value = value; entry[i].hashCode = m_hashFunc(value); @@ -241,7 +297,7 @@ public: } /** Returns the number of elements. */ - inline int size() const { + int size() const { return m_size; } @@ -251,13 +307,19 @@ public: return m_bounds; } + void debugPrintStatistics() const { + debugPrintf("Deepest bucket size = %d\n", (int)m_data.debugGetDeepestBucketSize()); + debugPrintf("Average bucket size = %g\n", m_data.debugGetAverageBucketSize()); + debugPrintf("Load factor = %g\n", m_data.debugGetLoad()); + } + /** Insert @a v at position @a p given by getPosition(v, p). Multiple elements that are equal may be inserted; all copies will be in the data structure. */ void insert(const Value& v) { - Vector3 pos; + Point3 pos; PosFunc::getPosition(v, pos); - Vector3int32 cellCoord; + Point3int32 cellCoord; getCellCoord(pos, cellCoord); // See if the cell already exists @@ -316,7 +378,8 @@ public: // Drop our pointer, which is about to dangle cell = NULL; - bool success = m_data.remove(cellCoord); + const bool success = m_data.remove(cellCoord); + (void)success; debugAssertM(success, "Data structure corrupt: " "tried to remove a cell that doesn't exist."); } @@ -328,7 +391,7 @@ public: } } - /** Removes all elements of @v. */ + /** Removes all elements of \a v. */ void remove(const Array& v, bool shrink = true) { for (int i = 0; i < v.size(); ++i) { remove(v[i], shrink); @@ -387,6 +450,11 @@ public: } } + bool isValid() const { + return ! m_isEnd; + } + + /** @deprecated Use isValid */ bool hasMore() const { return ! m_isEnd; } @@ -615,9 +683,14 @@ public: const Value* operator->() const { return &value(); } operator Value*() const { return &value(); } + /** \deprecated Use isValid */ bool hasMore() const { return ! m_isEnd; } + + bool isValid() const { + return ! m_isEnd; + } }; // BoxIterator /** @@ -652,7 +725,7 @@ public: SphereIterator() : m_isEnd(true) {} void advance() { - if (! m_boxIterator.hasMore()) { + if (! m_boxIterator.isValid()) { m_isEnd = true; return; } @@ -660,7 +733,7 @@ public: while (! m_sphere.contains(m_boxIterator.position())) { ++m_boxIterator; - if (! m_boxIterator.hasMore()) { + if (! m_boxIterator.isValid()) { m_isEnd = true; return; } @@ -677,13 +750,13 @@ public: m_isEnd(false), m_sphere(sphere), m_boxIterator(grid, false, getBoundingBox(sphere)) { - + // Find the first element that is actually in the sphere, // not just the box. advance(); } - const Value& value() const { + const Value& value() const { return *m_boxIterator; } @@ -693,6 +766,7 @@ public: // Intentionally unimplemented SphereIterator& operator=(const SphereIterator&); + public: inline bool operator!=(const SphereIterator& other) const { @@ -710,8 +784,6 @@ public: return !(*this != other); } - - /** Preincrement */ SphereIterator& operator++() { debugAssert(! m_isEnd); @@ -733,34 +805,55 @@ public: const Value* operator->() const { return &value(); } operator Value*() const { return &value(); } - bool hasMore() const { + /** \deprecated use isValid */ + bool G3D_DEPRECATED hasMore() const { + return ! m_isEnd; + } + + bool isValid() const { return ! m_isEnd; } }; // SphereIterator - /** - Finds all values whose positions are within @a sphere. It is an error - to mutate the HashGrid while iterating through it. - */ - SphereIterator beginSphereIntersection(const Sphere& sphere) const { + /** Finds all values whose positions are within \a sphere. It is + an error to mutate the PointHashGrid while iterating through + it. */ + SphereIterator begin(const Sphere& sphere) const { return SphereIterator(this, sphere); } + + /** \deprecated \sa beginIntersection */ + SphereIterator G3D_DEPRECATED beginSphereIntersection(const Sphere& sphere) const { + return SphereIterator(this, sphere); + } + + + /** \deprecated \sa SphereIterator::hasMore */ const SphereIterator& endSphereIntersection() const { static const SphereIterator it; return it; } + + /** Appends results */ + void getIntersectingMembers(const Sphere& sphere, Array& result) const { + for (SphereIterator it = beginSphereIntersection(sphere); it.isValid(); ++it) { + result.append(*it); + } + } + + /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /** Dereference to access the bounds() and size() [element count] of the underlying - cell objet. + cell object. Example:
    -       for(PointHashGrid::CellIterator iter = grid.beginCells(); iter != grid.endCells(); ++iter) {	
    +       for(PointHashGrid::CellIterator iter = grid.beginCells(); iter != grid.endCells(); ++iter) {    
            entriesFound += iter->size();
            }
            
    @@ -793,8 +886,8 @@ public: /** Returns the bounds on this cell */ AABox bounds() const { const Vector3int32& k = m_parent->m_tableIterator->key; - return AABox(Vector3(k) * m_parent->m_cellWidth, - Vector3(k + Vector3int32(1, 1, 1)) * m_parent->m_cellWidth); + return AABox(Vector3(k) * m_parent->m_grid->m_cellWidth, + Vector3(k + Vector3int32(1, 1, 1)) * m_parent->m_grid->m_cellWidth); } /** Number of elements inside this cell */ @@ -823,7 +916,7 @@ public: m_tableIterator( grid->m_data.begin()), m_epoch(grid->m_epoch) { m_indirection.m_parent = this; - m_isEnd = ! m_tableIterator.hasMore(); + m_isEnd = ! m_tableIterator.isValid(); } // Intentionally unimplemented @@ -853,7 +946,7 @@ public: "It is illegal to mutate the HashGrid while " "iterating through it."); ++m_tableIterator; - m_isEnd = ! m_tableIterator.hasMore(); + m_isEnd = ! m_tableIterator.isValid(); return *this; } @@ -864,9 +957,14 @@ public: return old; } + /** \deprecated Use isValid */ bool hasMore() const { return ! m_isEnd; } + + bool isValid() const { + return ! m_isEnd; + } }; // CellIterator /** Iterates through the non-empty cells. This is intended primarily for @@ -897,11 +995,11 @@ public: This is a helper to avoid requiring you to iterate through the data structure, removing and deleting each one. Clears the PointHashGrid at the end. - + Using objects (instead of pointers) or reference counted pointers is recommended over using pointers and this deleteAll method.*/ void deleteAll() { - for (Iterator it = begin(); it.hasMore(); ++it) { + for (Iterator it = begin(); it.isValid(); ++it) { delete *it; } clear(); @@ -924,7 +1022,7 @@ public: m_bounds = AABox(); if (! shrink) { // Remove all data - for (CellIterator it = beginCells(); it.hasMore(); ++it) { + for (CellIterator it = beginCells(); it.isValid(); ++it) { it.cell().clear(true); } } else { @@ -934,7 +1032,7 @@ public: } int debugGetDeepestBucketSize() const { - return m_data.debugGetDeepestBucketSize(); + return (int)m_data.debugGetDeepestBucketSize(); } float debugGetAverageBucketSize() const { diff --git a/deps/g3dlite/include/G3D/PointKDTree.h b/deps/g3dlite/include/G3D/PointKDTree.h index 151cbd5f2..8ea7cf8d0 100644 --- a/deps/g3dlite/include/G3D/PointKDTree.h +++ b/deps/g3dlite/include/G3D/PointKDTree.h @@ -4,15 +4,15 @@ @maintainer Morgan McGuire, http://graphics.cs.williams.edu @created 2004-01-11 - @edited 2008-11-02 + @edited 2012-07-30 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ -#ifndef X_PointKDTree_H -#define X_PointKDTree_H +#ifndef G3D_PointKDTree_h +#define G3D_PointKDTree_h #include "G3D/platform.h" #include "G3D/Array.h" @@ -26,7 +26,7 @@ #include "G3D/BinaryInput.h" #include "G3D/BinaryOutput.h" #include "G3D/CollisionDetection.h" -#include "G3D/GCamera.h" +#include "G3D/Frustum.h" #include "G3D/PositionTrait.h" #include @@ -234,36 +234,38 @@ protected: } - void verifyNode(const Vector3& lo, const Vector3& hi) { - // debugPrintf("Verifying: split %d @ %f [%f, %f, %f], [%f, %f, %f]\n", - // splitAxis, splitLocation, lo.x, lo.y, lo.z, hi.x, hi.y, hi.z); + void verifyNode(const Vector3& lo, const Vector3& hi) { + // debugPrintf("Verifying: split %d @ %f [%f, %f, %f], [%f, %f, %f]\n", + // splitAxis, splitLocation, lo.x, lo.y, lo.z, hi.x, hi.y, hi.z); debugAssert(lo == splitBounds.low()); debugAssert(hi == splitBounds.high()); - for (int i = 0; i < valueArray.length(); ++i) { - const Vector3& b = valueArray[i].position(); +# ifdef G3D_DEBUG + for (int i = 0; i < valueArray.length(); ++i) { + const Vector3& b = valueArray[i].position(); debugAssert(splitBounds.contains(b)); - } + } +# endif - if (child[0] || child[1]) { - debugAssert(lo[splitAxis] < splitLocation); - debugAssert(hi[splitAxis] > splitLocation); - } + if (child[0] || child[1]) { + debugAssert(lo[splitAxis] < splitLocation); + debugAssert(hi[splitAxis] > splitLocation); + } - Vector3 newLo = lo; - newLo[splitAxis] = splitLocation; - Vector3 newHi = hi; - newHi[splitAxis] = splitLocation; + Vector3 newLo = lo; + newLo[splitAxis] = splitLocation; + Vector3 newHi = hi; + newHi[splitAxis] = splitLocation; - if (child[0] != NULL) { - child[0]->verifyNode(lo, newHi); - } + if (child[0] != NULL) { + child[0]->verifyNode(lo, newHi); + } - if (child[1] != NULL) { - child[1]->verifyNode(newLo, hi); - } - } + if (child[1] != NULL) { + child[1]->verifyNode(newLo, hi); + } + } /** @@ -297,6 +299,7 @@ protected: for (int c = 0; c < 2; ++c) { n->child[c] = deserializeStructure(bi); } + return n; } } @@ -484,7 +487,7 @@ protected: // Compute the mean along the axis splitLocation = (bounds.high()[splitAxis] + - bounds.low()[splitAxis]) / 2.0; + bounds.low()[splitAxis]) / 2.0f; Handle splitHandle; Vector3 v; @@ -525,10 +528,10 @@ protected: for(int i = 0; i < node->valueArray.size(); ++i) { memberTable.set(node->valueArray[i].value, node); } - - } - - return node; + + } + + return node; } /** @@ -611,7 +614,7 @@ public: } - int size() const { + size_t size() const { return memberTable.size(); } @@ -809,7 +812,7 @@ private: // Test values at this node against remaining planes for (int p = 0; p < plane.size(); ++p) { - if ((parentMask >> p) & 1 != 0) { + if (((parentMask >> p) & 1) != 0) { // Test against this plane const Plane& curPlane = plane[p]; for (int v = node->valueArray.size() - 1; v >= 0; --v) { @@ -851,7 +854,7 @@ public: /** Typically used to find all visible - objects inside the view frustum (see also GCamera::getClipPlanes)... i.e. all objects + objects inside the view frustum (see also Camera::getClipPlanes)... i.e. all objects not culled by frustum. Example: @@ -862,7 +865,7 @@ public: @param members The results are appended to this array. */ - void getIntersectingMembers(const GCamera::Frustum& frustum, Array& members) const { + void getIntersectingMembers(const Frustum& frustum, Array& members) const { Array plane; for (int i = 0; i < frustum.faceArray.size(); ++i) { @@ -960,51 +963,51 @@ public: BoxIntersectionIterator& operator++() { ++nextValueArrayIndex; - bool foundIntersection = false; + bool foundIntersection = false; while (! isEnd && ! foundIntersection) { - // Search for the next node if we've exhausted this one + // Search for the next node if we've exhausted this one while ((! isEnd) && (nextValueArrayIndex >= node->valueArray.length())) { - // If we entered this loop, then the iterator has exhausted the elements at - // node (possibly because it just switched to a child node with no members). - // This loop continues until it finds a node with members or reaches - // the end of the whole intersection search. + // If we entered this loop, then the iterator has exhausted the elements at + // node (possibly because it just switched to a child node with no members). + // This loop continues until it finds a node with members or reaches + // the end of the whole intersection search. - // If the right child overlaps the box, push it onto the stack for - // processing. - if ((node->child[1] != NULL) && - (box.high()[node->splitAxis] > node->splitLocation)) { - stack.push(node->child[1]); - } + // If the right child overlaps the box, push it onto the stack for + // processing. + if ((node->child[1] != NULL) && + (box.high()[node->splitAxis] > node->splitLocation)) { + stack.push(node->child[1]); + } - // If the left child overlaps the box, push it onto the stack for - // processing. - if ((node->child[0] != NULL) && - (box.low()[node->splitAxis] < node->splitLocation)) { - stack.push(node->child[0]); - } + // If the left child overlaps the box, push it onto the stack for + // processing. + if ((node->child[0] != NULL) && + (box.low()[node->splitAxis] < node->splitLocation)) { + stack.push(node->child[0]); + } - if (stack.length() > 0) { - // Go on to the next node (which may be either one of the ones we - // just pushed, or one from farther back the tree). - node = stack.pop(); - nextValueArrayIndex = 0; - } else { - // That was the last node; we're done iterating - isEnd = true; - } - } + if (stack.length() > 0) { + // Go on to the next node (which may be either one of the ones we + // just pushed, or one from farther back the tree). + node = stack.pop(); + nextValueArrayIndex = 0; + } else { + // That was the last node; we're done iterating + isEnd = true; + } + } - // Search for the next intersection at this node until we run out of children - while (! isEnd && ! foundIntersection && (nextValueArrayIndex < node->valueArray.length())) { - if (box.intersects(node->valueArray[nextValueArrayIndex].bounds)) { - foundIntersection = true; - } else { - ++nextValueArrayIndex; - // If we exhaust this node, we'll loop around the master loop - // to find a new node. - } - } + // Search for the next intersection at this node until we run out of children + while (! isEnd && ! foundIntersection && (nextValueArrayIndex < node->valueArray.length())) { + if (box.intersects(node->valueArray[nextValueArrayIndex].bounds)) { + foundIntersection = true; + } else { + ++nextValueArrayIndex; + // If we exhaust this node, we'll loop around the master loop + // to find a new node. + } + } } return *this; diff --git a/deps/g3dlite/include/G3D/Pointer.h b/deps/g3dlite/include/G3D/Pointer.h index 6e35062a7..61894fba0 100644 --- a/deps/g3dlite/include/G3D/Pointer.h +++ b/deps/g3dlite/include/G3D/Pointer.h @@ -1,12 +1,12 @@ /** - @file Pointer.h + \file Pointer.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2007-05-16 - @edited 2009-03-26 + \created 2007-05-16 + \edited 2012-10-06 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ #ifndef G3D_Pointer_h @@ -27,7 +27,7 @@ namespace G3D { Because the accessors require values to be passed by value (instead of by reference) this is primarily useful for objects whose memory size is small. -
    +   \code
        class Foo {
        public:
           void setEnabled(bool b);
    @@ -51,14 +51,15 @@ namespace G3D {
     
        p2.setValue(p1.getValue());
        p2 = p1;
    -   
    + \endcode Note: Because of the way that dereference is implemented, you cannot pass *p through a function that takes varargs (...), e.g., printf("%d", *p) will produce a compile-time error. Instead use printf("%d",(bool)*p) or printf("%d", p.getValue()). - + + \cite McGuire, GUIs for Real-time Programs, using Universal Pointers, SIGGRAPH 2008 Poster. */ -template +template class Pointer { private: @@ -78,9 +79,7 @@ private: public: - Memory(ValueType* value) : value(value) { - //debugAssert(value != NULL); - } + Memory(ValueType* value) : value(value) {} virtual void set(ValueType v) { *value = v; @@ -99,6 +98,35 @@ private: } }; + template + class FcnAccessor : public Interface { + private: + + GetMethod getMethod; + SetMethod setMethod; + + public: + + FcnAccessor(GetMethod getMethod, SetMethod setMethod) : getMethod(getMethod), setMethod(setMethod) { + } + + virtual void set(ValueType v) { + if (setMethod) { + (*setMethod)(v); + } + } + + virtual ValueType get() const { + return (*getMethod)(); + } + + virtual Interface* clone() const { + return new FcnAccessor(getMethod, setMethod); + } + + virtual bool isNull() const { return false; } + }; + template class Accessor : public Interface { private: @@ -116,7 +144,9 @@ private: } virtual void set(ValueType v) { - (object->*setMethod)(v); + if (setMethod) { + (object->*setMethod)(v); + } } virtual ValueType get() const { @@ -134,17 +164,17 @@ private: template - class RefAccessor : public Interface { + class SharedAccessor : public Interface { private: - ReferenceCountedPointer object; - GetMethod getMethod; - SetMethod setMethod; + shared_ptr object; + GetMethod getMethod; + SetMethod setMethod; public: - RefAccessor( - const ReferenceCountedPointer& object, + SharedAccessor + (const shared_ptr& object, GetMethod getMethod, SetMethod setMethod) : object(object), getMethod(getMethod), setMethod(setMethod) { @@ -152,23 +182,24 @@ private: } virtual void set(ValueType v) { - (object.pointer()->*setMethod)(v); + if (setMethod) { + (object.get()->*setMethod)(v); + } } virtual ValueType get() const { - return (object.pointer()->*getMethod)(); + return (object.get()->*getMethod)(); } virtual Interface* clone() const { - return new RefAccessor(object, getMethod, setMethod); + return new SharedAccessor(object, getMethod, setMethod); } virtual bool isNull() const { - return object.isNull(); + return (bool)object; } }; - Interface* m_interface; public: @@ -197,48 +228,69 @@ public: this[0] = p; } + + /** \param setMethod May be NULL */ template - Pointer(const ReferenceCountedPointer& object, + Pointer(const shared_ptr& object, ValueType (Class::*getMethod)() const, void (Class::*setMethod)(ValueType)) : - m_interface(new RefAccessor(object, getMethod, setMethod)) {} + m_interface(new SharedAccessor(object, getMethod, setMethod)) {} + /** \param setMethod May be NULL */ template - Pointer(const ReferenceCountedPointer& object, + Pointer(const shared_ptr& object, const ValueType& (Class::*getMethod)() const, void (Class::*setMethod)(ValueType)) : - m_interface(new RefAccessor(object, getMethod, setMethod)) {} + m_interface(new SharedAccessor(object, getMethod, setMethod)) {} + + /** \param setMethod May be NULL */ + Pointer(ValueType (*getMethod)(), + void (*setMethod)(ValueType)) : + m_interface(new FcnAccessor(getMethod, setMethod)) {} + + /** \param setMethod May be NULL */ + Pointer(const ValueType& (*getMethod)(), + void (*setMethod)(ValueType)) : + m_interface(new FcnAccessor(getMethod, setMethod)) {} + + + /** \param setMethod May be NULL */ template - Pointer(const ReferenceCountedPointer& object, + Pointer(const shared_ptr& object, ValueType (Class::*getMethod)() const, void (Class::*setMethod)(const ValueType&)) : - m_interface(new RefAccessor(object, getMethod, setMethod)) {} + m_interface(new SharedAccessor(object, getMethod, setMethod)) {} + /** \param setMethod May be NULL */ template - Pointer(const ReferenceCountedPointer& object, + Pointer(const shared_ptr& object, const ValueType& (Class::*getMethod)() const, void (Class::*setMethod)(const ValueType&)) : - m_interface(new RefAccessor(object, getMethod, setMethod)) {} + m_interface(new SharedAccessor(object, getMethod, setMethod)) {} + /** \param setMethod May be NULL */ template Pointer(Class* object, const ValueType& (Class::*getMethod)() const, void (Class::*setMethod)(const ValueType&)) : m_interface(new Accessor(object, getMethod, setMethod)) {} + /** \param setMethod May be NULL */ template Pointer(Class* object, ValueType (Class::*getMethod)() const, void (Class::*setMethod)(const ValueType&)) : m_interface(new Accessor(object, getMethod, setMethod)) {} + /** \param setMethod May be NULL */ template Pointer(Class* object, const ValueType& (Class::*getMethod)() const, void (Class::*setMethod)(ValueType)) : m_interface(new Accessor(object, getMethod, setMethod)) {} + /** \param setMethod May be NULL */ template Pointer(Class* object, ValueType (Class::*getMethod)() const, @@ -254,6 +306,8 @@ public: return m_interface->get(); } + /** \brief Assign a value to the referenced element. + If this Pointer was initialized with a NULL setMethod, the call is ignored */ inline void setValue(const ValueType& v) { debugAssert(m_interface != NULL); m_interface->set(v); @@ -287,6 +341,16 @@ public: } }; +template +bool isNull(const Pointer& p) { + return p.isNull(); +} + +template +bool notNull(const Pointer& p) { + return ! p.isNull(); +} + } #endif diff --git a/deps/g3dlite/include/G3D/Quat.h b/deps/g3dlite/include/G3D/Quat.h index d8fdfafec..73e661a4f 100644 --- a/deps/g3dlite/include/G3D/Quat.h +++ b/deps/g3dlite/include/G3D/Quat.h @@ -1,12 +1,12 @@ /** - @file Quat.h + \file G3D/Quat.h Quaternion - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2002-01-23 - @edited 2009-05-10 + \created 2002-01-23 + \edited 2011-05-10 */ #ifndef G3D_Quat_h @@ -21,9 +21,9 @@ namespace G3D { /** - Arbitrary quaternion (not necessarily unit) + Arbitrary quaternion (not necessarily unit). - Unit quaternions are used in computer graphics to represent + Unit quaternions (aka versors) are used in computer graphics to represent rotation about an axis. Any 3x3 rotation matrix can be stored as a quaternion. @@ -72,6 +72,8 @@ public: /** Expects "Quat(x,y,z,w)" or a Matrix3 constructor. */ Quat(const class Any& a); + Any toAny() const; + Quat(const Matrix3& rot); Quat(float _x, float _y, float _z, float _w) : @@ -81,6 +83,12 @@ public: Quat(const Vector3& v, float _w = 0) : x(v.x), y(v.y), z(v.z), w(_w) { } + /** True if the components are exactly equal. Note that two quaternations may + be unequal but map to the same rotation. */ + bool operator==(const Quat& q) const { + return x == q.x && y == q.y && z == q.z && w == q.w; + } + /** The real part of the quaternion. */ @@ -92,9 +100,9 @@ public: return w; } - Quat operator-() const { - return Quat(-x, -y, -z, -w); - } + Quat operator-() const { + return Quat(-x, -y, -z, -w); + } Quat operator-(const Quat& other) const { return Quat(x - other.x, y - other.y, z - other.z, w - other.w); @@ -148,7 +156,7 @@ public: } - /** @cite Based on Watt & Watt, page 360 */ + /** @cite Based on Watt & Watt, page 360 */ friend Quat operator* (float s, const Quat& q); inline Quat operator/(float s) const { @@ -196,36 +204,69 @@ public: void toAxisAngleRotation( Vector3& axis, float& angle) const { - double d; - toAxisAngleRotation(axis, d); - angle = (float)d; - } + double d; + toAxisAngleRotation(axis, d); + angle = (float)d; + } Matrix3 toRotationMatrix() const; void toRotationMatrix( Matrix3& rot) const; +private: + /** \param maxAngle Maximum angle of rotation allowed. If a larger rotation is required, the angle of rotation applied is clamped to maxAngle */ + Quat slerp + (const Quat& other, + float alpha, + float threshold, + float maxAngle) const; +public: + /** Spherical linear interpolation: linear interpolation along the shortest (3D) great-circle route between two quaternions. + Assumes that both arguments are unit quaternions. + Note: Correct rotations are expected between 0 and PI in the right order. - @cite Based on Game Physics -- David Eberly pg 538-540 - @param threshold Critical angle between between rotations at which - the algorithm switches to normalized lerp, which is more - numerically stable in those situations. 0.0 will always slerp. + \cite Based on Game Physics -- David Eberly pg 538-540 + + \param threshold Critical angle between between rotations (in radians) at which + the algorithm switches to normalized lerp, which is more + numerically stable in those situations. 0.0 will always slerp. + */ - Quat slerp( - const Quat& other, + Quat slerp + (const Quat& other, float alpha, - float threshold = 0.05f) const; + float threshold = 0.05f) const { + return slerp(other, alpha, threshold, finf()); + } - /** Normalized linear interpolation of quaternion components. */ - Quat nlerp(const Quat& other, float alpha) const; + /** Rotates towards \a other by at most \a maxAngle. */ + Quat movedTowards + (const Quat& other, + float maxAngle) const { + return slerp(other, 1.0f, 0.05f, maxAngle); + } + + /** Rotates towards \a other by at most \a maxAngle. */ + void moveTowards + (const Quat& other, + float maxAngle) { + *this = movedTowards(other, maxAngle); + } + /** Returns the angle in radians between this and other, assuming both are unit quaternions. + + \returns On the range [0, pif()]*/ + float angleBetween(const Quat& other) const; + /** Normalized linear interpolation of quaternion components. */ + Quat nlerp(const Quat& other, float alpha) const; + /** Note that q-1 = q.conj() for a unit quaternion. @cite Dam99 page 13 */ @@ -274,22 +315,6 @@ public: return Quat(t * x, t * y, t * z, ::logf(len)); } } - /** log q = [Av, 0] where q = [sin(A) * v, cos(A)]. - Only for unit quaternions - debugAssertM(isUnit(), "Log only defined for unit quaternions"); - // Solve for A in q = [sin(A)*v, cos(A)] - Vector3 u(x, y, z); - double len = u.magnitude(); - - if (len == 0.0) { - return - } - double A = atan2((double)w, len); - Vector3 v = u / len; - - return Quat(v * A, 0); - } - */ /** exp q = [sin(A) * v, cos(A)] where q = [Av, 0]. Only defined for pure-vector quaternions */ @@ -310,8 +335,8 @@ public: Note that q.pow(a).pow(b) == q.pow(a + b) @cite Dam98 pg 21 */ - inline Quat pow(float x) const { - return (log() * x).exp(); + inline Quat pow(float r) const { + return (log() * r).exp(); } /** Make unit length in place */ @@ -324,9 +349,9 @@ public: the magnitude. */ Quat toUnit() const { - Quat x = *this; - x.unitize(); - return x; + Quat copyOfThis = *this; + copyOfThis.unitize(); + return copyOfThis; } /** @@ -348,7 +373,7 @@ public: float& operator[] (int i); /** Generate uniform random unit quaternion (i.e. random "direction") - @cite From "Uniform Random Rotations", Ken Shoemake, Graphics Gems III. + @cite From "Uniform Random Rotations", Ken Shoemake, Graphics Gems III. */ static Quat unitRandom(); diff --git a/deps/g3dlite/include/G3D/Queue.h b/deps/g3dlite/include/G3D/Queue.h index 36573265d..c560eb426 100644 --- a/deps/g3dlite/include/G3D/Queue.h +++ b/deps/g3dlite/include/G3D/Queue.h @@ -7,8 +7,8 @@ @edited 2008-12-20 */ -#ifndef G3D_QUEUE_H -#define G3D_QUEUE_H +#ifndef G3D_Queue_h +#define G3D_Queue_h #include "G3D/platform.h" #include "G3D/System.h" @@ -23,6 +23,8 @@ namespace G3D { sequence without using the modulo operator. [0 ... secondEnd) [head .... firstEnd) + + \sa ThreadsafeQueue */ #define FIND_ENDS \ int firstEnd = head + num;\ @@ -325,6 +327,10 @@ public: return (*this)[size() - 1]; } + bool empty() const { + return size() == 0; + } + /** Returns true if the given element is in the queue. */ @@ -346,7 +352,7 @@ public: FIND_ENDS; int i; - for (i = 0; i < secondEnd; ++i) { + for (i = 0; i < secondEnd; ++i) { delete data[i]; } diff --git a/deps/g3dlite/include/G3D/Random.h b/deps/g3dlite/include/G3D/Random.h index 54491d06f..9d911806a 100644 --- a/deps/g3dlite/include/G3D/Random.h +++ b/deps/g3dlite/include/G3D/Random.h @@ -1,12 +1,12 @@ /** - @file Random.h + \file G3D/Random.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2009-01-02 - @edited 2009-03-20 + \created 2009-01-02 + \edited 2012-07-20 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ #ifndef G3D_Random_h @@ -33,6 +33,8 @@ namespace G3D { On OS X, Random is about 10x faster than drand48() (which is threadsafe) and 4x faster than rand() (which is not threadsafe). + + \sa Noise */ class Random { protected: @@ -71,6 +73,23 @@ protected: public constructor.*/ Random(void*); + +private: + + Random& operator=(const Random&) { + alwaysAssertM(false, + "There is no copy constructor or assignment operator for Random because you " + "probably didn't actually want to copy the state--it would " + "be slow and duplicate the state of a pseudo-random sequence. Maybe you could " + "provide arguments to a member variable in the constructor, " + "or pass the Random by reference?"); + return *this; + } + + Random(const Random& r) { + *this = r; + } + public: /** \param threadsafe Set to false if you know that this random @@ -81,6 +100,8 @@ public: virtual ~Random(); + virtual void reset(uint32 seed = 0xF018A4D2, bool threadsafe = true); + /** Each bit is random. Subclasses can choose to override just this method and the other methods will all work automatically. */ virtual uint32 bits(); @@ -109,9 +130,13 @@ public: virtual float gaussian(float mean, float stdev); /** Returns 3D unit vectors distributed according to - a cosine distribution about the z-axis. */ + a cosine distribution about the positive z-axis. */ virtual void cosHemi(float& x, float& y, float& z); + /** Returns 3D unit vectors distributed according to + a cosine distribution about the z-axis. */ + virtual void cosSphere(float& x, float& y, float& z); + /** Returns 3D unit vectors distributed according to a cosine power distribution (\f$ \cos^k \theta \f$) about the z-axis. */ diff --git a/deps/g3dlite/include/G3D/Ray.h b/deps/g3dlite/include/G3D/Ray.h index 1d9bf318d..79afc7616 100644 --- a/deps/g3dlite/include/G3D/Ray.h +++ b/deps/g3dlite/include/G3D/Ray.h @@ -25,78 +25,85 @@ class Ray { private: friend class Intersect; - Vector3 m_origin; + Point3 m_origin; - /** Unit length */ - Vector3 m_direction; + /** Unit length */ + Vector3 m_direction; - /** 1.0 / direction */ - Vector3 m_invDirection; + /** 1.0 / direction */ + Vector3 m_invDirection; + + /** The following are for the "ray slope" optimization from + "Fast Ray / Axis-Aligned Bounding Box Overlap Tests using Ray Slopes" + by Martin Eisemann, Thorsten Grosch, Stefan Müller and Marcus Magnor + Computer Graphics Lab, TU Braunschweig, Germany and + University of Koblenz-Landau, Germany */ + enum Classification {MMM, MMP, MPM, MPP, PMM, PMP, PPM, PPP, POO, MOO, OPO, OMO, OOP, OOM, OMM, OMP, OPM, OPP, MOM, MOP, POM, POP, MMO, MPO, PMO, PPO}; - // The following are for the "ray slope" optimization from - // "Fast Ray / Axis-Aligned Bounding Box Overlap Tests using Ray Slopes" - // by Martin Eisemann, Thorsten Grosch, Stefan M�ller and Marcus Magnor - // Computer Graphics Lab, TU Braunschweig, Germany and - // University of Koblenz-Landau, Germany*/ - enum Classification {MMM, MMP, MPM, MPP, PMM, PMP, PPM, PPP, POO, MOO, OPO, OMO, OOP, OOM, OMM, OMP, OPM, OPP, MOM, MOP, POM, POP, MMO, MPO, PMO, PPO}; Classification classification; - // ray slope - float ibyj, jbyi, kbyj, jbyk, ibyk, kbyi; - // Precomputed components - float c_xy, c_xz, c_yx, c_yz, c_zx, c_zy; + Classification classification; + + /** ray slope */ + float ibyj, jbyi, kbyj, jbyk, ibyk, kbyi; + + /** Precomputed components */ + float c_xy, c_xz, c_yx, c_yz, c_zx, c_zy; public: + /** \param direction Assumed to have unit length */ + void set(const Point3& origin, const Vector3& direction); - void set(const Vector3& origin, const Vector3& direction); - - inline const Vector3& origin() const { - return m_origin; - } - - /** Unit direction vector. */ - inline const Vector3& direction() const { - return m_direction; - } - - /** Component-wise inverse of direction vector. May have inf() components */ - inline const Vector3& invDirection() const { - return m_invDirection; - } - - inline Ray() { - set(Vector3::zero(), Vector3::unitX()); - } - - inline Ray(const Vector3& origin, const Vector3& direction) { - set(origin, direction); - } - - Ray(class BinaryInput& b); - - void serialize(class BinaryOutput& b) const; - void deserialize(class BinaryInput& b); - - /** - Creates a Ray from a origin and a (nonzero) unit direction. - */ - static Ray fromOriginAndDirection(const Vector3& point, const Vector3& direction) { - return Ray(point, direction); + const Point3& origin() const { + return m_origin; + } + + /** Unit direction vector. */ + const Vector3& direction() const { + return m_direction; } - /** Advances the origin along the direction by @a distance */ - inline Ray bump(float distance) const { - return Ray(m_origin + m_direction * distance, m_direction); - } + /** Component-wise inverse of direction vector. May have inf() components */ + const Vector3& invDirection() const { + return m_invDirection; + } + + Ray() { + set(Point3::zero(), Vector3::unitX()); + } - /** Advances the origin along the @a bumpDirection by @a distance and returns the new ray*/ - inline Ray bump(float distance, const Vector3& bumpDirection) const { - return Ray(m_origin + bumpDirection * distance, m_direction); - } + /** \param direction Assumed to have unit length */ + Ray(const Point3& origin, const Vector3& direction) { + set(origin, direction); + } + + Ray(class BinaryInput& b); + + void serialize(class BinaryOutput& b) const; + void deserialize(class BinaryInput& b); + + /** + Creates a Ray from a origin and a (nonzero) unit direction. + */ + static Ray fromOriginAndDirection(const Point3& point, const Vector3& direction) { + return Ray(point, direction); + } + + /** Returns a new ray which has the same direction but an origin + advanced along direction by @a distance */ + Ray bumpedRay(float distance) const { + return Ray(m_origin + m_direction * distance, m_direction); + } + + /** Returns a new ray which has the same direction but an origin + advanced by \a distance * \a bumpDirection */ + Ray bumpedRay(float distance, const Vector3& bumpDirection) const { + return Ray(m_origin + bumpDirection * distance, m_direction); + } /** - Returns the closest point on the Ray to point. - */ - Vector3 closestPoint(const Vector3& point) const { + \brief Returns the closest point on the Ray to point. + */ + Point3 closestPoint(const Point3& point) const { float t = m_direction.dot(point - m_origin); if (t < 0) { return m_origin; @@ -108,7 +115,7 @@ public: /** Returns the closest distance between point and the Ray */ - float distance(const Vector3& point) const { + float distance(const Point3& point) const { return (closestPoint(point) - point).magnitude(); } @@ -119,7 +126,7 @@ public: Planes are considered one-sided, so the ray will not intersect a plane where the normal faces in the traveling direction. */ - Vector3 intersection(const class Plane& plane) const; + Point3 intersection(const class Plane& plane) const; /** Returns the distance until intersection with the sphere or the (solid) ball bounded by the sphere. @@ -151,54 +158,56 @@ public: float intersectionTime( const Vector3& v0, const Vector3& v1, const Vector3& v2, const Vector3& edge01, const Vector3& edge02, - double& w0, double& w1, double& w2) const; + float& w0, float& w1, float& w2) const; /** Ray-triangle intersection for a 1-sided triangle. Fastest version. @cite http://www.acm.org/jgt/papers/MollerTrumbore97/ http://www.graphics.cornell.edu/pubs/1997/MT97.html */ - inline float intersectionTime( - const Vector3& vert0, - const Vector3& vert1, - const Vector3& vert2, + float intersectionTime( + const Point3& vert0, + const Point3& vert1, + const Point3& vert2, const Vector3& edge01, const Vector3& edge02) const; - inline float intersectionTime( - const Vector3& vert0, - const Vector3& vert1, - const Vector3& vert2) const { + float intersectionTime( + const Point3& vert0, + const Point3& vert1, + const Point3& vert2) const { return intersectionTime(vert0, vert1, vert2, vert1 - vert0, vert2 - vert0); } - inline float intersectionTime( - const Vector3& vert0, - const Vector3& vert1, - const Vector3& vert2, - double& w0, - double& w1, - double& w2) const { + float intersectionTime( + const Point3& vert0, + const Point3& vert1, + const Point3& vert2, + float& w0, + float& w1, + float& w2) const { return intersectionTime(vert0, vert1, vert2, vert1 - vert0, vert2 - vert0, w0, w1, w2); } + /* One-sided triangle */ - inline float intersectionTime(const Triangle& triangle) const { + float intersectionTime(const Triangle& triangle) const { return intersectionTime( triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), triangle.edge01(), triangle.edge02()); } - inline float intersectionTime( - const Triangle& triangle, - double& w0, - double& w1, - double& w2) const { + + float intersectionTime + (const Triangle& triangle, + float& w0, + float& w1, + float& w2) const { return intersectionTime(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), triangle.edge01(), triangle.edge02(), w0, w1, w2); } @@ -236,9 +245,9 @@ public: dest[2]=v1[2]-v2[2]; inline float Ray::intersectionTime( - const Vector3& vert0, - const Vector3& vert1, - const Vector3& vert2, + const Point3& vert0, + const Point3& vert1, + const Point3& vert2, const Vector3& edge1, const Vector3& edge2) const { @@ -294,15 +303,15 @@ inline float Ray::intersectionTime( } -inline float Ray::intersectionTime( - const Vector3& vert0, - const Vector3& vert1, - const Vector3& vert2, - const Vector3& edge1, - const Vector3& edge2, - double& w0, - double& w1, - double& w2) const { +inline float Ray::intersectionTime +(const Point3& vert0, + const Point3& vert1, + const Point3& vert2, + const Vector3& edge1, + const Vector3& edge2, + float& w0, + float& w1, + float& w2) const { (void)vert1; (void)vert2; diff --git a/deps/g3dlite/include/G3D/Rect2D.h b/deps/g3dlite/include/G3D/Rect2D.h index 2fb58c504..93dd0e619 100644 --- a/deps/g3dlite/include/G3D/Rect2D.h +++ b/deps/g3dlite/include/G3D/Rect2D.h @@ -1,12 +1,12 @@ /** - @file Rect2D.h + \file Rect2D.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2003-11-13 - @created 2009-11-16 + \created 2003-11-13 + \created 2011-06-16 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ @@ -39,7 +39,7 @@ class Any; */ class Rect2D { private: - Vector2 min, max; + Point2 min, max; /** Returns true if the whole polygon is clipped. @@ -117,38 +117,60 @@ private: return false; } + /** Uninitialized constructor */ + Rect2D(bool /*b*/) {} public: /** \param any Must either Rect2D::xywh(#, #, #, #) or Rect2D::xyxy(#, #, #, #)*/ Rect2D(const Any& any); /** Converts the Rect2D to an Any. */ - operator Any() const; + Any toAny() const; - Rect2D() : min(0, 0), max(0, 0) {} + Rect2D(const Rect2D& r) : min(r.min), max(r.max) {} + + /** Creates the empty set rectangle. + */ + Rect2D() : min(fnan(), fnan()), max(fnan(), fnan()) {} + + static const Rect2D& empty(); + + /** Returns true if this is the empty set, which is distinct from a zero-area rectangle. */ + inline bool isEmpty() const { + return min.isNaN() && max.isNaN(); + } /** Creates a rectangle at 0,0 with the given width and height*/ Rect2D(const Vector2& wh) : min(0, 0), max(wh.x, wh.y) {} - /** Computes a rectangle that contains both @a a and @a b. - Note that even if @a or @b has zero area, its origin will be included.*/ - Rect2D(const Rect2D& a, const Rect2D& b) { - min = a.min.min(b.min); - max = a.max.max(b.max); + Vector2 extent() const { + if (isEmpty()) { + return Vector2::zero(); + } else { + return max - min; + } } /** @brief Uniformly random point on the interior */ - Vector2 randomPoint() const { - return Vector2(uniformRandom(0, max.x - min.x) + min.x, + Point2 randomPoint() const { + return Point2(uniformRandom(0, max.x - min.x) + min.x, uniformRandom(0, max.y - min.y) + min.y); } float width() const { - return max.x - min.x; + if (isEmpty()) { + return 0; + } else { + return max.x - min.x; + } } float height() const { - return max.y - min.y; + if (isEmpty()) { + return 0; + } else { + return max.y - min.y; + } } float x0() const { @@ -168,29 +190,33 @@ public: } /** Min, min corner */ - Vector2 x0y0() const { + Point2 x0y0() const { return min; } - Vector2 x1y0() const { - return Vector2(max.x, min.y); + Point2 x1y0() const { + return Point2(max.x, min.y); } - Vector2 x0y1() const { - return Vector2(min.x, max.y); + Point2 x0y1() const { + return Point2(min.x, max.y); } /** Max,max corner */ - Vector2 x1y1() const { + Point2 x1y1() const { return max; } /** Width and height */ Vector2 wh() const { - return max - min; + if (isEmpty()) { + return Vector2::zero(); + } else { + return max - min; + } } - Vector2 center() const { + Point2 center() const { return (max + min) * 0.5; } @@ -203,7 +229,7 @@ public: } Rect2D lerp(const Rect2D& other, float alpha) const { - Rect2D out; + Rect2D out(false); out.min = min.lerp(other.min, alpha); out.max = max.lerp(other.max, alpha); @@ -212,7 +238,7 @@ public: } static Rect2D xyxy(float x0, float y0, float x1, float y1) { - Rect2D r; + Rect2D r(false); r.min.x = G3D::min(x0, x1); r.min.y = G3D::min(y0, y1); @@ -222,8 +248,8 @@ public: return r; } - static Rect2D xyxy(const Vector2& v0, const Vector2& v1) { - Rect2D r; + static Rect2D xyxy(const Point2& v0, const Point2& v1) { + Rect2D r(false); r.min = v0.min(v1); r.max = v0.max(v1); @@ -235,7 +261,7 @@ public: return xyxy(x, y, x + w, y + h); } - static Rect2D xywh(const Vector2& v, const Vector2& w) { + static Rect2D xywh(const Point2& v, const Vector2& w) { return xyxy(v.x, v.y, v.x + w.x, v.y + w.y); } @@ -246,11 +272,13 @@ public: return xyxy(Vector2::inf(), Vector2::inf()); } - bool contains(const Vector2& v) const { + bool contains(const Point2& v) const { + // This will automatically return false if isEmpty() return (v.x >= min.x) && (v.y >= min.y) && (v.x <= max.x) && (v.y <= max.y); } bool contains(const Rect2D& r) const { + // This will automatically return false if isEmpty() return (min.x <= r.min.x) && (min.y <= r.min.y) && (max.x >= r.max.x) && (max.y >= r.max.y); } @@ -259,12 +287,14 @@ public: Note that two rectangles that are adjacent do not intersect because there is zero area to the overlap, even though one of them "contains" the corners of the other.*/ bool intersects(const Rect2D& r) const { + // This will automatically return false if isEmpty() return (min.x < r.max.x) && (min.y < r.max.y) && (max.x > r.min.x) && (max.y > r.min.y); } /** Like intersection, but counts the adjacent case as touching. */ bool intersectsOrTouches(const Rect2D& r) const { + // This will automatically return false if isEmpty() return (min.x <= r.max.x) && (min.y <= r.max.y) && (max.x >= r.min.x) && (max.y >= r.min.y); } @@ -273,6 +303,10 @@ public: return xyxy(min.x * s, min.y * s, max.x * s, max.y * s); } + Rect2D operator*(const Vector2& s) const { + return xyxy(min * s, max * s); + } + Rect2D operator/(float s) const { return xyxy(min / s, max / s); } @@ -297,21 +331,25 @@ public: return (min != other.min) || (max != other.max); } + void serialize(class BinaryOutput& b) const; + + void deserialize(class BinaryInput& b); + /** Returns the corners in the order: (min,min), (max,min), (max,max), (min,max). */ - Vector2 corner(int i) const { + Point2 corner(int i) const { debugAssert(i >= 0 && i < 4); switch (i & 3) { case 0: - return Vector2(min.x, min.y); + return Point2(min.x, min.y); case 1: - return Vector2(max.x, min.y); + return Point2(max.x, min.y); case 2: - return Vector2(max.x, max.y); + return Point2(max.x, max.y); case 3: - return Vector2(min.x, max.y); + return Point2(min.x, max.y); default: // Should never get here - return Vector2(0, 0); + return Point2(0, 0); } } @@ -345,6 +383,22 @@ public: return Rect2D::xywh(newX, newY, newW, newH); } + void merge(const Rect2D& other) { + if (isEmpty()) { + *this = other; + } else if (! other.isEmpty()) { + min = min.min(other.min); + max = max.max(other.max); + } + } + + /** Computes a rectangle that contains both @a a and @a b. + Note that even if @a or @b has zero area, its origin will be included.*/ + Rect2D(const Rect2D& a, const Rect2D& b) { + *this = a; + merge(b); + } + /** Clips so that the rightmost point of the outPoly is at rect.x1 (e.g. a 800x600 window produces rightmost point 799, not 800). The results are suitable for pixel rendering if iRounded. @@ -398,15 +452,16 @@ public: } /** - Returns the overlap region between the two rectangles. This may have zero area - if they do not intersect. See the two-Rect2D constructor for a way to compute - a union-like rectangle. + Returns the overlap region between the two rectangles. This may + have zero area if they do not intersect. See the two-Rect2D + constructor and merge() for a way to compute a union-like + rectangle. */ Rect2D intersect(const Rect2D& other) const { if (intersects(other)) { return Rect2D::xyxy(min.max(other.min), max.min(other.max)); - }else{ - return Rect2D::xywh(0, 0, 0, 0); + } else { + return empty(); } } }; diff --git a/deps/g3dlite/include/G3D/ReferenceCount.h b/deps/g3dlite/include/G3D/ReferenceCount.h index 84591c6d8..d3ac03915 100644 --- a/deps/g3dlite/include/G3D/ReferenceCount.h +++ b/deps/g3dlite/include/G3D/ReferenceCount.h @@ -1,14 +1,12 @@ /** - @file ReferenceCount.h + \file G3D/ReferenceCount.h 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 + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2001-10-23 - @edited 2009-04-25 + \created 2001-10-23 + \edited 2013-01-05 */ #ifndef G3D_ReferenceCount_h #define G3D_ReferenceCount_h @@ -17,552 +15,40 @@ #include "G3D/debug.h" #include "G3D/AtomicInt32.h" +#define USE_SHARED_PTR + +#define ReferenceCountedPointer shared_ptr +#define WeakReferenceCountedPointer weak_ptr namespace G3D { -#ifdef _MSC_VER -// Turn off "conditional expression is constant" warning; MSVC generates this -// for debug assertions in inlined methods. -# pragma warning (disable : 4127) -#endif - -/** Base class for WeakReferenceCountedPointer */ -class _WeakPtr { +class ReferenceCountedObject : public enable_shared_from_this { public: - inline virtual ~_WeakPtr() {} - -protected: - friend class ReferenceCountedObject; - - /** Called by ReferenceCountedObject to tell a weak pointer that its underlying object was collected. */ - virtual void objectCollected() = 0; + virtual ~ReferenceCountedObject() {}; }; -/** Used internally by ReferenceCountedObject */ -class _WeakPtrLinkedList { -public: - _WeakPtr* weakPtr; - _WeakPtrLinkedList* next; +} // namespace - inline _WeakPtrLinkedList() : weakPtr(NULL), next(NULL) {} +namespace G3D { - /** Inserts this node into the head of the list that previously had n as its head. */ - inline _WeakPtrLinkedList(_WeakPtr* p, _WeakPtrLinkedList* n) : weakPtr(p), next(n) {} -}; - -/** - Objects that are reference counted inherit from this. Subclasses - must have a public destructor (the default destructor is fine) - and publicly inherit ReferenceCountedObject. - - Multiple inheritance from a reference counted object is dangerous-- use - at your own risk. - - ReferenceCountedPointer and ReferenceCountedObject are threadsafe. - You can create and drop references on multiple threads without - violating integrity. WeakReferenceCountedPointer is not - threadsafe. Introducing a weak pointer destroys all thread safety, - even for strong pointers to the same object (this is inherent in the - design of the class; we cannot fix it without slowing down the - performance of reference counted objects.) - - Usage Example - -
    -
    -class Foo : public G3D::ReferenceCountedObject {
    -public:
    -    int x;
    -};
    -
    -class Bar : public Foo {};
    -
    -typedef G3D::ReferenceCountedPointer FooRef;
    -typedef G3D::WeakReferenceCountedPointer WeakFooRef;
    -typedef G3D::ReferenceCountedPointer BarRef;
    -
    -
    -int main(int argc, char *argv[]) {
    -
    -    WeakFooRef x;
    -
    -    {
    -        FooRef a = new Foo();
    -
    -        // Reference count == 1
    -
    -        x = a;
    -        // Weak references do not increase count
    -
    -        {
    -            FooRef b = a;
    -            // Reference count == 2
    -        }
    -
    -        // Reference count == 1
    -    }
    -    // No more strong references; object automatically deleted.
    -    // x is set to NULL automatically.
    -
    -    // Example of using dynamic cast on reference counted objects
    -    BarRef b = new Bar();
    -
    -    // No cast needed to go down the heirarchy.
    -    FooRef f = b;
    -
    -    // We can't cast the reference object because it is a class.
    -    // Instead we must extract the pointer and cast that:
    -    b = dynamic_cast(&*f);
    -
    -    return 0;
    +template
    +bool isNull(const ReferenceCountedPointer& ptr) {
    +    return ! ptr;
     }
    -
    - */ -class ReferenceCountedObject { -public: - /** - The long name is to keep this from accidentally conflicting with - a subclass's variable name. Do not use or explicitly manipulate - this value--its type may change in the future and is not part - of the supported API. - */ - AtomicInt32 ReferenceCountedObject_refCount; - - /** - Linked list of all weak pointers that reference this (some may be - on the stack!). Do not use or explicitly manipulate this value. - */ - _WeakPtrLinkedList* ReferenceCountedObject_weakPointer; +template +bool notNull(const ReferenceCountedPointer& ptr) { + return (bool)ptr; +} -protected: +template +bool isNull(const T* ptr) { + return ptr == NULL; +} - ReferenceCountedObject(); - -public: - - /** Automatically called immediately before the object is deleted. - This is not called from the destructor because it needs to be invoked - before the subclass destructor. - */ - void ReferenceCountedObject_zeroWeakPointers(); - - virtual ~ReferenceCountedObject(); - - - /** - Note: copies will initially start out with 0 - references and 0 weak references like any other object. - */ - ReferenceCountedObject(const ReferenceCountedObject& notUsed); - - ReferenceCountedObject& operator=(const ReferenceCountedObject& other); -}; - - - -/** - Use ReferenceCountedPointer in place of T* in your program. - T must subclass ReferenceCountedObject. -@deprecated To be replaced by boost::shared_ptr in 7.0 - */ -template -class ReferenceCountedPointer { -private: - - T* m_pointer; - -public: - typedef T element_type; - - inline T* pointer() const { - return m_pointer; - } - -private: - - /** Nulls out the pointer and drops a reference. If the reference - count hits zero. */ - void zeroPointer() { - if (m_pointer != NULL) { - - ReferenceCountedObject* pointer = ((ReferenceCountedObject*)m_pointer); - debugAssert(G3D::isValidHeapPointer(m_pointer)); - debugAssertM(pointer->ReferenceCountedObject_refCount.value() > 0, - "Dangling reference detected."); - - // Only delete if this instance caused the count to hit - // exactly zero. If there is a race condition, the value - // may be zero after decrement returns, but only one of - // the instances will get a zero return value. - if (pointer->ReferenceCountedObject_refCount.decrement() == 0) { - // We held the last reference, so delete the object. - // This test is threadsafe because there is no way for - // the reference count to increase after the last - // reference was dropped (assuming the application does - // not voilate the class abstraction). - //debugPrintf(" delete 0x%x\n", m_pointer); - - // We must zero the weak pointers *before* deletion in case there - // are cycles of weak references. - // Note that since there are no strong references at this point, - // it is perfectly fair to zero the weak pointers anyway. - pointer->ReferenceCountedObject_zeroWeakPointers(); - delete pointer; - } - - m_pointer = NULL; - } - } - - /** Non-atomic (except for the referencec increment). Can only be - called in contexts like the copy constructor or initial - constructor where it is known that the reference count will - not hit zero on some other thread. */ - void setPointer(T* x) { - if (x != m_pointer) { - zeroPointer(); - - if (x != NULL) { - debugAssert(G3D::isValidHeapPointer(x)); - - m_pointer = x; - - // Note that the ref count can be zero if this is the - // first pointer to it - ReferenceCountedObject* pointer = (ReferenceCountedObject*)m_pointer; - debugAssertM(pointer->ReferenceCountedObject_refCount.value() >= 0, - "Negative reference count detected."); - pointer->ReferenceCountedObject_refCount.increment(); - } - } - } - -public: - - inline ReferenceCountedPointer() : m_pointer(NULL) {} - - /** - Allow silent cast to the base class. - -
    -        SubRef  s = new Sub();
    -        BaseRef b = s;
    -      
    - - i.e., compile-time subtyping rule - RCP<T> <: RCP<S> if T <: S - */ - template - inline ReferenceCountedPointer(const ReferenceCountedPointer& p) : - m_pointer(NULL) { - setPointer(p.pointer()); - } - -# if (! defined(MSC_VER) || (MSC_VER >= 1300)) - /** - Explicit cast to a subclass. Acts like dynamic cast; the result will be NULL if - the cast cannot succeed. Not supported on VC6. -
    -        SubRef  s = new Sub();
    -        BaseRef b = s;
    -        s = b.downcast();   // Note that the template argument is the object type, not the pointer type.
    -      
    - */ - template - ReferenceCountedPointer downcast() { - return ReferenceCountedPointer(dynamic_cast(m_pointer)); - } - - template - const ReferenceCountedPointer downcast() const { - return ReferenceCountedPointer(dynamic_cast(m_pointer)); - } -# endif - - // We need an explicit version of the copy constructor as well or - // the default copy constructor will be used. - inline ReferenceCountedPointer(const ReferenceCountedPointer& p) : m_pointer(NULL) { - setPointer(p.m_pointer); - } - - /** Allows construction from a raw pointer. That object will thereafter be - reference counted -- do not call delete on it. - - Use of const allows downcast on const references */ - inline ReferenceCountedPointer(const T* p) : m_pointer(NULL) { - // only const constructor is defined to remove ambiguity using NULL - setPointer(const_cast(p)); - } - - - inline ~ReferenceCountedPointer() { - zeroPointer(); - } - - inline size_t hashCode() const { - return reinterpret_cast(m_pointer);; - } - - inline const ReferenceCountedPointer& operator=(const ReferenceCountedPointer& p) { - setPointer(p.m_pointer); - return *this; - } - - inline ReferenceCountedPointer& operator=(T* p) { - setPointer(p); - return *this; - } - - inline bool operator==(const ReferenceCountedPointer& y) const { - return (m_pointer == y.m_pointer); - } - - inline bool operator!=(const ReferenceCountedPointer& y) const { - return (m_pointer != y.m_pointer); - } - - bool operator < (const ReferenceCountedPointer& y) const { - return (m_pointer < y.m_pointer); - } - - bool operator > (const ReferenceCountedPointer& y) const { - return (m_pointer > y.m_pointer); - } - - bool operator <= (const ReferenceCountedPointer& y) const { - return (m_pointer <= y.m_pointer); - } - - bool operator >= (const ReferenceCountedPointer& y) const { - return (m_pointer >= y.m_pointer); - } - - inline T& operator*() const { - debugAssertM(m_pointer != NULL, "Dereferenced a NULL ReferenceCountedPointer"); - return (*m_pointer); - } - - inline T* operator->() const { - debugAssertM(m_pointer != NULL, "Dereferenced a NULL ReferenceCountedPointer"); - return m_pointer; - } - - inline bool isNull() const { - return (m_pointer == NULL); - } - - inline bool notNull() const { - return (m_pointer != NULL); - } - - // TODO: distinguish between last strong and last any pointer - /** - Returns true if this is the last reference to an object. - Useful for flushing memoization caches-- a cache that holds the last - reference is unnecessarily keeping an object alive. - - Not threadsafe. - - @deprecated Use WeakReferenceCountedPointer for caches - */ - inline int isLastReference() const { - return (m_pointer->ReferenceCountedObject_refCount.value() == 1); - } -}; - - -/** - A weak pointer allows the object it references to be garbage collected. - Weak pointers are commonly used in caches, where it is important to hold - a pointer to an object without keeping that object alive solely for the - cache's benefit (i.e., the object can be collected as soon as all - pointers to it outside the cache are gone). They are also convenient - for adding back-pointers in tree and list structures. - - Weak pointers may become NULL at any point (when their target is collected). - Therefore the only way to reference the target is to convert to a strong - pointer and then check that it is not NULL. - -@deprecated To be replaced by boost::weak_ptr in 7.0 - */ -template -class WeakReferenceCountedPointer : public _WeakPtr { -private: - - /** NULL if the object has been collected. */ - T* pointer; - -public: - /** - Creates a strong pointer, which prevents the object from being - garbage collected. The strong pointer may be NULL, which means - that the underlying. - */ - // There is intentionally no way to check if the - // WeakReferenceCountedPointer has a null reference without - // creating a strong pointer since there is no safe way to use - // that information-- the pointer could be collected by a - // subsequent statement. - ReferenceCountedPointer createStrongPtr() const { - // TODO: What if the object's destructor is called while we - // are in this method? - return ReferenceCountedPointer(pointer); - } - -private: - - /** Thread issues: safe because this is only called when another - object is guaranteed to keep p alive for the duration of this - call. */ - void setPointer(T* p) { - // TODO: must prevent the object from being collected while in - // this method - - zeroPointer(); - pointer = p; - - if (pointer != NULL) { - // TODO: threadsafe: must update the list atomically - - // Add myself to the head of my target's list of weak pointers - _WeakPtrLinkedList* head = - new _WeakPtrLinkedList - (this, - pointer->ReferenceCountedObject_weakPointer); - - pointer->ReferenceCountedObject_weakPointer = head; - } else { - - } - } - - - /** - Removes this from its target's list of weak pointers. Called - when the weak pointer goes out of scope. - - Thread issues: depends on the thread safety of createStrongPtr. - */ - void zeroPointer() { - // Grab a strong reference to prevent the object from being collected while we - // are traversing its list. - ReferenceCountedPointer strong = createStrongPtr(); - - // If the following test fails then the object was collected before we - // reached it. - if (strong.notNull()) { - debugAssertM(((ReferenceCountedObject*)pointer)->ReferenceCountedObject_weakPointer != NULL, - "Weak pointer exists without a backpointer from the object."); - - // Remove myself from my target's list of weak pointers - _WeakPtrLinkedList** node = &((ReferenceCountedObject*)pointer)->ReferenceCountedObject_weakPointer; - while ((*node)->weakPtr != this) { - node = &((*node)->next); - debugAssertM(*node != NULL, - "Weak pointer exists without a backpointer from the object (2)."); - } - - // Node must now point at the node for me. Remove node and - // close the linked list behind it. - _WeakPtrLinkedList* temp = *node; - *node = temp->next; - - // Now delete the node corresponding to me - delete temp; - } - - pointer = NULL; - } - -public: - - WeakReferenceCountedPointer() : pointer(0) {} - - /** - Allow compile time subtyping rule - RCP<T> <: RCP<S> if T <: S - */ - template - inline WeakReferenceCountedPointer(const WeakReferenceCountedPointer& p) : pointer(0) { - // Threadsafe: the object cannot be collected while the other pointer exists. - setPointer(p.pointer); - } - - template - inline WeakReferenceCountedPointer(const ReferenceCountedPointer& p) : pointer(0) { - // Threadsafe: the object cannot be collected while the other - // pointer exists. - setPointer(p.pointer()); - } - - // Gets called a *lot* when weak pointers are on the stack - WeakReferenceCountedPointer( - const WeakReferenceCountedPointer& weakPtr) : pointer(0) { - setPointer(weakPtr.pointer); - } - - WeakReferenceCountedPointer( - const ReferenceCountedPointer& strongPtr) : pointer(0) { - setPointer(strongPtr.pointer()); - } - - ~WeakReferenceCountedPointer() { - zeroPointer(); - } - - WeakReferenceCountedPointer& operator=(const WeakReferenceCountedPointer& other) { - // Threadsafe: the object cannot be collected while the other pointer exists. - - // I now point at other's target - setPointer(other.pointer); - - return *this; - } - - WeakReferenceCountedPointer& operator=(const ReferenceCountedPointer& other) { - - // Threadsafe: the object cannot be collected while the other pointer exists. - - // I now point at other's target - setPointer(other.pointer()); - - return *this; - } - - bool operator==(const WeakReferenceCountedPointer& other) const { - return pointer == other.pointer; - } - - bool operator!=(const WeakReferenceCountedPointer& other) const { - return pointer != other.pointer; - } - - bool operator < (const WeakReferenceCountedPointer& y) const { - return (pointer < y.pointer); - } - - bool operator > (const WeakReferenceCountedPointer& y) const { - return (pointer > y.pointer); - } - - bool operator <= (const WeakReferenceCountedPointer& y) const { - return (pointer <= y.pointer); - } - - bool operator >= (const ReferenceCountedPointer& y) const { - return (pointer >= y.pointer); - } - -protected: - - /** Invoked by the destructor on ReferenceCountedPointer. */ - void objectCollected() { - debugAssertM(pointer != NULL, - "Removed a weak pointer twice."); - pointer = NULL; - } - -}; +template +bool notNull(const T* ptr) { + return ptr != NULL; +} } // namespace diff --git a/deps/g3dlite/include/G3D/RegistryUtil.h b/deps/g3dlite/include/G3D/RegistryUtil.h index 4b47be5f4..bd728562f 100644 --- a/deps/g3dlite/include/G3D/RegistryUtil.h +++ b/deps/g3dlite/include/G3D/RegistryUtil.h @@ -15,7 +15,7 @@ #include "G3D/g3dmath.h" // This file is only used on Windows -#ifdef G3D_WIN32 +#ifdef G3D_WINDOWS #include @@ -92,6 +92,6 @@ public: } // namespace G3D -#endif // G3D_WIN32 +#endif // G3D_WINDOWS #endif // G3D_REGISTRYTUIL_H diff --git a/deps/g3dlite/include/G3D/Set.h b/deps/g3dlite/include/G3D/Set.h index 0ea96b880..abad5e44e 100644 --- a/deps/g3dlite/include/G3D/Set.h +++ b/deps/g3dlite/include/G3D/Set.h @@ -125,8 +125,13 @@ public: return !(*this == other); } + bool isValid() const { + return it.isValid(); + } + + /** @deprecated Use isValid */ bool hasMore() const { - return it.hasMore(); + return it.isValid(); } bool operator==(const Iterator& other) const { diff --git a/deps/g3dlite/include/G3D/SmallArray.h b/deps/g3dlite/include/G3D/SmallArray.h index 900d2335e..f738e1e8d 100644 --- a/deps/g3dlite/include/G3D/SmallArray.h +++ b/deps/g3dlite/include/G3D/SmallArray.h @@ -1,10 +1,10 @@ /** - @file SmallArray.h + \file G3D/SmallArray.h - @created 2009-04-26 - @edited 2010-02-26 + \created 2009-04-26 + \edited 2012-07-23 - Copyright 2000-2010, Morgan McGuire, http://graphics.cs.williams.edu + Copyright 2000-2012, Morgan McGuire, http://graphics.cs.williams.edu All rights reserved. */ #ifndef G3D_SmallArray_h @@ -83,6 +83,35 @@ public: push(v); } + inline void append(const T& v, const T& v2) { + push(v); + push(v2); + } + + inline void append(const T& v, const T& v2, const T& v3) { + push(v); + push(v2); + push(v3); + } + + inline void append(const T& v, const T& v2, const T& v3, const T& v4) { + push(v); + push(v2); + push(v3); + push(v4); + } + + /** Find the index of \a v or -1 if not found */ + int findIndex(const T& v) { + for (int i = 0; i < N; ++i) { + if (m_embedded[i] == v) { + return i; + } + } + + return m_rest.findIndex(v) + N; + } + void fastRemove(int i, bool shrinkIfNecessary = false) { debugAssert(i < m_size && i >= 0); if (i < N) { @@ -139,8 +168,8 @@ public: return m_rest.contains(value); } - template - SmallArray& operator=(const Array& src) { + template + SmallArray& operator=(const Array& src) { resize(src.size()); for (int i = 0; i < src.size(); ++i) { (*this)[i] = src[i]; @@ -148,13 +177,13 @@ public: return *this; } - inline const T& last() const { - return (*this)[size() - 1]; - } + inline const T& last() const { + return (*this)[size() - 1]; + } - inline T& last() { - return (*this)[size() - 1]; - } + inline T& last() { + return (*this)[size() - 1]; + } }; } diff --git a/deps/g3dlite/include/G3D/SpawnBehavior.h b/deps/g3dlite/include/G3D/SpawnBehavior.h new file mode 100644 index 000000000..25f68c0a6 --- /dev/null +++ b/deps/g3dlite/include/G3D/SpawnBehavior.h @@ -0,0 +1,6 @@ +#ifndef SpawnBehavior_h +#define SpawnBehavior_h +namespace G3D { +enum SpawnBehavior {USE_NEW_THREAD, USE_CURRENT_THREAD}; +} +#endif diff --git a/deps/g3dlite/include/G3D/Sphere.h b/deps/g3dlite/include/G3D/Sphere.h index d1448261d..fa060f0c1 100644 --- a/deps/g3dlite/include/G3D/Sphere.h +++ b/deps/g3dlite/include/G3D/Sphere.h @@ -1,16 +1,16 @@ /** - @file Sphere.h + \file G3D/Sphere.h Sphere class - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2001-06-02 - @edited 2008-10-07 + \created 2001-06-02 + \edited 2011-02-07 */ -#ifndef G3D_SPHERE_H -#define G3D_SPHERE_H +#ifndef G3D_Sphere_h +#define G3D_Sphere_h #include "G3D/platform.h" #include "G3D/Vector3.h" @@ -27,28 +27,36 @@ private: static int32 dummy; public: - Vector3 center; + Point3 center; float radius; - Sphere() { - center = Vector3::zero(); - radius = 0; + Sphere() : center(Point3::zero()), radius(0) { } + explicit Sphere(float radius) : radius(radius) {} + Sphere(class BinaryInput& b); void serialize(class BinaryOutput& b) const; void deserialize(class BinaryInput& b); - Sphere( - const Vector3& center, - float radius) { + /** Format is one of: + - Sphere(point, radius) + - Sphere(radius) + */ + explicit Sphere(const class Any& a); - this->center = center; - this->radius = radius; + Any toAny() const; + + Sphere + (const Point3& center, + float radius) : center(center), radius(radius) { } virtual ~Sphere() {} + /** Returns the infinite sphere. */ + static const Sphere& inf(); + bool operator==(const Sphere& other) const { return (center == other.center) && (radius == other.radius); } @@ -61,7 +69,7 @@ public: Returns true if point is less than or equal to radius away from the center. */ - bool contains(const Vector3& point) const; + bool contains(const Point3& point) const; bool contains(const Sphere& other) const; @@ -71,7 +79,7 @@ public: bool culledBy( const class Plane* plane, int numPlanes, - int32& cullingPlaneIndex, + int32& cullingPlaneIndex, const uint32 testMask, uint32& childMask) const; @@ -88,18 +96,18 @@ public: See AABox::culledBy */ bool culledBy( - const Array& plane, - int32& cullingPlaneIndex, - const uint32 testMask, + const Array& plane, + int32& cullingPlaneIndex, + const uint32 testMask, uint32& childMask) const; /** Conservative culling test that does not produce a mask for children. */ bool culledBy( - const Array& plane, - int32& cullingPlaneIndex = dummy, - const uint32 testMask = 0xFFFFFFFF) const; + const Array& plane, + int32& cullingPlaneIndex = dummy, + const uint32 testMask = 0xFFFFFFFF) const; virtual std::string toString() const; @@ -110,12 +118,12 @@ public: /** Uniformly distributed on the surface. */ - Vector3 randomSurfacePoint() const; + Point3 randomSurfacePoint() const; /** Uniformly distributed on the interior (includes surface) */ - Vector3 randomInteriorPoint() const; + Point3 randomInteriorPoint() const; void getBounds(class AABox& out) const; diff --git a/deps/g3dlite/include/G3D/Spline.h b/deps/g3dlite/include/G3D/Spline.h index 89f89194f..360de1676 100644 --- a/deps/g3dlite/include/G3D/Spline.h +++ b/deps/g3dlite/include/G3D/Spline.h @@ -1,17 +1,19 @@ /** - @file Spline.h + \file G3D/Spline.h - @author Morgan McGuire, http://graphics.cs.williams.edu + \author Morgan McGuire, http://graphics.cs.williams.edu */ -#ifndef G3D_SPLINE_H -#define G3D_SPLINE_H +#ifndef G3D_Spline_h +#define G3D_Spline_h #include "G3D/platform.h" #include "G3D/Array.h" #include "G3D/g3dmath.h" #include "G3D/Matrix4.h" #include "G3D/Vector4.h" +#include "G3D/Any.h" +#include "G3D/SplineExtrapolationMode.h" namespace G3D { @@ -23,10 +25,12 @@ public: number of elements as Spline::control. */ Array time; - /** If cyclic, then the control points will be assumed to wrap around. - If not cyclic, then the tangents at the ends of the spline - point to the final control points.*/ - bool cyclic; + /** If CYCLIC, then the control points will be assumed to wrap around. + If LINEAR, then the tangents at the ends of the spline + point to the final control points. If CONSTANT, the end control + points will be treated as multiple contol points (so the value remains constant at the ends) + */ + SplineExtrapolationMode extrapolationMode; /** For a cyclic spline, this is the time elapsed between the last control point and the first. If less than or equal to zero this is @@ -36,8 +40,13 @@ public: time[time.size() - 1] - time[time.size() - 2]) / 2. */ float finalInterval; + + SplineInterpolationMode interpolationMode; - SplineBase() : cyclic(true), finalInterval(-1) {} + SplineBase() : + extrapolationMode(SplineExtrapolationMode::CYCLIC), + finalInterval(-1), + interpolationMode(SplineInterpolationMode::CUBIC) {} virtual ~SplineBase() {} @@ -144,11 +153,7 @@ public: break; case 1: - if (time[0] == 0) { - append(1, c); - } else { - append(time[0], c); - } + append(time[0] + 1, c); break; default: @@ -192,7 +197,7 @@ public: if (N == 0) { c = zero; t = 0; - } else if (cyclic) { + } else if (extrapolationMode == SplineExtrapolationMode::CYCLIC) { c = control[iWrap(i, N)]; if (i < 0) { @@ -222,9 +227,16 @@ public: // Step away from control point 0 float dt = time[1] - time[0]; - // Extrapolate (note; i is negative) - c = control[1] * float(i) + control[0] * float(1 - i); - correct(c); + if (extrapolationMode == SplineExtrapolationMode::LINEAR) { + // Extrapolate (note; i is negative) + c = control[1] * float(i) + control[0] * float(1 - i); + correct(c); + } else if (extrapolationMode == SplineExtrapolationMode::CLAMP){ + // Return the first, clamping + c = control[0]; + } else { + alwaysAssertM(false, "Invalid extrapolation mode"); + } t = dt * i + time[0]; } else { @@ -239,9 +251,17 @@ public: if (N >= 2) { float dt = time[N - 1] - time[N - 2]; + if (extrapolationMode == SplineExtrapolationMode::LINEAR) { + // Extrapolate (note; i is negative) + c = control[N - 1] * float(i - N + 2) + control[N - 2] * -float(i - N + 1); + correct(c); + } else if (extrapolationMode == SplineExtrapolationMode::CLAMP){ + // Return the last, clamping + c = control.last(); + } else { + alwaysAssertM(false, "Invalid extrapolation mode"); + } // Extrapolate - c = control[N - 1] * float(i - N + 2) + control[N - 2] * -float(i - N + 1); - correct(c); t = time[N - 1] + dt * (i - N + 1); } else { @@ -279,8 +299,47 @@ protected: /** Normalize or otherwise adjust this interpolated Control. */ virtual void correct(Control& A) const { (void)A; } + /** Does not invoke verifyDone() on the propertyTable because subclasses may have more properties */ + virtual void init(AnyTableReader& propertyTable) { + propertyTable.getIfPresent("extrapolationMode", extrapolationMode); + propertyTable.getIfPresent("interpolationMode", interpolationMode); + propertyTable.getIfPresent("finalInterval", finalInterval); + + const bool hasTime = propertyTable.getIfPresent("time", time); + + if (propertyTable.getIfPresent("control", control)) { + if (! hasTime) { + // Assign unit times + time.resize(control.size()); + for (int i = 0; i < time.size(); ++i) { + time[i] = float(i); + } + } // if has time + } // if has control + } // init + public: - + + /** Accepts a table of properties, or any valid PhysicsFrame specification for a single control*/ + explicit Spline(const Any& any) { + AnyTableReader propertyTable(any); + init(propertyTable); + propertyTable.verifyDone(); + } + + /** Note that invoking classes can call setName on the returned value instead of passing a name in. */ + virtual Any toAny(const std::string& myName) const { + Any a(Any::TABLE, myName); + + a["extrapolationMode"] = extrapolationMode; + a["interpolationMode"] = interpolationMode; + a["control"] = Any(control); + a["time"] = Any(time); + a["finalInterval"] = finalInterval; + + return a; + } + /** Return the position at time s. The spline is defined outside @@ -313,6 +372,22 @@ public: Control p[4]; float t[4]; getControls(i - 1, t, p, 4); + + const Control& p0 = p[0]; + const Control& p1 = p[1]; + const Control& p2 = p[2]; + const Control& p3 = p[3]; + + // Compute the weighted sum of the neighboring control points. + Control sum; + + if (interpolationMode == SplineInterpolationMode::LINEAR) { + const float a = (s - t[1]) / (t[2] - t[1]); + sum = p1 * (1.0f - a) + p2 * a; + correct(sum); + return sum; + } + float dt0 = t[1] - t[0]; float dt1 = t[2] - t[1]; float dt2 = t[3] - t[2]; @@ -325,13 +400,6 @@ public: // Compute the weights on each of the control points. const Vector4& weights = uvec * basis; - // Compute the weighted sum of the neighboring control points. - Control sum; - - const Control& p0 = p[0]; - const Control& p1 = p[1]; - const Control& p2 = p[2]; - const Control& p3 = p[3]; // The factor of 1/2 from averaging two time intervals is // already factored into the basis diff --git a/deps/g3dlite/include/G3D/SplineExtrapolationMode.h b/deps/g3dlite/include/G3D/SplineExtrapolationMode.h new file mode 100644 index 000000000..b5cdc6fb8 --- /dev/null +++ b/deps/g3dlite/include/G3D/SplineExtrapolationMode.h @@ -0,0 +1,94 @@ +/** + \file G3D/SplineExtrapolationMode.h + + \maintainer Michael Mara, http://graphics.cs.williams.edu + + \created 2013-01-24 + \edited 2013-01-24 + + Copyright 2000-2013, Morgan McGuire. + All rights reserved. + */ + +#ifndef G3D_SplineExtrapolationMode_h +#define G3D_SplineExtrapolationMode_h + +#include "G3D/platform.h" +#include "G3D/enumclass.h" + + +namespace G3D { + +/** + Describes the behavior of G3D::Spline, etc. when accessing a time outside of the control point range. + + Refer to these as scoped enums, e.g., SplineExtrapolationMode m = SplineExtrapolationMode::CLAMP;. + + Uses the "Intelligent Enum" design pattern + http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4001/ + */ +class SplineExtrapolationMode { +public: + /** Don't use this enum; use SplineExtrapolationMode instances instead. */ + enum Value { + CYCLIC, + LINEAR, + CLAMP + }; + Value value; +private: + + static const char* toString(int i, Value& v) { + static const char* str[] = {"CYCLIC", "LINEAR", "CLAMP", NULL}; + static const Value val[] = {CYCLIC, LINEAR, CLAMP}; + const char* s = str[i]; + if (s) { + v = val[i]; + } + return s; + } + +public: + + G3D_DECLARE_ENUM_CLASS_METHODS(SplineExtrapolationMode); +}; + + + + +/** + Describes the behavior of G3D::Spline + */ +class SplineInterpolationMode { +public: + /** Don't use this enum; use SplineExtrapolationMode instances instead. */ + enum Value { + LINEAR, + CUBIC + }; + Value value; +private: + + static const char* toString(int i, Value& v) { + static const char* str[] = {"LINEAR", "CUBIC", NULL}; + static const Value val[] = {LINEAR, CUBIC}; + const char* s = str[i]; + if (s) { + v = val[i]; + } + return s; + } + +public: + + G3D_DECLARE_ENUM_CLASS_METHODS(SplineInterpolationMode); + +}; + + +} // namespace G3D + +G3D_DECLARE_ENUM_CLASS_HASHCODE(G3D::SplineExtrapolationMode); +G3D_DECLARE_ENUM_CLASS_HASHCODE(G3D::SplineInterpolationMode); + +#endif diff --git a/deps/g3dlite/include/G3D/Stopwatch.h b/deps/g3dlite/include/G3D/Stopwatch.h index 3f2aa9c8d..48c223b5b 100644 --- a/deps/g3dlite/include/G3D/Stopwatch.h +++ b/deps/g3dlite/include/G3D/Stopwatch.h @@ -46,6 +46,9 @@ class Stopwatch { private: std::string myName; + + bool m_enabled; + double startTime; std::string prevMark; double prevTime; @@ -85,6 +88,15 @@ public: Stopwatch(const std::string& name = "Stopwatch"); + void setEnabled(bool e) { + m_enabled = e; + } + + /** A stopwatch only prints output when enabled */ + bool enabled() const { + return m_enabled; + } + /** Returns the number of times that tick was called per wall-clock second; e.g. frames-per-second. */ double FPS() const { @@ -130,7 +142,10 @@ public: void reset(); /** Call after an operation has completed, with the name of the operation, to - print a debug message listing the time since the previous after() call. */ + print a debug message listing the time since the previous after() call. + + Does nothing if the stopwatch is disabled. + */ void after(const std::string& s = ""); }; diff --git a/deps/g3dlite/include/G3D/System.h b/deps/g3dlite/include/G3D/System.h index 39ea842c9..9ed88957d 100644 --- a/deps/g3dlite/include/G3D/System.h +++ b/deps/g3dlite/include/G3D/System.h @@ -1,14 +1,14 @@ /** - @file System.h + \file System.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @cite Rob Wyatt http://www.gamasutra.com/features/wyatts_world/19990709/processor_detection_01.htm - @cite Benjamin Jurke http://www.flipcode.com/cgi-bin/msg.cgi?showThread=COTD-ProcessorDetectionClass&forum=cotd&id=-1 - @cite Michael Herf http://www.stereopsis.com/memcpy.html + \cite Rob Wyatt http://www.gamasutra.com/features/wyatts_world/19990709/processor_detection_01.htm + \cite Benjamin Jurke http://www.flipcode.com/cgi-bin/msg.cgi?showThread=COTD-ProcessorDetectionClass&forum=cotd&id=-1 + \cite Michael Herf http://www.stereopsis.com/memcpy.html - @created 2003-01-25 - @edited 2008-10-14 + \created 2003-01-25 + \edited 2012-10-02 */ #ifndef G3D_System_h @@ -18,28 +18,20 @@ #include "G3D/g3dmath.h" #include "G3D/G3DGameUnits.h" #include "G3D/BinaryFormat.h" +#include "G3D/FileNotFound.h" #include -#ifdef G3D_LINUX -# include + +#if defined(__aarch64__) +#include #endif #ifdef G3D_OSX +#define Zone OSX_Zone # include #endif namespace G3D { - -/** - Routine used by the demos to find the data. Searches in - ../data, ../../data, etc. up to 5 levels back. Checks - common locations like \verbatim c:\libraries\g3d-\data \endverbatim - and some hard-coded paths on the Brown University file - system. - - @deprecated - */ -std::string demoFindData(bool errorIfNotFound = true); - + /** G3D, SDL, and IJG libraries require license documentation to be distributed with your program. This generates the string that must appear in your documentation. @@ -118,7 +110,7 @@ private: std::string m_cpuArch; std::string m_operatingSystem; -# ifdef G3D_WIN32 +# ifdef G3D_WINDOWS /** Used by getTick() for timing */ LARGE_INTEGER m_start; LARGE_INTEGER m_counterFrequency; @@ -167,7 +159,6 @@ private: */ static void cpuid(CPUIDFunction func, uint32& areg, uint32& breg, uint32& creg, uint32& dreg); - void init(); /** Called from init() */ void getStandardProcessorExtensions(); @@ -175,7 +166,12 @@ private: /** Called from init() */ void initTime(); + void init(); + public: + + /** atexit handling code invoked from G3DCleanupHook. */ + static void cleanup(); /** Returns the speed of processor 0 in MHz. Always returns 0 on linux.*/ @@ -243,16 +239,13 @@ public: */ static std::string currentDateString(); - /** - Guarantees that the start of the array is aligned to the - specified number of bytes. - */ - static void* alignedMalloc(size_t bytes, size_t alignment); - + /** Returns the current 24-hour local time as a string in the form HH:MM:SS */ + static std::string currentTimeString(); + /** Uses pooled storage to optimize small allocations (1 byte to 5 - kilobytes). Can be 10x to 100x faster than calling ::malloc or - new. + kilobytes). Can be 10x to 100x faster than calling \c malloc or + \c new. The result must be freed with free. @@ -288,6 +281,12 @@ public: */ static void free(void* p); + /** + Guarantees that the start of the array is aligned to the + specified number of bytes. + */ + static void* alignedMalloc(size_t bytes, size_t alignment); + /** Frees memory allocated with alignedMalloc. */ @@ -370,6 +369,7 @@ public: /** To count the number of cycles a given operation takes: + \htmlonly
          unsigned long count;
          System::beginCycleCount(count);
    @@ -377,11 +377,12 @@ public:
          System::endCycleCount(count);
          // count now contains the cycle count for the intervening operation.
          
    + \endhtmlonly */ - /* static void beginCycleCount(uint64& cycleCount); + static void beginCycleCount(uint64& cycleCount); static void endCycleCount(uint64& cycleCount); - static uint64 getCycleCount(); */ + static uint64 getCycleCount(); inline static void setOutOfMemoryCallback(OutOfMemoryCallback c) { instance().m_outOfMemoryCallback = c; @@ -404,7 +405,7 @@ public: /** Set an environment variable for the current process */ static void setEnv(const std::string& name, const std::string& value); - + /** Get an environment variable for the current process. Returns NULL if the variable doesn't exist. */ static const char* getEnv(const std::string& name); @@ -412,25 +413,53 @@ public: Prints a human-readable description of this machine to the text output stream. Either argument may be NULL. */ - static void describeSystem( - class TextOutput& t); + static void describeSystem + (class TextOutput& t); - static void describeSystem( - std::string& s); - - /** On Win32, returns the clipboard text contents. Does nothing on other - platforms (yet) */ - static std::string getClipboardText(); - - /** Copies the text to the clipboard on Win32. */ - static void setClipboardText(const std::string& s); + static void describeSystem + (std::string& s); /** Tries to locate the resource by looking in related directories. If found, returns the full path to the resource, otherwise returns the empty string. + + Looks in: + + - Literal interpretation of full (i.e., if it contains a fully-qualified name) + - Last directory in which a file was found + - Current directory + - System::appDataDir (which is usually GApp::Settings.dataDir, which defaults to the directory containing the program binary) + - $G3D9DATA directory + - System::appDataDir() + "data/" (note that this may be a zipfile named "data" with no extension) + - System::appDataDir() + "data.zip/" + - ../data-files/ (windows) + - ../../data-files/ (windows) + - ../../../data-files/ (windows) + + Plus the following subdirectories of those: + + - cubemap + - gui + - font + - icon + - models + - image + - sky + - md2 + - md3 + - ifs + - 3ds + + \param exceptionIfNotFound If true and the file is not found, throws G3D::FileNotFound. */ - static std::string findDataFile(const std::string& full, bool errorIfNotFound = true); + static std::string findDataFile(const std::string& full, bool exceptionIfNotFound = true, bool caseSensitive = +#ifdef G3D_WINDOWS + false +#else + true +#endif + ); /** Sets the path that the application is using as its data directory. @@ -441,47 +470,80 @@ public: }; -/* don't need that for Moongose, not portable to Win64... + #ifdef _MSC_VER - inline uint64 System::getCycleCount() { - uint32 timehi, timelo; +# ifdef _M_IX86 + // 32-bit + inline uint64 System::getCycleCount() { + uint32 timehi, timelo; - // Use the assembly instruction rdtsc, which gets the current - // cycle count (since the process started) and puts it in edx:eax. - __asm - { - rdtsc; - mov timehi, edx; - mov timelo, eax; - } + // Use the assembly instruction rdtsc, which gets the current + // cycle count (since the process started) and puts it in edx:eax. + __asm + { + rdtsc; + mov timehi, edx; + mov timelo, eax; + } - return ((uint64)timehi << 32) + (uint64)timelo; - } + return ((uint64)timehi << 32) + (uint64)timelo; + } +# else + // 64-bit + inline uint64 System::getCycleCount() { + LARGE_INTEGER now; + QueryPerformanceCounter(&now); + return now.QuadPart; + } + +# endif #elif defined(G3D_LINUX) inline uint64 System::getCycleCount() { - uint32 timehi, timelo; +# if defined(__aarch64__) +# if (__ARM_ARCH >= 6) // V6 is the earliest arch that has a standard cyclecount + uint32_t pmccntr; + uint32_t pmuseren; + uint32_t pmcntenset; + // Read the user mode perf monitor counter access permissions. + __asm__ __volatile__("mrc p15, 0, %w0, c9, c14, 0" : "=r"(pmuseren)); + if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. + __asm__ __volatile__("mrc p15, 0, %w0, c9, c12, 1" : "=r"(pmcntenset)); + if (pmcntenset & 0x80000000ul) { // Is it counting? + __asm__ __volatile__("mrc p15, 0, %w0, c9, c13, 0" : "=r"(pmccntr)); + // The counter is set up to count every 64th cycle + return static_cast(pmccntr) * 64; // Should optimize to << 6 + } + } +# endif - __asm__ __volatile__ ( - "rdtsc " - : "=a" (timelo), - "=d" (timehi) - : ); + struct timeval tv; + gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; +# else + uint32 timehi, timelo; - return ((uint64)timehi << 32) + (uint64)timelo; + __asm__ __volatile__ ( + "rdtsc " + : "=a" (timelo), + "=d" (timehi) + : ); + + return ((uint64)timehi << 32) + (uint64)timelo; +# endif } #elif defined(G3D_OSX) inline uint64 System::getCycleCount() { - //Note: To put off extra processing until the end, this does not - //return the actual clock cycle count. It is a bus cycle count. - //When endCycleCount() is called, it converts the two into a difference - //of clock cycles - + //Note: To put off extra processing until the end, this does not + //return the actual clock cycle count. It is a bus cycle count. + //When endCycleCount() is called, it converts the two into a difference + //of clock cycles + return (uint64) UnsignedWideToUInt64(UpTime()); - //return (uint64) mach_absolute_time(); + //return (uint64) mach_absolute_time(); } #endif @@ -496,15 +558,20 @@ inline void System::endCycleCount(uint64& cycleCount) { cycleCount = getCycleCount() - cycleCount; #else AbsoluteTime end = UpTime(); - Nanoseconds diffNS = + Nanoseconds diffNS = AbsoluteDeltaToNanoseconds(end, UInt64ToUnsignedWide(cycleCount)); - cycleCount = - (uint64) ((double) (instance().m_OSXCPUSpeed) * + cycleCount = + (uint64) ((double) (instance().m_OSXCPUSpeed) * (double) UnsignedWideToUInt64(diffNS) * instance().m_secondsPerNS); #endif } - */ + } // namespace + +#ifdef G3D_OSX +#undef Zone +#endif + #endif diff --git a/deps/g3dlite/include/G3D/Table.h b/deps/g3dlite/include/G3D/Table.h index ab0b114b1..b8653fdcc 100644 --- a/deps/g3dlite/include/G3D/Table.h +++ b/deps/g3dlite/include/G3D/Table.h @@ -5,8 +5,8 @@ @maintainer Morgan McGuire, http://graphics.cs.williams.edu @created 2001-04-22 - @edited 2010-01-28 - Copyright 2000-2010, Morgan McGuire. + @edited 2013-01-22 + Copyright 2000-2013, Morgan McGuire. All rights reserved. */ @@ -90,7 +90,8 @@ namespace G3D { }; - and rely on the default enum operator==. + And rely on the default enum operator==. + Periodically check that debugGetLoad() is low (> 0.1). When it gets near 1.0 your hash function is badly designed and maps too many inputs to @@ -132,10 +133,12 @@ private: // Private to require use of the allocator Node(const Key& k, const Value& v, size_t h, Node* n) : entry(k, v), hashCode(h), next(n) { + debugAssert((next == NULL) || isValidHeapPointer(next)); } Node(const Key& k, size_t h, Node* n) : entry(k), hashCode(h), next(n) { + debugAssert((next == NULL) || isValidHeapPointer(next)); } public: @@ -213,9 +216,9 @@ private: // Allocate a new m_bucket array with the new size m_bucket = (Node**)alloc(sizeof(Node*) * newSize); + alwaysAssertM(m_bucket != NULL, "MemoryManager::alloc returned NULL. Out of memory."); // Set all pointers to NULL System::memset(m_bucket, 0, newSize * sizeof(Node*)); - debugAssertM(m_bucket != NULL, "MemoryManager::alloc returned NULL. Out of memory."); // Move each node to its new hash location for (size_t b = 0; b < m_numBuckets; ++b) { Node* node = oldBucket[b]; @@ -274,7 +277,7 @@ private: void freeMemory() { checkIntegrity(); - for (size_t b = 0; b < m_numBuckets; b++) { + for (size_t b = 0; b < m_numBuckets; ++b) { Node* node = m_bucket[b]; while (node != NULL) { Node* next = node->next; @@ -357,7 +360,7 @@ public: size_t debugGetDeepestBucketSize() const { size_t deepest = 0; - for (size_t b = 0; b < m_numBuckets; b++) { + for (size_t b = 0; b < m_numBuckets; ++b) { size_t count = 0; Node* node = m_bucket[b]; while (node != NULL) { @@ -377,21 +380,16 @@ public: Returns the average size of non-empty buckets. */ float debugGetAverageBucketSize() const { - size_t num = 0; - size_t count = 0; + uint64 num = 0; - for (size_t b = 0; b < m_numBuckets; b++) { + for (size_t b = 0; b < m_numBuckets; ++b) { Node* node = m_bucket[b]; if (node != NULL) { ++num; - while (node != NULL) { - node = node->next; - ++count; - } } } - return (float)((double)count / num); + return (float)((double)size() / num); } /** @@ -402,7 +400,7 @@ public: many keys to the same code. */ double debugGetLoad() const { - return debugGetDeepestBucketSize() / (double)size(); + return (double)size() / m_numBuckets; } /** @@ -428,7 +426,7 @@ public: Linked list node. */ Node* node; - ThisType* table; + size_t m_numBuckets; Node** m_bucket; bool isDone; @@ -436,13 +434,14 @@ public: /** Creates the end iterator. */ - Iterator(const ThisType* table) : table(const_cast(table)) { + Iterator() : index(0), node(NULL), m_bucket(NULL) { isDone = true; } - Iterator(const ThisType* table, size_t m_numBuckets, Node** m_bucket) : - table(const_cast(table)), - m_numBuckets(m_numBuckets), + Iterator(size_t numBuckets, Node** m_bucket) : + index(0), + node(NULL), + m_numBuckets(numBuckets), m_bucket(m_bucket) { if (m_numBuckets == 0) { @@ -451,26 +450,38 @@ public: return; } +# ifdef G3D_DEBUG + for (unsigned int i = 0; i < m_numBuckets; ++i) { + debugAssert((m_bucket[i] == NULL) || isValidHeapPointer(m_bucket[i])); + } +# endif + index = 0; node = m_bucket[index]; + debugAssert((node == NULL) || isValidHeapPointer(node)); isDone = false; findNext(); + debugAssert((node == NULL) || isValidHeapPointer(node)); } /** - Finds the next element, setting isDone if one can't be found. - Looks at the current element first. + If node is NULL, then finds the next element by searching through the bucket array. + Sets isDone if no more nodes are available. */ void findNext() { while (node == NULL) { - index++; + ++index; if (index >= m_numBuckets) { + m_bucket = NULL; + index = 0; isDone = true; - break; + return; } else { node = m_bucket[index]; + debugAssert((node == NULL) || isValidHeapPointer(node)); } } + debugAssert(isValidHeapPointer(node)); } public: @@ -481,12 +492,9 @@ public: bool operator==(const Iterator& other) const { if (other.isDone || isDone) { // Common case; check against isDone. - return (isDone == other.isDone) && (other.table == table); + return (isDone == other.isDone); } else { - return - (table == other.table) && - (node == other.node) && - (index == other.index); + return (node == other.node) && (index == other.index); } } @@ -494,8 +502,13 @@ public: Pre increment. */ Iterator& operator++() { + debugAssert(! isDone); + debugAssert(node != NULL); + debugAssert(isValidHeapPointer(node)); + debugAssert((node->next == NULL) || isValidHeapPointer(node->next)); node = node->next; findNext(); + debugAssert(isDone || isValidHeapPointer(node)); return *this; } @@ -512,17 +525,32 @@ public: return node->entry; } + const Value& value() const { + return node->entry.value; + } + + const Key& key() const { + return node->entry.key; + } + Entry* operator->() const { + debugAssert(isValidHeapPointer(node)); return &(node->entry); } operator Entry*() const { + debugAssert(isValidHeapPointer(node)); return &(node->entry); } - bool hasMore() const { - return ! isDone; - } + bool isValid() const { + return ! isDone; + } + + /** @deprecated Use isValid */ + bool hasMore() const { + return ! isDone; + } }; @@ -532,7 +560,7 @@ public: the next element. Do not modify the table while iterating. */ Iterator begin() const { - return Iterator(this, m_numBuckets, m_bucket); + return Iterator(m_numBuckets, m_bucket); } /** @@ -540,11 +568,12 @@ public: element. */ const Iterator end() const { - return Iterator(this); + return Iterator(); } /** - Removes all elements + Removes all elements. Guaranteed to free all memory associated with + the table. */ void clear() { freeMemory(); @@ -578,20 +607,21 @@ private: if (m_numBuckets == 0) { return false; } - size_t code = HashFunc::hashCode(key); - size_t b = code % m_numBuckets; + + const size_t code = HashFunc::hashCode(key); + const size_t b = code % m_numBuckets; - // Go to the m_bucket - Node* n = m_bucket[b]; + // Go to the m_bucket + Node* n = m_bucket[b]; - if (n == NULL) { - return false; - } + if (n == NULL) { + return false; + } - Node* previous = NULL; + Node* previous = NULL; - // Try to find the node - do { + // Try to find the node + do { if ((code == n->hashCode) && EqualsFunc::equals(n->entry.key, key)) { // This is the node; remove it @@ -609,6 +639,8 @@ private: // Delete the node Node::destroy(n, m_memoryManager); --m_size; + + //checkIntegrity(); return true; } @@ -616,8 +648,8 @@ private: n = n->next; } while (n != NULL); + //checkIntegrity(); return false; - //alwaysAssertM(false, "Tried to remove a key that was not in the table."); } public: @@ -658,7 +690,7 @@ private: node = node->next; } - return NULL; + return NULL; } public: @@ -733,7 +765,6 @@ public: } - /** Called by getCreate() and set() \param created Set to true if the entry was created by this method. @@ -756,6 +787,7 @@ public: m_bucket[b] = Node::create(key, code, NULL, m_memoryManager); ++m_size; created = true; + //checkIntegrity(); return m_bucket[b]->entry; } @@ -772,6 +804,7 @@ public: if ((code == n->hashCode) && EqualsFunc::equals(n->entry.key, key)) { // This is the a pre-existing node + //checkIntegrity(); return n->entry; } @@ -779,12 +812,18 @@ public: ++bucketLength; } while (n != NULL); + // Allow the load factor to rise as the table gets huge + const int bucketsPerElement = + (m_size > 50000) ? 3 : + ((m_size > 10000) ? 5 : + ((m_size > 5000) ? 10 : 15)); + const size_t maxBucketLength = 3; // (Don't bother changing the size of the table if all entries // have the same hashcode--they'll still collide) if ((bucketLength > maxBucketLength) && ! allSameCode && - (m_numBuckets < m_size * 15)) { + (m_numBuckets < m_size * bucketsPerElement)) { // This m_bucket was really large; rehash if all elements // don't have the same hashcode the number of buckets is @@ -807,8 +846,10 @@ public: m_bucket[b] = Node::create(key, code, m_bucket[b], m_memoryManager); ++m_size; created = true; + + //checkIntegrity(); return m_bucket[b]->entry; - } + } Entry& getCreateEntry(const Key& key) { bool ignore; @@ -871,7 +912,7 @@ public: void getKeys(Array& keyArray) const { keyArray.resize(0, DONT_SHRINK_UNDERLYING_ARRAY); - for (size_t i = 0; i < m_numBuckets; i++) { + for (size_t i = 0; i < m_numBuckets; ++i) { Node* node = m_bucket[i]; while (node != NULL) { keyArray.append(node->entry.key); @@ -880,14 +921,27 @@ public: } } + /** Will contain duplicate values if they exist in the table. This array is parallel to the one returned by getKeys() if the table has not been modified. */ + void getValues(Array& valueArray) const { + valueArray.resize(0, DONT_SHRINK_UNDERLYING_ARRAY); + for (size_t i = 0; i < m_numBuckets; ++i) { + Node* node = m_bucket[i]; + while (node != NULL) { + valueArray.append(node->entry.value); + node = node->next; + } + } + } + /** Calls delete on all of the keys and then clears the table. */ void deleteKeys() { - for (size_t i = 0; i < m_numBuckets; i++) { + for (size_t i = 0; i < m_numBuckets; ++i) { Node* node = m_bucket[i]; while (node != NULL) { delete node->entry.key; + node->entry.key = NULL; node = node->next; } } @@ -912,6 +966,37 @@ public: } } } + + template + bool operator==(const Table& other) const { + if (size() != other.size()) { + return false; + } + + for (Iterator it = begin(); it.hasMore(); ++it) { + const Value* v = other.getPointer(it->key); + if ((v == NULL) || (*v != it->value)) { + // Either the key did not exist or the value was not the same + return false; + } + } + + // this and other have the same number of keys, so we don't + // have to check for extra keys in other. + + return true; + } + + template + bool operator!=(const Table& other) const { + return ! (*this == other); + } + + void debugPrintStatus() { + debugPrintf("Deepest bucket size = %d\n", (int)debugGetDeepestBucketSize()); + debugPrintf("Average bucket size = %g\n", debugGetAverageBucketSize()); + debugPrintf("Load factor = %g\n", debugGetLoad()); + } }; } // namespace diff --git a/deps/g3dlite/include/G3D/TextInput.h b/deps/g3dlite/include/G3D/TextInput.h index 7aefb50ff..47cbe8c91 100644 --- a/deps/g3dlite/include/G3D/TextInput.h +++ b/deps/g3dlite/include/G3D/TextInput.h @@ -1,16 +1,16 @@ /** - @file TextInput.h + \file G3D/TextInput.h Simple text lexer/tokenizer. - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @cite Based on a lexer written by Aaron Orenstein. + \cite Based on a lexer written by Aaron Orenstein. - @created 2002-11-27 - @edited 2010-07-03 + \created 2002-11-27 + \edited 2013-03-25 - Copyright 2000-2010, Morgan McGuire. + Copyright 2000-2013, Morgan McGuire. All rights reserved. */ @@ -148,7 +148,9 @@ public: /** - A simple style tokenizer for reading text files. TextInput handles a + \brief A simple tokenizer for parsing text files. + + TextInput handles a superset of C++,Java, Matlab, and Bash code text including single line comments, block comments, quoted strings with escape sequences, and operators. TextInput recognizes several categories of tokens, @@ -191,7 +193,7 @@ public: Examples -
    +  \code
       TextInput ti(TextInput::FROM_STRING, "name = \"Max\", height = 6");
     
       Token t;
    @@ -206,15 +208,15 @@ public:
     
       std::string name = ti.read().sval;
       ti.read();
    -  
    + \endcode -
    +  \code
       TextInput ti(TextInput::FROM_STRING, "name = \"Max\", height = 6");
       ti.readSymbols("name", "=");
       std::string name = ti.readString();
       ti.readSymbols(",", "height", "=");
       double height = ti. readNumber();
    -  
    + \endcode Assumes that the file is not modified once opened. */ @@ -329,14 +331,15 @@ public: int startingLineNumberOffset; /** - Parse -1.#IND00 as the floating point number returned by - nan(), -1.#INF00 as -G3D::inf(), and 1.#INF00 as G3D::inf(). - + Parse "-1.#IND00" as the floating point number returned by + G3D::nan(), "-1.#INF00" as - G3D::inf(), and "1.#INF00" as G3D::inf(). + Note that the C99 standard specifies that a variety of formats like "nan" are to be used; these are supported by G3D::TextInput::Settings::simpleFloatSpecials. An alternative to specifying msvcFloatSpecials is to read numbers as: + \htmlonly
                 Token x = t.read();
                 Token y = t.peek();
    @@ -349,6 +352,7 @@ public:
                 }
                 // ... similar cases for inf
               
    + \endhtmlonly If the single-comment character was #, the floating point special format overrides the comment and will be parsed @@ -398,9 +402,12 @@ public: Settings(); }; - + private: + /** \sa pushSettings / popSettings */ + Array settingsStack; + std::deque stack; /** @@ -477,7 +484,7 @@ private: Read the next token, returning an END token if no more input is available. */ - Token nextToken(); + void nextToken(Token& t); /** Helper for nextToken. Appends characters to t._string until the end @@ -488,6 +495,8 @@ private: */ void parseQuotedString(unsigned char delimiter, Token& t); + void initFromString(const char* str, int len, const Settings& settings); + public: class TokenException : public ParseError { @@ -569,9 +578,25 @@ public: */ TextInput(FS fs, const std::string& str, const Settings& settings = Settings()); + /** Creates input directly from a fixed-length, non-NULL terminated string. The first argument must be + TextInput::FROM_STRING. + */ + TextInput(FS fs, const char* str, size_t strLen, const Settings& settings = Settings()); + /** Returns true while there are tokens remaining. */ bool hasMore(); + /** Temporarily switch parsing to use \a settings. Note that this will override the currently recorded sourceFilename unless you explicitly set it back. + \sa popSettings */ + void pushSettings(const Settings& settings) { + settingsStack.push(options); + options = settings; + } + + void popSettings() { + options = settingsStack.pop(); + } + /** Read the next token (which will be the END token if ! hasMore()). Signed numbers can be handled in one of two modes. If the option @@ -589,10 +614,13 @@ public: */ Token read(); + /** Avoids the copy of read() */ + void read(Token& t); + /** Calls read() until the result is not a newline or comment */ Token readSignificant(); - /** Read one token (or possibly two) as a number or throws + /** Read one token (or possibly two, for minus sign) as a number or throws WrongTokenType, and returns the number. If the first token in the input is a number, it is returned directly. @@ -608,6 +636,10 @@ public: */ double readNumber(); + /** Reads a number that must be in C integer format: + [ '+' | '-' ] #+ | '0x'#+ */ + int readInteger(); + bool readBoolean(); /** Reads a string token or throws WrongTokenType, and returns the token. @@ -643,7 +675,7 @@ public: input stream is a string but does not match the @p s parameter. When an exception is thrown, no tokens are consumed. - \sa readString(), readStringToken(), readUntilNewlineAsString() + \sa readString(), readStringToken(), readUntilNewlineAsString(), readUntilDelimiterAsString() */ void readString(const std::string& s); @@ -653,6 +685,12 @@ public: end of file token (if they are enabled for parsing).*/ std::string readUntilNewlineAsString(); + /** Read from the beginning of the next token until the following delimiter character + and return the result as a string, ignoring all parsing in between. The delimiter + is not returned in the string, and the following token read will begin at the delimiter or + end of file token (if they are enabled for parsing).*/ + std::string readUntilDelimiterAsString(const char delimiter1, const char delimiter2 = '\0'); + /** Reads a comment token or throws WrongTokenType, and returns the token. Use this method (rather than readComment) if you want the token's @@ -734,6 +772,9 @@ public: */ Token readSymbolToken(); + /** Avoids the copy of readSymbolToken() */ + void readSymbolToken(Token& t); + /** Like readSymbolToken, but returns the token's string. Use this method (rather than readSymbolToken) if you want the token's diff --git a/deps/g3dlite/include/G3D/TextOutput.h b/deps/g3dlite/include/G3D/TextOutput.h index 4c22b7d56..b124f0b74 100644 --- a/deps/g3dlite/include/G3D/TextOutput.h +++ b/deps/g3dlite/include/G3D/TextOutput.h @@ -1,16 +1,16 @@ /** - @file TextOutput.h + \file G3D/TextOutput.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2004-06-21 - @edited 2006-10-24 + \maintainer Morgan McGuire, http://graphics.cs.williams.edu + \created 2004-06-21 + \edited 2011-05-24 - Copyright 2000-2007, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ -#ifndef G3D_TEXTOUTPUT_H -#define G3D_TEXTOUTPUT_H +#ifndef G3D_TextOutput_h +#define G3D_TextOutput_h #include "G3D/platform.h" #include "G3D/Array.h" @@ -112,7 +112,7 @@ public: convertNewlines(true), trueSymbol("true"), falseSymbol("false") { - #ifdef G3D_WIN32 + #ifdef G3D_WINDOWS newlineStyle = NEWLINE_WINDOWS; #else newlineStyle = NEWLINE_UNIX; @@ -156,6 +156,9 @@ private: /** the newline character(s) */ std::string newline; + /** Starts at 1 */ + int m_currentLine; + void setOptions(const Settings& _opt); /** Converts to the desired newlines. Called from vprintf */ @@ -175,6 +178,11 @@ public: /** Constructs a text output that can later be commited to a string instead of a file.*/ explicit TextOutput(const Settings& options = Settings()); + /** Returns one plus the number of newlines written since the output was created. */ + int line() const { + return m_currentLine; + } + /** Commit to the filename specified on the constructor. Not called from the destructor; you must call it yourself. @@ -206,6 +214,9 @@ public: void writeNewline(); void writeNewlines(int numLines); + /** If the most recently written character was a space, remove it and return true. Can be called repeatedly to back up over multiple spaces. */ + bool deleteSpace(); + /** The symbol is written without quotes. Symbols are required to begin with a letter or underscore and contain only letters, underscores, and numbers or be a C++ symbol (e.g. "{", "(", "++", etc.) @@ -213,6 +224,8 @@ public: printed with a trailing space.*/ void writeSymbol(const std::string& string); + void writeSymbol(char s); + /** Convenient idiom for writing multiple symbols in a row, e.g. writeSymbols("name", "="); The empty symbols are not written. */ diff --git a/deps/g3dlite/include/G3D/ThreadSet.h b/deps/g3dlite/include/G3D/ThreadSet.h index 121f1415a..5b78e44d6 100644 --- a/deps/g3dlite/include/G3D/ThreadSet.h +++ b/deps/g3dlite/include/G3D/ThreadSet.h @@ -1,14 +1,16 @@ -#ifndef G3D_THREADSET_H -#define G3D_THREADSET_H +#ifndef G3D_ThreadSet_h +#define G3D_ThreadSet_h #include "G3D/platform.h" #include "G3D/Array.h" #include "G3D/ReferenceCount.h" -#include "G3D/GThread.h" #include "G3D/GMutex.h" +#include "G3D/SpawnBehavior.h" namespace G3D { +class GThread; + /** Manages a set of threads. All methods are threadsafe except for the iterator begin/end. @@ -18,8 +20,8 @@ public: /** Intended to allow future use with a template parameter.*/ typedef GThread Thread; - typedef ReferenceCountedPointer ThreadRef; - typedef ReferenceCountedPointer Ref; + typedef shared_ptr ThreadRef; + typedef shared_ptr Ref; typedef Array::Iterator Iterator; typedef Array::ConstIterator ConstIterator; @@ -41,13 +43,14 @@ public: /** Start all threads that are not currently started. - @param lastThreadBehavior If USE_CURRENT_THREAD, takes the last unstarted thread and executes it manually on - the current thread. This helps to take full advantage of the machine when - running a large number of jobs and avoids the overhead of a thread start for single-thread groups. - Note that this forces start() to block until - that thread is complete. + @param lastThreadBehavior If USE_CURRENT_THREAD, takes the + last unstarted thread and executes it manually on the current + thread. This helps to take full advantage of the machine when + running a large number of jobs and avoids the overhead of a + thread start for single-thread groups. Note that this forces + start() to block until that thread is complete. */ - void start(GThread::SpawnBehavior lastThreadBehavior = GThread::USE_NEW_THREAD) const; + void start(SpawnBehavior lastThreadBehavior = USE_NEW_THREAD) const; /** Terminate all threads that are currently started */ void terminate() const; diff --git a/deps/g3dlite/include/G3D/Triangle.h b/deps/g3dlite/include/G3D/Triangle.h index 590dbaad9..f9ece956c 100644 --- a/deps/g3dlite/include/G3D/Triangle.h +++ b/deps/g3dlite/include/G3D/Triangle.h @@ -1,19 +1,19 @@ /** - @file Triangle.h + \file G3D/Triangle.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2003-04-05 - @edited 2008-10-06 + \created 2003-04-05 + \edited 2011-06-20 - @cite Random point method by Greg Turk, Generating random points in triangles. In A. S. Glassner, ed., Graphics Gems, pp. 24-28. Academic Press, 1990 + \cite Random point method by Greg Turk, Generating random points in triangles. In A. S. Glassner, ed., Graphics Gems, pp. 24-28. Academic Press, 1990 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ -#ifndef G3D_TRIANGLE_H -#define G3D_TRIANGLE_H +#ifndef G3D_Triangle_h +#define G3D_Triangle_h #include "G3D/platform.h" #include "G3D/g3dmath.h" @@ -55,19 +55,19 @@ private: void init(const Vector3& v0, const Vector3& v1, const Vector3& v2); public: - + Triangle(class BinaryInput& b); - void serialize(class BinaryOutput& b); - void deserialize(class BinaryInput& b); + void serialize(class BinaryOutput& b); + void deserialize(class BinaryInput& b); Triangle(); - Triangle(const Vector3& v0, const Vector3& v1, const Vector3& v2); + Triangle(const Point3& v0, const Point3& v1, const Point3& v2); ~Triangle(); /** 0, 1, or 2 */ - inline const Vector3& vertex(int n) const { + inline const Point3& vertex(int n) const { debugAssert((n >= 0) && (n < 3)); return _vertex[n]; } @@ -91,15 +91,15 @@ public: const Vector3& normal() const; /** Barycenter */ - Vector3 center() const; + Point3 center() const; const Plane& plane() const; /** Returns a random point in the triangle. */ - Vector3 randomPoint() const; + Point3 randomPoint() const; inline void getRandomSurfacePoint - (Vector3& P, + (Point3& P, Vector3& N = Vector3::ignore()) const { P = randomPoint(); N = normal(); diff --git a/deps/g3dlite/include/G3D/UprightFrame.h b/deps/g3dlite/include/G3D/UprightFrame.h index ad5157cb1..696ab94df 100644 --- a/deps/g3dlite/include/G3D/UprightFrame.h +++ b/deps/g3dlite/include/G3D/UprightFrame.h @@ -1,25 +1,24 @@ /** - @file UprightFrame.h - - @author Morgan McGuire, http://graphics.cs.williams.edu + \file G3D/UprightFrame.h + \author Morgan McGuire, http://graphics.cs.williams.edu */ -#ifndef G3D_UPRIGHTFRAME_H -#define G3D_UPRIGHTFRAME_H +#ifndef G3D_UprightFrame_h +#define G3D_UprightFrame_h #include "G3D/platform.h" #include "G3D/Spline.h" -#include "G3D/Vector3.h" +#include "G3D/Any.h" #include "G3D/CoordinateFrame.h" namespace G3D { /** - Coordinate frame expressed in Euler angles. - Unlike a G3D::Quat, UprightFrame always keeps the reference frame from rolling about its own z axis. - Particularly useful for cameras. + \brief Coordinate frame expressed in Euler angles. + Unlike a G3D::Quat, UprightFrame always keeps the reference frame from rolling about its own z axis. + Particularly useful for cameras. - @sa G3D::CoordinateFrame, G3D::Matrix4, G3D::PhysicsFrame, G3D::UprightSpline, G3D::UprightSplineManipulator + \sa G3D::CoordinateFrame, G3D::Matrix4, G3D::PhysicsFrame, G3D::UprightSpline, G3D::UprightSplineManipulator */ class UprightFrame { public: @@ -32,18 +31,32 @@ public: /** In radians about the Y-axis */ float yaw; - inline UprightFrame(const Vector3& t = Vector3::zero(), float p = 0, float y = 0) + UprightFrame(const Vector3& t = Vector3::zero(), float p = 0, float y = 0) : translation(t), pitch(p), yaw(y) {} UprightFrame(const CoordinateFrame& cframe); + + /** Constructs an UprightFrame from an Any object. + + The Any format for UprightFrame is: + + pitch = ##, + translation = Vector3(), + yaw = ## + */ + explicit UprightFrame(const Any& any); - CoordinateFrame toCoordinateFrame() const; + Any toAny() const; + + UprightFrame& operator=(const Any& any); /** Supports implicit cast to CoordinateFrame */ - inline operator CoordinateFrame() const { + operator CoordinateFrame() const { return toCoordinateFrame(); } + CoordinateFrame toCoordinateFrame() const; + /** Required for use with spline */ UprightFrame operator+(const UprightFrame& other) const; @@ -61,8 +74,10 @@ public: void deserialize(class BinaryInput& b); }; -/** Shortest-path linear velocity spline for camera positions. Always keeps the camera from rolling. -@sa G3D::UprightSplineManipulator, G3D::UprightFrame +/** + \brief Shortest-path linear velocity spline for camera positions. Always keeps the camera from rolling. + + \sa G3D::UprightSplineManipulator, G3D::UprightFrame */ class UprightSpline : public Spline { protected: @@ -72,10 +87,29 @@ protected: } public: - + UprightSpline(); + + + /** Constructs an UprightSpline from an Any object. + + The Any format for UprightSpline is: + + controls = (UprightFrame, ...), + times = (##, ...), + cyclic = bool + + The controls and times arrays must have the same length. + */ + explicit UprightSpline(const Any& any); + + virtual Any toAny(const std::string& myName) const override; + + Any toAny() const; + + UprightSpline& operator=(const Any& any); + void serialize(class BinaryOutput& b) const; void deserialize(class BinaryInput& b); - }; } diff --git a/deps/g3dlite/include/G3D/Vector2.h b/deps/g3dlite/include/G3D/Vector2.h index dba735378..65cf7fa8f 100644 --- a/deps/g3dlite/include/G3D/Vector2.h +++ b/deps/g3dlite/include/G3D/Vector2.h @@ -1,19 +1,19 @@ /** - @file Vector2.h + \file G3D/Vector2.h 2D vector class - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2001-06-02 - @edited 2008-11-30 + \created 2001-06-02 + \edited 2011-11-30 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ -#ifndef G3D_VECTOR2_H -#define G3D_VECTOR2_H +#ifndef G3D_Vector2_h +#define G3D_Vector2_h #include @@ -22,6 +22,7 @@ #include "G3D/Table.h" #include "G3D/HashTrait.h" #include "G3D/Vector2int16.h" +#include "G3D/Vector2unorm16.h" #include "G3D/Random.h" namespace G3D { @@ -29,6 +30,7 @@ namespace G3D { class Vector2; class Vector3; class Vector4; +class Vector2int32; class Any; /** @@ -51,7 +53,7 @@ public: Vector2(const Any& any); /** Converts the Vector2 to an Any. */ - operator Any() const; + Any toAny() const; /** Creates the zero vector */ Vector2(); @@ -62,6 +64,12 @@ public: Vector2(double coordinate[2]); Vector2(const Vector2& other); Vector2(const Vector2int16& other); + Vector2(const Vector2unorm16& other); + + // explicit because of precision loss + explicit Vector2(const Vector2int32& other); + + Vector2& operator=(const Any& a); void serialize(class BinaryOutput& b) const; void deserialize(class BinaryInput& b); @@ -83,6 +91,11 @@ public: /** Returns true if this vector has finite length */ bool isFinite() const; + /** True if any field is NaN */ + bool isNaN() const { + return G3D::isNaN(x) || G3D::isNaN(y); + } + /** Returns true if this vector has length == 0 */ bool isZero() const; @@ -94,6 +107,11 @@ public: Vector2 operator-(const Vector2& v) const; Vector2 operator*(float s) const; + /** Raise each component of this vector to a power */ + Vector2 pow(float p) const { + return Vector2(powf(x, p), powf(y, p)); + } + /** Array (pointwise) multiplication */ Vector2 operator*(const Vector2& v) const; @@ -138,12 +156,19 @@ public: // vector operations - /** */ + /** Magnitude of the vector */ float length() const; - /** Returns a unit-length vector */ + /** + Returns a unit-length version of this vector. + Returns nan if length is almost zero. + */ Vector2 direction() const; + /** Returns Vector2::zero() is magnitude is almost zero, + otherwise returns unit-length vector. */ + Vector2 directionOrZero() const; + /** Potentially less accurate but faster than direction(). Only works if System::hasSSE is true. @@ -155,15 +180,35 @@ public: float squaredLength() const; float dot(const Vector2& s) const; - /** - Make this vector have unit length and return the old length. - If the vector length was less than tolerance, do not normalize. - */ - float unitize(float fTolerance = 1e-06); + /** Componentwise absolute value */ + Vector2 abs() const { + return Vector2(fabs(x), fabs(y)); + } + /** Component-wise minimum */ Vector2 min(const Vector2& v) const; + + /** Component-wise maximum */ Vector2 max(const Vector2& v) const; + /** Component-wise argmax(abs(), v.abs()). + + For the larger magnitude vector, simply use (a.squaredMagnitude() > b.squaredMagnitude) ? a : b. + \sa max + */ + Vector2 maxAbs(const Vector2& v) const { + return Vector2(::fabsf(x) > ::fabsf(v.x) ? x : v.x, ::fabsf(y) > ::fabsf(v.y) ? y : v.y); + } + + /** Component-wise argmin(abs(), v.abs()). + + For the smaller magnitude vector, simply use (a.squaredMagnitude() < b.squaredMagnitude) ? a : b. + \sa max + */ + Vector2 minAbs(const Vector2& v) const { + return Vector2(::fabsf(x) < ::fabsf(v.x) ? x : v.x, ::fabsf(y) < ::fabsf(v.y) ? y : v.y); + } + /** Uniformly distributed random vector on the unit sphere */ static Vector2 random(Random& r = Random::common()); @@ -263,7 +308,8 @@ inline Vector2::Vector2 (const Vector2& rkVector) { inline Vector2::Vector2 (const Vector2int16& v) : x(v.x), y(v.y) { } - +inline Vector2::Vector2 (const Vector2unorm16& v) : x(float(v.x)), y(float(v.y)) { +} inline float& Vector2::operator[] (int i) { return ((float*)this)[i]; @@ -385,6 +431,16 @@ inline Vector2 Vector2::direction () const { } } +inline Vector2 Vector2::directionOrZero() const { + float mag = length(); + if (mag < 0.0000001f) { + return Vector2::zero(); + } else if (mag < 1.00001f && mag > 0.99999f) { + return *this; + } else { + return *this * (1.0f / mag); + } +} inline float Vector2::dot (const Vector2& rkVector) const { @@ -424,15 +480,19 @@ inline bool Vector2::isFinite() const { inline bool Vector2::isZero() const { - return (x == 0.0f) && (y == 0.0f); + return G3D::fuzzyEq(fabsf(x) + fabsf(y), 0.0f); } inline bool Vector2::isUnit() const { - return squaredLength() == 1.0f; + return G3D::fuzzyEq(squaredLength(), 1.0f); } +typedef Vector2 Point2; +void serialize(const Vector2& v, class BinaryOutput& b); +void deserialize(Vector2& v, class BinaryInput& b); + } // namespace G3D template <> diff --git a/deps/g3dlite/include/G3D/Vector2int16.h b/deps/g3dlite/include/G3D/Vector2int16.h index ba72266d7..d24662b18 100644 --- a/deps/g3dlite/include/G3D/Vector2int16.h +++ b/deps/g3dlite/include/G3D/Vector2int16.h @@ -4,14 +4,14 @@ @maintainer Morgan McGuire, matrix@brown.edu @created 2003-08-09 - @edited 2004-01-03 + @edited 2010-01-03 - Copyright 2000-2006, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ -#ifndef VECTOR2INT16_H -#define VECTOR2INT16_H +#ifndef Vector2int16_h +#define Vector2int16_h #include "G3D/platform.h" #include "G3D/g3dmath.h" @@ -19,12 +19,13 @@ namespace G3D { +class Any; /** \class Vector2int16 - A Vector2 that packs its fields into uint16s. + A Vector2 that packs its fields into G3D::int16 s. */ G3D_BEGIN_PACKED_CLASS(2) -class Vector2int16 { +Vector2int16 { private: // Hidden operators bool operator<(const Vector2int16&) const; @@ -38,8 +39,14 @@ public: Vector2int16() : x(0), y(0) {} Vector2int16(G3D::int16 _x, G3D::int16 _y) : x(_x), y(_y){} - Vector2int16(const class Vector2& v); - Vector2int16(class BinaryInput& bi); + explicit Vector2int16(const class Vector2& v); + explicit Vector2int16(class BinaryInput& bi); + explicit Vector2int16(const class Any& a); + explicit Vector2int16(const class Vector2int32& v); + + Any toAny() const; + + Vector2int16& operator=(const Any& a); inline G3D::int16& operator[] (int i) { debugAssert(((unsigned int)i) <= 1); @@ -63,6 +70,10 @@ public: return Vector2int16(x * other.x, y * other.y); } + Vector2int16 operator-() const { + return Vector2int16(-x, -y); + } + inline Vector2int16 operator*(const int s) const { return Vector2int16(x * s, y * s); } @@ -73,6 +84,10 @@ public: return *this; } + bool isZero() const { + return (x == 0) && (y == 0); + } + /** Shifts both x and y */ inline Vector2int16 operator>>(const int s) const { return Vector2int16(x >> s, y >> s); @@ -118,6 +133,8 @@ public: } G3D_END_PACKED_CLASS(2) +typedef Vector2int16 Point2int16; + } template<> struct HashTrait { diff --git a/deps/g3dlite/include/G3D/Vector2int32.h b/deps/g3dlite/include/G3D/Vector2int32.h new file mode 100644 index 000000000..fe161604c --- /dev/null +++ b/deps/g3dlite/include/G3D/Vector2int32.h @@ -0,0 +1,134 @@ +/** + @file G3D/Vector2int32.h + + @maintainer Morgan McGuire, matrix@brown.edu + + @created 2003-08-09 + @edited 2010-09-03 + + Copyright 2000-2012, Morgan McGuire. + All rights reserved. + */ + +#ifndef G3D_Vector2int32_h +#define G3D_Vector2int32_h + +#include "G3D/platform.h" +#include "G3D/g3dmath.h" +#include "G3D/HashTrait.h" + +namespace G3D { + +/** + \class Vector2int32 + A Vector2 that packs its fields into int32s. + */ +G3D_BEGIN_PACKED_CLASS(2) +Vector2int32 { +private: + // Hidden operators + bool operator<(const Vector2int32&) const; + bool operator>(const Vector2int32&) const; + bool operator<=(const Vector2int32&) const; + bool operator>=(const Vector2int32&) const; + +public: + G3D::int32 x; + G3D::int32 y; + + Vector2int32() : x(0), y(0) {} + Vector2int32(G3D::int32 _x, G3D::int32 _y) : x(_x), y(_y){} + explicit Vector2int32(const class Vector2& v); + explicit Vector2int32(class BinaryInput& bi); + Vector2int32(const class Vector2int16& v); + + inline G3D::int32& operator[] (int i) { + debugAssert(((unsigned int)i) <= 1); + return ((G3D::int32*)this)[i]; + } + + inline const G3D::int32& operator[] (int i) const { + debugAssert(((unsigned int)i) <= 1); + return ((G3D::int32*)this)[i]; + } + + inline Vector2int32 operator+(const Vector2int32& other) const { + return Vector2int32(x + other.x, y + other.y); + } + + inline Vector2int32 operator-(const Vector2int32& other) const { + return Vector2int32(x - other.x, y - other.y); + } + + inline Vector2int32 operator-() const { + return Vector2int32(-x, -y); + } + + inline Vector2int32 operator*(const Vector2int32& other) const { + return Vector2int32(x * other.x, y * other.y); + } + + inline Vector2int32 operator*(const int s) const { + return Vector2int32(x * s, y * s); + } + + inline Vector2int32& operator+=(const Vector2int32& other) { + x += other.x; + y += other.y; + return *this; + } + + /** Shifts both x and y */ + inline Vector2int32 operator>>(const int s) const { + return Vector2int32(x >> s, y >> s); + } + + /** Shifts both x and y */ + inline Vector2int32 operator<<(const int s) const { + return Vector2int32(x << s, y << s); + } + + inline Vector2int32& operator-=(const Vector2int32& other) { + x -= other.x; + y -= other.y; + return *this; + } + + inline Vector2int32& operator*=(const Vector2int32& other) { + x *= other.x; + y *= other.y; + return *this; + } + + Vector2int32 clamp(const Vector2int32& lo, const Vector2int32& hi); + + inline bool operator==(const Vector2int32& other) const { + return (x == other.x) && (y == other.y); + } + + inline bool operator!= (const Vector2int32& other) const { + return !(*this == other); + } + + Vector2int32 max(const Vector2int32& v) const { + return Vector2int32(iMax(x, v.x), iMax(y, v.y)); + } + + Vector2int32 min(const Vector2int32& v) const { + return Vector2int32(iMin(x, v.x), iMin(y, v.y)); + } + + void serialize(class BinaryOutput& bo) const; + void deserialize(class BinaryInput& bi); +} +G3D_END_PACKED_CLASS(2) + +typedef Vector2int32 Point2int32; + +} // namespace G3D + +template<> struct HashTrait { + static size_t hashCode(const G3D::Vector2int32& key) { return static_cast(key.x ^ ((int)key.y << 1)); } +}; + +#endif diff --git a/deps/g3dlite/include/G3D/Vector2unorm16.h b/deps/g3dlite/include/G3D/Vector2unorm16.h new file mode 100644 index 000000000..06902612a --- /dev/null +++ b/deps/g3dlite/include/G3D/Vector2unorm16.h @@ -0,0 +1,91 @@ +/** + \file G3D/Vector2unorm16.h + + \maintainer Morgan McGuire, morgan@cs.williams.edu + + \created 2003-03-13 + \edited 2012-03-13 + + Copyright 2000-2012, Morgan McGuire. + All rights reserved. + */ + +#ifndef Vector2unorm16_h +#define Vector2unorm16_h + +#include "G3D/platform.h" +#include "G3D/g3dmath.h" +#include "G3D/HashTrait.h" +#include "G3D/unorm16.h" + +namespace G3D { + +class Any; +/** + \class Vector2unorm16 + + A Vector2 that packs its fields into G3D::unorm16%s. This is mostly + useful for texture coordinates that are on the range [0, 1]. + + \sa Vector2int16 + */ +G3D_BEGIN_PACKED_CLASS(2) +Vector2unorm16 { +private: + // Hidden operators + bool operator<(const Vector2unorm16&) const; + bool operator>(const Vector2unorm16&) const; + bool operator<=(const Vector2unorm16&) const; + bool operator>=(const Vector2unorm16&) const; + +public: + G3D::unorm16 x; + G3D::unorm16 y; + + Vector2unorm16() {} + Vector2unorm16(G3D::unorm16 _x, G3D::unorm16 _y) : x(_x), y(_y){} + Vector2unorm16(float _x, float _y) : x(_x), y(_y){} + explicit Vector2unorm16(const class Vector2& v); + explicit Vector2unorm16(class BinaryInput& bi); + explicit Vector2unorm16(const class Any& a); + + Any toAny() const; + + Vector2unorm16& operator=(const Any& a); + + inline G3D::unorm16& operator[] (int i) { + debugAssert(((unsigned int)i) <= 1); + return ((G3D::unorm16*)this)[i]; + } + + inline const G3D::unorm16& operator[] (int i) const { + debugAssert(((unsigned int)i) <= 1); + return ((G3D::unorm16*)this)[i]; + } + + inline bool operator== (const Vector2unorm16& rkVector) const { + return ((int32*)this)[0] == ((int32*)&rkVector)[0]; + } + + inline bool operator!= (const Vector2unorm16& rkVector) const { + return ((int32*)this)[0] != ((int32*)&rkVector)[0]; + } + + void serialize(class BinaryOutput& bo) const; + void deserialize(class BinaryInput& bi); + size_t hashCode() const { + return static_cast(x.bits() + ((int)y.bits() << 16)); + } + +} +G3D_END_PACKED_CLASS(2) + +typedef Vector2unorm16 Point2unorm16; + +} + +template<> struct HashTrait { + static size_t hashCode(const G3D::Vector2unorm16& key) { return key.hashCode(); } +}; + +#endif diff --git a/deps/g3dlite/include/G3D/Vector3.h b/deps/g3dlite/include/G3D/Vector3.h index 771448d63..1c42513b4 100644 --- a/deps/g3dlite/include/G3D/Vector3.h +++ b/deps/g3dlite/include/G3D/Vector3.h @@ -1,13 +1,14 @@ /** - @file Vector3.h - + \file Vector3.h + 3D vector class + + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \created 2001-06-02 + \edited 2010-12-25 - @created 2001-06-02 - @edited 2009-11-01 - Copyright 2000-2009, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ @@ -36,7 +37,7 @@ class Any; /** Swizzles Vector classes have swizzle operators, e.g. v.xy(), that - allow selection of arbitrary sub-fields. These cannot be used as write + allow selection of arbitrary sub-fields. These cannot be used as write masks. Examples
    @@ -72,29 +73,37 @@ public:
         /** Initializes to zero */
         Vector3();
     
    -    /** \param any Must either Vector3(#, #, #) or Vector3 {x = #, y = #, z = #}*/
    -    Vector3(const Any& any);
    +    /** 
    +        \param any  Must either Vector3(#, #, #) or Vector3 {x = #, y = #, z = #}.
    +        Because Point3 is a typedef for Vector3 in the current implementation,
    +        this constructor accepts Point3(#, #, #), etc. as well.
    +        
    +     */
    +    explicit Vector3(const Any& any);
    +    
    +    /** Converts the Vector3 to an Any, using the specified \a name instead of "Vector3" */
    +    Any toAny(const std::string& name) const;
     
         /** Converts the Vector3 to an Any. */
    -    operator Any() const;
    +    Any toAny() const;
     
         /** Divides by 127 */
         Vector3(const Vector4int8&);
    +    Vector3(const class Vector2& v, float z);
         Vector3(const class Vector3int32& v);
         explicit Vector3(class BinaryInput& b);
         Vector3(float _x, float _y, float _z);
    -    explicit Vector3(const class Vector2& v, float _z);
         explicit Vector3(float coordinate[3]);
         explicit Vector3(double coordinate[3]);
         Vector3(const class Vector3int16& v);
    -	explicit Vector3(class TextInput& t);
    +    explicit Vector3(class TextInput& t);
         explicit Vector3(const class Color3& c);
     
    -	/** Format is three float32's */
    +     /** Format is three float32's */
         void serialize(class BinaryOutput& b) const;
         void deserialize(class BinaryInput& b);
     
    -	/** Format is "(%f, %f, %f)" */
    +    /** Format is "(%f, %f, %f)" */
         void serialize(class TextOutput& t) const;
         void deserialize(class TextInput& t);
     
    @@ -106,6 +115,10 @@ public:
         const float& __fastcall operator[] (int i) const;
         float& operator[] (int i);
     
    +    bool nonZero() const {
    +        return (x != 0) || (y != 0) || (z != 0);    
    +    }
    +
         enum Axis {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, DETECT_AXIS=-1};
     
         /**
    @@ -115,12 +128,8 @@ public:
         Axis primaryAxis() const;
     
         // assignment and comparison
    -    Vector3& __fastcall operator= (const Vector3& rkVector);
    -    /* requried as of C++ 11 */
    -    #if __cplusplus >= 201103L
    -    Vector3(const Vector3&) = default;
    -    Vector3(Vector3&&) = default;
    -    #endif
    +    Vector3& operator=(const Vector3& rkVector) = default;
    +    Vector3& operator=(const Any& a);
         bool operator== (const Vector3& rkVector) const;
         bool operator!= (const Vector3& rkVector) const;
         size_t hashCode() const;
    @@ -130,12 +139,19 @@ public:
         /** Returns true if this vector has finite length. */
         bool isFinite() const;
     
    +    /** True if any field is nan */
    +    bool isNaN() const;
    +
         /** Returns true if this vector has length ~= 0 */
         bool isZero() const;
     
         /** Returns true if this vector has length ~= 1 */
         bool isUnit() const;
     
    +    /** Returns a vector that is \a this translated towards \a goal with a maximum translation of \a maxTranslation. */
    +    Vector3 movedTowards(const Vector3& goal, float maxTranslation) const;
    +    void moveTowards(const Vector3& goal, float maxTranslation);
    +    
         // arithmetic operations
         Vector3 __fastcall operator+ (const Vector3& v) const;
         Vector3 __fastcall operator- (const Vector3& v) const;
    @@ -158,12 +174,18 @@ public:
         Vector3& __fastcall operator/= (const Vector3& v);
     
         /** Same as magnitude */
    -	float length() const;
    +    float length() const;
     
         float magnitude() const;
     
    +    /** Raise each component of this vector to a power */
    +    Vector3 pow(float p) const {
    +        return Vector3(powf(x, p), powf(y, p), powf(z, p));
    +    }
    +    
         /**
    -     The result is a nan vector if the length is almost zero.
    +     Returns a unit-length version of this vector.
    +     Returns nan if length is almost zero.
          */
         Vector3 direction() const;
     
    @@ -184,7 +206,7 @@ public:
     
          
            V'    N      V
    -
    +                 
              r   ^   -,
               \  |  /
                 \|/
    @@ -196,17 +218,17 @@ public:
     
         /**
           See also G3D::Ray::reflect.
    -      The length is 1.
    +      The length is 1. 
          
            V'    N       V
    -
    +                 
              r   ^    /
               \  |  /
                 \|'-
          
    */ Vector3 reflectionDirection(const Vector3& normal) const; - + /** Returns Vector3::zero() if the length is nearly zero, otherwise @@ -228,7 +250,7 @@ public: where iExit is the index of refraction for the previous material and iEnter is the index of refraction for the new material. Like Vector3::reflectionDirection, - the result has length 1 and is + the result has length 1 and is pointed away from the intersection. Returns Vector3::zero() in the case of total internal refraction. @@ -242,7 +264,7 @@ public: See also G3D::Ray::refract.
                   N      V
    -
    +                  
                   ^    /
                   |  /
                   |'-
    @@ -270,11 +292,9 @@ public:
         float squaredLength() const;
     
         float squaredMagnitude () const;
    -
    +    
         float __fastcall dot(const Vector3& rkVector) const;
    -
    -    float unitize(float tolerance = 1e-06);
    -
    +    
         /** Cross product.  Note that two cross products in a row
             can be computed more cheaply: v1 x (v2 x v3) = (v1 dot v3) v2  - (v1 dot v2) v3.
           */
    @@ -320,18 +340,29 @@ public:
                 G3D::clamp(z, low, high));
         }
     
    +
    +    inline Vector3 floor() const {
    +        return G3D::Vector3(::floor(x), ::floor(y), ::floor(z));
    +    }
    +
    +
    +    inline Vector3 round() const {
    +        return Vector3(G3D::round(x), G3D::round(y), G3D::round(z));
    +    }
    +
    +
         /**
          Linear interpolation
          */
         inline Vector3 lerp(const Vector3& v, float alpha) const {
    -        return (*this) + (v - *this) * alpha;
    +        return (*this) + (v - *this) * alpha; 
         }
     
         /** Gram-Schmidt orthonormalization. */
         static void orthonormalize (Vector3 akVector[3]);
     
    -    /** \brief Random unit vector, uniformly distributed on the sphere.
    -
    +    /** \brief Random unit vector, uniformly distributed on the sphere. 
    +    
            Distribution rendered by G3D::DirectionHistogram:
            \image html vector3-random.png
           */
    @@ -339,8 +370,8 @@ public:
     
         /** \brief Random unit vector, distributed according to \f$\max(\cos \theta,0)\f$.
     
    -        That is, so that the probability of \f$\vec{V}\f$ is proportional
    -        to \f$\max(\vec{v} \cdot \vec{n}, 0)\f$.  Useful in photon mapping for
    +        That is, so that the probability of \f$\vec{V}\f$ is proportional 
    +        to \f$\max(\vec{v} \cdot \vec{n}, 0)\f$.  Useful in photon mapping for 
             Lambertian scattering.
     
             Distribution rendered by G3D::DirectionHistogram:
    @@ -352,6 +383,8 @@ public:
         */
         static Vector3 cosHemiRandom(const Vector3& n, Random& r = Random::common());
     
    +    static Vector3 cosSphereRandom(const Vector3& n, Random& r = Random::common());
    +
         /** \brief Random unit vector, distributed according to \f$\max(\cos^k \theta,0)\f$.
     
             That is, so that the probability of \f$\vec{V}\f$ is
    @@ -375,14 +408,6 @@ public:
          */
         static Vector3 hemiRandom(const Vector3& normal, Random& r = Random::common());
     
    -    /** Input W must be initialize to a nonzero vector, output is {U,V,W}
    -        an orthonormal basis.  A hint is provided about whether or not W
    -        is already unit length.
    -        @deprecated Use getTangents
    -    */
    -    static void generateOrthonormalBasis (Vector3& rkU, Vector3& rkV,
    -                                          Vector3& rkW, bool bUnitLengthW = true);
    -
         inline float sum() const {
             return x + y + z;
         }
    @@ -399,7 +424,7 @@ public:
         static const Vector3& unitZ();
         static const Vector3& inf();
         static const Vector3& nan();
    -
    +    
         /** Smallest (most negative) representable vector */
         static const Vector3& minFinite();
     
    @@ -410,16 +435,16 @@ public:
         /** Creates two orthonormal tangent vectors X and Y such that
             if Z = this, X x Y = Z.*/
         inline void getTangents(Vector3& X, Vector3& Y) const {
    -        debugAssertM(G3D::fuzzyEq(length(), 1.0f),
    +        debugAssertM(G3D::fuzzyEq(length(), 1.0f), 
                          "makeAxes requires Z to have unit length");
    -
    +        
             // Choose another vector not perpendicular
             X = (abs(x) < 0.9f) ? Vector3::unitX() : Vector3::unitY();
    -
    +        
             // Remove the part that is parallel to Z
             X -= *this * this->dot(X);
             X /= X.length();
    -
    +    
             Y = this->cross(X);
         }
     
    @@ -554,6 +579,8 @@ public:
         static Vector3& ignore();
     };
     
    +
    +
     inline G3D::Vector3 operator*(float s, const G3D::Vector3& v) {
         return v * s;
     }
    @@ -600,14 +627,6 @@ inline float& Vector3::operator[] (int i) {
     }
     
     
    -//----------------------------------------------------------------------------
    -inline Vector3& Vector3::operator= (const Vector3& rkVector) {
    -    x = rkVector.x;
    -    y = rkVector.y;
    -    z = rkVector.z;
    -    return *this;
    -}
    -
     //----------------------------------------------------------------------------
     
     inline bool Vector3::fuzzyEq(const Vector3& other) const {
    @@ -755,8 +774,7 @@ inline Vector3 Vector3::cross (const Vector3& rkVector) const {
     inline Vector3 Vector3::unitCross (const Vector3& rkVector) const {
         Vector3 kCross(y*rkVector.z - z*rkVector.y, z*rkVector.x - x*rkVector.z,
                        x*rkVector.y - y*rkVector.x);
    -    kCross.unitize();
    -    return kCross;
    +    return kCross.direction();
     }
     
     //----------------------------------------------------------------------------
    @@ -771,7 +789,7 @@ inline Vector3 Vector3::max(const Vector3 &v) const {
     
     //----------------------------------------------------------------------------
     inline bool Vector3::isZero() const {
    -    return G3D::fuzzyEq(squaredMagnitude(), 0.0f);
    +    return G3D::fuzzyEq(fabsf(x) + fabsf(y) + fabsf(z), 0.0f);
     }
     
     //----------------------------------------------------------------------------
    @@ -780,6 +798,22 @@ inline bool Vector3::isUnit() const {
         return G3D::fuzzyEq(squaredMagnitude(), 1.0f);
     }
     
    +/** 
    + Points are technically distinct mathematical entities from vectors.
    + Actually distinguishing them at the class level tends to add lots of
    + boilerplate (e.g., (P - Point3::zero()).direction()
    + vs. P.direction()), so many programmers prefer use a single class,
    + as GLSL does.  
    +
    + G3D provides this typedef as a way of documenting arguments that are
    + locations in space and not directions.  Beware that points and
    + vectors are interchangable from the compiler's point of view, and
    + that the programmer must track which is really which. */
    +typedef Vector3 Point3;
    +
    +void serialize(const Vector3& v, class BinaryOutput& b);
    +void deserialize(Vector3& v, class BinaryInput& b);
    +
     } // namespace G3D
     
     
    diff --git a/deps/g3dlite/include/G3D/Vector3int16.h b/deps/g3dlite/include/G3D/Vector3int16.h
    index 6043aea9f..2cf4e5f13 100644
    --- a/deps/g3dlite/include/G3D/Vector3int16.h
    +++ b/deps/g3dlite/include/G3D/Vector3int16.h
    @@ -1,16 +1,17 @@
     /**
    -  @file Vector3int16.h
    +  \file G3D/Vector3int16.h
       
    -  @maintainer Morgan McGuire, matrix@brown.edu
    +  \maintainer Morgan McGuire, matrix@brown.edu
     
    -  @created 2003-04-07
    -  @edited  2003-06-24
    -  Copyright 2000-2004, Morgan McGuire.
    +  \created 2003-04-07
    +  \edited  2011-06-24
    +
    +  Copyright 2000-2012, Morgan McGuire.
       All rights reserved.
      */
     
    -#ifndef VECTOR3INT16_H
    -#define VECTOR3INT16_H
    +#ifndef G3D_Vector3int16_h
    +#define G3D_Vector3int16_h
     
     #include "G3D/platform.h"
     #include "G3D/g3dmath.h"
    @@ -19,6 +20,7 @@
     #ifdef _MSC_VER
     // Turn off "conditional expression is constant" warning; MSVC generates this
     // for debug assertions in inlined methods.
    +#pragma warning (push)
     #pragma warning (disable : 4127)
     #endif
     
    @@ -30,7 +32,7 @@ namespace G3D {
      A Vector3 that packs its fields into uint16s.
      */
     G3D_BEGIN_PACKED_CLASS(2)
    -class Vector3int16 {
    +Vector3int16 {
     private:
         // Hidden operators
         bool operator<(const Vector3int16&) const;
    @@ -45,8 +47,8 @@ public:
     
         Vector3int16() : x(0), y(0), z(0) {}
         Vector3int16(G3D::int16 _x, G3D::int16 _y, G3D::int16 _z) : x(_x), y(_y), z(_z) {}
    -    Vector3int16(const class Vector3& v);
    -    Vector3int16(class BinaryInput& bi);
    +    explicit Vector3int16(const class Vector3& v);
    +    explicit Vector3int16(class BinaryInput& bi);
     
         void serialize(class BinaryOutput& bo) const;
         void deserialize(class BinaryInput& bi);
    @@ -98,6 +100,9 @@ public:
             return *this;
         }
     
    +    static Vector3int16 floor(const Vector3& v);
    +    static Vector3int16 ceil(const Vector3& v);
    +
         inline bool operator== (const Vector3int16& rkVector) const {
             return ( x == rkVector.x && y == rkVector.y && z == rkVector.z );
         }
    @@ -106,6 +111,10 @@ public:
             return ( x != rkVector.x || y != rkVector.y || z != rkVector.z );
         }
     
    +    int dot(const Vector3int16& v) const {
    +        return x * v.x + y * v.y + z * v.z;
    +    }
    +
         Vector3int16 max(const Vector3int16& v) const {
             return Vector3int16(std::max(x, v.x), std::max(y, v.y), std::max(z, v.z));
         }
    @@ -115,13 +124,49 @@ public:
         }
     
         std::string toString() const;
    +
    +
    +    Vector3int16 operator-() const {
    +        return Vector3int16(-x, -y, -z);
    +    }
    +
    +    Vector3int16 operator<<(int i) const {
    +        return Vector3int16(x << i, y << i, z << i);
    +    }
    +
    +    Vector3int16 operator>>(int i) const {
    +        return Vector3int16(x >> i, y >> i, z >> i);
    +    }
    +
    +    Vector3int16 operator>>(const Vector3int16& v) const {
    +        return Vector3int16(x >> v.x, y >> v.y, z >> v.z);
    +    }
    +
    +    Vector3int16 operator<<(const Vector3int16& v) const {
    +        return Vector3int16(x << v.x, y << v.y, z << v.z);
    +    }
    +
    +    Vector3int16 operator&(int16 i) const {
    +        return Vector3int16(x & i, y & i, z & i);
    +    }
    +
    +    Vector3int16 operator&(const Vector3int16& v) const {
    +        return Vector3int16(x & v.x, y & v.y, z & v.z);
    +    }
     }
     G3D_END_PACKED_CLASS(2)
     
    -}
    +typedef Vector3int16 Point3int16;
    +
    +} // namespace G3D
     
     template <> struct HashTrait {
         static size_t hashCode(const G3D::Vector3int16& key) { return static_cast(key.x + ((int)key.y << 5) + ((int)key.z << 10)); }
     };
     
    +
    +#ifdef G3D_WINDOWS
    +#pragma warning( pop )
    +#endif
    +
     #endif
    diff --git a/deps/g3dlite/include/G3D/Vector3int32.h b/deps/g3dlite/include/G3D/Vector3int32.h
    index c1a6b21e1..c68227866 100644
    --- a/deps/g3dlite/include/G3D/Vector3int32.h
    +++ b/deps/g3dlite/include/G3D/Vector3int32.h
    @@ -1,29 +1,32 @@
     /**
    -  @file Vector3int32.h
    +  @file G3D/Vector3int32.h
       
       @maintainer Morgan McGuire, matrix@brown.edu
     
       @created 2008-07-01
    -  @edited  2008-07-01
    -  Copyright 2000-2009, Morgan McGuire.
    +  @edited  2011-01-01
    +  Copyright 2000-2012, Morgan McGuire.
       All rights reserved.
      */
     
    -#ifndef VECTOR3INT32_H
    -#define VECTOR3INT32_H
    +#ifndef G3D_Vector3int32_h
    +#define G3D_Vector3int32_h
     
     #include "G3D/platform.h"
     #include "G3D/g3dmath.h"
     #include "G3D/HashTrait.h"
    +#include "G3D/Crypto.h"
     
     namespace G3D {
     
    +    class Any;
    +
     /**
      \ Vector3int32
      A Vector3 that packs its fields into uint32s.
      */
     G3D_BEGIN_PACKED_CLASS(4)
    -class Vector3int32 {
    +Vector3int32 {
     private:
         // Hidden operators
         bool operator<(const Vector3int32&) const;
    @@ -38,9 +41,21 @@ public:
     
         Vector3int32() : x(0), y(0), z(0) {}
         Vector3int32(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {}
    +    Vector3int32(const class Vector2int32& v, int _z);
    +    Vector3int32(const class Vector2int16& v, int _z);
         Vector3int32(const class Vector3int16& v);
    -    Vector3int32(const class Vector3& v);
    -    Vector3int32(class BinaryInput& bi);
    +    Vector3int32(const Any& any);
    +    Any toAny() const;
    +
    +    /** Rounds to the nearest int */
    +    explicit Vector3int32(const class Vector3& v);
    +    explicit Vector3int32(class BinaryInput& bi);
    +
    +    static Vector3int32 truncate(const class Vector3& v);
    +
    +    bool nonZero() const {
    +        return (x != 0) || (y != 0) || (z != 0);
    +    }
     
         void serialize(class BinaryOutput& bo) const;
         void deserialize(class BinaryInput& bi);
    @@ -71,32 +86,42 @@ public:
             return Vector3int32(x * s, y * s, z * s);
         }
     
    -    inline Vector3int32& operator+=(const Vector3int32& other) {
    +    /** Integer division */
    +    inline Vector3int32 operator/(const Vector3int32& other) const {
    +        return Vector3int32(x / other.x, y / other.y, z / other.z);
    +    }
    +
    +    /** Integer division */
    +    inline Vector3int32 operator/(const int s) const {
    +        return Vector3int32(x / s, y / s, z / s);
    +    }
    +
    +    Vector3int32& operator+=(const Vector3int32& other) {
             x += other.x;
             y += other.y;
             z += other.z;
             return *this;
         }
     
    -    inline Vector3int32& operator-=(const Vector3int32& other) {
    +    Vector3int32& operator-=(const Vector3int32& other) {
             x -= other.x;
             y -= other.y;
             z -= other.z;
             return *this;
         }
     
    -    inline Vector3int32& operator*=(const Vector3int32& other) {
    +    Vector3int32& operator*=(const Vector3int32& other) {
             x *= other.x;
             y *= other.y;
             z *= other.z;
             return *this;
         }
     
    -    inline bool operator== (const Vector3int32& rkVector) const {
    +    bool operator== (const Vector3int32& rkVector) const {
             return ( x == rkVector.x && y == rkVector.y && z == rkVector.z );
         }
     
    -    inline bool operator!= (const Vector3int32& rkVector) const {
    +    bool operator!= (const Vector3int32& rkVector) const {
             return ( x != rkVector.x || y != rkVector.y || z != rkVector.z );
         }
     
    @@ -108,20 +133,64 @@ public:
             return Vector3int32(iMin(x, v.x), iMin(y, v.y), iMin(z, v.z));
         }
     
    +    Vector3int32 operator-() const {
    +        return Vector3int32(-x, -y, -z);
    +    }
    +
         std::string toString() const;
    +
    +    Vector3int32 operator<<(int i) const {
    +        return Vector3int32(x << i, y << i, z << i);
    +    }
    +
    +    Vector3int32 operator>>(int i) const {
    +        return Vector3int32(x >> i, y >> i, z >> i);
    +    }
    +
    +    Vector3int32 operator>>(const Vector3int32& v) const {
    +        return Vector3int32(x >> v.x, y >> v.y, z >> v.z);
    +    }
    +
    +    Vector3int32 operator<<(const Vector3int32& v) const {
    +        return Vector3int32(x << v.x, y << v.y, z << v.z);
    +    }
    +
    +    Vector3int32 operator&(int16 i) const {
    +        return Vector3int32(x & i, y & i, z & i);
    +    }
    +
    +    // 2-char swizzles
    +
    +    Vector2int32 xx() const;
    +    Vector2int32 yx() const;
    +    Vector2int32 zx() const;
    +    Vector2int32 xy() const;
    +    Vector2int32 yy() const;
    +    Vector2int32 zy() const;
    +    Vector2int32 xz() const;
    +    Vector2int32 yz() const;
    +    Vector2int32 zz() const;
     }
     G3D_END_PACKED_CLASS(4)
     
    -}
    +typedef Vector3int32 Point3int32;
    +
    +Vector3int32 iFloor(const Vector3&);
    +
    +} // namespace G3D
     
     template <> struct HashTrait {
         static size_t hashCode(const G3D::Vector3int32& key) {
    +        return G3D::superFastHash(&key, sizeof(key));
    +        //return G3D::Crypto::crc32(&key, sizeof(key));
    +        /*
             // Mask for the top bit of a uint32
             const G3D::uint32 top = (1UL << 31);
             // Mask for the bottom 10 bits of a uint32
             const G3D::uint32 bot = 0x000003FF;
             return static_cast(((key.x & top) | ((key.y & top) >> 1) | ((key.z & top) >> 2)) | 
                                        (((key.x & bot) << 19) ^ ((key.y & bot) << 10) ^ (key.z & bot)));
    +        */
         }
     };
     
    diff --git a/deps/g3dlite/include/G3D/Vector4.h b/deps/g3dlite/include/G3D/Vector4.h
    index 5e511451f..24521efc9 100644
    --- a/deps/g3dlite/include/G3D/Vector4.h
    +++ b/deps/g3dlite/include/G3D/Vector4.h
    @@ -47,10 +47,11 @@ private:
     public:
     
         /** \param any Must either Vector4(#, #, #, #) or Vector3 {x = #, y = #, z = #, w =#}*/
    -    Vector4(const Any& any);
    +    explicit Vector4(const Any& any);
         
    +    Vector4& operator=(const Any& a);
         /** Converts the Vector4 to an Any. */
    -    operator Any() const;
    +    Any toAny() const;
     
         // construction
         Vector4();
    @@ -698,7 +699,11 @@ inline float Vector4::squaredLength() const {
         return x * x + y * y + z * z + w * w;
     }
     
    -}
    +
    +void serialize(const Vector4& v, class BinaryOutput& b);
    +void deserialize(Vector4& v, class BinaryInput& b);
    +
    +} // G3D
     
     template <> struct HashTrait {
         static size_t hashCode(const G3D::Vector4& key) { return key.hashCode(); }
    diff --git a/deps/g3dlite/include/G3D/Vector4int8.h b/deps/g3dlite/include/G3D/Vector4int8.h
    index 544b693e8..14fe7fe0c 100644
    --- a/deps/g3dlite/include/G3D/Vector4int8.h
    +++ b/deps/g3dlite/include/G3D/Vector4int8.h
    @@ -51,14 +51,14 @@ public:
         inline Vector4int8() : x(0), y(0), z(0), w(0) {}
         
         /** Multiplies the source by 127 and clamps to (-128, 127) when converting */
    -    Vector4int8(const Vector4& source);
    +    explicit Vector4int8(const Vector4& source);
     
         /** Multiplies the source by 127 and clamps to (-128, 127) when converting */
    -    Vector4int8(const Vector3& source, int8 w);
    +    explicit Vector4int8(const Vector3& source, int8 w);
     
         inline Vector4int8(int8 x, int8 y, int8 z, int8 w) : x(x), y(y), z(z), w(w) {}
     
    -    Vector4int8(class BinaryInput& b);
    +    explicit Vector4int8(class BinaryInput& b);
         void serialize(class BinaryOutput& b) const;
         void deserialize(class BinaryInput& b);
     
    diff --git a/deps/g3dlite/include/G3D/WeakCache.h b/deps/g3dlite/include/G3D/WeakCache.h
    index f9fdc4bbd..b2f43818b 100644
    --- a/deps/g3dlite/include/G3D/WeakCache.h
    +++ b/deps/g3dlite/include/G3D/WeakCache.h
    @@ -1,16 +1,16 @@
     /** 
    -  @file WeakCache.h
    +  \file G3D/WeakCache.h
      
    -  @maintainer Morgan McGuire, graphics3d.com
    +  \maintainer Morgan McGuire, graphics3d.com
      
    -  @created 2007-05-16
    -  @edited  2007-05-16
    +  \created 2007-05-16
    +  \edited  2012-01-02
     
    -  Copyright 2000-2007, Morgan McGuire.
    +  Copyright 2000-2012, Morgan McGuire.
       All rights reserved.
      */
    -#ifndef G3D_WEAKCACHE_H
    -#define G3D_WEAKCACHE_H
    +#ifndef G3D_WeakCache_h
    +#define G3D_WeakCache_h
     
     #include "G3D/ReferenceCount.h"
     #include "G3D/Table.h"
    @@ -31,10 +31,10 @@ namespace G3D {
     
        Example:
        
    -      WeakCache textureCache;
    +      WeakCache> textureCache;
     
    -      TextureRef loadTexture(std::string s) {
    -          TextureRef t = textureCache[s];
    +      shared_ptr loadTexture(std::string s) {
    +          shared_ptr t = textureCache[s];
     
               if (t.isNull()) {
                   t = Texture::fromFile(s);
    @@ -49,7 +49,7 @@ namespace G3D {
      */
     template
     class WeakCache {
    -    typedef WeakReferenceCountedPointer ValueWeakRef;
    +    typedef weak_ptr ValueWeakRef;
     
     private:
     
    @@ -62,17 +62,34 @@ public:
         ValueRef operator[](const Key& k) {
             if (table.containsKey(k)) {
                 ValueWeakRef w = table[k];
    -            ValueRef s = w.createStrongPtr();
    -            if (s.isNull()) {
    +            ValueRef s = w.lock();
    +            if (! s) {
                     // This object has been collected; clean out its key
                     table.remove(k);
                 }
                 return s;
             } else {
    -            return NULL;
    +            return ValueRef();
             }
         }
     
    +
    +
    +    void getValues(Array& values) {
    +        Array keys;
    +        table.getKeys(keys);
    +        for (int i = 0; i < keys.size(); ++i) {
    +            ValueRef value = (*this)[keys[i]];
    +            if(notNull(value)) {
    +                values.append(value);
    +            }
    +        }
    +    }
    +
    +    void clear() {
    +        table.clear();
    +    }
    +
         void set(const Key& k, ValueRef v) {
             table.set(k, v);
         }
    @@ -85,38 +102,6 @@ public:
         }
     };
     
    -#if 0 // To turn off all WeakCaching
    -template
    -class WeakCache {
    -private:
    -
    -    Table table;
    -
    -public:
    -    /**
    -       Returns NULL if the object is not in the cache
    -    */
    -    ValueRef operator[](const Key& k) {
    -        if (table.containsKey(k)) {
    -            return table[k];
    -        } else {
    -            return NULL;
    -        }
    -    }
    -
    -    void set(const Key& k, ValueRef v) {
    -        table.set(k, v);
    -    }
    -
    -    /** Removes k from the cache or does nothing if it is not currently in the cache.*/
    -    void remove(const Key& k) {
    -        if (table.containsKey(k)) {
    -            table.remove(k);
    -        }
    -    }
    -};
    -#endif
    -
     }
     #endif
     
    diff --git a/deps/g3dlite/include/G3D/Welder.h b/deps/g3dlite/include/G3D/Welder.h
    index 2c2554da7..8ab65cfa4 100644
    --- a/deps/g3dlite/include/G3D/Welder.h
    +++ b/deps/g3dlite/include/G3D/Welder.h
    @@ -22,30 +22,38 @@ public:
             /** Surfaces with normals that are within this angle of each
                 other are considered to be curved.  Default value is toRadians(70.0f).*/
             float   normalSmoothingAngle;
    -        float  	vertexWeldRadius;
    -        float  	textureWeldRadius;
    -        float  	normalWeldRadius;
    +
    +        /** Default value is 0 */
    +        float      vertexWeldRadius;
    +
    +        float      textureWeldRadius;
    +
    +        float      normalWeldRadius;
     
             inline Settings(float normalSmoothAngle = toRadians(70.0f)) : 
                 normalSmoothingAngle(normalSmoothAngle),
    -            vertexWeldRadius(0.0001f), 
    +            vertexWeldRadius(0.001f), 
                 textureWeldRadius(0.0001f), 
                 normalWeldRadius(0.01f) {}
     
     
             Settings(const Any& any);
    -        operator Any() const;
    +        
    +        Any toAny() const;
    +
    +        void serialize(class BinaryOutput& b) const;
    +
    +        void deserialize(class BinaryInput& b);
         };
     
     /**
    -     Mutates geometry, texCoord, and indexArray so that the output has collocated vertices collapsed (welded).
    +     Mutates geometry, texCoord, and indexArray so that the output has
    +     collocated vertices collapsed (welded).
     
          @param vertices Input and output
          @param textureCoords Input and output
          @param normals Output only
          @param indices Input and output. This is an array of trilist indices. 
    -     @param oldToNewIndex Output argument
    -     @param normalSmoothingAngle Varies from 0 (flat shading) to toRadians(180) for extremely smooth shading. Default is toRadians(70)
          */
         static void weld(
             Array&     vertices,
    @@ -61,8 +69,6 @@ public:
          @param textureCoords Input and output
          @param normals Output only
          @param indices Input and output. This is an array of trilist indices. 
    -     @param oldToNewIndex Output argument
    -     @param normalSmoothingAngle Varies from 0 (flat shading) to toRadians(180) for extremely smooth shading. Default is toRadians(70)
          */
         inline static void weld(
             Array&     vertices,
    diff --git a/deps/g3dlite/include/G3D/WrapMode.h b/deps/g3dlite/include/G3D/WrapMode.h
    index 25a2fb472..e71d6dfa6 100644
    --- a/deps/g3dlite/include/G3D/WrapMode.h
    +++ b/deps/g3dlite/include/G3D/WrapMode.h
    @@ -1,12 +1,12 @@
     /** 
    -  @file WrapMode.h
    +  \file G3D/WrapMode.h
      
    -  @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    +  \maintainer Morgan McGuire, http://graphics.cs.williams.edu
      
    -  @created 2007-04-17
    -  @edited  2010-04-17
    +  \created 2007-04-17
    +  \edited  2010-04-17
     
    -  Copyright 2000-2010, Morgan McGuire.
    +  Copyright 2000-2012, Morgan McGuire.
       All rights reserved.
      */
     
    @@ -15,7 +15,6 @@
     
     #include "G3D/platform.h"
     #include "G3D/enumclass.h"
    -#include "G3D/Any.h"
     
     #ifdef IGNORE
     #   undef IGNORE
    @@ -62,9 +61,7 @@ public:
             ZERO,
             IGNORE, 
             ERROR
    -    };
    -
    -private:
    +    } value;
         
         static const char* toString(int i, Value& v) {
             static const char* str[] = {"CLAMP", "TILE", "ZERO", "IGNORE", "ERROR", NULL}; 
    @@ -76,14 +73,11 @@ private:
             return s;
         }
     
    -    Value value;
    -
    -public:
     
         G3D_DECLARE_ENUM_CLASS_METHODS(WrapMode);
    -
     };
     
    +
     } // namespace G3D
     
     G3D_DECLARE_ENUM_CLASS_HASHCODE(G3D::WrapMode);
    diff --git a/deps/g3dlite/include/G3D/XML.h b/deps/g3dlite/include/G3D/XML.h
    index 9ff98f9d1..82816d20f 100644
    --- a/deps/g3dlite/include/G3D/XML.h
    +++ b/deps/g3dlite/include/G3D/XML.h
    @@ -7,7 +7,7 @@
      @created 2010-02-11
      @edited  2010-02-24
     
    - Copyright 2000-2010, Morgan McGuire.
    + Copyright 2000-2012, Morgan McGuire.
      All rights reserved.
      */
     
    @@ -52,6 +52,7 @@ end with "-->" e.g.,
     
     \sa G3D::Any, http://www.grinninglizard.com/tinyxml/
     
    +\htmlonly
     
     
       child0 ...
    @@ -59,6 +60,7 @@ end with "-->" e.g.,
       child2 ...
     
     
    +\endhtmlonly */ class XML { public: @@ -117,7 +119,7 @@ public: return m_attribute; } - const Array childArray() const { + const Array& childArray() const { return m_child; } @@ -127,7 +129,7 @@ public: } /** Attribute table size; zero for a TAG */ - int numAttributes() const { + size_t numAttributes() const { return m_attribute.size(); } @@ -142,7 +144,7 @@ public: return m_attribute[k]; } - const bool containsAttribute(const std::string& k) const { + bool containsAttribute(const std::string& k) const { return m_attribute.containsKey(k); } diff --git a/deps/g3dlite/include/G3D/constants.h b/deps/g3dlite/include/G3D/constants.h index 4121f744e..edecf10e1 100644 --- a/deps/g3dlite/include/G3D/constants.h +++ b/deps/g3dlite/include/G3D/constants.h @@ -26,20 +26,13 @@ public: TRIANGLE_STRIP = 0x0005, TRIANGLE_FAN = 0x0006, QUADS = 0x0007, - QUAD_STRIP = 0x0008 + QUAD_STRIP = 0x0008, + PATCHES = 0x000E }; private: - static const char* toString(int i, Value& v) { - static const char* str[] = {"POINTS", "LINES", "LINE_STRIP", "TRIANGLES", "TRIANGLE_FAN", "QUADS", "QUAD_STRIP", NULL}; - static const Value val[] = {POINTS, LINES, LINE_STRIP, TRIANGLES, TRIANGLE_FAN, QUADS, QUAD_STRIP}; - const char* s = str[i]; - if (s) { - v = val[i]; - } - return s; - } + static const char* toString(int i, Value& v); Value value; @@ -49,7 +42,7 @@ public: }; -/** Values for SuperSurface::GPUGeom::refractionHint. */ +/** Values for UniversalSurface::GPUGeom::refractionHint. */ class RefractionQuality { public: enum Value { @@ -77,15 +70,7 @@ public: private: - static const char* toString(int i, Value& v) { - static const char* str[] = {"NONE", "STATIC_ENV", "DYNAMIC_FLAT", "DYNAMIC_FLAT_MULTILAYER", "DYNAMIC_ENV", "BEST", NULL}; - static const Value val[] = {NONE, STATIC_ENV, DYNAMIC_FLAT, DYNAMIC_FLAT_MULTILAYER, DYNAMIC_ENV, BEST}; - const char* s = str[i]; - if (s) { - v = val[i]; - } - return s; - } + static const char* toString(int i, Value& v); Value value; @@ -95,7 +80,7 @@ public: }; -/** Values for SuperSurface::GPUGeom::mirrorHint. */ +/** Values for UniversalSurface::GPUGeom::mirrorHint. */ class MirrorQuality { public: @@ -119,15 +104,7 @@ public: private: - static const char* toString(int i, Value& v) { - static const char* str[] = {"NONE", "STATIC_ENV", "DYNAMIC_PLANAR", "DYNAMIC_ENV", "BEST", NULL}; - static const Value val[] = {NONE, STATIC_ENV, DYNAMIC_PLANAR, DYNAMIC_ENV, BEST}; - const char* s = str[i]; - if (s) { - v = val[i]; - } - return s; - } + static const char* toString(int i, Value& v); Value value; diff --git a/deps/g3dlite/include/G3D/debug.h b/deps/g3dlite/include/G3D/debug.h index a7697fe9c..4f34e5b3b 100644 --- a/deps/g3dlite/include/G3D/debug.h +++ b/deps/g3dlite/include/G3D/debug.h @@ -1,17 +1,17 @@ /** - @file debug.h + \file debug.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2001-08-26 - @edited 2006-02-16 + \created 2001-08-26 + \edited 2008-08-16 - Copyright 2000-2006, Morgan McGuire. + Copyright 2000-2006, Morgan McGuire. All rights reserved. */ -#ifndef G3D_DEBUG_H -#define G3D_DEBUG_H +#ifndef G3D_debug_h +#define G3D_debug_h #include "G3D/platform.h" #ifdef _MSC_VER @@ -38,7 +38,9 @@ namespace G3D { inline bool isValidHeapPointer(const void* x) { #ifdef _MSC_VER return - (x != (void*)0xcccccccc) && (x != (void*)0xdeadbeef) && (x != (void*)0xfeeefeee); + (x != NULL) && + (x != (void*)0xcccccccc) && (x != (void*)0xdeadbeef) && (x != (void*)0xfeeefeee) && + (x != (void*)0xcdcdcdcd) && (x != (void*)0xabababab) && (x != (void*)0xfdfdfdfd); #else return x != NULL; #endif @@ -51,7 +53,9 @@ inline bool isValidHeapPointer(const void* x) { */ inline bool isValidPointer(const void* x) { #ifdef _MSC_VER - return x != ((void*)0xcccccccc) && (x != (void*)0xdeadbeef) && (x != (void*)0xfeeefeee); + return (x != NULL) && + (x != (void*)0xcccccccc) && (x != (void*)0xdeadbeef) && (x != (void*)0xfeeefeee) && + (x != (void*)0xcdcdcdcd) && (x != (void*)0xabababab) && (x != (void*)0xfdfdfdfd); #else return x != NULL; #endif diff --git a/deps/g3dlite/include/G3D/enumclass.h b/deps/g3dlite/include/G3D/enumclass.h index 2874a630a..8e0c221f8 100644 --- a/deps/g3dlite/include/G3D/enumclass.h +++ b/deps/g3dlite/include/G3D/enumclass.h @@ -1,30 +1,39 @@ /** - @file G3D/enumclass.h + \file G3D/enumclass.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2007-01-27 - @edited 2007-07-20 + \maintainer Morgan McGuire, http://graphics.cs.williams.edu + \created 2007-01-27 + \edited 2013-04-09 */ #ifndef G3D_enumclass_h #define G3D_enumclass_h +#include "G3D/platform.h" #include "G3D/HashTrait.h" #include "G3D/BinaryInput.h" #include "G3D/BinaryOutput.h" +#include "G3D/TextOutput.h" +#include "G3D/Any.h" + +namespace G3D { + namespace _internal { + const char** smartEnumParseNames(const char* enumValList); + } +} /** \def G3D_DECLARE_ENUM_CLASS_METHODS \brief Creates a series of methods that turn a class into a scoped enumeration. - Uses the "Intelligent Enum" design pattern - http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4001/ + Example of use: - Enum classes are initialized to their zero value by default. - - You must implement the following method before calling G3D_DECLARE_ENUM_CLASS_METHODS, as either: - -
    +  \code
    +  class Resource {
    +  public:
    +    enum Value {FUEL, FOOD, WATER} value;
    +    
    +    // i is the position the enum value in Value (not the enum value itself)
         static const char* toString(int i, Value& v) {
             static const char* str[] = {"FUEL", "FOOD", "WATER", NULL}; // Whatever your enum values are
             static const Value val[] = {FUEL, FOOD, WATER};             // Whatever your enum values are
    @@ -34,29 +43,42 @@
             }
             return s;
         }
    -  
    - See GLG3D/GKey.h for an example. + G3D_DECLARE_ENUM_CLASS_METHODS(Resource); + }; + G3D_DECLARE_ENUM_CLASS_HASHCODE(Resource); + \endcode + + Extends the "Intelligent Enum" design pattern + http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4001/ + + Enum classes are initialized to their zero value by default. + + See GLG3D/GKey.h and G3D/WrapMode for an example. \sa G3D_DECLARE_ENUM_CLASS_HASHCODE */ #define G3D_DECLARE_ENUM_CLASS_METHODS(Classname)\ private: \ void fromString(const std::string& x) {\ - Value v;\ + Value v = (Value)0;\ const char* s;\ int i = 0;\ \ do {\ s = toString(i, v);\ + if (s == NULL) { return; /** Needed to get correct compilation on gcc */ } \ if (x == s) {\ value = v;\ return;\ }\ ++i;\ - } while (s);\ + } while (true);\ }\ \ public:\ + static const char* classname() {\ + return #Classname;\ + }\ \ const char* toString() const {\ const char* s;\ @@ -69,37 +91,36 @@ public:\ }\ ++i;\ }\ - return NULL;\ }\ \ explicit Classname(const std::string& x) : value((Value)0) {\ fromString(x);\ }\ \ - Classname(const Any& a) : value((Value)0) {\ + explicit Classname(const G3D::Any& a) : value((Value)0) { \ fromString(a.string());\ }\ \ - operator Any() const {\ - return Any(toString());\ + G3D::Any toAny() const { \ + return G3D::Any(toString()); \ }\ \ - Classname(char v) : value((Value)v) {}\ + explicit Classname(char v) : value((Value)v) {}\ \ Classname() : value((Value)0) {}\ \ Classname(const Value v) : value(v) {}\ \ explicit Classname(int v) : value((Value)v) {}\ -\ - /** Support cast back to the Value type, which is needed to allow implicit assignment inside unions. */\ - /*inline operator Value() const { - return value; - }*/\ \ operator int() const {\ return (int)value;\ }\ +\ + Classname& operator=(const Any& a) {\ + value = Classname(a).value;\ + return *this;\ + }\ \ bool operator== (const Classname other) const {\ return value == other.value;\ @@ -181,15 +202,16 @@ public:\ return (unsigned int)value;\ }\ \ - void serialize(BinaryOutput& b) const {\ + void serialize(G3D::BinaryOutput& b) const { \ b.writeInt32(value);\ }\ \ - void deserialize(BinaryInput& b) {\ + void deserialize(G3D::BinaryInput& b) { \ value = (Value)b.readInt32();\ } /** \def G3D_DECLARE_ENUM_CLASS_HASHCODE + Must be used at top level (i.e., not inside a class or namespace), with a fully qualified class name. */ #define G3D_DECLARE_ENUM_CLASS_HASHCODE(Classname)\ template <> struct HashTrait \ @@ -202,4 +224,108 @@ template <> struct HashTrait static size_t hashCode(Classname key) { return static_cast(key.hashCode()); } \ }; +/** +\def G3D_DECLARE_ENUM_CLASS + +\code +// Arguments may not have initializer expressions. Arguments may contain comments. +// Namespaces aren't *required*, this example just shows how to use them. +namespace Foo { + G3D_DECLARE_ENUM_CLASS(Day, SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY); +} +G3D_DECLARE_ENUM_CLASS_HASHCODE(Foo::Day); +... + +using namespace Foo; +// Example use of the smart enum +Day d = Day::TUESDAY; +Day d2("SATURDAY"); +Any a(d); +d = a; +printf("%s = %d\n", d.toString(), d.value); +\endcode + +\sa G3D_DECLARE_ENUM_CLASS_METHODS, G3D_DECLARE_ENUM_CLASS_HASHCODE, G3D::enumToJavaScriptDeclaration, G3D_BEGIN_ENUM_CLASS_DECLARATION +*/ +#define G3D_DECLARE_ENUM_CLASS(ClassName, ...)\ + G3D_BEGIN_ENUM_CLASS_DECLARATION(ClassName, __VA_ARGS__);\ + G3D_END_ENUM_CLASS_DECLARATION(); + +/** \def G3D_BEGIN_ENUM_CLASS_DECLARATION + +\code +G3D_BEGIN_ENUM_CLASS_DECLARATION(Day, SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY); + // Put extra methods here, e.g., + Value nextValue() { ... } +G3D_END_ENUM_CLASS_DECLARATION(); +} +G3D_DECLARE_ENUM_CLASS_HASHCODE(Foo::Day); + +\endcode + \sa G3D_DECLARE_ENUM_CLASS, G3D_END_ENUM_CLASS_DECLARATION +*/ +#define G3D_BEGIN_ENUM_CLASS_DECLARATION(ClassName, ...)\ +class ClassName {\ +public:\ + enum Value {\ + __VA_ARGS__\ + } value;\ +\ + /* The static variables here may be duplicated in different shared object binaries (DLLs), but that's ok--we only depend on their values, not their uniqueness. See also http://stackoverflow.com/questions/11962918/local-static-variable-is-instantiated-multiple-times-why */\ + static const char* toString(int i, Value& v) {\ + static const char** str = G3D::_internal::smartEnumParseNames(#__VA_ARGS__);\ + static const Value val[] = {__VA_ARGS__};\ + const char* s = str[i];\ + if (s) { v = val[i]; }\ + return s;\ + }\ +\ + G3D_DECLARE_ENUM_CLASS_METHODS(ClassName); + +/** \def G3D_END_ENUM_CLASS_DECLARATION + \sa G3D_BEGIN_ENUM_CLASS_DECLARATION */ +#define G3D_END_ENUM_CLASS_DECLARATION() } + + +namespace G3D { + +/** + \brief Generates JavaScript source code defining an enum equivalent to + EnumClass. + + \code + TextOutput t("WrapMode.js"); + enumToJavaScriptDeclaration(t); + t.commit(); + \endcode + */ +template +void enumToJavaScriptDeclaration(TextOutput& t) { + t.printf("/* BEGIN GENERATED CODE. The following was automatically generated by G3D::enumToJavaScriptDeclaration(). Do not edit it manually. */\n\n"); + t.printf("var %s = (function (propList) {", EnumClass::classname()); t.writeNewline(); + t.pushIndent(); { + t.printf("// Define immutable properties"); t.writeNewline(); + t.printf("var en = {};"); t.writeNewline(); + t.printf("for (var i = 0; i < propList.length; i += 2)"); t.writeNewline(); + t.pushIndent(); { + t.printf("Object.defineProperty(en, propList[i], {enumerable: true, value: propList[i + 1]});"); t.writeNewline(); + } t.popIndent(); + t.printf("return en;"); + t.writeNewline(); + } t.popIndent(); + t.printf("})(["); + int i = 0; + EnumClassValue m; + const char* s = EnumClass::toString(i, m); + while (notNull(s)) { + t.printf("\"%s\", %d, ", s, int(m)); + ++i; + s = EnumClass::toString(i, m); + } + // JavaScript allows a trailing comma + t.printf("]);"); t.writeNewline(); + t.printf("/* END GENERATED CODE */"); t.writeNewline(); +} + +} #endif diff --git a/deps/g3dlite/include/G3D/fileutils.h b/deps/g3dlite/include/G3D/fileutils.h index 89b416902..7717d6f72 100644 --- a/deps/g3dlite/include/G3D/fileutils.h +++ b/deps/g3dlite/include/G3D/fileutils.h @@ -4,9 +4,9 @@ @maintainer Morgan McGuire, http://graphics.cs.williams.edu @author 2002-06-06 - @edited 2010-03-06 + @edited 2011-03-06 - Copyright 2000-2010, Morgan McGuire. + Copyright 2000-2012, Morgan McGuire. All rights reserved. */ @@ -20,42 +20,16 @@ #include "G3D/Set.h" #include "G3D/g3dmath.h" -#ifdef G3D_WIN32 +#ifdef G3D_WINDOWS // For chdir, mkdir, etc. # include #endif namespace G3D { - - namespace _internal { - extern Set currentFilesUsed; - } - -/** Returns all the files used by G3D and GLG3D during the current execution. */ -Array filesUsed(); - -std::string readWholeFile( - const std::string& filename); - - -/** Reads from a zip file and decompresses the desired contents - into memory. Does not support recursive zip calls (i.e. a .zip - stored within another .zip) - - @param file the path, of the format C:\\...\\something.zip\\...\\desiredfile.ext - @param data a pointer to the memory where the file will be stored - @param length the size of the file decompressed to memory */ -void zipRead(const std::string& file, - void*& data, - size_t& length); - - -/** Closes the contents of a zip file that had been decompressed to - memory. Must be called in tandem with zipRead() to avoid memory - leaks. - - @param data the pointer to the decompressed file in memory */ -void zipClose(void* data); + +/** Returns the contents of a text file as a single string */ +std::string readWholeFile +(const std::string& filename); /** @@ -88,8 +62,8 @@ FILE* createTempFile(); */ bool zipfileExists (const std::string& filename, - std::string& outZipfile, - std::string& outInternalFile); + std::string& outZipfile, + std::string& outInternalFile); bool zipfileExists(const std::string& filename); diff --git a/deps/g3dlite/include/G3D/g3dfnmatch.h b/deps/g3dlite/include/G3D/g3dfnmatch.h index 464b3927e..186b79565 100644 --- a/deps/g3dlite/include/G3D/g3dfnmatch.h +++ b/deps/g3dlite/include/G3D/g3dfnmatch.h @@ -42,7 +42,7 @@ namespace G3D { -#if defined(G3D_WIN32) +#if defined(G3D_WINDOWS) # if ! defined(FNM_NOMATCH) # define FNM_NOMATCH 1 /* Match failed. */ diff --git a/deps/g3dlite/include/G3D/g3dmath.h b/deps/g3dlite/include/G3D/g3dmath.h index b0c98aeaf..54cc6ed37 100644 --- a/deps/g3dlite/include/G3D/g3dmath.h +++ b/deps/g3dlite/include/G3D/g3dmath.h @@ -7,9 +7,9 @@ @cite highestBit by Jukka Liimatta @created 2001-06-02 - @edited 2009-04-07 + @edited 2013-01-27 - Copyright 2000-2006, Morgan McGuire. + Copyright 2000-2013, Morgan McGuire. All rights reserved. */ @@ -29,8 +29,9 @@ #include #include #include +#include -#ifdef _MSC_VER +#if defined(_MSC_VER) && (_MSC_VER < 1000) // Visual Studio is missing inttypes.h # ifndef PRId64 # define PRId64 "I64d" @@ -58,6 +59,16 @@ #undef min #undef max +/** +\def G3D_DECLARE_SYMBOL(s) +Defines SYMBOL_s as a static const std::string with the value s. +Useful for avoiding heap allocation from C-string constants being +converted at runtime. +*/ +#define G3D_DECLARE_SYMBOL(s) \ + static const std::string SYMBOL_##s = #s + + namespace G3D { #ifdef _MSC_VER @@ -65,59 +76,61 @@ inline double __fastcall drand48() { return ::rand() / double(RAND_MAX); } -#if !defined(_WIN64) - -/** - Win32 implementation of the C99 fast rounding routines. +# ifdef _M_IX86 + // 32-bit + /** + Win32 implementation of the C99 fast rounding routines. - @cite routines are - Copyright (C) 2001 Erik de Castro Lopo + @cite routines are + Copyright (C) 2001 Erik de Castro Lopo - Permission to use, copy, modify, distribute, and sell this file for any - purpose is hereby granted without fee, provided that the above copyright - and this permission notice appear in all copies. No representations are - made about the suitability of this software for any purpose. It is - provided "as is" without express or implied warranty. -*/ + Permission to use, copy, modify, distribute, and sell this file for any + purpose is hereby granted without fee, provided that the above copyright + and this permission notice appear in all copies. No representations are + made about the suitability of this software for any purpose. It is + provided "as is" without express or implied warranty. + */ -__inline long int lrint (double flt) { - int intgr; - _asm { - fld flt - fistp intgr - }; + __inline long int lrint (double flt) { + int intgr; - return intgr; -} + _asm { + fld flt + fistp intgr + }; -__inline long int lrintf(float flt) { - int intgr; + return intgr; + } - _asm { - fld flt - fistp intgr - }; + __inline long int lrintf(float flt) { + int intgr; - return intgr; -} + _asm { + fld flt + fistp intgr + }; -#else + return intgr; + } +# else + // 64-bit + + __inline long int lrintf(float flt) { + return (long int)(flt + 0.5f); + } __inline long int lrint (double flt) { - return (long int)floor(flt+0.5f); + return (long int)(flt + 0.5); } - __inline long int lrintf(float flt) { - return (long int)floorf(flt+0.5f); - } - -#endif - +# endif #endif -#define fuzzyEpsilon (0.00001f) +#define fuzzyEpsilon64 (0.0000005) +#define fuzzyEpsilon32 (0.00001f) + /** This value should not be tested against directly, instead G3D::isNan() and G3D::isFinite() will return reliable results. */ @@ -147,23 +160,14 @@ inline double twoPi() { return 6.28318531; } -typedef signed char int8; -typedef unsigned char uint8; -typedef short int16; -typedef unsigned short uint16; -typedef int int32; -typedef unsigned int uint32; - -#ifdef _MSC_EXTENSIONS - typedef __int64 int64; - typedef unsigned __int64 uint64; -#elif ! defined(_MSC_VER) - typedef int64_t int64; - typedef uint64_t uint64; -#else - typedef long long int64; - typedef unsigned long long uint64; -#endif +typedef int8_t int8; +typedef uint8_t uint8; +typedef int16_t int16; +typedef uint16_t uint16; +typedef int32_t int32; +typedef uint32_t uint32; +typedef int64_t int64; +typedef uint64_t uint64; typedef float float32; typedef double float64; @@ -207,7 +211,14 @@ inline int iSign(float f) { return iSign((double)f); } +inline double round(double f) { + return floor(f + 0.5f); +} +inline float round(float f) { + return floor(f + 0.5f); +} + /** Fast round to integer using the lrint routine. Typically 6x faster than casting to integer. @@ -256,6 +267,11 @@ inline bool isNaN(int x) { return false; } +inline bool isNaN(uint64 x) { + (void)x; + return false; +} + /** Computes x % 3. */ @@ -339,6 +355,7 @@ int highestBit(uint32 x); */ bool fuzzyEq(double a, double b); + /** True if a is definitely not equal to b. Guaranteed false if a == b. Possibly false when a != b.*/ @@ -393,6 +410,7 @@ inline double log2(int x) { * True if num is a power of two. */ bool isPow2(int num); +bool isPow2(uint64 num); bool isOdd(int num); bool isEven(int num); @@ -455,7 +473,7 @@ inline double rsqrt(double x) { /** @deprecated Use rsq */ inline float rsqrt(float x) { // TODO: default this to using the SSE2 instruction - return 1.0 / sqrtf(x); + return 1.0f / sqrtf(x); } /** @@ -526,59 +544,59 @@ inline int iCeil (double fValue) { inline int iClamp(int val, int low, int hi) { debugAssert(low <= hi); - if (val <= low) { - return low; - } else if (val >= hi) { - return hi; - } else { - return val; - } + if (val <= low) { + return low; + } else if (val >= hi) { + return hi; + } else { + return val; + } } //---------------------------------------------------------------------------- inline int16 iClamp(int16 val, int16 low, int16 hi) { debugAssert(low <= hi); - if (val <= low) { - return low; - } else if (val >= hi) { - return hi; - } else { - return val; - } + if (val <= low) { + return low; + } else if (val >= hi) { + return hi; + } else { + return val; + } } //---------------------------------------------------------------------------- inline double clamp(double val, double low, double hi) { debugAssert(low <= hi); - if (val <= low) { - return low; - } else if (val >= hi) { - return hi; - } else { - return val; - } + if (val <= low) { + return low; + } else if (val >= hi) { + return hi; + } else { + return val; + } } inline float clamp(float val, float low, float hi) { debugAssert(low <= hi); - if (val <= low) { - return low; - } else if (val >= hi) { - return hi; - } else { - return val; - } + if (val <= low) { + return low; + } else if (val >= hi) { + return hi; + } else { + return val; + } } //---------------------------------------------------------------------------- inline int iWrap(int val, int hi) { - if (val < 0) { - return ((val % hi) + hi) % hi; - } else { - return val % hi; - } + if (val < 0) { + return ((val % hi) + hi) % hi; + } else { + return val % hi; + } } //---------------------------------------------------------------------------- @@ -651,11 +669,11 @@ inline double aTan2 (double fY, double fX) { inline double sign (double fValue) { if (fValue > 0.0) { return 1.0; - } + } if (fValue < 0.0) { return -1.0; - } + } return 0.0; } @@ -663,11 +681,11 @@ inline double sign (double fValue) { inline float sign (float fValue) { if (fValue > 0.0f) { return 1.0f; - } + } if (fValue < 0.0f) { return -1.0f; - } + } return 0.0f; } @@ -759,6 +777,16 @@ inline bool isPow2(int num) { return ((num & -num) == num); } +inline bool isPow2(uint64 x) { + // See http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/, method #9 + return ((x != 0) && !(x & (x - 1))); +} + +inline bool isPow2(uint32 x) { + // See http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/, method #9 + return ((x != 0) && !(x & (x - 1))); +} + inline bool isOdd(int num) { return (num & 1) == 1; } @@ -801,12 +829,31 @@ inline double eps(double a, double b) { (void)b; const double aa = abs(a) + 1.0; if (aa == inf()) { - return fuzzyEpsilon; + return fuzzyEpsilon64; } else { - return fuzzyEpsilon * aa; + return fuzzyEpsilon64 * aa; } } +inline float eps(float a, float b) { + // For a and b to be nearly equal, they must have nearly + // the same magnitude. This means that we can ignore b + // since it either has the same magnitude or the comparison + // will fail anyway. + (void)b; + const float aa = (float)abs(a) + 1.0f; + if (aa == inf()) { + return fuzzyEpsilon32; + } else { + return fuzzyEpsilon32 * aa; + } +} + + +inline bool fuzzyEq(float a, float b) { + return (a == b) || (abs(a - b) <= eps(a, b)); +} + inline bool fuzzyEq(double a, double b) { return (a == b) || (abs(a - b) <= eps(a, b)); } @@ -850,9 +897,47 @@ inline uint16 flipEndian16(const uint16 x) { return (x << 8) | ((x & 0xFF00) >> 8); } +/** The GLSL smoothstep function */ +inline float smoothstep(float edge0, float edge1, float x) { + // Scale, bias and saturate x to 0..1 range + x = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); + + // Evaluate polynomial + return x * x * (3 - 2 * x); +} + + +/** Perlin's C2 continous variation on smoothstep() */ +inline float smootherstep(float edge0, float edge1, float x) { + + // Scale, and saturate x to 0..1 range + x = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); + + // Evaluate polynomial + return x * x * x * (x * (x * 6 - 15) + 10); +} + + +/** Computes |b|^e * sign(b) */ +inline float signedPow(float b, float e) { + return sign(b) * powf(fabsf(b), e); +} + + +/** Computes |b|^e * sign(b) */ +inline double signedPow(double b, double e) { + return sign(b) * pow(abs(b), e); +} + } // namespace +namespace std { +inline int pow(int a, int b) { + return (int)::pow(double(a), double(b)); +} + +} #ifdef _MSC_VER # pragma warning (pop) #endif diff --git a/deps/g3dlite/include/G3D/netheaders.h b/deps/g3dlite/include/G3D/netheaders.h index a82d7c36f..cff382344 100644 --- a/deps/g3dlite/include/G3D/netheaders.h +++ b/deps/g3dlite/include/G3D/netheaders.h @@ -3,7 +3,7 @@ #include "G3D/platform.h" -#ifdef G3D_WIN32 +#ifdef G3D_WINDOWS # if (G3D_WINSOCK_MAJOR_VERSION == 2) # include # elif (G3D_WINSOCK_MAJOR_VERSION == 1) diff --git a/deps/g3dlite/include/G3D/networkHelpers.h b/deps/g3dlite/include/G3D/networkHelpers.h index 7a532d71e..e3168c243 100644 --- a/deps/g3dlite/include/G3D/networkHelpers.h +++ b/deps/g3dlite/include/G3D/networkHelpers.h @@ -85,7 +85,7 @@ #ifndef _SOCKLEN_T -# if defined(G3D_WIN32) || defined(G3D_OSX) +# if defined(G3D_WINDOWS) || defined(G3D_OSX) typedef int socklen_t; # endif #endif diff --git a/deps/g3dlite/include/G3D/platform.h b/deps/g3dlite/include/G3D/platform.h index 65616f0b5..d043f2149 100644 --- a/deps/g3dlite/include/G3D/platform.h +++ b/deps/g3dlite/include/G3D/platform.h @@ -1,22 +1,26 @@ /** - @file platform.h + \file platform.h \#defines for platform specific issues. - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2003-06-09 - @edited 2010-08-11 + Copyright 2000-2012, Morgan McGuire. + All rights reserved. + + \created 2003-06-09 + \edited 2013-01-03 */ #ifndef G3D_platform_h #define G3D_platform_h /** + \def G3D_VER The version number of G3D in the form: MmmBB -> version M.mm [beta BB] */ -#define G3D_VER 80100 +#define G3D_VER 90000 // fatal error for unsupported architectures #if defined(__powerpc__) @@ -31,13 +35,15 @@ # undef _DEBUG #endif -/** @def G3D_DEBUG() +/** \def G3D_DEBUG Defined if G3D is built in debug mode. */ #if !defined(G3D_DEBUG) && (defined(_DEBUG) || defined(G3D_DEBUGRELEASE)) # define G3D_DEBUG #endif -/** These control the version of Winsock used by G3D. +/** +\def G3D_WINSOCK_MAJOR_VERSION +These control the version of Winsock used by G3D. Version 2.0 is standard for G3D 6.09 and later. Version 1.1 is standard for G3D 6.08 and earlier. */ @@ -49,10 +55,15 @@ #define __fastcall #endif +/** \def G3D_WINDOWS*/ +/** \def G3D_FREEBSD2*/ +/** \def G3D_LINUX*/ +/** \def G3D_OSX */ + #ifdef _MSC_VER - #define G3D_WIN32 +# define G3D_WINDOWS #elif defined(__MINGW32__) - #define G3D_WIN32 + #define G3D_WINDOWS #undef __MSVCRT_VERSION__ #define __MSVCRT_VERSION__ 0x0601 #include @@ -61,8 +72,6 @@ #define G3D_LINUX #elif defined(__linux__) #define G3D_LINUX -#elif defined(__CYGWIN__) - #define G3D_LINUX #elif defined(__APPLE__) #define G3D_LINUX @@ -70,25 +79,26 @@ // pi as a constant, which creates a conflict with G3D #define __FP__ #else - #error Unknown platform + #error Unknown platform +#endif + +/** \def G3D_64BIT */ +/** \def G3D_32BIT */ + + + +/** Define the g++ thread-local syntax on all platforms (since the MSVC version would be hard to emulate with a macro) */ +#if defined(_MSC_VER) +# define __thread __declspec(thread) #endif // Detect 64-bit under various compilers #if (defined(_M_X64) || defined(_WIN64) || defined(__LP64__) || defined(_LP64)) # define G3D_64BIT - #if defined(WIN32) - #include - #endif #else # define G3D_32BIT #endif -// Strongly encourage inlining on gcc -#ifdef __GNUC__ -#define inline __inline__ -#endif - - // Verify that the supported compilers are being used and that this is a known // processor. @@ -96,13 +106,14 @@ # ifndef __GNUC__ # error G3D only supports the gcc compiler on Linux. # endif +# define G3D_NO_FFMPEG #endif #ifdef G3D_OSX # ifndef __GNUC__ # error G3D only supports the gcc compiler on OS X. # endif - + # if defined(__i386__) # define G3D_OSX_INTEL # elif defined(__PPC__) @@ -115,11 +126,13 @@ #ifdef _MSC_VER +// Microsoft Visual C++ 10.0 = 1600 +// Microsoft Visual C++ 9.0 = 1500 // Microsoft Visual C++ 8.0 ("Express") = 1400 -// Microsoft Visual C++ 7.1 ("2003") _MSC_VER = 1310 -// Microsoft Visual C++ 7.0 ("2002") _MSC_VER = 1300 -// Microsoft Visual C++ 6.0 _MSC_VER = 1200 -// Microsoft Visual C++ 5.0 _MSC_VER = 1100 +// Microsoft Visual C++ 7.1 ("2003") _MSC_VER = 1310 +// Microsoft Visual C++ 7.0 ("2002") _MSC_VER = 1300 +// Microsoft Visual C++ 6.0 _MSC_VER = 1200 +// Microsoft Visual C++ 5.0 _MSC_VER = 1100 // Turn off warnings about deprecated C routines # pragma warning (disable : 4996) @@ -128,8 +141,16 @@ // for debug assertions in inlined methods. # pragma warning (disable : 4127) -/** @def G3D_DEPRECATED() - Creates deprecated warning. */ +/** \def G3D_DEPRECATED() + Creates deprecated warning at compile time when used. + + Example: + \code + int G3D_DEPRECATED sum(int a, int b) { + return a + b; + } + \endcode + */ # define G3D_DEPRECATED __declspec(deprecated) // Prevent Winsock conflicts by hiding the winsock API @@ -140,14 +161,12 @@ // Disable 'name too long for browse information' warning # pragma warning (disable : 4786) -// TODO: remove -# pragma warning (disable : 4244) # define restrict /** @def G3D_CHECK_PRINTF_METHOD_ARGS() Enables printf parameter validation on gcc. */ -# define G3D_CHECK_PRINTF_ARGS +# define G3D_CHECK_PRINTF_ARGS /** @def G3D_CHECK_PRINTF_METHOD_ARGS() Enables printf parameter validation on gcc. */ @@ -173,50 +192,34 @@ // DLL runtime #ifndef _DLL - #define _DLL + #define _DLL #endif // Multithreaded runtime #ifndef _MT - #define _MT 1 + #define _MT 1 #endif // Ensure that we aren't forced into the static lib #ifdef _STATIC_CPPLIB - #undef _STATIC_CPPLIB + #undef _STATIC_CPPLIB #endif - #ifdef _DEBUG - #pragma comment (linker, "/NODEFAULTLIB:LIBCMTD.LIB") - #pragma comment (linker, "/NODEFAULTLIB:LIBCPMTD.LIB") - #pragma comment (linker, "/NODEFAULTLIB:LIBCPD.LIB") - #pragma comment (linker, "/DEFAULTLIB:MSVCPRTD.LIB") - #pragma comment(linker, "/NODEFAULTLIB:LIBCD.LIB") - #pragma comment(linker, "/DEFAULTLIB:MSVCRTD.LIB") - #else - #pragma comment(linker, "/NODEFAULTLIB:LIBC.LIB") - #pragma comment(linker, "/DEFAULTLIB:MSVCRT.LIB") - #pragma comment (linker, "/NODEFAULTLIB:LIBCMT.LIB") - #pragma comment (linker, "/NODEFAULTLIB:LIBCPMT.LIB") - #pragma comment(linker, "/NODEFAULTLIB:LIBCP.LIB") - #pragma comment (linker, "/DEFAULTLIB:MSVCPRT.LIB") - #endif - - // Now set up external linking - -# ifdef _DEBUG - // zlib was linked against the release MSVCRT; force - // the debug version. -# pragma comment(linker, "/NODEFAULTLIB:MSVCRT.LIB") -# endif +#ifdef _DEBUG + // Some of the support libraries are always built in Release. + // Make sure the debug runtime library is linked in + #pragma comment(linker, "/NODEFAULTLIB:MSVCRT.LIB") + #pragma comment(linker, "/NODEFAULTLIB:MSVCPRT.LIB") +#endif # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN 1 # endif - -# define NOMINMAX 1 +# ifndef NOMINMAX +# define NOMINMAX 1 +# endif # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0500 # endif @@ -230,8 +233,9 @@ # endif -/** @def G3D_START_AT_MAIN() - Defines necessary wrapper around WinMain on Windows to allow transfer of execution to main(). */ +/** \def G3D_START_AT_MAIN() + Makes Windows programs using the WINDOWS subsystem invoke main() at program start by + defining a WinMain(). Does nothing on other operating systems.*/ # define G3D_START_AT_MAIN()\ int WINAPI G3D_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw);\ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\ @@ -269,7 +273,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\ # define __stdcall __attribute__((stdcall)) # endif -# elif defined(__x86_64__) +# elif defined(__x86_64__) || defined(__arm) || defined(__aarch64__) # ifndef __cdecl # define __cdecl @@ -299,7 +303,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\ /** - @def STR(expression) + \def STR(expression) Creates a string from the expression. Frequently used with G3D::Shader to express shading programs inline. @@ -319,26 +323,100 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\ # define PRAGMA(x) _Pragma(#x) #endif -/** @def G3D_BEGIN_PACKED_CLASS(byteAlign) - Switch to tight alignment +/** \def G3D_BEGIN_PACKED_CLASS(byteAlign) + Switch to tight alignment. + + \code + G3D_BEGIN_PACKED_CLASS(1) + ThreeBytes { + public: + uint8 a, b, c; + } + G3D_END_PACKED_CLASS(1) + \endcode + + See G3D::Color3uint8 for an example.*/ -#ifdef _MSC_VER -# define G3D_BEGIN_PACKED_CLASS(byteAlign) PRAGMA( pack(push, byteAlign) ) +#ifdef __GNUC__ +# define G3D_BEGIN_PACKED_CLASS(byteAlign) class __attribute((__packed__)) +#elif defined(_MSC_VER) +# define G3D_BEGIN_PACKED_CLASS(byteAlign) PRAGMA( pack(push, byteAlign) ) class #else -# define G3D_BEGIN_PACKED_CLASS(byteAlign) +# define G3D_BEGIN_PACKED_CLASS(byteAlign) class #endif -/** @def G3D_END_PACKED_CLASS(byteAlign) +/** \def G3D_END_PACKED_CLASS(byteAlign) End switch to tight alignment + See G3D::Color3uint8 for an example.*/ -#ifdef _MSC_VER -# define G3D_END_PACKED_CLASS(byteAlign) ; PRAGMA( pack(pop) ) -#elif defined(__GNUC__) +#ifdef __GNUC__ # define G3D_END_PACKED_CLASS(byteAlign) __attribute((aligned(byteAlign))) ; +#elif defined(_MSC_VER) +# define G3D_END_PACKED_CLASS(byteAlign) ; PRAGMA( pack(pop) ) #else # define G3D_END_PACKED_CLASS(byteAlign) ; #endif -// Header guard +// Bring in shared_ptr and weak_ptr +#if (defined(__GNUC__) && defined(__APPLE__)) || defined(__linux__) +#include // Defines _LIBCC_VERSION if linking against libc++ or does nothing #endif +#if (!defined(_LIBCPP_VERSION) && defined(__APPLE__)) || (!defined(_LIBCPP_VERSION) && defined(__linux__)) +# include +#else +# include +#endif + +namespace G3D { +#if (!defined(_LIBCPP_VERSION) && defined(__APPLE__)) || (!defined(_LIBCPP_VERSION) && defined(__linux__)) + using std::tr1::shared_ptr; + using std::tr1::weak_ptr; + using std::tr1::dynamic_pointer_cast; + using std::tr1::static_pointer_cast; + using std::tr1::enable_shared_from_this; +#else + using std::shared_ptr; + using std::weak_ptr; + using std::dynamic_pointer_cast; + using std::static_pointer_cast; + using std::enable_shared_from_this; +#endif + + /** Options for initG3D and initGLG3D. */ + class G3DSpecification { + public: + /** + \brief Should G3D spawn its own network thread? + + If true, G3D will spawn a thread for network management on the first invocation of G3D::NetServer::create or + G3D::NetConnection::connectToServer. + + If false and networking is used, the application must explicitly invoke G3D::serviceNetwork() regularly to allow the network + code to run. + + In either case, the network API is threadsafe. + + Default: true. + */ + bool threadedNetworking; + + G3DSpecification() : threadedNetworking(true) {} + + virtual ~G3DSpecification() {} + }; + + + namespace _internal { + /** Set by initG3D, defined in initG3D.cpp */ + G3DSpecification& g3dInitializationSpecification(); + } +} + +// See http://stackoverflow.com/questions/2670816/how-can-i-use-the-compile-time-constant-line-in-a-string +// For use primarily with NUMBER_TO_STRING(__LINE__) +#define NUMBER_TO_STRING(x) NUMBER_TO_STRING2(x) +#define NUMBER_TO_STRING2(x) #x +#define __LINE_AS_STRING__ NUMBER_TO_STRING(__LINE__) + +#endif // Header guard diff --git a/deps/g3dlite/include/G3D/serialize.h b/deps/g3dlite/include/G3D/serialize.h index 2382c0ee0..f4a286117 100644 --- a/deps/g3dlite/include/G3D/serialize.h +++ b/deps/g3dlite/include/G3D/serialize.h @@ -1,18 +1,68 @@ -#ifndef G3D_SERIALIZE_H -#define G3D_SERIALIZE_H +#ifndef G3D_serialize_h +#define G3D_serialize_h #include "G3D/BinaryInput.h" #include "G3D/BinaryOutput.h" #include "G3D/Array.h" +#include namespace G3D { + - +inline void serialize(const std::string& s, BinaryOutput& b) { + b.writeString32(s); +} + +inline void deserialize(std::string& s, BinaryInput& b) { + s = b.readString32(); +} + +inline void serialize(const int32& i, BinaryOutput& b) { + b.writeInt32(i); +} + +inline void deserialize(int32& i, BinaryInput& b) { + i = b.readInt32(); +} + +inline void serialize(const uint32& i, BinaryOutput& b) { + b.writeUInt32(i); +} + +inline void deserialize(uint32& i, BinaryInput& b) { + i = b.readUInt32(); +} + +inline void serialize(const bool& i, BinaryOutput& b) { + b.writeBool8(i); +} + +inline void deserialize(bool& i, BinaryInput& b) { + i = b.readBool8(); +} + +inline void serialize(const float32& f, BinaryOutput& b) { + b.writeFloat32(f); +} + +inline void deserialize(float32& f, BinaryInput& b) { + f = b.readFloat32(); +} + +inline void serialize(const float64& f, BinaryOutput& b) { + b.writeFloat64(f); +} + +inline void deserialize(float64& f, BinaryInput& b) { + f = b.readFloat64(); +} + +/** serialize(const T&, BinaryOutput&) must have been overridden as well */ template void serialize(const Array& array, BinaryOutput& b) { b.writeInt32(array.size()); for (int i = 0; i < array.size(); ++i) { - serialize(array[i], b); + serialize(array[i], b); } } @@ -25,6 +75,6 @@ void deserialize(Array& array, BinaryInput& b) { } } -} +} // G3D -#endif +#endif //G3D_serialize_h diff --git a/deps/g3dlite/include/G3D/stringutils.h b/deps/g3dlite/include/G3D/stringutils.h index 42a488652..01ac674f3 100644 --- a/deps/g3dlite/include/G3D/stringutils.h +++ b/deps/g3dlite/include/G3D/stringutils.h @@ -31,53 +31,72 @@ void parseCommaSeparated(const std::string s, Array& array, bool st /** Finds the index of the first '\\' or '/' character, starting at index \a start. \sa G3D::findLastSlash, G3D::isSlash */ -inline int findSlash(const std::string& f, int start = 0) { - int i = f.find('/', start); - int j = f.find('\\', start); - if (((i != -1) && (i < j)) || (j == -1)) { +inline size_t findSlash(const std::string& f, size_t start = 0) { + size_t i = f.find('/', start); + size_t j = f.find('\\', start); + if ((i != std::string::npos) && (i < j)) { return i; } else { return j; } } +/** \brief Returns the larger string index, ignoring std::string::npos. */ +inline size_t maxNotNPOS(size_t i, size_t j) { + if (i == std::string::npos) { + return j; + } else if (j == std::string::npos) { + return i; + } else { + return max(i, j); + } +} /** Finds the index of the first '\\' or '/' character, starting at index \a start (if \a start is -1, starts at the end of the string). \sa G3D::findSlash, G3D::isSlash */ -inline int findLastSlash(const std::string& f, int start = -1) { - if (start == -1) { +inline size_t findLastSlash(const std::string& f, size_t start = std::string::npos) { + if (start == std::string::npos) { start = f.length() - 1; } - int i = f.rfind('/', start); - int j = f.rfind('\\', start); - return max(i, j); + size_t i = f.rfind('/', start); + size_t j = f.rfind('\\', start); + return maxNotNPOS(i, j); } + +/** Returns a string which is \a s, with all instances of \a pattern replaced */ +std::string replace(const std::string& s, const std::string& pattern, const std::string& replacement); + +/** Returns true if \a s is a valid C++ identifier */ +bool isValidIdentifier(const std::string& s); + /** - Returns true if the test string begins with the pattern string. + \brief Returns true if the test string begins with the pattern string. */ -bool beginsWith( - const std::string& test, +bool beginsWith + (const std::string& test, const std::string& pattern); /** - Returns true if the test string ends with the pattern string. + \brief Returns true if the test string ends with the pattern string. */ -bool endsWith( - const std::string& test, +bool endsWith + (const std::string& test, const std::string& pattern); /** - Produces a new string that is the input string + \brief Produces a new string that is the input string wrapped at a certain number of columns (where the line is broken at the latest space before the column limit.) Platform specific NEWLINEs are inserted to wrap. + + \sa G3D::GFont::wordWrapCut, G3D::TextOutput::Settings::WordWrapMode */ -std::string wordWrap( - const std::string& input, +std::string wordWrap + (const std::string& input, int numCols); /** @@ -161,6 +180,17 @@ inline bool isQuote(const unsigned char c) { return (c == '\'') || (c == '\"'); } +/** Number of new lines in the given string */ +inline int countNewlines(const std::string& s) { + int c = 0; + for (int i = 0; i < (int)s.size(); ++i) { + if (s[i] == '\n') { + ++c; + } + } + return c; +} + }; // namespace #endif diff --git a/deps/g3dlite/include/G3D/uint128.h b/deps/g3dlite/include/G3D/uint128.h index da1af3ec2..6698d88f0 100644 --- a/deps/g3dlite/include/G3D/uint128.h +++ b/deps/g3dlite/include/G3D/uint128.h @@ -20,31 +20,30 @@ namespace G3D { class uint128 { public: - G3D::uint64 hi; - G3D::uint64 lo; + G3D::uint64 hi; + G3D::uint64 lo; uint128(const uint64& lo); - uint128(const uint64& hi, const uint64& lo); - - uint128& operator+=(const uint128& x); - - uint128& operator*=(const uint128& x); - - uint128& operator^=(const uint128& x); - - uint128& operator&=(const uint128& x); - - uint128& operator|=(const uint128& x); - - bool operator==(const uint128& x); - + uint128(const uint64& hi, const uint64& lo); + + uint128& operator+=(const uint128& x); + + uint128& operator*=(const uint128& x); + + uint128& operator^=(const uint128& x); + + uint128& operator&=(const uint128& x); + + uint128& operator|=(const uint128& x); + + bool operator==(const uint128& x); + uint128& operator>>=(const int x); uint128& operator<<=(const int x); - + uint128 operator&(const uint128& x); - }; } diff --git a/deps/g3dlite/include/G3D/units.h b/deps/g3dlite/include/G3D/units.h index 2e30304dc..694576f3d 100644 --- a/deps/g3dlite/include/G3D/units.h +++ b/deps/g3dlite/include/G3D/units.h @@ -1,10 +1,10 @@ /** - @file units.h + \file G3D/units.h - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2009-08-21 - @edited 2009-08-21 + \created 2009-08-21 + \edited 2011-07-08 */ #ifndef G3D_units_h #define G3D_units_h @@ -46,7 +46,7 @@ inline float meters() { /** 1000 m */ inline float kilometers() { - return 100.0f; + return 1000.0f; } /** 0.0254 m */ @@ -120,7 +120,37 @@ inline float years() { /////////////////////////////////////////// -} +/** SI unit of mass */ +inline float kilograms() { + return 1.0f; } +/////////////////////////////////////////// + +/** 1 kg m / s^2 */ +inline float newtons() { + return 1.0f; +} + +/////////////////////////////////////////// + +/** SI unit of power: W = J/s*/ +inline float watts() { + return 1.0; +} + +/** SI unit of energy: J = N*m */ +inline float joules() { + return 1.0; +} + +/** Unit of solid angle measure. A sphere subtends 4 * pi sr. */ +inline float steradians() { + return 1.0; +} + + +} // units +} // G3D + #endif diff --git a/deps/g3dlite/include/G3D/unorm16.h b/deps/g3dlite/include/G3D/unorm16.h new file mode 100644 index 000000000..d879eb063 --- /dev/null +++ b/deps/g3dlite/include/G3D/unorm16.h @@ -0,0 +1,180 @@ +/** + \file G3D/unorm16.h + + \maintainer Morgan McGuire, http://graphics.cs.williams.edu + + \created 2012-03-02 by Zina Cigolle + \edited 2012-03-02 + + Copyright 2000-2012, Morgan McGuire. + All rights reserved. + */ +#ifndef G3D_unorm16_h +#define G3D_unorm16_h + +#include "G3D/platform.h" +#include "G3D/g3dmath.h" + +namespace G3D { + + +/** Represents numbers on [0, 1] in 16 bits as an unsigned normalized + 0.8 fixed-point value using the same encoding scheme as OpenGL. + + Note that arithmetic operations may over and under-flow, just like + uint16 arithmetic. + + OpenGL specifications can be found here: + http://www.opengl.org/registry/specs/ARB/shading_language_packing.txt + +*/ +G3D_BEGIN_PACKED_CLASS(1) +unorm16 { +private: + uint16 m_bits; + + /** Private to prevent illogical conversions without explicitly + stating that the input should be treated as bits; see fromBits. */ + explicit unorm16(uint16 b) : m_bits(b) {} + +public: + + /** Equivalent to: \code unorm16 u = reinterpret_cast(255);\endcode */ + static unorm16 fromBits(uint16 b) { + return unorm16(b); + } + + /** \copydoc fromBits */ + static unorm16 reinterpretFrom(uint16 b) { + return unorm16(b); + } + + unorm16() : m_bits(0) {} + + unorm16(const unorm16& other) : m_bits(other.m_bits) {} + + explicit unorm16(const class Any& a); + + class Any toAny() const; + + /** Maps f to round(f * 65535).*/ + explicit unorm16(float f) { + m_bits = uint16(clamp(f, 0.0f, 1.0f) * 65535.0f + 0.5f); + } + + explicit unorm16(double f) { + m_bits = uint16(clamp(f, 0.0, 1.0) * 65535.0 + 0.5); + } + + /** Returns a number on [0.0f, 1.0f] */ + operator float() const { + return float(m_bits) * (1.0f / 65535.0f); + } + + operator double() const { + return double(m_bits) * (1.0 / 65535.0); + } + + static unorm16 one() { + return fromBits(65535); + } + + static unorm16 zero() { + return fromBits(0); + } + + /**\brief Returns the underlying bits in this representation. + Equivalent to: + \code uint16 i = reinterpret_cast(u); \endcode */ + uint16 bits() const { + return m_bits; + } + + /** \copydoc bits */ + uint16 reinterpretAsUInt16() const { + return m_bits; + } + + bool operator>(const unorm16 other) const { + return m_bits > other.m_bits; + } + + bool operator<(const unorm16 other) const { + return m_bits < other.m_bits; + } + + bool operator>=(const unorm16 other) const { + return m_bits >= other.m_bits; + } + + bool operator<=(const unorm16 other) const { + return m_bits <= other.m_bits; + } + + bool operator==(const unorm16 other) const { + return m_bits <= other.m_bits; + } + + bool operator!=(const unorm16 other) const { + return m_bits != other.m_bits; + } + + unorm16 operator+(const unorm16 other) const { + return unorm16(uint16(m_bits + other.m_bits)); + } + + unorm16& operator+=(const unorm16 other) { + m_bits += other.m_bits; + return *this; + } + + unorm16 operator-(const unorm16 other) const { + return unorm16(uint16(m_bits - other.m_bits)); + } + + unorm16& operator-=(const unorm16 other) { + m_bits -= other.m_bits; + return *this; + } + + unorm16 operator*(const int i) const { + return unorm16(uint16(m_bits * i)); + } + + unorm16& operator*=(const int i) { + m_bits *= i; + return *this; + } + + unorm16 operator/(const int i) const { + return unorm16(uint16(m_bits / i)); + } + + unorm16& operator/=(const int i) { + m_bits /= i; + return *this; + } + + unorm16 operator<<(const int i) const { + return unorm16((uint16)(m_bits << i)); + } + + unorm16& operator<<=(const int i) { + m_bits <<= i; + return *this; + } + + unorm16 operator>>(const int i) const { + return unorm16(uint16(m_bits >> i)); + } + + unorm16& operator>>=(const int i) { + m_bits >>= i; + return *this; + } +} +G3D_END_PACKED_CLASS(1) + +} // namespace G3D + +#endif // G3D_unorm16 diff --git a/deps/g3dlite/include/G3D/unorm8.h b/deps/g3dlite/include/G3D/unorm8.h new file mode 100644 index 000000000..b62d100ab --- /dev/null +++ b/deps/g3dlite/include/G3D/unorm8.h @@ -0,0 +1,177 @@ +/** + \file G3D/unorm8.h + + \maintainer Morgan McGuire, http://graphics.cs.williams.edu + + \created 2011-08-11 + \edited 2011-08-11 + + Copyright 2000-2012, Morgan McGuire. + All rights reserved. + */ +#ifndef G3D_unorm8_h +#define G3D_unorm8_h + +#include "G3D/platform.h" +#include "G3D/g3dmath.h" + +namespace G3D { + + +/** Represents numbers on [0, 1] in 8 bits as an unsigned normalized + 0.8 fixed-point value using the same encoding scheme as OpenGL. + + OpenGL specifications can be found here: + + + Note that arithmetic operations may over and under-flow, just like + uint8 arithmetic. + + +*/ +G3D_BEGIN_PACKED_CLASS(1) +unorm8 { +private: + uint8 m_bits; + + /** Private to prevent illogical conversions without explicitly + stating that the input should be treated as bits; see fromBits. */ + explicit unorm8(uint8 b) : m_bits(b) {} + +public: + + /** Equivalent to: \code unorm8 u = reinterpret_cast(255);\endcode */ + static unorm8 fromBits(uint8 b) { + return unorm8(b); + } + + /** \copydoc fromBits */ + static unorm8 reinterpretFrom(uint8 b) { + return unorm8(b); + } + + unorm8() : m_bits(0) {} + + unorm8(const unorm8& other) : m_bits(other.m_bits) {} + + /** Maps f to round(f * 255).*/ + explicit unorm8(float f) { + m_bits = (uint8)(clamp(f, 0.0f, 1.0f) * 255.0f + 0.5f); + } + + explicit unorm8(double f) { + m_bits = iClamp(int(f * 255.0f + 0.5f), 0, 255); + } + + /** Returns a number on [0.0f, 1.0f] */ + operator float() const { + return float(m_bits) * (1.0f / 255.0f); + } + + operator double() const { + return double(m_bits) * (1.0 / 255.0); + } + + static unorm8 one() { + return fromBits(255); + } + + static unorm8 zero() { + return fromBits(0); + } + + /**\brief Returns the underlying bits in this representation. + Equivalent to: + \code uint8 i = reinterpret_cast(u); \endcode */ + uint8 bits() const { + return m_bits; + } + + /** \copydoc bits */ + uint8 reinterpretAsUInt8() const { + return m_bits; + } + + bool operator>(const unorm8 other) const { + return m_bits > other.m_bits; + } + + bool operator<(const unorm8 other) const { + return m_bits < other.m_bits; + } + + bool operator>=(const unorm8 other) const { + return m_bits >= other.m_bits; + } + + bool operator<=(const unorm8 other) const { + return m_bits <= other.m_bits; + } + + bool operator==(const unorm8 other) const { + return m_bits <= other.m_bits; + } + + bool operator!=(const unorm8 other) const { + return m_bits != other.m_bits; + } + + unorm8 operator+(const unorm8 other) const { + return unorm8(uint8(m_bits + other.m_bits)); + } + + unorm8& operator+=(const unorm8 other) { + m_bits += other.m_bits; + return *this; + } + + unorm8 operator-(const unorm8 other) const { + return unorm8(uint8(m_bits - other.m_bits)); + } + + unorm8& operator-=(const unorm8 other) { + m_bits -= other.m_bits; + return *this; + } + + unorm8 operator*(const int i) const { + return unorm8(uint8(m_bits * i)); + } + + unorm8& operator*=(const int i) { + m_bits *= i; + return *this; + } + + unorm8 operator/(const int i) const { + return unorm8(uint8(m_bits / i)); + } + + unorm8& operator/=(const int i) { + m_bits /= i; + return *this; + } + + unorm8 operator<<(const int i) const { + return unorm8((uint8)(m_bits << i)); + } + + unorm8& operator<<=(const int i) { + m_bits <<= i; + return *this; + } + + unorm8 operator>>(const int i) const { + return unorm8(uint8(m_bits >> i)); + } + + unorm8& operator>>=(const int i) { + m_bits >>= i; + return *this; + } +} +G3D_END_PACKED_CLASS(1) + +} // namespace G3D + +#endif // G3D_unorm8 diff --git a/deps/g3dlite/source/AABox.cpp b/deps/g3dlite/source/AABox.cpp index 8e66456c0..72695b487 100644 --- a/deps/g3dlite/source/AABox.cpp +++ b/deps/g3dlite/source/AABox.cpp @@ -1,10 +1,13 @@ /** - @file AABox.cpp + \file G3D.lib/source/AABox.cpp - @maintainer Morgan McGuire, http://graphics.cs.williams.edu + \maintainer Morgan McGuire, http://graphics.cs.williams.edu - @created 2004-01-10 - @edited 2006-01-11 + \created 2004-01-10 + \edited 2013-06-11 + + Copyright 2000-2013, Morgan McGuire. + All rights reserved. */ #include "G3D/platform.h" @@ -14,10 +17,53 @@ #include "G3D/Sphere.h" #include "G3D/BinaryInput.h" #include "G3D/BinaryOutput.h" +#include "G3D/Any.h" namespace G3D { +AABox::AABox(const Any& a) { + if (a.name() == "AABox::empty") { + *this = AABox::empty(); + } else if (a.name() == "AABox::inf") { + *this = AABox::inf(); + } else { + a.verifyName("AABox"); + a.verifyType(Any::ARRAY); + if (a.size() == 1) { + *this = AABox(Point3(a[0])); + } else if (a.size() == 2) { + set(Point3(a[0]), Point3(a[1])); + } else { + a.verify(false, "AABox must recieve exactly 1 or two arguments."); + } + } +} + + +Any AABox::toAny() const { + if (isEmpty()) { + return Any(Any::ARRAY, "AABox::empty"); + } else if (! isFinite()) { + return Any(Any::ARRAY, "AABox::inf"); + } else { + Any a(Any::ARRAY, "AABox"); + if (lo == hi) { + a.append(lo); + } else { + a.append(lo, hi); + } + return a; + } +} + + +const AABox& AABox::empty() { + static const AABox b; + return b; +} + + const AABox& AABox::maxFinite() { static const AABox b = AABox(Vector3::minFinite(), Vector3::maxFinite()); @@ -56,6 +102,13 @@ void AABox::deserialize(class BinaryInput& b) { } +void AABox::merge(const Box& b) { + AABox aab; + b.getBounds(aab); + merge(aab); +} + + void AABox::split(const Vector3::Axis& axis, float location, AABox& low, AABox& high) const { // Low, medium, and high along the chosen axis float L = G3D::min(location, lo[axis]); @@ -139,11 +192,11 @@ bool AABox::intersects(const AABox& other) const { int AABox::dummy = 0; -bool AABox::culledBy( - const Array& plane, - int& cullingPlane, - const uint32 _inMask, - uint32& childMask) const { +bool AABox::culledBy + (const Array& plane, + int& cullingPlane, + const uint32 _inMask, + uint32& childMask) const { uint32 inMask = _inMask; assert(plane.size() < 31); @@ -159,13 +212,13 @@ bool AABox::culledBy( (abs(hi.z) < G3D::finf()); // See if there is one plane for which all of the - // vertices are in the negative half space. + // vertices are in the negative half space. for (int p = 0; p < plane.size(); ++p) { - // Only test planes that are not masked - if ((inMask & 1) != 0) { - - Vector3 corner; + // Only test planes that are not masked + if ((inMask & 1) != 0) { + + Vector3 corner; int numContained = 0; int v = 0; @@ -173,12 +226,12 @@ bool AABox::culledBy( // We can early-out only if we have found one point on each // side of the plane (i.e. if we are straddling). That // occurs when (numContained < v) && (numContained > 0) - for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) { + for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) { // Unrolling these 3 if's into a switch decreases performance // by about 2x - corner.x = (v & 1) ? hi.x : lo.x; - corner.y = (v & 2) ? hi.y : lo.y; - corner.z = (v & 4) ? hi.z : lo.z; + corner.x = (v & 1) ? hi.x : lo.x; + corner.y = (v & 2) ? hi.y : lo.y; + corner.z = (v & 4) ? hi.z : lo.z; if (finite) { // this branch is highly predictable if (plane[p].halfSpaceContainsFinite(corner)) { @@ -189,43 +242,43 @@ bool AABox::culledBy( ++numContained; } } - } + } - if (numContained == 0) { - // Plane p culled the box - cullingPlane = p; + if (numContained == 0) { + // Plane p culled the box + cullingPlane = p; // The caller should not recurse into the children, // since the parent is culled. If they do recurse, // make them only test against this one plane, which // will immediately cull the volume. childMask = 1 << p; - return true; + return true; } else if (numContained < v) { // The bounding volume straddled the plane; we have // to keep testing against this plane childMask |= (1 << p); } - } + } // Move on to the next bit. - inMask = inMask >> 1; + inMask = inMask >> 1; } // None of the planes could cull this box - cullingPlane = -1; + cullingPlane = -1; return false; } bool AABox::culledBy( const Array& plane, - int& cullingPlane, - const uint32 _inMask) const { + int& cullingPlane, + const uint32 _inMask) const { - uint32 inMask = _inMask; - assert(plane.size() < 31); + uint32 inMask = _inMask; + assert(plane.size() < 31); const bool finite = (abs(lo.x) < G3D::finf()) && @@ -236,58 +289,60 @@ bool AABox::culledBy( (abs(hi.z) < G3D::finf()); // See if there is one plane for which all of the - // vertices are in the negative half space. + // vertices are in the negative half space. for (int p = 0; p < plane.size(); ++p) { - // Only test planes that are not masked - if ((inMask & 1) != 0) { - - bool culled = true; - Vector3 corner; + // Only test planes that are not masked + if ((inMask & 1) != 0) { + + bool culled = true; + Vector3 corner; int v; - // Assume this plane culls all points. See if there is a point - // not culled by the plane... early out when at least one point + // Assume this plane culls all points. See if there is a point + // not culled by the plane... early out when at least one point // is in the positive half space. - for (v = 0; (v < 8) && culled; ++v) { + for (v = 0; (v < 8) && culled; ++v) { // Unrolling these 3 if's into a switch decreases performance // by about 2x - corner.x = (v & 1) ? hi.x : lo.x; - corner.y = (v & 2) ? hi.y : lo.y; - corner.z = (v & 4) ? hi.z : lo.z; + corner.x = (v & 1) ? hi.x : lo.x; + corner.y = (v & 2) ? hi.y : lo.y; + corner.z = (v & 4) ? hi.z : lo.z; if (finite) { // this branch is highly predictable culled = ! plane[p].halfSpaceContainsFinite(corner); } else { culled = ! plane[p].halfSpaceContains(corner); } - } - - if (culled) { - // Plane p culled the box - cullingPlane = p; - - return true; } - } + + if (culled) { + // Plane p culled the box + cullingPlane = p; + + return true; + } + } // Move on to the next bit. - inMask = inMask >> 1; + inMask = inMask >> 1; } // None of the planes could cull this box - cullingPlane = -1; + cullingPlane = -1; return false; } + void AABox::getBounds(Sphere& s) const { s.center = center(); s.radius = extent().length() / 2; } -bool AABox::intersects(const class Sphere& sphere) const { + +bool AABox::intersects(const Sphere& sphere) const { double d = 0; //find the square of the distance diff --git a/deps/g3dlite/source/Any.cpp b/deps/g3dlite/source/Any.cpp index 92159bb18..9204f9efc 100644 --- a/deps/g3dlite/source/Any.cpp +++ b/deps/g3dlite/source/Any.cpp @@ -1,19 +1,21 @@ /** - @file Any.cpp + \file Any.cpp - @author Morgan McGuire - @author Shawn Yarbrough + \author Morgan McGuire + \author Shawn Yarbrough - @created 2006-06-11 - @edited 2010-07-24 + \created 2006-06-11 + \edited 2013-03-29 - Copyright 2000-2010, Morgan McGuire. + Copyright 2000-2013, Morgan McGuire. All rights reserved. */ #include "G3D/Any.h" #include "G3D/TextOutput.h" #include "G3D/TextInput.h" +#include "G3D/BinaryOutput.h" +#include "G3D/BinaryInput.h" #include "G3D/stringutils.h" #include "G3D/fileutils.h" #include "G3D/FileSystem.h" @@ -21,14 +23,40 @@ #include namespace G3D { +const char* Any::PAREN = "()"; +const char* Any::BRACKET = "[]"; +const char* Any::BRACE = "{}"; -std::string Any::resolveStringAsFilename() const { +static bool isContainerType(Any::Type& t) { + return (t == Any::ARRAY) || (t == Any::TABLE) || (t == Any::EMPTY_CONTAINER); +} + +void Any::serialize(BinaryOutput& b) const { + TextOutput::Settings s; + s.wordWrap = TextOutput::Settings::WRAP_NONE; + b.writeInt32(1); + b.writeString32(unparse(s)); +} + + +void Any::deserialize(BinaryInput& b) { + const int version = b.readInt32(); + alwaysAssertM(version == 1, "Wrong Any serialization version"); + _parse(b.readString32()); +} + + +std::string Any::resolveStringAsFilename(bool errorIfNotFound) const { verifyType(STRING); - std::string f = FileSystem::resolve(string(), sourceDirectory()); + if ((string().length() > 0) && (string()[0] == '<') && (string()[string().length() - 1] == '>')) { + return string(); + } + + const std::string& f = FileSystem::resolve(string(), sourceDirectory()); if (FileSystem::exists(f)) { return f; } else { - const std::string& s = System::findDataFile(string(), false); + const std::string& s = System::findDataFile(string(), errorIfNotFound); if (s.empty()) { return string(); } else { @@ -37,6 +65,47 @@ std::string Any::resolveStringAsFilename() const { } } +void Any::become(const Type& t) { + if ((t == ARRAY) || (t == TABLE)) { + debugAssert(m_type == EMPTY_CONTAINER); + m_type = t; + m_data->type = m_type; + if(t == ARRAY) { + m_data->value.a = new AnyArray(); + } else { + m_data->value.t = new AnyTable(); + } + } +} + + +void Any::remove(const std::string& key) { + verifyType(TABLE); + ensureMutable(); + m_data->value.t->remove(key); +} + + +void Any::remove(int i) { + verifyType(ARRAY); + ensureMutable(); + m_data->value.a->remove(i); +} + + +Any Any::fromFile(const std::string& filename) { + Any a; + a.load(filename); + return a; +} + + +void Any::loadIfExists(const std::string& filename) { + if (FileSystem::exists(filename)) { + load(filename); + } +} + bool Any::nameBeginsWith(const std::string& s) const { return nameBeginsWith(s.c_str()); @@ -73,7 +142,7 @@ bool Any::nameBeginsWith(const char* s) const { bool Any::nameEquals(const char* s) const { verifyType(Any::ARRAY, Any::TABLE); -#ifdef G3D_WIN32 +#ifdef G3D_WINDOWS return stricmp(name().c_str(), s) == 0; #else return strcasecmp(name().c_str(), s) == 0; @@ -86,16 +155,11 @@ void Any::beforeRead() const { if (isPlaceholder()) { // Tried to read from a placeholder--throw an exception as if // the original operator[] had failed. - KeyNotFound e; alwaysAssertM(m_data, "Corrupt placeholder"); + KeyNotFound e(m_data); - e.filename = m_data->source.filename; - e.line = m_data->source.line; - e.character = m_data->source.character; e.key = m_placeholderName; - e.message = - "This exception may have been thrown later than " - "the actual operator[] invocation."; + e.message = "Key \"" + m_placeholderName + "\" not found in operator[] lookup."; throw e; } @@ -105,13 +169,18 @@ void Any::beforeRead() const { Any::Data* Any::Data::create(const Data* d) { Data* p = create(d->type); - p->comment = d->comment; - p->name = d->name; + p->includeLine = d->includeLine; + p->bracket = d->bracket; + p->separator = d->separator; + p->comment = d->comment; + p->name = d->name; + p->source = d->source; switch (d->type) { - case NONE: + case NIL: case BOOLEAN: case NUMBER: + case EMPTY_CONTAINER: // No clone needed break; @@ -134,11 +203,11 @@ Any::Data* Any::Data::create(const Data* d) { } -Any::Data* Any::Data::create(Any::Type t) { +Any::Data* Any::Data::create(Any::Type t, const char* b, char sep) { size_t s = sizeof(Data); switch (t) { - case NONE: + case NIL: case BOOLEAN: case NUMBER: // No extra space needed @@ -148,23 +217,38 @@ Any::Data* Any::Data::create(Any::Type t) { s += sizeof(std::string); break; + case EMPTY_CONTAINER: + // We need to allocate space for the worst-case + s += max(sizeof(AnyArray), sizeof(AnyTable)); + // If no separator and brackets were provided, substitute defaults + if (b == NULL) { b = PAREN; } + if (sep == '\0') { sep = ','; } + break; + case ARRAY: s += sizeof(AnyArray); + // If no separator and brackets were provided, substitute defaults + if (b == NULL) { b = PAREN; } + if (sep == '\0') { sep = ','; } break; case TABLE: s += sizeof(AnyTable); + // If no separator and brackets were provided, substitute defaults + if (b == NULL) { b = BRACE; } + if (sep == '\0') { sep = ';'; } break; } // Allocate the data object - Data* p = new (MemoryManager::create()->alloc(s)) Data(t); + Data* p = new (MemoryManager::create()->alloc(s)) Data(t, b, sep); - // Create the (empyt) value object at the end of the Data object + // Create the (empty) value object at the end of the Data object switch (t) { - case NONE: + case NIL: case BOOLEAN: case NUMBER: + case EMPTY_CONTAINER: // No value break; @@ -179,7 +263,9 @@ Any::Data* Any::Data::create(Any::Type t) { case TABLE: p->value.t = new (p + 1) AnyTable(); break; - } + } + + if (isContainerType(p->type)) debugAssert(p->separator != '\0'); return p; } @@ -227,7 +313,10 @@ Any::Data::~Data() { bool Any::containsKey(const std::string& x) const { beforeRead(); verifyType(TABLE); - + if (size() == 0) { + //catches the case of an empty container, where value.t is null + return false; + } Any* a = m_data->value.t->getPointer(x); // Don't return true for placeholder objects @@ -255,16 +344,16 @@ void Any::ensureMutable() { } -Any::Any() : m_type(NONE), m_data(NULL) { +Any::Any() : m_type(NIL), m_data(NULL) { } -Any::Any(TextInput& t) : m_type(NONE), m_data(NULL) { +Any::Any(TextInput& t) : m_type(NIL), m_data(NULL) { deserialize(t); } -Any::Any(const Any& x) : m_type(NONE), m_data(NULL) { +Any::Any(const Any& x) : m_type(NIL), m_data(NULL) { x.beforeRead(); *this = x; } @@ -274,16 +363,16 @@ Any::Any(double x) : m_type(NUMBER), m_simpleValue(x), m_data(NULL) { } -#ifdef G3D_32BIT -Any::Any(int64 x) : m_type(NUMBER), m_simpleValue((double)x), m_data(NULL) { +Any::Any(float x) : m_type(NUMBER), m_simpleValue(double(x)), m_data(NULL) { } -#endif // G3D_32BIT +Any::Any(char x) : m_type(NUMBER), m_simpleValue(double(x)), m_data(NULL) { +} + Any::Any(long x) : m_type(NUMBER), m_simpleValue((double)x), m_data(NULL) { } - Any::Any(int x) : m_type(NUMBER), m_simpleValue((double)x), m_data(NULL) { } @@ -303,7 +392,7 @@ Any::Any(const std::string& s) : m_type(STRING), m_data(Data::create(STRING)) { Any::Any(const char* s) : m_type(STRING), m_data(NULL) { if (s == NULL) { - m_type = NONE; + m_type = NIL; } else { ensureData(); *(m_data->value.s) = s; @@ -311,13 +400,43 @@ Any::Any(const char* s) : m_type(STRING), m_data(NULL) { } -Any::Any(Type t, const std::string& name) : m_type(t), m_data(NULL) { - alwaysAssertM(t == ARRAY || t == TABLE, "Can only create ARRAY or TABLE from Type enum."); + + +Any::Any(Type t, const std::string& name, const std::string& brackets, char separator) : m_type(t), m_data(NULL) { + alwaysAssertM(isContainerType(t), "Can only create ARRAY or TABLE from Type enum."); ensureData(); if (name != "") { m_data->name = name; } + + if (brackets == "") { + if (t == ARRAY) { + m_data->bracket = PAREN; + } else { + m_data->bracket = BRACE; + } + } else if (brackets == PAREN) { + m_data->bracket = PAREN; + } else if (brackets == BRACE) { + m_data->bracket = BRACE; + } else if (brackets == BRACKET) { + m_data->bracket = BRACKET; + } else { + alwaysAssertM(false, std::string("illegal brackets: ") + brackets); + } + + if (separator == '\0') { + if (t == ARRAY) { + m_data->separator = ','; + } else { + m_data->separator = ';'; + } + } else if (separator == ',' || separator == ';') { + m_data->separator = separator; + } else { + alwaysAssertM(false, std::string("illegal separator: ") + separator); + } } @@ -329,10 +448,17 @@ Any::~Any() { void Any::beforeWrite() { if (isPlaceholder()) { // This is no longer a placeholder - m_placeholderName = ""; + m_placeholderName.clear(); + } + + if (m_data && ! m_data->includeLine.empty()) { + // Forget where this Any was included from...it no + // longer matches the contents there. + m_data->includeLine = ""; } } + Any& Any::operator=(const Any& x) { x.beforeRead(); @@ -356,48 +482,20 @@ Any& Any::operator=(const Any& x) { } -Any& Any::operator=(double x) { - *this = Any(x); - return *this; -} - - -Any& Any::operator=(int x) { - return (*this = Any(x)); -} - - -Any& Any::operator=(bool x) { - *this = Any(x); - return *this; -} - - -Any& Any::operator=(const std::string& x) { - *this = Any(x); - return *this; -} - - -Any& Any::operator=(const char* x) { - *this = Any(x); - return *this; -} - - Any& Any::operator=(Type t) { switch (t) { - case NONE: + case NIL: *this = Any(); break; - case TABLE: - case ARRAY: + case TABLE: // All 3 cases intentionally fall through + case ARRAY: + case EMPTY_CONTAINER: *this = Any(t); break; default: - alwaysAssertM(false, "Can only assign NONE, TABLE, or ARRAY Type enum."); + alwaysAssertM(false, "Can only assign NIL, TABLE, or ARRAY Type enum."); } return *this; @@ -429,18 +527,23 @@ void Any::setComment(const std::string& c) { } -bool Any::isNone() const { +bool Any::isNil() const { beforeRead(); - return (m_type == NONE); + return (m_type == NIL); } - double Any::number() const { beforeRead(); verifyType(NUMBER); return m_simpleValue.n; } +float Any::floatValue() const { + beforeRead(); + verifyType(NUMBER); + return (float)m_simpleValue.n; +} + const std::string& Any::string() const { beforeRead(); @@ -479,14 +582,14 @@ int Any::size() const { verifyType(ARRAY, TABLE); switch (m_type) { case TABLE: - return m_data->value.t->size(); + return (int)m_data->value.t->size(); case ARRAY: return m_data->value.a->size(); - default:; + default: return 0; - } // switch (m_type) + } } @@ -500,6 +603,9 @@ void Any::resize(int n) { beforeRead(); alwaysAssertM(n >= 0, "Cannot resize less than 0."); verifyType(ARRAY); + if (type() == EMPTY_CONTAINER) { + become(ARRAY); + } m_data->value.a->resize(n); } @@ -515,7 +621,6 @@ void Any::clear() { case TABLE: m_data->value.t->clear(); break; - default:; } } @@ -526,6 +631,9 @@ const Any& Any::operator[](int i) const { verifyType(ARRAY); debugAssert(m_data != NULL); Array& array = *(m_data->value.a); + if (i < 0 || i >= array.size()) { + throw IndexOutOfBounds(m_data, i, array.size()); + } return array[i]; } @@ -541,9 +649,13 @@ Any& Any::next() { Any& Any::operator[](int i) { beforeRead(); + ensureMutable(); verifyType(ARRAY); debugAssert(m_data != NULL); Array& array = *(m_data->value.a); + if (i < 0 || i >= array.size()) { + throw IndexOutOfBounds(m_data, i, array.size()); + } return array[i]; } @@ -556,22 +668,25 @@ const Array& Any::array() const { } -void Any::append(const Any& x0) { +void Any::_append(const Any& x0) { beforeRead(); verifyType(ARRAY); debugAssert(m_data != NULL); + if (type() == EMPTY_CONTAINER) { + become(ARRAY); + } m_data->value.a->append(x0); } -void Any::append(const Any& x0, const Any& x1) { +void Any::_append(const Any& x0, const Any& x1) { beforeRead(); append(x0); append(x1); } -void Any::append(const Any& x0, const Any& x1, const Any& x2) { +void Any::_append(const Any& x0, const Any& x1, const Any& x2) { beforeRead(); append(x0); append(x1); @@ -579,7 +694,7 @@ void Any::append(const Any& x0, const Any& x1, const Any& x2) { } -void Any::append(const Any& x0, const Any& x1, const Any& x2, const Any& x3) { +void Any::_append(const Any& x0, const Any& x1, const Any& x2, const Any& x3) { beforeRead(); append(x0); append(x1); @@ -592,6 +707,12 @@ const Table& Any::table() const { beforeRead(); verifyType(TABLE); debugAssert(m_data != NULL); + + if (type() == Any::EMPTY_CONTAINER) { + // if empty, m_data->value.t will not be initialized as it is unknown whether this is supposed to be an array or a table + static const Table emptyTable; + return emptyTable; + } return *(m_data->value.t); } @@ -603,13 +724,9 @@ const Any& Any::operator[](const std::string& x) const { const Table& table = *(m_data->value.t); Any* value = table.getPointer(x); if (value == NULL) { - KeyNotFound e; - if (m_data) { - e.filename = m_data->source.filename; - e.line = m_data->source.line; - e.character = m_data->source.character; - } + KeyNotFound e(m_data); e.key = x; + e.message = "Key not found in operator[] lookup."; throw e; } return *value; @@ -618,6 +735,7 @@ const Any& Any::operator[](const std::string& x) const { Any& Any::operator[](const std::string& key) { beforeRead(); + ensureMutable(); verifyType(TABLE); bool created = false; @@ -637,17 +755,20 @@ Any& Any::operator[](const std::string& key) { } -void Any::set(const std::string& k, const Any& v) { +void Any::_set(const std::string& k, const Any& v) { beforeRead(); v.beforeRead(); verifyType(TABLE); debugAssert(m_data != NULL); + if ( type() == EMPTY_CONTAINER) { + become(TABLE); + } Table& table = *(m_data->value.t); table.set(k, v); } -const Any& Any::get(const std::string& x, const Any& defaultVal) const { +Any Any::_get(const std::string& x, const Any& defaultVal) const { beforeRead(); defaultVal.beforeRead(); try { @@ -661,12 +782,13 @@ const Any& Any::get(const std::string& x, const Any& defaultVal) const { bool Any::operator==(const Any& x) const { beforeRead(); x.beforeRead(); + if (m_type != x.m_type) { return false; } switch (m_type) { - case NONE: + case NIL: return true; case BOOLEAN: @@ -687,14 +809,17 @@ bool Any::operator==(const Any& x) const { if (m_data->name != x.m_data->name) { return false; } - Table& cmptable = *( m_data->value.t); - Table& xcmptable = *(x.m_data->value.t); - for (Table::Iterator it1 = cmptable.begin(), it2 = xcmptable.begin(); - it1 != cmptable.end() && it2 != xcmptable.end(); - ++it1, ++it2) { - if (*it1 != *it2) { + const Table& table1 = table(); + const Table& table2 = x.table(); + for (Table::Iterator it = table1.begin(); it.isValid(); ++it) { + const Any* p2 = table2.getPointer(it->key); + if (p2 == NULL) { + // Key not found return false; - } + } else if (*p2 != it->value) { + // Different value + return false; + } } return true; } @@ -718,19 +843,19 @@ bool Any::operator==(const Any& x) const { } return true; } - + + case EMPTY_CONTAINER: + return true; default: alwaysAssertM(false, "Unknown type."); return false; - } // switch (m_type) + } } bool Any::operator!=(const Any& x) const { - beforeRead(); - x.beforeRead(); - return !operator==(x); + return ! operator==(x); } @@ -740,21 +865,35 @@ static void getDeserializeSettings(TextInput::Settings& settings) { settings.otherLineComments = false; settings.generateCommentTokens = true; settings.singleQuotedStrings = false; - settings.msvcFloatSpecials = false; + settings.msvcFloatSpecials = true; settings.caseSensitive = false; } -std::string Any::unparse() const { +std::string Any::unparseJSON(const TextOutput::Settings& settings, bool allowCoercion) const { + beforeRead(); + TextOutput to(settings); + serialize(to, true, allowCoercion); + return to.commitString(); +} + + +std::string Any::unparse(const TextOutput::Settings& settings) const { beforeRead(); - TextOutput::Settings settings; TextOutput to(settings); serialize(to); return to.commitString(); } -void Any::parse(const std::string& src) { +Any Any::parse(const std::string& src) { + Any a; + a._parse(src); + return a; +} + + +void Any::_parse(const std::string& src) { beforeRead(); TextInput::Settings settings; getDeserializeSettings(settings); @@ -814,16 +953,41 @@ static bool needsQuotes(const std::string& s) { } -// TODO: if the output will fit on one line, compress tables and arrays into a single line -void Any::serialize(TextOutput& to) const { +void Any::serialize(TextOutput& to, bool json, bool coerce) const { beforeRead(); + + if (m_data && ! m_data->includeLine.empty()) { + if (json) { + if (! coerce) { + throw "Could not coerce to JSON"; + } + + // Silently fall through + } else { + // This value came from a #include...preserve it. This includes the comment + // if any. + to.printf("%s", m_data->includeLine.c_str()); + return; + } + } + if (m_data && ! m_data->comment.empty()) { - to.printf("\n/* %s */\n", m_data->comment.c_str()); + if (json) { + if (! coerce) { + throw "Could not coerce to JSON"; + } + } else { + to.printf("\n/* %s */\n", m_data->comment.c_str()); + } } switch (m_type) { - case NONE: - to.writeSymbol("NONE"); + case NIL: + if (json) { + to.writeSymbol("null"); + } else { + to.writeSymbol("NIL"); + } break; case BOOLEAN: @@ -831,7 +995,24 @@ void Any::serialize(TextOutput& to) const { break; case NUMBER: - to.writeNumber(m_simpleValue.n); + if (json) { + // Specials have no legal syntax in JSON, so insert values that will parse + // to something close to what we want (there is no good solution for NaN, unfortunately) + if (m_simpleValue.n == inf()) { + to.writeSymbol("1e10000"); + } else if (m_simpleValue.n == -inf()) { + to.writeSymbol("-1e10000"); + } else if (isNaN(m_simpleValue.n)) { + if (! coerce) { + throw "There is no way to represent NaN in JSON"; + } + to.writeSymbol("null"); + } else { + to.writeNumber(m_simpleValue.n); + } + } else { + to.writeNumber(m_simpleValue.n); + } break; case STRING: @@ -841,14 +1022,26 @@ void Any::serialize(TextOutput& to) const { case TABLE: { debugAssert(m_data != NULL); + debugAssert(m_data->separator != '\0'); + if (! m_data->name.empty()) { - if (needsQuotes(m_data->name)) { - to.writeString(m_data->name); + if (json) { + if (! coerce) { + throw "Could not coerce to JSON"; + } } else { - to.writeSymbol(m_data->name); + if (needsQuotes(m_data->name)) { + to.writeString(m_data->name); + } else { + to.writeSymbol(m_data->name); + } } } - to.writeSymbol("{"); + if (json) { + to.writeSymbol("{"); + } else { + to.writeSymbol(m_data->bracket[0]); + } to.writeNewline(); to.pushIndent(); AnyTable& table = *(m_data->value.t); @@ -858,56 +1051,134 @@ void Any::serialize(TextOutput& to) const { for (int i = 0; i < keys.size(); ++i) { - to.writeSymbol(keys[i]); - to.writeSymbol("="); - table[keys[i]].serialize(to); - - if (i < keys.size() - 1) { - to.writeSymbol(","); + int prevLine = to.line(); + if (needsQuotes(keys[i]) || json) { + to.writeString(keys[i]); + } else { + to.writeSymbol(keys[i]); + } + + if (json) { + to.writeSymbol(":"); + } else { + to.writeSymbol("="); + } + table[keys[i]].serialize(to, json, coerce); + + to.deleteSpace(); + if (json) { + // Don't put a separator after the last + if (i != keys.size() - 1) { + to.writeSymbol(","); + } + } else { + to.writeSymbol(m_data->separator); + } + + // Skip an extra line between table entries that are longer than a line + if (prevLine != to.line()) { + to.writeNewline(); } - to.writeNewline(); - // Skip a line between table entries to.writeNewline(); } to.popIndent(); - to.writeSymbol("}"); + to.writeSymbol(m_data->bracket[1]); break; } case ARRAY: { debugAssert(m_data != NULL); + debugAssert(m_data->separator != '\0'); + if (! m_data->name.empty()) { - // For arrays, leave no trailing space between the name and the paren - to.writeSymbol(format("%s(", m_data->name.c_str())); + if (json) { + if (! coerce) { + throw "Could not coerce to JSON"; + } + to.writeSymbol("["); + } else { + // For arrays, leave no trailing space between the name and the paren + to.printf("%s%c", m_data->name.c_str(), m_data->bracket[0]); + } } else { - to.writeSymbol("("); + if (json) { + to.writeSymbol("["); + } else { + to.writeSymbol(m_data->bracket[0]); + } } - to.writeNewline(); + const Array& array = *(m_data->value.a); + const bool longForm = (array.size() > 0) && ((array[0].type() == ARRAY) || (array[0].type() == TABLE)); + + if (longForm) { + to.writeNewline(); + } + to.pushIndent(); - Array& array = *(m_data->value.a); for (int ii = 0; ii < size(); ++ii) { - array[ii].serialize(to); + array[ii].serialize(to, json, coerce); if (ii < size() - 1) { - to.writeSymbol(","); - to.writeNewline(); + to.deleteSpace(); + if (longForm) { + // Probably a long-form array + if (json) { + to.writeSymbol(","); + } else { + to.writeSymbol(m_data->separator); + } + to.writeNewline(); + } else { + // Probably a short-form array + if (json) { + to.writeSymbol(","); + } else { + to.writeSymbol(m_data->separator); + } + } } // Put the close paren on an array right behind the last element } to.popIndent(); - to.writeSymbol(")"); + if (json) { + to.writeSymbol("]"); + } else { + to.writeSymbol(m_data->bracket[1]); + } + break; + } + + case EMPTY_CONTAINER: { + debugAssert(m_data != NULL); + debugAssert(m_data->separator != '\0'); + + if (json) { + if (! coerce) { + throw "Cannot strictly convert the ambiguous Any empty container to JSON"; + } + to.writeSymbols("[", "]"); + } else { + if (! m_data->name.empty()) { + // Leave no trailing space between the name and the paren + to.printf("%s%c", m_data->name.c_str(), m_data->bracket[0]); + } else { + to.writeSymbol(m_data->bracket[0]); + } + to.writeSymbol(m_data->bracket[1]); + } break; } } + } void Any::deserializeComment(TextInput& ti, Token& token, std::string& comment) { // Parse comments while (token.type() == Token::COMMENT) { - comment += trimWhitespace(token.string()) + "\n"; + comment += trimWhitespace(token.string()); // Allow comments to contain newlines. do { @@ -919,6 +1190,7 @@ void Any::deserializeComment(TextInput& ti, Token& token, std::string& comment) comment = trimWhitespace(comment); } + /** True if \a c is an open paren of some form */ static bool isOpen(const char c) { return c == '(' || c == '[' || c == '{'; @@ -961,7 +1233,7 @@ void Any::deserialize(TextInput& ti) { void Any::deserialize(TextInput& ti, Token& token) { // Deallocate old data dropReference(); - m_type = NONE; + m_type = NIL; m_simpleValue.b = false; // Skip leading newlines @@ -1009,7 +1281,7 @@ void Any::deserialize(TextInput& ti, Token& token) { break; case Token::SYMBOL: - // Pragma, Named Array, Named Table, Array, Table, or NONE + // Pragma, Named Array, Named Table, Array, Table, or NIL if (token.string() == "#") { // Pragma @@ -1022,14 +1294,16 @@ void Any::deserialize(TextInput& ti, Token& token) { } ti.readSymbol("("); + // The string typed into the file, which may be relative const std::string& includeName = ti.readString(); // Find the include file - const std::string& myPath = filenamePath(ti.filename()); - std::string t = pathConcat(myPath, includeName); + const std::string& myPath = FilePath::parent(ti.filename()); + + std::string t = FileSystem::resolve(includeName, myPath); if (! FileSystem::exists(t)) { - // Try and find it, starting with cwd + // Try and find the path, starting with the cwd t = System::findDataFile(includeName); } @@ -1038,20 +1312,29 @@ void Any::deserialize(TextInput& ti, Token& token) { // Update the source information ensureData(); - m_data->source.filename += + if (! comment.empty()) { + m_data->includeLine = format("\n/* %s */\n", comment.c_str()); + } + m_data->includeLine += format("#include(\"%s\")", includeName.c_str()); + m_data->source.filename += format(" [included from %s:%d(%d)]", ti.filename().c_str(), token.line(), token.character()); ti.readSymbol(")"); - } else if (toUpper(token.string()) == "NONE") { - // Nothing left to do; we initialized to NONE originally + } else if (toUpper(token.string()) == "NIL" || token.string() == "None") { + // Nothing left to do; we initialized to NIL originally ensureData(); m_data->source.set(ti, token); + } else if (isValidIdentifier(token.string()) && !isOpen(ti.peek().string()[0]) && ti.peek().string() != "::") { + // Valid unquoted string + m_type = STRING; + ensureData(); + *(m_data->value.s) = token.string(); + m_data->source.set(ti, token); } else { // Array or Table // Parse the name - // s must have at least one element or this would not have // been parsed as a symbol std::string name; @@ -1074,7 +1357,7 @@ void Any::deserialize(TextInput& ti, Token& token) { m_data->name = name; } needRead = false; - } // if NONE + } // if NIL break; default: @@ -1107,10 +1390,11 @@ static bool isSeparator(char c) { } -void Any::readUntilCommaOrClose(TextInput& ti, Token& token) { +void Any::readUntilSeparatorOrClose(TextInput& ti, Token& token) { bool atClose = (token.type() == Token::SYMBOL) && isClose(token.string()[0]); - bool atComma = isSeparator(token.string()[0]); - while (! (atClose || atComma)) { + bool atSeparator = isSeparator(token.string()[0]); + + while (! (atClose || atSeparator)) { switch (token.type()) { case Token::NEWLINE: case Token::COMMENT: @@ -1123,28 +1407,85 @@ void Any::readUntilCommaOrClose(TextInput& ti, Token& token) { "Expected a comma or close paren"); } - // Update checks - atComma = isSeparator(token.string()[0]); + // Update checks + atSeparator = isSeparator(token.string()[0]); atClose = (token.type() == Token::SYMBOL) && isClose(token.string()[0]); } } +/** + Determines the type [TABLE, ARRAY, or EMPTY_CONTAINER] from the given TextInput + TextInput is the same at the end as it was beofr +*/ +static Any::Type findType(TextInput& ti, const char closeSymbol) { + Any::Type type = Any::NIL; + std::vector tokens; + // consumes the open symbol + Token token = ti.read(); + tokens.push_back(token); + + bool hasAnElement = false; + while (type == Any::NIL) { + if (token.type() == Token::COMMENT) { + // consumes tokens and prepares to push them back onto the TextInput + token = ti.read(); + tokens.push_back(token); + } else if ((token.type() == Token::SYMBOL) && ((token.string() == "=") || (token.string() == ":"))) { + // an '=' indicates a key = value pairing, and thus a table + type = Any::TABLE; + } else if (hasAnElement) { + // any non-comment, non-'=' token after any element indicates an array + type = Any::ARRAY; + } else if ((token.type() == Token::SYMBOL) && (token.string()[0] == closeSymbol)) { + // catches no previous element and a closing symbol (e.g []) + type = Any::EMPTY_CONTAINER; + } else { + // consumes elements, indicating one has been seen, and prepares to push them back onto TextInput + hasAnElement = true; + token = ti.read(); + tokens.push_back(token); + } + } + // pushes everything back to the TextInput + while (!tokens.empty()) { + token = tokens.back(); + ti.push(token); + tokens.pop_back(); + } + return type; +} + void Any::deserializeBody(TextInput& ti, Token& token) { - char closeSymbol = '}'; + char closeSymbol = '\0'; m_type = TABLE; const char c = token.string()[0]; - - if (c != '{') { - m_type = ARRAY; - // Chose the appropriate close symbol - closeSymbol = (c == '(') ? ')' : ']'; + + // Chose the appropriate close symbol based on the open symbol + const char* bracket; + if (c == '(') { + bracket = PAREN; + } else if (c == '[') { + bracket = BRACKET; + } else if (c == '{') { + bracket = BRACE; + } else { + debugAssertM(false, "Illegal bracket type"); + bracket = PAREN; } + closeSymbol = bracket[1]; + + // We must set the type before we allocate m_data in ensureData(). + m_type = findType(ti, closeSymbol); // Allocate the underlying data structure ensureData(); m_data->source.set(ti, token); + m_data->bracket = bracket; + + debugAssert(m_data->type == m_type); + debugAssert(m_data->separator != '\0'); // Consume the open token token = ti.read(); @@ -1157,12 +1498,12 @@ void Any::deserializeBody(TextInput& ti, Token& token) { deserializeComment(ti, token, comment); if ((token.type() == Token::SYMBOL) && (token.string()[0] == closeSymbol)) { - // We're done; this catches the case where the array is empty + // We're done; this catches the case where the container is empty break; } // Pointer the value being read - Any a = NULL; + Any a; std::string key; if (m_type == TABLE) { @@ -1175,8 +1516,8 @@ void Any::deserializeBody(TextInput& ti, Token& token) { // Consume everything up to the = sign, returning the "=" sign. token = ti.readSignificant(); - if ((token.type() != Token::SYMBOL) || (token.string() != "=")) { - throw ParseError(ti.filename(), token.line(), token.character(), "Expected ="); + if ((token.type() != Token::SYMBOL) || ((token.string() != "=") && token.string() != ":")) { + throw ParseError(ti.filename(), token.line(), token.character(), "Expected = or :"); } else { // Read the next token, which is the value (don't consume comments--we want the value pointed to by a to get those). token = ti.read(); @@ -1196,12 +1537,16 @@ void Any::deserializeBody(TextInput& ti, Token& token) { append(a); } - // Read until the comma or close paren, discarding trailing comments and newlines - readUntilCommaOrClose(ti, token); + // Read until the separator or close paren, discarding trailing comments and newlines + readUntilSeparatorOrClose(ti, token); - // Consume the comma - if (isSeparator(token.string()[0])) { + char s = token.string()[0]; + + // Consume the separator + if (isSeparator(s)) { token = ti.read(); + m_data->separator = s; + debugAssert(m_data->separator != '\0'); } } @@ -1216,6 +1561,12 @@ Any::operator int() const { } +Any::operator uint32() const { + beforeRead(); + return uint32(number() + 0.5); +} + + Any::operator float() const { beforeRead(); return float(number()); @@ -1258,7 +1609,6 @@ std::string Any::sourceDirectory() const { } } - void Any::verify(bool value, const std::string& message) const { beforeRead(); if (! value) { @@ -1286,21 +1636,109 @@ void Any::verify(bool value, const std::string& message) const { void Any::verifyName(const std::string& n) const { beforeRead(); - verify(beginsWith(toUpper(name()), toUpper(n)), "Name must begin with " + n); + verify(name() == n, "Name must be " + n); } void Any::verifyName(const std::string& n, const std::string& m) const { beforeRead(); - const std::string& x = toUpper(name()); - verify(beginsWith(x, toUpper(n)) || - beginsWith(x, toUpper(m)), "Name must begin with " + n + " or " + m); + const std::string& x = name(); + verify(x == n || + x == m, "Name must be " + n + " or " + m); +} + + +void Any::verifyName(const std::string& n, const std::string& m, const std::string& p) const { + beforeRead(); + const std::string& x = name(); + verify(x == n || + x == m || + x == p, "Name must be " + n + ", " + m + ", or " + p); +} + + +void Any::verifyName(const std::string& n, const std::string& m, const std::string& p, const std::string& q) const { + beforeRead(); + const std::string& x = name(); + verify(x == n || + x == m || + x == p || + x == q, "Name must be " + n + ", " + m + ", " + p + ", or " + q); +} + + +void Any::verifyNameBeginsWith(const std::string& n) const { + beforeRead(); + verify(beginsWith(name(), n), "Name must begin with " + n); +} + + +void Any::verifyNameBeginsWith(const std::string& n, const std::string& m) const { + beforeRead(); + const std::string& x = name(); + verify(beginsWith(x, n) || + beginsWith(x, m), "Name must be " + n + " or " + m); +} + + +void Any::verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p) const { + beforeRead(); + const std::string& x = name(); + verify(beginsWith(x, n) || + beginsWith(x, m) || + beginsWith(x, p), "Name must be " + n + ", " + m + ", or " + p); +} + + +void Any::verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q) const { + beforeRead(); + const std::string& x = name(); + verify(beginsWith(x, n) || + beginsWith(x, m) || + beginsWith(x, p) || + beginsWith(x, q), "Name must be " + n + ", " + m + ", " + p + ", or " + q); +} + + +void Any::verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q, const std::string& r) const { + beforeRead(); + const std::string& x = name(); + verify(beginsWith(x, n) || + beginsWith(x, m) || + beginsWith(x, p) || + beginsWith(x, q) || + beginsWith(x, r), "Name must be " + n + ", " + m + ", " + p + ", or " + q + ", or " + r); +} + + +void Any::verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q, const std::string& r, const std::string& s) const { + beforeRead(); + const std::string& x = name(); + verify(beginsWith(x, n) || + beginsWith(x, m) || + beginsWith(x, p) || + beginsWith(x, q) || + beginsWith(x, r) || + beginsWith(x, s), "Name must be " + n + ", " + m + ", " + p + ", or " + q + ", or " + r + ", or " + s); +} + + +void Any::verifyNameBeginsWith(const std::string& n, const std::string& m, const std::string& p, const std::string& q, const std::string& r, const std::string& s, const std::string& t) const { + beforeRead(); + const std::string& x = name(); + verify(beginsWith(x, n) || + beginsWith(x, m) || + beginsWith(x, p) || + beginsWith(x, q) || + beginsWith(x, r) || + beginsWith(x, s) || + beginsWith(x, t), "Name must be " + n + ", " + m + ", " + p + ", or " + q + ", or " + r + ", or " + s + ", or " + t); } void Any::verifyType(Type t) const { beforeRead(); - if (type() != t) { + if ((type() != t) && ! ((type() == EMPTY_CONTAINER) && isContainerType(t))) { verify(false, "Must have type " + toString(t)); } } @@ -1308,7 +1746,8 @@ void Any::verifyType(Type t) const { void Any::verifyType(Type t0, Type t1) const { beforeRead(); - if (type() != t0 && type() != t1) { + if ((type() != t0 && !((type() == EMPTY_CONTAINER) && isContainerType(t0))) && + (type() != t1 && !((type() == EMPTY_CONTAINER) && isContainerType(t1)))) { verify(false, "Must have type " + toString(t0) + " or " + toString(t1)); } } @@ -1334,7 +1773,7 @@ void Any::verifySize(int s) const { std::string Any::toString(Type t) { switch(t) { - case NONE: return "NONE"; + case NIL: return "NIL"; case BOOLEAN: return "BOOLEAN"; case NUMBER: return "NUMBER"; case STRING: return "STRING"; diff --git a/deps/g3dlite/source/AnyTableReader.cpp b/deps/g3dlite/source/AnyTableReader.cpp new file mode 100644 index 000000000..7fff1983e --- /dev/null +++ b/deps/g3dlite/source/AnyTableReader.cpp @@ -0,0 +1,50 @@ +#include "G3D/Any.h" + +namespace G3D { + +/** Verifies that \a is a TABLE with the given \a name. */ +AnyTableReader::AnyTableReader(const std::string& name, const Any& a) : m_any(a) { + try { + m_any.verifyType(Any::TABLE); + m_any.verifyName(name); + } catch (const ParseError& e) { + // If an exception is thrown, the destructors will not be + // invoked automatically. + m_any.~Any(); + m_alreadyRead.~Set(); + throw e; + } +} + + +AnyTableReader::AnyTableReader(const Any& a) : m_any(a) { + try { + m_any.verifyType(Any::TABLE); + } catch (const ParseError& e) { + // If an exception is thrown, the destructors will not be + // invoked automatically. + m_any.~Any(); + m_alreadyRead.~Set(); + throw e; + } +} + + +void AnyTableReader::verifyDone() const { + if (hasMore()) { + // Some entries were unread. Find them. + const Table& table = m_any.table(); + + for (Table::Iterator it = table.begin(); + it.hasMore(); + ++it) { + + if (containsUnread(it->key)) { + it->value.verify(false, std::string("Unread Any table key \"") + it->key + "\""); + } + } + } +} + + +} // namespace G3D diff --git a/deps/g3dlite/source/AreaMemoryManager.cpp b/deps/g3dlite/source/AreaMemoryManager.cpp index 00cb33dc9..33e5099c3 100644 --- a/deps/g3dlite/source/AreaMemoryManager.cpp +++ b/deps/g3dlite/source/AreaMemoryManager.cpp @@ -43,7 +43,7 @@ bool AreaMemoryManager::isThreadsafe() const { AreaMemoryManager::Ref AreaMemoryManager::create(size_t sizeHint) { - return new AreaMemoryManager(sizeHint); + return shared_ptr(new AreaMemoryManager(sizeHint)); } @@ -80,7 +80,7 @@ void AreaMemoryManager::free(void* x) { void AreaMemoryManager::deallocateAll() { - m_bufferArray.deleteAll(); + m_bufferArray.invokeDeleteOnAllElements(); m_bufferArray.clear(); } diff --git a/deps/g3dlite/source/BinaryInput.cpp b/deps/g3dlite/source/BinaryInput.cpp index 19ab2722c..c6eafa5ce 100644 --- a/deps/g3dlite/source/BinaryInput.cpp +++ b/deps/g3dlite/source/BinaryInput.cpp @@ -1,11 +1,11 @@ /** - @file BinaryInput.cpp + \file BinaryInput.cpp - @author Morgan McGuire, graphics3d.com - Copyright 2001-2007, Morgan McGuire. All rights reserved. + \author Morgan McGuire, graphics3d.com + Copyright 2001-2013, Morgan McGuire. All rights reserved. - @created 2001-08-09 - @edited 2010-03-05 + \created 2001-08-09 + \edited 2013-01-03
    @@ -40,154 +40,17 @@
     #include "G3D/FileSystem.h"
     #include 
     #if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
    -  #include "zip.h"
    +#include "../../zip.lib/include/zip.h"
     #endif
     #include 
     
     namespace G3D {
     
    -void BinaryInput::readBool8(std::vector& 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& out, int64 n) {
    -    out.resize(n);
    -    readBool8(out.begin(), n);
    -}
    -
    -
    -#define IMPLEMENT_READER(ucase, lcase)\
    -void BinaryInput::read##ucase(std::vector& out, int64 n) {\
    -    out.resize(n);\
    -    read##ucase(&out[0], n);\
    -}\
    -\
    -\
    -void BinaryInput::read##ucase(Array& 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 != "", "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(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) {
    +static uint32 readUInt32FromBuffer(const uint8* data, bool swapBytes) {
         if (swapBytes) {
             uint8 out[4];
             out[0] = data[3];
    @@ -201,12 +64,6 @@ static uint32 readUInt32(const uint8* data, bool swapBytes) {
     }
     
     
    -void BinaryInput::setEndian(G3DEndian e) {
    -    m_fileEndian = e;
    -    m_swapBytes = needSwapBytes(m_fileEndian);
    -}
    -
    -
     BinaryInput::BinaryInput(
         const uint8*        data,
         int64               dataLen,
    @@ -227,26 +84,26 @@ BinaryInput::BinaryInput(
     
         if (compressed) {
             // Read the decompressed size from the first 4 bytes
    -        m_length = G3D::readUInt32(data, m_swapBytes);
    +        m_length = readUInt32FromBuffer(data, m_swapBytes);
     
             debugAssert(m_freeBuffer);
             m_buffer = (uint8*)System::alignedMalloc(m_length, 16);
     
    -        unsigned long L = m_length;
    +        unsigned long L = (unsigned long)m_length;
             // Decompress with zlib
    -        int64 result = uncompress(m_buffer, (unsigned long*)&L, data + 4, dataLen - 4);
    +        int64 result = uncompress(m_buffer, &L, data + 4, (uLong)dataLen - 4);
             m_length = L;
             m_bufferLength = L;
             debugAssert(result == Z_OK); (void)result;
     
         } else {
    -    	m_length = dataLen;
    +        m_length = dataLen;
             m_bufferLength = m_length;
             if (! copyMemory) {
    - 	        debugAssert(!m_freeBuffer);
    +            debugAssert(!m_freeBuffer);
                 m_buffer = const_cast(data);
             } else {
    -	        debugAssert(m_freeBuffer);
    +            debugAssert(m_freeBuffer);
                 m_buffer = (uint8*)System::alignedMalloc(m_length, 16);
                 System::memcpy(m_buffer, data, dataLen);
             }
    @@ -254,10 +111,10 @@ BinaryInput::BinaryInput(
     }
     
     
    -BinaryInput::BinaryInput(
    -    const std::string&  filename,
    -    G3DEndian           fileEndian,
    -    bool                compressed) :
    +BinaryInput::BinaryInput
    +(const std::string&  filename,
    + G3DEndian           fileEndian,
    + bool                compressed) :
         m_filename(filename),
         m_bitPos(0),
         m_bitString(0),
    @@ -270,18 +127,16 @@ BinaryInput::BinaryInput(
         m_freeBuffer(true) {
     
         setEndian(fileEndian);
    -
    -    // Update global file tracker
    -    _internal::currentFilesUsed.insert(m_filename);
         
    -
     #if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
         std::string zipfile;
         if (FileSystem::inZipfile(m_filename, zipfile)) {
             // Load from zipfile
    -//        zipRead(filename, v, s);
    +        FileSystem::markFileUsed(m_filename);
    +        FileSystem::markFileUsed(zipfile);
     
    -        std::string internalFile = m_filename.substr(zipfile.length() + 1);
    +        // Zipfiles require Unix-style slashes
    +        std::string internalFile = FilePath::canonicalize(m_filename.substr(zipfile.length() + 1));
             struct zip* z = zip_open(zipfile.c_str(), ZIP_CHECKCONS, NULL);
             {
                 struct zip_stat info;
    @@ -291,29 +146,31 @@ BinaryInput::BinaryInput(
                 // sets machines up to use MMX, if they want
                 m_buffer = reinterpret_cast(System::alignedMalloc(m_length, 16));
                 struct zip_file* zf = zip_fopen( z, internalFile.c_str(), ZIP_FL_NOCASE );
    -            {
    -                int64 test = zip_fread( zf, m_buffer, m_length );
    -                debugAssertM(test == m_length,
    +            if (zf == NULL) {
    +                throw std::string("\"") + internalFile + "\" inside \"" + zipfile + "\" could not be opened.";
    +            } else {
    +                const int64 bytesRead = zip_fread( zf, m_buffer, m_length );
    +                debugAssertM(bytesRead == m_length,
                                  internalFile + " was corrupt because it unzipped to the wrong size.");
    -                (void)test;
    +                (void)bytesRead;
    +                zip_fclose( zf );
                 }
    -            zip_fclose( zf );
             }
             zip_close( z );
     
             if (compressed) {
                 decompress();
             }
    +
             m_freeBuffer = true;
             return;
         }
     #endif
    -
         // Figure out how big the file is and verify that it exists.
         m_length = FileSystem::size(m_filename);
     
         // Read the file into memory
    -    FILE* file = fopen(m_filename.c_str(), "rb");
    +    FILE* file = FileSystem::fopen(m_filename.c_str(), "rb");
     
         if (! file || (m_length == -1)) {
             throw format("File not found: \"%s\"", m_filename.c_str());
    @@ -346,8 +203,8 @@ BinaryInput::BinaryInput(
         }
         debugAssert(m_buffer);
         
    -    fread(m_buffer, m_bufferLength, sizeof(int8), file);
    -    fclose(file);
    +    (void)fread(m_buffer, m_bufferLength, sizeof(int8), file);
    +    FileSystem::fclose(file);
         file = NULL;
     
         if (compressed) {
    @@ -359,13 +216,36 @@ BinaryInput::BinaryInput(
         }
     }
     
    +BinaryInput::~BinaryInput() {
    +
    +    if (m_freeBuffer) {
    +        System::alignedFree(m_buffer);
    +    }
    +    m_buffer = NULL;
    +}
    +
    +
    +std::string BinaryInput::readFixedLengthString(int numBytes) {
    +    Array str;
    +    str.resize(numBytes + 1);
    +
    +    // Ensure NULL termination
    +    str.last() = '\0';
    +
    +    readBytes(str.getCArray(), numBytes);
    +
    +    // Copy up to the first NULL
    +    return std::string(str.getCArray());
    +}
    +
    +
     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);
    +    m_length = readUInt32FromBuffer(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");
    @@ -377,8 +257,8 @@ void BinaryInput::decompress() {
         debugAssert(isValidHeapPointer(tempBuffer));
         debugAssert(isValidHeapPointer(m_buffer));
         
    -    unsigned long L = m_length;
    -    int64 result = uncompress(m_buffer, &L, tempBuffer + 4, tempLength - 4);
    +    unsigned long L = (unsigned long)m_length;
    +    int64 result = (int64)uncompress(m_buffer, &L, tempBuffer + 4, (uLong)tempLength - 4);
         m_length = L;
         m_bufferLength = m_length;
         
    @@ -389,6 +269,70 @@ void BinaryInput::decompress() {
     }
     
     
    +void BinaryInput::setEndian(G3DEndian e) {
    +    m_fileEndian = e;
    +    m_swapBytes = (m_fileEndian != System::machineEndian());
    +}
    +
    +
    +void BinaryInput::loadIntoMemory(int64 startPosition, int64 minLength) {
    +    // Load the next section of the file
    +    debugAssertM(m_filename != "", "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_WINDOWS
    +        FILE* file = fopen(m_filename.c_str(), "rb");
    +        debugAssert(file);
    +        size_t 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(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);
    +}
    +
    +
    +void BinaryInput::prepareToRead(int64 nbytes) {
    +    debugAssertM(m_length > 0, m_filename + " not found or corrupt.");
    +    debugAssertM(m_pos + nbytes + m_alreadyRead <= m_length, "Read past end of file.");
    +
    +    if (m_pos + nbytes > m_bufferLength) {
    +        loadIntoMemory(m_pos + m_alreadyRead, nbytes);    
    +    }
    +}
    +
    +
     void BinaryInput::readBytes(void* bytes, int64 n) {
         prepareToRead(n);
         debugAssert(isValidPointer(bytes));
    @@ -398,14 +342,6 @@ void BinaryInput::readBytes(void* bytes, int64 n) {
     }
     
     
    -BinaryInput::~BinaryInput() {
    -
    -    if (m_freeBuffer) {
    -        System::alignedFree(m_buffer);
    -    }
    -    m_buffer = NULL;
    -}
    -
     
     uint64 BinaryInput::readUInt64() {
         prepareToRead(8);
    @@ -429,52 +365,47 @@ uint64 BinaryInput::readUInt64() {
     }
     
     
    -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);
    +std::string BinaryInput::readString(int64 maxLength) {
    +    prepareToRead(maxLength);
     
    -    memcpy(s, m_buffer + m_pos, n);
    -    // There may not be a null, so make sure
    -    // we add one.
    -    s[n] = '\0';
    +    int64 n = 0;
    +    while ((m_buffer[m_pos + n] != '\0') && (n != maxLength)) {
    +        ++n;
    +    }
     
    -    std::string out = s;
    -    System::alignedFree(s);
    -    s = NULL;
    +    std::string s((char*)(m_buffer + m_pos), n);
     
    -    m_pos += n;
    -
    -    return out;
    +    m_pos += maxLength;
     
    +    return s;
     }
     
     
     std::string BinaryInput::readString() {
    +    prepareToRead(1);
    +
         int64 n = 0;
    +    bool hasNull = true;
     
    -    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')) {
    -
    +    while(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;
    +        if ((m_pos + m_alreadyRead + n) == m_length) {
    +            hasNull = false;
    +            break;
             }
    +
    +        prepareToRead(n + 1);
         }
     
    -    // Consume NULL
    -    ++n;
    +    std::string s((char*)(m_buffer + m_pos), n);
    +    m_pos += n;
     
    -    return readString(n);
    +    if (hasNull) {
    +        skip(1);
    +    }
    +    
    +    return s;
     }
     
     static bool isNewline(char c) {
    @@ -482,32 +413,48 @@ static bool isNewline(char c) {
     }
     
     std::string BinaryInput::readStringNewline() {
    +    prepareToRead(1);
    +
         int64 n = 0;
    +    bool hasNull = true;
    +    bool hasNewline = false;
     
    -    if ((m_pos + m_alreadyRead + n) < (m_length - 1)) {
    -        prepareToRead(1);
    -    }
    +    while(m_buffer[m_pos + n] != '\0') {
    +        if ((m_pos + m_alreadyRead + n + 1) == m_length) {
    +            hasNull = false;
    +            break;
    +        }
     
    -    if ( ((m_pos + m_alreadyRead + n) < (m_length - 1)) &&
    -         ! isNewline(m_buffer[m_pos + n])) {
    +        if (isNewline(m_buffer[m_pos + n])) {
    +            hasNull = false;
    +            hasNewline = true;
    +            break;
    +        }
     
             ++n;
    -        while ( ((m_pos + m_alreadyRead + n) < (m_length - 1)) &&
    -                ! isNewline(m_buffer[m_pos + n])) {
    -
    -            prepareToRead(1);
    -            ++n;
    -        }
    +        prepareToRead(n + 1);
         }
     
    -    const std::string s = readString(n);
    +    std::string s((char*)(m_buffer + m_pos), n);
    +    m_pos += n;
     
    -    // Consume the newline
    -    char firstNLChar = readUInt8();
    -
    -    // Consume the 2nd newline
    -    if (isNewline(m_buffer[m_pos + 1]) && (m_buffer[m_pos + 1] != firstNLChar)) {
    -        readUInt8();
    +    if (hasNull) {
    +        skip(1);
    +    }
    +    
    +    if (hasNewline) {
    +        if ((m_pos + m_alreadyRead + 2) != m_length) {
    +            prepareToRead(2);
    +            if (m_buffer[m_pos] == '\r' && m_buffer[m_pos + 1] == '\n') {
    +                skip(2);
    +            } else if (m_buffer[m_pos] == '\n' && m_buffer[m_pos + 1] == '\r') {
    +                skip(2);
    +            } else {
    +                skip(1);
    +            }
    +        } else {
    +            skip(1);
    +        }
         }
     
         return s;
    @@ -516,7 +463,7 @@ std::string BinaryInput::readStringNewline() {
     
     std::string BinaryInput::readStringEven() {
         std::string x = readString();
    -    if (hasMore() && (G3D::isOdd(x.length() + 1))) {
    +    if (hasMore() && (G3D::isOdd((int)x.length() + 1))) {
             skip(1);
         }
         return x;
    @@ -618,4 +565,90 @@ void BinaryInput::endBits() {
         m_bitPos = 0;
     }
     
    +
    +void BinaryInput::readBool8(std::vector& 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& out, int64 n) {
    +    out.resize(n);
    +    readBool8(out.begin(), n);
    +}
    +
    +
    +#define IMPLEMENT_READER(ucase, lcase)\
    +void BinaryInput::read##ucase(std::vector& out, int64 n) {\
    +    out.resize(n);\
    +    read##ucase(&out[0], n);\
    +}\
    +\
    +\
    +void BinaryInput::read##ucase(Array& 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
    +
    +} // namespace G3D
    +
    diff --git a/deps/g3dlite/source/BinaryOutput.cpp b/deps/g3dlite/source/BinaryOutput.cpp
    index 81fa98222..b174751c8 100644
    --- a/deps/g3dlite/source/BinaryOutput.cpp
    +++ b/deps/g3dlite/source/BinaryOutput.cpp
    @@ -2,7 +2,7 @@
      @file BinaryOutput.cpp
      
      @author Morgan McGuire, http://graphics.cs.williams.edu
    - Copyright 2002-2010, Morgan McGuire, All rights reserved.
    + Copyright 2002-2011, Morgan McGuire, All rights reserved.
      
      @created 2002-02-20
      @edited  2010-03-17
    @@ -22,10 +22,6 @@
     #    include 
     #endif
     
    -#ifdef __CYGWIN__
    -#    include 
    -#endif
    -
     // Largest memory buffer that the system will use for writing to
     // disk.  After this (or if the system runs out of memory)
     // chunks of the file will be dumped to disk.
    @@ -121,10 +117,11 @@ void BinaryOutput::reallocBuffer(size_t bytes, size_t oldBufferLen) {
         uint8* newBuffer = NULL;
     
         if ((m_filename == "") || (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.
    +        // 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); 
    +        // debugPrintf("  realloc(%d)\n", newBufferLen); 
             newBuffer = (uint8*)System::realloc(m_buffer, newBufferLen);
             if (newBuffer != NULL) {
                 m_maxBufferLen = newBufferLen;
    @@ -134,9 +131,11 @@ void BinaryOutput::reallocBuffer(size_t bytes, size_t oldBufferLen) {
         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.
    +        alwaysAssertM(m_filename != "", "Realloc failed while writing to memory.");
             m_bufferLen = oldBufferLen;
             reserveBytesWhenOutOfMemory(bytes);
         } else {
    +        // Realloc succeeded
             m_buffer = newBuffer;
             debugAssert(isValidHeapPointer(m_buffer));
         }
    @@ -152,7 +151,7 @@ void BinaryOutput::reserveBytesWhenOutOfMemory(size_t bytes) {
     
             // 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;
    +        size_t writeBytes = m_bufferLen - 10 * 1024 * 1024;
     
             if (writeBytes < m_bufferLen / 3) {
                 // We're going to write less than 1/3 of the file;
    @@ -164,11 +163,12 @@ void BinaryOutput::reserveBytesWhenOutOfMemory(size_t bytes) {
             //debugPrintf("Writing %d bytes to disk\n", writeBytes);
     
             const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb";
    +        alwaysAssertM(m_filename != "", "Writing memory file");
             FILE* file = FileSystem::fopen(m_filename.c_str(), mode);
             debugAssert(file);
     
             size_t count = fwrite(m_buffer, 1, writeBytes, file);
    -        debugAssert((int)count == writeBytes); (void)count;
    +        debugAssert(count == writeBytes); (void)count;
     
             fclose(file);
             file = NULL;
    @@ -181,7 +181,7 @@ void BinaryOutput::reserveBytesWhenOutOfMemory(size_t bytes) {
             debugAssert(m_bufferLen < m_maxBufferLen);
             debugAssert(m_bufferLen >= 0);
             debugAssert(m_pos >= 0);
    -        debugAssert(m_pos <= m_bufferLen);
    +        debugAssert(m_pos <= (int64)m_bufferLen);
     
             // Shift the unwritten data back appropriately in the buffer.
             debugAssert(isValidHeapPointer(m_buffer));
    @@ -273,45 +273,49 @@ bool BinaryOutput::ok() const {
     }
     
     
    -void BinaryOutput::compress() {
    +void BinaryOutput::compress(int level) {
         if (m_alreadyWritten > 0) {
             throw "Cannot compress huge files (part of this file has already been written to disk).";
         }
    +    debugAssertM(! m_committed, "Cannot compress after committing.");
    +    alwaysAssertM(m_bufferLen < 0xFFFFFFFF, "Compress only works for 32-bit files.");
     
    -    // Old buffer size
    -    int L = m_bufferLen;
    -    uint8* convert = (uint8*)&L;
    +    // This is the worst-case size, as mandated by zlib
    +    unsigned long compressedSize = iCeil(m_bufferLen * 1.001) + 12;
     
    -    // 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); 
    +    // Save the old buffer and reallocate to the worst-case size
    +    const uint8* src     = m_buffer;
    +    const uint32 srcSize = (uint32)m_bufferLen;
    +
    +    // add space for the 4-byte header
    +    m_maxBufferLen = compressedSize + 4;
    +    m_buffer = (uint8*)System::malloc(m_maxBufferLen);
    +    
    +    // Write the header containing the old buffer size, which is needed for decompression
    +    {
    +        const uint8* convert = (const uint8*)&srcSize;
    +        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];
    +        }
    +    }
    +
    +    // Compress and write after the header
    +    int result = compress2(m_buffer + 4, &compressedSize, src, srcSize, iClamp(level, 0, 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_bufferLen = compressedSize + 4;
         m_pos = m_bufferLen;
     
    -    System::free(temp);
    +    // Free the old data
    +    System::free((void*)src);
     }
     
     
    @@ -320,6 +324,10 @@ void BinaryOutput::commit(bool flush) {
         m_committed = true;
         debugAssertM(m_beginEndBits == 0, "Missing endBits before commit");
     
    +    if (m_filename == "") {
    +        return;
    +    }
    +
         // Make sure the directory exists.
         std::string root, base, ext, path;
         Array pathArray;
    @@ -332,6 +340,7 @@ void BinaryOutput::commit(bool flush) {
     
         const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb";
     
    +    alwaysAssertM(m_filename != "", "Writing to memory file");
         FILE* file = FileSystem::fopen(m_filename.c_str(), mode);
     
         if (! file) {
    @@ -345,7 +354,7 @@ void BinaryOutput::commit(bool flush) {
             if (m_buffer != NULL) {
                 m_alreadyWritten += m_bufferLen;
     
    -            int success = fwrite(m_buffer, m_bufferLen, 1, file);
    +            size_t success = fwrite(m_buffer, m_bufferLen, 1, file);
                 (void)success;
                 debugAssertM(success == 1, std::string("Could not write to '") + m_filename + "'");
             }
    @@ -427,7 +436,7 @@ void BinaryOutput::writeUInt64(uint64 u) {
     
     void BinaryOutput::writeString(const char* s) {
         // +1 is because strlen doesn't count the null
    -    int len = strlen(s) + 1;
    +    size_t len = strlen(s) + 1;
     
         debugAssert(m_beginEndBits == 0);
         reserveBytes(len);
    @@ -438,7 +447,7 @@ void BinaryOutput::writeString(const char* s) {
     
     void BinaryOutput::writeStringEven(const char* s) {
         // +1 is because strlen doesn't count the null
    -    int len = strlen(s) + 1;
    +    size_t len = strlen(s) + 1;
     
         reserveBytes(len);
         System::memcpy(m_buffer + m_pos, s, len);
    @@ -452,8 +461,14 @@ void BinaryOutput::writeStringEven(const char* s) {
     
     
     void BinaryOutput::writeString32(const char* s) {
    -    writeUInt32(strlen(s) + 1);
    -    writeString(s);
    +    // Write the NULL and count it
    +    size_t len = strlen(s) + 1;
    +    writeUInt32((uint32)len);
    +
    +    debugAssert(m_beginEndBits == 0);
    +    reserveBytes(len);
    +    System::memcpy(m_buffer + m_pos, s, len);
    +    m_pos += len;
     }
     
     
    diff --git a/deps/g3dlite/source/Box.cpp b/deps/g3dlite/source/Box.cpp
    index f7c112ae3..3ee3dc040 100644
    --- a/deps/g3dlite/source/Box.cpp
    +++ b/deps/g3dlite/source/Box.cpp
    @@ -1,11 +1,11 @@
     /**
    -  @file Box.cpp
    +  \file G3D.lib/source/Box.cpp
       Box class
     
    -  @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    +  \maintainer Morgan McGuire, http://graphics.cs.williams.edu, Michael Mara
     
    -  @created 2001-06-02
    -  @edited  2006-02-05
    +  \created 2001-06-02
    +  \edited  2013-04-13
     */
     
     #include "G3D/Box.h"
    @@ -13,126 +13,207 @@
     #include "G3D/Plane.h"
     #include "G3D/AABox.h"
     #include "G3D/CoordinateFrame.h"
    +#include "G3D/vectorMath.h"
    +#include "G3D/Any.h"
     
     namespace G3D {
     
    -/**
    - Sets a field on four vertices.  Used by the constructor.
    - */
    -#define setMany(i0, i1, i2, i3, field, extreme) \
    -    _corner[i0].field = _corner[i1].field = \
    -    _corner[i2].field = _corner[i3].field = \
    -    (extreme).field
    +Box::Box() : _area(0), _volume(0) {
    +}
     
    -Box::Box() {
    +
    +Box::Box
    +   (const Point3& min,
    +    const Point3& max) {
    +    init(min.min(max), min.max(max));
    +}
    +
    +
    +Box::Box(const Point3& min) {
    +    init(min, min);
    +}
    +
    +
    +Box::Box
    +   (const Point3& min,
    +    const Point3& max,
    +    const CFrame& c) {
    +    init(min.min(max), min.max(max));
    +    *this = c.toWorldSpace(*this);
     }
     
     
     Box::Box(const AABox& b) {
    +    debugAssert(! b.isEmpty());
         init(b.low(), b.high());
     }
     
    -Box::Box(class BinaryInput& b) {
    -	deserialize(b);	
    +
    +Box::Box(BinaryInput& b) {
    +    deserialize(b);    
     }
     
     
    -void Box::serialize(class BinaryOutput& b) const {
    -	int i;
    -	for (i = 0; i < 8; ++i) {
    -		_corner[i].serialize(b);
    -	}
    +Box::Box(const Any& a) {
    +    if (a.name() == "Box::inf") {
    +        *this = Box::inf();
    +    } else {
    +        a.verifyName("Box", "AABox", "Point3");
    +
    +        if (a.name() == "Point3") {
    +            *this = Box(Point3(a));
    +        } else if (a.size() == 1) {
    +            // Single point
    +            *this = Box(Point3(a[0]));
    +        } else if (a.size() == 2) {
    +            *this = Box(Point3(a[0]), Point3(a[1]));
    +        } else {
    +            // Oriented box
    +            a.verifySize(2);
    +            a.verifyName("Box");
    +            *this = Box(Point3(a[0]), Point3(a[1]), CFrame(a[2]));
    +        }
    +    }
    +}
    +
    +
    +Any Box::toAny() const {
    +    if (! isFinite()) {
    +        return Any(Any::ARRAY, "Box::inf");
    +    } else {
    +        CFrame c;
    +        getLocalFrame(c);
    +        if (c.rotation == Matrix3::identity()) {
    +            // Aligned box
    +            AABox b;
    +            getBounds(b);
    +            return b.toAny();
    +        } else {
    +            // Oriented box
    +            Any a(Any::ARRAY, "Box");
    +
    +            AABox b;
    +            c.toObjectSpace(*this).getBounds(b);
    +            a.append(b.low(), b.high(), c);
    +            return a;
    +        }
    +    }
    +}
    +
    +
    +Box Box::operator*(float f) const {
    +    Box b;
    +
    +    for (int i = 0; i < 3; ++i) {
    +        b._edgeVector[i] = _edgeVector[i] * f;
    +        b._center = _center * f;
    +        b._area = _area * square(f * f);
    +        b._volume = _area * (f * f * f);
    +    }
    +
    +    return b;
    +}
    +
    +
    +void Box::serialize(BinaryOutput& b) const {
    +    int i;
    +    for (i = 0; i < 3; ++i) {
    +        _edgeVector[i].serialize(b);
    +    }
    +    _center.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];
    -
    +    int i;
         for (i = 0; i < 3; ++i) {
    -        _extent[i] = _axis[i].magnitude();
    -        _axis[i] /= _extent[i];
    +        _edgeVector[i].deserialize(b);
         }
    +    _center.deserialize(b);
     
    -    _volume = _extent.x * _extent.y * _extent.z;
    +    float extent0 = extent(0);
    +    float extent1 = extent(1);
    +    float extent2 = extent(2);
    +    _volume = extent0 * extent1 * extent2;
     
         _area = 2 * 
    -        (_extent.x * _extent.y +
    -         _extent.y * _extent.z +
    -         _extent.z * _extent.x);
    +        (extent0 * extent1 +
    +         extent1 * extent2 +
    +         extent2 * extent0);
     }
     
     
    -Box::Box(
    -    const Vector3& min,
    -    const Vector3& max) {
    -
    -    init(min.min(max), min.max(max));
    -
    -}
    -
    -void Box::init(
    -    const Vector3& min,
    -    const Vector3& max) {
    +void Box::init
    +   (const Point3& min,
    +    const Point3& 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);
    +    _center = (max + min) * 0.5f;
     
    -    setMany(1, 2, 5, 6, x, max);
    -    setMany(0, 3, 4, 7, x, min);
    +    Vector3 bounds = Vector3(max.x - min.x, max.y - min.y, max.z - min.z);
    +    _edgeVector[0] = Vector3(bounds.x, 0, 0);
    +    _edgeVector[1] = Vector3(0, bounds.y, 0);
    +    _edgeVector[2] = Vector3(0, 0, bounds.z);
    +    bool finiteExtent = true;
    +    
    +    for (int i = 0; i < 3; ++i) {
    +        if (! G3D::isFinite(extent(i))) {
    +            finiteExtent = false;
    +            // If the extent is infinite along an axis, make the center zero to avoid NaNs
    +            _center[i] = 0.0f;
    +        }
    +    }
     
    -    setMany(3, 2, 6, 7, y, max);
    -    setMany(0, 1, 5, 4, y, min);
     
    -    _extent = max - min;
    -
    -    _axis[0] = Vector3::unitX();
    -    _axis[1] = Vector3::unitY();
    -    _axis[2] = Vector3::unitZ();
    -
    -    if (_extent.isFinite()) {
    -        _volume = _extent.x * _extent.y * _extent.z;
    +    if (finiteExtent) {
    +        _volume = bounds.x * bounds.y * bounds.z;
         } else {
             _volume = G3D::finf();
         }
     
    -    debugAssert(! isNaN(_extent.x));
    +    debugAssert(! _edgeVector[0].isNaN());
     
         _area = 2 * 
    -        (_extent.x * _extent.y +
    -         _extent.y * _extent.z +
    -         _extent.z * _extent.x);
    -
    -    _center = (max + min) * 0.5f;
    -
    -    // If the extent is infinite along an axis, make the center zero to avoid NaNs
    -    for (int i = 0; i < 3; ++i) {
    -        if (! G3D::isFinite(_extent[i])) {
    -            _center[i] = 0.0f;
    -        }
    -    }
    +        (bounds.x * bounds.y +
    +         bounds.y * bounds.z +
    +         bounds.z * bounds.x);
     }
     
     
    +Vector3 Box::corner(int i) const{
    +    debugAssert(i < 8);
    +    // The corner forms a bit mask (xyz), where a one indicates we should
    +    // add half of the corresponding edge vector from center, and a zero indicates 
    +    // we should subtract it. Note:
    +    // 1 = 001
    +    // 2 = 010
    +    // 4 = 100
    +    // 
    +    // The following bit-hacky code shows this directly:
    +    // return _center + ((_edgeVector[0] * ((i&1) - 0.5) +
    +    //                  _edgeVector[1] * (((i>>1)&1) - 0.5) +
    +    //                  _edgeVector[2] * (((i>>2)&1) - 0.5)));
    +    // This method is implemented as a swtich statement due to being marginally faster than the bit-hack method
    +    // Also, the _center + 0.5f * (...) is repeated every time for similarly speed-based reasons.
    +    switch(i) {
    +        case 0:  return _center + (0.5f * (-_edgeVector[0]  - _edgeVector[1] - _edgeVector[2]));
    +        case 1:  return _center + (0.5f * ( _edgeVector[0]  - _edgeVector[1] - _edgeVector[2]));
    +        case 2:  return _center + (0.5f * (-_edgeVector[0]  + _edgeVector[1] - _edgeVector[2]));
    +        case 3:  return _center + (0.5f * ( _edgeVector[0]  + _edgeVector[1] - _edgeVector[2]));
    +        case 4:  return _center + (0.5f * (-_edgeVector[0]  - _edgeVector[1] + _edgeVector[2]));
    +        case 5:  return _center + (0.5f * ( _edgeVector[0]  - _edgeVector[1] + _edgeVector[2]));
    +        case 6:  return _center + (0.5f * (-_edgeVector[0]  + _edgeVector[1] + _edgeVector[2]));
    +        default: return _center + (0.5f * ( _edgeVector[0]  + _edgeVector[1] + _edgeVector[2]));//case 7
    +    }
    +        
    +}
    +
     float Box::volume() const {
         return _volume;
     }
    @@ -144,11 +225,14 @@ float Box::area() const {
     
     
     void Box::getLocalFrame(CoordinateFrame& frame) const {
    +    const Vector3& axis0 = axis(0);
    +    const Vector3& axis1 = axis(1);
    +    const Vector3& axis2 = axis(2);
     
         frame.rotation = Matrix3(
    -        _axis[0][0], _axis[1][0], _axis[2][0],
    -        _axis[0][1], _axis[1][1], _axis[2][1],
    -        _axis[0][2], _axis[1][2], _axis[2][2]);
    +        axis0[0], axis1[0], axis2[0],
    +        axis0[1], axis1[1], axis2[1],
    +        axis0[2], axis1[2], axis2[2]);
     
         frame.translation = _center;
     }
    @@ -161,30 +245,30 @@ CoordinateFrame Box::localFrame() const {
     }
     
     
    -void Box::getFaceCorners(int f, Vector3& v0, Vector3& v1, Vector3& v2, Vector3& v3) const {
    +void Box::getFaceCorners(int f, Point3& v0, Point3& v1, Point3& v2, Point3& v3) const {
         switch (f) {
         case 0:
    -        v0 = _corner[0]; v1 = _corner[1]; v2 = _corner[2]; v3 = _corner[3];
    +        v0 = corner(0); v1 = corner(2); v2 = corner(3); v3 = corner(1);
             break;
     
         case 1:
    -        v0 = _corner[1]; v1 = _corner[5]; v2 = _corner[6]; v3 = _corner[2];
    +        v0 = corner(1); v1 = corner(3); v2 = corner(7); v3 = corner(5);
             break;
     
         case 2:
    -        v0 = _corner[7]; v1 = _corner[6]; v2 = _corner[5]; v3 = _corner[4];
    +        v0 = corner(6); v1 = corner(4); v2 = corner(5); v3 = corner(7);
             break;
     
         case 3:
    -        v0 = _corner[2]; v1 = _corner[6]; v2 = _corner[7]; v3 = _corner[3];
    +        v0 = corner(3); v1 = corner(2); v2 = corner(6); v3 = corner(7);
             break;
     
         case 4:
    -        v0 = _corner[3]; v1 = _corner[7]; v2 = _corner[4]; v3 = _corner[0];
    +        v0 = corner(2); v1 = corner(0); v2 = corner(4); v3 = corner(6);
             break;
     
         case 5:
    -        v0 = _corner[1]; v1 = _corner[0]; v2 = _corner[4]; v3 = _corner[5];
    +        v0 = corner(1); v1 = corner(5); v2 = corner(4); v3 = corner(0);
             break;
     
         default:
    @@ -196,8 +280,8 @@ void Box::getFaceCorners(int f, Vector3& v0, Vector3& v1, Vector3& v2, Vector3&
     
     int Box::dummy = 0;
     
    -bool Box::culledBy(
    -    const Array& plane,
    +bool Box::culledBy
    +   (const Array& plane,
         int&                cullingPlane,
         const uint32        _inMask,
         uint32&             childMask) const {
    @@ -208,13 +292,11 @@ bool Box::culledBy(
         childMask = 0;
     
         // See if there is one plane for which all of the
    -	// vertices are in the negative half space.
    +    // vertices are in the negative half space.
         for (int p = 0; p < plane.size(); ++p) {
     
    -		// Only test planes that are not masked
    -		if ((inMask & 1) != 0) {
    -		
    -			Vector3 corner;
    +        // Only test planes that are not masked
    +        if ((inMask & 1) != 0) {
     
                 int numContained = 0;
                 int v = 0;
    @@ -222,93 +304,94 @@ bool Box::culledBy(
                 // We can early-out only if we have found one point on each
                 // side of the plane (i.e. if we are straddling).  That
                 // occurs when (numContained < v) && (numContained > 0)
    -			for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) {
    -                if (plane[p].halfSpaceContains(_corner[v])) {
    +            for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) {
    +                if (plane[p].halfSpaceContains(corner(v))) {
                         ++numContained;
                     }
    -			}
    +            }
     
    -			if (numContained == 0) {
    -				// Plane p culled the box
    -				cullingPlane = p;
    +            if (numContained == 0) {
    +                // Plane p culled the box
    +                cullingPlane = p;
     
                     // The caller should not recurse into the children,
                     // since the parent is culled.  If they do recurse,
                     // make them only test against this one plane, which
                     // will immediately cull the volume.
                     childMask = 1 << p;
    -				return true;
    +                return true;
     
                 } else if (numContained < v) {
                     // The bounding volume straddled the plane; we have
                     // to keep testing against this plane
                     childMask |= (1 << p);
                 }
    -		}
    +        }
     
             // Move on to the next bit.
    -		inMask = inMask >> 1;
    +        inMask = inMask >> 1;
         }
     
         // None of the planes could cull this box
    -	cullingPlane = -1;
    +    cullingPlane = -1;
         return false;
     }
     
     
    -bool Box::culledBy(
    -    const Array& plane,
    -	int&				cullingPlane,
    -	const uint32		_inMask) const {
    +bool Box::culledBy
    +   (const Array& plane,
    +    int&                cullingPlane,
    +    const uint32        _inMask) const {
     
    -	uint32 inMask = _inMask;
    -	assert(plane.size() < 31);
    +    uint32 inMask = _inMask;
    +    assert(plane.size() < 31);
     
         // See if there is one plane for which all of the
    -	// vertices are in the negative half space.
    +    // vertices are in the negative half space.
         for (int p = 0; p < plane.size(); ++p) {
     
    -		// Only test planes that are not masked
    -		if ((inMask & 1) != 0) {
    -		
    -			bool culled = true;
    +        // Only test planes that are not masked
    +        if ((inMask & 1) != 0) {
    +        
    +            bool culled = true;
     
                 int v;
     
    -			// Assume this plane culls all points.  See if there is a point
    -			// not culled by the plane... early out when at least one point
    +            // Assume this plane culls all points.  See if there is a point
    +            // not culled by the plane... early out when at least one point
                 // is in the positive half space.
    -			for (v = 0; (v < 8) && culled; ++v) {
    +            for (v = 0; (v < 8) && culled; ++v) {
                     culled = ! plane[p].halfSpaceContains(corner(v));
    -			}
    -
    -			if (culled) {
    -				// Plane p culled the box
    -				cullingPlane = p;
    -
    -				return true;
                 }
    -		}
    +
    +            if (culled) {
    +                // Plane p culled the box
    +                cullingPlane = p;
    +
    +                return true;
    +            }
    +        }
     
             // Move on to the next bit.
    -		inMask = inMask >> 1;
    +        inMask = inMask >> 1;
         }
     
         // None of the planes could cull this box
    -	cullingPlane = -1;
    +    cullingPlane = -1;
         return false;
     }
     
     
    -bool Box::contains(
    -    const Vector3&      point) const {
    +bool Box::contains
    +    (const Point3&      point) const {
     
         // Form axes from three edges, transform the point into that
         // space, and perform 3 interval tests
    -
    -    Vector3 u = _corner[4] - _corner[0];
    -    Vector3 v = _corner[3] - _corner[0];
    -    Vector3 w = _corner[1] - _corner[0];
    +    // TODO: Write in a more intuitive way. I left it as it was before after figuring it out, but
    +    // this should make no sense to someone who is just starting to read this code.
    +    const Vector3& u = _edgeVector[2];
    +    const Vector3& v = _edgeVector[1];
    +    const Vector3& w = _edgeVector[0];
     
         Matrix3 M = Matrix3(u.x, v.x, w.x,
                             u.y, v.y, w.y,
    @@ -316,7 +399,7 @@ bool Box::contains(
     
         // M^-1 * (point - _corner[0]) = point in unit cube's object space
         // compute the inverse of M
    -    Vector3 osPoint = M.inverse() * (point - _corner[0]);
    +    Vector3 osPoint = M.inverse() * (point - corner(0));
     
         return
             (osPoint.x >= 0) && 
    @@ -327,13 +410,13 @@ bool Box::contains(
             (osPoint.z <= 1);
     }
     
    -#undef setMany
    +
     
     
     void Box::getRandomSurfacePoint(Vector3& P, Vector3& N) const {
    -    float aXY = _extent.x * _extent.y;
    -    float aYZ = _extent.y * _extent.z;
    -    float aZX = _extent.z * _extent.x;
    +    float aXY = extent(0) * extent(1);
    +    float aYZ = extent(1) * extent(2);
    +    float aZX = extent(2) * extent(0);
     
         float r = (float)uniformRandom(0, aXY + aYZ + aZX);
     
    @@ -343,20 +426,20 @@ void Box::getRandomSurfacePoint(Vector3& P, Vector3& N) const {
         // The probability of choosing a given face is proportional to
         // its area.
         if (r < aXY) {
    -        P = _axis[0] * (float)uniformRandom(-0.5, 0.5) * _extent.x +
    -            _axis[1] * (float)uniformRandom(-0.5, 0.5) * _extent.y +
    -            _center + _axis[2] * d * _extent.z * 0.5f;
    -        N = _axis[2] * d;
    +        P = _edgeVector[0] * (float)uniformRandom(-0.5, 0.5) +
    +            _edgeVector[1] * (float)uniformRandom(-0.5, 0.5) +
    +            _center + _edgeVector[2] * d  * 0.5f;
    +        N = axis(2) * d;
         } else if (r < aYZ) {
    -        P = _axis[1] * (float)uniformRandom(-0.5, 0.5) * _extent.y +
    -            _axis[2] * (float)uniformRandom(-0.5, 0.5) * _extent.z +
    -            _center + _axis[0] * d * _extent.x * 0.5f;
    -        N = _axis[0] * d;
    +        P = _edgeVector[1] * (float)uniformRandom(-0.5, 0.5) +
    +            _edgeVector[2] * (float)uniformRandom(-0.5, 0.5) +
    +            _center + _edgeVector[0] * d  * 0.5f;
    +        N = axis(0) * d;
         } else {
    -        P = _axis[2] * (float)uniformRandom(-0.5, 0.5) * _extent.z +
    -            _axis[0] *(float) uniformRandom(-0.5, 0.5) * _extent.x +
    -            _center + _axis[1] * d * _extent.y * 0.5f;
    -        N = _axis[1] * d;
    +        P = _edgeVector[2] * (float)uniformRandom(-0.5, 0.5) +
    +            _edgeVector[0] *(float) uniformRandom(-0.5, 0.5) +
    +            _center + _edgeVector[1] * d * 0.5f;
    +        N = axis(1) * d;
         }
     }
     
    @@ -365,28 +448,25 @@ Vector3 Box::randomInteriorPoint() const {
         Vector3 sum = _center;
     
         for (int a = 0; a < 3; ++a) {
    -        sum += _axis[a] * (float)uniformRandom(-0.5, 0.5) * _extent[a];
    +        sum += _edgeVector[a] * (float)uniformRandom(-0.5, 0.5);
         }
     
         return sum;
     }
     
    +
     Box Box::inf() {
         return Box(-Vector3::inf(), Vector3::inf());
     }
     
    -void Box::getBounds(class AABox& aabb) const {
     
    -    Vector3 lo = _corner[0];
    -    Vector3 hi = lo;
    -
    -    for (int v = 1; v < 8; ++v) {
    -        const Vector3& C = _corner[v];
    -        lo = lo.min(C);
    -        hi = hi.max(C);
    +void Box::getBounds(AABox& aabb) const {
    +    debugAssert(! _edgeVector[0].isNaN());
    +    debugAssert(! _center.isNaN());
    +    aabb = AABox::empty();
    +    for (int i = 0; i < 8; ++i) {
    +        aabb.merge(corner(i));
         }
    -
    -    aabb = AABox(lo, hi);
     }
     
     
    diff --git a/deps/g3dlite/source/BumpMapPreprocess.cpp b/deps/g3dlite/source/BumpMapPreprocess.cpp
    index 20281caf8..df5a23c13 100644
    --- a/deps/g3dlite/source/BumpMapPreprocess.cpp
    +++ b/deps/g3dlite/source/BumpMapPreprocess.cpp
    @@ -6,7 +6,7 @@
       \created 2010-01-28
       \edited  2010-01-28
     
    -  Copyright 2000-2010, Morgan McGuire.
    +  Copyright 2000-2012, Morgan McGuire.
       All rights reserved.
      */
     #include "G3D/BumpMapPreprocess.h"
    @@ -17,7 +17,7 @@ namespace G3D {
     
     BumpMapPreprocess::BumpMapPreprocess(const Any& any) {
         *this = BumpMapPreprocess();
    -    for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
    +    for (Any::AnyTable::Iterator it = any.table().begin(); it.isValid(); ++it) {
             const std::string& key = toLower(it->key);
             if (key == "lowpassfilter") {
                 lowPassFilter = it->value;
    @@ -32,7 +32,7 @@ BumpMapPreprocess::BumpMapPreprocess(const Any& any) {
     }
     
     
    -BumpMapPreprocess::operator Any() const {
    +Any BumpMapPreprocess::toAny() const {
         Any any(Any::TABLE, "BumpMapPreprocess");
         any["lowPassFilter"] = lowPassFilter;
         any["zExtentPixels"] = zExtentPixels;
    diff --git a/deps/g3dlite/source/Capsule.cpp b/deps/g3dlite/source/Capsule.cpp
    index 2ad3891c9..14df8d31b 100644
    --- a/deps/g3dlite/source/Capsule.cpp
    +++ b/deps/g3dlite/source/Capsule.cpp
    @@ -22,7 +22,7 @@
     namespace G3D {
     
     Capsule::Capsule(class BinaryInput& b) {
    -	deserialize(b);
    +    deserialize(b);
     }
     
     
    @@ -31,47 +31,47 @@ Capsule::Capsule() {
     
     
     Capsule::Capsule(const Vector3& _p1, const Vector3& _p2, float _r) 
    -	: p1(_p1), p2(_p2), _radius(_r) {
    +    : p1(_p1), p2(_p2), _radius(_r) {
     }
     
     
     void Capsule::serialize(class BinaryOutput& b) const {
    -	p1.serialize(b);
    -	p2.serialize(b);
    -	b.writeFloat64(_radius);
    +    p1.serialize(b);
    +    p2.serialize(b);
    +    b.writeFloat64(_radius);
     }
     
     
     void Capsule::deserialize(class BinaryInput& b) {
    -	p1.deserialize(b);
    -	p2.deserialize(b);
    -	_radius = b.readFloat64();
    +    p1.deserialize(b);
    +    p2.deserialize(b);
    +    _radius = (float)b.readFloat64();
     }
     
     
     Line Capsule::axis() const {
    -	return Line::fromTwoPoints(p1, p2);
    +    return Line::fromTwoPoints(p1, p2);
     }
     
     
     float Capsule::volume() const {
    -	return 
    -		// Sphere volume
    -		pow(_radius, 3) * pi() * 4 / 3 +
    +    return 
    +        // Sphere volume
    +        pow(_radius, 3) * (float)pi() * 4 / 3 +
     
    -		// Cylinder volume
    -		pow(_radius, 2) * (p1 - p2).magnitude();
    +        // Cylinder volume
    +        pow(_radius, 2) * (p1 - p2).magnitude();
     }
     
     
     float Capsule::area() const {
     
    -	return
    -		// Sphere area
    -		pow(_radius, 2) * 4 * pi() +
    +    return
    +        // Sphere area
    +        pow(_radius, 2) * 4 * (float)pi() +
     
    -		// Cylinder area
    -		twoPi() * _radius * (p1 - p2).magnitude();
    +        // Cylinder area
    +        (float)twoPi() * _radius * (p1 - p2).magnitude();
     }
     
     
    @@ -147,10 +147,10 @@ Vector3 Capsule::randomInteriorPoint() const {
     
         Vector3 p;
     
    -    float hemiVolume = pi() * (r*r*r) * 4 / 6.0;
    -    float cylVolume = pi() * square(r) * h;
    +    float hemiVolume = (float)pi() * (r*r*r) * 4 / 6.0f;
    +    float cylVolume = (float)pi() * square(r) * h;
         
    -    float r1 = uniformRandom(0, 2.0 * hemiVolume + cylVolume);
    +    float r1 = uniformRandom(0, 2.0f * hemiVolume + cylVolume);
     
         if (r1 < 2.0 * hemiVolume) {
     
    diff --git a/deps/g3dlite/source/CollisionDetection.cpp b/deps/g3dlite/source/CollisionDetection.cpp
    index 4bc15d9fe..ef48a5bb9 100644
    --- a/deps/g3dlite/source/CollisionDetection.cpp
    +++ b/deps/g3dlite/source/CollisionDetection.cpp
    @@ -37,7 +37,7 @@
     namespace G3D {
     
     bool CollisionDetection::ignoreBool;
    -Vector3	CollisionDetection::ignore;
    +Vector3    CollisionDetection::ignore;
     Array CollisionDetection::ignoreArray;
     
     
    @@ -186,7 +186,7 @@ bool CollisionDetection::parallelAxisForSolidBoxSolidBox(
             int & axis1,
             int & axis2) {
         const double parallelDot = 1.0 - epsilon;
    -    for (int i = 0; i < 9; i++) {
    +    for (int i = 0; i < 9; ++i) {
             if (ca[i] >= parallelDot) {
                 axis1 = i / 3;
                 axis2 = i % 3;
    @@ -221,14 +221,14 @@ void CollisionDetection::fillSolidBoxSolidBoxInfo(
         // corresponds to c[row * 3 + col] for this 9 element array.
         //
         // c[] holds signed values, ca[] hold absolute values
    -    for (int i = 0; i < 9; i++) {
    +    for (int i = 0; i < 9; ++i) {
             c[i] = dot(box1.axis(i / 3), box2.axis(i % 3));
             ca[i] = fabs(c[i]);
         }
     
         // store all possible dot products between the axes of box1 and D,
         // as well as the axes of box2 and D
    -    for (int i = 0; i < 3; i++) {
    +    for (int i = 0; i < 3; ++i) {
             ad[i] = dot(box1.axis(i), D);
             bd[i] = dot(box2.axis(i), D);
         }
    @@ -251,7 +251,7 @@ bool CollisionDetection::conservativeBoxBoxTest(
     bool CollisionDetection::fixedSolidBoxIntersectsFixedSolidBox(
         const Box&      box1,
         const Box&      box2,
    -	const int		lastSeparatingAxis) {
    +    const int        lastSeparatingAxis) {
         // for explanations of the variable please refer to the
         // paper and fillSolidBoxSolidBoxInfo()
         Vector3 a;
    @@ -285,7 +285,7 @@ bool CollisionDetection::fixedSolidBoxIntersectsFixedSolidBox(
         // any of the three axes of box1, any of the three axes of box2,
         // or any of the 9 possible cross products of axes from box1
         // and box2
    -    for (int i = 0; i < 15; i++) {
    +    for (int i = 0; i < 15; ++i) {
             // do not need to check edge-edge cases if any two of
             // the axes are parallel
             if (parallelAxes && i == 6) {
    @@ -388,10 +388,10 @@ float CollisionDetection::penetrationDepthForFixedBoxFixedBox(
         // test if the boxes can be separated by a plane normal to
         // any of the three axes of box1, any of the three axes of box2,
         // (test 9 possible cross products later)
    -	float penetration = -finf();
    +    float penetration = -finf();
         int penetrationAxisIndex = -1;
     
    -    for (int i = 0; i < 6; i++) {
    +    for (int i = 0; i < 6; ++i) {
             float projectedDistance =
                 projectedDistanceForSolidBoxSolidBox(i, a, b, D, c, ca, ad, bd);
     
    @@ -411,44 +411,45 @@ float CollisionDetection::penetrationDepthForFixedBoxFixedBox(
         // for each edge-edge case we have to adjust the magnitude of
         // penetration since we did not include the dot(L, L) denominator
         // that can be smaller than 1.0 for the edge-edge cases.
    -	if (!parallelAxes) {
    -	    double edgeDistances[9];
     
    -		// run through edge-edge cases to see if we can find a separating axis
    -		for (int i = 6; i < 15; i++) {
    -			float projectedDistance =
    -				projectedDistanceForSolidBoxSolidBox(i, a, b, D, c, ca, ad, bd);
    +    if (!parallelAxes) {
    +        double edgeDistances[9];
     
    -			// found a separating axis, the boxes do not intersect,
    -			// correct magnitude and return projected distance
    -			if (projectedDistance > 0.0) {
    -				Vector3 L = separatingAxisForSolidBoxSolidBox(i, box1, box2);
    -				projectedDistance /= dot(L, L);
    -				return -projectedDistance;
    -			}
    +        // run through edge-edge cases to see if we can find a separating axis
    +        for (int i = 6; i < 15; ++i) {
    +            float projectedDistance =
    +                projectedDistanceForSolidBoxSolidBox(i, a, b, D, c, ca, ad, bd);
     
    -			edgeDistances[i - 6] = projectedDistance;
    -		}
    +            // found a separating axis, the boxes do not intersect,
    +            // correct magnitude and return projected distance
    +            if (projectedDistance > 0.0) {
    +                Vector3 L = separatingAxisForSolidBoxSolidBox(i, box1, box2);
    +                projectedDistance /= dot(L, L);
    +                return -projectedDistance;
    +            }
     
    -		// no separating axis found, the boxes do intersect,
    -		// correct the magnitudes of the projectedDistance values
    -		for (int i = 6; i < 15; i++) {
    -			// find the negative penetration value with the smallest magnitude,
    -			// the adjustment done for the edge-edge cases only increases
    -			// magnitude by dividing by a number smaller than 1 and greater than 0
    -			float projectedDistance = (float)edgeDistances[i - 6];
    -			if (projectedDistance > penetration) {
    -				Vector3 L = separatingAxisForSolidBoxSolidBox(i, box1, box2);
    -				projectedDistance /= dot(L, L);
    -				if (projectedDistance > penetration) {
    -					penetration = projectedDistance;
    -					penetrationAxisIndex = i;
    -				}
    -			}
    -		}
    -	}
    +            edgeDistances[i - 6] = projectedDistance;
    +        }
     
    -	// get final separating axis vector
    +        // no separating axis found, the boxes do intersect,
    +        // correct the magnitudes of the projectedDistance values
    +        for (int i = 6; i < 15; ++i) {
    +            // find the negative penetration value with the smallest magnitude,
    +            // the adjustment done for the edge-edge cases only increases
    +            // magnitude by dividing by a number smaller than 1 and greater than 0
    +            float projectedDistance = (float)edgeDistances[i - 6];
    +            if (projectedDistance > penetration) {
    +                Vector3 L = separatingAxisForSolidBoxSolidBox(i, box1, box2);
    +                projectedDistance /= dot(L, L);
    +                if (projectedDistance > penetration) {
    +                    penetration = projectedDistance;
    +                    penetrationAxisIndex = i;
    +                }
    +            }
    +        }
    +    }
    +
    +    // get final separating axis vector
         Vector3 L = separatingAxisForSolidBoxSolidBox(penetrationAxisIndex,
                 box1, box2);
     
    @@ -462,18 +463,15 @@ float CollisionDetection::penetrationDepthForFixedBoxFixedBox(
         if (penetrationAxisIndex < 6) {
             // vertex to face collision, find deepest colliding vertex
             const Box* vertexBox;
    -        const Box* faceBox;
             Vector3 faceNormal = L;
     
             // L will be the outward facing normal for the faceBox
             if (penetrationAxisIndex < 3) {
    -            faceBox = & box1;
                 vertexBox = & box2;
                 if (dot(L, D) < 0) {
                     faceNormal = -L;
                 }
             } else {
    -            faceBox = & box2;
                 vertexBox = & box1;
                 if (dot(L, D) > 0) {
                     faceNormal = -L;
    @@ -484,7 +482,7 @@ float CollisionDetection::penetrationDepthForFixedBoxFixedBox(
             // face normal direction
             int deepestPointIndex = 0;
             float deepestPointDot = dot(faceNormal, vertexBox->corner(0));
    -        for (int i = 1; i < 8; i++) {
    +        for (int i = 1; i < 8; ++i) {
                 float dotProduct = dot(faceNormal, vertexBox->corner(i));
                 if (dotProduct < deepestPointDot) {
                     deepestPointDot = dotProduct;
    @@ -507,7 +505,7 @@ float CollisionDetection::penetrationDepthForFixedBoxFixedBox(
     
             // find edge line by finding the edge axis, and the
             // other two axes that are closest to the other box
    -        for (int i = 0; i < 3; i++ ) {
    +        for (int i = 0; i < 3; ++i) {
                 if (i == edge1) {
                     lineDir1 = box1.axis(i);
                 } else {
    @@ -854,27 +852,27 @@ float CollisionDetection::collisionTimeForMovingPointFixedPlane(
         Vector3&        outNormal) {
     
         // Solve for the time at which normal.dot(point + velocity) + d == 0.
    -    double d;
    +    float d;
         Vector3 normal;
         plane.getEquation(normal, d);
         
    -    float vdotN = velocity.dot(normal);
    -    float pdotN = point.dot(normal);
    +    const float vdotN = velocity.dot(normal);
    +    const float pdotN = point.dot(normal);
     
    -    if (fuzzyEq(pdotN + d, 0)) {
    +    if (fuzzyEq(pdotN + d, 0.0f)) {
             // The point is *in* the plane.
             location = point;
             outNormal = normal;
             return 0;
         }
     
    -    if (vdotN >= 0) {
    +    if (vdotN >= 0.0f) {
             // no collision will occur
             location = Vector3::inf();
             return finf();
         }
     
    -    float t = -(pdotN + d) / vdotN;
    +    const float t = -(pdotN + d) / vdotN;
         if (t < 0) {
             location = Vector3::inf();
             return finf();
    @@ -921,7 +919,7 @@ bool __fastcall CollisionDetection::rayAABox(
         // Find candidate planes.
         for (int i = 0; i < 3; ++i) {
             if (ray.origin()[i] < MinB[i]) {
    -            location[i]	= MinB[i];
    +            location[i]    = MinB[i];
                 inside      = false;
                 
                 // Calculate T distances to candidate planes
    @@ -929,7 +927,7 @@ bool __fastcall CollisionDetection::rayAABox(
                     MaxT[i] = (MinB[i] - ray.origin()[i]) * invDir[i];
                 }
             } else if (ray.origin()[i] > MaxB[i]) {
    -            location[i]	= MaxB[i];
    +            location[i]    = MaxB[i];
                 inside      = false;
     
                 // Calculate T distances to candidate planes
    @@ -940,7 +938,7 @@ bool __fastcall CollisionDetection::rayAABox(
         }
     
         if (inside) {
    -    	// Ray origin inside bounding box
    +        // Ray origin inside bounding box
             location = ray.origin();
             return true;
         }
    @@ -1065,10 +1063,10 @@ float CollisionDetection::collisionTimeForMovingSphereFixedSphere(
     
     /*
     float CollisionDetection::collisionTimeForMovingPointFixedTriangle(
    -    const Vector3&			point,
    -    const Vector3&			velocity,
    +    const Vector3&            point,
    +    const Vector3&            velocity,
         const Triangle&       triangle,
    -    Vector3&				outLocation,
    +    Vector3&                outLocation,
         Vector3&                outNormal) {
     
         double time = collisionTimeForMovingPointFixedPlane(point, velocity, triangle.plane(), outLocation, outNormal);
    @@ -1234,73 +1232,73 @@ bool CollisionDetection::collisionLocationForMovingPointFixedAABox(
         Vector3&                normal) {
     
         // Integer representation of a floating-point value.
    -    #define IR(x)	((uint32&)x)
    +    #define IR(x)    ((uint32&)x)
     
         Inside = true;
    -	const Vector3& MinB = box.low();
    -	const Vector3& MaxB = box.high();
    -	Vector3 MaxT(-1.0f, -1.0f, -1.0f);
    +    const Vector3& MinB = box.low();
    +    const Vector3& MaxB = box.high();
    +    Vector3 MaxT(-1.0f, -1.0f, -1.0f);
     
    -	// Find candidate planes.
    +    // Find candidate planes.
         for (int i = 0; i < 3; ++i) {
    -		if (origin[i] < MinB[i]) {
    -			location[i]	= MinB[i];
    -			Inside      = false;
    +        if (origin[i] < MinB[i]) {
    +            location[i]    = MinB[i];
    +            Inside      = false;
     
    -			// Calculate T distances to candidate planes
    +            // Calculate T distances to candidate planes
                 if (IR(dir[i])) {
                     MaxT[i] = (MinB[i] - origin[i]) / dir[i];
                 }
             } else if (origin[i] > MaxB[i]) {
    -			location[i]	= MaxB[i];
    -			Inside	    = false;
    +            location[i]    = MaxB[i];
    +            Inside        = false;
     
    -			// Calculate T distances to candidate planes
    +            // Calculate T distances to candidate planes
                 if (IR(dir[i])) {
                     MaxT[i] = (MaxB[i] - origin[i]) / dir[i];
                 }
    -		}
    -	}
    +        }
    +    }
     
    -	if (Inside) {
    -    	// Ray origin inside bounding box
    +    if (Inside) {
    +        // Ray origin inside bounding box
             location = origin;
    -		return false;
    -	}
    +        return false;
    +    }
     
    -	// Get largest of the maxT's for final choice of intersection
    -	int WhichPlane = 0;
    -    if (MaxT[1] > MaxT[WhichPlane])	{
    +    // Get largest of the maxT's for final choice of intersection
    +    int WhichPlane = 0;
    +    if (MaxT[1] > MaxT[WhichPlane])    {
             WhichPlane = 1;
         }
     
    -    if (MaxT[2] > MaxT[WhichPlane])	{
    +    if (MaxT[2] > MaxT[WhichPlane])    {
             WhichPlane = 2;
         }
     
    -	// Check final candidate actually inside box
    +    // Check final candidate actually inside box
         if (IR(MaxT[WhichPlane]) & 0x80000000) {
             // Miss the box
             return false;
         }
     
    -	for (int i = 0; i < 3; ++i) {
    +    for (int i = 0; i < 3; ++i) {
             if (i != WhichPlane) {
    -			location[i] = origin[i] + MaxT[WhichPlane] * dir[i];
    +            location[i] = origin[i] + MaxT[WhichPlane] * dir[i];
                 if ((location[i] < MinB[i]) ||
                     (location[i] > MaxB[i])) {
                     // On this plane we're outside the box extents, so
                     // we miss the box
                     return false;
                 }
    -		}
    -	}
    +        }
    +    }
     
         // Choose the normal to be the plane normal facing into the ray
         normal = Vector3::zero();
         normal[WhichPlane] = (dir[WhichPlane] > 0) ? -1.0 : 1.0;
     
    -	return true;
    +    return true;
     
         #undef IR
     }
    @@ -1338,19 +1336,24 @@ float CollisionDetection::collisionTimeForMovingPointFixedRectangle(
     /** Used by findRayCapsuleIntersection.
         @cite From magic software http://www.magic-software.com/Source/Intersection3D/MgcIntr3DLinCap.cpp */
     static int findRayCapsuleIntersectionAux(
    -	const Vector3&		rkOrigin,
    -	const Vector3&		rkDirection,
    -    const Capsule&		rkCapsule,
    -	double   			afT[2]) {
    +    const Vector3&        rkOrigin,
    +    const Vector3&        rkDirection,
    +    const Capsule&        rkCapsule,
    +    double               afT[2]) {
     
    -	Vector3 capsuleDirection = rkCapsule.point(1) - rkCapsule.point(0);
    +    Vector3 capsuleDirection = rkCapsule.point(1) - rkCapsule.point(0);
     
         // set up quadratic Q(t) = a*t^2 + 2*b*t + c
    -    Vector3 kU, kV, kW = capsuleDirection;
    -    float fWLength = kW.unitize();
    -    Vector3::generateOrthonormalBasis(kU, kV, kW);
    +    Vector3 kW = capsuleDirection;
    +    float fWLength = kW.length();
    +    kW = kW.direction();
    +
    +    Vector3 kU, kV;
    +    kW.getTangents(kU, kV);
         Vector3 kD(kU.dot(rkDirection), kV.dot(rkDirection), kW.dot(rkDirection));
    -    float fDLength = kD.unitize();
    +
    +    float fDLength = kD.length();
    +    kD = kD.direction();
     
         float fEpsilon = 1e-6f;
     
    @@ -1405,15 +1408,15 @@ static int findRayCapsuleIntersectionAux(
             fTmp = kP.z + fT*kD.z;
             if ((0.0f <= fTmp) && (fTmp <= fWLength)) {
                 afT[iQuantity] = fT * fInvDLength;
    -            iQuantity++;
    -		}
    +            ++iQuantity;
    +        }
     
             fT = (-fB + fRoot)*fInv;
             fTmp = kP.z + fT*kD.z;
             
    -		if ((0.0f <= fTmp) && (fTmp <= fWLength)) {
    +        if ((0.0f <= fTmp) && (fTmp <= fWLength)) {
                 afT[iQuantity++] = fT*fInvDLength;
    -		}
    +        }
     
             if (iQuantity == 2) {
                 // line intersects capsule wall in two places
    @@ -1442,7 +1445,7 @@ static int findRayCapsuleIntersectionAux(
                 afT[iQuantity++] = fT*fInvDLength;
                 if (iQuantity == 2) {
                     return 2;
    -			}
    +            }
             }
     
             fT = -fB + fRoot;
    @@ -1451,7 +1454,7 @@ static int findRayCapsuleIntersectionAux(
                 afT[iQuantity++] = fT*fInvDLength;
                 if (iQuantity == 2) {
                     return 2;
    -			}
    +            }
             }
         } else if (fDiscr == 0.0f) {
             fT = -fB;
    @@ -1460,7 +1463,7 @@ static int findRayCapsuleIntersectionAux(
                 afT[iQuantity++] = fT*fInvDLength;
                 if (iQuantity == 2) {
                     return 2;
    -			}
    +            }
             }
         }
     
    @@ -1478,7 +1481,7 @@ static int findRayCapsuleIntersectionAux(
                 afT[iQuantity++] = fT*fInvDLength;
                 if (iQuantity == 2) {
                     return 2;
    -			}
    +            }
             }
     
             fT = -fB + fRoot;
    @@ -1487,7 +1490,7 @@ static int findRayCapsuleIntersectionAux(
                 afT[iQuantity++] = fT*fInvDLength;
                 if (iQuantity == 2) {
                     return 2;
    -			}
    +            }
             }
         } else if (fDiscr == 0.0f) {
             fT = -fB;
    @@ -1496,7 +1499,7 @@ static int findRayCapsuleIntersectionAux(
                 afT[iQuantity++] = fT*fInvDLength;
                 if (iQuantity == 2) {
                     return 2;
    -			}
    +            }
             }
         }
     
    @@ -1506,25 +1509,25 @@ static int findRayCapsuleIntersectionAux(
     
     /** Used by collisionTimeForMovingPointFixedCapsule.
         @cite From magic software http://www.magic-software.com/Source/Intersection3D/MgcIntr3DLinCap.cpp
    -	
    -	@param rkRay      The ray
    -	@param rkCapsule  The capsule
    -	@param riQuantity The number of intersections found
    -	@param akPoint    The intersections found
    -	@return           True if there is at least one intersection
    -	*/
    +    
    +    @param rkRay      The ray
    +    @param rkCapsule  The capsule
    +    @param riQuantity The number of intersections found
    +    @param akPoint    The intersections found
    +    @return           True if there is at least one intersection
    +    */
     static bool findRayCapsuleIntersection(
    -	const Ray&			rkRay,
    -	const Capsule&		rkCapsule,
    -	int&				riQuantity,
    -	Vector3				akPoint[2]) {
    +    const Ray&            rkRay,
    +    const Capsule&        rkCapsule,
    +    int&                riQuantity,
    +    Vector3                akPoint[2]) {
     
         double afT[2];
         riQuantity = findRayCapsuleIntersectionAux(rkRay.origin(), rkRay.direction(), rkCapsule, afT);
     
         // Only return intersections that occur in the future
         int iClipQuantity = 0;
    -	int i;
    +    int i;
         for (i = 0; i < riQuantity; ++i) {
             if (afT[i] >= 0.0f) {
                 akPoint[iClipQuantity] = rkRay.origin() + afT[i] * rkRay.direction();
    @@ -1537,30 +1540,30 @@ static bool findRayCapsuleIntersection(
     }
     
     float CollisionDetection::collisionTimeForMovingPointFixedCapsule(
    -	const Vector3&		_point,
    -	const Vector3&		velocity,
    -	const Capsule&		capsule,
    -	Vector3&		    location,
    +    const Vector3&        _point,
    +    const Vector3&        velocity,
    +    const Capsule&        capsule,
    +    Vector3&            location,
         Vector3&            outNormal) {
     
    -	float timeScale = velocity.magnitude();
    +    float timeScale = velocity.magnitude();
     
         if (timeScale == 0.0f) {
             timeScale = 1;
         }
     
    -	Vector3 direction = velocity / timeScale;
    -	int numIntersections;
    -	Vector3 intersection[2];
    -	findRayCapsuleIntersection(Ray::fromOriginAndDirection(_point, direction), capsule, numIntersections, intersection);
    +    Vector3 direction = velocity / timeScale;
    +    int numIntersections;
    +    Vector3 intersection[2];
    +    findRayCapsuleIntersection(Ray::fromOriginAndDirection(_point, direction), capsule, numIntersections, intersection);
     
    -	if (numIntersections == 2) {
    -		// A collision can only occur if there are two intersections.  If there is one
    -		// intersection, that one is exiting the capsule.  
    +    if (numIntersections == 2) {
    +        // A collision can only occur if there are two intersections.  If there is one
    +        // intersection, that one is exiting the capsule.  
     
    -		// Find the entering intersection (the first one that occurs).
    -		float d0 = (intersection[0] - _point).squaredMagnitude();
    -		float d1 = (intersection[1] - _point).squaredMagnitude();
    +        // Find the entering intersection (the first one that occurs).
    +        float d0 = (intersection[0] - _point).squaredMagnitude();
    +        float d1 = (intersection[1] - _point).squaredMagnitude();
     
             // Compute the surface normal (if we aren't ignoring the result)
             if (&outNormal != &ignore) {
    @@ -1569,40 +1572,41 @@ float CollisionDetection::collisionTimeForMovingPointFixedCapsule(
             }
     
             if (d0 > d1) {
    -			location = intersection[1];
    -			return sqrt(d1) / timeScale;
    -		} else {
    -			location = intersection[0];
    -			return sqrt(d0) / timeScale;
    -		}
    -	} else {
    -		// No entering intersection discovered; return no intersection.
    -		location = Vector3::inf();
    -		return finf();
    -	}
    +            location = intersection[1];
    +            return sqrt(d1) / timeScale;
    +        } else {
    +            location = intersection[0];
    +            return sqrt(d0) / timeScale;
    +        }
    +    } else {
    +        // No entering intersection discovered; return no intersection.
    +        location = Vector3::inf();
    +        return finf();
    +    }
     }
     
     
     float CollisionDetection::collisionTimeForMovingSphereFixedPlane(
    -    const Sphere&		sphere,
    -    const Vector3&		velocity,
    -    const Plane&		plane,
    -    Vector3&			location,
    +    const Sphere&        sphere,
    +    const Vector3&        velocity,
    +    const Plane&        plane,
    +    Vector3&            location,
         Vector3&            outNormal) {
     
    -	if (sphere.radius == 0) {
    -		// Optimization for zero radius sphere
    +    if (sphere.radius == 0) {
    +        // Optimization for zero radius sphere
             return collisionTimeForMovingPointFixedPlane(sphere.center, velocity, plane, location, outNormal);
    -	}
    +    }
     
    -    // The collision point on the sphere will be the point at
    -    // center - (radius * normal).  Collisions only occur when
    +    // The world-space collision point, which lies on the surface of the sphere, will be the point at
    +    // center + velocity * time - (radius * planeNormal).  Collisions only occur when
         // the sphere is travelling into the plane.
     
    -    double d;
    +    float d;
         plane.getEquation(outNormal, d);
         
    -    double vdotN = velocity.dot(outNormal);
    +    // Rate at which the sphere is approaching the plane
    +    const float vdotN = velocity.dot(outNormal);
     
         if (fuzzyGt(vdotN, 0)) {
             // No collision when the sphere is moving towards a backface.
    @@ -1610,34 +1614,37 @@ float CollisionDetection::collisionTimeForMovingSphereFixedPlane(
             return (float)finf();
         }
     
    -    float cdotN = sphere.center.dot(outNormal);
    -
    -    // Distance from the center to the plane
    -    float distance = cdotN + (float)d;
    -
    -    // Where is the collision on the sphere?
    -    Vector3 point = sphere.center - (sphere.radius * outNormal);
    +    // Initial distance from the sphere center to the plane
    +    const float distance = sphere.center.dot(outNormal) + d;
     
         if (fuzzyLe(G3D::abs(distance), sphere.radius)) {
             // Already interpenetrating
             location = sphere.center - distance * outNormal;
             return 0;
         } else {
    +        // The point on the sphere (in world space) that will eventually first contact the plane
    +        const Point3& point = sphere.center - (sphere.radius * outNormal);
    +
    +        // The problem is now reduced to finding when the point hits the plane
             return collisionTimeForMovingPointFixedPlane(point, velocity, plane, location, outNormal);
         }
     
     }
     
     
    -float CollisionDetection::collisionTimeForMovingSphereFixedTriangle(
    -    const class Sphere&		sphere,
    -    const Vector3&              velocity,
    -    const Triangle&             triangle,
    -    Vector3&                    outLocation,
    -    float                       b[3]) {
    +float CollisionDetection::collisionTimeForMovingSphereFixedTriangle
    +(const Sphere&                 sphere,
    + const Vector3&              velocity,
    + const Triangle&             triangle,
    + Vector3&                    outLocation,
    + float                       b[3]) {
     
    +    if (velocity.dot(triangle.normal()) > 0.0f) {
    +        // No collision if moving towards a backface
    +        return finf();
    +    }
         Vector3 dummy;
    -    float time = collisionTimeForMovingSphereFixedPlane(sphere, velocity, triangle.plane(), 
    +    const float time = collisionTimeForMovingSphereFixedPlane(sphere, velocity, triangle.plane(), 
                                                             outLocation, dummy);
     
         if (time == finf()) {
    @@ -1660,7 +1667,7 @@ float CollisionDetection::collisionTimeForMovingSphereFixedTriangle(
                 debugAssertM(b[0] >= 0.0 && b[0] <= 1.0f, "Intersection is outside triangle.");
                 debugAssertM(b[1] >= 0.0 && b[1] <= 1.0f, "Intersection is outside triangle.");
                 debugAssertM(b[2] >= 0.0 && b[2] <= 1.0f, "Intersection is outside triangle.");
    -            Vector3 blend = 
    +            const Vector3& blend = 
                     b[0] * triangle.vertex(0) + 
                     b[1] * triangle.vertex(1) + 
                     b[2] * triangle.vertex(2);
    @@ -1817,18 +1824,18 @@ float CollisionDetection::collisionTimeForMovingSphereFixedBox(
     
     
     float CollisionDetection::collisionTimeForMovingSphereFixedCapsule(
    -	const Sphere&		sphere,
    -	const Vector3&		velocity,
    -	const Capsule&		capsule,
    -	Vector3&		    location,
    +    const Sphere&        sphere,
    +    const Vector3&        velocity,
    +    const Capsule&        capsule,
    +    Vector3&            location,
         Vector3&            outNormal) {
     
         (void)outNormal;
     
    -	Capsule _capsule(capsule.point(0), capsule.point(1), capsule.radius() + sphere.radius);
    +    Capsule _capsule(capsule.point(0), capsule.point(1), capsule.radius() + sphere.radius);
     
         Vector3 normal;
    -	double time = collisionTimeForMovingPointFixedCapsule(sphere.center, velocity, _capsule, location, normal);
    +    double time = collisionTimeForMovingPointFixedCapsule(sphere.center, velocity, _capsule, location, normal);
         
         if (time < finf()) {
             // Location is now the position of the center of the sphere at the time of collision.
    @@ -1847,14 +1854,14 @@ Vector3 CollisionDetection::bounceDirection(
         const Vector3&  collisionLocation,
         const Vector3&  collisionNormal) {
     
    -	// Location when the collision occurs
    +    // Location when the collision occurs
         Vector3 sphereLocation  = sphere.center + velocity * collisionTime;
     
         Vector3 normal          = (sphereLocation - collisionLocation);
         if (fuzzyEq(normal.squaredMagnitude(), 0)) {
             normal = collisionNormal;
         } else {
    -        normal.unitize();
    +        normal = normal.direction();
         }
     
         Vector3 direction       = velocity.direction();
    @@ -1926,10 +1933,10 @@ Vector3 CollisionDetection::closestPointOnLineSegment(
     
     
     Vector3 CollisionDetection::closestPointOnTrianglePerimeter(
    -    const Vector3&			v0, 
    -    const Vector3&			v1,
    -    const Vector3&			v2,
    -    const Vector3&			point) {
    +    const Vector3&            v0, 
    +    const Vector3&            v1,
    +    const Vector3&            v2,
    +    const Vector3&            point) {
         
         Vector3 v[3] = {v0, v1, v2};
         Vector3 edgeDirection[3] = {(v1 - v0), (v2 - v1), (v0 - v2)};
    @@ -2000,11 +2007,11 @@ Vector3 CollisionDetection::closestPointOnTrianglePerimeter(
     
     
     bool CollisionDetection::isPointInsideTriangle(
    -    const Vector3&			v0,
    -    const Vector3&			v1,
    -    const Vector3&			v2,
    -    const Vector3&			normal,
    -    const Vector3&			point,
    +    const Vector3&            v0,
    +    const Vector3&            v1,
    +    const Vector3&            v2,
    +    const Vector3&            normal,
    +    const Vector3&            point,
         float                   b[3],
         Vector3::Axis           primaryAxis) {
         
    @@ -2267,7 +2274,7 @@ bool CollisionDetection::fixedSolidSphereIntersectsFixedTriangle(
     
     
     ////////////////////////////////////////////////////////////////////////////////
    -// AABB-triangle overlap test code based on Tomas Akenine-M��ller's
    +// AABB-triangle overlap test code based on Tomas Akenine-Mller's
     // http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/tribox3.txt
     // Ported 2008-12-28
     
    diff --git a/deps/g3dlite/source/Color1.cpp b/deps/g3dlite/source/Color1.cpp
    index 04f3f9412..6347a4a05 100644
    --- a/deps/g3dlite/source/Color1.cpp
    +++ b/deps/g3dlite/source/Color1.cpp
    @@ -1,17 +1,17 @@
     /**
    - @file Color1.cpp
    + \file Color1.cpp
     
      Color class.
     
    - @author Morgan McGuire, http://graphics.cs.williams.edu
    + \author Morgan McGuire, http://graphics.cs.williams.edu
     
    - @created 2007-01-30
    - @edited  2009-03-27
    + \created 2007-01-30
    + \edited  2011-08-27
      */
     
     #include "G3D/platform.h"
     #include "G3D/Color1.h"
    -#include "G3D/Color1uint8.h"
    +#include "G3D/Color1unorm8.h"
     #include "G3D/BinaryInput.h"
     #include "G3D/BinaryOutput.h"
     #include "G3D/Color3.h"
    @@ -50,8 +50,8 @@ void Color1::serialize(BinaryOutput& bo) const {
     }
     
     
    -Color1::Color1(const class Color1uint8& other) {
    -    value = other.value / 255.0f;
    +Color1::Color1(const class Color1unorm8& other) {
    +    value = other.value;
     }
     
     } // namespace G3D
    diff --git a/deps/g3dlite/source/Color3.cpp b/deps/g3dlite/source/Color3.cpp
    index deb0bd87e..bc50aaf40 100644
    --- a/deps/g3dlite/source/Color3.cpp
    +++ b/deps/g3dlite/source/Color3.cpp
    @@ -1,12 +1,12 @@
     /**
    - @file Color3.cpp
    + \file Color3.cpp
     
      Color class.
     
    - @author Morgan McGuire, http://graphics.cs.williams.edu
    + \author Morgan McGuire, http://graphics.cs.williams.edu
     
    - @created 2001-06-02
    - @edited  2010-01-28
    + \created 2001-06-02
    + \edited  2013-03-29
      */
     
     #include "G3D/platform.h"
    @@ -16,21 +16,26 @@
     #include "G3D/format.h"
     #include "G3D/BinaryInput.h"
     #include "G3D/BinaryOutput.h"
    -#include "G3D/Color3uint8.h"
    +#include "G3D/Color3unorm8.h"
     #include "G3D/Any.h"
     #include "G3D/stringutils.h"
     
     namespace G3D {
     
    +Color3& Color3::operator=(const Any& a) {
    +    *this = Color3(a);
    +    return *this;
    +}
    +
    +
     Color3::Color3(const Any& any) {
         *this = Color3::zero();
    -    any.verifyName("Color3");
    -    std::string name = toLower(any.name());
    +    any.verifyNameBeginsWith("Color3", "Power3", "Radiance3", "Irradiance3", "Energy3", "Radiosity3", "Biradiance3");
     
         switch (any.type()) {
         case Any::TABLE:
     
    -        for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
    +        for (Any::AnyTable::Iterator it = any.table().begin(); it.isValid(); ++it) {
                 const std::string& key = toLower(it->key);
                 if (key == "r") {
                     r = it->value;
    @@ -44,22 +49,38 @@ Color3::Color3(const Any& any) {
             }
             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");
    +    case Any::ARRAY: // Intentionally falls through
    +    case Any::EMPTY_CONTAINER:
    +        {   
    +            const std::string& name = any.name();
    +            std::string factoryName;
    +            size_t i = name.find("::");
    +            if (i != std::string::npos && i > 1) {
    +                factoryName = name.substr(i + 2);
    +            }
    +
    +            if (factoryName == "") {
    +                if (any.size() == 1) {
    +                    r = g = b = any[0];
    +                } else {
    +                    any.verifySize(3);
    +                    r = any[0];
    +                    g = any[1];
    +                    b = any[2];
    +                }
    +            } else if (factoryName == "one") {
    +                any.verifySize(0);
    +                *this = one();
    +            } else if (factoryName == "zero") {
    +                any.verifySize(0);
    +                *this = zero();
    +            } else if (factoryName == "fromARGB") {
    +                *this = Color3::fromARGB((int)any[0].number());
    +            } else if (factoryName == "fromASRGB") {
    +                *this = Color3::fromASRGB((int)any[0].number());
    +            } else {
    +                any.verify(false, "Expected Color3 constructor");
    +            }
             }
             break;
     
    @@ -69,7 +90,7 @@ Color3::Color3(const Any& any) {
     }
        
     
    -Color3::operator Any() const {
    +Any Color3::toAny() const {
         Any a(Any::ARRAY, "Color3");
         a.append(r, g, b);
         return a;
    @@ -169,7 +190,7 @@ const Color3& Color3::gray() {
     
     
     const Color3& Color3::white() {
    -    static Color3 c(1, 1, 1);
    +    static Color3 c(1.0f, 1.0f, 1.0f);
         return c;
     }
     
    @@ -224,15 +245,16 @@ Color3::Color3(const Vector3& v) {
     }
     
     
    -Color3::Color3(const class Color3uint8& other) {
    -    r = other.r / 255.0f;
    -    g = other.g / 255.0f;
    -    b = other.b / 255.0f;
    +Color3::Color3(const class Color3unorm8& other) : r(other.r), g(other.g), b(other.b) {
     }
     
     
     Color3 Color3::fromARGB(uint32 x) {
    -    return Color3((float)((x >> 16) & 0xFF), (float)((x >> 8) & 0xFF), (float)(x & 0xFF)) / 255.0f;
    +    return Color3(Color3unorm8::fromARGB(x));
    +}
    +
    +Color3 Color3::fromASRGB(uint32 x) {
    +    return Color3(Color3unorm8::fromARGB(x)).pow(2.2f);
     }
     
     //----------------------------------------------------------------------------
    @@ -247,7 +269,7 @@ Color3 Color3::random() {
     //----------------------------------------------------------------------------
     Color3& Color3::operator/= (float fScalar) {
         if (fScalar != 0.0f) {
    -		float fInvScalar = 1.0f / fScalar;
    +        float fInvScalar = 1.0f / fScalar;
             r *= fInvScalar;
             g *= fInvScalar;
             b *= fInvScalar;
    @@ -262,10 +284,10 @@ Color3& Color3::operator/= (float fScalar) {
     
     //----------------------------------------------------------------------------
     float Color3::unitize (float fTolerance) {
    -	float fLength = length();
    +    float fLength = length();
     
         if ( fLength > fTolerance ) {
    -		float fInvLength = 1.0f / fLength;
    +        float fInvLength = 1.0f / fLength;
             r *= fInvLength;
             g *= fInvLength;
             b *= fInvLength;
    @@ -313,56 +335,56 @@ Color3 Color3::fromHSV(const Vector3& _hsv) {
     
     
     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;
    -	}
    -	
    +    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; 
    +    hsv.y = (hsv.z - x) / hsv.z; 
     
         if (G3D::fuzzyEq(hsv.y, 0.0f)) {
    -		return hsv;
    -	}
    +        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);
    +    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;
    -	}
    -	
    +    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;
    +    return hsv;
     }
     
     Color3 Color3::jetColorMap(const float& val) {
    -	debugAssertM(val <= 1.0f && val >= 0.0f , "value should be in [0,1]");
    +    debugAssertM(val <= 1.0f && val >= 0.0f , "value should be in [0,1]");
     
    -	//truncated triangles where sides have slope 4
    -	Color3 jet;
    +    //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::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);
    +    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;
    +    return jet;
     }
     
     
    diff --git a/deps/g3dlite/source/Color4.cpp b/deps/g3dlite/source/Color4.cpp
    index eab09eb9c..5c1117c6b 100644
    --- a/deps/g3dlite/source/Color4.cpp
    +++ b/deps/g3dlite/source/Color4.cpp
    @@ -1,20 +1,17 @@
     /**
    - @file Color4.cpp
    + \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
    + \author Morgan McGuire, http://graphics.cs.williams.edu
     
    -
    - @created 2002-06-25
    - @edited  2009-11-10
    + \created 2002-06-25
    + \edited  2011-09-10
      */
     
     #include 
     #include "G3D/Color4.h"
    -#include "G3D/Color4uint8.h"
    +#include "G3D/Color4unorm8.h"
     #include "G3D/Vector4.h"
     #include "G3D/format.h"
     #include "G3D/BinaryInput.h"
    @@ -24,38 +21,39 @@
     
     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];
    +    any.verifyNameBeginsWith("Color", "Power", "Radiance", "Irradiance", "Energy", "Radiosity", "Biradiance");
    +
    +    if (any.name().find('3') != std::string::npos) {
    +        // This is a Color3 constructor--extend with alpha = 1
    +        *this = Color4(Color3(any), 1.0f);
         } else {
    -        any.verifyName("Color4::fromARGB");
    -        *this = Color4::fromARGB((int)any[0].number());
    +
    +        if (any.type() == Any::TABLE) {
    +            any.verifyName("Color4");
    +            AnyTableReader atr(any);
    +            atr.getIfPresent("r", r);
    +            atr.getIfPresent("g", g);
    +            atr.getIfPresent("b", b);
    +            atr.getIfPresent("a", a);
    +            atr.verifyDone();
    +        } 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((uint32)any[0].number());
    +        }
         }
     }
        
     
    -Color4::operator Any() const {
    +Any Color4::toAny() const {
         Any any(Any::ARRAY, "Color4");
         any.append(r, g, b, a);
         return any;
    @@ -99,8 +97,7 @@ Color4::Color4(const Vector4& v) {
     }
     
     
    -Color4::Color4(const Color4uint8& c) : r(c.r), g(c.g), b(c.b), a(c.a) {
    -    *this /= 255.0f;
    +Color4::Color4(const Color4unorm8& c) : r(c.r), g(c.g), b(c.b), a(c.a) {
     }
     
     size_t Color4::hashCode() const {
    @@ -148,7 +145,7 @@ Color4 Color4::operator/ (float fScalar) const {
         Color4 kQuot;
     
         if (fScalar != 0.0f) {
    -		float fInvScalar = 1.0f / fScalar;
    +        float fInvScalar = 1.0f / fScalar;
             kQuot.r = fInvScalar * r;
             kQuot.g = fInvScalar * g;
             kQuot.b = fInvScalar * b;
    @@ -165,7 +162,7 @@ Color4 Color4::operator/ (float fScalar) const {
     
     Color4& Color4::operator/= (float fScalar) {
         if (fScalar != 0.0f) {
    -		float fInvScalar = 1.0f / fScalar;
    +        float fInvScalar = 1.0f / fScalar;
             r *= fInvScalar;
             g *= fInvScalar;
             b *= fInvScalar;
    diff --git a/deps/g3dlite/source/Cone.cpp b/deps/g3dlite/source/Cone.cpp
    index 3104b8424..586ccfd67 100644
    --- a/deps/g3dlite/source/Cone.cpp
    +++ b/deps/g3dlite/source/Cone.cpp
    @@ -17,6 +17,24 @@
     
     namespace G3D {
     
    +
    +float Cone::solidAngleFromHalfAngle(float halfAngle){
    +    return 2.0f * pif() * (1 - cosf(halfAngle));
    +}
    +
    +double Cone::solidAngleFromHalfAngle(double halfAngle){
    +    return 2.0 * pi() * (1.0 - cos(halfAngle));
    +}
    +
    +float Cone::halfAngleFromSolidAngle(float solidAngle){
    +    return acos((1.0f - (solidAngle / (2.0f * pif()))));
    +}
    +
    +double Cone::halfAngleFromSolidAngle(double solidAngle){
    +    return aCos((1.0 - (solidAngle / (2.0 * pi()))));
    +}
    +
    +
     Cone::Cone(const Vector3 &tip, const Vector3 &direction, float angle) {
         this->tip = tip;
         this->direction = direction.direction();
    @@ -26,6 +44,42 @@ Cone::Cone(const Vector3 &tip, const Vector3 &direction, float angle) {
         debugAssert(angle <= pi());
     }
     
    +Vector3 Cone::randomDirectionInCone(Random& rng) const {
    +        const float cosThresh = cos(angle);
    +
    +        float cosAngle;
    +        float normalizer;
    +        Vector3 v;
    +        do {
    +            float vlenSquared;
    +
    +            // Sample uniformly on a sphere by rejection sampling and then normalizing
    +            do {
    +                v.x = rng.uniform(-1, 1);
    +                v.y = rng.uniform(-1, 1);
    +                v.z = rng.uniform(-1, 1);
    +
    +                // Sample uniformly on a cube
    +                vlenSquared = v.squaredLength();
    +            } while (vlenSquared > 1);
    +
    +
    +            const float temp = v.dot(direction);
    +        
    +            // Compute 1 / ||v||, but
    +            // if the vector is in the wrong hemisphere, flip the sign
    +            normalizer = rsqrt(vlenSquared) * sign(temp);
    +
    +            // Cosine of the angle between v and the light's negative-z axis
    +            cosAngle = temp * normalizer;
    +
    +        } while (cosAngle < cosThresh);
    +
    +        // v was within the cone.  Normalize it and maybe flip the hemisphere.
    +        return v * normalizer;
    +    }
    +
    +
     /**
      Forms the smallest cone that contains the box.  Undefined if
      the tip is inside or on the box.
    diff --git a/deps/g3dlite/source/ConvexPolyhedron.cpp b/deps/g3dlite/source/ConvexPolyhedron.cpp
    index 5fa76e3ed..b76d9160b 100644
    --- a/deps/g3dlite/source/ConvexPolyhedron.cpp
    +++ b/deps/g3dlite/source/ConvexPolyhedron.cpp
    @@ -27,7 +27,7 @@ ConvexPolygon::ConvexPolygon(const Vector3& v0, const Vector3& v1, const Vector3
     
     
     bool ConvexPolygon::isEmpty() const {
    -    return (_vertex.length() == 0) || (getArea() <= fuzzyEpsilon);
    +    return (_vertex.length() == 0) || (getArea() <= fuzzyEpsilon32);
     }
     
     
    @@ -41,7 +41,7 @@ float ConvexPolygon::getArea() const {
     
         int length = _vertex.length();
         // Split into triangle fan, compute individual area
    -    for (int v = 2; v < length; v++) {
    +    for (int v = 2; v < length; ++v) {
             int i0 = 0;
             int i1 = v - 1;
             int i2 = v;
    @@ -110,7 +110,7 @@ void ConvexPolygon::cut(const Plane& plane, ConvexPolygon &above, ConvexPolygon
             below._vertex.append(_vertex[v]);
         }
     
    -    for (v = 1; v < length; v++) {
    +    for (v = 1; v < length; ++v) {
             bool isAbove = plane.halfSpaceContains(_vertex[v]);
         
             if (lastAbove ^ isAbove) {
    @@ -141,7 +141,7 @@ void ConvexPolygon::cut(const Plane& plane, ConvexPolygon &above, ConvexPolygon
                 } else {
                     newEdge.start = interp;
                 }
    -            count++;
    +            ++count;
             }
     
             lastAbove = isAbove;
    @@ -191,7 +191,7 @@ ConvexPolygon ConvexPolygon::inverse() const {
         int length = _vertex.length();
         result._vertex.resize(length);
         
    -    for (int v = 0; v < length; v++) {
    +    for (int v = 0; v < length; ++v) {
             result._vertex[v] = _vertex[length - v - 1];
         }
     
    @@ -210,7 +210,7 @@ void ConvexPolygon::removeDuplicateVertices(){
                     --i; // Don't move forward.
                 }
             }
    -	
    +    
             // Check the last vertex against the first.
             if (_vertex[_vertex.size()-1].fuzzyEq(_vertex[0])){
                 _vertex.pop();
    @@ -239,7 +239,7 @@ float ConvexPolyhedron::getVolume() const {
         // 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++) {        
    +    for (int f = 1; f < face.length(); ++f) {        
             const ConvexPolygon& poly = face[f];
             
             float height = (poly._vertex[0] - v0).dot(poly.normal());
    @@ -252,7 +252,7 @@ float ConvexPolyhedron::getVolume() const {
     }
     
     bool ConvexPolyhedron::isEmpty() const {
    -    return (face.length() == 0) || (getVolume() <= fuzzyEpsilon);
    +    return (face.length() == 0) || (getVolume() <= fuzzyEpsilon32);
     }
     
     void ConvexPolyhedron::cut(const Plane& plane, ConvexPolyhedron &above, ConvexPolyhedron &below) {
    @@ -280,11 +280,11 @@ void ConvexPolyhedron::cut(const Plane& plane, ConvexPolyhedron &above, ConvexPo
                 for (int v = poly._vertex.length() - 1; (v >= 0) && (!ruledOut); v--) { 
                     double r = abc.dot(poly._vertex[v]) + d;
                     if (r > eps) {
    -                    numAbove++;
    +                    ++numAbove;
                     } else if (r < -eps) {
    -                    numBelow++;
    +                    ++numBelow;
                     } else {
    -                    numIn++;
    +                    ++numIn;
                     }
     
                     ruledOut = (numAbove != 0) && (numBelow !=0);
    @@ -333,11 +333,11 @@ void ConvexPolyhedron::cut(const Plane& plane, ConvexPolyhedron &above, ConvexPo
                 const Array& _vertex = (aEmpty ? b._vertex : a._vertex);
                 int L = _vertex.length();
                 int count = 0;
    -            for (int v = 0; v < L; v++) {
    +            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++;
    +                    ++count;
                     }
                 }
     
    @@ -366,7 +366,7 @@ void ConvexPolyhedron::cut(const Plane& plane, ConvexPolyhedron &above, ConvexPo
             // Collect the final polgyon by sorting the edges
             int numVertices = edge.length();
     /*debugPrintf("\n");
    -for (int xx=0; xx < numVertices; xx++) {
    +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());
    @@ -387,7 +387,7 @@ for (int xx=0; xx < numVertices; xx++) {
                 int index = 0;
                 int num = edge.length();
                 double distance = (edge[index].start - last_vertex).squaredMagnitude();
    -            for (int e = 1; e < num; e++) {
    +            for (int e = 1; e < num; ++e) {
                     double d = (edge[e].start - last_vertex).squaredMagnitude();
     
                     if (d < distance) {
    @@ -430,7 +430,7 @@ bool ConvexPolygon2D::contains(const Vector2& p, bool reverse) const {
         // the polygon.  (To adapt this algorithm for a concave polygon,
         // the *sum* of the areas must be non-negative).
     
    -    float r = reverse ? -1 : 1;
    +    float r = reverse ? -1.0f : 1.0f;
     
         for (int i0 = 0; i0 < m_vertex.size(); ++i0) {
             int i1 = (i0 + 1) % m_vertex.size();
    diff --git a/deps/g3dlite/source/CoordinateFrame.cpp b/deps/g3dlite/source/CoordinateFrame.cpp
    index 7f9a4c098..e2c08a54e 100644
    --- a/deps/g3dlite/source/CoordinateFrame.cpp
    +++ b/deps/g3dlite/source/CoordinateFrame.cpp
    @@ -1,14 +1,14 @@
     /**
    - @file CoordinateFrame.cpp
    + \file CoordinateFrame.cpp
     
      Coordinate frame class
     
    - @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    + \maintainer Morgan McGuire, http://graphics.cs.williams.edu
     
    - @created 2001-06-02
    - @edited  2010-03-13
    + \created 2001-06-02
    + \edited  2012-09-29
     
    - Copyright 2000-2010, Morgan McGuire.
    + Copyright 2000-2012, Morgan McGuire.
      All rights reserved.
     */
     
    @@ -28,16 +28,17 @@
     #include "G3D/stringutils.h"
     #include "G3D/PhysicsFrame.h"
     #include "G3D/UprightFrame.h"
    +#include "G3D/Frustum.h"
     
     namespace G3D {
     
     
     std::string CoordinateFrame::toXYZYPRDegreesString() const {
    -    UprightFrame uframe(*this);
    +    float x,y,z,yaw,pitch,roll;
    +    getXYZYPRDegrees(x,y,z,yaw,pitch,roll);
         
         return format("CFrame::fromXYZYPRDegrees(% 5.1ff, % 5.1ff, % 5.1ff, % 5.1ff, % 5.1ff, % 5.1ff)", 
    -                  uframe.translation.x, uframe.translation.y, uframe.translation.z, 
    -                  toDegrees(uframe.yaw), toDegrees(uframe.pitch), 0.0f);
    +                  x,y,z,yaw,pitch,roll);
     }
     
     
    @@ -46,10 +47,12 @@ CoordinateFrame::CoordinateFrame(const Any& any) {
     
         const std::string& n = toUpper(any.name());
     
    -    if (beginsWith(n, "VECTOR3")) {
    -        translation = any;
    +    if (beginsWith(n, "VECTOR3") || beginsWith(n, "POINT3")) {
    +        translation = Point3(any);
         } else if (beginsWith(n, "MATRIX3")) {
    -        rotation = any;
    +        rotation = Matrix3(any);
    +    } else if (beginsWith(n, "MATRIX4")) {
    +        *this = Matrix4(any).approxCoordinateFrame();
         } else if ((n == "CFRAME") || (n == "COORDINATEFRAME")) {
             any.verifyType(Any::TABLE, Any::ARRAY);
             if (any.type() == Any::ARRAY) {
    @@ -57,19 +60,15 @@ CoordinateFrame::CoordinateFrame(const Any& any) {
                 rotation    = any[0];
                 translation = any[1];
             } else {
    -            for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
    -                const std::string& n = toLower(it->key);
    -                if (n == "translation") {
    -                    translation = Vector3(it->value);
    -                } else if (n == "rotation") {
    -                    rotation = Matrix3(it->value);
    -                } else {
    -                    any.verify(false, "Illegal table key: " + it->key);
    -                }
    -            }
    +            AnyTableReader r(any);
    +            r.getIfPresent("translation", translation);
    +            r.getIfPresent("rotation", rotation);
    +            r.verifyDone();
             }
         } else if (beginsWith(n, "PHYSICSFRAME") || beginsWith(n, "PFRAME")) {
             *this = PhysicsFrame(any);
    +//    } else if (beginsWith(n, "UPRIGHTFRAME") || beginsWith(n, "UFRAME")) {
    +//        *this = UprightFrame(any);
         } else {
             any.verifyName("CFrame::fromXYZYPRDegrees", "CoordinateFrame::fromXYZYPRDegrees");
             any.verifyType(Any::ARRAY);
    @@ -78,18 +77,18 @@ CoordinateFrame::CoordinateFrame(const Any& any) {
             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);
    +                                  (s > 3) ? (float)any[3].number() : 0.0f,
    +                                  (s > 4) ? (float)any[4].number() : 0.0f,
    +                                  (s > 5) ? (float)any[5].number() : 0.0f);
         }
     }
     
     
    -CoordinateFrame::operator Any() const {
    +Any CoordinateFrame::toAny() 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);
    +    a.append(x, y, z);
         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)) {
    @@ -114,11 +113,7 @@ CoordinateFrame::CoordinateFrame() :
     
     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 Matrix3& rotation = Matrix3::fromEulerAnglesYXZ(yaw, pitch, roll);
         const Vector3 translation(x, y, z);
         
         return CoordinateFrame(rotation, translation);
    @@ -131,28 +126,7 @@ void CoordinateFrame::getXYZYPRRadians(float& x, float& y, float& z,
         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
    -    }
    +    rotation.toEulerAnglesYXZ(yaw, pitch, roll);
     }
     
     
    @@ -234,24 +208,55 @@ std::string CoordinateFrame::toXML() const {
     
     
     Plane CoordinateFrame::toObjectSpace(const Plane& p) const {
    +    // TODO
         Vector3 N, P;
         double d;
         p.getEquation(N, d);
         P = N * (float)d;
         P = pointToObjectSpace(P);
         N = normalToObjectSpace(N);
    +    debugAssertM(isFinite(d), "Not implemented for infinite planes");
         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);
    +Frustum CoordinateFrame::toWorldSpace(const Frustum& f) const {
    +    Frustum g;
    +    g.vertexPos.resize(f.vertexPos.size());
    +    g.faceArray.resize(f.faceArray.size());
    +
    +    for (int i = 0; i < f.vertexPos.size(); ++i) {
    +        g.vertexPos[i] = toWorldSpace(f.vertexPos[i]);
    +    }
    +    for (int i = 0; i < f.faceArray.size(); ++i) {
    +        g.faceArray[i].plane = toWorldSpace(f.faceArray[i].plane);
    +        for (int j = 0; j < 4; ++j) {
    +            g.faceArray[i].vertexIndex[j] = f.faceArray[i].vertexIndex[j];
    +        }
    +    }
    +
    +    return g;
    +}
    +
    +
    +Plane CoordinateFrame::toWorldSpace(const Plane& plane) const {
    +    // Since there is no scale factor, we don't have to 
    +    // worry about the inverse transpose of the normal.
    +    Vector3 normal;
    +    float d;
    +        
    +    plane.getEquation(normal, d);
    +        
    +    const Vector3& newNormal = rotation * normal;
    +        
    +    if (isFinite(d)) {
    +        d = (newNormal * -d + translation).dot(newNormal);
    +        return Plane(newNormal, newNormal * d);
    +    } else {
    +        // When d is infinite, we can't multiply 0's by it without
    +        // generating NaNs.
    +        return Plane::fromEquation(newNormal.x, newNormal.y, newNormal.z, d);
    +    }
     }
     
     
    @@ -285,6 +290,20 @@ Capsule CoordinateFrame::toWorldSpace(const Capsule& c) const {
     }
     
     
    +void CoordinateFrame::toWorldSpace(const AABox& b, AABox& result) const {
    +    if (b.isEmpty()) {
    +        result = b;
    +    } else if (! b.isFinite()) {
    +        // We can't combine infinite elements under a matrix
    +        // multiplication: if the computation performs inf-inf we'll
    +        // get NaN.  So treat the box as infinite in all directions.
    +        result = AABox::inf();
    +    } else {
    +        toWorldSpace(Box(b)).getBounds(result);
    +    }
    +}
    +
    +
     Box CoordinateFrame::toWorldSpace(const AABox& b) const {
         Box b2(b);
         return toWorldSpace(b2);
    @@ -292,18 +311,17 @@ Box CoordinateFrame::toWorldSpace(const AABox& b) const {
     
     
     Box CoordinateFrame::toWorldSpace(const Box& b) const {
    +    if(!b.isFinite()) {
    +        return b;
    +    }
         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);
    +    for (int i = 0; i < 3; ++i) {
    +        out._edgeVector[i] = vectorToWorldSpace(out._edgeVector[i]);
    +    }
    +
    +    out._area   = b._area;
    +    out._volume = b._volume;
     
         return out;
     }
    @@ -376,11 +394,11 @@ void CoordinateFrame::lookAt(
         }
     
         up -= look * look.dot(up);
    -    up.unitize();
    +    up = up.direction();
     
         Vector3 z = -look;
         Vector3 x = -z.cross(up);
    -    x.unitize();
    +    x = x.direction();
     
         Vector3 y = z.cross(x);
     
    @@ -390,6 +408,14 @@ void CoordinateFrame::lookAt(
     }
     
     
    +void CoordinateFrame::moveTowards(const CoordinateFrame& goal, float maxTranslation, float maxRotation) {
    +    translation.moveTowards(goal.translation, maxTranslation);
    +    Quat q(rotation);
    +    q.moveTowards(Quat(goal.rotation), maxRotation);
    +    rotation = Matrix3(q);
    +}
    +
    +
     CoordinateFrame CoordinateFrame::lerp(
         const CoordinateFrame&  other,
         float                   alpha) const {
    diff --git a/deps/g3dlite/source/Crypto.cpp b/deps/g3dlite/source/Crypto.cpp
    index c69b23375..8d54fbeea 100644
    --- a/deps/g3dlite/source/Crypto.cpp
    +++ b/deps/g3dlite/source/Crypto.cpp
    @@ -11,7 +11,7 @@
     #include "G3D/platform.h"
     #include "G3D/Crypto.h"
     #include "G3D/g3dmath.h"
    -#include 
    +#include "zlib.h"
     
     namespace G3D {
         
    @@ -64,7 +64,8 @@ int Crypto::numSmallPrimes() {
     }
     
     uint32 Crypto::crc32(const void* byte, size_t numBytes) {
    -    return ::crc32(::crc32(0, Z_NULL, 0), static_cast(byte), numBytes);
    +    alwaysAssertM(numBytes < 0xFFFFFFFF, "Not implemented for arrays larger than 2^32 bytes");
    +    return ::crc32(::crc32(0, Z_NULL, 0), static_cast(byte), (int)numBytes);
     }
     
     } // G3D
    diff --git a/deps/g3dlite/source/Crypto_md5.cpp b/deps/g3dlite/source/Crypto_md5.cpp
    index c7ee535d6..6fca6383f 100644
    --- a/deps/g3dlite/source/Crypto_md5.cpp
    +++ b/deps/g3dlite/source/Crypto_md5.cpp
    @@ -38,9 +38,9 @@ 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_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
    @@ -55,7 +55,7 @@ static void md5_init(md5_state_t *pms);
     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]);
    +static void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
     #ifdef __cplusplus
     }    
     #endif
    @@ -100,7 +100,7 @@ MD5Hash Crypto::md5(const void* data, size_t n) {
     
       This code implements the MD5 Algorithm defined in RFC 1321, whose
       text is available at
    -	http://www.ietf.org/rfc/rfc1321.txt
    +    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
    @@ -111,14 +111,14 @@ MD5Hash Crypto::md5(const void* data, size_t n) {
       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 
    -	in library.
    +    either statically or dynamically; added missing #include 
    +    in library.
       2002-03-11 lpd Corrected argument list for main(), and added int return
    -	type, in test program and T value program.
    +    type, in test program and T value program.
       2002-02-21 lpd Added missing #include  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.
    +    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.
    @@ -220,8 +220,8 @@ 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];
    +    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. */
    @@ -234,51 +234,51 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
     
         {
     #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;
    +    /*
    +     * 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 */
    +    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;
    -	    }
    -	}
    +#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 */
    +    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        /* 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) */
    +        X = xbuf;        /* (dynamic only) */
     #  else
    -#    define xbuf X		/* (static only) */
    +#    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);
    -	}
    +        for (i = 0; i < 16; ++i, xp += 4)
    +        xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
    +    }
     #endif
         }
     
    @@ -416,56 +416,56 @@ md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
         md5_word_t nbits = (md5_word_t)(nbytes << 3);
     
         if (nbytes <= 0)
    -	return;
    +    return;
     
         /* Update the message length. */
         pms->count[1] += nbytes >> 29;
         pms->count[0] += nbits;
         if (pms->count[0] < nbits)
    -	pms->count[1]++;
    +    pms->count[1]++;
     
         /* Process an initial partial block. */
         if (offset) {
    -	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
    +    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);
    +    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);
    +    md5_process(pms, p);
     
         /* Process a final partial block. */
         if (left)
    -	memcpy(pms->buf, p, 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
    +    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));
    +    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));
    +    digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
     }
     
     }
    diff --git a/deps/g3dlite/source/Cylinder.cpp b/deps/g3dlite/source/Cylinder.cpp
    index 7a7b9f944..32d14e96b 100644
    --- a/deps/g3dlite/source/Cylinder.cpp
    +++ b/deps/g3dlite/source/Cylinder.cpp
    @@ -22,7 +22,7 @@
     namespace G3D {
     
     Cylinder::Cylinder(class BinaryInput& b) {
    -	deserialize(b);
    +    deserialize(b);
     }
     
     
    @@ -31,48 +31,48 @@ Cylinder::Cylinder() {
     
     
     Cylinder::Cylinder(const Vector3& _p1, const Vector3& _p2, float _r) 
    -	: p1(_p1), p2(_p2), mRadius(_r) {
    +    : p1(_p1), p2(_p2), mRadius(_r) {
     }
     
     
     void Cylinder::serialize(class BinaryOutput& b) const {
    -	p1.serialize(b);
    -	p2.serialize(b);
    -	b.writeFloat64(mRadius);
    +    p1.serialize(b);
    +    p2.serialize(b);
    +    b.writeFloat64(mRadius);
     }
     
     
     void Cylinder::deserialize(class BinaryInput& b) {
    -	p1.deserialize(b);
    -	p2.deserialize(b);
    -	mRadius = b.readFloat64();
    +    p1.deserialize(b);
    +    p2.deserialize(b);
    +    mRadius = (float)b.readFloat64();
     }
     
     
     Line Cylinder::axis() const {
    -	return Line::fromTwoPoints(p1, p2);
    +    return Line::fromTwoPoints(p1, p2);
     }
     
     
     
     float Cylinder::radius() const {
    -	return mRadius;
    +    return mRadius;
     }
     
     
     float Cylinder::volume() const {
    -	return
    -		(float)pi() * square(mRadius) * (p1 - p2).magnitude();
    +    return
    +        (float)pi() * square(mRadius) * (p1 - p2).magnitude();
     }
     
     
     float Cylinder::area() const {
    -	return
    +    return
             // Sides
    -		(twoPi() * mRadius) * height() +
    +        ((float)twoPi() * mRadius) * height() +
     
              // Caps
    -         twoPi() * square(mRadius);
    +         (float)twoPi() * square(mRadius);
     }
     
     void Cylinder::getBounds(AABox& out) const {
    diff --git a/deps/g3dlite/source/FileSystem.cpp b/deps/g3dlite/source/FileSystem.cpp
    index f082937a9..06e6ff00a 100644
    --- a/deps/g3dlite/source/FileSystem.cpp
    +++ b/deps/g3dlite/source/FileSystem.cpp
    @@ -1,10 +1,10 @@
     /**
    - @file FileSystem.cpp
    + \file FileSystem.cpp
      
    - @author Morgan McGuire, http://graphics.cs.williams.edu
    + \author Morgan McGuire, http://graphics.cs.williams.edu
      
    - @author  2002-06-06
    - @edited  2010-04-10
    + \author  2002-06-06
    + \edited  2010-10-10
      */
     #include "G3D/FileSystem.h"
     #include "G3D/System.h"
    @@ -19,7 +19,7 @@
     #include "G3D/BinaryInput.h"
     #include "G3D/BinaryOutput.h"
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         // Needed for _getcwd
     #   include 
     
    @@ -36,16 +36,16 @@
     #   include 
     #   define _getcwd getcwd
     #   define _stat stat
    -#endif
    -
    -#ifdef __CYGWIN__
    -#define stat64 stat
    +#   define stricmp strcasecmp 
    +#   define strnicmp strncasecmp 
     #endif
     
     namespace G3D {
     
     static FileSystem* common = NULL;
     
    +GMutex FileSystem::mutex;
    +
     FileSystem& FileSystem::instance() {
         init();
         return *common;
    @@ -70,24 +70,24 @@ FileSystem::FileSystem() : m_cacheLifetime(10) {}
     
     /////////////////////////////////////////////////////////////
     
    -bool FileSystem::Dir::contains(const std::string& f) const {
    +bool FileSystem::Dir::contains(const std::string& f, bool caseSensitive) const {
         
         for (int i = 0; i < nodeArray.size(); ++i) {
    -#       ifdef G3D_WIN32
    -            if (stricmp(f.c_str(), nodeArray[i].name.c_str()) == 0) {
    -                return true;
    -            }
    -#       else
    +        if (caseSensitive) {
                 if (f == nodeArray[i].name) {
                     return true;
                 }
    -#       endif
    +        } else if (stricmp(f.c_str(), nodeArray[i].name.c_str()) == 0) {
    +            return true;
    +        }
         }
         return false;
     }
    +
         
    -void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::string& pathInsideZipfile) {
    +void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::string& _pathInsideZipfile) {
     #if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
    +    const std::string& pathInsideZipfile = FilePath::canonicalize(_pathInsideZipfile);
         struct zip* z = zip_open( FilePath::removeTrailingSlash(zipfile).c_str(), ZIP_CHECKCONS, NULL );
         debugAssert(z);
     
    @@ -99,22 +99,23 @@ void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::s
             zip_stat_index( z, i, ZIP_FL_NOCASE, &info );
             
             // Fully-qualified name of a file inside zipfile
    -        std::string name = info.name;
    +        std::string name = FilePath::canonicalize(info.name);
     
             if (beginsWith(name, pathInsideZipfile)) {
                 // We found something inside the directory we were looking for,
    -            // so the directory itself must exist                        
    +            // so the directory itself must exist
                 exists = true;
     
                 // For building the cached directory listing, extract only elements that do not contain 
                 // additional subdirectories.
     
    -            int start = pathInsideZipfile.size();
    -            if ((int(name.length()) > start) && isSlash(name[start])) {
    +            size_t start = pathInsideZipfile.size();
    +            if ((name.length() > start) && isSlash(name[start])) {
                     ++start;
                 }
    -            int end = findSlash(name, start);
    -            if (end == -1) {
    +
    +            size_t end = findSlash(name, start);
    +            if (end == std::string::npos) {
                     // There are no more slashes; add this name
                     name = name.substr(start);
                     if (alreadyAdded.insert(name)) {
    @@ -126,8 +127,8 @@ void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::s
                     // There are more slashes, indicating that this is a directory
                     name = name.substr(start, end);
                     if (alreadyAdded.insert(name)) {
    -                    Entry& e = nodeArray.next();
    -                    e.name = name;
    +                    Entry& e = nodeArray.next();                    
    +                    e.name = FilePath::removeTrailingSlash(name);
                         e.type = DIR_TYPE;
                     }
                 }
    @@ -136,13 +137,16 @@ void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::s
         
         zip_close(z);
         z = NULL;
    +#else
    +    (void)zipfile;
    +    (void)_pathInsideZipfile;
     #endif
     }
     
     
     FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpdate) {
         const std::string& key = 
    -#   if defined(G3D_WIN32)
    +#   if defined(G3D_WINDOWS)
             FilePath::canonicalize(FilePath::removeTrailingSlash(toLower(FilePath::canonicalize(resolve(path)))));
     #   else
             FilePath::canonicalize(FilePath::removeTrailingSlash(FilePath::canonicalize(resolve(path))));
    @@ -156,10 +160,17 @@ FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpda
     
             // Out of date: update
             dir.lastChecked = now;
    -
    -        struct _stat st;
    -        const bool exists = _stat(key.c_str(), &st) != -1;
    -        const bool isDirectory = (st.st_mode & S_IFDIR) != 0;
    +#       ifdef G3D_WINDOWS
    +            // On windows, we have to use GetFileAttributes (http://msdn.microsoft.com/en-us/library/aa364944(v=vs.85).aspx) instead of 
    +            // stat in order to work with network shares
    +            const DWORD st = GetFileAttributesA(key.c_str());
    +            const bool exists = (st != INVALID_FILE_ATTRIBUTES);
    +            const bool isDirectory = (st & FILE_ATTRIBUTE_DIRECTORY) != 0;
    +#       else
    +            struct _stat st;
    +            const bool exists = _stat(key.c_str(), &st) != -1;
    +            const bool isDirectory = (st.st_mode & S_IFDIR) != 0;
    +#       endif
     
             // Does this path exist on the real filesystem?
             if (exists && isDirectory) {
    @@ -168,7 +179,7 @@ FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpda
                 if (isDirectory) {
                     dir.exists = true;
                     // Update contents
    -#               ifdef G3D_WIN32
    +#               ifdef G3D_WINDOWS
                         const std::string& filespec = FilePath::concat(key, "*");
                         struct _finddata_t fileinfo;
                         intptr_t handle = _findfirst(filespec.c_str(), &fileinfo);
    @@ -238,7 +249,6 @@ FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpda
                     // There is a zipfile somewhere in the path.  Does
                     // the rest of the path exist inside the zipfile?
                     dir.inZipfile = true;
    -
                     dir.computeZipListing(zip, path.substr(zip.length() + 1));
                 }
             }        
    @@ -248,27 +258,24 @@ FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpda
     }
     
     
    -bool FileSystem::_inZipfile(const std::string& path, std::string& z) {
    +bool FileSystem::_inZipfile(const std::string& _path, std::string& z) {
    +    const std::string& path = FilePath::expandEnvironmentVariables(_path);
    +
         // Reject trivial cases before parsing
    -    if (path.find('.') == std::string::npos) {
    -        // There is no zipfile possible, since G3D requires
    -        // an extension on zipfiles.
    -        return false;
    -    }
     
         // Look at all sub-paths containing periods.
         // For each, ask if it is a zipfile.
    -    int current = 0;
    +    size_t current = 0;
         current = path.find('.', current);
     
    -    while (current != -1) {
    +    while (current != std::string::npos) {
             // xxxxx/foo.zip/yyyyy
             current = path.find('.', current);
     
             // Look forward for the next slash
    -        int s = findSlash(path, current);
    +        size_t s = findSlash(path, current);
     
    -        if (s == -1) {
    +        if (s == std::string::npos) {
                 // No more slashes
                 return false;
             }
    @@ -286,17 +293,17 @@ bool FileSystem::_inZipfile(const std::string& path, std::string& z) {
     }
     
     
    -bool FileSystem::_isZipfile(const std::string& filename) {
    -    if (FilePath::ext(filename).empty()) {
    -        return false;
    -    }
    +bool FileSystem::_isZipfile(const std::string& _filename) {
    +    const std::string& filename = FilePath::canonicalize(FilePath::expandEnvironmentVariables(_filename));
    +
    +
         
         FILE* f = fopen(FilePath::removeTrailingSlash(filename).c_str(), "r");
         if (f == NULL) {
             return false;
         }
         uint8 header[4];
    -    fread(header, 4, 1, f);
    +    (void)fread(header, 4, 1, f);
         
         const uint8 zipHeader[4] = {0x50, 0x4b, 0x03, 0x04};
         for (int i = 0; i < 4; ++i) {
    @@ -311,7 +318,9 @@ bool FileSystem::_isZipfile(const std::string& filename) {
     }
     
     
    -FILE* FileSystem::_fopen(const char* filename, const char* mode) {
    +FILE* FileSystem::_fopen(const char* _filename, const char* mode) {
    +    const std::string& filename = FilePath::canonicalize(FilePath::expandEnvironmentVariables(_filename));
    +
         for (const char* m = mode; *m != '\0'; ++m) {
             if (*m == 'w') {
                 // Purge the cache entry for the parent of this directory
    @@ -319,11 +328,15 @@ FILE* FileSystem::_fopen(const char* filename, const char* mode) {
                 break;
             }
         }
    -    return ::fopen(filename, mode);
    +
    +    markFileUsed(filename);
    +    return ::fopen(filename.c_str(), mode);
     }
     
     
    -void FileSystem::_clearCache(const std::string& path) {
    +void FileSystem::_clearCache(const std::string& _path) {
    +    const std::string& path = FilePath::expandEnvironmentVariables(_path);
    +
         if ((path == "") || FilePath::isRoot(path)) {
             m_cache.clear();
         } else {
    @@ -331,7 +344,7 @@ void FileSystem::_clearCache(const std::string& path) {
             m_cache.getKeys(keys);
     
             const std::string& prefix = 
    -#           ifdef G3D_WIN32
    +#           ifdef G3D_WINDOWS
                     toLower(FilePath::canonicalize(FilePath::removeTrailingSlash(_resolve(path))));
     #           else
                     FilePath::canonicalize(FilePath::removeTrailingSlash(_resolve(path)));
    @@ -353,8 +366,9 @@ void FileSystem::_setCacheLifetime(float t) {
     }
     
     
    -void FileSystem::_createDirectory(const std::string& dir) {
    -    
    +void FileSystem::_createDirectory(const std::string& _dir) {
    +    const std::string& dir = FilePath::expandEnvironmentVariables(_dir);
    +
         if (dir == "") {
             return;
         }
    @@ -395,7 +409,7 @@ void FileSystem::_createDirectory(const std::string& dir) {
             if (! _exists(p)) {
                 // Windows only requires one argument to mkdir,
                 // where as unix also requires the permissions.
    -#           ifndef G3D_WIN32
    +#           ifndef G3D_WINDOWS
                     mkdir(p.c_str(), 0777);
     #           else
                     _mkdir(p.c_str());
    @@ -407,8 +421,10 @@ void FileSystem::_createDirectory(const std::string& dir) {
     }
     
     
    -void FileSystem::_copyFile(const std::string& source, const std::string& dest) {
    -#   ifdef G3D_WIN32
    +void FileSystem::_copyFile(const std::string& _source, const std::string& _dest) {
    +    const std::string& source = FilePath::expandEnvironmentVariables(_source);
    +    const std::string& dest = FilePath::expandEnvironmentVariables(_dest);
    +#   ifdef G3D_WINDOWS
             // TODO: handle case where srcPath is in a zipfile
             CopyFileA(source.c_str(), dest.c_str(), FALSE);
             _clearCache(FilePath::parent(_resolve(dest)));
    @@ -422,10 +438,11 @@ void FileSystem::_copyFile(const std::string& source, const std::string& dest) {
     }
     
     
    -bool FileSystem::_exists(const std::string& f, bool trustCache) {
    +bool FileSystem::_exists(const std::string& _f, bool trustCache, bool caseSensitive) {
    +    const std::string& f = FilePath::expandEnvironmentVariables(_f);
     
         if (FilePath::isRoot(f)) {
    -#       ifdef G3D_WIN32
    +#       ifdef G3D_WINDOWS
                 const std::string& winname = toLower(f.substr(0, 1)) + ":\\";
                 return _drives().contains(winname);
     #       else
    @@ -433,10 +450,11 @@ bool FileSystem::_exists(const std::string& f, bool trustCache) {
     #       endif
         }
     
    -    std::string path = FilePath::removeTrailingSlash(f);
    -    std::string parentPath = FilePath::parent(path);
    +    const std::string& path = FilePath::removeTrailingSlash(f);
    +    const std::string& parentPath = FilePath::parent(path);
     
    -    const Dir& entry = getContents(parentPath, ! trustCache);
    +    const bool forceUpdate = ! trustCache;
    +    const Dir& entry = getContents(parentPath, forceUpdate);
     
         if (FilePath::containsWildcards(f)) {
             if (! entry.exists) {
    @@ -446,15 +464,9 @@ bool FileSystem::_exists(const std::string& f, bool trustCache) {
     
             const std::string& pattern = FilePath::baseExt(path);
     
    -#       ifdef G3D_WIN32
    -            static const int flags = FNM_CASEFOLD;
    -#       else
    -            static const int flags = 0;
    -#       endif
    -
             // See if any element of entry matches the wild card
             for (int i = 0; i < entry.nodeArray.size(); ++i) {
    -            if (FilePath::matches(entry.nodeArray[i].name, pattern, flags)) {
    +            if (FilePath::matches(entry.nodeArray[i].name, pattern, caseSensitive)) {
                     return true;
                 }
             }
    @@ -463,12 +475,13 @@ bool FileSystem::_exists(const std::string& f, bool trustCache) {
             return false;
     
         } else {
    -        return entry.exists && entry.contains(FilePath::baseExt(path));
    +        return entry.exists && entry.contains(FilePath::baseExt(path), caseSensitive);
         }
     }
     
     
    -bool FileSystem::_isDirectory(const std::string& filename) {
    +bool FileSystem::_isDirectory(const std::string& _filename) {
    +    const std::string& filename = FilePath::expandEnvironmentVariables(_filename);
         // TODO: work with zipfiles and cache
         struct _stat st;
         const bool exists = _stat(FilePath::removeTrailingSlash(filename).c_str(), &st) != -1;
    @@ -476,14 +489,33 @@ bool FileSystem::_isDirectory(const std::string& filename) {
     }
     
     
    -std::string FileSystem::_resolve(const std::string& filename, const std::string& cwd) {
    +void FileSystem::_removeFile(const std::string& path) {
    +    alwaysAssertM(! inZipfile(path), "Cannot invoke removeFile() on files inside zipfiles.");
    +    Array files;
    +    getFiles(path, files, true);
    +
    +    for (int i = 0; i < files.size(); ++i) {
    +        const std::string& filename = files[i];
    +        int retval = ::remove(filename.c_str());
    +        (void)retval;
    +    }
    +    
    +    // Remove from cache
    +    _clearCache(FilePath::parent(path));
    +}
    +
    +
    +std::string FileSystem::_resolve(const std::string& _filename, const std::string& _cwd) {
    +    const std::string& filename = FilePath::expandEnvironmentVariables(_filename);
    +    const std::string& cwd = FilePath::expandEnvironmentVariables(_cwd);
    +
         if (filename.size() >= 1) {
             if (isSlash(filename[0])) {
                 // Already resolved
                 return filename;
             } else {
     
    -            #ifdef G3D_WIN32
    +            #ifdef G3D_WINDOWS
                     if ((filename.size() >= 2) && (filename[1] == ':')) {
                         // There is a drive spec on the front.
                         if ((filename.size() >= 3) && isSlash(filename[2])) {
    @@ -511,12 +543,29 @@ std::string FileSystem::_currentDirectory() {
         static const int N = 2048;
         char buffer[N];
     
    -    _getcwd(buffer, N);
    +    (void)_getcwd(buffer, N);
         return std::string(buffer);
     }
     
     
    -bool FileSystem::_isNewer(const std::string& src, const std::string& dst) {
    +static Set _filesUsed;
    +
    +void FileSystem::markFileUsed(const std::string& filename) {
    +    mutex.lock();
    +    _filesUsed.insert(filename);
    +    mutex.unlock();
    +}
    +
    +
    +const Set& FileSystem::usedFiles() {
    +    return _filesUsed;
    +}
    +
    +
    +bool FileSystem::_isNewer(const std::string& _src, const std::string& _dst) {
    +    const std::string& src = FilePath::expandEnvironmentVariables(_src);
    +    const std::string& dst = FilePath::expandEnvironmentVariables(_dst);
    +
         // TODO: work with cache and zipfiles
         struct _stat sts;
         bool sexists = _stat(src.c_str(), &sts) != -1;
    @@ -528,7 +577,9 @@ bool FileSystem::_isNewer(const std::string& src, const std::string& dst) {
     }
     
     
    -int64 FileSystem::_size(const std::string& filename) {
    +int64 FileSystem::_size(const std::string& _filename) {
    +    const std::string& filename = FilePath::canonicalize(FilePath::expandEnvironmentVariables(_filename));
    +
         struct stat64 st;
         int result = stat64(filename.c_str(), &st);
         
    @@ -544,6 +595,7 @@ int64 FileSystem::_size(const std::string& filename) {
                     struct zip_stat info;
                     zip_stat_init( &info );    // Docs unclear if zip_stat_init is required.
                     int success = zip_stat( z, contents.c_str(), ZIP_FL_NOCASE, &info );
    +                (void) success;
                     debugAssertM(success == 0, zip + ": " + contents + ": zip stat failed.");
                     requiredMem = info.size;
                 }
    @@ -553,7 +605,7 @@ int64 FileSystem::_size(const std::string& filename) {
     #endif
                 return -1;
     #if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
    -        }
    +         }
     #endif
         }
         
    @@ -561,7 +613,12 @@ int64 FileSystem::_size(const std::string& filename) {
     }
     
     
    -void FileSystem::listHelper(const std::string& shortSpec, const std::string& parentPath, Array& result, const ListSettings& settings) {
    +void FileSystem::listHelper
    +(const std::string&  shortSpec,
    + const std::string&  parentPath, 
    + Array& result, 
    + const ListSettings& settings) {
    +
         Dir& dir = getContents(parentPath, false);
     
         if (! dir.exists) {
    @@ -573,8 +630,10 @@ void FileSystem::listHelper(const std::string& shortSpec, const std::string& par
             // See if it matches the spec
             if (FilePath::matches(entry.name, shortSpec, settings.caseSensitive)) {
     
    -            if ((entry.type == UNKNOWN) && ! (settings.files && settings.directories)) {
    -                // Update the type
    +            if ((entry.type == UNKNOWN) && 
    +                (! (settings.files && settings.directories) ||
    +                 settings.recursive)) {
    +                // Update the type: it is unknown and we'll need to branch onit below
                     entry.type = isDirectory(FilePath::concat(parentPath, entry.name)) ? DIR_TYPE : FILE_TYPE;
                 }
                 
    @@ -589,15 +648,23 @@ void FileSystem::listHelper(const std::string& shortSpec, const std::string& par
                     }
                 }
             } // match
    +  
    +        if (settings.recursive) {
    +            if (entry.type == UNKNOWN) {
    +                entry.type = isDirectory(FilePath::concat(parentPath, entry.name)) ? DIR_TYPE : FILE_TYPE;
    +            }
     
    -        if (settings.recursive && (entry.type == DIR_TYPE)) {
    -            listHelper(shortSpec, FilePath::concat(parentPath, entry.name), result, settings);
    +            if (entry.type == DIR_TYPE) {
    +                listHelper(shortSpec, FilePath::concat(parentPath, entry.name), result, settings);
    +            }
             }
         } // for
     }
     
     
    -void FileSystem::_list(const std::string& spec, Array& result, const ListSettings& settings) {
    +void FileSystem::_list(const std::string& _spec, Array& result, const ListSettings& settings) {
    +    const std::string& spec = FilePath::expandEnvironmentVariables(_spec);
    +
         const std::string& shortSpec = FilePath::baseExt(spec);
         const std::string& parentPath = FilePath::parent(spec);
     
    @@ -606,7 +673,7 @@ void FileSystem::_list(const std::string& spec, Array& result, cons
     
     
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     const Array& FileSystem::_drives() {
         if (m_winDrive.length() == 0) {
             // See http://msdn.microsoft.com/en-us/library/aa364975(VS.85).aspx
    @@ -615,10 +682,10 @@ const Array& FileSystem::_drives() {
             GetLogicalDriveStringsA(bufSize, bufData);
     
             // Drive list is a series of NULL-terminated strings, itself terminated with a NULL.
    -        for (int i = 0; bufData[i] != '\0'; ++i) {
    +        for (size_t i = 0; bufData[i] != '\0'; ++i) {
                 const char* thisString = bufData + i;
                 m_winDrive.append(toLower(thisString));
    -            i += strlen(thisString) + 1;
    +            i += strlen(thisString);
             }
         }
     
    @@ -629,7 +696,7 @@ const Array& FileSystem::_drives() {
     /////////////////////////////////////////////////////////////////////
     
     bool FilePath::isRoot(const std::string& f) {
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
             if (f.length() < 2) {
                 return false;
             }
    @@ -644,9 +711,17 @@ bool FilePath::isRoot(const std::string& f) {
                 }
             }
     
    -        if (isSlash(f[0]) && isSlash(f[1])) {        
    -            // e.g., "\\foo\"
    -            return true;
    +        // Windows shares are considered roots, but only if this does not include a path inside the share
    +        if (isSlash(f[0]) && isSlash(f[1])) {
    +            size_t i = f.find("/", 3);
    +            size_t j = f.find("\\", 3);
    +
    +            if (i == std::string::npos) {
    +                i = j;
    +            }
    +
    +            // e.g., "\\foo\", "\\foo"
    +            return ((i == std::string::npos) || (i == f.length() - 1));
             }
     #   else
             if (f == "/") {
    @@ -678,8 +753,8 @@ std::string FilePath::concat(const std::string& dirname, const std::string& file
     
     
     std::string FilePath::ext(const std::string& filename) {
    -    int i = filename.rfind(".");
    -    if (i >= 0) {
    +    size_t i = filename.rfind(".");
    +    if (i != std::string::npos) {
             return filename.substr(i + 1, filename.length() - i);
         } else {
             return "";
    @@ -688,16 +763,16 @@ std::string FilePath::ext(const std::string& filename) {
     
     
     std::string FilePath::baseExt(const std::string& filename) {
    -    int i = findLastSlash(filename);
    +    size_t i = findLastSlash(filename);
     
    -#   ifdef G3D_WIN32
    -        int j = filename.rfind(":");
    -        if ((i == -1) && (j >= 0)) {
    +#   ifdef G3D_WINDOWS
    +        size_t j = filename.rfind(":");
    +        if ((i == std::string::npos) && (j != std::string::npos)) {
                 i = j;
             }
     #   endif
     
    -    if (i == -1) {
    +    if (i == std::string::npos) {
             return filename;
         } else {
             return filename.substr(i + 1, filename.length() - i);
    @@ -707,8 +782,8 @@ std::string FilePath::baseExt(const std::string& filename) {
     
     std::string FilePath::base(const std::string& path) {
         std::string filename = baseExt(path);
    -    int i = filename.rfind(".");
    -    if (i == -1) {
    +    size_t i = filename.rfind(".");
    +    if (i == std::string::npos) {
             // No extension
             return filename;
         } else {
    @@ -718,16 +793,16 @@ std::string FilePath::base(const std::string& path) {
     
     
     std::string FilePath::parent(const std::string& path) {    
    -    int i = findLastSlash(removeTrailingSlash(path));
    +    size_t i = findLastSlash(removeTrailingSlash(path));
     
    -#   ifdef G3D_WIN32
    -        int j = path.rfind(":");
    -        if ((i == -1) && (j >= 0)) {
    +#   ifdef G3D_WINDOWS
    +        size_t j = path.rfind(":");
    +        if ((i == std::string::npos) && (j != std::string::npos)) {
                 i = j;
             }
     #   endif
     
    -    if (i == -1) {
    +    if (i == std::string::npos) {
             return "";
         } else {
             return path.substr(0, i + 1);
    @@ -759,7 +834,6 @@ std::string FilePath::canonicalize(std::string x) {
         return x;
     }
     
    -
     void FilePath::parse
     (const std::string&     filename,
      std::string&           root,
    @@ -796,7 +870,7 @@ void FilePath::parse
     
             }
     
    -    } else if ((f.size() >= 2) & isSlash(f[0]) && isSlash(f[1])) {
    +    } else if ((f.size() >= 2) && isSlash(f[0]) && isSlash(f[1])) {
             
             // e.g. //foo
             root = f.substr(0, 2);
    @@ -816,7 +890,7 @@ void FilePath::parse
     
             if (i != std::string::npos) {
                 // Make sure it is after the last slash!
    -            size_t j = iMax(f.rfind('/'), f.rfind('\\'));
    +	    size_t j = findLastSlash(f);
                 if ((j == std::string::npos) || (i > j)) {
                     ext = f.substr(i + 1, f.size() - i - 1);
                     f = f.substr(0, i);
    @@ -827,7 +901,7 @@ void FilePath::parse
         // Pull the basename off
         {
             // Find the last slash
    -        size_t i = iMax(f.rfind('/'), f.rfind('\\'));
    +        size_t i = findLastSlash(f);
             
             if (i == std::string::npos) {
                 
    @@ -860,7 +934,7 @@ void FilePath::parse
                 j = f.size();
             }
     
    -        cur = iMin(i, j);
    +        cur = min(i, j);
     
             if (cur == std::string::npos) {
                 cur = f.size();
    @@ -871,4 +945,86 @@ void FilePath::parse
         }
     }
     
    +
    +std::string FilePath::expandEnvironmentVariables(const std::string& path) {
    +    // Search for pattern
    +    size_t end = path.find_first_of('$', 0);
    +    if (end == std::string::npos) {
    +        // Pattern does not exist
    +        return path;
    +    }
    +
    +    size_t start = 0;
    +    std::string result;
    +    while (end != std::string::npos) {
    +        const std::string& before = path.substr(start, end - start);
    +        result += before;
    +        start = end + 1;
    +        std::string var;
    +        if (path[start] == '(') {
    +            // Search for close paren
    +            end = path.find_first_of(')', start + 1);
    +            if (end == std::string::npos) {
    +                throw std::string("Missing close paren in environment variable in \"") + path + "\"";
    +            }
    +            var = path.substr(start + 1, end - start - 1);
    +        } else {
    +            // Search for slash or end of string
    +            end = path.find_first_of('/', start);
    +            size_t i = path.find_first_of('\\', start);
    +            if ((size_t(i) != std::string::npos) && ((end == std::string::npos) || (size_t(i) < end))) {
    +                end = i;
    +            }
    +            if (end == std::string::npos) {
    +                // If the varible goes to the end of the string, it is the rest of the string
    +                end = path.size();
    +            } else {
    +                --end;
    +            }
    +            var = path.substr(start, end - start + 1);
    +        }
    +
    +        if (! var.empty()) {
    +            const char* value = getenv(var.c_str());
    +
    +            if (value == NULL) {
    +                throw (std::string("LocalLightingEnvironment variable \"") + var + "\" not defined for path \"" + path + "\"");
    +            } else {
    +                result += value;
    +            }
    +        } else {
    +            // We just parsed an "empty" variable, which was probably a default share on Windows, e.g.,
    +            // "\\mycomputer\c$", and not a variable name.
    +            result += "$";            
    +        }
    +
    +        start = end + 1;
    +        end = path.find_first_of('$', start);
    +    }
    +
    +    // Paste on the remainder of the source path
    +    if (start < path.size()) {
    +        result += path.substr(start);
    +    }
    +
    +    return result;
    +}
    +
    +
    +/** Generate a unique filename based on the provided hint */
    +std::string FilePath::makeLegalFilename(const std::string& f, size_t maxLength) {
    +    std::string tentative;
    +    
    +    for (size_t i = 0; i < G3D::min(maxLength, f.size()); ++i) {
    +        const char c = f[i];
    +        if (isLetter(c) || isDigit(c) || (c == '-') || (c == '+') || (c == '=') || (c == '(') || (c == ')')) {
    +            tentative += c;
    +        } else {
    +            tentative += "_";
    +        }
    +    }
    +
    +    return tentative;
    +}
    +
     }
    diff --git a/deps/g3dlite/source/GThread.cpp b/deps/g3dlite/source/GThread.cpp
    index 607e4b357..5f3f7ffd6 100644
    --- a/deps/g3dlite/source/GThread.cpp
    +++ b/deps/g3dlite/source/GThread.cpp
    @@ -4,7 +4,7 @@
      GThread class.
     
      @created 2005-09-24
    - @edited  2005-10-22
    + @edited  2010-09-22
      */
     
     #include "G3D/GThread.h"
    @@ -38,7 +38,7 @@ GThread::GThread(const std::string& name):
         m_status(STATUS_CREATED),
         m_name(name) {
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         m_event = NULL;
     #endif
     
    @@ -56,15 +56,16 @@ GThread::~GThread() {
     #   pragma warning( pop )
     #endif
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         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);
    +    return shared_ptr(new _internal::BasicThread(name, proc, param));
     }
     
     
    @@ -72,6 +73,38 @@ bool GThread::started() const {
         return m_status != STATUS_CREATED;
     }
     
    +
    +int GThread::numCores() {
    +    return System::numCores();
    +}
    +
    +#ifdef G3D_WINDOWS
    +// From http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
    +const DWORD MS_VC_EXCEPTION=0x406D1388;
    +
    +#pragma pack(push,8)
    +typedef struct tagTHREADNAME_INFO {
    +   DWORD dwType; // Must be 0x1000.
    +   LPCSTR szName; // Pointer to name (in user addr space).
    +   DWORD dwThreadID; // Thread ID (-1=caller thread).
    +   DWORD dwFlags; // Reserved for future use, must be zero.
    +} THREADNAME_INFO;
    +#pragma pack(pop)
    +
    +static void SetThreadName(DWORD dwThreadID, const char* threadName) {
    +   THREADNAME_INFO info;
    +   info.dwType = 0x1000;
    +   info.szName = threadName;
    +   info.dwThreadID = dwThreadID;
    +   info.dwFlags = 0;
    +
    +   __try {
    +      RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
    +   } __except(EXCEPTION_EXECUTE_HANDLER) {}
    +}
    +#endif
    +
    +
     bool GThread::start(SpawnBehavior behavior) {
         
         debugAssertM(! started(), "Thread has already executed.");
    @@ -89,7 +122,7 @@ bool GThread::start(SpawnBehavior behavior) {
             return true;
         }
     
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
             DWORD threadId;
     
             m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
    @@ -102,6 +135,8 @@ bool GThread::start(SpawnBehavior behavior) {
                 m_event = NULL;
             }
     
    +        SetThreadName(threadId, m_name.c_str());
    +
             return (m_handle != NULL);
     #   else
             if (!pthread_create(&m_handle, NULL, &internalThreadProc, this)) {
    @@ -117,7 +152,7 @@ bool GThread::start(SpawnBehavior behavior) {
     
     void GThread::terminate() {
         if (m_handle) {
    -#       ifdef G3D_WIN32
    +#       ifdef G3D_WINDOWS
             ::TerminateThread(m_handle, 0);
     #       else
             pthread_kill(m_handle, SIGSTOP);
    @@ -144,7 +179,7 @@ void GThread::waitForCompletion() {
             return;
         }
     
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
             debugAssert(m_event);
             ::WaitForSingleObject(m_event, INFINITE);
     #   else
    @@ -154,7 +189,7 @@ void GThread::waitForCompletion() {
     }
     
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     DWORD WINAPI GThread::internalThreadProc(LPVOID param) {
         GThread* current = reinterpret_cast(param);
         debugAssert(current->m_event);
    @@ -178,7 +213,7 @@ void* GThread::internalThreadProc(void* param) {
     
     //GMutex implementation
     GMutex::GMutex() {
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         ::InitializeCriticalSection(&m_handle);
     #else
         int ret = pthread_mutexattr_init(&m_attr);
    @@ -192,7 +227,7 @@ GMutex::GMutex() {
     
     GMutex::~GMutex() {
         //TODO: Debug check for locked
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         ::DeleteCriticalSection(&m_handle);
     #else
         int ret = pthread_mutex_destroy(&m_handle);
    @@ -203,7 +238,7 @@ GMutex::~GMutex() {
     }
     
     bool GMutex::tryLock() {
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         return (::TryEnterCriticalSection(&m_handle) != 0);
     #else
         return (pthread_mutex_trylock(&m_handle) == 0);
    @@ -211,7 +246,7 @@ bool GMutex::tryLock() {
     }
     
     void GMutex::lock() {
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         ::EnterCriticalSection(&m_handle);
     #else
         pthread_mutex_lock(&m_handle);
    @@ -219,7 +254,7 @@ void GMutex::lock() {
     }
     
     void GMutex::unlock() {
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         ::LeaveCriticalSection(&m_handle);
     #else
         pthread_mutex_unlock(&m_handle);
    diff --git a/deps/g3dlite/source/GUniqueID.cpp b/deps/g3dlite/source/GUniqueID.cpp
    index 84c853e0e..7dcc3ccd2 100644
    --- a/deps/g3dlite/source/GUniqueID.cpp
    +++ b/deps/g3dlite/source/GUniqueID.cpp
    @@ -8,8 +8,27 @@
     #include "G3D/BinaryOutput.h"
     #include "G3D/TextOutput.h"
     #include "G3D/NetworkDevice.h"
    +#include "G3D/Any.h"
     
     namespace G3D {
    +    
    +GUniqueID& GUniqueID::operator=(const Any& a) {
    +    a.verifyName("GUniqueID");
    +    a.verifyType(Any::ARRAY);
    +    a.verifySize(1);
    +    std::string s = a[0];
    +    a.verify(s.length() == 16);
    +    id = GUniqueID::fromString16(s);
    +    return *this;
    +}
    +
    +
    +Any GUniqueID::toAny() const {
    +    Any a(Any::ARRAY, "GUniqueID");
    +    a.append(toString16());
    +    return a;
    +}
    +
     
     void GUniqueID::serialize(BinaryOutput& b) const {
         b.writeUInt64(id);
    @@ -34,6 +53,33 @@ void GUniqueID::deserialize(TextInput& t) {
     }
     
     
    +GUniqueID GUniqueID::NONE(uint16 tag) {
    +    GUniqueID i;
    +    uint64 t = tag;
    +    i.id = (t << 54);
    +    return i;
    +}
    +
    +
    +std::string GUniqueID::toString16() const {
    +    return format("%08x%08x", uint32(id >> 32), uint32(id & 0xFFFFFFFF));
    +}
    +
    +
    +GUniqueID GUniqueID::fromString16(const std::string& s) {
    +    if (s.length() != 16) {
    +        debugAssertM(false, "Corrupt 16-character string");
    +        return GUniqueID();
    +    }
    +    
    +    uint32 high = 0, low = 0;
    +    sscanf(s.c_str(), "%08x%08x", &high, &low);
    +    GUniqueID i;
    +    i.id = (uint64(high) << 32) | low;
    +    return i;
    +}
    +
    +
     GUniqueID GUniqueID::create(uint16 tag) {
         static uint64 counter = 0;
         static uint64 systemID = 0;
    diff --git a/deps/g3dlite/source/Image1.cpp b/deps/g3dlite/source/Image1.cpp
    index a61f7faa6..ed125adad 100644
    --- a/deps/g3dlite/source/Image1.cpp
    +++ b/deps/g3dlite/source/Image1.cpp
    @@ -1,21 +1,23 @@
     /**
    -  @file Image1.cpp
    +  \file G3D/Image1.cpp
     
    -  @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    +  \maintainer Morgan McGuire, http://graphics.cs.williams.edu
     
    -  @created 2007-01-31
    -  @edited  2007-01-31
    +  \created 2007-01-31
    +  \edited  2012-12-25
     */
     
     
     #include "G3D/Image1.h"
    -#include "G3D/Image1uint8.h"
    -#include "G3D/GImage.h"
    +#include "G3D/Image1unorm8.h"
    +#include "G3D/Image.h"
     #include "G3D/Color4.h"
    -#include "G3D/Color4uint8.h"
    +#include "G3D/Color4unorm8.h"
     #include "G3D/Color1.h"
    -#include "G3D/Color1uint8.h"
    +#include "G3D/Color1unorm8.h"
     #include "G3D/ImageFormat.h"
    +#include "G3D/PixelTransferBuffer.h"
    +#include "G3D/CPUPixelTransferBuffer.h"
     
     namespace G3D {
     
    @@ -24,30 +26,12 @@ Image1::Image1(int w, int h, WrapMode wrap) : Map2D(w, h, wrap)
     }
     
     
    -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& im) {
    +Image1::Ref Image1::fromImage1unorm8(const shared_ptr& im) {
         Ref out = createEmpty(static_cast(im->wrapMode()));
         out->resize(im->width(), im->height());
     
         int N = im->width() * im->height();
    -    const Color1uint8* src = reinterpret_cast(im->getCArray());
    +    const Color1unorm8* src = reinterpret_cast(im->getCArray());
         for (int i = 0; i < N; ++i) {
             out->data[i] = Color1(src[i]);
         }
    @@ -57,7 +41,7 @@ Image1::Ref Image1::fromImage1uint8(const ReferenceCountedPointer&
     
     
     Image1::Ref Image1::createEmpty(int width, int height, WrapMode wrap) {
    -    return new Type(width, height, wrap);
    +    return Image1::Ref(new Type(width, height, wrap));
     }
     
     
    @@ -66,20 +50,49 @@ Image1::Ref Image1::createEmpty(WrapMode wrap) {
     }
     
     
    -Image1::Ref Image1::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
    +Image1::Ref Image1::fromFile(const std::string& filename, WrapMode wrap) {
         Ref out = createEmpty(wrap);
    -    out->load(filename, fmt);
    +    out->load(filename);
         return out;
     }
     
     
    -void Image1::load(const std::string& filename, GImage::Format fmt) {
    -    copyGImage(GImage(filename, fmt));
    +void Image1::load(const std::string& filename) {
    +    shared_ptr image = Image::fromFile(filename);
    +    if (image->format() != ImageFormat::L32F()) {
    +        image->convertToL8();
    +    }
    +
    +    switch (image->format()->code)
    +    {
    +        case ImageFormat::CODE_L8:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_L32F:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGB8:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGB32F:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGBA8:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGBA32F:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        default:
    +            debugAssertM(false, "Trying to load unsupported image format");
    +            break;
    +    }
    +
         setChanged(true);
     }
     
     
    -Image1::Ref Image1::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
    +Image1::Ref Image1::fromArray(const class Color3unorm8* ptr, int w, int h, WrapMode wrap) {
         Ref out = createEmpty(wrap);
         out->copyArray(ptr, w, h);
         return out;
    @@ -93,7 +106,7 @@ Image1::Ref Image1::fromArray(const class Color1* ptr, int w, int h, WrapMode wr
     }
     
     
    -Image1::Ref Image1::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
    +Image1::Ref Image1::fromArray(const class Color1unorm8* ptr, int w, int h, WrapMode wrap) {
         Ref out = createEmpty(wrap);
         out->copyArray(ptr, w, h);
         return out;
    @@ -107,7 +120,7 @@ Image1::Ref Image1::fromArray(const class Color3* ptr, int w, int h, WrapMode wr
     }
     
     
    -Image1::Ref Image1::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
    +Image1::Ref Image1::fromArray(const class Color4unorm8* ptr, int w, int h, WrapMode wrap) {
         Ref out = createEmpty(wrap);
         out->copyArray(ptr, w, h);
         return out;
    @@ -120,24 +133,7 @@ Image1::Ref Image1::fromArray(const class Color4* ptr, int w, int h, WrapMode wr
         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) {
    +void Image1::copyArray(const Color3unorm8* src, int w, int h) {
         resize(w, h);
     
         int N = w * h;
    @@ -149,7 +145,7 @@ void Image1::copyArray(const Color3uint8* src, int w, int h) {
     }
     
     
    -void Image1::copyArray(const Color4uint8* src, int w, int h) {
    +void Image1::copyArray(const Color4unorm8* src, int w, int h) {
         resize(w, h);
     
         int N = w * h;
    @@ -181,7 +177,7 @@ void Image1::copyArray(const Color4* src, int w, int h) {
     }
     
     
    -void Image1::copyArray(const Color1uint8* src, int w, int h) {
    +void Image1::copyArray(const Color1unorm8* src, int w, int h) {
         resize(w, h);
         int N = w * h;
     
    @@ -203,17 +199,10 @@ void Image1::copyArray(const Color3* src, int w, int h) {
     }
     
     
    -/** 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);
    +void Image1::save(const std::string& filename) {
    +    // To avoid saving as floating point image.  FreeImage cannot convert floating point to L8.
    +    Image1unorm8::Ref unorm8 = Image1unorm8::fromImage1(dynamic_pointer_cast(shared_from_this()));
    +    unorm8->save(filename);
     }
     
     
    diff --git a/deps/g3dlite/source/Image3.cpp b/deps/g3dlite/source/Image3.cpp
    index 0d85bdf45..671ad4b84 100644
    --- a/deps/g3dlite/source/Image3.cpp
    +++ b/deps/g3dlite/source/Image3.cpp
    @@ -4,18 +4,20 @@
       @maintainer Morgan McGuire, http://graphics.cs.williams.edu
     
       @created 2007-01-31
    -  @edited  2007-01-31
    +  @edited  2012-12-25
     */
     
     
     #include "G3D/Image3.h"
    -#include "G3D/Image3uint8.h"
    -#include "G3D/GImage.h"
    +#include "G3D/Image3unorm8.h"
    +#include "G3D/Image.h"
     #include "G3D/Color4.h"
    -#include "G3D/Color4uint8.h"
    +#include "G3D/Color4unorm8.h"
     #include "G3D/Color1.h"
    -#include "G3D/Color1uint8.h"
    +#include "G3D/Color1unorm8.h"
     #include "G3D/ImageFormat.h"
    +#include "G3D/PixelTransferBuffer.h"
    +#include "G3D/CPUPixelTransferBuffer.h"
     
     namespace G3D {
     
    @@ -24,30 +26,12 @@ Image3::Image3(int w, int h, WrapMode wrap) : Map2D(w, h, wrap)
     }
     
     
    -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& im) {
    +Image3::Ref Image3::fromImage3unorm8(const shared_ptr& im) {
         Ref out = createEmpty(im->wrapMode());
         out->resize(im->width(), im->height());
     
         int N = im->width() * im->height();
    -    const Color3uint8* src = reinterpret_cast(im->getCArray());
    +    const Color3unorm8* src = reinterpret_cast(im->getCArray());
         for (int i = 0; i < N; ++i) {
             out->data[i] = Color3(src[i]);
         }
    @@ -57,7 +41,7 @@ Image3::Ref Image3::fromImage3uint8(const ReferenceCountedPointer&
     
     
     Image3::Ref Image3::createEmpty(int width, int height, WrapMode wrap) {
    -    return new Image3(width, height, wrap);
    +    return shared_ptr(new Image3(width, height, wrap));
     }
     
     
    @@ -66,20 +50,49 @@ Image3::Ref Image3::createEmpty(WrapMode wrap) {
     }
     
     
    -Image3::Ref Image3::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
    +Image3::Ref Image3::fromFile(const std::string& filename, WrapMode wrap) {
         Ref out = createEmpty(wrap);
    -    out->load(filename, fmt);
    +    out->load(filename);
         return out;
     }
     
     
    -void Image3::load(const std::string& filename, GImage::Format fmt) {
    -    copyGImage(GImage(filename, fmt));
    +void Image3::load(const std::string& filename) {
    +    shared_ptr image = Image::fromFile(filename);
    +    if (image->format() != ImageFormat::RGB32F()) {
    +        image->convertToRGB8();
    +    }
    +
    +    switch (image->format()->code)
    +    {
    +        case ImageFormat::CODE_L8:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_L32F:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGB8:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGB32F:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGBA8:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGBA32F:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        default:
    +            debugAssertM(false, "Trying to load unsupported image format");
    +            break;
    +    }
    +
         setChanged(true);
     }
     
     
    -Image3::Ref Image3::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
    +Image3::Ref Image3::fromArray(const class Color3unorm8* ptr, int w, int h, WrapMode wrap) {
         Ref out = createEmpty(wrap);
         out->copyArray(ptr, w, h);
         return out;
    @@ -93,7 +106,7 @@ Image3::Ref Image3::fromArray(const class Color1* ptr, int w, int h, WrapMode wr
     }
     
     
    -Image3::Ref Image3::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
    +Image3::Ref Image3::fromArray(const class Color1unorm8* ptr, int w, int h, WrapMode wrap) {
         Ref out = createEmpty(wrap);
         out->copyArray(ptr, w, h);
         return out;
    @@ -107,7 +120,7 @@ Image3::Ref Image3::fromArray(const class Color3* ptr, int w, int h, WrapMode wr
     }
     
     
    -Image3::Ref Image3::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
    +Image3::Ref Image3::fromArray(const class Color4unorm8* ptr, int w, int h, WrapMode wrap) {
         Ref out = createEmpty(wrap);
         out->copyArray(ptr, w, h);
         return out;
    @@ -121,24 +134,7 @@ Image3::Ref Image3::fromArray(const class Color4* ptr, int w, int h, WrapMode wr
     }
     
     
    -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) {
    +void Image3::copyArray(const Color3unorm8* src, int w, int h) {
         resize(w, h);
     
         int N = w * h;
    @@ -150,7 +146,7 @@ void Image3::copyArray(const Color3uint8* src, int w, int h) {
     }
     
     
    -void Image3::copyArray(const Color4uint8* src, int w, int h) {
    +void Image3::copyArray(const Color4unorm8* src, int w, int h) {
         resize(w, h);
     
         int N = w * h;
    @@ -182,7 +178,7 @@ void Image3::copyArray(const Color4* src, int w, int h) {
     }
     
     
    -void Image3::copyArray(const Color1uint8* src, int w, int h) {
    +void Image3::copyArray(const Color1unorm8* src, int w, int h) {
         resize(w, h);
         int N = w * h;
     
    @@ -205,16 +201,10 @@ void Image3::copyArray(const Color1* src, int w, int h) {
     
     
     /** 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);
    +void Image3::save(const std::string& filename) {
    +    // To avoid saving as floating point image.  FreeImage cannot convert floating point to RGB8.
    +    Image3unorm8::Ref unorm8 = Image3unorm8::fromImage3(dynamic_pointer_cast(shared_from_this()));
    +    unorm8->save(filename);
     }
     
     
    diff --git a/deps/g3dlite/source/Image4.cpp b/deps/g3dlite/source/Image4.cpp
    index c6f2b1064..fa36050d3 100644
    --- a/deps/g3dlite/source/Image4.cpp
    +++ b/deps/g3dlite/source/Image4.cpp
    @@ -4,18 +4,20 @@
       @maintainer Morgan McGuire, http://graphics.cs.williams.edu
     
       @created 2007-01-31
    -  @edited  2008-07-27
    +  @edited  2011-08-27
     */
     
     
     #include "G3D/Image4.h"
    -#include "G3D/Image4uint8.h"
    -#include "G3D/GImage.h"
    +#include "G3D/Image4unorm8.h"
    +#include "G3D/Image.h"
     #include "G3D/Color3.h"
    -#include "G3D/Color3uint8.h"
    +#include "G3D/Color3unorm8.h"
     #include "G3D/Color1.h"
    -#include "G3D/Color1uint8.h"
    +#include "G3D/Color1unorm8.h"
     #include "G3D/ImageFormat.h"
    +#include "G3D/PixelTransferBuffer.h"
    +#include "G3D/CPUPixelTransferBuffer.h"
     
     namespace G3D {
     
    @@ -24,30 +26,12 @@ Image4::Image4(int w, int h, WrapMode wrap) : Map2D(w, h, wrap)
     }
     
     
    -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& im) {
    +Image4::Ref Image4::fromImage4unorm8(const shared_ptr& im) {
         Ref out = createEmpty(static_cast(im->wrapMode()));
         out->resize(im->width(), im->height());
     
         int N = im->width() * im->height();
    -    const Color4uint8* src = reinterpret_cast(im->getCArray());
    +    const Color4unorm8* src = reinterpret_cast(im->getCArray());
         for (int i = 0; i < N; ++i) {
             out->data[i] = Color4(src[i]);
         }
    @@ -57,7 +41,7 @@ Image4::Ref Image4::fromImage4uint8(const ReferenceCountedPointer&
     
     
     Image4::Ref Image4::createEmpty(int width, int height, WrapMode wrap) {
    -    return new Type(width, height, wrap);
    +    return shared_ptr(new Type(width, height, wrap));
     }
     
     
    @@ -66,20 +50,49 @@ Image4::Ref Image4::createEmpty(WrapMode wrap) {
     }
     
     
    -Image4::Ref Image4::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
    +Image4::Ref Image4::fromFile(const std::string& filename, WrapMode wrap) {
         Ref out = createEmpty(wrap);
         out->load(filename);
         return out;
     }
     
     
    -void Image4::load(const std::string& filename, GImage::Format fmt) {
    -    copyGImage(GImage(filename, fmt));
    +void Image4::load(const std::string& filename) {
    +    shared_ptr image = Image::fromFile(filename);
    +    if (image->format() != ImageFormat::RGBA32F()) {
    +        image->convertToRGBA8();
    +    }
    +
    +    switch (image->format()->code)
    +    {
    +        case ImageFormat::CODE_L8:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_L32F:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGB8:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGB32F:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGBA8:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        case ImageFormat::CODE_RGBA32F:
    +            copyArray(static_cast(image->toPixelTransferBuffer()->buffer()), image->width(), image->height());
    +            break;
    +        default:
    +            debugAssertM(false, "Trying to load unsupported image format");
    +            break;
    +    }
    +
         setChanged(true);
     }
     
     
    -Image4::Ref Image4::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
    +Image4::Ref Image4::fromArray(const class Color3unorm8* ptr, int w, int h, WrapMode wrap) {
         Ref out = createEmpty(wrap);
         out->copyArray(ptr, w, h);
         return out;
    @@ -93,7 +106,7 @@ Image4::Ref Image4::fromArray(const class Color1* ptr, int w, int h, WrapMode wr
     }
     
     
    -Image4::Ref Image4::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
    +Image4::Ref Image4::fromArray(const class Color1unorm8* ptr, int w, int h, WrapMode wrap) {
         Ref out = createEmpty(wrap);
         out->copyArray(ptr, w, h);
         return out;
    @@ -107,7 +120,7 @@ Image4::Ref Image4::fromArray(const class Color3* ptr, int w, int h, WrapMode wr
     }
     
     
    -Image4::Ref Image4::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
    +Image4::Ref Image4::fromArray(const class Color4unorm8* ptr, int w, int h, WrapMode wrap) {
         Ref out = createEmpty(wrap);
         out->copyArray(ptr, w, h);
         return out;
    @@ -121,24 +134,7 @@ Image4::Ref Image4::fromArray(const class Color4* ptr, int w, int h, WrapMode wr
     }
     
     
    -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) {
    +void Image4::copyArray(const Color4unorm8* src, int w, int h) {
         resize(w, h);
     
         int N = w * h;
    @@ -150,7 +146,7 @@ void Image4::copyArray(const Color4uint8* src, int w, int h) {
     }
     
     
    -void Image4::copyArray(const Color3uint8* src, int w, int h) {
    +void Image4::copyArray(const Color3unorm8* src, int w, int h) {
         resize(w, h);
     
         int N = w * h;
    @@ -182,7 +178,7 @@ void Image4::copyArray(const Color3* src, int w, int h) {
     }
     
     
    -void Image4::copyArray(const Color1uint8* src, int w, int h) {
    +void Image4::copyArray(const Color1unorm8* src, int w, int h) {
         resize(w, h);
         int N = w * h;
     
    @@ -207,16 +203,10 @@ void Image4::copyArray(const Color1* src, int w, int h) {
     
     
     /** 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);
    +void Image4::save(const std::string& filename) {
    +    // To avoid saving as floating point image.  FreeImage cannot convert floating point to RGBA8.
    +    Image4unorm8::Ref unorm8 = Image4unorm8::fromImage4(dynamic_pointer_cast(shared_from_this()));
    +    unorm8->save(filename);
     }
     
     const ImageFormat* Image4::format() const {
    diff --git a/deps/g3dlite/source/ImageFormat.cpp b/deps/g3dlite/source/ImageFormat.cpp
    index 46618c644..0ffc27b66 100644
    --- a/deps/g3dlite/source/ImageFormat.cpp
    +++ b/deps/g3dlite/source/ImageFormat.cpp
    @@ -1,14 +1,15 @@
     /**
    - @file ImageFormat.cpp
    + \file ImageFormat.cpp
      
    - @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    + \maintainer Morgan McGuire, http://graphics.cs.williams.edu
      
    - @created 2003-05-23
    - @edited  2010-03-30
    + \created 2003-05-23
    + \edited  2013-01-12
      */
     
     #include "GLG3D/glheaders.h"
     #include "G3D/ImageFormat.h"
    +#include "G3D/stringutils.h"
     
     namespace G3D {
     
    @@ -24,11 +25,11 @@ ImageFormat::ImageFormat(
         int             _blueBits,
         int             _depthBits,
         int             _stencilBits,
    -    int             _hardwareBitsPerTexel,
    -    int             _packedBitsPerTexel,
    +    int             _openGLBitsPerPixel,
    +    int             _cpuBitsPerPixel,
         int             glDataFormat,
         bool            _opaque,
    -    bool            _floatingPoint,
    +    NumberFormat    _numberFormat,
         Code            _code,
         ColorSpace      _colorSpace,
         BayerPattern    _bayerPattern) : 
    @@ -47,17 +48,30 @@ ImageFormat::ImageFormat(
         blueBits(_blueBits),
         stencilBits(_stencilBits),
         depthBits(_depthBits),
    -    cpuBitsPerPixel(_packedBitsPerTexel),
    -    packedBitsPerTexel(_packedBitsPerTexel),
    -    openGLBitsPerPixel(_hardwareBitsPerTexel),
    -    hardwareBitsPerTexel(_hardwareBitsPerTexel),
    +    cpuBitsPerPixel(_cpuBitsPerPixel),
    +    openGLBitsPerPixel(_openGLBitsPerPixel),
         openGLDataFormat(glDataFormat),
         opaque(_opaque),
    -    floatingPoint(_floatingPoint) {
    +    numberFormat(_numberFormat){
     
    -    debugAssert(_packedBitsPerTexel <= _hardwareBitsPerTexel);
    +    floatingPoint = (numberFormat == FLOATING_POINT_FORMAT);
    +    debugAssert(cpuBitsPerPixel <= openGLBitsPerPixel);
     }
     
    +
    +bool ImageFormat::sameComponents(const ImageFormat* other) const {
    +    return
    +        (numComponents == other->numComponents) &&
    +        ((alphaBits != 0) == (other->alphaBits != 0)) &&
    +        ((redBits != 0) == (other->redBits != 0)) &&
    +        ((greenBits != 0) == (other->greenBits != 0)) &&
    +        ((blueBits != 0) == (other->blueBits != 0)) &&
    +        ((luminanceBits != 0) == (other->luminanceBits != 0)) &&
    +        ((stencilBits != 0) == (other->stencilBits != 0)) &&
    +        ((depthBits != 0) == (other->depthBits != 0));
    +}
    +
    +
     const ImageFormat* ImageFormat::depth(int depthBits) {
     
         switch (depthBits) {
    @@ -98,7 +112,7 @@ const ImageFormat* ImageFormat::stencil(int bits) {
     }
     
     
    -    static const std::string nameArray[] = 
    +    static const std::string nameArray[ImageFormat::CODE_NUM] = 
         {
             "L8", 
             "L16",
    @@ -125,29 +139,62 @@ const ImageFormat* ImageFormat::stencil(int bits) {
             "RGB16F",
             "RGB32F",
             "R11G11B10F",
    -        "RGB9E10F",
    +        "RGB9E5F",
     
             "RGB8I",
             "RGB8UI",
     
    +        "RGBA8I",
             "RGBA8UI",
     
    +        "RGB8_SNORM",
    +        "RGBA8_SNORM",
    +        "RGB16_SNORM",
    +        "RGBA16_SNORM",
    +
             "ARGB8",
             "BGR8",
    +        "BGRA8",
     
             "R8",
    +        "R8I",
    +        "R8UI",
    +
    +        "R16",
    +        "R16I",
    +        "R16UI",
    +
    +        "R32I",
    +        "R32UI",
     
             "RG8",
             "RG8I",
             "RG8UI",
     
    +        "RG16",
    +        "RG16I",
    +        "RG16UI",
    +
    +        "R16F",
             "RG16F",
     
    +        "RG32I",
    +        "RG32UI",
    +
    +        "R32F",
    +        "RG32F",
    +
             "RGBA8",
             "RGBA16",
             "RGBA16F",
             "RGBA32F",
     
    +        "RGBA16I",
    +        "RGBA16UI",
    +
    +        "RGB32I",
    +        "RGB32UI",
    +        "RGBA32I",
             "RGBA32UI",
     
             "BAYER_RGGB8",
    @@ -192,8 +239,7 @@ const ImageFormat* ImageFormat::stencil(int bits) {
             "STENCIL8",
             "STENCIL16",
     
    -        "DEPTH24_STENCIL8",
    -        ""
    +        "DEPTH24_STENCIL8"
         };
     
     const std::string& ImageFormat::name() const {
    @@ -201,10 +247,148 @@ const std::string& ImageFormat::name() const {
         return nameArray[code];
     }
     
    +bool ImageFormat::canInterpretAs(const ImageFormat* otherFormat) const {
    +    if (this == otherFormat) {
    +        return true;
    +    }
    +
    +    if (compressed || otherFormat->compressed) {
    +        return false;
    +    }
    +
    +    if (colorSpace != otherFormat->colorSpace) {
    +        return false;
    +    }
    +
    +    if (floatingPoint != otherFormat->floatingPoint) {
    +        return false;
    +    }
    +
    +    if (numComponents != otherFormat->numComponents) {
    +        return false;
    +    }
    +
    +    if (cpuBitsPerPixel != otherFormat->cpuBitsPerPixel) {
    +        return false;
    +    }
    +
    +    if (openGLDataFormat != otherFormat->openGLDataFormat) {
    +        return false;
    +    }
    +
    +    return true;
    +}
    +
    +
    +const ImageFormat* ImageFormat::getSRGBFormat(const ImageFormat* otherFormat) {
    +    switch (otherFormat->code) {
    +    case CODE_RGB8:
    +        return SRGB8();
    +
    +    case CODE_RGBA8:
    +        return SRGBA8();
    +
    +    case CODE_RGB_DXT1:
    +        return SRGB_DXT1();
    +
    +    case CODE_RGBA_DXT1:
    +        return SRGBA_DXT1();
    +
    +    case CODE_RGBA_DXT3:
    +        return SRGBA_DXT3();
    +
    +    case CODE_RGBA_DXT5:
    +        return SRGBA_DXT5();
    +
    +    default:
    +        return otherFormat;
    +    }
    +}
    +
    +
    +const ImageFormat* ImageFormat::getFormatWithAlpha(const ImageFormat* otherFormat) {
    +    if (! otherFormat->opaque) {
    +        return otherFormat;
    +    }
    +
    +    switch (otherFormat->code) {
    +    case CODE_L8:
    +        return LA8();
    +        break;
    +
    +    case CODE_L16F:
    +        return LA16F();
    +        break;
    +
    +    case CODE_RGB8:
    +        return RGBA8();
    +        break;
    +        
    +    case CODE_RGB8I:
    +        return RGBA8I();
    +        break;
    +
    +    case CODE_RGB32I:
    +        return RGBA32I();
    +        break;
    +
    +    case CODE_RGB32UI:
    +        return RGBA32UI();
    +        break;
    +
    +    case CODE_RGB8UI:
    +        return RGBA8UI();
    +        break;
    +
    +    case CODE_RGB8_SNORM:
    +        return RGB8_SNORM();
    +        break;
    +    case CODE_RGBA8_SNORM:
    +        return RGBA8_SNORM();
    +        break;
    +
    +    case CODE_RGB16_SNORM:
    +        return RGB16_SNORM();
    +        break;
    +
    +    case CODE_RGBA16_SNORM:
    +        return RGBA16_SNORM();
    +        break;
    +        
    +    case CODE_BGR8:
    +        return BGRA8();
    +        break;
    +        
    +    case CODE_RGB16:
    +        return RGBA16();
    +        break;
    +        
    +    case CODE_RGB16F:
    +        return RGBA16F();
    +        break;
    +        
    +    case CODE_RGB32F:
    +        return RGBA32F();
    +        break;
    +
    +    case CODE_R11G11B10F:
    +        return RGBA16F();
    +        break;
    +        
    +    default:
    +        break;
    +    }
    +
    +    return NULL;
    +}
    +
     
     const ImageFormat* ImageFormat::fromString(const std::string& s) {
    -    
    -    for (int i = 0; ! nameArray[i].empty(); ++i) {
    +    if (toLower(s) == "auto") {
    +        return NULL;
    +    }
    +
    +    for (int i = 0; i < CODE_NUM; ++i) {
             if (s == nameArray[i]) {
                 return fromCode(ImageFormat::Code(i));
             }
    @@ -212,7 +396,6 @@ const ImageFormat* ImageFormat::fromString(const std::string& s) {
         return NULL;
     }
     
    -
     const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
         switch (code) {
         case ImageFormat::CODE_L8:
    @@ -250,7 +433,7 @@ const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
     
         case ImageFormat::CODE_LA16F:
             return ImageFormat::LA16F();
    -        break;
    +        
         case ImageFormat::CODE_LA32F:
             return ImageFormat::LA32F();
     
    @@ -287,15 +470,54 @@ const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
         case ImageFormat::CODE_RGB8UI:
             return ImageFormat::RGB8UI();
     
    +    case ImageFormat::CODE_RGBA8I:
    +        return ImageFormat::RGBA8I();
    +
    +    case ImageFormat::CODE_RGBA8UI:
    +        return ImageFormat::RGBA8UI();
    +
    +    case ImageFormat::CODE_RGB8_SNORM:
    +        return ImageFormat::RGB8_SNORM();
    +    case ImageFormat::CODE_RGBA8_SNORM:
    +        return ImageFormat::RGBA8_SNORM();
    +    case ImageFormat::CODE_RGB16_SNORM:
    +        return ImageFormat::RGB16_SNORM();
    +    case ImageFormat::CODE_RGBA16_SNORM:
    +        return ImageFormat::RGBA16_SNORM();
    +
         case ImageFormat::CODE_ARGB8:
             return NULL;
     
         case ImageFormat::CODE_BGR8:
             return ImageFormat::BGR8();
     
    +    case ImageFormat::CODE_BGRA8:
    +        return ImageFormat::BGRA8();
    +
         case ImageFormat::CODE_R8:
             return ImageFormat::R8();
     
    +    case ImageFormat::CODE_R8I:
    +        return ImageFormat::R8I();
    +
    +    case ImageFormat::CODE_R8UI:
    +        return ImageFormat::R8UI();
    +
    +    case ImageFormat::CODE_R16:
    +        return ImageFormat::R16();
    +
    +    case ImageFormat::CODE_R16I:
    +        return ImageFormat::R16I();
    +
    +    case ImageFormat::CODE_R16UI:
    +        return ImageFormat::R16UI();
    +
    +    case ImageFormat::CODE_R32I:
    +        return ImageFormat::R32I();
    +
    +    case ImageFormat::CODE_R32UI:
    +        return ImageFormat::R32UI();
    +
         case ImageFormat::CODE_RG8:
             return ImageFormat::RG8();
     
    @@ -305,9 +527,18 @@ const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
         case ImageFormat::CODE_RG8UI:
             return ImageFormat::RG8UI();
     
    +    case ImageFormat::CODE_R16F:
    +        return ImageFormat::R16F();
    +
         case ImageFormat::CODE_RG16F:
             return ImageFormat::RG16F();
     
    +    case ImageFormat::CODE_R32F:
    +        return ImageFormat::R32F();
    +
    +    case ImageFormat::CODE_RG32F:
    +        return ImageFormat::RG32F();
    +
         case ImageFormat::CODE_RGBA8:
             return ImageFormat::RGBA8();
     
    @@ -320,6 +551,15 @@ const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
         case ImageFormat::CODE_RGBA32F:
             return ImageFormat::RGBA32F();
     
    +    case ImageFormat::CODE_RGB32I:
    +        return ImageFormat::RGB32I();
    +
    +    case ImageFormat::CODE_RGBA32I:
    +        return ImageFormat::RGBA32I();
    +
    +    case ImageFormat::CODE_RGB32UI:
    +        return ImageFormat::RGB32UI();
    +
         case ImageFormat::CODE_RGBA32UI:
             return ImageFormat::RGBA32UI();
     
    @@ -439,11 +679,49 @@ const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
         }
     }
     
    -// Helper variables for defining texture formats
     
    -// Is floating point format
    -static const bool FLOAT_FORMAT  = true;
    -static const bool INT_FORMAT    = false;
    +bool ImageFormat::representableAsColor1unorm8() const {
    +    return (numComponents == 1) &&
    +        (cpuBitsPerPixel == 8) &&
    +        ((luminanceBits == 8) ||
    +         (redBits == 8) ||
    +         (alphaBits == 8));
    +}
    +
    +
    +bool ImageFormat::representableAsColor2unorm8() const {
    +    return (numComponents == 2) &&
    +        (cpuBitsPerPixel == 16) &&
    +        ((redBits == 8 && greenBits == 8) ||
    +         (luminanceBits == 8 && alphaBits == 8) ||
    +         (redBits == 8 && alphaBits == 8));
    +}
    +
    +
    +bool ImageFormat::representableAsColor3unorm8() const {
    +    return (numComponents == 3) &&
    +        (cpuBitsPerPixel == 24) &&
    +        (redBits == 8 && greenBits == 8 && blueBits == 8);
    +}
    +
    +
    +bool ImageFormat::representableAsColor4unorm8() const {
    +    return (numComponents == 4) &&
    +        (cpuBitsPerPixel == 32) &&
    +        (redBits == 8 && greenBits == 8 && blueBits == 8 && alphaBits == 8);
    +}
    +
    +Color4 ImageFormat::channelMask() const{
    +    Color4 mask;
    +    mask.r = (redBits > 0 || luminanceBits > 0) ? 1.0f : 0.0f;
    +    mask.b = (blueBits > 0)                     ? 1.0f : 0.0f;
    +    mask.g = (greenBits > 0)                    ? 1.0f : 0.0f;
    +    mask.a = (alphaBits > 0)                    ? 1.0f : 0.0f;
    +    return mask;
    +
    +}
    +
    +// Helper variables for defining texture formats
     
     // Is opaque format (no alpha)
     static const bool OPAQUE_FORMAT = true;
    @@ -453,136 +731,176 @@ static const bool CLEAR_FORMAT  = false;
     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(L8,         1, UNCOMP_FORMAT,   GL_LUMINANCE8,      GL_LUMINANCE,   8, 0, 0, 0, 0, 0, 0, 8, 8,  GL_UNSIGNED_BYTE, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_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(L16,        1, UNCOMP_FORMAT,   GL_LUMINANCE16,     GL_LUMINANCE,  16, 0, 0, 0, 0, 0, 0, 16, 16,GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INTEGER_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(L16F,       1, UNCOMP_FORMAT,   GL_LUMINANCE16F_ARB,GL_LUMINANCE, 16, 0, 0, 0, 0, 0, 0, 16, 16, GL_HALF_FLOAT, OPAQUE_FORMAT, FLOATING_POINT_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(L32F,       1, UNCOMP_FORMAT,   GL_LUMINANCE32F_ARB,GL_LUMINANCE, 32, 0, 0, 0, 0, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOATING_POINT_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(A8,         1, UNCOMP_FORMAT,   GL_ALPHA8,          GL_ALPHA,   0, 8, 0, 0, 0, 0, 0, 8, 8,      GL_UNSIGNED_BYTE, CLEAR_FORMAT, NORMALIZED_FIXED_POINT_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(A16,        1, UNCOMP_FORMAT,   GL_ALPHA16,         GL_ALPHA,   0, 16, 0, 0, 0, 0, 0, 16, 16,   GL_UNSIGNED_SHORT, CLEAR_FORMAT, NORMALIZED_FIXED_POINT_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(A16F,       1, UNCOMP_FORMAT,   GL_ALPHA16F_ARB,    GL_ALPHA,   0, 16, 0, 0, 0, 0, 0, 16, 16,   GL_HALF_FLOAT, CLEAR_FORMAT, FLOATING_POINT_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(A32F,       1, UNCOMP_FORMAT,   GL_ALPHA32F_ARB,    GL_ALPHA,   0, 32, 0, 0, 0, 0, 0, 32, 32,   GL_FLOAT, CLEAR_FORMAT, FLOATING_POINT_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(LA4,        2, UNCOMP_FORMAT,   GL_LUMINANCE4_ALPHA4,       GL_LUMINANCE_ALPHA, 4, 4, 0, 0, 0, 0, 0, 8, 8,              GL_UNSIGNED_BYTE, CLEAR_FORMAT, NORMALIZED_FIXED_POINT_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(LA8,        2, UNCOMP_FORMAT,   GL_LUMINANCE8_ALPHA8,       GL_LUMINANCE_ALPHA, 8, 8, 0, 0, 0, 0, 0, 16, 16,            GL_UNSIGNED_BYTE, CLEAR_FORMAT, NORMALIZED_FIXED_POINT_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(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, NORMALIZED_FIXED_POINT_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(LA16F,      2, UNCOMP_FORMAT,   GL_LUMINANCE_ALPHA16F_ARB,  GL_LUMINANCE_ALPHA, 16, 16, 0, 0, 0, 0, 0, 16*2, 16*2,      GL_HALF_FLOAT, CLEAR_FORMAT, FLOATING_POINT_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(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, FLOATING_POINT_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(BGR8,       3, UNCOMP_FORMAT,   GL_RGB8,            GL_BGR,     0,  0,  8,  8,  8,  0,  0, 32, 24,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_BGR8, ImageFormat::COLOR_SPACE_RGB);
     
    -DEFINE_TEXTUREFORMAT_METHOD(R8,         1, UNCOMP_FORMAT,   GL_R8,              GL_RED,    0,  0,  8,  0,  0,  0,  0, 8, 8,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_R8, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(BGRA8,      4, UNCOMP_FORMAT,   GL_RGBA8,           GL_BGRA,    0,  8,  8,  8,  8,  0,  0, 32, 32,      GL_UNSIGNED_BYTE, CLEAR_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_BGRA8, 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(R8,         1, UNCOMP_FORMAT,   GL_R8,              GL_RED,    0,  0,  8,  0,  0,  0,  0, 8, 8,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_R8, ImageFormat::COLOR_SPACE_RGB);
    +
    +DEFINE_TEXTUREFORMAT_METHOD(R8I,        1, UNCOMP_FORMAT,   GL_R8I,             GL_RED_INTEGER,    0,  0,  8,  0,  0,  0,  0, 8, 8,      GL_BYTE, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_R8I, ImageFormat::COLOR_SPACE_RGB);
    +
    +DEFINE_TEXTUREFORMAT_METHOD(R8UI,       1, UNCOMP_FORMAT,   GL_R8UI,            GL_RED_INTEGER,    0,  0,  8,  0,  0,  0,  0, 8, 8,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_R8UI, ImageFormat::COLOR_SPACE_RGB);
    +
    +DEFINE_TEXTUREFORMAT_METHOD(R16,        1, UNCOMP_FORMAT,   GL_R16,             GL_RED,    0,  0,  16,  0,  0,  0,  0, 16, 16,      GL_UNSIGNED_SHORT, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_R16, ImageFormat::COLOR_SPACE_RGB);
    +
    +DEFINE_TEXTUREFORMAT_METHOD(R16I,       1, UNCOMP_FORMAT,   GL_R16I,            GL_RED_INTEGER,    0,  0,  16,  0,  0,  0,  0, 16, 16,      GL_SHORT, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_R16I, ImageFormat::COLOR_SPACE_RGB);
    +
    +DEFINE_TEXTUREFORMAT_METHOD(R16UI,      1, UNCOMP_FORMAT,   GL_R16UI,           GL_RED_INTEGER,    0,  0,  16,  0,  0,  0,  0, 16, 16,      GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_R16UI, ImageFormat::COLOR_SPACE_RGB);
    +
    +DEFINE_TEXTUREFORMAT_METHOD(R32I,       1, UNCOMP_FORMAT,   GL_R32I,            GL_RED_INTEGER,    0,  0,  32,  0,  0,  0,  0, 32, 32,      GL_INT, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_R32I, ImageFormat::COLOR_SPACE_RGB);
    +
    +DEFINE_TEXTUREFORMAT_METHOD(R32UI,      1, UNCOMP_FORMAT,   GL_R32UI,           GL_RED_INTEGER,    0,  0,  32,  0,  0,  0,  0, 32, 32,      GL_UNSIGNED_INT, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_R32UI, 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, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_RG8, ImageFormat::COLOR_SPACE_RGB);
     
     // The base format for integer formats must be *_INTEGER even though the spec doesn't state this
    -DEFINE_TEXTUREFORMAT_METHOD(RG8I,       2, UNCOMP_FORMAT,   GL_RG8I,            GL_RG_INTEGER,     0,  0,  8,  8,  0,  0,  0, 16, 16,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8I, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RG8I,       2, UNCOMP_FORMAT,   GL_RG8I,            GL_RG_INTEGER,     0,  0,  8,  8,  0,  0,  0, 16, 16,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RG8I, ImageFormat::COLOR_SPACE_RGB);
     
    -DEFINE_TEXTUREFORMAT_METHOD(RG8UI,      2, UNCOMP_FORMAT,   GL_RG8UI,           GL_RG_INTEGER,     0,  0,  8,  8,  0,  0,  0, 16, 16,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8UI, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RG8UI,      2, UNCOMP_FORMAT,   GL_RG8UI,           GL_RG_INTEGER,     0,  0,  8,  8,  0,  0,  0, 16, 16,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RG8UI, ImageFormat::COLOR_SPACE_RGB);
     
    -DEFINE_TEXTUREFORMAT_METHOD(RG16F,      2, UNCOMP_FORMAT,   GL_RG16F,           GL_RG,     0,  0,  16, 16,  0,  0,  0, 32, 32,      GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RG16F, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RG16,       2, UNCOMP_FORMAT,   GL_RG16,            GL_RG,    0,  0,  16,  16,  0,  0,  0, 16*2, 16*2,      GL_UNSIGNED_SHORT, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_RG16, 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(RG16I,      2, UNCOMP_FORMAT,   GL_RG16I,           GL_RG_INTEGER,    0,  0,  16,  16,  0,  0,  0, 16*2, 16*2,      GL_SHORT, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RG16I, 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(RG16UI,     2, UNCOMP_FORMAT,   GL_RG16UI,          GL_RG_INTEGER,    0,  0,  16,  16,  0,  0,  0, 16*2, 16*2,      GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RG16UI, 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(R16F,       1, UNCOMP_FORMAT,   GL_R16F,            GL_RED,      0,  0,  16, 0,  0,  0,  0, 16, 16,       GL_HALF_FLOAT, OPAQUE_FORMAT, FLOATING_POINT_FORMAT, ImageFormat::CODE_R16F, 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(RG16F,      2, UNCOMP_FORMAT,   GL_RG16F,           GL_RG,     0,  0,  16, 16,  0,  0,  0, 32, 32,      GL_HALF_FLOAT, OPAQUE_FORMAT, FLOATING_POINT_FORMAT, ImageFormat::CODE_RG16F, 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(RG32I,      2, UNCOMP_FORMAT,   GL_RG32I,           GL_RG_INTEGER,    0,  0,  32,  32,  0,  0,  0, 32*2, 32*2,      GL_INT, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RG32I, 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(RG32UI,     2, UNCOMP_FORMAT,   GL_RG32UI,          GL_RG_INTEGER,    0,  0,  32,  32,  0,  0,  0, 32*2, 32*2,      GL_UNSIGNED_INT, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RG32UI, 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(R32F,       1, UNCOMP_FORMAT,   GL_R32F,            GL_RED,      0,  0,  32, 0,  0,  0,  0, 32, 32,       GL_FLOAT, OPAQUE_FORMAT, FLOATING_POINT_FORMAT, ImageFormat::CODE_R32F, 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(RG32F,      2, UNCOMP_FORMAT,   GL_RG32F,           GL_RG,     0,  0,  32, 32,  0,  0,  0, 64, 64,      GL_FLOAT, OPAQUE_FORMAT, FLOATING_POINT_FORMAT, ImageFormat::CODE_RG32F, 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(RGB5,       3, UNCOMP_FORMAT,   GL_RGB5,            GL_RGBA,    0,  0,  5,  5,  5,  0,  0, 16, 16,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_RGB5, 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(RGB5A1,     4, UNCOMP_FORMAT,   GL_RGB5_A1,         GL_RGBA,    0,  1,  5,  5,  5,  0,  0, 16, 16,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_RGB5A1, 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(RGB8,       3, UNCOMP_FORMAT,   GL_RGB8,            GL_RGB,     0,  0,  8,  8,  8,  0,  0, 32, 24,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_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, NORMALIZED_FIXED_POINT_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, NORMALIZED_FIXED_POINT_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, NORMALIZED_FIXED_POINT_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_HALF_FLOAT, OPAQUE_FORMAT, FLOATING_POINT_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, FLOATING_POINT_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, NORMALIZED_FIXED_POINT_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, NORMALIZED_FIXED_POINT_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_HALF_FLOAT, CLEAR_FORMAT, FLOATING_POINT_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, FLOATING_POINT_FORMAT, ImageFormat::CODE_RGBA32F, ImageFormat::COLOR_SPACE_RGB);
    +
    +DEFINE_TEXTUREFORMAT_METHOD(RGBA16I,    4, UNCOMP_FORMAT,   GL_RGBA16I,         GL_RGBA_INTEGER,    0, 16, 16, 16, 16, 0, 0, 16*4, 16*4,    GL_SHORT, CLEAR_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RGBA16I, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGBA16UI,   4, UNCOMP_FORMAT,   GL_RGBA16UI,        GL_RGBA_INTEGER,    0, 16, 16, 16, 16, 0, 0, 16*4, 16*4,    GL_UNSIGNED_SHORT, CLEAR_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RGBA16UI, ImageFormat::COLOR_SPACE_RGB);
     
    -DEFINE_TEXTUREFORMAT_METHOD(RGBA32F,    4, UNCOMP_FORMAT,   GL_RGBA32F_ARB,                     GL_RGBA,    0, 32, 32, 32, 32, 0, 0, 32*4, 32*4,    GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGBA32F, ImageFormat::COLOR_SPACE_RGB);
     
     // The base format for integer formats must be *_INTEGER even though the spec doesn't state this
    -DEFINE_TEXTUREFORMAT_METHOD(RGBA32UI,   4, UNCOMP_FORMAT,   GL_RGBA32UI,                        GL_RGBA_INTEGER,    0, 32, 32, 32, 32, 0, 0, 32*4, 32*4,    GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA32UI, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGB32I,     3, UNCOMP_FORMAT,   GL_RGB32I,           GL_RGBA_INTEGER,    0, 32, 32, 32,  0, 0, 0, 32*3, 32*3,    GL_INT, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RGB32I, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGB32UI,    3, UNCOMP_FORMAT,   GL_RGB32UI,          GL_RGBA_INTEGER,    0, 32, 32, 32,  0, 0, 0, 32*3, 32*3,    GL_UNSIGNED_INT, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RGB32UI, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGBA32I,    4, UNCOMP_FORMAT,   GL_RGBA32I,          GL_RGBA_INTEGER,    0, 32, 32, 32, 32, 0, 0, 32*4, 32*4,    GL_INT, CLEAR_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RGBA32I, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGBA32UI,   4, UNCOMP_FORMAT,   GL_RGBA32UI,         GL_RGBA_INTEGER,    0, 32, 32, 32, 32, 0, 0, 32*4, 32*4,    GL_UNSIGNED_INT, CLEAR_FORMAT, INTEGER_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(R11G11B10F, 3, UNCOMP_FORMAT,   GL_R11F_G11F_B10F_EXT,GL_RGB,     0,  0, 11, 11, 10, 0, 0,   32,   32,    GL_FLOAT, OPAQUE_FORMAT, FLOATING_POINT_FORMAT, ImageFormat::CODE_R11G11B10F, ImageFormat::COLOR_SPACE_RGB);
    +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, FLOATING_POINT_FORMAT, ImageFormat::CODE_RGB9E5F, ImageFormat::COLOR_SPACE_RGB);
     
     // The base format for integer formats must be *_INTEGER even though the spec doesn't state this
    -DEFINE_TEXTUREFORMAT_METHOD(RGB8I,      3, UNCOMP_FORMAT,   GL_RGB8I_EXT,                       GL_RGB_INTEGER,     0,  0,  8,  8,  8,  0,  0, 32, 24,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8I, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGB8I,      3, UNCOMP_FORMAT,   GL_RGB8I_EXT,        GL_RGB_INTEGER,     0,  0,  8,  8,  8,  0,  0, 32, 24,      GL_BYTE, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RGB8I, ImageFormat::COLOR_SPACE_RGB);
     
    -DEFINE_TEXTUREFORMAT_METHOD(RGB8UI,     3, UNCOMP_FORMAT,   GL_RGB8UI_EXT,                      GL_RGB_INTEGER,     0,  0,  8,  8,  8,  0,  0, 32, 24,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8UI, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGB8UI,     3, UNCOMP_FORMAT,   GL_RGB8UI_EXT,       GL_RGB_INTEGER,     0,  0,  8,  8,  8,  0,  0, 32, 24,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RGB8UI, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGBA8I,     4, UNCOMP_FORMAT,   GL_RGBA8I_EXT,       GL_RGBA_INTEGER,    0,  8,  8,  8,  8,  0,  0, 32, 32,      GL_BYTE, CLEAR_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RGBA8I, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGBA8UI,    4, UNCOMP_FORMAT,   GL_RGBA8UI_EXT,      GL_RGBA_INTEGER,    0,  8,  8,  8,  8,  0,  0, 32, 32,      GL_UNSIGNED_BYTE, CLEAR_FORMAT, INTEGER_FORMAT, ImageFormat::CODE_RGBA8UI, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGB8_SNORM, 3, UNCOMP_FORMAT,   GL_RGB8_SNORM,       GL_RGB,       0,  0,  8,  8,  8,  0,  0, 32, 32,      GL_BYTE, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_RGB8_SNORM, ImageFormat::COLOR_SPACE_RGB);
     
    -DEFINE_TEXTUREFORMAT_METHOD(RGBA8UI,    4, UNCOMP_FORMAT,   GL_RGBA8UI_EXT,                     GL_RGBA_INTEGER,    0,  0,  8,  8,  8,  8,  0, 32, 32,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA8UI, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGBA8_SNORM,4, UNCOMP_FORMAT,   GL_RGBA8_SNORM,      GL_RGBA,      0,  8,  8,  8,  8,  0,  0, 32, 32,      GL_BYTE, CLEAR_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_RGBA8_SNORM, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGB16_SNORM,3, UNCOMP_FORMAT,   GL_RGB16_SNORM,      GL_RGB,       0,  0, 16, 16, 16,  0,  0, 64, 64,      GL_SHORT, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_RGB16_SNORM, ImageFormat::COLOR_SPACE_RGB);
    +DEFINE_TEXTUREFORMAT_METHOD(RGBA16_SNORM,4,UNCOMP_FORMAT,   GL_RGBA16_SNORM,     GL_RGB,      0, 16, 16, 16, 16,  0,  0, 64, 64,      GL_SHORT, CLEAR_FORMAT, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_RGBA16_SNORM, 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(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, OTHER, 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_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, OTHER, 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_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, OTHER, 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(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, OTHER, 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(SRGB8,      3, UNCOMP_FORMAT,   GL_SRGB8,                           GL_RGB,                0,  0,  8,  8,  8,  0,  0, 32, 24,      GL_UNSIGNED_BYTE, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_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(SRGBA8,     4, UNCOMP_FORMAT,   GL_SRGB8_ALPHA8,                    GL_RGBA,            0,  8,  8,  8,  8,  0,  0, 32, 24,      GL_UNSIGNED_BYTE, CLEAR_FORMAT, NORMALIZED_FIXED_POINT_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(SL8,        1, UNCOMP_FORMAT,   GL_SLUMINANCE8,                     GL_LUMINANCE,        8,  0,  0,  0,  0,  0,  0, 8, 8,        GL_UNSIGNED_BYTE, OPAQUE_FORMAT, NORMALIZED_FIXED_POINT_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(SLA8,       2, UNCOMP_FORMAT,   GL_SLUMINANCE8_ALPHA8,              GL_LUMINANCE_ALPHA,    8,  8,  0,  0,  0,  0,  0, 16, 16,      GL_UNSIGNED_BYTE, CLEAR_FORMAT, NORMALIZED_FIXED_POINT_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(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, OTHER, 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_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, OTHER, 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_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, OTHER, 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(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, OTHER, 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(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, NORMALIZED_FIXED_POINT_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(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, NORMALIZED_FIXED_POINT_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(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, NORMALIZED_FIXED_POINT_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);
    +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, FLOATING_POINT_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(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, NORMALIZED_FIXED_POINT_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(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, NORMALIZED_FIXED_POINT_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(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, NORMALIZED_FIXED_POINT_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(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, NORMALIZED_FIXED_POINT_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(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_24_8, CLEAR_FORMAT, NORMALIZED_FIXED_POINT_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);
    +
    +// TODO: Find out if these are acutally NFP, not integer, formats.
    +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, NORMALIZED_FIXED_POINT_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, NORMALIZED_FIXED_POINT_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, NORMALIZED_FIXED_POINT_FORMAT, ImageFormat::CODE_YUV444, ImageFormat::COLOR_SPACE_YUV);
     
     }
    diff --git a/deps/g3dlite/source/ImageFormat_convert.cpp b/deps/g3dlite/source/ImageFormat_convert.cpp
    index ecefe6319..69b9c71ae 100644
    --- a/deps/g3dlite/source/ImageFormat_convert.cpp
    +++ b/deps/g3dlite/source/ImageFormat_convert.cpp
    @@ -1,7 +1,7 @@
     #include "G3D/ImageFormat.h"
    -#include "G3D/Color1uint8.h"
    -#include "G3D/Color3uint8.h"
    -#include "G3D/Color4uint8.h"
    +#include "G3D/Color1unorm8.h"
    +#include "G3D/Color3unorm8.h"
    +#include "G3D/Color4unorm8.h"
     #include "G3D/Color1.h"
     #include "G3D/Color3.h"
     #include "G3D/Color4.h"
    @@ -212,8 +212,8 @@ bool ImageFormat::convert(const Array& srcBytes, int srcWidth, int
     static void l8_to_rgb8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         (void)bayerAlg;
         (void)dstRowPadBits;
    -    uint8* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; ++x) {
                 int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
    @@ -230,7 +230,7 @@ static void l8_to_rgb8(const Array& srcBytes, int srcWidth, int src
     static void l32f_to_rgb8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         int srcIndex = 0;
         int dstByteOffset = 0;
    -    uint8* dst = static_cast(dstBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
         const float* src = static_cast(srcBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
    @@ -239,19 +239,18 @@ static void l32f_to_rgb8(const Array& srcBytes, int srcWidth, int s
             }
             
             for (int x = 0; x < srcWidth; ++x, ++srcIndex, dstByteOffset += 3) {
    -            Color3uint8&  d = *reinterpret_cast(dst + dstByteOffset);
    -            float s = src[srcIndex];
    -
    -            uint8 c = iMin(255, iFloor(s * 256));
    -            d = Color3uint8(c, c, c);
    +            Color3unorm8&  d = *reinterpret_cast(dst + dstByteOffset);
    +            const float s = src[srcIndex];
    +            const unorm8 c(s);
    +            d = Color3unorm8(c, c, c);
             }
         } 
     }
     
     // RGB8 ->
     static void rgb8_to_rgba8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
    -    uint8* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; ++x) {
                 int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
    @@ -261,14 +260,14 @@ static void rgb8_to_rgba8(const Array& srcBytes, int srcWidth, int
                 dst[i4 + 0] = src[i3 + 0]; 
                 dst[i4 + 1] = src[i3 + 1]; 
                 dst[i4 + 2] = src[i3 + 2]; 
    -            dst[i4 + 3] = 255; 
    +            dst[i4 + 3] = unorm8::one(); 
             }
         }
     }
     
     static void rgb8_to_bgr8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
    -    uint8* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; ++x) {
                 int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
    @@ -287,14 +286,14 @@ static void rgb8_to_rgba32f(const Array& srcBytes, int srcWidth, in
         int srcByteOffset = 0;
         int srcRowPadBytes = srcRowPadBits / 8;
         Color4* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
             if (invertY) {
                 dstIndex = srcWidth * (srcHeight - 1 - y);
             }
             for (int x = 0; x < srcWidth; ++x, ++dstIndex, srcByteOffset += 3) {
    -            const Color3uint8& s = *reinterpret_cast(src + srcByteOffset);
    +            const Color3unorm8& s = *reinterpret_cast(src + srcByteOffset);
                 dst[dstIndex] = Color4(Color3(s), 1.0f);
             }
             srcByteOffset += srcRowPadBytes;
    @@ -303,8 +302,8 @@ static void rgb8_to_rgba32f(const Array& srcBytes, int srcWidth, in
     
     // BGR8 ->
     static void bgr8_to_rgb8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
    -    uint8* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; ++x) {
                 int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
    @@ -317,8 +316,8 @@ static void bgr8_to_rgb8(const Array& srcBytes, int srcWidth, int s
     }
     
     static void bgr8_to_rgba8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
    -    uint8* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; ++x) {
                 int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
    @@ -328,7 +327,7 @@ static void bgr8_to_rgba8(const Array& srcBytes, int srcWidth, int
                 dst[i4 + 0] = src[i3 + 2]; 
                 dst[i4 + 1] = src[i3 + 1]; 
                 dst[i4 + 2] = src[i3 + 0]; 
    -            dst[i4 + 3] = 255; 
    +            dst[i4 + 3] = unorm8::one(); 
             }
         }
     }
    @@ -340,7 +339,7 @@ static void bgr8_to_rgba32f(const Array& srcBytes, int srcWidth, in
         int srcByteOffset = 0;
         int srcRowPadBytes = srcRowPadBits / 8;
         Color4* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
             if (invertY) {
    @@ -348,7 +347,7 @@ static void bgr8_to_rgba32f(const Array& srcBytes, int srcWidth, in
             }
     
             for (int x = 0; x < srcWidth; ++x, ++dstIndex, srcByteOffset += 3) {
    -            const Color3uint8& s = *reinterpret_cast(src + srcByteOffset);
    +            const Color3unorm8& s = *reinterpret_cast(src + srcByteOffset);
                 dst[dstIndex] = Color4(Color3(s).bgr(), 1.0f);
             }
             srcByteOffset += srcRowPadBytes;
    @@ -357,8 +356,8 @@ static void bgr8_to_rgba32f(const Array& srcBytes, int srcWidth, in
     
     // RGBA8 ->
     static void rgba8_to_rgb8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
    -    uint8* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; ++x) {
                 int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
    @@ -373,8 +372,8 @@ static void rgba8_to_rgb8(const Array& srcBytes, int srcWidth, int
     }
     
     static void rgba8_to_bgr8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
    -    uint8* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; ++x) {
                 int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
    @@ -395,7 +394,7 @@ static void rgba8_to_rgba32f(const Array& srcBytes, int srcWidth, i
         int srcByteOffset = 0;
         int srcRowPadBytes = srcRowPadBits / 8;
         Color4* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
             if (invertY) {
    @@ -403,7 +402,7 @@ static void rgba8_to_rgba32f(const Array& srcBytes, int srcWidth, i
             }
     
             for (int x = 0; x < srcWidth; ++x, ++dstIndex, srcByteOffset += 4) {
    -            const Color4uint8& s = *reinterpret_cast(src + srcByteOffset);
    +            const Color4unorm8& s = *reinterpret_cast(src + srcByteOffset);
                 dst[dstIndex] = Color4(s);
             }
             srcByteOffset += srcRowPadBytes;
    @@ -418,7 +417,7 @@ static void rgb32f_to_rgba32f(const Array& srcBytes, int srcWidth,
         int srcByteOffset = 0;
         int srcRowPadBytes = srcRowPadBits / 8;
         Color4* dst = static_cast(dstBytes[0]);
    -    const uint8* src = static_cast(srcBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
             if (invertY) {
    @@ -440,7 +439,7 @@ static void rgba32f_to_rgb8(const Array& srcBytes, int srcWidth, in
         int srcIndex = 0;
         int dstByteOffset = 0;
         int dstRowPadBytes = dstRowPadBits / 8;
    -    uint8* dst = static_cast(dstBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
         const Color4* src = static_cast(srcBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
    @@ -449,10 +448,10 @@ static void rgba32f_to_rgb8(const Array& srcBytes, int srcWidth, in
             }
             
             for (int x = 0; x < srcWidth; ++x, ++srcIndex, dstByteOffset += 3) {
    -            Color3uint8&  d = *reinterpret_cast(dst + dstByteOffset);
    +            Color3unorm8&  d = *reinterpret_cast(dst + dstByteOffset);
                 const Color4& s = src[srcIndex];
     
    -            d = Color3uint8(s.rgb());
    +            d = Color3unorm8(s.rgb());
             }
             dstByteOffset += dstRowPadBytes;
         } 
    @@ -464,7 +463,7 @@ static void rgba32f_to_rgba8(const Array& srcBytes, int srcWidth, i
         int srcIndex = 0;
         int dstByteOffset = 0;
         int dstRowPadBytes = dstRowPadBits / 8;
    -    uint8* dst = static_cast(dstBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
         const Color4* src = static_cast(srcBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
    @@ -472,10 +471,10 @@ static void rgba32f_to_rgba8(const Array& srcBytes, int srcWidth, i
                 srcIndex = srcWidth * (srcHeight - 1 - y);
             }
             for (int x = 0; x < srcWidth; ++x, ++srcIndex, dstByteOffset += 4) {
    -            Color4uint8&  d = *reinterpret_cast(dst + dstByteOffset);
    +            Color4unorm8&  d = *reinterpret_cast(dst + dstByteOffset);
                 const Color4& s = src[srcIndex];
     
    -            d = Color4uint8(s);
    +            d = Color4unorm8(s);
             }
             dstByteOffset += dstRowPadBytes;
         } 
    @@ -487,7 +486,7 @@ static void rgba32f_to_bgr8(const Array& srcBytes, int srcWidth, in
         int srcIndex = 0;
         int dstByteOffset = 0;
         int dstRowPadBytes = dstRowPadBits / 8;
    -    uint8* dst = static_cast(dstBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
         const Color4* src = static_cast(srcBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
    @@ -496,10 +495,10 @@ static void rgba32f_to_bgr8(const Array& srcBytes, int srcWidth, in
             }
             
             for (int x = 0; x < srcWidth; ++x, ++srcIndex, dstByteOffset += 3) {
    -            Color3uint8&  d = *reinterpret_cast(dst + dstByteOffset);
    +            Color3unorm8&  d = *reinterpret_cast(dst + dstByteOffset);
                 const Color4& s = src[srcIndex];
     
    -            d = Color3uint8(s.rgb()).bgr();
    +            d = Color3unorm8(s.rgb()).bgr();
             }
             dstByteOffset += dstRowPadBytes;
         } 
    @@ -511,7 +510,7 @@ static void rgba32f_to_rgb32f(const Array& srcBytes, int srcWidth,
         int srcIndex = 0;
         int dstByteOffset = 0;
         int dstRowPadBytes = dstRowPadBits / 8;
    -    uint8* dst = static_cast(dstBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
         const Color4* src = static_cast(srcBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
    @@ -520,7 +519,7 @@ static void rgba32f_to_rgb32f(const Array& srcBytes, int srcWidth,
             }
             for (int x = 0; x < srcWidth; ++x, ++srcIndex, dstByteOffset += 3 * sizeof(float)) {
                 Color3& d = *reinterpret_cast(dst + dstByteOffset);
    -            const Color4& s = src[srcIndex];	    
    +            const Color4& s = src[srcIndex];        
                 d = s.rgb();
             }
             dstByteOffset += dstRowPadBytes;
    @@ -545,19 +544,19 @@ static uint32 blendPixels(uint32 pixel1, uint32 pixel2) {
         return ((rb & rbMask) | (ag & agMask));
     }
     
    -#define PIXEL_RGB8_TO_YUV_Y(r, g, b) static_cast(iClamp(((66 * r + 129 * g + 25 * b + 128) >> 8) + 16, 0, 255))
    -#define PIXEL_RGB8_TO_YUV_U(r, g, b) static_cast(iClamp(((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128, 0, 255))
    -#define PIXEL_RGB8_TO_YUV_V(r, g, b) static_cast(iClamp(((112 * r - 94 * g - 18 * b + 128) >> 8) + 128, 0, 255))
    +#define PIXEL_RGB8_TO_YUV_Y(r, g, b) unorm8::fromBits(iClamp(((66 * r.bits() + 129 * g.bits() + 25 * b.bits() + 128) >> 8) + 16, 0, 255))
    +#define PIXEL_RGB8_TO_YUV_U(r, g, b) unorm8::fromBits(iClamp(((-38 * r.bits() - 74 * g.bits() + 112 * b.bits() + 128) >> 8) + 128, 0, 255))
    +#define PIXEL_RGB8_TO_YUV_V(r, g, b) unorm8::fromBits(iClamp(((112 * r.bits() - 94 * g.bits() - 18 * b.bits() + 128) >> 8) + 128, 0, 255))
     
     static void rgb8_to_yuv420p(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
         debugAssertM((srcWidth % 2 == 0) && (srcHeight % 2 == 0), "Source width and height must be a multiple of two");
     
    -    const Color3uint8* src = static_cast(srcBytes[0]);
    +    const Color3unorm8* src = static_cast(srcBytes[0]);
     
    -    uint8* dstY = static_cast(dstBytes[0]);
    -    uint8* dstU = static_cast(dstBytes[1]);
    -    uint8* dstV = static_cast(dstBytes[2]);
    +    unorm8* dstY = static_cast(dstBytes[0]);
    +    unorm8* dstU = static_cast(dstBytes[1]);
    +    unorm8* dstV = static_cast(dstBytes[2]);
     
         for (int y = 0; y < srcHeight; y += 2) {
             for (int x = 0; x < srcWidth; x += 2) {
    @@ -578,7 +577,7 @@ static void rgb8_to_yuv420p(const Array& srcBytes, int srcWidth, in
                 dstY[yIndex + 1] = PIXEL_RGB8_TO_YUV_Y(src[srcPixelOffset3].r, src[srcPixelOffset3].g, src[srcPixelOffset3].b);
     
                 uint32 blendedPixel = blendPixels(src[srcPixelOffset0].asUInt32(), src[srcPixelOffset2].asUInt32());
    -            Color3uint8 uvSrcColor = Color3uint8::fromARGB(blendedPixel);
    +            Color3unorm8 uvSrcColor = Color3unorm8::fromARGB(blendedPixel);
     
                 int uvIndex = y / 2 * srcWidth / 2 + x / 2;
                 dstU[uvIndex] =    PIXEL_RGB8_TO_YUV_U(uvSrcColor.r, uvSrcColor.g, uvSrcColor.b);
    @@ -591,9 +590,9 @@ static void rgb8_to_yuv422(const Array& srcBytes, int srcWidth, int
         debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
         debugAssertM((srcWidth % 2 == 0), "Source width must be a multiple of two");
     
    -    const Color3uint8* src = static_cast(srcBytes[0]);
    +    const Color3unorm8* src = static_cast(srcBytes[0]);
     
    -    uint8* dst = static_cast(dstBytes[0]);
    +    unorm8* dst = static_cast(dstBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; x += 2) {
    @@ -603,7 +602,7 @@ static void rgb8_to_yuv422(const Array& srcBytes, int srcWidth, int
                 int dstIndex = srcIndex * 2;
     
                 uint32 blendedPixel = blendPixels(src[srcIndex].asUInt32(), src[srcIndex + 1].asUInt32());
    -            Color3uint8 uvSrcColor = Color3uint8::fromARGB(blendedPixel);
    +            Color3unorm8 uvSrcColor = Color3unorm8::fromARGB(blendedPixel);
     
                 dst[dstIndex]     = PIXEL_RGB8_TO_YUV_Y(src[srcIndex].r, src[srcIndex].g, src[srcIndex].b);
     
    @@ -620,18 +619,18 @@ static void rgb8_to_yuv422(const Array& srcBytes, int srcWidth, int
     static void rgb8_to_yuv444(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
     
    -    const Color3uint8* src = static_cast(srcBytes[0]);
    +    const Color3unorm8* src = static_cast(srcBytes[0]);
     
    -    Color3uint8* dst = static_cast(dstBytes[0]);
    +    Color3unorm8* dst = static_cast(dstBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; ++x) {
     
                 // convert 1-pixels at a time
                 int index = y * srcWidth + x;
    -            uint8 y = PIXEL_RGB8_TO_YUV_Y(src[index].r, src[index].g, src[index].b);
    -            uint8 u = PIXEL_RGB8_TO_YUV_U(src[index].r, src[index].g, src[index].b);
    -            uint8 v = PIXEL_RGB8_TO_YUV_V(src[index].r, src[index].g, src[index].b);
    +            unorm8 y = PIXEL_RGB8_TO_YUV_Y(src[index].r, src[index].g, src[index].b);
    +            unorm8 u = PIXEL_RGB8_TO_YUV_U(src[index].r, src[index].g, src[index].b);
    +            unorm8 v = PIXEL_RGB8_TO_YUV_V(src[index].r, src[index].g, src[index].b);
     
                 dst[index].r = y;
                 dst[index].g = u;
    @@ -641,25 +640,25 @@ static void rgb8_to_yuv444(const Array& srcBytes, int srcWidth, int
     }
     
     
    -#define PIXEL_YUV_TO_RGB8_R(y, u, v) static_cast(iClamp((298 * (y - 16) + 409 * (v - 128) + 128) >> 8, 0, 255))
    -#define PIXEL_YUV_TO_RGB8_G(y, u, v) static_cast(iClamp((298 * (y - 16) - 100 * (u - 128) - 208 * (v - 128) + 128) >> 8, 0, 255))
    -#define PIXEL_YUV_TO_RGB8_B(y, u, v) static_cast(iClamp((298 * (y - 16) + 516 * (u - 128) + 128) >> 8, 0, 255))
    +#define PIXEL_YUV_TO_RGB8_R(y, u, v) unorm8::fromBits(iClamp((298 * (y.bits() - 16) + 409 * (v.bits() - 128) + 128) >> 8, 0, 255))
    +#define PIXEL_YUV_TO_RGB8_G(y, u, v) unorm8::fromBits(iClamp((298 * (y.bits() - 16) - 100 * (u.bits() - 128) - 208 * (v.bits() - 128) + 128) >> 8, 0, 255))
    +#define PIXEL_YUV_TO_RGB8_B(y, u, v) unorm8::fromBits(iClamp((298 * (y.bits() - 16) + 516 * (u.bits() - 128) + 128) >> 8, 0, 255))
     
     static void yuv420p_to_rgb8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
         debugAssertM((srcWidth % 2 == 0) && (srcHeight % 2 == 0), "Source width and height must be a multiple of two");
     
    -    const uint8* srcY = static_cast(srcBytes[0]);
    -    const uint8* srcU = static_cast(srcBytes[1]);
    -    const uint8* srcV = static_cast(srcBytes[2]);
    +    const unorm8* srcY = static_cast(srcBytes[0]);
    +    const unorm8* srcU = static_cast(srcBytes[1]);
    +    const unorm8* srcV = static_cast(srcBytes[2]);
     
    -    Color3uint8* dst = static_cast(dstBytes[0]);
    +    Color3unorm8* dst = static_cast(dstBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; x += 2) {
     
                 // convert to two rgb pixels in a row
    -            Color3uint8* rgb = &dst[y * srcWidth + x];
    +            Color3unorm8* rgb = &dst[y * srcWidth + x];
     
                 int yOffset = y * srcWidth + x;
                 int uvOffset = y / 2 * srcWidth / 2 + x / 2;
    @@ -680,21 +679,21 @@ static void yuv422_to_rgb8(const Array& srcBytes, int srcWidth, int
         debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
         debugAssertM((srcWidth % 2 == 0), "Source width must be a multiple of two");
     
    -    const uint8* src = static_cast(srcBytes[0]);
    +    const unorm8* src = static_cast(srcBytes[0]);
     
    -    Color3uint8* dst = static_cast(dstBytes[0]);
    +    Color3unorm8* dst = static_cast(dstBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; x += 2) {
     
                 // convert to two rgb pixels in a row
    -            Color3uint8* rgb = &dst[y * srcWidth + x];
    +            Color3unorm8* rgb = &dst[y * srcWidth + x];
                 
    -            int srcIndex = (y * srcWidth + x) * 2;
    -            uint8 y  = src[srcIndex];
    -            uint8 u  = src[srcIndex + 1];
    -            uint8 y2 = src[srcIndex + 2];
    -            uint8 v  = src[srcIndex + 3];
    +            const int srcIndex = (y * srcWidth + x) * 2;
    +            const unorm8 y  = src[srcIndex];
    +            const unorm8 u  = src[srcIndex + 1];
    +            const unorm8 y2 = src[srcIndex + 2];
    +            const unorm8 v  = src[srcIndex + 3];
     
                 rgb->r = PIXEL_YUV_TO_RGB8_R(y, u, v);
                 rgb->g = PIXEL_YUV_TO_RGB8_G(y, u, v);
    @@ -711,20 +710,21 @@ static void yuv422_to_rgb8(const Array& srcBytes, int srcWidth, int
     static void yuv444_to_rgb8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
     
    -    const Color3uint8* src = static_cast(srcBytes[0]);
    +    const Color3unorm8* src = static_cast(srcBytes[0]);
     
    -    Color3uint8* dst = static_cast(dstBytes[0]);
    +    Color3unorm8* dst = static_cast(dstBytes[0]);
     
         for (int y = 0; y < srcHeight; ++y) {
             for (int x = 0; x < srcWidth; ++x) {
     
                 // convert to one rgb pixels at a time
    -            int index = y * srcWidth + x;
    -            Color3uint8* rgb = &dst[index];
    -            
    -            rgb->r = PIXEL_YUV_TO_RGB8_R(src[index].r, src[index].g, src[index].b);
    -            rgb->g = PIXEL_YUV_TO_RGB8_G(src[index].r, src[index].g, src[index].b);
    -            rgb->b = PIXEL_YUV_TO_RGB8_B(src[index].r, src[index].g, src[index].b);
    +            const int index = y * srcWidth + x;
    +            const Color3unorm8 s = src[index];
    +
    +            Color3unorm8& rgb = dst[index];
    +            rgb.r = PIXEL_YUV_TO_RGB8_R(s.r, s.g, s.b);
    +            rgb.g = PIXEL_YUV_TO_RGB8_G(s.r, s.g, s.b);
    +            rgb.b = PIXEL_YUV_TO_RGB8_B(s.r, s.g, s.b);
             }
         }
     }
    @@ -799,12 +799,12 @@ static const float R_BGB[5][5] =
     
     
     /** 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]) {
    +static unorm8 applyFilter(const unorm8*    I,
    +             int             x,
    +             int             y,
    +             int             w,
    +             int             h,
    +             const float     filter[5][5]) {
         
         debugAssert(isEven(w));
         debugAssert(isEven(h));
    @@ -813,24 +813,24 @@ static uint8 applyFilter(const uint8*    I,
         float denom = 0.0f;
         
         for (int dy = 0; dy < 5; ++dy) {
    -	int offset = ((y + dy + h - 2) % h) * w;
    +    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;
    -	}
    +    for (int dx = 0; dx < 5; ++dx) {
    +        float f = filter[dy][dx];
    +        sum += f * (float)I[((x + dx + w - 2) % w) + offset];
    +        denom += f;
    +    }
         }
         
    -    return (uint8)iClamp(iRound(sum / denom), 0, 255);
    +    return unorm8(sum / denom);
     }
     
     /** Helper method for Bayer grbg and bggr --> rgb8 */
    -static void swapRedAndBlue(int N, Color3uint8* out) {
    +static void swapRedAndBlue(int N, Color3unorm8* out) {
         for (int i = N - 1; i >= 0; --i) {
    -	uint8 tmp = out[i].r;
    -	out[i].r = out[i].b;
    -	out[i].b = tmp;
    +    unorm8 tmp = out[i].r;
    +    out[i].r = out[i].b;
    +    out[i].b = tmp;
         }
     }
     
    @@ -840,149 +840,149 @@ static void swapRedAndBlue(int N, Color3uint8* out) {
     // rgb8 --> bayer helpers
     // =====================================================================
     static void rgb8_to_bayer_rggb8(const int w, const int h, 
    -				const uint8* src, uint8* dst) {
    -    Color3uint8* srcColor = (Color3uint8*)src;
    -    Color1uint8* dstColor = (Color1uint8*)dst;
    +                const unorm8* src, unorm8* dst) {
    +    Color3unorm8* srcColor = (Color3unorm8*)src;
    +    Color1unorm8* dstColor = (Color1unorm8*)dst;
     
         // Top row pixels
         for (int y = 0; y < h - 1; y += 2) {
    -	int offset = y * w;
    +        int offset = y * w;
     
    -	// Top left pixels
    -	for(int x = 0; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].r);
    -	}
    +        // Top left pixels
    +        for(int x = 0; x < w - 1; x += 2) {
    +            dstColor[x + offset] = Color1unorm8(srcColor[x + offset].r);
    +        }
     
    -	// Top right pixels
    -	for(int x = 1; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].g);
    -	}
    -    }
    +        // Top right pixels
    +        for(int x = 1; x < w - 1; x += 2) {
    +            dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
    +        }
    +        }
     
    -    // Bottom row pixels
    -    for (int y = 1; y < h - 1; y += 2) {
    -	int offset = y * w;
    +        // Bottom row pixels
    +        for (int y = 1; y < h - 1; y += 2) {
    +        int offset = y * w;
     
    -	// Bottom left pixels
    -	for (int x = 0; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].g);
    -	}
    +        // Bottom left pixels
    +        for (int x = 0; x < w - 1; x += 2) {
    +            dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
    +        }
     
    -	// Bottom right pixels
    -	for (int x = 1; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].b);
    -	}
    +        // Bottom right pixels
    +        for (int x = 1; x < w - 1; x += 2) {
    +            dstColor[x + offset] = Color1unorm8(srcColor[x + offset].b);
    +        }
         }
     }
     
     
     static void rgb8_to_bayer_grbg8(const int w, const int h, 
    -				const uint8* src, uint8* dst) {
    -    Color3uint8* srcColor = (Color3uint8*)src;
    -    Color1uint8* dstColor = (Color1uint8*)dst;
    +                const unorm8* src, unorm8* dst) {
    +    Color3unorm8* srcColor = (Color3unorm8*)src;
    +    Color1unorm8* dstColor = (Color1unorm8*)dst;
     
         // Top row pixels
         for (int y = 0; y < h - 1; y += 2) {
    -	int offset = y * w;
    +    int offset = y * w;
     
    -	// Top left pixels
    -	for (int x = 0; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].g);
    -	}
    +    // Top left pixels
    +    for (int x = 0; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
    +    }
     
    -	// Top right pixels
    -	for (int x = 1; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].r);
    -	}
    +    // Top right pixels
    +    for (int x = 1; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].r);
    +    }
         }
     
         // Bottom row pixels
         for (int y = 1; y < h - 1; y += 2) {
    -	int offset = y * w;
    +    int offset = y * w;
     
    -	// Bottom left pixels
    -	for (int x = 0; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].b);
    -	}
    +    // Bottom left pixels
    +    for (int x = 0; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].b);
    +    }
     
    -	// Bottom right pixels
    -	for (int x = 1; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].g);
    -	}
    +    // Bottom right pixels
    +    for (int x = 1; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
    +    }
         }
     }
     
     
     static void rgb8_to_bayer_bggr8(const int w, const int h, 
    -				const uint8* src, uint8* dst) {
    -    Color3uint8* srcColor = (Color3uint8*)src;
    -    Color1uint8* dstColor = (Color1uint8*)dst;
    +                const unorm8* src, unorm8* dst) {
    +    Color3unorm8* srcColor = (Color3unorm8*)src;
    +    Color1unorm8* dstColor = (Color1unorm8*)dst;
     
         // Top row pixels
         for (int y = 0; y < h - 1; y += 2) {
    -	int offset = y * w;
    +    int offset = y * w;
     
    -	// Top left pixels
    -	for (int x = 0; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].b);
    -	}
    +    // Top left pixels
    +    for (int x = 0; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].b);
    +    }
     
    -	// Top right pixels
    -	for (int x = 1; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].g);
    -	}
    +    // Top right pixels
    +    for (int x = 1; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
    +    }
         }
     
         // Bottom row pixels
         for (int y = 1; y < h - 1; y += 2) {
    -	int offset = y * w;
    +    int offset = y * w;
     
    -	// Bottom left pixels
    -	for(int x = 0; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].g);
    -	}
    +    // Bottom left pixels
    +    for(int x = 0; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
    +    }
     
    -	// Bottom right pixels
    -	for(int x = 1; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].r);
    -	}
    +    // Bottom right pixels
    +    for(int x = 1; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].r);
    +    }
         }
     }
     
     
     static void rgb8_to_bayer_gbrg8(const int w, const int h, 
    -				const uint8* src, uint8* dst) {
    -    Color3uint8* srcColor = (Color3uint8*)src;
    -    Color1uint8* dstColor = (Color1uint8*)dst;
    +                const unorm8* src, unorm8* dst) {
    +    Color3unorm8* srcColor = (Color3unorm8*)src;
    +    Color1unorm8* dstColor = (Color1unorm8*)dst;
     
         // Top row pixels
         for(int y = 0; y < h - 1; y += 2) {
    -	int offset = y * w;
    +    int offset = y * w;
     
    -	// Top left pixels
    -	for(int x = 0; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].g);
    -	}
    +    // Top left pixels
    +    for(int x = 0; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
    +    }
     
    -	// Top right pixels
    -	for(int x = 1; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].b);
    -	}
    +    // Top right pixels
    +    for(int x = 1; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].b);
    +    }
         }
     
         // Bottom row pixels
         for(int y = 1; y < h - 1; y += 2) {
    -	int offset = y * w;
    +    int offset = y * w;
     
    -	// Bottom left pixels
    -	for(int x = 0; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].r);
    -	}
    +    // Bottom left pixels
    +    for(int x = 0; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].r);
    +    }
     
    -	// Bottom right pixels
    -	for(int x = 1; x < w - 1; x += 2) {
    -	    dstColor[x + offset] = Color1(srcColor[x + offset].g);
    -	}
    +    // Bottom right pixels
    +    for(int x = 1; x < w - 1; x += 2) {
    +        dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
    +    }
         }
     }
     
    @@ -991,40 +991,40 @@ static void rgb8_to_bayer_gbrg8(const int w, const int h,
     // =====================================================================
     static void rgba32f_to_bayer_rggb8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         Array tmp;
    -    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3uint8)));
    +    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
     
         rgba32f_to_rgb8(srcBytes, srcWidth, srcHeight, ImageFormat::RGBA32F(), 0, tmp, ImageFormat::RGB8(), 0, invertY, bayerAlg);
    -    rgb8_to_bayer_rggb8(srcWidth, srcHeight, static_cast(tmp[0]), static_cast(dstBytes[0]));
    +    rgb8_to_bayer_rggb8(srcWidth, srcHeight, static_cast(tmp[0]), static_cast(dstBytes[0]));
     
         System::free(tmp[0]);
     }
     
     static void rgba32f_to_bayer_gbrg8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         Array tmp;
    -    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3uint8)));
    +    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
     
         rgba32f_to_rgb8(srcBytes, srcWidth, srcHeight, ImageFormat::RGBA32F(), 0, tmp, ImageFormat::RGB8(), 0, invertY, bayerAlg);
    -    rgb8_to_bayer_grbg8(srcWidth, srcHeight, static_cast(tmp[0]), static_cast(dstBytes[0]));
    +    rgb8_to_bayer_grbg8(srcWidth, srcHeight, static_cast(tmp[0]), static_cast(dstBytes[0]));
     
         System::free(tmp[0]);
     }
     
     static void rgba32f_to_bayer_grbg8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         Array tmp;
    -    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3uint8)));
    +    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
     
         rgba32f_to_rgb8(srcBytes, srcWidth, srcHeight, ImageFormat::RGBA32F(), 0, tmp, ImageFormat::RGB8(), 0, invertY, bayerAlg);
    -    rgb8_to_bayer_gbrg8(srcWidth, srcHeight, static_cast(tmp[0]), static_cast(dstBytes[0]));
    +    rgb8_to_bayer_gbrg8(srcWidth, srcHeight, static_cast(tmp[0]), static_cast(dstBytes[0]));
     
         System::free(tmp[0]);
     }
     
     static void rgba32f_to_bayer_bggr8(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         Array tmp;
    -    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3uint8)));
    +    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
     
         rgba32f_to_rgb8(srcBytes, srcWidth, srcHeight, ImageFormat::RGBA32F(), 0, tmp, ImageFormat::RGB8(), 0, invertY, bayerAlg);
    -    rgb8_to_bayer_bggr8(srcWidth, srcHeight, static_cast(tmp[0]), static_cast(dstBytes[0]));
    +    rgb8_to_bayer_bggr8(srcWidth, srcHeight, static_cast(tmp[0]), static_cast(dstBytes[0]));
     
         System::free(tmp[0]);
     }
    @@ -1035,109 +1035,109 @@ static void rgba32f_to_bayer_bggr8(const Array& srcBytes, int srcWi
     // bayer --> rgb8 helpers
     // =====================================================================
     static void bayer_rggb8_to_rgb8_mhc(int w, int h, 
    -				    const uint8* in, uint8* _out) {
    +                    const unorm8* in, unorm8* _out) {
         debugAssert(in != _out);
     
    -    Color3uint8* out = (Color3uint8*)_out;
    +    Color3unorm8* out = (Color3unorm8*)_out;
     
         for (int y = 0; y < h; ++y) {
     
    -	// Row beginning in the input array.
    -	int offset = y * w;
    +    // 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;
    +    // 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);
    -	    }
    -	}
    +        // 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;
    +    ++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;
    +    // 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];
    -	    }
    -	}
    +        // 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 bayer_gbrg8_to_rgb8_mhc(int w, int h, 
    -				    const uint8* in, uint8* _out) {
    +                    const unorm8* in, unorm8* _out) {
     
         debugAssert(in != _out);
     
    -    Color3uint8* out = (Color3uint8*)_out;
    +    Color3unorm8* out = (Color3unorm8*)_out;
     
         for (int y = 0; y < h; ++y) {
     
    -	// Row beginning in the input array.
    -	int offset = y * w;
    +    // 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;
    +    // 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];
    -	    }
    -	}
    +        // 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 bayer_grbg8_to_rgb8_mhc(int w, int h, 
    -				    const uint8* in, uint8* _out) {
    +                    const unorm8* in, unorm8* _out) {
         // Run the equivalent function for red
         bayer_gbrg8_to_rgb8_mhc(w, h, in, _out);
     
         // Now swap red and blue
    -    swapRedAndBlue(w * h, (Color3uint8*)_out);
    +    swapRedAndBlue(w * h, (Color3unorm8*)_out);
     }
     
     
     static void bayer_bggr8_to_rgb8_mhc(int w, int h, 
    -				    const uint8* in, uint8* _out) {
    +                    const unorm8* in, unorm8* _out) {
         // Run the equivalent function for red
         bayer_rggb8_to_rgb8_mhc(w, h, in, _out);
     
         // Now swap red and blue
    -    swapRedAndBlue(w * h, (Color3uint8*)_out);
    +    swapRedAndBlue(w * h, (Color3unorm8*)_out);
     }
     
     // =====================================================================
    @@ -1145,9 +1145,9 @@ static void bayer_bggr8_to_rgb8_mhc(int w, int h,
     // =====================================================================
     static void bayer_rggb8_to_rgba32f(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         Array tmp;
    -    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3uint8)));
    +    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
     
    -    bayer_rggb8_to_rgb8_mhc(srcWidth, srcHeight, static_cast(srcBytes[0]), static_cast(tmp[0]));
    +    bayer_rggb8_to_rgb8_mhc(srcWidth, srcHeight, static_cast(srcBytes[0]), static_cast(tmp[0]));
         rgb8_to_rgba32f(reinterpret_cast&>(tmp), srcWidth, srcHeight, ImageFormat::RGB8(), 0, dstBytes, ImageFormat::RGBA32F(), 0, invertY, bayerAlg);
     
         System::free(tmp[0]);
    @@ -1155,9 +1155,9 @@ static void bayer_rggb8_to_rgba32f(const Array& srcBytes, int srcWi
     
     static void bayer_gbrg8_to_rgba32f(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         Array tmp;
    -    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3uint8)));
    +    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
     
    -    bayer_grbg8_to_rgb8_mhc(srcWidth, srcHeight, static_cast(srcBytes[0]), static_cast(tmp[0]));
    +    bayer_grbg8_to_rgb8_mhc(srcWidth, srcHeight, static_cast(srcBytes[0]), static_cast(tmp[0]));
         rgb8_to_rgba32f(reinterpret_cast&>(tmp), srcWidth, srcHeight, ImageFormat::RGB8(), 0, dstBytes, ImageFormat::RGBA32F(), 0, invertY, bayerAlg);
     
         System::free(tmp[0]);
    @@ -1165,9 +1165,9 @@ static void bayer_gbrg8_to_rgba32f(const Array& srcBytes, int srcWi
     
     static void bayer_grbg8_to_rgba32f(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         Array tmp;
    -    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3uint8)));
    +    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
     
    -    bayer_gbrg8_to_rgb8_mhc(srcWidth, srcHeight, static_cast(srcBytes[0]), static_cast(tmp[0]));
    +    bayer_gbrg8_to_rgb8_mhc(srcWidth, srcHeight, static_cast(srcBytes[0]), static_cast(tmp[0]));
         rgb8_to_rgba32f(reinterpret_cast&>(tmp), srcWidth, srcHeight, ImageFormat::RGB8(), 0, dstBytes, ImageFormat::RGBA32F(), 0, invertY, bayerAlg);
     
         System::free(tmp[0]);
    @@ -1175,9 +1175,9 @@ static void bayer_grbg8_to_rgba32f(const Array& srcBytes, int srcWi
     
     static void bayer_bggr8_to_rgba32f(const Array& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
         Array tmp;
    -    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3uint8)));
    +    tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
     
    -    bayer_bggr8_to_rgb8_mhc(srcWidth, srcHeight, static_cast(srcBytes[0]), static_cast(tmp[0]));
    +    bayer_bggr8_to_rgb8_mhc(srcWidth, srcHeight, static_cast(srcBytes[0]), static_cast(tmp[0]));
         rgb8_to_rgba32f(reinterpret_cast&>(tmp), srcWidth, srcHeight, ImageFormat::RGB8(), 0, dstBytes, ImageFormat::RGBA32F(), 0, invertY, bayerAlg);
     
         System::free(tmp[0]);
    @@ -1198,106 +1198,106 @@ static void bayer_bggr8_to_rgba32f(const Array& srcBytes, int srcWi
     // // =====================================================================
     
     // static void bayer_rggb8_to_bgr8_mhc(int w, int h, 
    -// 				    const uint8* in, uint8* _out) {
    +//                     const unorm8* in, unorm8* _out) {
     //     debugAssert(in != _out);
     
    -//     Color3uint8* out = (Color3uint8*)_out;
    +//     Color3unorm8* out = (Color3unorm8*)_out;
     
     //     for (int y = 0; y < h; ++y) {
     
    -// 	// Row beginning in the input array.
    -// 	int offset = y * w;
    +//     // Row beginning in the input array.
    +//     int offset = y * w;
     
    -// 	// RG row
    -// 	for (int x = 0; x < w; ++x, ++out) {
    -// 	    // R pixel
    -// 	    {
    -// 		out->b = in[x + offset];
    -// 		out->g = applyFilter(in, x, y, w, h, G_GRR);
    -// 		out->r = applyFilter(in, x, y, w, h, B_GRR);
    -// 	    }
    -// 	    ++x; ++out;
    +//     // RG row
    +//     for (int x = 0; x < w; ++x, ++out) {
    +//         // R pixel
    +//         {
    +//         out->b = in[x + offset];
    +//         out->g = applyFilter(in, x, y, w, h, G_GRR);
    +//         out->r = applyFilter(in, x, y, w, h, B_GRR);
    +//         }
    +//         ++x; ++out;
     
    -// 	    // G pixel
    -// 	    {
    -// 		out->b = applyFilter(in, x, y, w, h, R_GRG);
    -// 		out->g = in[x + offset];
    -// 		out->r = applyFilter(in, x, y, w, h, B_GRG);
    -// 	    }
    -// 	}
    +//         // G pixel
    +//         {
    +//         out->b = applyFilter(in, x, y, w, h, R_GRG);
    +//         out->g = in[x + offset];
    +//         out->r = applyFilter(in, x, y, w, h, B_GRG);
    +//         }
    +//     }
     
    -// 	++y;
    -// 	offset += w;
    +//     ++y;
    +//     offset += w;
     
    -// 	// GB row
    -// 	for (int x = 0; x < w; ++x, ++out) {
    -// 	    // G pixel
    -// 	    {
    -// 		out->b = applyFilter(in, x, y, w, h, R_BGG);
    -// 		out->g = in[x + offset];
    -// 		out->r = applyFilter(in, x, y, w, h, B_BGG);
    -// 	    }
    -// 	    ++x; ++out;
    +//     // GB row
    +//     for (int x = 0; x < w; ++x, ++out) {
    +//         // G pixel
    +//         {
    +//         out->b = applyFilter(in, x, y, w, h, R_BGG);
    +//         out->g = in[x + offset];
    +//         out->r = applyFilter(in, x, y, w, h, B_BGG);
    +//         }
    +//         ++x; ++out;
     
    -// 	    // B pixel
    -// 	    {
    -// 		out->b = applyFilter(in, x, y, w, h, R_BGB);
    -// 		out->g = applyFilter(in, x, y, w, h, G_BGB);
    -// 		out->r = in[x + offset];
    -// 	    }
    -// 	}
    +//         // B pixel
    +//         {
    +//         out->b = applyFilter(in, x, y, w, h, R_BGB);
    +//         out->g = applyFilter(in, x, y, w, h, G_BGB);
    +//         out->r = in[x + offset];
    +//         }
    +//     }
     //     }
     // }
     
     
     // static void bayer_gbrg8_to_bgr8_mhc(int w, int h, 
    -// 				    const uint8* in, uint8* _out) {
    +//                     const unorm8* in, unorm8* _out) {
     
     //     debugAssert(in != _out);
     
    -//     Color3uint8* out = (Color3uint8*)_out;
    +//     Color3unorm8* out = (Color3unorm8*)_out;
     
     //     for (int y = 0; y < h; ++y) {
     
    -// 	// Row beginning in the input array.
    -// 	int offset = y * w;
    +//     // Row beginning in the input array.
    +//     int offset = y * w;
     
    -// 	// GB row
    -// 	for (int x = 0; x < srcWidth; ++x, ++out) {
    -// 	    // G pixel
    -// 	    {
    -// 		out->b = applyFilter(in, x, y, w, h, R_BGG);
    -// 		out->g = in[x + offset];
    -// 		out->r = applyFilter(in, x, y, w, h, B_BGG);
    -// 	    }
    -// 	    ++x; ++out;
    +//     // GB row
    +//     for (int x = 0; x < srcWidth; ++x, ++out) {
    +//         // G pixel
    +//         {
    +//         out->b = applyFilter(in, x, y, w, h, R_BGG);
    +//         out->g = in[x + offset];
    +//         out->r = applyFilter(in, x, y, w, h, B_BGG);
    +//         }
    +//         ++x; ++out;
     
    -// 	    // B pixel
    -// 	    {
    -// 		out->b = applyFilter(in, x, y, w, h, R_BGB);
    -// 		out->g = applyFilter(in, x, y, w, h, G_BGB);
    -// 		out->r = in[x + offset];
    -// 	    }
    -// 	}
    +//         // B pixel
    +//         {
    +//         out->b = applyFilter(in, x, y, w, h, R_BGB);
    +//         out->g = applyFilter(in, x, y, w, h, G_BGB);
    +//         out->r = in[x + offset];
    +//         }
    +//     }
     //     }
     // }
     
     // static void bayer_grbg8_to_bgr8_mhc(int w, int h, 
    -// 				    const uint8* in, uint8* _out) {
    +//                     const unorm8* in, unorm8* _out) {
     //     // Run the equivalent function for red
     //     bayer_gbrg8_to_bgr8_mhc(w, h, in, _out);
     
     //     // Now swap red and blue
    -//     swapRedAndBlue(srcWidth * h, (Color3uint8*)_out);
    +//     swapRedAndBlue(srcWidth * h, (Color3unorm8*)_out);
     // }
     
     // static void bayer_bggr8_to_bgr8_mhc(int w, int h, 
    -// 				    const uint8* in, uint8* _out) {
    +//                     const unorm8* in, unorm8* _out) {
     //     // Run the equivalent function for red
     //     bayer_rggb8_to_bgr8_mhc(w, h, in, _out);
     
     //     // Now swap red and blue
    -//     swapRedAndBlue(srcWidth * h, (Color3uint8*)_out);
    +//     swapRedAndBlue(srcWidth * h, (Color3unorm8*)_out);
     // }
     
     
    diff --git a/deps/g3dlite/source/Intersect.cpp b/deps/g3dlite/source/Intersect.cpp
    index 929a2e4e6..06c9630c1 100644
    --- a/deps/g3dlite/source/Intersect.cpp
    +++ b/deps/g3dlite/source/Intersect.cpp
    @@ -1,23 +1,23 @@
     /**
    - @file Intersect.cpp
    - 
    - @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    -  
    - @created 2009-06-29
    - @edited  2009-06-29
    +@file Intersect.cpp
     
    - Copyright 2000-2009, Morgan McGuire.
    - All rights reserved.
    +@maintainer Morgan McGuire, http://graphics.cs.williams.edu
     
    - From the G3D Innovation Engine
    - http://g3d.sf.net
    - */
    +@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
    +    // Turn on fast floating-point optimizations
     #pragma float_control( push )
     #pragma fp_contract( on )
     #pragma fenv_access( off )
    @@ -28,816 +28,821 @@ namespace G3D {
     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;
    +        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;
    +        else
    +        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::MMP:
     
    -	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;
    +        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;
    +        else
    +            return true;
     
    -	case Ray::PMM:
    +    case Ray::MPM:
     
    -		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;
    +        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;
    +        else
    +        return true;
     
    -		return true;
    +    case Ray::MPP:
     
    -	case Ray::PMP:
    +        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;
    +        else
    +        return true;
     
    -		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;
    +    case Ray::PMM:
     
    -		return true;
    +        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;
    +        else
    +        return true;
     
    -	case Ray::PPM:
    +    case Ray::PMP:
     
    -		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;
    +        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;
    +        else
    +        return true;
     
    -	case Ray::PPP:
    +    case Ray::PPM:
     
    -		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)
    +        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;
    +        else
    +            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;
    +                return false;
    +        }   else
    +          return true;
     
    -	case Ray::OMM:
    +    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;
    +        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;
    +        else
    +            return true;
     
    -		return true;
    +    case Ray::OMP:
     
    -	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;
    +        else
    +            return true;
     
    -		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;
    +    case Ray::OPM:
     
    -		return true;
    +        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;
    +        else
    +            return true;
     
    -	case Ray::OPM:
    +    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.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;
    +        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;
    +        else
    +            return true;
     
    -		return true;
    +    case Ray::MOM:
     
    -	case Ray::OPP:
    +        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;
    +        else
    +            return true;
     
    -		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;
    +    case Ray::MOP:
     
    -		return true;
    +        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;
    +        else
    +            return true;
     
    -	case Ray::MOM:
    +    case Ray::POM:
     
    -		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;
    +        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;
    +        else
    +            return true;
     
    -		return true;
    +    case Ray::POP:
     
    -	case Ray::MOP:
    +        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;
    +        else
    +            return true;
     
    -		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;
    +    case Ray::MMO:
     
    -		return true;
    +        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;
    +        else
    +            return true;
     
    -	case Ray::POM:
    +    case Ray::MPO:
     
    -		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;
    +        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;
    +        else
    +            return true;
     
    -		return true;
    +    case Ray::PMO:
     
    -	case Ray::POP:
    +        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;
    +        else
    +            return true;
     
    -		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;
    +    case Ray::PPO:
     
    -		return true;
    +        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;
    +        else
    +            return true;
     
    -	case Ray::MMO:
    +    case Ray::MOO:
     
    -		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;
    +        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;
    +        else
    +            return true;
     
    -		return true;
    +    case Ray::POO:
     
    -	case Ray::MPO:
    +        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;
    +        else
    +            return true;
     
    -		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;
    +    case Ray::OMO:
     
    -		return true;
    +        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;
    +        else
    +            return true;
     
    -	case Ray::PMO:
    +    case Ray::OPO:
     
    -		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;
    +        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;
    +        else
    +            return true;
     
    -		return true;
    +    case Ray::OOM:
     
    -	case Ray::PPO:
    +        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;
    +        else
    +            return true;
     
    -		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;
    +    case Ray::OOP:
     
    -		return true;
    +        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;
    +        else
    +            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;
    +    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;
    +    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;
             }
     
    -		// compute the intersection distance
    +    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;
    +            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;
             }
     
    -		float t2 = (box.hi.z - ray.m_origin.z) * ray.m_invDirection.z;
    -        if (t2 > time) {
    -			time = t2;
    +    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;
             }
     
    -		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;
    +            }
     
    -	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;
    -		}
    +            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;
    +            }
     
    -	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;
             }
     
    -		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;
    +            }
     
    -	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;
    +            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;
             }
     
    -		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;
    +    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;
             }
     
    -		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;
    +            }
     
    -	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.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;
             }
     
    -		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;
    +    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;
             }
     
    -		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;
    +            }
     
    -	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;
    +            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;
             }
     
    -		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;
    +            }
     
    -	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;
    +            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;
             }
     
    -		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;
    +            }
     
    -	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.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;
             }
     
    -		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;
    +    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;
             }
     
    -		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;
    +    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;
             }
     
    -		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;
    +
    +    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;
             }
     
    -		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;
    +            }
     
    -	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.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;
             }
     
    -		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;
    +
    +    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;
             }
     
    -		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;
    +    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;
             }
     
    -		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;
    +            }
     
    -	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;
    +            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;
             }
     
    -		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;
    +    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;
             }
     
    -		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;
    +    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;
             }
     
    -		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::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;
    +            time = (box.hi.y - ray.m_origin.y) * ray.m_invDirection.y;
    +            return true;
             }
     
    -		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;
    +            }
     
    -	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.y - ray.m_origin.y) * ray.m_invDirection.y;
    +            return true;
             }
     
    -		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;
    +
    +    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;
             }
     
    -		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;
    +            }
     
    -	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.lo.z - ray.m_origin.z) * ray.m_invDirection.z;
    +            return true;
    +        }    
    +    }
     
    -		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;
    +    return false;
     }
     
     #ifdef _MSC_VER
    -// Turn off fast floating-point optimizations
    +    // Turn off fast floating-point optimizations
     #pragma float_control( pop )
     #endif
     
    diff --git a/deps/g3dlite/source/Line.cpp b/deps/g3dlite/source/Line.cpp
    index 195ae7197..2ced4a78b 100644
    --- a/deps/g3dlite/source/Line.cpp
    +++ b/deps/g3dlite/source/Line.cpp
    @@ -33,19 +33,19 @@ Vector3 Line::intersection(const Plane& plane) const {
     
     
     Line::Line(class BinaryInput& b) {
    -	deserialize(b);
    +    deserialize(b);
     }
     
     
     void Line::serialize(class BinaryOutput& b) const {
    -	_point.serialize(b);
    -	_direction.serialize(b);
    +    _point.serialize(b);
    +    _direction.serialize(b);
     }
     
     
     void Line::deserialize(class BinaryInput& b) {
    -	_point.deserialize(b);
    -	_direction.deserialize(b);
    +    _point.deserialize(b);
    +    _direction.deserialize(b);
     }
     
     
    @@ -80,7 +80,7 @@ Vector3 Line::closestPoint(const Line& B, float& minDist) const {
         
         float t1 = R.dot(U2);
         
    -    minDist = abs(P21.dot(M)) / sqrt(m2);
    +    minDist = (float)abs(P21.dot(M)) / sqrt(m2);
     
         return P1 + t1 * U1;
     }
    diff --git a/deps/g3dlite/source/LineSegment.cpp b/deps/g3dlite/source/LineSegment.cpp
    index 754600ad5..63a28fce6 100644
    --- a/deps/g3dlite/source/LineSegment.cpp
    +++ b/deps/g3dlite/source/LineSegment.cpp
    @@ -80,19 +80,19 @@ bool LineSegment::intersectsSolidSphere(const class Sphere& s) const {
     
     
     LineSegment::LineSegment(class BinaryInput& b) {
    -	deserialize(b);
    +    deserialize(b);
     }
     
     
     void LineSegment::serialize(class BinaryOutput& b) const {
    -	_point.serialize(b);
    -	direction.serialize(b);
    +    _point.serialize(b);
    +    direction.serialize(b);
     }
     
     
     void LineSegment::deserialize(class BinaryInput& b) {
    -	_point.deserialize(b);
    -	direction.deserialize(b);
    +    _point.deserialize(b);
    +    direction.deserialize(b);
     }
     
     
    diff --git a/deps/g3dlite/source/Log.cpp b/deps/g3dlite/source/Log.cpp
    index f437351cf..c113b0b0f 100644
    --- a/deps/g3dlite/source/Log.cpp
    +++ b/deps/g3dlite/source/Log.cpp
    @@ -14,7 +14,7 @@
     #include "G3D/FileSystem.h"
     #include 
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         #include 
     #else
         #include 
    @@ -23,16 +23,16 @@
     namespace G3D {
     
     void logPrintf(const char* fmt, ...) {
    -	va_list arg_list;
    -	va_start(arg_list, 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);
    +    va_list arg_list;
    +    va_start(arg_list, fmt);
         Log::common()->lazyvprintf(fmt, arg_list);
         va_end(arg_list);
     }
    @@ -53,7 +53,7 @@ Log::Log(const std::string& filename, int stripFromStackBottom) :
             std::string logName = base + ((ext != "") ? ("." + ext) : ""); 
     
             // Write time is greater than 1ms.  This may be a network drive.... try another file.
    -        #ifdef G3D_WIN32
    +        #ifdef G3D_WINDOWS
                 logName = std::string(std::getenv("TEMP")) + logName;
             #else
                 logName = std::string("/tmp/") + logName;
    @@ -86,7 +86,9 @@ Log::~Log() {
             Log::commonLog = NULL;
         }
     
    -    fclose(logFile);
    +    if (logFile) {
    +        FileSystem::fclose(logFile);
    +    }
     }
     
     
    diff --git a/deps/g3dlite/source/Matrix.cpp b/deps/g3dlite/source/Matrix.cpp
    index 7a668e59e..77188f47e 100644
    --- a/deps/g3dlite/source/Matrix.cpp
    +++ b/deps/g3dlite/source/Matrix.cpp
    @@ -43,21 +43,21 @@ void Matrix::serialize(TextOutput& t) const {
     
     
     std::string Matrix::toString(const std::string& name) const {
    -	std::string s;
    +    std::string s;
     
         if (name != "") {
             s += format("%s = \n", name.c_str());
         }
     
    -	s += "[";
    +    s += "[";
         for (int r = 0; r < rows(); ++r) {
             for (int c = 0; c < cols(); ++c) {
                 double v = impl->get(r, c);
     
    -			if (::fabs(v) < 0.00001) {
    -				// Don't print "negative zero"
    +            if (::fabs(v) < 0.00001) {
    +                // Don't print "negative zero"
                     s += format("% 10.04g", 0.0);
    -			} else if (v == iRound(v)) {
    +            } else if (v == iRound(v)) {
                     // Print integers nicely
                     s += format("% 10.04g", v);
                 } else {
    @@ -68,20 +68,20 @@ std::string Matrix::toString(const std::string& name) const {
                     s += ",";
                 } else if (r < rows() - 1) {
                     s += ";\n ";
    -			} else {
    -				s += "]\n";
    -			}
    +            } else {
    +                s += "]\n";
    +            }
             }
         }
    -	return s;
    +    return s;
     }
     
     
     #define INPLACE(OP)\
         ImplRef A = impl;\
     \
    -    if (! A.isLastReference()) {\
    -        impl = new Impl(A->R, A->C);\
    +    if (! A.unique()) {\
    +        impl.reset(new Impl(A->R, A->C));\
         }\
     \
         A->OP(B, *impl);
    @@ -157,9 +157,9 @@ Matrix Matrix::fromDiagonal(const Matrix& d) {
     }
     
     void Matrix::set(int r, int c, T v) {
    -    if (! impl.isLastReference()) {
    +    if (! impl.unique()) {
             // Copy the data before mutating; this object is shared
    -        impl = new Impl(*impl);
    +        impl.reset(new Impl(*impl));
         }
         impl->set(r, c, v);
     }
    @@ -174,9 +174,9 @@ void Matrix::setRow(int r, const Matrix& vec) {
         debugAssert(r >= 0);
         debugAssert(r < rows());
     
    -    if (! impl.isLastReference()) {
    +    if (! impl.unique()) {
             // Copy the data before mutating; this object is shared
    -        impl = new Impl(*impl);
    +        impl.reset(new Impl(*impl));
         }
         impl->setRow(r, vec.impl->data);
     }
    @@ -192,9 +192,9 @@ void Matrix::setCol(int c, const Matrix& vec) {
     
         debugAssert(c < cols());
     
    -    if (! impl.isLastReference()) {
    +    if (! impl.unique()) {
             // Copy the data before mutating; this object is shared
    -        impl = new Impl(*impl);
    +        impl.reset(new Impl(*impl));
         }
         impl->setCol(c, vec.impl->data);
     }
    @@ -272,7 +272,7 @@ Matrix Matrix::identity(int N) {
     // Implement an explicit-output unary method by trampolining to the impl
     #define TRAMPOLINE_EXPLICIT_1(method)\
     void Matrix::method(Matrix& out) const {\
    -    if ((out.impl == impl) && impl.isLastReference()) {\
    +    if ((out.impl == impl) && impl.unique()) {\
             impl->method(*out.impl);\
         } else {\
             out = this->method();\
    @@ -289,8 +289,8 @@ TRAMPOLINE_EXPLICIT_1(arraySin)
     void Matrix::mulRow(int r, const T& v) {
         debugAssert(r >= 0 && r < rows());
     
    -    if (! impl.isLastReference()) {
    -        impl = new Impl(*impl);
    +    if (! impl.unique()) {
    +        impl.reset(new Impl(*impl));
         }
     
         impl->mulRow(r, v);
    @@ -298,7 +298,7 @@ void Matrix::mulRow(int r, const T& v) {
     
     
     void Matrix::transpose(Matrix& out) const {
    -    if ((out.impl == impl) && impl.isLastReference() && (impl->R == impl->C)) {
    +    if ((out.impl == impl) && impl.unique() && (impl->R == impl->C)) {
             // In place
             impl->transpose(*out.impl);
         } else {
    @@ -369,8 +369,8 @@ void Matrix::swapRows(int r0, int r1) {
             return;
         }
     
    -    if (! impl.isLastReference()) {
    -        impl = new Impl(*impl);
    +    if (! impl.unique()) {
    +        impl.reset(new Impl(*impl));
         }
     
         impl->swapRows(r0, r1);
    @@ -385,8 +385,8 @@ void Matrix::swapAndNegateCols(int c0, int c1) {
             return;
         }
     
    -    if (! impl.isLastReference()) {
    -        impl = new Impl(*impl);
    +    if (! impl.unique()) {
    +        impl.reset(new Impl(*impl));
         }
     
         impl->swapAndNegateCols(c0, c1);
    @@ -432,15 +432,15 @@ void Matrix::svd(Matrix& U, Array& d, Matrix& V, bool sort) const {
         int C = cols();
     
         // Make sure we don't overwrite a shared matrix
    -    if (! V.impl.isLastReference()) {
    +    if (! V.impl.unique()) {
             V = Matrix::zero(C, C);
         } else {
             V.impl->setSize(C, C);
         }
     
    -    if (&U != this || ! impl.isLastReference()) {
    +    if (&U != this || ! impl.unique()) {
             // Make a copy of this for in-place SVD
    -        U.impl = new Impl(*impl);
    +        U.impl.reset(new Impl(*impl));
         }
     
         d.resize(C);
    @@ -746,7 +746,7 @@ void Matrix::Impl::inverseViaAdjoint(Impl& out) const {
             det += elt[0][r] * out.elt[r][0];
         }
     
    -	out.div(Matrix::T(det), out);
    +    out.div(Matrix::T(det), out);
     }
     
     
    @@ -848,7 +848,7 @@ Matrix::T Matrix::Impl::determinant() const {
               float cofactor10 = elt[1][2] * elt[2][0] - elt[1][0] * elt[2][2];
               float cofactor20 = elt[1][0] * elt[2][1] - elt[1][1] * elt[2][0];
           
    -		  return Matrix::T(
    +          return Matrix::T(
                 elt[0][0] * cofactor00 +
                 elt[0][1] * cofactor10 +
                 elt[0][2] * cofactor20);
    @@ -896,10 +896,11 @@ Matrix Matrix::pseudoInverse(float tolerance) const {
         Public function for testing purposes only. Use pseudoInverse(), as it contains optimizations for 
         nonsingular matrices with at least one small (<5) dimension.
     */
    +// See http://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_pseudoinverse
     Matrix Matrix::svdPseudoInverse(float tolerance) const {
    -   	if (cols() > rows()) {
    -		return transpose().svdPseudoInverse(tolerance).transpose();
    -	}
    +    if (cols() > rows()) {
    +        return transpose().svdPseudoInverse(tolerance).transpose();
    +    }
     
         // Matrices from SVD
         Matrix U, V;
    @@ -907,32 +908,32 @@ Matrix Matrix::svdPseudoInverse(float tolerance) const {
         // Diagonal elements
         Array d;
     
    -	svd(U, d, V);
    +    svd(U, d, V);
     
         if (rows() == 1) {
             d.resize(1, false);
         }
     
    -	if (tolerance < 0) {
    -		// TODO: Should be eps(d[0]), which is the largest diagonal
    -		tolerance = G3D::max(rows(), cols()) * 0.0001f;
    -	}
    +    if (tolerance < 0) {
    +        // TODO: Should be eps(d[0]), which is the largest diagonal
    +        tolerance = G3D::max(rows(), cols()) * 0.0001f;
    +    }
     
    -	Matrix X;
    -
    -	int r = 0;
    -	for (int i = 0; i < d.size(); ++i) {
    -		if (d[i] > tolerance) {
    -			d[i] = Matrix::T(1) / d[i];
    -			++r;
    -		}
    -	}
    -
    -	if (r == 0) {
    -		// There were no non-zero elements
    -		X = zero(cols(), rows());
    -	} else {
    -		// Use the first r columns
    +    Matrix X;
    +    
    +    int r = 0;
    +    for (int i = 0; i < d.size(); ++i) {
    +        if (d[i] > tolerance) {
    +            d[i] = Matrix::T(1) / d[i];
    +            ++r;
    +        }
    +    }
    +    
    +    if (r == 0) {
    +        // There were no non-zero elements
    +        X = zero(cols(), rows());
    +    } else {
    +        // Use the first r columns
             
             // Test code (the rest is below)
             /*
    @@ -1003,7 +1004,8 @@ Matrix Matrix::svdPseudoInverse(float tolerance) const {
             debugAssert(n < 0.0001);
             */
         }
    -	return X;
    +
    +    return X;
     }
     
     // Computes pseudoinverse for a vector
    @@ -1426,7 +1428,7 @@ void Matrix::Impl::inverseInPlaceGaussJordan() {
             elt[col][col] = 1.0;
     
             for (int k = 0; k < R; ++k) {
    -			elt[col][k] *= Matrix::T(pivotInverse);
    +            elt[col][k] *= Matrix::T(pivotInverse);
             }
     
             // Reduce all rows
    @@ -1438,7 +1440,7 @@ void Matrix::Impl::inverseInPlaceGaussJordan() {
                     elt[r][col] = 0.0;
     
                     for (int k = 0; k < R; ++k) {
    -					elt[r][k] -= Matrix::T(elt[col][k] * oldValue);
    +                    elt[r][k] -= Matrix::T(elt[col][k] * oldValue);
                     }
                 }
             }
    @@ -1537,13 +1539,12 @@ const char* Matrix::svdCore(float** U, int rows, int cols, float* D, float** V)
     
                     f = (double)U[i][i];
     
    -                // TODO: what is this 2-arg sign function?
    -                g = -SIGN(sqrt(s), f);
    +                g = -sign(f)*(sqrt(s));
                     h = f * g - s;
                     U[i][i] = (float)(f - g);
                     
                     if (i != cols - 1) {
    -                    for (j = l; j < cols; j++) {
    +                    for (j = l; j < cols; ++j) {
     
                             for (s = 0.0, k = i; k < rows; ++k) {
                                 s += ((double)U[k][i] * (double)U[k][j]);
    @@ -1610,13 +1611,13 @@ const char* Matrix::svdCore(float** U, int rows, int cols, float* D, float** V)
         for (i = cols - 1; i >= 0; --i) {
             if (i < cols - 1) {
                 if (g) {
    -                for (j = l; j < cols; j++) {
    +                for (j = l; j < cols; ++j) {
                         V[j][i] = (float)(((double)U[i][j] / (double)U[i][l]) / g);
                     }
     
                     // double division to avoid underflow 
                     for (j = l; j < cols; ++j) {
    -                    for (s = 0.0, k = l; k < cols; k++) {
    +                    for (s = 0.0, k = l; k < cols; ++k) {
                             s += ((double)U[i][k] * (double)V[k][j]);
                         }
     
    @@ -1778,7 +1779,7 @@ const char* Matrix::svdCore(float** U, int rows, int cols, float* D, float** V)
                     }
                     f = (c * g) + (s * y);
                     x = (c * y) - (s * g);
    -                for (jj = 0; jj < rows; jj++) {
    +                for (jj = 0; jj < rows; ++jj) {
                         y = (double)U[jj][j];
                         z = (double)U[jj][i];
                         U[jj][j] = (float)(y * c + z * s);
    diff --git a/deps/g3dlite/source/Matrix3.cpp b/deps/g3dlite/source/Matrix3.cpp
    index 7e4de9962..2f704c8f8 100644
    --- a/deps/g3dlite/source/Matrix3.cpp
    +++ b/deps/g3dlite/source/Matrix3.cpp
    @@ -6,9 +6,9 @@
      @author Morgan McGuire, graphics3d.com
     
      @created 2001-06-02
    - @edited  2009-11-15
    + @edited  2010-08-15
     
    -  Copyright 2000-2009, Morgan McGuire.
    +  Copyright 2000-2012, Morgan McGuire.
       All rights reserved.
     */
     
    @@ -32,7 +32,12 @@ Matrix3::Matrix3(const Any& any) {
     
         if (any.nameEquals("Matrix3::fromAxisAngle")) {
             any.verifySize(2);
    -        *this = Matrix3::fromAxisAngle(any[0], any[1].number());
    +        *this = fromAxisAngle(Vector3(any[0]), any[1].floatValue());
    +    } else if (any.nameEquals("Matrix3::diagonal")) {
    +        any.verifySize(3);
    +        *this = diagonal(any[0], any[1], any[2]);
    +    } else if (any.nameEquals("Matrix3::identity")) {
    +        *this = identity();
         } else {
             any.verifySize(9);
     
    @@ -45,7 +50,7 @@ Matrix3::Matrix3(const Any& any) {
     }
     
     
    -Matrix3::operator Any() const {
    +Any Matrix3::toAny() const {
         Any any(Any::ARRAY, "Matrix3");
         any.resize(9);
         for (int r = 0; r < 3; ++r) {
    @@ -116,7 +121,7 @@ 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
    +    // See also http://www.flipcode.com/documents/matrfaq.html#Q54
         Quat q = _q;
         q.unitize();
         float xx = 2.0f * q.x * q.x;
    @@ -226,8 +231,8 @@ void Matrix3::setRow(int iRow, const Vector3 &vector) {
     
     //----------------------------------------------------------------------------
     bool Matrix3::operator== (const Matrix3& rkMatrix) const {
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 if ( elt[iRow][iCol] != rkMatrix.elt[iRow][iCol] )
                     return false;
             }
    @@ -245,8 +250,8 @@ bool Matrix3::operator!= (const Matrix3& rkMatrix) const {
     Matrix3 Matrix3::operator+ (const Matrix3& rkMatrix) const {
         Matrix3 kSum;
     
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 kSum.elt[iRow][iCol] = elt[iRow][iCol] +
                                               rkMatrix.elt[iRow][iCol];
             }
    @@ -259,8 +264,8 @@ Matrix3 Matrix3::operator+ (const Matrix3& rkMatrix) const {
     Matrix3 Matrix3::operator- (const Matrix3& rkMatrix) const {
         Matrix3 kDiff;
     
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 kDiff.elt[iRow][iCol] = elt[iRow][iCol] -
                                                rkMatrix.elt[iRow][iCol];
             }
    @@ -273,8 +278,8 @@ Matrix3 Matrix3::operator- (const Matrix3& rkMatrix) const {
     Matrix3 Matrix3::operator* (const Matrix3& rkMatrix) const {
         Matrix3 kProd;
     
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 kProd.elt[iRow][iCol] =
                     elt[iRow][0] * rkMatrix.elt[0][iCol] +
                     elt[iRow][1] * rkMatrix.elt[1][iCol] +
    @@ -286,8 +291,8 @@ Matrix3 Matrix3::operator* (const Matrix3& rkMatrix) const {
     }
     
     Matrix3& Matrix3::operator+= (const Matrix3& rkMatrix) {
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 elt[iRow][iCol] = elt[iRow][iCol] + rkMatrix.elt[iRow][iCol];
             }
         }
    @@ -296,8 +301,8 @@ Matrix3& Matrix3::operator+= (const Matrix3& rkMatrix) {
     }
     
     Matrix3& Matrix3::operator-= (const Matrix3& rkMatrix) {
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 elt[iRow][iCol] = elt[iRow][iCol] - rkMatrix.elt[iRow][iCol];
             }
         }
    @@ -307,8 +312,8 @@ Matrix3& Matrix3::operator-= (const Matrix3& rkMatrix) {
     
     Matrix3& Matrix3::operator*= (const Matrix3& rkMatrix) {
         Matrix3 mulMat;
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 mulMat.elt[iRow][iCol] =
                     elt[iRow][0] * rkMatrix.elt[0][iCol] +
                     elt[iRow][1] * rkMatrix.elt[1][iCol] +
    @@ -324,8 +329,8 @@ Matrix3& Matrix3::operator*= (const Matrix3& rkMatrix) {
     Matrix3 Matrix3::operator- () const {
         Matrix3 kNeg;
     
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 kNeg[iRow][iCol] = -elt[iRow][iCol];
             }
         }
    @@ -337,8 +342,8 @@ Matrix3 Matrix3::operator- () const {
     Matrix3 Matrix3::operator* (float fScalar) const {
         Matrix3 kProd;
     
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 kProd[iRow][iCol] = fScalar * elt[iRow][iCol];
             }
         }
    @@ -352,8 +357,8 @@ Matrix3& Matrix3::operator/= (float fScalar) {
     
     Matrix3& Matrix3::operator*= (float fScalar) {
     
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 elt[iRow][iCol] *= fScalar;
             }
         }
    @@ -365,9 +370,9 @@ Matrix3& Matrix3::operator*= (float fScalar) {
     Matrix3 operator* (double fScalar, const Matrix3& rkMatrix) {
         Matrix3 kProd;
     
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    -            kProd[iRow][iCol] = fScalar * rkMatrix.elt[iRow][iCol];
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
    +            kProd[iRow][iCol] = (float)fScalar * rkMatrix.elt[iRow][iCol];
             }
         }
     
    @@ -386,8 +391,8 @@ Matrix3 operator* (int fScalar, const Matrix3& rkMatrix) {
     Matrix3 Matrix3::transpose () const {
         Matrix3 kTranspose;
     
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 kTranspose[iRow][iCol] = elt[iCol][iRow];
             }
         }
    @@ -427,10 +432,10 @@ bool Matrix3::inverse (Matrix3& rkInverse, float fTolerance) const {
         if ( G3D::abs(fDet) <= fTolerance )
             return false;
     
    -    float fInvDet = 1.0 / fDet;
    +    float fInvDet = 1.0f / fDet;
     
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++)
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol)
                 rkInverse[iRow][iCol] *= fInvDet;
         }
     
    @@ -473,13 +478,13 @@ void Matrix3::bidiagonalize (Matrix3& kA, Matrix3& kL,
                              kA[2][0] * kA[2][0]);
     
         if ( fLength > 0.0 ) {
    -        fSign = (kA[0][0] > 0.0 ? 1.0 : -1.0);
    -        fT1 = kA[0][0] + fSign * fLength;
    -        fInvT1 = 1.0 / fT1;
    +        fSign = (kA[0][0] > 0.0 ? 1.0f : -1.0f);
    +        fT1 = (float)kA[0][0] + fSign * fLength;
    +        fInvT1 = 1.0f / fT1;
             afV[1] = kA[1][0] * fInvT1;
             afV[2] = kA[2][0] * fInvT1;
     
    -        fT2 = -2.0 / (1.0 + afV[1] * afV[1] + afV[2] * afV[2]);
    +        fT2 = -2.0f / (1.0f + afV[1] * afV[1] + afV[2] * afV[2]);
             afW[0] = fT2 * (kA[0][0] + kA[1][0] * afV[1] + kA[2][0] * afV[2]);
             afW[1] = fT2 * (kA[0][1] + kA[1][1] * afV[1] + kA[2][1] * afV[2]);
             afW[2] = fT2 * (kA[0][2] + kA[1][2] * afV[1] + kA[2][2] * afV[2]);
    @@ -491,12 +496,12 @@ void Matrix3::bidiagonalize (Matrix3& kA, Matrix3& kL,
             kA[2][1] += afV[2] * afW[1];
             kA[2][2] += afV[2] * afW[2];
     
    -        kL[0][0] = 1.0 + fT2;
    +        kL[0][0] = 1.0f + fT2;
             kL[0][1] = kL[1][0] = fT2 * afV[1];
             kL[0][2] = kL[2][0] = fT2 * afV[2];
    -        kL[1][1] = 1.0 + fT2 * afV[1] * afV[1];
    +        kL[1][1] = 1.0f + fT2 * afV[1] * afV[1];
             kL[1][2] = kL[2][1] = fT2 * afV[1] * afV[2];
    -        kL[2][2] = 1.0 + fT2 * afV[2] * afV[2];
    +        kL[2][2] = 1.0f + fT2 * afV[2] * afV[2];
             bIdentity = false;
         } else {
             kL = Matrix3::identity();
    @@ -507,11 +512,11 @@ void Matrix3::bidiagonalize (Matrix3& kA, Matrix3& kL,
         fLength = sqrt(kA[0][1] * kA[0][1] + kA[0][2] * kA[0][2]);
     
         if ( fLength > 0.0 ) {
    -        fSign = (kA[0][1] > 0.0 ? 1.0 : -1.0);
    +        fSign = (kA[0][1] > 0.0 ? 1.0f : -1.0f);
             fT1 = kA[0][1] + fSign * fLength;
             afV[2] = kA[0][2] / fT1;
     
    -        fT2 = -2.0 / (1.0 + afV[2] * afV[2]);
    +        fT2 = -2.0f / (1.0f + afV[2] * afV[2]);
             afW[0] = fT2 * (kA[0][1] + kA[0][2] * afV[2]);
             afW[1] = fT2 * (kA[1][1] + kA[1][2] * afV[2]);
             afW[2] = fT2 * (kA[2][1] + kA[2][2] * afV[2]);
    @@ -521,12 +526,12 @@ void Matrix3::bidiagonalize (Matrix3& kA, Matrix3& kL,
             kA[2][1] += afW[2];
             kA[2][2] += afW[2] * afV[2];
     
    -        kR[0][0] = 1.0;
    -        kR[0][1] = kR[1][0] = 0.0;
    -        kR[0][2] = kR[2][0] = 0.0;
    -        kR[1][1] = 1.0 + fT2;
    +        kR[0][0] = 1.0f;
    +        kR[0][1] = kR[1][0] = 0.0f;
    +        kR[0][2] = kR[2][0] = 0.0f;
    +        kR[1][1] = 1.0f + fT2;
             kR[1][2] = kR[2][1] = fT2 * afV[2];
    -        kR[2][2] = 1.0 + fT2 * afV[2] * afV[2];
    +        kR[2][2] = 1.0f + fT2 * afV[2] * afV[2];
         } else {
             kR = Matrix3::identity();
         }
    @@ -535,20 +540,20 @@ void Matrix3::bidiagonalize (Matrix3& kA, Matrix3& kL,
         fLength = sqrt(kA[1][1] * kA[1][1] + kA[2][1] * kA[2][1]);
     
         if ( fLength > 0.0 ) {
    -        fSign = (kA[1][1] > 0.0 ? 1.0 : -1.0);
    +        fSign = (kA[1][1] > 0.0 ? 1.0f : -1.0f);
             fT1 = kA[1][1] + fSign * fLength;
             afV[2] = kA[2][1] / fT1;
     
    -        fT2 = -2.0 / (1.0 + afV[2] * afV[2]);
    +        fT2 = -2.0f / (1.0f + afV[2] * afV[2]);
             afW[1] = fT2 * (kA[1][1] + kA[2][1] * afV[2]);
             afW[2] = fT2 * (kA[1][2] + kA[2][2] * afV[2]);
             kA[1][1] += afW[1];
             kA[1][2] += afW[2];
             kA[2][2] += afV[2] * afW[2];
     
    -        float fA = 1.0 + fT2;
    +        float fA = 1.0f + fT2;
             float fB = fT2 * afV[2];
    -        float fC = 1.0 + fB * afV[2];
    +        float fC = 1.0f + fB * afV[2];
     
             if ( bIdentity ) {
                 kL[0][0] = 1.0;
    @@ -558,7 +563,7 @@ void Matrix3::bidiagonalize (Matrix3& kA, Matrix3& kL,
                 kL[1][2] = kL[2][1] = fB;
                 kL[2][2] = fC;
             } else {
    -            for (int iRow = 0; iRow < 3; iRow++) {
    +            for (int iRow = 0; iRow < 3; ++iRow) {
                     float fTmp0 = kL[iRow][1];
                     float fTmp1 = kL[iRow][2];
                     kL[iRow][1] = fA * fTmp0 + fB * fTmp1;
    @@ -576,15 +581,15 @@ void Matrix3::golubKahanStep (Matrix3& kA, Matrix3& kL,
         float fT12 = kA[1][1] * kA[1][2];
         float fTrace = fT11 + fT22;
         float fDiff = fT11 - fT22;
    -    float fDiscr = sqrt(fDiff * fDiff + 4.0 * fT12 * fT12);
    -    float fRoot1 = 0.5 * (fTrace + fDiscr);
    -    float fRoot2 = 0.5 * (fTrace - fDiscr);
    +    float fDiscr = sqrt(fDiff * fDiff + 4.0f * fT12 * fT12);
    +    float fRoot1 = 0.5f * (fTrace + fDiscr);
    +    float fRoot2 = 0.5f * (fTrace - fDiscr);
     
         // adjust right
         float fY = kA[0][0] - (G3D::abs(fRoot1 - fT22) <=
                               G3D::abs(fRoot2 - fT22) ? fRoot1 : fRoot2);
         float fZ = kA[0][1];
    -    float fInvLength = 1.0 / sqrt(fY * fY + fZ * fZ);
    +    float fInvLength = 1.0f / sqrt(fY * fY + fZ * fZ);
         float fSin = fZ * fInvLength;
         float fCos = -fY * fInvLength;
     
    @@ -597,7 +602,7 @@ void Matrix3::golubKahanStep (Matrix3& kA, Matrix3& kL,
     
         int iRow;
     
    -    for (iRow = 0; iRow < 3; iRow++) {
    +    for (iRow = 0; iRow < 3; ++iRow) {
             fTmp0 = kR[0][iRow];
             fTmp1 = kR[1][iRow];
             kR[0][iRow] = fCos * fTmp0 - fSin * fTmp1;
    @@ -609,7 +614,7 @@ void Matrix3::golubKahanStep (Matrix3& kA, Matrix3& kL,
     
         fZ = kA[1][0];
     
    -    fInvLength = 1.0 / sqrt(fY * fY + fZ * fZ);
    +    fInvLength = 1.0f / sqrt(fY * fY + fZ * fZ);
     
         fSin = fZ * fInvLength;
     
    @@ -631,7 +636,7 @@ void Matrix3::golubKahanStep (Matrix3& kA, Matrix3& kL,
     
         int iCol;
     
    -    for (iCol = 0; iCol < 3; iCol++) {
    +    for (iCol = 0; iCol < 3; ++iCol) {
             fTmp0 = kL[iCol][0];
             fTmp1 = kL[iCol][1];
             kL[iCol][0] = fCos * fTmp0 - fSin * fTmp1;
    @@ -643,7 +648,7 @@ void Matrix3::golubKahanStep (Matrix3& kA, Matrix3& kL,
     
         fZ = kA[0][2];
     
    -    fInvLength = 1.0 / sqrt(fY * fY + fZ * fZ);
    +    fInvLength = 1.0f / sqrt(fY * fY + fZ * fZ);
     
         fSin = fZ * fInvLength;
     
    @@ -663,7 +668,7 @@ void Matrix3::golubKahanStep (Matrix3& kA, Matrix3& kL,
     
         kA[2][2] *= fCos;
     
    -    for (iRow = 0; iRow < 3; iRow++) {
    +    for (iRow = 0; iRow < 3; ++iRow) {
             fTmp0 = kR[1][iRow];
             fTmp1 = kR[2][iRow];
             kR[1][iRow] = fCos * fTmp0 - fSin * fTmp1;
    @@ -675,7 +680,7 @@ void Matrix3::golubKahanStep (Matrix3& kA, Matrix3& kL,
     
         fZ = kA[2][1];
     
    -    fInvLength = 1.0 / sqrt(fY * fY + fZ * fZ);
    +    fInvLength = 1.0f / sqrt(fY * fY + fZ * fZ);
     
         fSin = fZ * fInvLength;
     
    @@ -691,7 +696,7 @@ void Matrix3::golubKahanStep (Matrix3& kA, Matrix3& kL,
     
         kA[2][2] = fSin * fTmp0 + fCos * fTmp1;
     
    -    for (iCol = 0; iCol < 3; iCol++) {
    +    for (iCol = 0; iCol < 3; ++iCol) {
             fTmp0 = kL[iCol][1];
             fTmp1 = kL[iCol][2];
             kL[iCol][1] = fCos * fTmp0 - fSin * fTmp1;
    @@ -707,7 +712,7 @@ void Matrix3::singularValueDecomposition (Matrix3& kL, Vector3& kS,
         Matrix3 kA = *this;
         bidiagonalize(kA, kL, kR);
     
    -    for (int i = 0; i < ms_iSvdMaxIterations; i++) {
    +    for (int i = 0; i < ms_iSvdMaxIterations; ++i) {
             float fTmp, fTmp0, fTmp1;
             float fSin0, fCos0, fTan0;
             float fSin1, fCos1, fTan1;
    @@ -727,11 +732,11 @@ void Matrix3::singularValueDecomposition (Matrix3& kL, Vector3& kS,
                     // 2x2 closed form factorization
                     fTmp = (kA[1][1] * kA[1][1] - kA[2][2] * kA[2][2] +
                             kA[1][2] * kA[1][2]) / (kA[1][2] * kA[2][2]);
    -                fTan0 = 0.5 * (fTmp + sqrt(fTmp * fTmp + 4.0));
    -                fCos0 = 1.0 / sqrt(1.0 + fTan0 * fTan0);
    +                fTan0 = 0.5f * (fTmp + sqrt(fTmp * fTmp + 4.0f));
    +                fCos0 = 1.0f / sqrt(1.0f + fTan0 * fTan0);
                     fSin0 = fTan0 * fCos0;
     
    -                for (iCol = 0; iCol < 3; iCol++) {
    +                for (iCol = 0; iCol < 3; ++iCol) {
                         fTmp0 = kL[iCol][1];
                         fTmp1 = kL[iCol][2];
                         kL[iCol][1] = fCos0 * fTmp0 - fSin0 * fTmp1;
    @@ -739,10 +744,10 @@ void Matrix3::singularValueDecomposition (Matrix3& kL, Vector3& kS,
                     }
     
                     fTan1 = (kA[1][2] - kA[2][2] * fTan0) / kA[1][1];
    -                fCos1 = 1.0 / sqrt(1.0 + fTan1 * fTan1);
    +                fCos1 = 1.0f / sqrt(1.0f + fTan1 * fTan1);
                     fSin1 = -fTan1 * fCos1;
     
    -                for (iRow = 0; iRow < 3; iRow++) {
    +                for (iRow = 0; iRow < 3; ++iRow) {
                         fTmp0 = kR[1][iRow];
                         fTmp1 = kR[2][iRow];
                         kR[1][iRow] = fCos1 * fTmp0 - fSin1 * fTmp1;
    @@ -761,11 +766,11 @@ void Matrix3::singularValueDecomposition (Matrix3& kL, Vector3& kS,
                     // 2x2 closed form factorization
                     fTmp = (kA[0][0] * kA[0][0] + kA[1][1] * kA[1][1] -
                             kA[0][1] * kA[0][1]) / (kA[0][1] * kA[1][1]);
    -                fTan0 = 0.5 * ( -fTmp + sqrt(fTmp * fTmp + 4.0));
    -                fCos0 = 1.0 / sqrt(1.0 + fTan0 * fTan0);
    +                fTan0 = 0.5f * ( -fTmp + sqrt(fTmp * fTmp + 4.0f));
    +                fCos0 = 1.0f / sqrt(1.0f + fTan0 * fTan0);
                     fSin0 = fTan0 * fCos0;
     
    -                for (iCol = 0; iCol < 3; iCol++) {
    +                for (iCol = 0; iCol < 3; ++iCol) {
                         fTmp0 = kL[iCol][0];
                         fTmp1 = kL[iCol][1];
                         kL[iCol][0] = fCos0 * fTmp0 - fSin0 * fTmp1;
    @@ -773,10 +778,10 @@ void Matrix3::singularValueDecomposition (Matrix3& kL, Vector3& kS,
                     }
     
                     fTan1 = (kA[0][1] - kA[1][1] * fTan0) / kA[0][0];
    -                fCos1 = 1.0 / sqrt(1.0 + fTan1 * fTan1);
    +                fCos1 = 1.0f / sqrt(1.0f + fTan1 * fTan1);
                     fSin1 = -fTan1 * fCos1;
     
    -                for (iRow = 0; iRow < 3; iRow++) {
    +                for (iRow = 0; iRow < 3; ++iRow) {
                         fTmp0 = kR[0][iRow];
                         fTmp1 = kR[1][iRow];
                         kR[0][iRow] = fCos1 * fTmp0 - fSin1 * fTmp1;
    @@ -796,11 +801,11 @@ void Matrix3::singularValueDecomposition (Matrix3& kL, Vector3& kS,
         }
     
         // positize diagonal
    -    for (iRow = 0; iRow < 3; iRow++) {
    +    for (iRow = 0; iRow < 3; ++iRow) {
             if ( kS[iRow] < 0.0 ) {
                 kS[iRow] = -kS[iRow];
     
    -            for (iCol = 0; iCol < 3; iCol++)
    +            for (iCol = 0; iCol < 3; ++iCol)
                     kR[iRow][iCol] = -kR[iRow][iCol];
             }
         }
    @@ -813,17 +818,17 @@ void Matrix3::singularValueComposition (const Matrix3& kL,
         Matrix3 kTmp;
     
         // product S*R
    -    for (iRow = 0; iRow < 3; iRow++) {
    -        for (iCol = 0; iCol < 3; iCol++)
    +    for (iRow = 0; iRow < 3; ++iRow) {
    +        for (iCol = 0; iCol < 3; ++iCol)
                 kTmp[iRow][iCol] = kS[iRow] * kR[iRow][iCol];
         }
     
         // product L*S*R
    -    for (iRow = 0; iRow < 3; iRow++) {
    -        for (iCol = 0; iCol < 3; iCol++) {
    +    for (iRow = 0; iRow < 3; ++iRow) {
    +        for (iCol = 0; iCol < 3; ++iCol) {
                 elt[iRow][iCol] = 0.0;
     
    -            for (int iMid = 0; iMid < 3; iMid++)
    +            for (int iMid = 0; iMid < 3; ++iMid)
                     elt[iRow][iCol] += kL[iRow][iMid] * kTmp[iMid][iCol];
             }
         }
    @@ -842,7 +847,7 @@ void Matrix3::orthonormalize () {
         // product of vectors A and B.
     
         // compute q0
    -    float fInvLength = 1.0 / sqrt(elt[0][0] * elt[0][0]
    +    float fInvLength = 1.0f / sqrt(elt[0][0] * elt[0][0]
                                            + elt[1][0] * elt[1][0] +
                                            elt[2][0] * elt[2][0]);
     
    @@ -860,7 +865,7 @@ void Matrix3::orthonormalize () {
         elt[1][1] -= fDot0 * elt[1][0];
         elt[2][1] -= fDot0 * elt[2][0];
     
    -    fInvLength = 1.0 / sqrt(elt[0][1] * elt[0][1] +
    +    fInvLength = 1.0f / sqrt(elt[0][1] * elt[0][1] +
                                       elt[1][1] * elt[1][1] +
                                       elt[2][1] * elt[2][1]);
     
    @@ -883,7 +888,7 @@ void Matrix3::orthonormalize () {
         elt[1][2] -= fDot0 * elt[1][0] + fDot1 * elt[1][1];
         elt[2][2] -= fDot0 * elt[2][0] + fDot1 * elt[2][1];
     
    -    fInvLength = 1.0 / sqrt(elt[0][2] * elt[0][2] +
    +    fInvLength = 1.0f / sqrt(elt[0][2] * elt[0][2] +
                                       elt[1][2] * elt[1][2] +
                                       elt[2][2] * elt[2][2]);
     
    @@ -923,7 +928,7 @@ void Matrix3::qDUDecomposition (Matrix3& kQ,
         // U stores the entries U[0] = u01, U[1] = u02, U[2] = u12
     
         // build orthogonal matrix Q
    -    float fInvLength = 1.0 / sqrt(elt[0][0] * elt[0][0]
    +    float fInvLength = 1.0f / sqrt(elt[0][0] * elt[0][0]
                                            + elt[1][0] * elt[1][0] +
                                            elt[2][0] * elt[2][0]);
         kQ[0][0] = elt[0][0] * fInvLength;
    @@ -935,7 +940,7 @@ void Matrix3::qDUDecomposition (Matrix3& kQ,
         kQ[0][1] = elt[0][1] - fDot * kQ[0][0];
         kQ[1][1] = elt[1][1] - fDot * kQ[1][0];
         kQ[2][1] = elt[2][1] - fDot * kQ[2][0];
    -    fInvLength = 1.0 / sqrt(kQ[0][1] * kQ[0][1] + kQ[1][1] * kQ[1][1] +
    +    fInvLength = 1.0f / sqrt(kQ[0][1] * kQ[0][1] + kQ[1][1] * kQ[1][1] +
                                       kQ[2][1] * kQ[2][1]);
         kQ[0][1] *= fInvLength;
         kQ[1][1] *= fInvLength;
    @@ -951,7 +956,7 @@ void Matrix3::qDUDecomposition (Matrix3& kQ,
         kQ[0][2] -= fDot * kQ[0][1];
         kQ[1][2] -= fDot * kQ[1][1];
         kQ[2][2] -= fDot * kQ[2][1];
    -    fInvLength = 1.0 / sqrt(kQ[0][2] * kQ[0][2] + kQ[1][2] * kQ[1][2] +
    +    fInvLength = 1.0f / sqrt(kQ[0][2] * kQ[0][2] + kQ[1][2] * kQ[1][2] +
                                       kQ[2][2] * kQ[2][2]);
         kQ[0][2] *= fInvLength;
         kQ[1][2] *= fInvLength;
    @@ -963,8 +968,8 @@ void Matrix3::qDUDecomposition (Matrix3& kQ,
                     kQ[0][1] * kQ[1][0] * kQ[2][2] - kQ[0][0] * kQ[1][2] * kQ[2][1];
     
         if ( fDet < 0.0 ) {
    -        for (int iRow = 0; iRow < 3; iRow++)
    -            for (int iCol = 0; iCol < 3; iCol++)
    +        for (int iRow = 0; iRow < 3; ++iRow)
    +            for (int iCol = 0; iCol < 3; ++iCol)
                     kQ[iRow][iCol] = -kQ[iRow][iCol];
         }
     
    @@ -997,7 +1002,7 @@ void Matrix3::qDUDecomposition (Matrix3& kQ,
         kD[2] = kR[2][2];
     
         // the shear component
    -    float fInvD0 = 1.0 / kD[0];
    +    float fInvD0 = 1.0f / kD[0];
     
         kU[0] = kR[0][1] * fInvD0;
     
    @@ -1031,7 +1036,7 @@ void Matrix3::polarDecomposition(Matrix3 &R, Matrix3 &S) const{
         const int MAX_ITERS = 100;
     
         const double eps = 50 * std::numeric_limits::epsilon();
    -    const float BigEps = 50 * eps;
    +    const float BigEps = 50.0f * (float)eps;
     
         /* Higham suggests using OneNorm(Xit-X) < eps * OneNorm(X)
          * as the convergence criterion, but OneNorm(X) should quickly
    @@ -1046,23 +1051,23 @@ void Matrix3::polarDecomposition(Matrix3 &R, Matrix3 &S) const{
           Xit = tmp.transpose();
           
           if (resid < BigEps) {
    -	// close enough use simple iteration
    -	X += Xit;
    -	X *= 0.5f;
    +    // close enough use simple iteration
    +    X += Xit;
    +    X *= 0.5f;
           }
           else {
    -	// not close to convergence, compute acceleration factor
    +    // 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;
    +    X *= 0.5f * gamma;
    +    tmp = Xit;
    +    tmp *= 0.5f / gamma;
    +    X += tmp;
           }
           
           resid = X.diffOneNorm(Xit);
    -      iter++;
    +      ++iter;
         }
     
         R = X;
    @@ -1119,13 +1124,13 @@ float Matrix3::maxCubicRoot (float afCoeff[3]) {
     
         if ( fPoly < 0.0f ) {
             // uses a matrix norm to find an upper bound on maximum root
    -        fX = G3D::abs(afCoeff[0]);
    -        float fTmp = 1.0 + G3D::abs(afCoeff[1]);
    +        fX = (float)G3D::abs(afCoeff[0]);
    +        float fTmp = 1.0f + (float)G3D::abs(afCoeff[1]);
     
             if ( fTmp > fX )
                 fX = fTmp;
     
    -        fTmp = 1.0 + G3D::abs(afCoeff[2]);
    +        fTmp = 1.0f + (float)G3D::abs(afCoeff[2]);
     
             if ( fTmp > fX )
                 fX = fTmp;
    @@ -1134,7 +1139,7 @@ float Matrix3::maxCubicRoot (float afCoeff[3]) {
         // Newton's method to find root
         float fTwoC2 = 2.0f * afCoeff[2];
     
    -    for (int i = 0; i < 16; i++) {
    +    for (int i = 0; i < 16; ++i) {
             fPoly = afCoeff[0] + fX * (afCoeff[1] + fX * (afCoeff[2] + fX));
     
             if ( G3D::abs(fPoly) <= fEpsilon )
    @@ -1154,11 +1159,11 @@ float Matrix3::spectralNorm () const {
         int iRow, iCol;
         float fPmax = 0.0;
     
    -    for (iRow = 0; iRow < 3; iRow++) {
    -        for (iCol = 0; iCol < 3; iCol++) {
    +    for (iRow = 0; iRow < 3; ++iRow) {
    +        for (iCol = 0; iCol < 3; ++iCol) {
                 kP[iRow][iCol] = 0.0;
     
    -            for (int iMid = 0; iMid < 3; iMid++) {
    +            for (int iMid = 0; iMid < 3; ++iMid) {
                     kP[iRow][iCol] +=
                         elt[iMid][iRow] * elt[iMid][iCol];
                 }
    @@ -1168,10 +1173,10 @@ float Matrix3::spectralNorm () const {
             }
         }
     
    -    float fInvPmax = 1.0 / fPmax;
    +    float fInvPmax = 1.0f / fPmax;
     
    -    for (iRow = 0; iRow < 3; iRow++) {
    -        for (iCol = 0; iCol < 3; iCol++)
    +    for (iRow = 0; iRow < 3; ++iRow) {
    +        for (iCol = 0; iCol < 3; ++iCol)
                 kP[iRow][iCol] *= fInvPmax;
         }
     
    @@ -1215,7 +1220,7 @@ float Matrix3::l1Norm() const {
           float f = fabs(elt[0][c])+ fabs(elt[1][c]) + fabs(elt[2][c]);
           
           if (f > oneNorm) {
    -	oneNorm = f;
    +    oneNorm = f;
           }
         }
         return oneNorm;
    @@ -1231,7 +1236,7 @@ float Matrix3::lInfNorm() const {
           float f = fabs(elt[r][0]) + fabs(elt[r][1])+ fabs(elt[r][2]);
           
           if (f > infNorm) {
    -	infNorm = f;
    +    infNorm = f;
           }
         }
         return infNorm;
    @@ -1244,10 +1249,10 @@ float Matrix3::diffOneNorm(const Matrix3 &y) const{
         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]);
    +    + fabs(elt[2][c] - y[2][c]);
           
           if (f > oneNorm) {
    -	oneNorm = f;
    +    oneNorm = f;
           }
         }
         return oneNorm;
    @@ -1280,14 +1285,14 @@ void Matrix3::toAxisAngle (Vector3& rkAxis, float& rfRadians) const {
     
         float fTrace = elt[0][0] + elt[1][1] + elt[2][2];
         float fCos = 0.5f * (fTrace - 1.0f);
    -    rfRadians = G3D::aCos(fCos);  // in [0,PI]
    +    rfRadians = (float)G3D::aCos(fCos);  // in [0,PI]
     
         if ( rfRadians > 0.0 ) {
             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];
    -            rkAxis.unitize();
    +            rkAxis = rkAxis.direction();
             } else {
                 // angle is PI
                 float fHalfInverse;
    @@ -1296,16 +1301,16 @@ void Matrix3::toAxisAngle (Vector3& rkAxis, float& rfRadians) const {
                     // r00 >= r11
                     if ( elt[0][0] >= elt[2][2] ) {
                         // r00 is maximum diagonal term
    -                    rkAxis.x = 0.5 * sqrt(elt[0][0] -
    -                                                elt[1][1] - elt[2][2] + 1.0);
    -                    fHalfInverse = 0.5 / rkAxis.x;
    +                    rkAxis.x = 0.5f * sqrt(elt[0][0] -
    +                                                elt[1][1] - elt[2][2] + 1.0f);
    +                    fHalfInverse = 0.5f / rkAxis.x;
                         rkAxis.y = fHalfInverse * elt[0][1];
                         rkAxis.z = fHalfInverse * elt[0][2];
                     } else {
                         // r22 is maximum diagonal term
    -                    rkAxis.z = 0.5 * sqrt(elt[2][2] -
    -                                                elt[0][0] - elt[1][1] + 1.0);
    -                    fHalfInverse = 0.5 / rkAxis.z;
    +                    rkAxis.z = 0.5f * sqrt(elt[2][2] -
    +                                                elt[0][0] - elt[1][1] + 1.0f);
    +                    fHalfInverse = 0.5f / rkAxis.z;
                         rkAxis.x = fHalfInverse * elt[0][2];
                         rkAxis.y = fHalfInverse * elt[1][2];
                     }
    @@ -1313,16 +1318,16 @@ void Matrix3::toAxisAngle (Vector3& rkAxis, float& rfRadians) const {
                     // r11 > r00
                     if ( elt[1][1] >= elt[2][2] ) {
                         // r11 is maximum diagonal term
    -                    rkAxis.y = 0.5 * sqrt(elt[1][1] -
    -                                                elt[0][0] - elt[2][2] + 1.0);
    -                    fHalfInverse = 0.5 / rkAxis.y;
    +                    rkAxis.y = 0.5f * sqrt(elt[1][1] -
    +                                                elt[0][0] - elt[2][2] + 1.0f);
    +                    fHalfInverse = 0.5f / rkAxis.y;
                         rkAxis.x = fHalfInverse * elt[0][1];
                         rkAxis.z = fHalfInverse * elt[1][2];
                     } else {
                         // r22 is maximum diagonal term
    -                    rkAxis.z = 0.5 * sqrt(elt[2][2] -
    -                                                elt[0][0] - elt[1][1] + 1.0);
    -                    fHalfInverse = 0.5 / rkAxis.z;
    +                    rkAxis.z = 0.5f * sqrt(elt[2][2] -
    +                                                elt[0][0] - elt[1][1] + 1.0f);
    +                    fHalfInverse = 0.5f / rkAxis.z;
                         rkAxis.x = fHalfInverse * elt[0][2];
                         rkAxis.y = fHalfInverse * elt[1][2];
                     }
    @@ -1339,12 +1344,16 @@ void Matrix3::toAxisAngle (Vector3& rkAxis, float& rfRadians) const {
     
     //----------------------------------------------------------------------------
     Matrix3 Matrix3::fromAxisAngle (const Vector3& _axis, float fRadians) {
    -    Vector3 axis = _axis.direction();
    +    return fromUnitAxisAngle(_axis.direction(), fRadians);
    +}
    +
    +Matrix3 Matrix3::fromUnitAxisAngle (const Vector3& axis, float fRadians) {
    +    debugAssertM(axis.isUnit(), "Matrix3::fromUnitAxisAngle requires ||axis|| = 1");
     
         Matrix3 m;
         float fCos  = cos(fRadians);
         float fSin  = sin(fRadians);
    -    float fOneMinusCos = 1.0 - fCos;
    +    float fOneMinusCos = 1.0f - fCos;
         float fX2   = square(axis.x);
         float fY2   = square(axis.y);
         float fZ2   = square(axis.z);
    @@ -1379,20 +1388,20 @@ bool Matrix3::toEulerAnglesXYZ (float& rfXAngle, float& rfYAngle,
     
         if ( elt[0][2] < 1.0f ) {
             if ( elt[0][2] > -1.0f ) {
    -            rfXAngle = G3D::aTan2( -elt[1][2], elt[2][2]);
    +            rfXAngle = (float) G3D::aTan2( -elt[1][2], elt[2][2]);
                 rfYAngle = (float) G3D::aSin(elt[0][2]);
    -            rfZAngle = G3D::aTan2( -elt[0][1], elt[0][0]);
    +            rfZAngle = (float) G3D::aTan2( -elt[0][1], elt[0][0]);
                 return true;
             } else {
                 // WARNING.  Not unique.  XA - ZA = -atan2(r10,r11)
    -            rfXAngle = -G3D::aTan2(elt[1][0], elt[1][1]);
    +            rfXAngle = -(float)G3D::aTan2(elt[1][0], elt[1][1]);
                 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]);
    +        rfXAngle = (float)G3D::aTan2(elt[1][0], elt[1][1]);
             rfYAngle = (float)halfPi();
             rfZAngle = 0.0f;
             return false;
    @@ -1408,20 +1417,20 @@ bool Matrix3::toEulerAnglesXZY (float& rfXAngle, float& rfZAngle,
     
         if ( elt[0][1] < 1.0f ) {
             if ( elt[0][1] > -1.0f ) {
    -            rfXAngle = G3D::aTan2(elt[2][1], elt[1][1]);
    +            rfXAngle = (float) G3D::aTan2(elt[2][1], elt[1][1]);
                 rfZAngle = (float) asin( -elt[0][1]);
    -            rfYAngle = G3D::aTan2(elt[0][2], elt[0][0]);
    +            rfYAngle = (float) G3D::aTan2(elt[0][2], elt[0][0]);
                 return true;
             } else {
                 // WARNING.  Not unique.  XA - YA = atan2(r20,r22)
    -            rfXAngle = G3D::aTan2(elt[2][0], elt[2][2]);
    +            rfXAngle = (float)G3D::aTan2(elt[2][0], elt[2][2]);
                 rfZAngle = (float)halfPi();
    -            rfYAngle = 0.0;
    +            rfYAngle = 0.0f;
                 return false;
             }
         } else {
             // WARNING.  Not unique.  XA + YA = atan2(-r20,r22)
    -        rfXAngle = G3D::aTan2( -elt[2][0], elt[2][2]);
    +        rfXAngle = (float)G3D::aTan2( -elt[2][0], elt[2][2]);
             rfZAngle = -(float)halfPi();
             rfYAngle = 0.0f;
             return false;
    @@ -1437,20 +1446,20 @@ bool Matrix3::toEulerAnglesYXZ (float& rfYAngle, float& rfXAngle,
     
         if ( elt[1][2] < 1.0 ) {
             if ( elt[1][2] > -1.0 ) {
    -            rfYAngle = G3D::aTan2(elt[0][2], elt[2][2]);
    +            rfYAngle = (float) G3D::aTan2(elt[0][2], elt[2][2]);
                 rfXAngle = (float) asin( -elt[1][2]);
    -            rfZAngle = G3D::aTan2(elt[1][0], elt[1][1]);
    +            rfZAngle = (float) G3D::aTan2(elt[1][0], elt[1][1]);
                 return true;
             } else {
                 // WARNING.  Not unique.  YA - ZA = atan2(r01,r00)
    -            rfYAngle = G3D::aTan2(elt[0][1], elt[0][0]);
    +            rfYAngle = (float)G3D::aTan2(elt[0][1], elt[0][0]);
                 rfXAngle = (float)halfPi();
    -            rfZAngle = 0.0;
    +            rfZAngle = 0.0f;
                 return false;
             }
         } else {
             // WARNING.  Not unique.  YA + ZA = atan2(-r01,r00)
    -        rfYAngle = G3D::aTan2( -elt[0][1], elt[0][0]);
    +        rfYAngle = (float)G3D::aTan2( -elt[0][1], elt[0][0]);
             rfXAngle = -(float)halfPi();
             rfZAngle = 0.0f;
             return false;
    @@ -1466,20 +1475,20 @@ bool Matrix3::toEulerAnglesYZX (float& rfYAngle, float& rfZAngle,
     
         if ( elt[1][0] < 1.0 ) {
             if ( elt[1][0] > -1.0 ) {
    -            rfYAngle = G3D::aTan2( -elt[2][0], elt[0][0]);
    +            rfYAngle = (float) G3D::aTan2( -elt[2][0], elt[0][0]);
                 rfZAngle = (float) asin(elt[1][0]);
    -            rfXAngle = G3D::aTan2( -elt[1][2], elt[1][1]);
    +            rfXAngle = (float) G3D::aTan2( -elt[1][2], elt[1][1]);
                 return true;
             } else {
                 // WARNING.  Not unique.  YA - XA = -atan2(r21,r22);
    -            rfYAngle = -G3D::aTan2(elt[2][1], elt[2][2]);
    +            rfYAngle = -(float)G3D::aTan2(elt[2][1], elt[2][2]);
                 rfZAngle = -(float)halfPi();
    -            rfXAngle = 0.0;
    +            rfXAngle = 0.0f;
                 return false;
             }
         } else {
             // WARNING.  Not unique.  YA + XA = atan2(r21,r22)
    -        rfYAngle = G3D::aTan2(elt[2][1], elt[2][2]);
    +        rfYAngle = (float)G3D::aTan2(elt[2][1], elt[2][2]);
             rfZAngle = (float)halfPi();
             rfXAngle = 0.0f;
             return false;
    @@ -1495,20 +1504,20 @@ bool Matrix3::toEulerAnglesZXY (float& rfZAngle, float& rfXAngle,
     
         if ( elt[2][1] < 1.0 ) {
             if ( elt[2][1] > -1.0 ) {
    -            rfZAngle = G3D::aTan2( -elt[0][1], elt[1][1]);
    +            rfZAngle = (float) G3D::aTan2( -elt[0][1], elt[1][1]);
                 rfXAngle = (float) asin(elt[2][1]);
    -            rfYAngle = G3D::aTan2( -elt[2][0], elt[2][2]);
    +            rfYAngle = (float) G3D::aTan2( -elt[2][0], elt[2][2]);
                 return true;
             } else {
                 // WARNING.  Not unique.  ZA - YA = -atan(r02,r00)
    -            rfZAngle = -G3D::aTan2(elt[0][2], elt[0][0]);
    +            rfZAngle = -(float)G3D::aTan2(elt[0][2], elt[0][0]);
                 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]);
    +        rfZAngle = (float)G3D::aTan2(elt[0][2], elt[0][0]);
             rfXAngle = (float)halfPi();
             rfYAngle = 0.0f;
             return false;
    @@ -1525,19 +1534,19 @@ bool Matrix3::toEulerAnglesZYX (float& rfZAngle, float& rfYAngle,
         if ( elt[2][0] < 1.0 ) {
             if ( elt[2][0] > -1.0 ) {
                 rfZAngle = atan2f(elt[1][0], elt[0][0]);
    -            rfYAngle = asinf(-(double)elt[2][1]);
    +            rfYAngle = asinf(-elt[2][0]);
                 rfXAngle = atan2f(elt[2][1], elt[2][2]);
                 return true;
             } else {
                 // WARNING.  Not unique.  ZA - XA = -atan2(r01,r02)
    -            rfZAngle = -G3D::aTan2(elt[0][1], elt[0][2]);
    +            rfZAngle = -(float)G3D::aTan2(elt[0][1], elt[0][2]);
                 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]);
    +        rfZAngle = (float)G3D::aTan2( -elt[0][1], -elt[0][2]);
             rfYAngle = -(float)halfPi();
             rfXAngle = 0.0f;
             return false;
    @@ -1693,10 +1702,10 @@ void Matrix3::tridiagonal (float afDiag[3], float afSubDiag[3]) {
     
         if ( G3D::abs(fC) >= EPSILON ) {
             float fLength = sqrt(fB * fB + fC * fC);
    -        float fInvLength = 1.0 / fLength;
    +        float fInvLength = 1.0f / fLength;
             fB *= fInvLength;
             fC *= fInvLength;
    -        float fQ = 2.0 * fB * fE + fC * (fF - fD);
    +        float fQ = 2.0f * fB * fE + fC * (fF - fD);
             afDiag[1] = fD + fC * fQ;
             afDiag[2] = fF - fC * fQ;
             afSubDiag[0] = fLength;
    @@ -1732,16 +1741,16 @@ bool Matrix3::qLAlgorithm (float afDiag[3], float afSubDiag[3]) {
         // QL iteration with implicit shifting to reduce matrix from tridiagonal
         // to diagonal
     
    -    for (int i0 = 0; i0 < 3; i0++) {
    +    for (int i0 = 0; i0 < 3; ++i0) {
             const int iMaxIter = 32;
             int iIter;
     
    -        for (iIter = 0; iIter < iMaxIter; iIter++) {
    +        for (iIter = 0; iIter < iMaxIter; ++iIter) {
                 int i1;
     
    -            for (i1 = i0; i1 <= 1; i1++) {
    -                float fSum = G3D::abs(afDiag[i1]) +
    -                            G3D::abs(afDiag[i1 + 1]);
    +            for (i1 = i0; i1 <= 1; ++i1) {
    +                float fSum = float(G3D::abs(afDiag[i1]) +
    +                            G3D::abs(afDiag[i1 + 1]));
     
                     if ( G3D::abs(afSubDiag[i1]) + fSum == fSum )
                         break;
    @@ -1750,9 +1759,9 @@ bool Matrix3::qLAlgorithm (float afDiag[3], float afSubDiag[3]) {
                 if ( i1 == i0 )
                     break;
     
    -            float fTmp0 = (afDiag[i0 + 1] - afDiag[i0]) / (2.0 * afSubDiag[i0]);
    +            float fTmp0 = (afDiag[i0 + 1] - afDiag[i0]) / (2.0f * afSubDiag[i0]);
     
    -            float fTmp1 = sqrt(fTmp0 * fTmp0 + 1.0);
    +            float fTmp1 = sqrt(fTmp0 * fTmp0 + 1.0f);
     
                 if ( fTmp0 < 0.0 )
                     fTmp0 = afDiag[i1] - afDiag[i0] + afSubDiag[i0] / (fTmp0 - fTmp1);
    @@ -1771,25 +1780,25 @@ bool Matrix3::qLAlgorithm (float afDiag[3], float afSubDiag[3]) {
     
                     if (G3D::abs(fTmp3) >= G3D::abs(fTmp0)) {
                         fCos = fTmp0 / fTmp3;
    -                    fTmp1 = sqrt(fCos * fCos + 1.0);
    +                    fTmp1 = sqrt(fCos * fCos + 1.0f);
                         afSubDiag[i2 + 1] = fTmp3 * fTmp1;
    -                    fSin = 1.0 / fTmp1;
    +                    fSin = 1.0f / fTmp1;
                         fCos *= fSin;
                     } else {
                         fSin = fTmp3 / fTmp0;
    -                    fTmp1 = sqrt(fSin * fSin + 1.0);
    +                    fTmp1 = sqrt(fSin * fSin + 1.0f);
                         afSubDiag[i2 + 1] = fTmp0 * fTmp1;
    -                    fCos = 1.0 / fTmp1;
    +                    fCos = 1.0f / fTmp1;
                         fSin *= fCos;
                     }
     
                     fTmp0 = afDiag[i2 + 1] - fTmp2;
    -                fTmp1 = (afDiag[i2] - fTmp0) * fSin + 2.0 * fTmp4 * fCos;
    +                fTmp1 = (afDiag[i2] - fTmp0) * fSin + 2.0f * fTmp4 * fCos;
                     fTmp2 = fSin * fTmp1;
                     afDiag[i2 + 1] = fTmp0 + fTmp2;
                     fTmp0 = fCos * fTmp1 - fTmp4;
     
    -                for (int iRow = 0; iRow < 3; iRow++) {
    +                for (int iRow = 0; iRow < 3; ++iRow) {
                         fTmp3 = elt[iRow][i2 + 1];
                         elt[iRow][i2 + 1] = fSin * elt[iRow][i2] +
                                                    fCos * fTmp3;
    @@ -1820,7 +1829,7 @@ void Matrix3::eigenSolveSymmetric (float afEigenvalue[3],
         kMatrix.tridiagonal(afEigenvalue, afSubDiag);
         kMatrix.qLAlgorithm(afEigenvalue, afSubDiag);
     
    -    for (int i = 0; i < 3; i++) {
    +    for (int i = 0; i < 3; ++i) {
             akEigenvector[i][0] = kMatrix[0][i];
             akEigenvector[i][1] = kMatrix[1][i];
             akEigenvector[i][2] = kMatrix[2][i];
    @@ -1841,8 +1850,8 @@ void Matrix3::eigenSolveSymmetric (float afEigenvalue[3],
     //----------------------------------------------------------------------------
     void Matrix3::tensorProduct (const Vector3& rkU, const Vector3& rkV,
                                  Matrix3& rkProduct) {
    -    for (int iRow = 0; iRow < 3; iRow++) {
    -        for (int iCol = 0; iCol < 3; iCol++) {
    +    for (int iRow = 0; iRow < 3; ++iRow) {
    +        for (int iCol = 0; iCol < 3; ++iCol) {
                 rkProduct[iRow][iCol] = rkU[iRow] * rkV[iCol];
             }
         }
    @@ -1922,9 +1931,9 @@ void Matrix3::_transpose(const Matrix3& A, Matrix3& out) {
     //-----------------------------------------------------------------------------
     std::string Matrix3::toString() const {
         return G3D::format("[%g, %g, %g; %g, %g, %g; %g, %g, %g]", 
    -			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]);
    +            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]);
     }
     
     
    diff --git a/deps/g3dlite/source/Matrix4.cpp b/deps/g3dlite/source/Matrix4.cpp
    index fbc918f8f..0588cb6ff 100644
    --- a/deps/g3dlite/source/Matrix4.cpp
    +++ b/deps/g3dlite/source/Matrix4.cpp
    @@ -1,16 +1,16 @@
     /**
    -  @file Matrix4.cpp
    +  \file G3D/source/Matrix4.cpp 
      
    - 
    -  @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    +  \maintainer Morgan McGuire, http://graphics.cs.williams.edu
     
    -  @created 2003-10-02
    -  @edited  2010-01-29
    +  \created 2003-10-02
    +  \edited  2012-02-19
      */
     
     #include "G3D/platform.h"
     #include "G3D/Matrix4.h"
     #include "G3D/Matrix3.h"
    +#include "G3D/Matrix2.h"
     #include "G3D/Vector4.h"
     #include "G3D/Vector3.h"
     #include "G3D/BinaryInput.h"
    @@ -24,11 +24,11 @@ namespace G3D {
     
         
     Matrix4::Matrix4(const Any& any) {
    -    any.verifyName("Matrix4");
    +    any.verifyNameBeginsWith("Matrix4", "CFrame", "CoordinateFrame");
         any.verifyType(Any::ARRAY);
     
    -    const std::string& name = toLower(any.name());
    -    if (name == "matrix4") {
    +    const std::string& name = any.name();
    +    if (name == "Matrix4") {
             any.verifySize(16);
     
             for (int r = 0; r < 4; ++r) {
    @@ -36,26 +36,43 @@ Matrix4::Matrix4(const Any& any) {
                     elt[r][c] = any[r * 4 + c];
                 }
             }
    -    } else if (name == "matrix4::scale") {
    +    } else if (name == "Matrix4::scale") {
             if (any.size() == 1) {
    -            *this = scale(any[0].number());
    +            *this = scale(any[0].floatValue());
             } else if (any.size() == 3) {
                 *this = scale(any[0], any[1], any[2]);
             } else {
                 any.verify(false, "Matrix4::scale() takes either 1 or 3 arguments");
             }
    -    } else if (name == "matrix4::translation") {
    +    } else if (name == "Matrix4::rollDegrees") {
    +        any.verifySize(1);
    +        *this = rollDegrees(any[0].floatValue());
    +    } else if (name == "Matrix4::yawDegrees") {
    +        any.verifySize(1);
    +        *this = yawDegrees(any[0].floatValue());
    +    } else if (name == "Matrix4::pitchDegrees") {
    +        any.verifySize(1);
    +        *this = pitchDegrees(any[0].floatValue());
    +    } else if (name == "Matrix4::translation") {
             if (any.size() == 3) {
                 *this = translation(any[0], any[1], any[2]);
             } else {
    -            any.verify(false, "Matrix4::translation() takes either 1 or 3 arguments");
    -        }    } else {
    +            any.verify(false, "Matrix4::translation() requires 3 arguments");
    +        }    
    +    } else if (name == "Matrix4::diagonal") {
    +        any.verifySize(4);
    +        *this = diagonal(any[0], any[1], any[2], any[3]);
    +    } else if (name == "Matrix4::identity") {
    +        *this = identity();
    +    } else if (beginsWith(name, "CFrame") || beginsWith(name, "CoordinateFrame")) {
    +        *this = CFrame(any);
    +    } else {
             any.verify(false, "Expected Matrix4 constructor");
         }
     }
     
     
    -Matrix4::operator Any() const {
    +Any Matrix4::toAny() const {
         Any any(Any::ARRAY, "Matrix4");
         any.resize(16);
         for (int r = 0; r < 4; ++r) {
    @@ -121,6 +138,12 @@ Matrix3 Matrix4::upper3x3() const {
     }
     
     
    +Matrix2 Matrix4::upper2x2() const {
    +    return Matrix2(elt[0][0], elt[0][1],
    +                   elt[1][0], elt[1][1]);
    +}
    +
    +
     Matrix4 Matrix4::orthogonalProjection(
         const class Rect2D& rect,
         float            nearval,
    @@ -164,59 +187,59 @@ Matrix4 Matrix4::orthogonalProjection(
     
     
     Matrix4 Matrix4::perspectiveProjection(
    -    float left,    
    -    float right,
    -    float bottom,  
    -    float top,
    -    float nearval, 
    -    float farval,
    -    float upDirection) {
    +    double left,    
    +    double right,
    +    double bottom,  
    +    double top,
    +    double nearval, 
    +    double farval,
    +    float  upDirection) {
     
    -    float x, y, a, b, c, d;
    +    double x, y, a, b, c, d;
     
    -    x = (2.0f*nearval) / (right-left);
    -    y = (2.0f*nearval) / (top-bottom);
    +    x = (2.0*nearval) / (right-left);
    +    y = (2.0*nearval) / (top-bottom);
         a = (right+left) / (right-left);
         b = (top+bottom) / (top-bottom);
     
    -    if (farval >= finf()) {
    +    if (farval >= inf()) {
            // Infinite view frustum
    -       c = -1.0f;
    -       d = -2.0f * nearval;
    +       c = -1.0;
    +       d = -2.0 * nearval;
         } else {
            c = -(farval+nearval) / (farval-nearval);
    -       d = -(2.0f*farval*nearval) / (farval-nearval);
    +       d = -(2.0*farval*nearval) / (farval-nearval);
         }
     
    -    debugAssertM(abs(upDirection) == 1.0f, "upDirection must be -1 or +1");
    +    debugAssertM(abs(upDirection) == 1.0, "upDirection must be -1 or +1");
         y *= upDirection;
         b *= upDirection;
     
         return Matrix4(
    -        x,  0,  a,  0,
    -        0,  y,  b,  0,
    -        0,  0,  c,  d,
    +        (float)x,  0,  (float)a,  0,
    +        0,  (float)y,  (float)b,  0,
    +        0,  0,  (float)c,  (float)d,
             0,  0, -1,  0);
     }
     
     
     void Matrix4::getPerspectiveProjectionParameters(
    -    float& left,    
    -    float& right,
    -    float& bottom,  
    -    float& top,
    -    float& nearval, 
    -    float& farval,
    +    double& left,    
    +    double& right,
    +    double& bottom,  
    +    double& top,
    +    double& nearval, 
    +    double& 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];
    +    double x = elt[0][0];
    +    double y = elt[1][1] * upDirection;
    +    double a = elt[0][2];
    +    double b = elt[1][2] * upDirection;
    +    double c = elt[2][2];
    +    double d = elt[2][3];
     
         // Verify that this really is a projection matrix
         debugAssertM(elt[3][2] == -1, "Not a projection matrix");
    @@ -232,18 +255,18 @@ void Matrix4::getPerspectiveProjectionParameters(
     
         if (c == -1) {
             farval = finf();
    -        nearval = -d / 2.0f;
    +        nearval = -d / 2.0;
         } 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));
    +        nearval = d * ((c - 1.0) / (c + 1.0) - 1.0) / (-2.0 * (c - 1.0) / (c + 1.0));
    +        farval = nearval * ((c - 1.0) / (c + 1.0));
         }
     
     
    -    left = (a - 1.0f) * nearval / x;
    -    right = 2.0f * nearval / x + left;
    +    left = (a - 1.0) * nearval / x;
    +    right = 2.0 * nearval / x + left;
     
    -    bottom = (b - 1.0f) * nearval / y;
    -    top = 2.0f * nearval / y + bottom;
    +    bottom = (b - 1.0) * nearval / y;
    +    top = 2.0 * nearval / y + bottom;
     }
     
     
    @@ -401,7 +424,7 @@ bool Matrix4::operator==(const Matrix4& other) const {
     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));
    +    return cofactor().row(0).dot(row(0));
     }
     
     
    @@ -417,14 +440,14 @@ Matrix4 Matrix4::inverse() 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)
    -	float det = A.column(0).dot(row(0));
    +    float det = A.column(0).dot(row(0));
     
    -	return A * (1.0f / det);
    +    return A * (1.0f / det);
     }
     
     
     Matrix4 Matrix4::cofactor() const {
    -	Matrix4 out;
    +    Matrix4 out;
     
         // We'll use i to incrementally compute -1 ^ (r+c)
         int i = 1;
    @@ -482,19 +505,19 @@ float Matrix4::subDeterminant(int excludeRow, int excludeCol) const {
     
     
     CoordinateFrame Matrix4::approxCoordinateFrame() const {
    -	CoordinateFrame cframe;
    +    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];
    -	}
    +    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();
    +    // Ensure that the rotation matrix is orthonormal
    +    cframe.rotation.orthonormalize();
     
    -	return cframe;
    +    return cframe;
     }
     
     
    @@ -517,12 +540,138 @@ void Matrix4::deserialize(class BinaryInput& b) {
     
     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]);
    +            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]);
     }
     
    +
    +/////////////////////////////////////////////////////////////////////////////////////////////////////////////
    +
    +
    +Matrix4float64::Matrix4float64(const Matrix4& m) {
    +    for (int r = 0; r < 4; ++r) {
    +        for (int c = 0; c < 4; ++c) {
    +            elt[r][c] = m[r][c];
    +        }
    +    }
    +}
    +
    +
    +Matrix4float64::Matrix4float64() {
    +    for (int r = 0; r < 4; ++r) {
    +        for (int c = 0; c < 4; ++c) {
    +            elt[r][c] = 0.0;
    +        }
    +    }
    +}
    +
    +
    +Matrix4float64::Matrix4float64
    +   (double r1c1, double r1c2, double r1c3, double r1c4,
    +    double r2c1, double r2c2, double r2c3, double r2c4,
    +    double r3c1, double r3c2, double r3c3, double r3c4,
    +    double r4c1, double r4c2, double r4c3, double 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;
    +}
    +
    +
    +const Matrix4float64& Matrix4float64::identity() {
    +    static Matrix4float64 m(
    +        1, 0, 0, 0,
    +        0, 1, 0, 0,
    +        0, 0, 1, 0,
    +        0, 0, 0, 1);
    +    return m;
    +}
    +    
    +
    +const Matrix4float64& Matrix4float64::zero() {
    +    static Matrix4float64 m;
    +    return m;
    +}
    +
    +
    +bool Matrix4float64::operator!=(const Matrix4float64& other) const {
    +    return ! (*this == other);
    +}
    +
    +
    +bool Matrix4float64::operator==(const Matrix4float64& 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(Matrix4float64)) == 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;
    +}
    +
    +
    +Vector4 Matrix4float64::operator*(const Vector4& vector) const {
    +    Vector4 result;
    +    for (int r = 0; r < 4; ++r) {
    +        double sum = 0;
    +        for (int c = 0; c < 4; ++c) {
    +            sum += elt[r][c] * vector[c];
    +        }
    +        result[r] = (float)sum;
    +    }
    +
    +    return result;
    +}
    +
    +
    +Matrix4float64 Matrix4float64::perspectiveProjection(
    +    double            left,
    +    double            right,
    +    double            bottom,
    +    double            top,
    +    double            nearval,
    +    double            farval,
    +    float             upDirection) {
    +    double x, y, a, b, c, d;
    +
    +    x = (2.0*nearval) / (right-left);
    +    y = (2.0*nearval) / (top-bottom);
    +    a = (right+left) / (right-left);
    +    b = (top+bottom) / (top-bottom);
    +
    +    if (farval >= inf()) {
    +       // Infinite view frustum
    +       c = -1.0;
    +       d = -2.0 * nearval;
    +    } else {
    +       c = -(farval+nearval) / (farval-nearval);
    +       d = -(2.0*farval*nearval) / (farval-nearval);
    +    }
    +
    +    debugAssertM(abs(upDirection) == 1.0, "upDirection must be -1 or +1");
    +    y *= upDirection;
    +    b *= upDirection;
    +
    +    return Matrix4float64(
    +        (float)x,  0,  (float)a,  0,
    +        0,  (float)y,  (float)b,  0,
    +        0,  0,  (float)c,  (float)d,
    +        0,  0, -1,  0);
    +}
    +
    +
     } // namespace
     
     
    diff --git a/deps/g3dlite/source/MemoryManager.cpp b/deps/g3dlite/source/MemoryManager.cpp
    index 240188a1f..7346b0f07 100644
    --- a/deps/g3dlite/source/MemoryManager.cpp
    +++ b/deps/g3dlite/source/MemoryManager.cpp
    @@ -33,7 +33,7 @@ bool MemoryManager::isThreadsafe() const {
     
     
     MemoryManager::Ref MemoryManager::create() {
    -    static MemoryManager::Ref m = new MemoryManager();
    +    static MemoryManager::Ref m(new MemoryManager());
         return m;
     }
     
    @@ -59,7 +59,7 @@ bool AlignedMemoryManager::isThreadsafe() const {
     
     
     AlignedMemoryManager::Ref AlignedMemoryManager::create() {
    -    static AlignedMemoryManager::Ref m = new AlignedMemoryManager();
    +    static AlignedMemoryManager::Ref m(new AlignedMemoryManager());
         return m;
     }
     
    @@ -85,7 +85,7 @@ bool CRTMemoryManager::isThreadsafe() const {
     
     
     CRTMemoryManager::Ref CRTMemoryManager::create() {
    -    static CRTMemoryManager::Ref m = new CRTMemoryManager();
    +    static CRTMemoryManager::Ref m(new CRTMemoryManager());
         return m;
     }
     }
    diff --git a/deps/g3dlite/source/MeshAlg.cpp b/deps/g3dlite/source/MeshAlg.cpp
    index 626fed929..75dee7274 100644
    --- a/deps/g3dlite/source/MeshAlg.cpp
    +++ b/deps/g3dlite/source/MeshAlg.cpp
    @@ -50,7 +50,7 @@ void MeshAlg::generateGrid(
     
                 texCoord.append(t);
     
    -            if (height.notNull()) {
    +            if (height) {
                     v.y = height->nearest(v.x * (height->width() - 1), v.z * (height->height() - 1)).value;
                 }
                 if (spaceCentered) {
    @@ -253,7 +253,7 @@ void MeshAlg::identifyBackfaces(
     
         backface.resize(faceArray.size());
     
    -    if (fuzzyEq(HP.w, 0.0)) {
    +    if (fuzzyEq(HP.w, 0.0f)) {
             // Infinite case
             for (int f = faceArray.size() - 1; f >= 0; --f) {
                 const MeshAlg::Face& face = faceArray[f];
    @@ -294,7 +294,7 @@ void MeshAlg::identifyBackfaces(
     
         backface.resize(faceArray.size());
     
    -    if (fuzzyEq(HP.w, 0.0)) {
    +    if (fuzzyEq(HP.w, 0.0f)) {
             // Infinite case
             for (int f = faceArray.size() - 1; f >= 0; --f) {
                 const Vector3& N = faceNormals[f];
    @@ -417,6 +417,7 @@ void MeshAlg::computeBounds(
         AABox&                  box, 
         Sphere&                 sphere) {
     
    +    // Makes a copy so as to re-use the existing computebounds code
         Array newArray;
         newArray.resize(indexArray.size());
         for (int i = 0; i < indexArray.size(); ++i) {
    @@ -441,54 +442,54 @@ void MeshAlg::computeBounds(
             const Vector3& vertex = vertexArray[v];
     
             if (vertex.x < xmin.x) {
    -    		xmin = vertex;
    +            xmin = vertex;
             }
     
             if (vertex.x > xmax.x) {
    -    		xmax = vertex;
    +            xmax = vertex;
             }
     
             if (vertex.y < ymin.y) {
    -    		ymin = vertex;
    +            ymin = vertex;
             }
     
             if (vertex.y > ymax.y) {
    -		    ymax = vertex;
    +            ymax = vertex;
             }
     
             if (vertex.z < zmin.z) {
    -		    zmin = vertex;
    +            zmin = vertex;
             }
     
             if (vertex.z > zmax.z) {
    -		    zmax = vertex;
    +            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();
    +        float xspan = (xmax - xmin).squaredMagnitude();
     
             // Same for y & z spans
    -        double yspan = (ymax - ymin).squaredMagnitude();
    -        double zspan = (zmax - zmin).squaredMagnitude();
    +        float yspan = (ymax - ymin).squaredMagnitude();
    +        float zspan = (zmax - zmin).squaredMagnitude();
         
    -        double maxspan = xspan;
    +        float maxspan = xspan;
     
             if (yspan > maxspan) {
    -	        maxspan = yspan;
    -	        dia1    = ymin;
    +            maxspan = yspan;
    +            dia1    = ymin;
                 dia2    = ymax;
    -	    }
    +        }
     
             if (zspan > maxspan) {
                 maxspan = zspan;
    -    	    dia1    = zmin;
    +            dia1    = zmin;
                 dia2    = zmax;
    -	    }
    +        }
         }
     
     
    @@ -500,52 +501,52 @@ void MeshAlg::computeBounds(
         // calculate initial radius^2 and radius 
         Vector3 d = dia2 - sphere.center;
     
    -    double radSq = d.squaredMagnitude();
    -    double rad  = sqrt(radSq);
    +    float radSq = d.squaredMagnitude();
    +    float rad  = sqrt(radSq);
     
         // SECOND PASS: increment current sphere
    -    double old_to_p, old_to_new;
    +    float 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();
    +        float old_to_p_sq = d.squaredMagnitude();
     
    -    	// do r^2 test first 
    +        // 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);
    +             // 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;
    +            // calc radius of new sphere
    +            rad = (rad + old_to_p) / 2.0f;
     
                 // for next r^2 compare
    -		    radSq = rad * rad; 	
    -		    old_to_new = old_to_p - rad;
    +            radSq = rad * rad;     
    +            old_to_new = old_to_p - rad;
     
    -		    // calc center of new sphere
    +            // 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);
    +    const Vector3 min(xmin.x, ymin.y, zmin.z);
    +    const Vector3 max(xmax.x, ymax.y, zmax.z);
     
    -        box = AABox(min, max);
    +   box = AABox(min, max);
     
    -	const float boxRadSq = (max - min).squaredMagnitude() * 0.25f;
    +    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));
    -	}
    +    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(
    @@ -600,7 +601,10 @@ void MeshAlg::computeTangentSpaceBasis(
             float r = te1.x * te2.y - te1.y * te2.x;
             if (r == 0.0) {
                 // degenerate case
    -            Vector3::generateOrthonormalBasis(t, b, n, true);
    +            if (! n.isFinite() || n.isZero()) {
    +                n = Vector3::unitY();
    +            }
    +            n.getTangents(t, b);
             } else {
                 r = 1.0f / r;        
                 t = (te2.y * ve1 - te1.y * ve2) * r;
    diff --git a/deps/g3dlite/source/MeshAlgAdjacency.cpp b/deps/g3dlite/source/MeshAlgAdjacency.cpp
    index f0bf33821..e3bdbd635 100644
    --- a/deps/g3dlite/source/MeshAlgAdjacency.cpp
    +++ b/deps/g3dlite/source/MeshAlgAdjacency.cpp
    @@ -5,7 +5,7 @@
       @created 2003-09-14
       @edited  2010-04-26
     
    -  Copyright 2000-2010, Morgan McGuire.
    +  Copyright 2000-2012, Morgan McGuire.
       All rights reserved.
     
      */
    @@ -125,6 +125,11 @@ public:
                 return *this;
             }
     
    +        bool isValid() const {
    +            return ! m_end;
    +        }
    +
    +        /** @deprecated  Use isValid */
             bool hasMore() const {
                 return ! m_end;
             }
    @@ -254,7 +259,7 @@ void MeshAlg::computeAdjacency(
         MeshEdgeTable::Iterator cur = edgeTable.begin();
     
         Array tempEdgeArray;
    -    while (cur.hasMore()) {
    +    while (cur.isValid()) {
             MeshEdgeTable::FaceIndexArray& faceIndexArray = cur.faceIndex();
     
             // Process this edge
    @@ -620,7 +625,7 @@ void MeshAlg::weldAdjacency(
         Array&          faceArray,
         Array&          edgeArray,
         Array&        vertexArray,
    -    double                radius) {
    +    float                 radius) {
     
         // Num vertices
         const int n = originalGeometry.size();
    diff --git a/deps/g3dlite/source/MeshAlgWeld.cpp b/deps/g3dlite/source/MeshAlgWeld.cpp
    index 6067f17c2..b1e602f95 100644
    --- a/deps/g3dlite/source/MeshAlgWeld.cpp
    +++ b/deps/g3dlite/source/MeshAlgWeld.cpp
    @@ -40,18 +40,18 @@ public:
         Array&           toOld;
     
         /** Must be less than one grid cell, not checked */
    -    const double          radius;
    +    const float           radius;
     
         /** (oldVertexArray[i] - offset) * scale is on the range [0, 1] */
         Vector3               offset;
         Vector3               scale;
     
    -    Welder(    
    -        const Array& _oldVertexArray,
    -        Array&       _newVertexArray,
    -        Array&           _toNew,
    -        Array&           _toOld,
    -        double                _radius);
    +    Welder
    +    (const Array& _oldVertexArray,
    +     Array&       _newVertexArray,
    +     Array&           _toNew,
    +     Array&           _toOld,
    +     float                 _radius);
             
         /**
          Computes the grid index from an ordinate.
    @@ -73,6 +73,7 @@ template<> struct HashTrait {
         static size_t hashCode(const G3D::_internal::Welder::List* key) { return reinterpret_cast(key); }
     };
     
    +
     namespace G3D {
     namespace _internal {
     
    @@ -81,7 +82,7 @@ Welder::Welder(
         Array&       _newVertexArray,
         Array&           _toNew,
         Array&           _toOld,
    -    double                _radius) :
    +    float                 _radius) :
         oldVertexArray(_oldVertexArray),
         newVertexArray(_newVertexArray),
         toNew(_toNew),
    @@ -102,10 +103,10 @@ Welder::Welder(
         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)) {
    +        if (fuzzyEq(scale[i], 0.0f)) {
                 scale[i] = 1.0;
             } else {
    -            scale[i] = 1.0 / scale[i];
    +            scale[i] = 1.0f / scale[i];
             }
         }
     }
    @@ -204,10 +205,10 @@ void MeshAlg::computeWeld(
         Array&       newVertexArray,
         Array&           toNew,
         Array&           toOld,
    -    double                radius) {
    +    float                 radius) {
     
    -    _internal::Welder welder(oldVertexArray, newVertexArray, toNew, toOld, radius);
    -    welder.weld();
    +    shared_ptr<_internal::Welder> welder = shared_ptr<_internal::Welder> (new _internal::Welder(oldVertexArray, newVertexArray, toNew, toOld, radius));
    +    welder->weld();
     }
     
     } // G3D namespace
    diff --git a/deps/g3dlite/source/MeshBuilder.cpp b/deps/g3dlite/source/MeshBuilder.cpp
    index 1bf2bab5d..6109af946 100644
    --- a/deps/g3dlite/source/MeshBuilder.cpp
    +++ b/deps/g3dlite/source/MeshBuilder.cpp
    @@ -36,7 +36,7 @@ void MeshBuilder::commit(std::string& n, Array& indexArray, Array&
             close = minEdgeLen * 0.1;
         }
     
    -    MeshAlg::computeWeld(triList, outvertexArray, toNew, toOld, close);
    +    MeshAlg::computeWeld(triList, outvertexArray, toNew, toOld, (float)close);
     
         // Construct triangles
         for (int t = 0; t < triList.size(); t += 3) {
    @@ -62,19 +62,21 @@ void MeshBuilder::centerTriList() {
     
         computeBounds(vmin, vmax);
     
    -    Vector3 diagonal = vmax - vmin;
    -    double scale = max(max(diagonal.x, diagonal.y), diagonal.z) / 2;
    +    const Vector3 diagonal = vmax - vmin;
    +    float scale = max(max(diagonal.x, diagonal.y), diagonal.z) / 2.0f;
         debugAssert(scale > 0);
     
    -    Vector3 translation = vmin + diagonal / 2;
    +    const Vector3 translation = vmin + diagonal / 2.0f;
     
         // 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];
    +    if (scaleAndCenter) {
    +        //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];
    +        }
         }
     }
     
    @@ -94,9 +96,9 @@ void MeshBuilder::computeBounds(Vector3& min, Vector3& max) {
     void MeshBuilder::addTriangle(const Vector3& a, const Vector3& b, const Vector3& c) {
         triList.append(a, b, c);
     
    -	if (_twoSided) {
    -	    triList.append(c, b, a);
    -	}
    +    if (_twoSided) {
    +        triList.append(c, b, a);
    +    }
     }
     
     
    @@ -107,7 +109,7 @@ void MeshBuilder::addQuad(const Vector3& a, const Vector3& b, const Vector3& c,
     
     
     void MeshBuilder::addTriangle(const Triangle& t) {
    -	addTriangle(t.vertex(0), t.vertex(1), t.vertex(2));
    +    addTriangle(t.vertex(0), t.vertex(1), t.vertex(2));
     }
     
     } // namespace
    diff --git a/deps/g3dlite/source/NetAddress.cpp b/deps/g3dlite/source/NetAddress.cpp
    index 64d692d47..95f975b0c 100644
    --- a/deps/g3dlite/source/NetAddress.cpp
    +++ b/deps/g3dlite/source/NetAddress.cpp
    @@ -1,9 +1,9 @@
     /**
    - @file NetMessage.cpp
    + \file NetAddress.cpp
     
    - @maintainer Morgan McGuire, morgan@cs.brown.edu
    - @created 2005-02-06
    - @edited  2005-02-06
    + \maintainer Morgan McGuire, http://graphics.cs.williams.edu
    + \created 2005-02-06
    + \edited  2013-03-17
      */
     #include "G3D/platform.h"
     #include "G3D/NetAddress.h"
    @@ -13,6 +13,7 @@
     #include "G3D/stringutils.h"
     #include "G3D/System.h"
     #include "G3D/NetworkDevice.h"
    +#include "G3D/Log.h"
     
     #if defined(G3D_LINUX) || defined(G3D_OSX)
         #include 
    @@ -23,6 +24,7 @@
         #include 
         #include 
         #define _alloca alloca
    +    #define SOCKET_ERROR -1
     
     #   ifndef SOCKADDR_IN
     #       define SOCKADDR_IN struct sockaddr_in
    @@ -40,6 +42,7 @@
     
     namespace G3D {
     
    +    
     NetAddress::NetAddress() {
         System::memset(&addr, 0, sizeof(addr));
     }
    @@ -58,15 +61,15 @@ void NetAddress::init(uint32 host, uint16 port) {
     }
     
     
    -NetAddress::NetAddress(
    -    const std::string&          hostname,
    +NetAddress::NetAddress
    +   (const std::string&          hostname,
         uint16                      port) {
         init(hostname, port);
     }
     
     
    -void NetAddress::init(
    -    const std::string&          hostname,
    +void NetAddress::init
    +   (const std::string&          hostname,
         uint16                      port) {
     
         uint32 addr;
    @@ -77,7 +80,7 @@ void NetAddress::init(
             addr = inet_addr(hostname.c_str());
         }
     
    -	// The address wasn't in numeric form, resolve it
    +    // 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());
    @@ -122,13 +125,35 @@ NetAddress::NetAddress(const SOCKADDR_IN& a) {
     
     
     NetAddress::NetAddress(const struct in_addr& addr, uint16 port) {
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
             init(ntohl(addr.S_un.S_addr), port);
         #else
             init(htonl(addr.s_addr), port);
         #endif
     }
     
    +void NetAddress::localHostAddresses(Array& array) {
    +    array.resize(0);
    +
    +    char ac[256];
    +
    +    if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) {
    +        Log::common()->printf("Error while getting local host name\n");
    +        return;
    +    }
    +
    +    struct hostent* phe = gethostbyname(ac);
    +    if (phe == 0) {
    +        Log::common()->printf("Error while getting local host address\n");
    +        return;
    +    }
    +
    +    for (int i = 0; (phe->h_addr_list[i] != 0); ++i) {
    +        struct in_addr addr;
    +        memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
    +        array.append(NetAddress(addr));
    +    }    
    +}
     
     void NetAddress::serialize(class BinaryOutput& b) const {
         b.writeUInt32(ip());
    diff --git a/deps/g3dlite/source/NetworkDevice.cpp b/deps/g3dlite/source/NetworkDevice.cpp
    index 1fc794479..e9d4f112c 100644
    --- a/deps/g3dlite/source/NetworkDevice.cpp
    +++ b/deps/g3dlite/source/NetworkDevice.cpp
    @@ -31,19 +31,18 @@ std::ostream& operator<<(std::ostream& os, const NetAddress& a) {
     static void logSocketInfo(const SOCKET& sock) {
         uint32 val;
         socklen_t sz = 4;
    -    int ret;
     
    -    ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&val, (socklen_t*)&sz);
    +    getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&val, (socklen_t*)&sz);
         logPrintf("SOL_SOCKET/SO_RCVBUF = %d\n", val);
     
    -    ret = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&val, (socklen_t*)&sz);
    +    getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&val, (socklen_t*)&sz);
         logPrintf("SOL_SOCKET/SO_SNDBUF = %d\n", val);
     
         // Note: timeout = 0 means no timeout
    -    ret = getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&val, (socklen_t*)&sz);
    +    getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&val, (socklen_t*)&sz);
         logPrintf("SOL_SOCKET/SO_RCVTIMEO = %d\n", val);
     
    -    ret = getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&val, (socklen_t*)&sz);
    +    getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&val, (socklen_t*)&sz);
         logPrintf("SOL_SOCKET/SO_SNDTIMEO = %d\n", val);
     }
     
    @@ -63,7 +62,7 @@ static int selectOneReadSocket(const SOCKET& sock) {
         FD_ZERO(&socketSet); 
         FD_SET(sock, &socketSet);
     
    -    int ret = select(sock + 1, &socketSet, NULL, NULL, &timeout);
    +    int ret = select((int)sock + 1, &socketSet, NULL, NULL, &timeout);
     
         return ret;
     }
    @@ -102,7 +101,7 @@ static int selectOneWriteSocket(const SOCKET& sock) {
         FD_ZERO(&socketSet); 
         FD_SET(sock, &socketSet);
     
    -    return select(sock + 1, NULL, &socketSet, NULL, &timeout);
    +    return select((int)sock + 1, NULL, &socketSet, NULL, &timeout);
     }
     
     ///////////////////////////////////////////////////////////////////////////////
    @@ -146,7 +145,7 @@ std::string NetworkDevice::localHostName() const {
         return gethostbyname(ac)->h_name;
     }
     
    -#ifndef G3D_WIN32
    +#ifndef G3D_WINDOWS
     const char* errnoToString() {
         switch (errno) {
         case EBADF:
    @@ -192,31 +191,31 @@ void NetworkDevice::EthernetAdapter::describe(TextOutput& t) const {
         t.writeNewline();
         
         t.writeSymbols("hostname", "=");
    -    t.writeString(hostname);
    +    t.writeString(hostname + ";");
         t.writeNewline();
     
         t.writeSymbols("name", "=");
    -    t.writeString(name);
    +    t.writeString(name + ";");
         t.writeNewline();    
     
         t.writeSymbols("ip", "=");
    -    t.writeSymbol(formatIP(ip));
    +    t.writeSymbol("\"" + formatIP(ip) + "\";");
         t.writeNewline();    
     
         t.writeSymbols("subnet", "=");
    -    t.writeSymbol(formatIP(subnet));
    +    t.writeSymbol("\"" + formatIP(subnet) + "\";");
         t.writeNewline();    
     
         t.writeSymbols("broadcast", "=");
    -    t.writeSymbol(formatIP(broadcast));
    +    t.writeSymbol("\"" + formatIP(broadcast) + "\";");
         t.writeNewline();    
     
         t.writeSymbols("mac", "=");
    -    t.writeSymbol(formatMAC(mac));
    +    t.writeSymbol("\"" + formatMAC(mac) + "\";");
         t.writeNewline();    
     
         t.popIndent();
    -    t.writeSymbol("}");
    +    t.writeSymbol("};");
         t.writeNewline();
     }
     
    @@ -243,15 +242,17 @@ std::string NetworkDevice::formatMAC(const uint8 MAC[6]) {
     }
     
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     
     bool NetworkDevice::init() {
         debugAssert(! initialized);
     
         logPrintf("Network Startup");
         logPrintf("Starting WinSock networking.\n");
    -    WSADATA wsda;		    
    -    WSAStartup(MAKEWORD(G3D_WINSOCK_MAJOR_VERSION, G3D_WINSOCK_MINOR_VERSION), &wsda);
    +
    +//    G3D now initializes winsock through ENet
    +//    WSADATA wsda;            
    +//    WSAStartup(MAKEWORD(G3D_WINSOCK_MAJOR_VERSION, G3D_WINSOCK_MINOR_VERSION), &wsda);
             
         std::string hostname = "localhost";
         {
    @@ -280,7 +281,9 @@ bool NetworkDevice::init() {
         
         std::string machine = localHostName();
         std::string addr    = NetAddress(machine, 0).ipString();
    +    /*
         logPrintf(
    +
                   "Network:\n"
                   "  Status: %s\n"
                   "  Loaded winsock specification version %d (%d is "
    @@ -293,6 +296,7 @@ bool NetworkDevice::init() {
                   wsda.wHighVersion,
                   wsda.iMaxSockets,
                   wsda.iMaxUdpDg);
    +    */
         
         // TODO: WSAIoctl for subnet and broadcast addresses
         // http://msdn.microsoft.com/en-us/library/ms741621(VS.85).aspx
    @@ -449,7 +453,7 @@ bool NetworkDevice::init() {
         }
     
         // Extract all interesting adapters from the table
    -    for (AdapterTable::Iterator it = table.begin(); it.hasMore(); ++it) {
    +    for (AdapterTable::Iterator it = table.begin(); it.isValid(); ++it) {
             const EthernetAdapter& adapter = it->value;
             
             // Only add adapters that have IP addresses
    @@ -471,11 +475,10 @@ bool NetworkDevice::init() {
     void NetworkDevice::_cleanup() {
         debugAssert(initialized);
     
    -    logPrintf("Network Cleanup");
    -#   ifdef G3D_WIN32
    -        WSACleanup();
    +#   ifdef G3D_WINDOWS
    +    // Now handled through enet
    +//        WSACleanup();
     #   endif
    -    logPrintf("Network cleaned up.");
     }
     
     bool NetworkDevice::bind(SOCKET sock, const NetAddress& addr) const {
    @@ -497,7 +500,7 @@ bool NetworkDevice::bind(SOCKET sock, const NetAddress& addr) const {
     
     void NetworkDevice::closesocket(SOCKET& sock) const {
         if (sock != 0) {
    -        #ifdef G3D_WIN32
    +        #ifdef G3D_WINDOWS
                 ::closesocket(sock);
             #else
                 close(sock);
    @@ -512,7 +515,7 @@ void NetworkDevice::closesocket(SOCKET& sock) const {
     void NetworkDevice::localHostAddresses(Array& array) const {
         array.resize(0);
     
    -    char ac[128];
    +    char ac[256];
     
         if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) {
             Log::common()->printf("Error while getting local host name\n");
    @@ -606,13 +609,16 @@ static void increaseBufferSize(SOCKET sock) {
     //////////////////////////////////////////////////////////////////////////////
     
     ReliableConduitRef ReliableConduit::create(const NetAddress& address) {
    -    return new ReliableConduit(address);
    +    return ReliableConduitRef(new ReliableConduit(address));
     }
     
     
    -ReliableConduit::ReliableConduit(
    -    const NetAddress&   _addr) : state(NO_MESSAGE), receiveBuffer(NULL),
    -    receiveBufferTotalSize(0), receiveBufferUsedSize(0) {
    +ReliableConduit::ReliableConduit
    +   (const NetAddress&   _addr) : 
    +    state(NO_MESSAGE), 
    +    receiveBuffer(NULL),
    +    receiveBufferTotalSize(0), 
    +    receiveBufferUsedSize(0) {
     
         NetworkDevice* nd = NetworkDevice::instance();
         
    @@ -829,7 +835,7 @@ uint32 ReliableConduit::waitingMessageType() {
     
     void ReliableConduit::sendBuffer(const BinaryOutput& b) {
         NetworkDevice* nd = NetworkDevice::instance();
    -    int ret = ::send(sock, (const char*)b.getCArray(), b.size(), 0);
    +    int ret = ::send(sock, (const char*)b.getCArray(), (int)b.size(), 0);
         
         if (ret == SOCKET_ERROR) {
             Log::common()->println("Error occured while sending message.");
    @@ -938,11 +944,11 @@ void ReliableConduit::receiveIntoBuffer() {
     
         // Read the data itself
         int ret = 0;
    -    uint32 left = messageSize - receiveBufferUsedSize;
    +    uint32 left = messageSize - (uint32)receiveBufferUsedSize;
         int count = 0;
         while ((ret != SOCKET_ERROR) && (left > 0) && (count < 100)) {
     
    -        ret = recv(sock, ((char*)receiveBuffer) + receiveBufferUsedSize, left, 0);
    +        ret = recv(sock, ((char*)receiveBuffer) + (uint32)receiveBufferUsedSize, left, 0);
     
             if (ret > 0) {
                 left -= ret;
    @@ -985,11 +991,12 @@ LightweightConduitRef LightweightConduit::create(
         bool                        enableReceive,
         bool                        enableBroadcast) {
         
    -    return new LightweightConduit(receivePort, enableReceive, enableBroadcast);
    +    return LightweightConduitRef(new LightweightConduit(receivePort, enableReceive, enableBroadcast));
     }
     
    -LightweightConduit::LightweightConduit(
    -    uint16 port,
    +
    +LightweightConduit::LightweightConduit
    +   (uint16 port,
         bool enableReceive, 
         bool enableBroadcast) {
         NetworkDevice* nd = NetworkDevice::instance();
    @@ -1064,7 +1071,7 @@ bool LightweightConduit::receive(NetAddress& sender) {
     
     void LightweightConduit::sendBuffer(const NetAddress& a, BinaryOutput& b) {
         NetworkDevice* nd = NetworkDevice::instance();
    -    if (sendto(sock, (const char*)b.getCArray(), b.size(), 0,
    +    if (sendto(sock, (const char*)b.getCArray(), (int)b.size(), 0,
            (struct sockaddr *) &(a.addr), sizeof(a.addr)) == SOCKET_ERROR) {
             Log::common()->printf("Error occured while sending packet "
                                  "to %s\n", inet_ntoa(a.addr.sin_addr));
    @@ -1137,7 +1144,7 @@ uint32 LightweightConduit::waitingMessageType() {
     ///////////////////////////////////////////////////////////////////////////////
     
     NetListenerRef NetListener::create(const uint16 port) {
    -    return new NetListener(port);
    +    return NetListenerRef(new NetListener(port));
     }
     
     
    @@ -1215,20 +1222,20 @@ ReliableConduitRef NetListener::waitForConnection() {
             Log::common()->println("Error in NetListener::acceptConnection.");
             Log::common()->println(socketErrorCode());
             nd->closesocket(sock);
    -        return NULL;
    +        return ReliableConduitRef();
         }
     
         Log::common()->printf("%s connected, transferred to socket %d.\n", 
                              inet_ntoa(remote_addr.sin_addr), sClient);
     
    -    #ifndef G3D_WIN32
    -        return new ReliableConduit(sClient, 
    +    #ifndef G3D_WINDOWS
    +    return ReliableConduitRef(new ReliableConduit(sClient, 
                          NetAddress(htonl(remote_addr.sin_addr.s_addr), 
    -                                ntohs(remote_addr.sin_port)));
    +                                ntohs(remote_addr.sin_port))));
         #else
    -        return new ReliableConduit(sClient, 
    +    return ReliableConduitRef(ReliableConduitRef(new ReliableConduit(sClient, 
                         NetAddress(ntohl(remote_addr.sin_addr.S_un.S_addr), 
    -                               ntohs(remote_addr.sin_port)));
    +                               ntohs(remote_addr.sin_port)))));
         #endif
     }
     
    @@ -1247,17 +1254,17 @@ bool NetListener::clientWaiting() const {
     void NetworkDevice::describeSystem(
         TextOutput& t) {
     
    -    t.writeSymbols("Network", "{");
    +    t.writeSymbols("Network", "=", "{");
         t.writeNewline();
         t.pushIndent();
         
         for (int i = 0; i < m_adapterArray.size(); ++i) {
    +        t.printf("Adapter%d =", i);
             m_adapterArray[i].describe(t);
         }
     
    -
         t.popIndent();
    -    t.writeSymbols("}");
    +    t.writeSymbols("};");
         t.writeNewline();
         t.writeNewline();
     }
    diff --git a/deps/g3dlite/source/PhysicsFrame.cpp b/deps/g3dlite/source/PhysicsFrame.cpp
    index 30fbdf8d6..9146d78ff 100644
    --- a/deps/g3dlite/source/PhysicsFrame.cpp
    +++ b/deps/g3dlite/source/PhysicsFrame.cpp
    @@ -1,10 +1,10 @@
     /**
    - @file PhysicsFrame.cpp
    + \file PhysicsFrame.cpp
     
    - @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    + \maintainer Morgan McGuire, http://graphics.cs.williams.edu
      
    - @created 2002-07-09
    - @edited  2010-03-25
    + \created 2002-07-09
    + \edited  2013-04-25
     */
     
     #include "G3D/platform.h"
    @@ -13,6 +13,7 @@
     #include "G3D/PhysicsFrame.h"
     #include "G3D/BinaryInput.h"
     #include "G3D/BinaryOutput.h"
    +#include "G3D/UprightFrame.h"
     
     namespace G3D {
     
    @@ -22,31 +23,44 @@ PhysicsFrame::PhysicsFrame() {
     }
     
     
    -PhysicsFrame::PhysicsFrame(
    -    const CoordinateFrame& coordinateFrame) {
    -
    +PhysicsFrame::PhysicsFrame
    +   (const CoordinateFrame& coordinateFrame) {
         translation = coordinateFrame.translation;
         rotation    = Quat(coordinateFrame.rotation);
     }
     
     
    +Any PhysicsFrame::toAny() const {
    +    // Prefer to serialize as a CFrame, which is easier to read
    +    if (false) {
    +        Any a(Any::ARRAY, "PFrame");
    +        a.append(rotation, translation.toAny("Point3"));
    +        return a;
    +    } else {
    +        return CFrame(*this).toAny();
    +    }
    +}
    +
    +
     PhysicsFrame::PhysicsFrame(const Any& a) {
         const std::string& n = toLower(a.name());
         *this = PhysicsFrame();
     
    -    if (beginsWith(n, "vector3")) {
    -        *this = PhysicsFrame(Vector3(a));
    +    if (beginsWith(n, "vector3") || beginsWith(n, "point3")) {
    +        *this = PhysicsFrame(Point3(a));
         } else if (beginsWith(n, "matrix3")) {        
             *this = PhysicsFrame(Matrix3(a));
    -    } else if (beginsWith(n, "cframe") || beginsWith(n, "coordinateframe")) {        
    -        *this = PhysicsFrame(CoordinateFrame(a));
    +    } else if (beginsWith(n, "cframe") || beginsWith(n, "coordinateframe") || beginsWith(n, "matrix4")) {        
    +        *this = CoordinateFrame(a);
    +    } else if (beginsWith(n, "uprightframe")) {        
    +        *this = UprightFrame(a).toCoordinateFrame();
         } else if (beginsWith(n, "pframe") || beginsWith(n, "physicsframe")) {
             if (a.type() == Any::ARRAY) {
                 a.verifySize(2);
                 rotation    = a[0];
                 translation = a[1];
             } else {
    -            for (Any::AnyTable::Iterator it = a.table().begin(); it.hasMore(); ++it) {
    +            for (Any::AnyTable::Iterator it = a.table().begin(); it.isValid(); ++it) {
                     const std::string& n = toLower(it->key);
                     if (n == "translation") {
                         translation = it->value;
    @@ -57,6 +71,8 @@ PhysicsFrame::PhysicsFrame(const Any& a) {
                     }
                 }
             }
    +    } else {
    +        a.verify(false, "Unrecognized class name where a PhysicsFrame or equivalent was expected.");
         }
     }
     
    diff --git a/deps/g3dlite/source/PhysicsFrameSpline.cpp b/deps/g3dlite/source/PhysicsFrameSpline.cpp
    index 2dfdb6f91..ca9d6cc55 100644
    --- a/deps/g3dlite/source/PhysicsFrameSpline.cpp
    +++ b/deps/g3dlite/source/PhysicsFrameSpline.cpp
    @@ -6,55 +6,53 @@
     #include "G3D/PhysicsFrameSpline.h"
     #include "G3D/Any.h"
     #include "G3D/stringutils.h"
    +#include "G3D/UprightFrame.h"
     
     namespace G3D {
     
     PhysicsFrameSpline::PhysicsFrameSpline() {}
     
    +
     PhysicsFrameSpline::PhysicsFrameSpline(const Any& any) {
    -    *this = any;
    +    if (beginsWith(any.name(), "PFrameSpline") ||
    +        beginsWith(any.name(), "PhysicsFrameSpline") ||
    +        beginsWith(any.name(), "CFrameSpline") ||
    +        beginsWith(any.name(), "CoordinateFrameSpline") ||
    +        beginsWith(any.name(), "UprightSpline") ||
    +        beginsWith(any.name(), "UprightFrameSpline")) {
    +        AnyTableReader t(any);
    +        init(t);
    +        t.verifyDone();
    +    } else {
    +        // Must be a single control point
    +        control.append(any);
    +        time.append(0);
    +    }
     }
     
    -PhysicsFrameSpline& PhysicsFrameSpline::operator=(const Any& any) {
    -    const std::string& n = toLower(any.name());
    -    *this = PhysicsFrameSpline();
     
    -    if (n == "physicsframespline" || n == "pframespline") {
    -        any.verifyName("PhysicsFrameSpline", "PFrameSpline");
    -        
    -        for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
    -            const std::string& k = toLower(it->key);
    -            if (k == "cyclic") {
    -                cyclic = it->value;
    -            } else if (k == "control") {
    -                const Any& v = it->value;
    -                v.verifyType(Any::ARRAY);
    -                control.resize(v.size());
    -                for (int i = 0; i < control.size(); ++i) {
    -                    control[i] = v[i];
    -                }
    -                if (! any.containsKey("time")) {
    -                    time.resize(control.size());
    -                    for (int i = 0; i < time.size(); ++i) {
    -                        time[i] = i;
    -                    }
    -                }
    -            } else if (k == "finalinterval") {
    -                finalInterval = it->value;
    -            } else if (k == "time") {
    -                const Any& v = it->value;
    -                v.verifyType(Any::ARRAY);
    -                time.resize(v.size());
    -                for (int i = 0; i < time.size(); ++i) {
    -                    time[i] = v[i];
    -                }
    +bool PhysicsFrameSpline::operator==(const PhysicsFrameSpline& other) const {
    +    if ((extrapolationMode == other.extrapolationMode) && 
    +        (time.size() == other.size()) && 
    +        (finalInterval == other.finalInterval) && 
    +        (control.size() == other.control.size())) {
    +        // Check actual values
    +        for (int i = 0; i < time.size(); ++i) {
    +            if (time[i] != other.time[i]) {
    +                return false;
                 }
             }
    +
    +        for (int i = 0; i < control.size(); ++i) {
    +            if (control[i] != other.control[i]) {
    +                return false;
    +            }
    +        }
    +
    +        return true;
         } else {
    -        // Must be a PhysicsFrame constructor of some kind
    -        append(any);
    +        return false;
         }
    -    return *this;
     }
     
     
    @@ -62,6 +60,11 @@ void PhysicsFrameSpline::correct(PhysicsFrame& frame) const {
         frame.rotation.unitize();
     }
     
    +void PhysicsFrameSpline::scaleControlPoints(float scaleFactor) {
    +    for (int i = 0; i < control.size(); ++i) {
    +        control[i].translation *= scaleFactor;
    +    }
    +}
     
     void PhysicsFrameSpline::ensureShortestPath(PhysicsFrame* A, int N) const {
         for (int i = 1; i < N; ++i) {
    diff --git a/deps/g3dlite/source/Plane.cpp b/deps/g3dlite/source/Plane.cpp
    index 9b7991c03..d6b41d360 100644
    --- a/deps/g3dlite/source/Plane.cpp
    +++ b/deps/g3dlite/source/Plane.cpp
    @@ -4,7 +4,7 @@
      @maintainer Morgan McGuire, http://graphics.cs.williams.edu
      
      @created 2003-02-06
    - @edited  2006-01-29
    + \edited  2011-02-29
      */
     
     #include "G3D/platform.h"
    @@ -12,31 +12,47 @@
     #include "G3D/BinaryOutput.h"
     #include "G3D/BinaryInput.h"
     #include "G3D/stringutils.h"
    +#include "G3D/Any.h"
     
     namespace G3D {
     
    +Plane::Plane(const Any& a) {
    +    a.verifyName("Plane");
    +    a.verifySize(2);
    +    a.verifyType(Any::ARRAY);
    +    *this = Plane(Vector3(a[0]), Point3(a[1]));
    +}
    +
    +
    +Any Plane::toAny() const {
    +    Any a(Any::ARRAY, "Plane");
    +    a.append(normal(), normal() * _distance);
    +    return a;
    +}
    +
    +
     Plane::Plane(class BinaryInput& b) {
    -	deserialize(b);
    +    deserialize(b);
     }
     
     
     void Plane::serialize(class BinaryOutput& b) const {
    -	_normal.serialize(b);
    -	b.writeFloat64(_distance);
    +    _normal.serialize(b);
    +    b.writeFloat64(_distance);
     }
     
     
     void Plane::deserialize(class BinaryInput& b) {
    -	_normal.deserialize(b);
    -	_distance = (float)b.readFloat64();
    +    _normal.deserialize(b);
    +    _distance = (float)b.readFloat64();
     }
     
     
    -Plane::Plane(
    -    Vector4      point0,
    -    Vector4      point1,
    -    Vector4      point2) {
    -
    +Plane::Plane
    +(Vector4      point0,
    + Vector4      point1,
    + Vector4      point2) {
    +    
         debugAssertM(
             point0.w != 0 || 
             point1.w != 0 || 
    diff --git a/deps/g3dlite/source/Quat.cpp b/deps/g3dlite/source/Quat.cpp
    index e06483b44..25c1711a9 100644
    --- a/deps/g3dlite/source/Quat.cpp
    +++ b/deps/g3dlite/source/Quat.cpp
    @@ -1,12 +1,12 @@
     /**
    -  @file Quat.cpp
    +   \file G3D/Quat.cpp
      
       Quaternion implementation based on Watt & Watt page 363
       
    -  @author Morgan McGuire, graphics3d.com
    +  \uthor Morgan McGuire, graphics3d.com
       
    -  @created 2002-01-23
    -  @edited  2010-03-31
    +  \created 2002-01-23
    +  \edited  2010-05-31
      */
     
     #include "G3D/Quat.h"
    @@ -45,50 +45,57 @@ Quat::Quat(const class Any& a) {
     }
     
     
    +Any Quat::toAny() const {
    +    Any a(Any::ARRAY, "Quat");
    +    a.append(x, y, z, w);
    +    return a;
    +}
    +
    +
     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.
    +    // 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
    +    // 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*
    +    // 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:
    -	//
    +    // 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:
    +    //
    +    // 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
    +    // nc2 = -c^2
         double nc2 = ((rot[j][j] + rot[k][k]) - rot[i][i]) - 1.0;
    -    v[i] =  nc2;
    +    v[i] =  (float)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:
    +    // 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;
    +        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;
    @@ -116,25 +123,25 @@ void Quat::toAxisAngleRotation(
     
         // Reduce the range of the angle.
     
    -    if (angle < 0) {		
    -		angle = -angle;
    -		axis = -axis;
    +    if (angle < 0) {        
    +        angle = -angle;
    +        axis = -axis;
         }
     
    -	while (angle > twoPi()) {
    +    while (angle > twoPi()) {
             angle -= twoPi();
         }
     
    -	if (abs(angle) > pi()) {
    -		angle -= twoPi();
    +    if (abs(angle) > pi()) {
    +        angle -= twoPi();
         }
     
         // Make the angle positive.
     
    -	if (angle < 0.0f) {		
    -		angle = -angle;
    +    if (angle < 0.0f) {        
    +        angle = -angle;
             axis = -axis;
    -	}
    +    }
     }
     
     
    @@ -153,58 +160,71 @@ void Quat::toRotationMatrix(
         rot = Matrix3(*this);
     }
     
    -    
    -Quat Quat::slerp(
    -    const Quat&         _quat1,
    +
    +Quat Quat::slerp
    +   (const Quat&         _quat1,
         float               alpha,
    -    float               threshold) const {
    +    float               threshold,
    +    float               maxAngle) const {
     
         // From: Game Physics -- David Eberly pg 538-540
         // Modified to include lerp for small angles, which
    -	// is a common practice.
    +    // is a common practice.
     
    -	// See also:
    -	// http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/index.html
    +    // 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);
    +    float halfPhi;
    +    float cosHalfPhi = quat0.dot(quat1);
     
     
    -    if (cosphi < 0) {
    +    if (cosHalfPhi < 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;
    +        cosHalfPhi = -cosHalfPhi;
         }
     
         // Using G3D::aCos will clamp the angle to 0 and pi
    -    phi = static_cast(G3D::aCos(cosphi));
    +    halfPhi = static_cast(G3D::aCos(cosHalfPhi));
         
    -    if (phi >= threshold) {
    +    debugAssertM(halfPhi >= 0.0f, "Assumed acos returned a value >= 0");
    +    if (halfPhi * 2.0f * alpha > maxAngle) {
    +        // Back off alpha        
    +        alpha = maxAngle * 0.5f / halfPhi;
    +    }
    +
    +    if (halfPhi >= threshold) {
             // For large angles, slerp
             float scale0, scale1;
     
    -        scale0 = sin((1.0f - alpha) * phi);
    -        scale1 = sin(alpha * phi);
    +        scale0 = sin((1.0f - alpha) * halfPhi);
    +        scale1 = sin(alpha * halfPhi);
             
    -        return ( (quat0 * scale0) + (quat1 * scale1) ) / sin(phi);
    +        return ( (quat0 * scale0) + (quat1 * scale1) ) / sin(halfPhi);
         } else {
             // For small angles, linear interpolate
    -		return quat0.nlerp(quat1, alpha);
    +        return quat0.nlerp(quat1, alpha);
         }
     }
     
     
    -Quat Quat::nlerp(
    -    const Quat&         quat1,
    +float Quat::angleBetween(const Quat& other) const {
    +    const float d = this->dot(other);
    +    return 2.0f * acos(fabsf(d));
    +}
    +
    +
    +Quat Quat::nlerp
    +   (const Quat&         quat1,
         float               alpha) const {
     
         Quat result = (*this) * (1.0f - alpha) + quat1 * alpha;
    -	return result / result.magnitude();
    +    return result / result.magnitude();
     }
     
     
    diff --git a/deps/g3dlite/source/Random.cpp b/deps/g3dlite/source/Random.cpp
    index 2dda744a1..cbfa07dec 100644
    --- a/deps/g3dlite/source/Random.cpp
    +++ b/deps/g3dlite/source/Random.cpp
    @@ -1,12 +1,12 @@
     /**
    - @file Random.cpp
    + \file Random.cpp
      
    - @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    + \maintainer Morgan McGuire, http://graphics.cs.williams.edu
      
    - @created 2009-01-02
    - @edited  2009-03-29
    + \created 2009-01-02
    + \edited  2012-03-29
     
    - Copyright 2000-2009, Morgan McGuire.
    + Copyright 2000-2012, Morgan McGuire.
      All rights reserved.
      */
     #include "G3D/Random.h"
    @@ -18,15 +18,23 @@ Random& Random::common() {
         return r;
     }
     
    +
     Random::Random(void* x) : state(NULL), m_threadsafe(false) {
         (void)x;
     }
     
     
     Random::Random(uint32 seed, bool threadsafe) : m_threadsafe(threadsafe) {
    +    state = new uint32[N];
    +    reset(seed, threadsafe);
    +}
    +
    +
    +void Random::reset(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;
    @@ -115,6 +123,7 @@ void Random::generate() {
     
         
     int Random::integer(int low, int high) {
    +    debugAssert(high >= low);
         int r = iFloor(low + (high - low + 1) * (double)bits() / 0xFFFFFFFFUL);
     
         // There is a *very small* chance of generating
    @@ -147,6 +156,15 @@ float Random::gaussian(float mean, float stdev) {
     }
     
     
    +void Random::cosSphere(float& x, float& y, float& z) {
    +    cosHemi(x, y, z);
    +    if (bits() & 1) {
    +        // Choose the axis direction uniformly at random
    +        z = -z;
    +    }
    +}
    +
    +
     void Random::cosHemi(float& x, float& y, float& z) {
         const float e1 = uniform();
         const float e2 = uniform();
    diff --git a/deps/g3dlite/source/Ray.cpp b/deps/g3dlite/source/Ray.cpp
    index 0436ef0b3..8a8cf77c5 100644
    --- a/deps/g3dlite/source/Ray.cpp
    +++ b/deps/g3dlite/source/Ray.cpp
    @@ -16,127 +16,128 @@
     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;
    -					}
    -				}
    -			}			
    -		}
    -	}
    +    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);
    +    deserialize(b);
     }
     
     
     void Ray::serialize(class BinaryOutput& b) const {
    -	m_origin.serialize(b);
    -	m_direction.serialize(b);
    +    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);
    +    m_origin.deserialize(b);
    +    m_direction.deserialize(b);
    +    set(m_origin, m_direction);
     }
     
     
    diff --git a/deps/g3dlite/source/Rect2D.cpp b/deps/g3dlite/source/Rect2D.cpp
    index e4148315a..3aea02f51 100644
    --- a/deps/g3dlite/source/Rect2D.cpp
    +++ b/deps/g3dlite/source/Rect2D.cpp
    @@ -4,9 +4,9 @@
      @maintainer Morgan McGuire, http://graphics.cs.williams.edu
       
       @created 2003-11-13
    -  @created 2009-11-16
    +  @created 2011-06-16
     
    -  Copyright 2000-2009, Morgan McGuire.
    +  Copyright 2000-2012, Morgan McGuire.
       All rights reserved.
      */
     
    @@ -14,28 +14,56 @@
     #include "G3D/Rect2D.h"
     #include "G3D/Any.h"
     #include "G3D/stringutils.h"
    +#include "G3D/BinaryInput.h"
    +#include "G3D/BinaryOutput.h"
     
     namespace G3D {
     
    +const Rect2D& Rect2D::empty() {
    +    static Rect2D r;
    +    return r;
    +}
    +
    +
    +void Rect2D::serialize(class BinaryOutput& b) const {
    +    min.serialize(b);
    +    max.serialize(b);
    +}
    +
    +    
    +void Rect2D::deserialize(class BinaryInput& b) {
    +    min.deserialize(b);
    +    max.deserialize(b);
    +}
    +
    +
     /** \param any Must either Rect2D::xywh(#, #, #, #) or Rect2D::xyxy(#, #, #, #)*/
     Rect2D::Rect2D(const Any& any) {
    -    any.verifyName("Rect2D");
    +    if (any.name() == "Rect2D::empty" || any.name() == "AABox2D::empty") {
    +        *this = empty();
    +        return;
    +    }
    +
    +    any.verifyName("Rect2D::xyxy", "Rect2D::xywh");
         any.verifyType(Any::ARRAY);
         any.verifySize(4);
    -    if (toUpper(any.name()) == "RECT2D::XYWH") {
    +    if (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;
    +Any Rect2D::toAny() const {
    +    if (isEmpty()) {
    +        return Any(Any::ARRAY, "Rect2D::empty");
    +    } else {
    +        Any any(Any::ARRAY, "Rect2D::xywh");
    +        any.append(Any(x0()), Any(y0()), Any(width()), Any(height()));
    +        return any;
    +    }
     }
     
     }
    diff --git a/deps/g3dlite/source/RegistryUtil.cpp b/deps/g3dlite/source/RegistryUtil.cpp
    index 7c9e56f79..72c312120 100644
    --- a/deps/g3dlite/source/RegistryUtil.cpp
    +++ b/deps/g3dlite/source/RegistryUtil.cpp
    @@ -11,7 +11,7 @@
     #include "G3D/platform.h"
     
     // This file is only used on Windows
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     
     #include "G3D/RegistryUtil.h"
     #include "G3D/System.h"
    @@ -24,7 +24,6 @@
     #    define HKEY_PERFORMANCE_NLSTEXT ((HKEY)((LONG)0x80000060))
     #  endif
     #endif
    -
     namespace G3D {
     
     // static helpers
    @@ -256,7 +255,8 @@ bool RegistryUtil::writeString(const std::string& key, const std::string& value,
         debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
     
         if (result == ERROR_SUCCESS) {
    -        result = RegSetValueExA(openKey, value.c_str(), 0, REG_SZ, reinterpret_cast(data.c_str()), (data.size() + 1));                
    +        alwaysAssertM(data.size() < 0xFFFFFFFE, "String too long");
    +        result = RegSetValueExA(openKey, value.c_str(), 0, REG_SZ, reinterpret_cast(data.c_str()), (int)(data.size() + 1));                
             debugAssertM(result == ERROR_SUCCESS, "Could not write registry key value.");
     
             RegCloseKey(openKey);
    @@ -296,4 +296,4 @@ static HKEY getRootKeyFromString(const char* str, size_t length) {
     
     } // namespace G3D
     
    -#endif // G3D_WIN32
    +#endif // G3D_WINDOWS
    diff --git a/deps/g3dlite/source/Sphere.cpp b/deps/g3dlite/source/Sphere.cpp
    index 4ed0811cb..5c2eb91cd 100644
    --- a/deps/g3dlite/source/Sphere.cpp
    +++ b/deps/g3dlite/source/Sphere.cpp
    @@ -1,12 +1,12 @@
     /**
    - @file Sphere.cpp
    +   \file G3D.lib/source/Sphere.cpp
      
      Sphere class
      
    - @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    + \maintainer Morgan McGuire, http://graphics.cs.williams.edu
      
    - @created 2001-04-17
    - @edited  2009-01-20
    + \created 2001-04-17
    + \edited  2011-02-10
      */
     
     #include "G3D/platform.h"
    @@ -16,11 +16,37 @@
     #include "G3D/BinaryInput.h"
     #include "G3D/AABox.h"
     #include "G3D/Plane.h"
    +#include "G3D/Any.h"
     
     namespace G3D {
     
     int32 Sphere::dummy;
     
    +Sphere::Sphere(const Any& a) : radius(0) {
    +    a.verifyName("Sphere");
    +    a.verifyType(Any::ARRAY);
    +    if (a.size() == 1) {
    +        radius = a[0];
    +    } else if (a.size() == 2) {
    +        center = a[0];
    +        radius = a[1];
    +    } else {
    +        a.verify(false, "Sphere must recieve exactly 1 or two arguments.");
    +    }
    +}
    +
    +
    +Any Sphere::toAny() const {
    +    Any a(Any::ARRAY, "Sphere");
    +    if (center != Point3::zero()) {
    +        a.append(center);
    +    }
    +
    +    a.append(radius);
    +    return a;
    +}
    +
    +
     Sphere::Sphere(class BinaryInput& b) {
         deserialize(b);
     }
    @@ -38,6 +64,12 @@ void Sphere::deserialize(class BinaryInput& b) {
     }
     
     
    +const Sphere& Sphere::inf() {
    +    static const Sphere s(Point3::zero(), finf());
    +    return s;
    +}
    +
    +
     std::string Sphere::toString() const {
         return format("Sphere(<%g, %g, %g>, %g)", 
                       center.x, center.y, center.z, radius);
    @@ -82,19 +114,19 @@ void Sphere::merge(const Sphere& other) {
     
     
     bool Sphere::culledBy(
    -    const Array&		plane,
    -    int&				    cullingPlaneIndex,
    -    const uint32			inMask,
    -    uint32&					outMask) const {
    +    const Array&        plane,
    +    int&                    cullingPlaneIndex,
    +    const uint32            inMask,
    +    uint32&                    outMask) const {
         
         return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask, outMask);
     }
         
     
     bool Sphere::culledBy(
    -                      const Array&		plane,
    -                      int&				    cullingPlaneIndex,
    -                      const uint32			inMask) const {
    +                      const Array&        plane,
    +                      int&                    cullingPlaneIndex,
    +                      const uint32            inMask) const {
         
         return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask);
     }
    @@ -103,8 +135,8 @@ bool Sphere::culledBy(
     bool Sphere::culledBy(
         const class Plane*  plane,
         int                 numPlanes,
    -    int&				cullingPlane,
    -    const uint32		_inMask,
    +    int&                cullingPlane,
    +    const uint32        _inMask,
         uint32&             childMask) const {
     
         if (radius == finf()) {
    @@ -112,45 +144,45 @@ bool Sphere::culledBy(
             return false;
         }
     
    -	uint32 inMask = _inMask;
    -	assert(numPlanes < 31);
    +    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++) {
    +    // 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) {
    -		
    +        // 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;
    +            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;
    +                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;
    +        inMask = inMask >> 1;
         }
     
         // None of the planes could cull this box
    -	cullingPlane = -1;
    +    cullingPlane = -1;
         return false;
     }
     
    @@ -158,32 +190,34 @@ bool Sphere::culledBy(
     bool Sphere::culledBy(
         const class Plane*  plane,
         int                 numPlanes,
    -	int&				cullingPlane,
    -	const uint32		_inMask) const {
    +    int&                cullingPlane,
    +    const uint32        _inMask) const {
    +    // Don't cull if the sphere has infinite radius
    +    if(!isFinite(radius)) return false;
     
    -	uint32 inMask = _inMask;
    -	assert(numPlanes < 31);
    +    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++) {
    +    // 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;
    +        // 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;
    +        inMask = inMask >> 1;
         }
     
         // None of the planes could cull this box
    -	cullingPlane = -1;
    +    cullingPlane = -1;
         return false;
     }
     
    diff --git a/deps/g3dlite/source/SplineBase.cpp b/deps/g3dlite/source/SplineBase.cpp
    index 41221624b..5904e9a1a 100644
    --- a/deps/g3dlite/source/SplineBase.cpp
    +++ b/deps/g3dlite/source/SplineBase.cpp
    @@ -4,7 +4,7 @@
     namespace G3D {
     
     float SplineBase::getFinalInterval() const {
    -    if (! cyclic) {
    +    if (extrapolationMode != SplineExtrapolationMode::CYCLIC) {
             return 0;
         } else if (finalInterval <= 0) {
             int N = time.size();
    @@ -97,7 +97,7 @@ void SplineBase::computeIndex(float s, int& i, float& u) const {
             // No control points to work with
             i = 0;
             u = 0.0;
    -    } else if (cyclic) {
    +    } else if (extrapolationMode == SplineExtrapolationMode::CYCLIC) {
             float fi = getFinalInterval();
             
             // Cyclic spline
    @@ -156,7 +156,7 @@ void SplineBase::computeIndex(float s, int& i, float& u) const {
                 computeIndexInBounds(s, i, u);
                 
             } // if in bounds
    -    } // if cyclic
    +    } // extrapolation Mode
     }
     
     }
    diff --git a/deps/g3dlite/source/Stopwatch.cpp b/deps/g3dlite/source/Stopwatch.cpp
    index 9b785d502..713835ea7 100644
    --- a/deps/g3dlite/source/Stopwatch.cpp
    +++ b/deps/g3dlite/source/Stopwatch.cpp
    @@ -105,15 +105,16 @@ void Stopwatch::reset() {
     
     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);
    +    if (m_enabled) {
    +        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;
     }
     
     }
    -
    diff --git a/deps/g3dlite/source/System.cpp b/deps/g3dlite/source/System.cpp
    index 281104d39..4a75d320b 100644
    --- a/deps/g3dlite/source/System.cpp
    +++ b/deps/g3dlite/source/System.cpp
    @@ -1,7 +1,7 @@
     /** 
    -  @file System.cpp
    +  \file System.cpp
      
    -  @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    +  \maintainer Morgan McGuire, http://graphics.cs.williams.edu
     
       Note: every routine must call init() first.
     
    @@ -10,8 +10,8 @@
       can be used at all.  At runtime, processor detection is used to
       determine if we can safely call the routines that use that assembly.
     
    -  @created 2003-01-25
    -  @edited  2010-01-03
    +  \created 2003-01-25
    +  \edited  2012-01-05
      */
     
     #include "G3D/platform.h"
    @@ -37,17 +37,15 @@
     // allocation and use the operating system's malloc.
     //#define NO_BUFFERPOOL
     
    -#if defined(__i386__) || defined(__x86_64__) || defined(G3D_WIN32)
    -#    define G3D_NOT_OSX_PPC
    -#endif
    -
     #include 
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     
     #   include 
     #   include 
     #   include "G3D/RegistryUtil.h"
    +#include 
    +#include 
     
     #elif defined(G3D_LINUX) 
     
    @@ -81,13 +79,12 @@
     #endif
     
     // SIMM include
    -#ifdef __SSE__
    +#if !defined(__aarch64__)
     #include 
     #endif
     
     namespace G3D {
    -
    -
    +    
     /** Checks if the CPUID command is available on the processor (called from init) */
     static bool checkForCPUID();
     
    @@ -173,10 +170,6 @@ void System::init() {
                 m_cpuArch = "AMD Processor";
                 break;
     
    -        case 0x69727943:        // CyrixInstead
    -            m_cpuArch = "Cyrix Processor";
    -            break;
    -
             default:
                 m_cpuArch = "Unknown Processor Vendor";
                 break;
    @@ -195,43 +188,40 @@ void System::init() {
     
     
         // Get the operating system name (also happens to read some other information)
    -#    ifdef G3D_WIN32
    +#    ifdef G3D_WINDOWS
    +	    HRESULT r = OleInitialize(NULL);
             // Note that this overrides some of the values computed above
             bool success = RegistryUtil::readInt32
                 ("HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 
                  "~MHz", m_cpuSpeed);
    -
    +        HRESULT s = OleInitialize(NULL);
             SYSTEM_INFO systemInfo;
             GetSystemInfo(&systemInfo);
             const char* arch = NULL;
             switch (systemInfo.wProcessorArchitecture) {
             case PROCESSOR_ARCHITECTURE_INTEL:
    -            arch = "Intel";
    +            arch = "x86 Intel";
                 break;
         
    -        case PROCESSOR_ARCHITECTURE_MIPS:
    -            arch = "MIPS";
    -            break;
    +		case PROCESSOR_ARCHITECTURE_AMD64:
    +			arch = "x64 Intel/AMD";
    +			break;
     
    -        case PROCESSOR_ARCHITECTURE_ALPHA:
    -            arch = "Alpha";
    -            break;
    -
    -        case PROCESSOR_ARCHITECTURE_PPC:
    -            arch = "Power PC";
    -            break;
    +		case PROCESSOR_ARCHITECTURE_ARM:
    +			arch = "ARM";
    +			break;
     
             default:
                 arch = "Unknown";
    +			break;
             }
     
             m_numCores = systemInfo.dwNumberOfProcessors;
    -        uint32 maxAddr = (uint32)systemInfo.lpMaximumApplicationAddress;
    +        uint64_t maxAddr = reinterpret_cast(systemInfo.lpMaximumApplicationAddress);
             {
                 char c[1024];
    -            sprintf(c, "%d x %d-bit %s processor",
    +            sprintf(c, "%d - %s cores",
                         systemInfo.dwNumberOfProcessors,
    -                    (int)(::log((double)maxAddr) / ::log(2.0) + 2.0),
                         arch);
                 m_cpuArch = c;
             }
    @@ -261,12 +251,13 @@ void System::init() {
     
                 int len = 100;
                 char* r = (char*)::malloc(len * sizeof(char));
    -            fgets(r, len, f);
    +            (void)fgets(r, len, f);
                 // Remove trailing newline
                 if (r[strlen(r) - 1] == '\n') {
                     r[strlen(r) - 1] = '\0';
                 }
                 fclose(f);
    +            f = NULL;
     
                 m_operatingSystem = r;
                 ::free(r);
    @@ -294,72 +285,103 @@ void System::init() {
             m_secondsPerNS = 1.0 / 1.0e9;
             
             // System Architecture:
    -	const NXArchInfo* pInfo = NXGetLocalArchInfo();
    -		
    -	if (pInfo) {
    -	    m_cpuArch = pInfo->description;
    -			
    -	    switch (pInfo->cputype) {
    -	    case CPU_TYPE_POWERPC:
    -	        switch(pInfo->cpusubtype){
    -		case CPU_SUBTYPE_POWERPC_750:
    -		case CPU_SUBTYPE_POWERPC_7400:
    -		case CPU_SUBTYPE_POWERPC_7450:
    -		    m_cpuVendor = "Motorola";
    -		    break;
    -		case CPU_SUBTYPE_POWERPC_970:
    -		    m_cpuVendor = "IBM";
    -		    break;
    -		}
    -		break;
    -	    
    +    const NXArchInfo* pInfo = NXGetLocalArchInfo();
    +        
    +    if (pInfo) {
    +        m_cpuArch = pInfo->description;
    +            
    +        switch (pInfo->cputype) {
    +        case CPU_TYPE_POWERPC:
    +            switch(pInfo->cpusubtype){
    +        case CPU_SUBTYPE_POWERPC_750:
    +        case CPU_SUBTYPE_POWERPC_7400:
    +        case CPU_SUBTYPE_POWERPC_7450:
    +            m_cpuVendor = "Motorola";
    +            break;
    +        case CPU_SUBTYPE_POWERPC_970:
    +            m_cpuVendor = "IBM";
    +            break;
    +        }
    +        break;
    +        
                 case CPU_TYPE_I386:
                     m_cpuVendor = "Intel";
                     break;
    -	    }
    -	}
    +        }
    +    }
     #   endif
     
         initTime();
     
         getStandardProcessorExtensions();
    +
    +    m_appDataDir = FilePath::parent(System::currentProgramFilename());
     }
     
     
     void getG3DVersion(std::string& s) {
    +
    +    const char* build = 
    +#       ifdef G3D_64BIT
    +            "64-bit";
    +#       else
    +            "32-bit";
    +#       endif
    +
    +    const char* debug =
    +#       ifdef G3D_DEBUG
    +            " (Debug)";
    +#       else
    +            "";
    +#       endif
    +
         char cstr[100];
         if ((G3D_VER % 100) != 0) {
    -        sprintf(cstr, "G3D %d.%02d beta %d",
    +        sprintf(cstr, "G3D Innovation Engine %d.%02d beta %d, %s%s",
                     G3D_VER / 10000,
                     (G3D_VER / 100) % 100,
    -                G3D_VER % 100);
    +                G3D_VER % 100,
    +                build,
    +                debug);
         } else {
    -        sprintf(cstr, "G3D %d.%02d",
    +        sprintf(cstr, "G3D Innovation Engine %d.%02d, %s%s",
                     G3D_VER / 10000,
    -                (G3D_VER / 100) % 100);
    +                (G3D_VER / 100) % 100,
    +                build,
    +                debug);
         }
    +
         s = cstr;
     }
     
    +// Places where specific files were most recently found.  This is
    +// used to cache seeking of common files.
    +static Table lastFound;
     
    +// Places to look in findDataFile
    +static Array directoryArray;
    +
    +#define MARK_LOG()
    +//#define MARK_LOG() logPrintf("%s(%d)\n", __FILE__, __LINE__)
     std::string System::findDataFile
    -(const std::string&  full,
    - bool                errorIfNotFound) {
    +(const std::string&  _full,
    + bool                errorIfNotFound,
    + bool                caseSensitive) {
    +MARK_LOG();
     
    -    // Places where specific files were most recently found.  This is
    -    // used to cache seeking of common files.
    -    static Table lastFound;
    +    const std::string full = FilePath::expandEnvironmentVariables(_full);
     
         // First check if the file exists as requested.  This will go
         // through the FileSystemCache, so most calls do not touch disk.
    -    if (FileSystem::exists(full)) {
    +    if (FileSystem::exists(full, true, caseSensitive)) {
             return full;
         }
     
    +MARK_LOG();
         // Now check where we previously found this file.
         std::string* last = lastFound.getPointer(full);
         if (last != NULL) {
    -        if (FileSystem::exists(*last)) {
    +        if (FileSystem::exists(*last, true, caseSensitive)) {
                 // Even if cwd has changed the file is still present.
                 // We won't notice if it has been deleted, however.
                 return *last;
    @@ -369,11 +391,10 @@ std::string System::findDataFile
             }
         }
     
    -    // Places to look
    -    static Array directoryArray;
    +MARK_LOG();
     
    -    std::string initialAppDataDir(instance().m_appDataDir);
    -    const char* g3dPath = getenv("G3DDATA");
    +    const std::string initialAppDataDir(instance().m_appDataDir);
    +    const char* g3dPath = getenv("G3D9DATA");
     
         if (directoryArray.size() == 0) {
             // Initialize the directory array
    @@ -381,18 +402,27 @@ std::string System::findDataFile
     
             Array baseDirArray;
             
    -        baseDirArray.append("");
    +        baseDirArray.append(FileSystem::currentDirectory());
    +MARK_LOG();
             if (! initialAppDataDir.empty()) {
    +MARK_LOG();
                 baseDirArray.append(initialAppDataDir);
    +            baseDirArray.append(pathConcat(initialAppDataDir, "data"));
    +            baseDirArray.append(pathConcat(initialAppDataDir, "data.zip"));
    +        } else {
    +MARK_LOG();
    +            baseDirArray.append("data");
    +            baseDirArray.append("data.zip");
             }
    +MARK_LOG();
     
    -#       ifdef G3D_WIN32
    +#       ifdef G3D_WINDOWS
             if (g3dPath == NULL) {
                 // If running the demos under visual studio from the G3D.sln file,
                 // this will locate the data directory.
                 const char* paths[] = {"../data-files/", "../../data-files/", "../../../data-files/", NULL};
                 for (int i = 0; paths[i]; ++i) {
    -                if (FileSystem::exists(pathConcat(paths[i], "G3D-DATA-README.TXT"))) {
    +                if (FileSystem::exists(pathConcat(paths[i], "G3D-DATA-README.TXT"), true, caseSensitive)) {
                         g3dPath = paths[i];
                         break;
                     }
    @@ -405,96 +435,91 @@ std::string System::findDataFile
             }
     
             static const std::string subdirs[] = 
    -            {"font", "gui", "SuperShader", "cubemap", "icon", "material", "image", "md2", "md3", "ifs", "3ds", "sky", ""};
    +            {"font", "gui", "shader", "model", "cubemap", "icon", "material", "image", "md2", "md3", "ifs", "3ds", "sky", "music", "sound", "scene", ""};
             for (int j = 0; j < baseDirArray.size(); ++j) {
                 std::string d = baseDirArray[j];
    +//logPrintf("%s", d.c_str());
                 if ((d == "") || FileSystem::exists(d)) {
    +//logPrintf(" exists\n");
                     directoryArray.append(d);
                     for (int i = 0; ! subdirs[i].empty(); ++i) {
                         const std::string& p = pathConcat(d, subdirs[i]);
    -                    if (FileSystem::exists(p)) {
    +                    if (FileSystem::exists(p, true, caseSensitive)) {
                             directoryArray.append(p);
                         }
                     }
    +            } else {
    +//logPrintf(" does not exist\n");
                 }
             }
     
             logLazyPrintf("Initializing System::findDataFile took %fs\n", System::time() - t0);
    +
         }
    +MARK_LOG();
     
         for (int i = 0; i < directoryArray.size(); ++i) {
             const std::string& p = pathConcat(directoryArray[i], full);
    -        if (FileSystem::exists(p)) {
    +        if (FileSystem::exists(p, true, caseSensitive)) {
                 lastFound.set(full, p);
                 return p;
             }
         }
    +MARK_LOG();
     
         if (errorIfNotFound) {
    -        // Generate an error message
    +        // Generate an error message.  Delay this operation until we know that we need it;
    +        // otherwise all of the string concatenation would run on each successful find.
             std::string locations;
             for (int i = 0; i < directoryArray.size(); ++i) {
                 locations += "\'" + pathConcat(directoryArray[i], full) + "'\n";
             }
    +MARK_LOG();
     
             std::string msg = "Could not find '" + full + "'.\n\n";
    -        msg += "cwd = \'" + FileSystem::currentDirectory() + "\'\n";
    +        msg +=     "  cwd                    = '" + FileSystem::currentDirectory() + "'\n";
             if (g3dPath) {
    -            msg += "G3DDATA = ";
    -            if (! FileSystem::exists(g3dPath)) {
    -                msg += "(illegal path!) ";
    +            msg += "  G3D9DATA               = '" + std::string(g3dPath) + "'";
    +            if (! FileSystem::exists(g3dPath, true, caseSensitive)) {
    +                msg += " (illegal path!)";
                 }
    -            msg += std::string(g3dPath) + "\'\n";
    +            msg += "\n";
             } else {
    -            msg += "(G3DDATA environment variable is undefined)\n";
    +            msg += "  G3D9DATA               = (environment variable is not defined)\n";
             }
    -        msg += "GApp::Settings.dataDir = ";
    -        if (! FileSystem::exists(initialAppDataDir)) {
    -            msg += "(illegal path!) ";
    +MARK_LOG();
    +        msg +=     "  GApp::Settings.dataDir = '" + initialAppDataDir + "'";
    +        if (! FileSystem::exists(initialAppDataDir, true, caseSensitive)) {
    +            msg += " (illegal path!)";
             }
    -        msg += std::string(initialAppDataDir) + "\'\n";
    +        msg += "\n";
     
    -        msg += "\nLocations searched:\n" + locations;
    +        msg += "\nFilenames tested:\n" + locations;
     
    +MARK_LOG();
    +logPrintf("%s\n", msg.c_str());
    +        throw FileNotFound(full, msg);
             alwaysAssertM(false, msg);
         }
    +MARK_LOG();
     
         // Not found
         return "";
     }
    -
    +#undef MARK_LOG
     
     void System::setAppDataDir(const std::string& path) {
         instance().m_appDataDir = path;
    +
    +    // Wipe the findDataFile cache
    +    lastFound.clear();
    +    directoryArray.clear();
     }
     
     
    -std::string demoFindData(bool errorIfNotFound) {
    -    static const char* g3dPath = getenv("G3DDATA");
    -    if (g3dPath) {
    -        return g3dPath;
    -#   ifdef G3D_WIN32
    -    } else if (FileSystem::exists("../data")) {
    -        // G3D install on Windows
    -        return "../data";
    -    } else if (FileSystem::exists("../data-files")) {
    -        // G3D source on Windows
    -        return "../data-files";
    -    } else if (FileSystem::exists("c:/libraries/G3D/data")) {
    -        return "c:/libraries/G3D/data";
    -#   else
    -    } else if (FileSystem::exists("../../../../data")) {
    -        // G3D install on Unix
    -        return "../../../../data";
    -    } else if (FileSystem::exists("../../../../data-files")) {
    -        // G3D source on Unix
    -        return "../../../../data-files";
    -    } else if (FileSystem::exists("/usr/local/G3D/data")) {
    -        return "/usr/local/G3D/data";
    -#   endif
    -    } else {
    -        return "";
    -    }
    +void System::cleanup() {
    +    lastFound.clear();
    +    directoryArray.clear();
     }
     
     
    @@ -564,12 +589,15 @@ void System::getStandardProcessorExtensions() {
     #endif
     }
     
    -#if defined(G3D_WIN32) && !defined(G3D_64BIT) && !defined(__MINGW32__) /* G3DFIX: Don't check if on 64-bit Windows platforms or using MinGW */
    -    #pragma message("Port System::memcpy SIMD to all platforms")
    -/** Michael Herf's fast memcpy */
    +#if defined(G3D_WINDOWS) && defined(_M_IX86) && !defined(__MINGW32__) /* G3DFIX: Don't check if on 64-bit Windows platforms or using MinGW */
    +// 32-bit
    +/** Michael Herf's fast memcpy.  Assumes 16-byte alignment */
     void memcpyMMX(void* dst, const void* src, int nbytes) {
         int remainingBytes = nbytes;
     
    +    alwaysAssertM((int)dst % 16 == 0, format("Must be on 16-byte boundary.  dst = 0x%x", dst));
    +    alwaysAssertM((int)src % 16 == 0, format("Must be on 16-byte boundary.  src = 0x%x", src));
    +
         if (nbytes > 64) {
             _asm {
                 mov esi, src 
    @@ -615,8 +643,13 @@ void memcpyMMX(void* dst, const void* src, int nbytes) {
     #endif
     
     void System::memcpy(void* dst, const void* src, size_t numBytes) {
    -#if defined(G3D_WIN32) && !defined(G3D_64BIT) && !defined(__MINGW32__) /* G3DFIX: Don't check if on 64-bit Windows platforms or using MinGW */
    -    memcpyMMX(dst, src, numBytes);
    +#if defined(G3D_WINDOWS) && defined(_M_IX86) && !defined(__MINGW32__) /* G3DFIX: Don't check if on 64-bit Windows platforms or using MinGW */
    +    // The overhead of our memcpy seems to only be worthwhile on large arrays
    +    if (((size_t)dst % 16 == 0) && ((size_t)src % 16 == 0) && (numBytes > 3400000)) {
    +        memcpyMMX(dst, src, numBytes);
    +    } else {
    +        ::memcpy(dst, src, numBytes);
    +    }
     #else
         ::memcpy(dst, src, numBytes);
     #endif
    @@ -625,9 +658,7 @@ void System::memcpy(void* dst, const void* src, size_t numBytes) {
     
     /** Michael Herf's fastest memset. n32 must be filled with the same
         character repeated. */
    -#if defined(G3D_WIN32) && !defined(G3D_64BIT) && !defined(__MINGW32__) /* G3DFIX: Don't check if on 64-bit Windows platforms or using MinGW */
    -    #pragma message("Port System::memfill SIMD to all platforms")
    -
    +#if defined(G3D_WINDOWS) && defined(_M_IX86) && !defined(__MINGW32__) /* G3DFIX: Don't check if on 64-bit Windows platforms or using MinGW */
     // On x86 processors, use MMX
     void memfill(void *dst, int n32, unsigned long i) {
     
    @@ -664,10 +695,15 @@ void memfill(void *dst, int n32, unsigned long i) {
     
     
     void System::memset(void* dst, uint8 value, size_t numBytes) {
    -#if defined(G3D_WIN32) && !defined(G3D_64BIT) && !defined(__MINGW32__) /* G3DFIX: Don't check if on 64-bit Windows platforms or using MinGW */
    -    uint32 v = value;
    -    v = v + (v << 8) + (v << 16) + (v << 24); 
    -    G3D::memfill(dst, v, numBytes);
    +    alwaysAssertM(dst != NULL, "Cannot memset NULL address.");
    +#if defined(G3D_WINDOWS) && defined(_M_IX86) && !defined(__MINGW32__) /* G3DFIX: Don't check if on 64-bit Windows platforms or using MinGW */
    +    if ((((size_t)dst % 16) == 0) && (numBytes >= 512*1024)) {
    +        uint32 v = value;
    +        v = v + (v << 8) + (v << 16) + (v << 24); 
    +        G3D::memfill(dst, v, numBytes);
    +    } else {
    +        ::memset(dst, value, numBytes);
    +    }
     #else
         ::memset(dst, value, numBytes);
     #endif
    @@ -683,7 +719,7 @@ static std::string computeAppName(const std::string& start) {
         if (start[start.size() - 1] == 'd') {
             // Maybe remove the 'd'; see if ../ or ../../ has the same name
             char tmp[1024];
    -        getcwd(tmp, sizeof(tmp));
    +        (void)getcwd(tmp, sizeof(tmp));
             std::string drive, base, ext;
             Array path;
             parseFilename(tmp, drive, path, base, ext);
    @@ -712,7 +748,7 @@ std::string& System::appName() {
     std::string System::currentProgramFilename() {
         char filename[2048];
     
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
         {
             GetModuleFileNameA(NULL, filename, sizeof(filename));
         } 
    @@ -730,6 +766,7 @@ std::string System::currentProgramFilename() {
             int s = fread(filename, 1, sizeof(filename), fd);
             // filename will contain a newline.  Overwrite it:
             filename[s - 1] = '\0';
    +        pclose(fd);
         }
     #   else
         {
    @@ -784,7 +821,7 @@ void System::sleep(RealTime t) {
             }
     
             if (sleepTime >= 0) {
    -            #ifdef G3D_WIN32
    +            #ifdef G3D_WINDOWS
                     // Translate to milliseconds
                     Sleep((int)(sleepTime * 1e3));
                 #else
    @@ -800,16 +837,16 @@ void System::sleep(RealTime t) {
     
     
     void System::consoleClearScreen() {
    -#   ifdef G3D_WIN32
    -        system("cls");
    +#   ifdef G3D_WINDOWS
    +        (void)system("cls");
     #   else
    -        system("clear");
    +        (void)system("clear");
     #   endif
     }
     
     
     bool System::consoleKeyPressed() {
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
         
             return _kbhit() != 0;
     
    @@ -851,18 +888,18 @@ bool System::consoleKeyPressed() {
     
     
     int System::consoleReadKey() {
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
             return _getch();
     #   else
             char c;
    -        read(0, &c, 1);
    +        (void)read(0, &c, 1);
             return c;
     #   endif
     }
     
     
     void System::initTime() {
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
             if (QueryPerformanceFrequency(&m_counterFrequency)) {
                 QueryPerformanceCounter(&m_start);
             }
    @@ -888,11 +925,7 @@ void System::initTime() {
             
             if (localTimeVals) {
                 // tm_gmtoff is already corrected for daylight savings.
    -            #ifdef __CYGWIN__
    -            local = local + _timezone;
    -            #else
                 local = local + localTimeVals->tm_gmtoff;
    -            #endif
             }
             
             m_realWorldGetTickTime0 = local;
    @@ -901,7 +934,7 @@ void System::initTime() {
     
     
     RealTime System::time() { 
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
             LARGE_INTEGER now;
             QueryPerformanceCounter(&now);
     
    @@ -924,12 +957,11 @@ RealTime System::time() {
     
     ////////////////////////////////////////////////////////////////
     
    -
    -#define REALPTR_TO_USERPTR(x)   ((uint8*)(x) + sizeof(uint32))
    -#define USERPTR_TO_REALPTR(x)   ((uint8*)(x) - sizeof(uint32))
    -#define USERSIZE_TO_REALSIZE(x)       ((x) + sizeof(uint32))
    -#define REALSIZE_FROM_USERPTR(u) (*(uint32*)USERPTR_TO_REALPTR(ptr) + sizeof(uint32))
    -#define USERSIZE_FROM_USERPTR(u) (*(uint32*)USERPTR_TO_REALPTR(ptr))
    +#define REALPTR_TO_USERPTR(x)   ((uint8*)(x) + sizeof(size_t))
    +#define USERPTR_TO_REALPTR(x)   ((uint8*)(x) - sizeof(size_t))
    +#define USERSIZE_TO_REALSIZE(x)       ((x) + sizeof(size_t))
    +#define REALSIZE_FROM_USERPTR(u) (*(size_t*)USERPTR_TO_REALPTR(ptr) + sizeof(size_t))
    +#define USERSIZE_FROM_USERPTR(u) (*(size_t*)USERPTR_TO_REALPTR(ptr))
     
     class BufferPool {
     public:
    @@ -942,15 +974,20 @@ public:
             Tiny buffers are 128 bytes long because that seems to align well with
             cache sizes on many machines.
           */
    +#ifdef G3D_64BIT
    +    // 64-bit machines have larger pointers...and probably have more memory as well
    +    enum {tinyBufferSize = 256, smallBufferSize = 2048, medBufferSize = 8192};
    +#else
         enum {tinyBufferSize = 128, smallBufferSize = 1024, medBufferSize = 4096};
    +#endif
     
         /** 
            Most buffers we're allowed to store.
    -       250000 * 128  = 32 MB (preallocated)
    -        10000 * 1024 = 10 MB (allocated on demand)
    -         1024 * 4096 =  4 MB (allocated on demand)
    +       250000 * { 128 |  256} = {32 | 64} MB (preallocated)
    +        40000 * {1024 | 2048} = {40 | 80} MB (allocated on demand)
    +         5000 * {4096 | 8192} = {20 | 40} MB (allocated on demand)
          */
    -    enum {maxTinyBuffers = 250000, maxSmallBuffers = 10000, maxMedBuffers = 1024};
    +    enum {maxTinyBuffers = 250000, maxSmallBuffers = 40000, maxMedBuffers = 5000};
     
     private:
     
    @@ -995,31 +1032,6 @@ private:
             m_lock.unlock();
         }
     
    -#if 0 //-----------------------------------------------old mutex
    -#   ifdef G3D_WIN32
    -    CRITICAL_SECTION    mutex;
    -#   else
    -    pthread_mutex_t     mutex;
    -#   endif
    -
    -    /** Provide synchronization between threads */
    -    void lock() {
    -#       ifdef G3D_WIN32
    -            EnterCriticalSection(&mutex);
    -#       else
    -            pthread_mutex_lock(&mutex);
    -#       endif
    -    }
    -
    -    void unlock() {
    -#       ifdef G3D_WIN32
    -            LeaveCriticalSection(&mutex);
    -#       else
    -            pthread_mutex_unlock(&mutex);
    -#       endif
    -    }
    -#endif //-------------------------------------------old mutex
    -
         /** 
          Malloc out of the tiny heap. Returns NULL if allocation failed.
          */
    @@ -1133,7 +1145,7 @@ public:
             of a buffer.
             Primarily useful for detecting leaks.*/
         // TODO: make me an atomic int!
    -    volatile int bytesAllocated;
    +    volatile size_t bytesAllocated;
     
         BufferPool() {
             totalMallocs         = 0;
    @@ -1142,7 +1154,7 @@ public:
             mallocsFromSmallPool = 0;
             mallocsFromMedPool   = 0;
     
    -        bytesAllocated       = true;
    +        bytesAllocated       = 0;
     
             tinyPoolSize         = 0;
             tinyHeap             = NULL;
    @@ -1161,7 +1173,7 @@ public:
             tinyPoolSize = maxTinyBuffers;
     
     #if 0        ///---------------------------------- old mutex
    -#       ifdef G3D_WIN32
    +#       ifdef G3D_WINDOWS
                 InitializeCriticalSection(&mutex);
     #       else
                 pthread_mutex_init(&mutex, NULL);
    @@ -1175,7 +1187,7 @@ public:
             flushPool(smallPool, smallPoolSize);
             flushPool(medPool, medPoolSize);
     #if 0 //-------------------------------- old mutex
    -#       ifdef G3D_WIN32
    +#       ifdef G3D_WINDOWS
                 DeleteCriticalSection(&mutex);
     #       else
                 // No destruction on pthreads
    @@ -1274,6 +1286,11 @@ public:
             RealPtr ptr = ::malloc(USERSIZE_TO_REALSIZE(bytes));
     
             if (ptr == NULL) {
    +#           ifdef G3D_WINDOWS
    +                // Check for memory corruption
    +                alwaysAssertM(_CrtCheckMemory() == TRUE, "Heap corruption detected.");
    +#           endif
    +
                 // Flush memory pools to try and recover space
                 flushPool(smallPool, smallPoolSize);
                 flushPool(medPool, medPoolSize);
    @@ -1303,7 +1320,7 @@ public:
                 return NULL;
             }
     
    -        *(uint32*)ptr = bytes;
    +        ((size_t*)ptr)[0] = bytes;
     
             return REALPTR_TO_USERPTR(ptr);
         }
    @@ -1324,7 +1341,7 @@ public:
                 return;
             }
     
    -        uint32 bytes = USERSIZE_FROM_USERPTR(ptr);
    +        size_t bytes = USERSIZE_FROM_USERPTR(ptr);
     
             lock();
             if (bytes <= smallBufferSize) {
    @@ -1466,14 +1483,17 @@ void System::free(void* p) {
     
     void* System::alignedMalloc(size_t bytes, size_t alignment) {
     
    -    alwaysAssertM(isPow2(alignment), "alignment must be a power of 2");
    +    alwaysAssertM(isPow2((uint32)alignment), "alignment must be a power of 2");
     
         // We must align to at least a word boundary.
    -    alignment = iMax(alignment, sizeof(void *));
    +    alignment = max(alignment, sizeof(void *));
     
    -    // Pad the allocation size with the alignment size and the
    -    // size of the redirect pointer.
    -    size_t totalBytes = bytes + alignment + sizeof(void*);
    +    // Pad the allocation size with the alignment size and the size of
    +    // the redirect pointer.  This is the worst-case size we'll need.
    +    // Since the alignment size is at least teh word size, we don't
    +    // need to allocate space for the redirect pointer.  We repeat the max here
    +    // for clarity.
    +    size_t totalBytes = bytes + max(alignment, sizeof(void*));
     
         size_t truePtr = (size_t)System::malloc(totalBytes);
     
    @@ -1483,25 +1503,31 @@ void* System::alignedMalloc(size_t bytes, size_t alignment) {
         }
     
         debugAssert(isValidHeapPointer((void*)truePtr));
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
         // The blocks we return will not be valid Win32 debug heap
         // pointers because they are offset 
         //  debugAssert(_CrtIsValidPointer((void*)truePtr, totalBytes, TRUE) );
         #endif
     
    -    // The return pointer will be the next aligned location (we must at least
    -    // leave space for the redirect pointer, however).
    -    size_t  alignedPtr = truePtr + sizeof(void*);
     
    -    // 2^n - 1 has the form 1111... in binary.
    -    uint32 bitMask = (alignment - 1);
    +    // We want alignedPtr % alignment == 0, which we'll compute with a
    +    // binary AND because 2^n - 1 has the form 1111... in binary.
    +    const size_t bitMask = (alignment - 1);
     
    -    // Advance forward until we reach an aligned location.
    -    while ((alignedPtr & bitMask) != 0) {
    -        alignedPtr += sizeof(void*);
    -    }
    +    // The return pointer will be the next aligned location that is at
    +    // least sizeof(void*) after the true pointer. We need the padding
    +    // to have a place to write the redirect pointer.
    +    size_t alignedPtr = truePtr + sizeof(void*);
     
    -    debugAssert(alignedPtr - truePtr + bytes <= totalBytes);
    +    const size_t remainder = alignedPtr & bitMask;
    +    
    +    // Add what we need to make it to the next alignment boundary, but
    +    // if the remainder was zero, let it wrap to zero and don't add
    +    // anything.
    +    alignedPtr += ((alignment - remainder) & bitMask);
    +
    +    debugAssert((alignedPtr & bitMask) == 0);
    +    debugAssert((alignedPtr - truePtr + bytes) <= totalBytes);
     
         // Immediately before the aligned location, write the true array location
         // so that we can free it correctly.
    @@ -1510,8 +1536,10 @@ void* System::alignedMalloc(size_t bytes, size_t alignment) {
     
         debugAssert(isValidHeapPointer((void*)truePtr));
     
    -    #ifdef G3D_WIN32
    -        debugAssert( _CrtIsValidPointer((void*)alignedPtr, bytes, TRUE) );
    +    #if defined(G3D_WINDOWS) && defined(G3D_DEBUG)
    +        if (bytes < 0xFFFFFFFF) { 
    +            debugAssert( _CrtIsValidPointer((void*)alignedPtr, (int)bytes, TRUE) );
    +        }
         #endif
         return (void *)alignedPtr;
     }
    @@ -1539,7 +1567,7 @@ void System::alignedFree(void* _ptr) {
     
     void System::setEnv(const std::string& name, const std::string& value) {
         std::string cmd = name + "=" + value;
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
             _putenv(cmd.c_str());
     #   else
             // Many linux implementations of putenv expect char*
    @@ -1590,7 +1618,7 @@ void System::describeSystem(
         {
             var(t, "Name", System::currentProgramFilename());
             char cwd[1024];
    -        getcwd(cwd, 1024);
    +        (void)getcwd(cwd, 1024);
             var(t, "cwd", std::string(cwd));
         }
         t.popIndent();
    @@ -1633,8 +1661,10 @@ void System::describeSystem(
         t.writeNewline();
         t.pushIndent();
         {
    +        const char* g3dPath = getenv("G3D9DATA");
             var(t, "Link version", G3D_VER);
             var(t, "Compile version", System::version());
    +        var(t, "G3D9DATA", std::string(g3dPath ? g3dPath : ""));
         }
         t.popIndent();
         t.writeSymbols("}");
    @@ -1642,49 +1672,6 @@ void System::describeSystem(
         t.writeNewline();
     }
     
    -
    -void System::setClipboardText(const std::string& s) {
    -#   ifdef G3D_WIN32
    -        if (OpenClipboard(NULL)) {
    -            HGLOBAL hMem = GlobalAlloc(GHND | GMEM_DDESHARE, s.size() + 1);
    -            if (hMem) {
    -                char *pMem = (char*)GlobalLock(hMem);
    -                strcpy(pMem, s.c_str());
    -                GlobalUnlock(hMem);
    -
    -                EmptyClipboard();
    -                SetClipboardData(CF_TEXT, hMem);
    -            }
    -
    -            CloseClipboard();
    -            GlobalFree(hMem);
    -        }
    -#   endif
    -}
    -
    -
    -std::string System::getClipboardText() {
    -    std::string s;
    -
    -#   ifdef G3D_WIN32
    -        if (OpenClipboard(NULL)) {
    -            HANDLE h = GetClipboardData(CF_TEXT);
    -
    -            if (h) {
    -                char* temp = (char*)GlobalLock(h);
    -                if (temp) {
    -    	            s = temp;
    -                }
    -                temp = NULL;
    -                GlobalUnlock(h);
    -            }
    -            CloseClipboard();
    -        }
    -#   endif
    -    return s;
    -}
    -
    -
     std::string System::currentDateString() {
         time_t t1;
         ::time(&t1);
    @@ -1692,41 +1679,28 @@ std::string System::currentDateString() {
         return format("%d-%02d-%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday); 
     }
     
    -#ifdef _MSC_VER
    -
    -// VC on Intel
    -void System::cpuid(CPUIDFunction func, uint32& areg, uint32& breg, uint32& creg, uint32& dreg) {
    -#if !defined(G3D_64BIT) && !defined(__MINGW32__) /* G3DFIX: Don't check if on 64-bit platforms or using MinGW */
    -    // Can't copy from assembler direct to a function argument (which is on the stack) in VC.
    -    uint32 a,b,c,d;
    -
    -    // Intel assembler syntax
    -    __asm {
    -        mov	  eax, func      //  eax <- func
    -        mov   ecx, 0
    -        cpuid              
    -        mov   a, eax   
    -        mov   b, ebx   
    -        mov   c, ecx   
    -        mov   d, edx
    -    }
    -    areg = a;
    -    breg = b; 
    -    creg = c;
    -    dreg = d;
    -#else
    -    int CPUInfo[4];
    -    __cpuid(CPUInfo, func);
    -    memcpy(&areg, &CPUInfo[0], 4);
    -    memcpy(&breg, &CPUInfo[1], 4);
    -    memcpy(&creg, &CPUInfo[2], 4);
    -    memcpy(&dreg, &CPUInfo[3], 4);
    -#endif
    +std::string System::currentTimeString() {
    +    time_t t1;
    +    ::time(&t1);
    +    tm* t = localtime(&t1);
    +    return format("%02d:%02d:%02d", t->tm_hour, t->tm_min, t->tm_sec);
     }
     
    -#elif defined(G3D_OSX) && ! defined(G3D_OSX_INTEL)
    +#if defined(_MSC_VER)
     
    -// non-intel OS X; no CPUID
    +// Windows 64-bit
    +void System::cpuid(CPUIDFunction func, uint32& eax, uint32& ebx, uint32& ecx, uint32& edx) {
    +	int regs[4] = {eax, ebx, ecx, edx};
    +	__cpuid(regs, func);
    +	eax = regs[0];
    +	ebx = regs[1];
    +	ecx = regs[2];
    +	edx = regs[3];
    +}
    +
    +#elif defined(__aarch64__) || defined(G3D_OSX) && ! defined(G3D_OSX_INTEL)
    +
    +// non-x86 CPU; no CPUID
     void System::cpuid(CPUIDFunction func, uint32& eax, uint32& ebx, uint32& ecx, uint32& edx) {
         eax = 0;
         ebx = 0;
    diff --git a/deps/g3dlite/source/TextInput.cpp b/deps/g3dlite/source/TextInput.cpp
    index 354d0de13..6f74d9338 100644
    --- a/deps/g3dlite/source/TextInput.cpp
    +++ b/deps/g3dlite/source/TextInput.cpp
    @@ -1,23 +1,22 @@
     /**
    - @file TextInput.cpp
    + \file G3D/source/TextInput.cpp
       
    - @author Morgan McGuire, graphics3d.com
    + \author Morgan McGuire, http://graphics.cs.williams.edu
      
    - @cite Based on a lexer written by Aaron Orenstein. 
    + \cite Based on a lexer written by Aaron Orenstein. 
      
    - @created 2001-11-27
    - @edited  2010-07-03
    + \created 2001-11-27
    + \edited  2012-07-22
      */
     
     #include "G3D/fileutils.h"
     #include "G3D/TextInput.h"
     #include "G3D/BinaryInput.h"
    +#include "G3D/FileSystem.h"
     #include "G3D/stringutils.h"
     
     #ifdef _MSC_VER
     #   pragma warning (push)
    -// conversion from 'int' to 'char', possible loss of data (TODO: fix underlying problems)
    -#   pragma warning (disable: 4244)
     #endif
     
     namespace G3D {
    @@ -46,15 +45,15 @@ bool TextInput::parseBoolean(const std::string& _string) {
     
     double TextInput::parseNumber(const std::string& _string) {
         std::string s = toLower(_string);
    -    if (s == "-1.#ind00" || s == "nan") {
    +    if (s == "-1.#ind00" || s == "-1.#ind" || s == "nan" || s == "NaN") {
             return nan();
         }
         
    -    if (s == "1.#inf00" || s == "inf" || s == "+inf") {
    +    if (s == "1.#inf00" || s == "1.#inf" || s == "inf" || s == "+inf" || s == "Infinity") {
             return inf();
         }
         
    -    if (s == "-1.#inf00" || s == "-inf") {
    +    if (s == "-1.#inf00" || s == "-1.#inf" || s == "-inf" || s == "-Infinity") {
             return -inf();
         }
         
    @@ -99,7 +98,8 @@ TextInput::Settings::Settings () :
     
     Token TextInput::peek() {
         if (stack.size() == 0) {
    -        Token t = nextToken();
    +        Token t;
    +        nextToken(t);
             push(t);
         }
     
    @@ -118,18 +118,23 @@ int TextInput::peekCharacterNumber() {
     
     
     Token TextInput::read() {
    +    Token t;
    +    read(t);
    +    return t;
    +}
    +
    +
    +void TextInput::read(Token& t) {
         if (stack.size() > 0) {
    -        Token t = stack.front();
    +        t = stack.front();
             stack.pop_front();
    -        return t;
         } else {
    -        return nextToken();
    +        nextToken(t);
         }
     }
     
     
    -
    -std::string TextInput::readUntilNewlineAsString() {
    +std::string TextInput::readUntilDelimiterAsString(const char delimiter1, const char delimiter2) {
     /*
         // Reset the read position back to the start of that token
         currentCharOffset = t.bytePosition();
    @@ -144,11 +149,21 @@ std::string TextInput::readUntilNewlineAsString() {
         */
         std::string s;
     
    -    // Read until newline or eof
    -    char c = '\0';
    -    do {
    -        c = buffer[currentCharOffset];
    -        if (c == '\r' || c == '\n') {
    +    if (stack.size() > 0) {
    +        // Need to back up.  This only works if the stack is actually
    +        // in proper order reflecting the real file, and doesn't
    +        // contain incorrectly pushed elements.
    +        Token t = stack.back();
    +        stack.clear();
    +        currentCharOffset = (int)t.bytePosition();
    +        lineNumber = t.line();
    +        charNumber = t.character();
    +    }
    +
    +    // Read until delimiter or eof
    +    while (currentCharOffset < buffer.size()) {
    +        const char c = buffer[currentCharOffset];
    +        if ((c == delimiter1) || (c == delimiter2)) {
                 // Done
                 break;
             } else {
    @@ -156,12 +171,17 @@ std::string TextInput::readUntilNewlineAsString() {
                 ++currentCharOffset;
                 ++charNumber;
             }
    -    } while (currentCharOffset < buffer.size());
    +    }
     
         return s;    
     }
     
     
    +std::string TextInput::readUntilNewlineAsString() {
    +    return readUntilDelimiterAsString('\r', '\n');
    +}
    +
    +
     static void toUpper(Set& set) {
         Array symbols;
         set.getMembers(symbols);
    @@ -240,8 +260,7 @@ int TextInput::peekInputChar(int distance) {
     }
     
     
    -Token TextInput::nextToken() {
    -    Token t;
    +void TextInput::nextToken(Token& t) {
     
         t._bytePosition = currentCharOffset;
         t._line         = lineNumber;
    @@ -251,7 +270,7 @@ Token TextInput::nextToken() {
     
         int c = peekInputChar();
         if (c == EOF) {
    -        return t;
    +        return;
         }
     
         // loop through white space, newlines and comments
    @@ -276,7 +295,7 @@ Token TextInput::nextToken() {
                     }
     
                     eatInputChar();
    -                return t;
    +                return;
                 } else {
                     // Consume the single whitespace
                     c = eatAndPeekInputChar();
    @@ -288,8 +307,24 @@ Token TextInput::nextToken() {
             t._character    = charNumber;
             t._bytePosition = currentCharOffset;
     
    +        if (isDigit(c)) {
    +            // This is an unsigned number.  Jump ahead for fast number reading.
    +            goto numLabel;
    +        }
    +
             int c2 = peekInputChar(1);
     
    +        if ((c == '-') && isDigit(c2) && options.signedNumbers) {
    +            // This is a simple number.  Jump ahead for fast number reading.
    +            // We treat this case specially because large (i.e., slow) files
    +            // are usually large because they are full of numbers.
    +            t._string = "-";
    +            c = c2;
    +            // Consume the minus sign
    +            eatInputChar();
    +            goto numLabel;
    +        }
    +
             // parse comments and generate tokens if enabled
             std::string commentString;
     
    @@ -327,7 +362,7 @@ Token TextInput::nextToken() {
                     t._type         = Token::COMMENT;
                     t._extendedType = Token::LINE_COMMENT_TYPE;
                     t._string       = commentString;
    -                return t;
    +                return;
                 } else {
                     // There is whitespace after the comment (in particular, the
                     // newline that terminates the comment).  There might also be
    @@ -364,7 +399,7 @@ Token TextInput::nextToken() {
                     t._type         = Token::COMMENT;
                     t._extendedType = Token::BLOCK_COMMENT_TYPE;
                     t._string       = commentString;
    -                return t;
    +                return;
                 } else {
                     // There is whitespace after the comment (in particular, the
                     // newline that terminates the comment).  There might also be
    @@ -381,7 +416,7 @@ Token TextInput::nextToken() {
     
         // handle EOF
         if (c == EOF) {
    -        return t;
    +        return;
         }
     
         // Extended ASCII parses as itself, except for EOF
    @@ -420,7 +455,7 @@ Token TextInput::nextToken() {
         case '?':
         case '%':
             SETUP_SYMBOL(c);
    -        return t;
    +        return;
     
         case '-':                   // negative number, -, --, -=, or ->
             SETUP_SYMBOL(c);
    @@ -431,7 +466,7 @@ Token TextInput::nextToken() {
             case '=':               // -=
                 t._string += c;
                 eatInputChar();
    -            return t;
    +            return;
             }
     
             if (options.signedNumbers) {
    @@ -451,14 +486,14 @@ Token TextInput::nextToken() {
                         eatInputChar(); // i
                         eatInputChar(); // n
                         eatInputChar(); // f
    -                    return t;
    +                    return;
                     }
                 }
             }
     
     
             // plain -
    -        return t;
    +        return;
     
         case '+':                   // positive number, +, ++, or +=
             SETUP_SYMBOL(c);
    @@ -468,7 +503,7 @@ Token TextInput::nextToken() {
             case '=':               // +=
                 t._string += c;
                 eatInputChar();
    -            return t;
    +            return;
             }
     
             if (options.signedNumbers) {
    @@ -488,12 +523,12 @@ Token TextInput::nextToken() {
                         eatInputChar(); // i
                         eatInputChar(); // n
                         eatInputChar(); // f
    -                    return t;
    +                    return;
                     }
                 }
             }
     
    -        return t;
    +        return;
     
         case ':':                   // : or :: or ::> or ::= or := or :>
             SETUP_SYMBOL(c);
    @@ -510,12 +545,11 @@ Token TextInput::nextToken() {
                         eatInputChar();
                     }
                 }
    -        }
    -        else if (options.proofSymbols && (c == '=' || c == '>')) {
    +        } else if (options.proofSymbols && (c == '=' || c == '>')) {
                 t._string += c;
                 eatInputChar();
             }
    -        return t;
    +        return;
     
         case '=':                   // = or == or =>
             SETUP_SYMBOL(c);
    @@ -523,13 +557,11 @@ Token TextInput::nextToken() {
             if (c == '=') {
                 t._string += c;
                 eatInputChar();
    -            return t;
             } else if (options.proofSymbols && (c == '>')) {
                 t._string += c;
                 eatInputChar();
    -            return t;
             }
    -        return t;
    +        return;
     
         case '*':                   // * or *=
         case '/':                   // / or /=
    @@ -541,9 +573,8 @@ Token TextInput::nextToken() {
             if (c == '=') {
                 t._string += c;
                 eatInputChar();
    -            return t;
             }
    -        return t;
    +        return;
     
         case '>':                   // >, >>,or >=
         case '<':                   // <<, <<, or <= or <- or <:
    @@ -556,7 +587,6 @@ Token TextInput::nextToken() {
                 if ((c == '=') || (orig_c == c)) {
                     t._string += c;
                     eatInputChar();
    -                return t;
                 } else if (options.proofSymbols) {
                     if ((orig_c == '<') && (c == '-')) {
                         t._string += c;
    @@ -576,7 +606,7 @@ Token TextInput::nextToken() {
                     }
                 }
             }
    -        return t;
    +        return;
                 
         case '\\':                // backslash or escaped comment char.
             SETUP_SYMBOL(c);
    @@ -591,9 +621,9 @@ Token TextInput::nextToken() {
     
                 t._string = c;
                 eatInputChar();
    -            return t;
    +            return;
             }
    -        return t;
    +        return;
     
         case '.':                   // number, ., .., or ...
             if (isDigit(peekInputChar(1))) {
    @@ -611,10 +641,10 @@ Token TextInput::nextToken() {
                     t._string += c;
                     eatInputChar();
                 }
    -            return t;
    +            return;
             }
     
    -        return t;
    +        return;
     
         } // switch (c)
     
    @@ -640,7 +670,7 @@ numLabel:
             } else {
                 t._extendedType = Token::INTEGER_TYPE;
             }
    -        
    +
             if ((c == '0') && (peekInputChar(1) == 'x')) {
                 // Hex number
                 t._string += "0x";
    @@ -656,7 +686,7 @@ numLabel:
                 }
     
             } else {
    -			// Non-hex number
    +            // Non-hex number
     
                 // Read the part before the decimal.
                 while (isDigit(c)) {
    @@ -681,6 +711,7 @@ numLabel:
                         isSpecial = true;
                         // We are reading a floating point special value
                         // of the form -1.#IND00, -1.#INF00, or 1.#INF00
    +                    // (with or without the trailing 00
                         c = eatAndPeekInputChar();
                         char test = c;
                         if (! options.caseSensitive) {
    @@ -718,16 +749,25 @@ numLabel:
                                 t.line(), charNumber);
                         }
                         t._string += c;
    +
    +                    // On older systems, there may be an extra 00 tacked on.
                         for (int j = 0; j < 2; ++j) {
                             c = eatAndPeekInputChar();
    -                        if (c != '0') {
    -                            throw BadMSVCSpecial
    +                        if (c == '0') {
    +                            c = eatAndPeekInputChar();
    +                            if (c != '0') {
    +                                throw BadMSVCSpecial
                                     (
    -                                 "Incorrect floating-point special (inf or"
    -                                 "nan) format.",
    -                                 t.line(), charNumber);
    +                                 "Incorrect floating-point special (inf or nan) "
    +                                 "format.",
    +                                t.line(), charNumber);
    +                            } else {
    +                                eatInputChar();
    +                                t._string += "00";
    +                            }
    +                        } else {
    +                            break;
                             }
    -                        t._string += (char)c;
                         }
     
                     } else {
    @@ -763,7 +803,7 @@ numLabel:
                     c = eatAndPeekInputChar();
                 }
             }
    -        return t;
    +        return;
     
         } else if (isLetter(c) || (c == '_')) {
             // Identifier or keyword
    @@ -798,7 +838,7 @@ numLabel:
                 t._type = Token::NUMBER;
                 t._extendedType = Token::FLOATING_POINT_TYPE;
             }
    -        return t;
    +        return;
     
         } else if (c == '\"') {
     
    @@ -807,7 +847,7 @@ numLabel:
     
             // Double quoted string
             parseQuotedString('\"', t);
    -        return t;
    +        return;
     
         } else if (c == options.singleQuoteCharacter) {
     
    @@ -822,22 +862,20 @@ numLabel:
                 t._type = Token::SYMBOL;
                 t._extendedType = Token::SYMBOL_TYPE;
             }
    -        return t;
    +        return;
     
         } // end of special case tokens
     
    -    if (c == EOF) {
    +    if ((c == EOF) || (c == '\0')) {
             t._type = Token::END;
             t._extendedType = Token::END_TYPE;
             t._string = "";
    -        return t;
    +        return;
         }
     
         // Some unknown token
    -    debugAssertM(false, 
    -                 format("Unrecognized token type beginning with character '%c' (ASCII %d)", 
    -                        c, c));
    -    return t;
    +    throw format("Unrecognized token type beginning with character '%c' (ASCII %d)", c, c);
    +    return;
     }
     
     
    @@ -915,8 +953,9 @@ void TextInput::parseQuotedString(unsigned char delimiter, Token& t) {
         }
     }
     
    +
     bool TextInput::readBoolean() {
    -    Token t(read());
    +    const Token& t = read();
     
         if (t._type == Token::BOOLEAN) {
             return t.boolean();
    @@ -930,10 +969,53 @@ bool TextInput::readBoolean() {
                              Token::BOOLEAN, t._type); 
     }
     
    -double TextInput::readNumber() {
    -    Token t(read());
     
    -    if (t._type == Token::NUMBER) {
    +int TextInput::readInteger() {
    +    Token t;
    +    read(t);
    +
    +    if (t._extendedType == Token::INTEGER_TYPE) {  // common case
    +        return int(t.number());
    +    } else {
    +        // Even if signedNumbers is disabled, readInteger attempts to
    +        // read a signed number, so we handle that case here.
    +        if (! options.signedNumbers
    +            && (t._type == Token::SYMBOL)
    +            && ((t._string == "-") 
    +                 || (t._string == "+"))) {
    +
    +            Token t2;
    +            read(t2);
    +
    +            if ((t2._extendedType == Token::INTEGER_TYPE)
    +                && (t2._character == t._character + 1)) {
    +
    +                if (t._string == "-") {
    +                    return (int)-t2.number();
    +                } else {
    +                    return (int)t2.number();
    +                }
    +            }
    +
    +            // push back the second token.
    +            push(t2);
    +        }
    +
    +        // Push initial token back, and throw an error.  We intentionally
    +        // indicate that the wrong type is the type of the initial token.
    +        // Logically, the number started there.
    +        push(t);
    +        throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
    +                             Token::NUMBER, t._type); 
    +    }    
    +}
    +
    +
    +double TextInput::readNumber() {
    +    Token t;
    +    read(t);
    +
    +    if (t._type == Token::NUMBER) {  // common case
             return t.number();
         }
     
    @@ -970,7 +1052,8 @@ double TextInput::readNumber() {
     
     
     Token TextInput::readStringToken() {
    -    Token t(read());
    +    Token t;
    +    read(t);
     
         if (t._type == Token::STRING) {               // fast path
             return t;
    @@ -985,8 +1068,9 @@ std::string TextInput::readString() {
         return readStringToken()._string;
     }
     
    +
     void TextInput::readString(const std::string& s) {
    -    Token t(readStringToken());
    +    const Token& t = readStringToken();
     
         if (t._string == s) {                         // fast path
             return;
    @@ -997,8 +1081,10 @@ void TextInput::readString(const std::string& s) {
                           s, t._string);
     }
     
    +
     Token TextInput::readCommentToken() {
    -    Token t(read());
    +    Token t;
    +    read(t);
     
         if (t._type == Token::COMMENT) {               // fast path
             return t;
    @@ -1009,12 +1095,14 @@ Token TextInput::readCommentToken() {
                              Token::COMMENT, t._type);
     }
     
    +
     std::string TextInput::readComment() {
         return readCommentToken()._string;
     }
     
    +
     void TextInput::readComment(const std::string& s) {
    -    Token t(readCommentToken());
    +    const Token& t = readCommentToken();
     
         if (t._string == s) {                         // fast path
             return;
    @@ -1025,8 +1113,10 @@ void TextInput::readComment(const std::string& s) {
                           s, t._string);
     }
     
    +
     Token TextInput::readNewlineToken() {
    -    Token t(read());
    +    Token t;
    +    read(t);
     
         if (t._type == Token::NEWLINE) {               // fast path
             return t;
    @@ -1042,7 +1132,7 @@ std::string TextInput::readNewline() {
     }
     
     void TextInput::readNewline(const std::string& s) {
    -    Token t(readNewlineToken());
    +    const Token& t = readNewlineToken();
     
         if (t._string == s) {                         // fast path
             return;
    @@ -1053,11 +1143,19 @@ void TextInput::readNewline(const std::string& s) {
                           s, t._string);
     }
     
    +
     Token TextInput::readSymbolToken() {
    -    Token t(read());
    +    Token t;
    +    readSymbolToken(t);
    +    return t;
    +}
    +
    +
    +void TextInput::readSymbolToken(Token& t) {
    +    read(t);
         
         if (t._type == Token::SYMBOL) {               // fast path
    -        return t;
    +        return;
         }
     
         push(t);
    @@ -1070,10 +1168,12 @@ std::string TextInput::readSymbol() {
         return readSymbolToken()._string;
     }
     
    -void TextInput::readSymbol(const std::string& symbol) {
    -    Token t(readSymbolToken());
     
    -    if (t._string == symbol) {                    // fast path
    +void TextInput::readSymbol(const std::string& symbol) {
    +    Token t;
    +    readSymbolToken(t);
    +
    +    if (t._string == symbol) { // fast path
             return;
         }
     
    @@ -1085,29 +1185,53 @@ void TextInput::readSymbol(const std::string& symbol) {
     
     TextInput::TextInput(const std::string& filename, const Settings& opt) : options(opt) {
         init();
    -    std::string input = readWholeFile(filename);
    -
         if (options.sourceFileName.empty()) {
             options.sourceFileName = filename;
         }
    -    int n = input.size();
    -    buffer.resize(n);
    -    System::memcpy(buffer.getCArray(), input.c_str(), n);
    +
    +    std::string zipfile;
    +    if (FileSystem::inZipfile(filename, zipfile)) {
    +        // TODO: this could be faster if we directly read the zipfile
    +        const std::string& input = readWholeFile(filename);
    +        size_t n = input.size();
    +        buffer.resize(n);
    +        System::memcpy(buffer.getCArray(), input.c_str(), n);
    +    } else {
    +        // Read directly into the array
    +        const uint64 n = FileSystem::size(filename);
    +        alwaysAssertM(n != uint64(-1), std::string("File does not exist: ") + filename);
    +        buffer.resize(size_t(n));
    +        FILE* f = FileSystem::fopen(filename.c_str(), "rb");
    +        fread(buffer.getCArray(), 1, size_t(n), f);
    +        FileSystem::fclose(f);
    +    }
     }
     
     
    -TextInput::TextInput(FS fs, const std::string& str, const Settings& opt) : options(opt) {
    -    (void)fs;
    +void TextInput::initFromString(const char* str, int len, const Settings& settings) {
    +    options = settings;
         init();
         if (options.sourceFileName.empty()) {
    -        if (str.length() < 14) {
    -            options.sourceFileName = std::string("\"") + str + "\"";
    +        if (len < 14) {
    +            options.sourceFileName = format("\"%.*s\"", len, str);
             } else {
    -            options.sourceFileName = std::string("\"") + str.substr(0, 10) + "...\"";
    +            options.sourceFileName = format("\"%.*s...\"", 10, str);
             }
         }
    -    buffer.resize(str.length()); // we don't bother copying trailing NUL.
    -    System::memcpy(buffer.getCArray(), str.c_str(), buffer.size());
    +    buffer.resize(len);
    +    System::memcpy(buffer.getCArray(), str, buffer.size());
    +}
    +
    +
    +TextInput::TextInput(FS fs, const std::string& str, const Settings& opt) {
    +    (void)fs;
    +    initFromString(str.c_str(), (int)str.size(), opt);
    +}
    +
    +
    +TextInput::TextInput(FS fs, const char* str, size_t len, const Settings& opt) : options(opt) {
    +    (void)fs;
    +    initFromString(str, (int)len, opt);
     }
     
     
    diff --git a/deps/g3dlite/source/TextOutput.cpp b/deps/g3dlite/source/TextOutput.cpp
    index 3257f6fb9..e764b59c7 100644
    --- a/deps/g3dlite/source/TextOutput.cpp
    +++ b/deps/g3dlite/source/TextOutput.cpp
    @@ -1,11 +1,11 @@
     /**
    -  @file TextOutput.cpp
    +  \file G3D.lib/source/TextOutput.cpp
     
    -  @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    -  @created 2004-06-21
    -  @edited  2010-03-14
    +  \maintainer Morgan McGuire, http://graphics.cs.williams.edu
    +  \created 2004-06-21
    +  \edited  2013-04-09
     
    -  Copyright 2000-2010, Morgan McGuire.
    +  Copyright 2000-2013, Morgan McGuire.
       All rights reserved.
      */
     
    @@ -17,11 +17,12 @@
     namespace G3D {
     
     TextOutput::TextOutput(const TextOutput::Settings& opt) :
    -	startingNewLine(true),
    +    startingNewLine(true),
         currentColumn(0),
    -	inDQuote(false),
    -	filename(""),
    -	indentLevel(0)
    +    inDQuote(false),
    +    filename(""),
    +    indentLevel(0),
    +    m_currentLine(0)
     {
         setOptions(opt);
     }
    @@ -30,9 +31,10 @@ TextOutput::TextOutput(const TextOutput::Settings& opt) :
     TextOutput::TextOutput(const std::string& fil, const TextOutput::Settings& opt) :
         startingNewLine(true),
         currentColumn(0),
    -	inDQuote(false),
    -	filename(fil),
    -	indentLevel(0) 
    +    inDQuote(false),
    +    filename(fil),
    +    indentLevel(0),
    +    m_currentLine(0)
     {
     
         setOptions(opt);
    @@ -106,9 +108,17 @@ static std::string escape(const std::string& string) {
         return result;
     }
     
    +
     void TextOutput::writeString(const std::string& string) {
    +    // Never break a line in a string
    +    const Settings::WordWrapMode old = option.wordWrap;
    +
    +    if (! option.allowWordWrapInsideDoubleQuotes) {
    +        option.wordWrap = Settings::WRAP_NONE;
    +    }
         // Convert special characters to escape sequences
         this->printf("\"%s\"", escape(string).c_str());
    +    option.wordWrap = old;
     }
     
     
    @@ -117,7 +127,7 @@ void TextOutput::writeBoolean(bool b) {
     }
     
     void TextOutput::writeNumber(double n) {
    -    this->printf("%f ", n);
    +    this->printf("%g ", n);
     }
     
     
    @@ -128,11 +138,14 @@ void TextOutput::writeNumber(int 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::writeSymbol(char c) {
    +    this->printf("%c ", c);
    +}
    +
     void TextOutput::writeSymbols(
         const std::string& a,
         const std::string& b,
    @@ -166,6 +179,17 @@ void TextOutput::printf(const char* formatString, ...) {
     }
     
     
    +bool TextOutput::deleteSpace() {
    +    if ((currentColumn > 0) && (data.last() == ' ')) {
    +        data.popDiscard();
    +        --currentColumn;
    +        return true;
    +    } else {
    +        return false;
    +    }
    +}
    +
    +
     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
    @@ -256,20 +280,20 @@ void TextOutput::wordWrapIndentAppend(const std::string& str) {
                 //     search backwards for a space, then execute case 2.
     
                 // Index of most recent space
    -            uint32 lastSpace = data.size() - 1;
    +            size_t lastSpace = data.size() - 1;
     
                 // How far back we had to look for a space
    -            uint32 k = 0;
    -            uint32 maxLookBackward = currentColumn - indentSpaces;
    +            size_t k = 0;
    +            size_t maxLookBackward = currentColumn - indentSpaces;
     
                 // Search backwards (from current character), looking for a space.
                 while ((k < maxLookBackward) &&
    -                (lastSpace > 0) &&
    -                (! ((data[lastSpace] == ' ') && unquotedSpace))) {
    +                   (lastSpace > 0) &&
    +                   (! ((data[(int)lastSpace] == ' ') && unquotedSpace))) {
                     --lastSpace;
                     ++k;
     
    -                if ((data[lastSpace] == '\"') && !option.allowWordWrapInsideDoubleQuotes) {
    +                if ((data[(int)lastSpace] == '\"') && !option.allowWordWrapInsideDoubleQuotes) {
                         unquotedSpace = ! unquotedSpace;
                     }
                 }
    @@ -296,10 +320,10 @@ void TextOutput::wordWrapIndentAppend(const std::string& str) {
     
                     // Find the start of the spaces.  firstSpace is the index of the
                     // first non-space, looking backwards from lastSpace.
    -                uint32 firstSpace = lastSpace;
    +                size_t firstSpace = lastSpace;
                     while ((k < maxLookBackward) &&
                         (firstSpace > 0) &&
    -                    (data[firstSpace] == ' ')) {
    +                       (data[(int)firstSpace] == ' ')) {
                         --firstSpace;
                         ++k;
                     }
    @@ -323,8 +347,8 @@ void TextOutput::wordWrapIndentAppend(const std::string& str) {
     
                         // Copy over the characters that should be saved
                         Array temp;
    -                    for (uint32 j = lastSpace + 1; j < (uint32)data.size(); ++j) {
    -                        char c = data[j];
    +                    for (size_t j = lastSpace + 1; j < (uint32)data.size(); ++j) {
    +                        char c = data[(int)j];
     
                             if (c == '\"') {
                                 // Undo changes to quoting (they will be re-done
    @@ -339,8 +363,8 @@ void TextOutput::wordWrapIndentAppend(const std::string& str) {
                         writeNewline();
     
                         // Write them back
    -                    for (uint32 j = 0; j < (uint32)temp.size(); ++j) {
    -                        indentAppend(temp[j]);
    +                    for (size_t j = 0; j < (uint32)temp.size(); ++j) {
    +                        indentAppend(temp[(int)j]);
                         }
     
                         // We are now free to continue adding from the
    @@ -378,12 +402,13 @@ void TextOutput::indentAppend(char c) {
         startingNewLine = (c == '\n');
         if (startingNewLine) {
             currentColumn = 0;
    +        ++m_currentLine;
         }
     }
     
     
     void TextOutput::vprintf(const char* formatString, va_list argPtr) {
    -    std::string str = vformat(formatString, argPtr);
    +    const std::string& str = vformat(formatString, argPtr);
     
         std::string clean;
         convertNewlines(str, clean);
    diff --git a/deps/g3dlite/source/ThreadSet.cpp b/deps/g3dlite/source/ThreadSet.cpp
    index ee3895fe9..df6fd4d47 100644
    --- a/deps/g3dlite/source/ThreadSet.cpp
    +++ b/deps/g3dlite/source/ThreadSet.cpp
    @@ -1,4 +1,5 @@
     #include "G3D/ThreadSet.h"
    +#include "G3D/GThread.h"
     
     namespace G3D {
     
    @@ -25,7 +26,7 @@ int ThreadSet::numStarted() const {
     }
         
         
    -void ThreadSet::start(GThread::SpawnBehavior lastBehavior) const {
    +void ThreadSet::start(SpawnBehavior lastBehavior) const {
         ThreadSet* me = const_cast(this);
     
         Array unstarted;
    @@ -38,20 +39,22 @@ void ThreadSet::start(GThread::SpawnBehavior lastBehavior) const {
         }
     
         int last = unstarted.size();
    -    if (lastBehavior == GThread::USE_CURRENT_THREAD) {
    +    if (lastBehavior == USE_CURRENT_THREAD) {
             // Save the last unstarted for the current thread
             --last;
         }
     
    +    // Start all threads
         for (int i = 0; i < last; ++i) {
    -        unstarted[i]->start(GThread::USE_NEW_THREAD);
    +        unstarted[i]->start(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);
    +    if ((unstarted.size() > 0) && (lastBehavior == USE_CURRENT_THREAD)) {
    +        unstarted.last()->start(USE_CURRENT_THREAD);
    +        debugAssert(unstarted.last()->completed());
         }
     }
         
    @@ -70,6 +73,7 @@ void ThreadSet::terminate() const {
     
     void ThreadSet::waitForCompletion() const {
         ThreadSet* me = const_cast(this);
    +
         me->m_lock.lock();
         for (int i = 0; i < m_thread.size(); ++i) {
             if (m_thread[i]->started()) {
    diff --git a/deps/g3dlite/source/Triangle.cpp b/deps/g3dlite/source/Triangle.cpp
    index 253438ad5..e1b5f8e05 100644
    --- a/deps/g3dlite/source/Triangle.cpp
    +++ b/deps/g3dlite/source/Triangle.cpp
    @@ -172,7 +172,7 @@ bool Triangle::intersect(const Ray& ray, float& distance, float baryCoord[3]) co
             // This is a new hit, closer than the previous one
             distance = t;
     
    -        baryCoord[0] = 1.0 - u - v;
    +        baryCoord[0] = 1.0f - u - v;
             baryCoord[1] = u;
             baryCoord[2] = v;
     
    diff --git a/deps/g3dlite/source/UprightFrame.cpp b/deps/g3dlite/source/UprightFrame.cpp
    index c80264bf4..80c7e2402 100644
    --- a/deps/g3dlite/source/UprightFrame.cpp
    +++ b/deps/g3dlite/source/UprightFrame.cpp
    @@ -1,11 +1,7 @@
     /**
    -  @file UprightFrame.cpp
    -  Box class
    +  \file UprightFrame.cpp
     
    -  @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    -
    -  @created 2007-05-02
    -  @edited  2007-05-05
    +  \maintainer Morgan McGuire, http://graphics.cs.williams.edu
     */
     
     #include "G3D/UprightFrame.h"
    @@ -17,12 +13,38 @@ namespace G3D {
     UprightFrame::UprightFrame(const CoordinateFrame& cframe) {
         Vector3 look = cframe.lookVector();
     
    -    yaw = G3D::pi() + atan2(look.x, look.z);
    +    yaw = (float)(G3D::pi() + atan2(look.x, look.z));
         pitch = asin(look.y);
     
         translation = cframe.translation;
     }
     
    +
    +UprightFrame::UprightFrame(const Any& any) {
    +    any.verifyName("UprightFrame");
    +    any.verifyType(Any::TABLE);
    +
    +    translation = any["translation"];
    +    pitch = any["pitch"];
    +    yaw = any["yaw"];
    +}
    +
    +
    +Any UprightFrame::toAny() const {
    +    Any any(Any::TABLE, "UprightFrame");
    +
    +    any["translation"] = translation;
    +    any["pitch"] = pitch;
    +    any["yaw"] = yaw;
    +
    +    return any;
    +}
    +
    +
    +UprightFrame& UprightFrame::operator=(const Any& any) {
    +    *this = UprightFrame(any);
    +    return *this;
    +}
         
     CoordinateFrame UprightFrame::toCoordinateFrame() const {
         CoordinateFrame cframe;
    @@ -59,15 +81,15 @@ void UprightFrame::unwrapYaw(UprightFrame* a, int N) {
                 // to be interpolated the long way.
     
                 // Find canonical [0, 2pi] versions of these numbers
    -            float p = wrap(prev, twoPi());
    -            float c = wrap(cur, twoPi());
    +            float p = (float)wrap(prev, twoPi());
    +            float c = (float)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();
    +                diff += (float)twoPi();
                 } else if (diff > G3D::pi()) {
    -                diff -= twoPi();
    +                diff -= (float)twoPi();
                 } 
     
                 // Offset the current from the previous by the difference
    @@ -77,7 +99,6 @@ void UprightFrame::unwrapYaw(UprightFrame* a, int N) {
         }
     }
     
    -
     void UprightFrame::serialize(class BinaryOutput& b) const {
         translation.serialize(b);
         b.writeFloat32(pitch);
    @@ -91,9 +112,70 @@ void UprightFrame::deserialize(class BinaryInput& b) {
         yaw = b.readFloat32();
     }
     
    +///////////////////////////////////////////////////////////////////////////////////////////
    +
    +UprightSpline::UprightSpline() : Spline() {
    +}
    +
    +
    +UprightSpline::UprightSpline(const Any& any) {
    +    any.verifyName("UprightSpline");
    +    any.verifyType(Any::TABLE);
    +
    +    extrapolationMode = any["extrapolationMode"];
    +
    +    const Any& controlsAny = any["control"];
    +    controlsAny.verifyType(Any::ARRAY);
    +
    +    control.resize(controlsAny.length());
    +    for (int controlIndex = 0; controlIndex < control.length(); ++controlIndex) {
    +        control[controlIndex] = controlsAny[controlIndex];
    +    }
    +
    +    const Any& timesAny = any["time"];
    +    timesAny.verifyType(Any::ARRAY);
    +
    +    time.resize(timesAny.length());
    +    for (int timeIndex = 0; timeIndex < time.length(); ++timeIndex) {
    +        time[timeIndex] = timesAny[timeIndex];
    +    }
    +}
    +
    +
    +Any UprightSpline::toAny(const std::string& myName) const {
    +    Any any(Any::TABLE, myName);
    +
    +    any["extrapolationMode"] = extrapolationMode;
    +
    +    Any controlsAny(Any::ARRAY);
    +    for (int controlIndex = 0; controlIndex < control.length(); ++controlIndex) {
    +        controlsAny.append(control[controlIndex]);
    +    }
    +    any["control"] = controlsAny;
    +
    +    Any timesAny(Any::ARRAY);
    +    for (int timeIndex = 0; timeIndex < time.length(); ++timeIndex) {
    +        timesAny.append(Any(time[timeIndex]));
    +    }
    +    any["time"] = timesAny;
    +
    +    return any;
    +}
    +
    +
    +Any UprightSpline::toAny() const {
    +    return toAny("UprightSpline");
    +}
    +
    +
    +UprightSpline& UprightSpline::operator=(const Any& any) {
    +    *this = UprightSpline(any);
    +    return *this;
    +}
    +
     
     void UprightSpline::serialize(class BinaryOutput& b) const {
    -    b.writeBool8(cyclic);
    +    b.writeInt32(extrapolationMode);
     
         b.writeInt32(control.size());
         for (int i = 0; i < control.size(); ++i) {
    @@ -107,7 +189,7 @@ void UprightSpline::serialize(class BinaryOutput& b) const {
     
     
     void UprightSpline::deserialize(class BinaryInput& b) {
    -    cyclic = b.readBool8();
    +    extrapolationMode = SplineExtrapolationMode(b.readInt32());
     
         control.resize(b.readInt32());
         for (int i = 0; i < control.size(); ++i) {
    @@ -124,7 +206,7 @@ void UprightSpline::deserialize(class BinaryInput& b) {
             // Import legacy path
             time.resize(control.size());
             for (int i = 0; i < time.size(); ++i) {
    -            time[i] = i;
    +            time[i] = (float)i;
             }
         }
     }
    diff --git a/deps/g3dlite/source/Vector2.cpp b/deps/g3dlite/source/Vector2.cpp
    index ec0737c37..a6edea9a8 100644
    --- a/deps/g3dlite/source/Vector2.cpp
    +++ b/deps/g3dlite/source/Vector2.cpp
    @@ -9,12 +9,13 @@
       at http://www.magic-software.com
      
      @created 2001-06-02
    - @edited  2009-11-16
    + @edited  2010-11-16
      */
     
     #include "G3D/platform.h"
     #include 
     #include "G3D/Vector2.h"
    +#include "G3D/Vector2int32.h"
     #include "G3D/g3dmath.h"
     #include "G3D/format.h"
     #include "G3D/BinaryInput.h"
    @@ -25,9 +26,12 @@
     
     namespace G3D {
     
    +Vector2::Vector2(const Vector2int32& other) : x((float)other.x), y((float)other.y) {
    +}
    +
     
     Vector2::Vector2(const Any& any) {
    -    any.verifyName("Vector2");
    +    any.verifyName("Vector2", "Point2");
         any.verifyType(Any::TABLE, Any::ARRAY);
         any.verifySize(2);
     
    @@ -42,7 +46,13 @@ Vector2::Vector2(const Any& any) {
     }
     
     
    -Vector2::operator Any() const {
    +Vector2& Vector2::operator=(const Any& a) {
    +    *this = Vector2(a);
    +    return *this;
    +}
    +
    +
    +Any Vector2::toAny() const {
         Any any(Any::ARRAY, "Vector2");
         any.append(x, y);
         return any;
    @@ -70,26 +80,26 @@ const Vector2& Vector2::unitY() {
     }
     
     const Vector2& Vector2::inf() { 
    -	static Vector2 v((float)G3D::finf(), (float)G3D::finf());
    -	return v; 
    +    static Vector2 v(G3D::finf(), G3D::finf());
    +    return v; 
     }
     
     
     const Vector2& Vector2::nan() { 
    -	static Vector2 v((float)G3D::fnan(), (float)G3D::fnan()); 
    -	return v; 
    +    static Vector2 v(G3D::fnan(), G3D::fnan()); 
    +    return v; 
     }
     
     
     const Vector2& Vector2::minFinite() {
    -	static Vector2 v(-FLT_MAX, -FLT_MAX); 
    -	return v; 
    +    static Vector2 v(-FLT_MAX, -FLT_MAX); 
    +    return v; 
     }
     
     
     const Vector2& Vector2::maxFinite() {
    -	static Vector2 v(FLT_MAX, FLT_MAX); 
    -	return v; 
    +    static Vector2 v(FLT_MAX, FLT_MAX); 
    +    return v; 
     }
     
     
    @@ -145,9 +155,7 @@ Vector2 Vector2::random(G3D::Random& r) {
     
         } while (result.squaredLength() >= 1.0f);
     
    -    result.unitize();
    -
    -    return result;
    +    return result.direction();
     }
     
     
    @@ -161,20 +169,6 @@ Vector2& Vector2::operator/= (float 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;
    -}
     
     //----------------------------------------------------------------------------
     
    @@ -220,5 +214,12 @@ Vector4 Vector2::xyyy() const  { return Vector4       (x, y, y, y); }
     Vector4 Vector2::yyyy() const  { return Vector4       (y, y, y, y); }
     
     
    +void serialize(const Vector2& v, class BinaryOutput& b) {
    +    v.serialize(b);
    +}
    +
    +void deserialize(Vector2& v, class BinaryInput& b) {
    +    v.deserialize(b);
    +}
     
     } // namespace
    diff --git a/deps/g3dlite/source/Vector2int16.cpp b/deps/g3dlite/source/Vector2int16.cpp
    index 2a4035a4d..16893eb17 100644
    --- a/deps/g3dlite/source/Vector2int16.cpp
    +++ b/deps/g3dlite/source/Vector2int16.cpp
    @@ -1,10 +1,10 @@
     /**
    - @file Vector2int16.cpp
    + \file G3D/Vector2int16.cpp
      
    - @author Morgan McGuire, http://graphics.cs.williams.edu
    + \author Morgan McGuire, http://graphics.cs.williams.edu
       
    - @created 2003-08-09
    - @edited  2006-01-29
    + \created 2003-08-09
    + \edited  2011-01-06
      */
     
     #include "G3D/platform.h"
    @@ -13,9 +13,41 @@
     #include "G3D/Vector2.h"
     #include "G3D/BinaryInput.h"
     #include "G3D/BinaryOutput.h"
    +#include "G3D/Any.h"
    +#include "G3D/Vector2int32.h"
     
     namespace G3D {
     
    +Vector2int16::Vector2int16(const class Vector2int32& v) : x(v.x), y(v.y) {}
    +
    +Vector2int16::Vector2int16(const Any& any) {
    +    any.verifyName("Vector2int16", "Point2int16");
    +    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"];
    +    }
    +}
    +
    +
    +Vector2int16& Vector2int16::operator=(const Any& a) {
    +    *this = Vector2int16(a);
    +    return *this;
    +}
    +
    +
    +Any Vector2int16::toAny() const {
    +    Any any(Any::ARRAY, "Vector2int16");
    +    any.append(x, y);
    +    return any;
    +}
    +
     Vector2int16::Vector2int16(const class Vector2& v) {
         x = (int16)iFloor(v.x + 0.5);
         y = (int16)iFloor(v.y + 0.5);
    diff --git a/deps/g3dlite/source/Vector3.cpp b/deps/g3dlite/source/Vector3.cpp
    index 55343e96e..e2d9643e5 100644
    --- a/deps/g3dlite/source/Vector3.cpp
    +++ b/deps/g3dlite/source/Vector3.cpp
    @@ -1,14 +1,14 @@
     /**
    - @file Vector3.cpp
    + \file G3D.lib/source/Vector3.cpp
      
      3D vector class
      
    - @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    + \maintainer Morgan McGuire, http://graphics.cs.williams.edu
      
    - @cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com
    + \cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com
      
    - @created 2001-06-02
    - @edited  2009-11-27
    + \created 2001-06-02
    + \edited  2011-11-27
      */
     
     #include 
    @@ -31,8 +31,39 @@
      
     namespace G3D {
     
    +    
    +Vector3 Vector3::movedTowards(const Vector3& goal, float maxTranslation) const {
    +    Vector3 t = *this;
    +    t.moveTowards(goal, maxTranslation);
    +    return t;
    +}
    +
    +
    +void Vector3::moveTowards(const Vector3& goal, float maxTranslation) {
    +    // Apply clamped translation
    +    Vector3 dX = goal - *this;
    +    float length = dX.length();
    +    if ((length < 0.00001f) || (length < maxTranslation)) {
    +        *this = goal;
    +    } else {
    +        *this += G3D::min(1.0f, maxTranslation / length) * dX;
    +    }
    +}
    +
    +
     Vector3::Vector3(const Any& any) {
    -    any.verifyName("Vector3");
    +    if (any.name() == "Vector3::inf" || any.name() == "Point3::inf") {
    +        *this = inf();
    +        return;
    +    } else if (any.name() == "Vector3::zero" || any.name() == "Point3::zero") {
    +        *this = zero();
    +        return;
    +    } else if (any.name() == "Vector3::nan" || any.name() == "Point3::nan") {
    +        *this = nan();
    +        return;
    +    }
    +
    +    any.verifyName("Vector3", "Point3");
         any.verifyType(Any::TABLE, Any::ARRAY);
         any.verifySize(3);
     
    @@ -48,8 +79,25 @@ Vector3::Vector3(const Any& any) {
         }
     }
     
    -Vector3::operator Any() const {
    -    Any any(Any::ARRAY, "Vector3");
    +
    +bool Vector3::isNaN() const {
    +    return G3D::isNaN(x) || G3D::isNaN(y) || G3D::isNaN(z);
    +}
    +
    +
    +Vector3& Vector3::operator=(const Any& a) {
    +    *this = Vector3(a);
    +    return *this;
    +}
    +
    +
    +Any Vector3::toAny() const {
    +    return toAny("Vector3");
    +}
    +
    +
    +Any Vector3::toAny(const std::string& name) const {
    +    Any any(Any::ARRAY, name);
         any.append(x, y, z);
         return any;
     }
    @@ -105,7 +153,11 @@ Vector3::Axis Vector3::primaryAxis() const {
     
     
     size_t Vector3::hashCode() const {
    -    return Vector4(*this, 0.0f).hashCode();
    +    const uint32* u = (const uint32*)this;
    +    return 
    +        HashTrait::hashCode(u[0]) ^ 
    +        HashTrait::hashCode(~u[1]) ^
    +        HashTrait::hashCode((u[2] << 16) | ~(u[2] >> 16));
     }
     
     std::ostream& operator<<(std::ostream& os, const Vector3& v) {
    @@ -120,7 +172,7 @@ double frand() {
     }
     
     Vector3::Vector3(TextInput& t) {
    -	deserialize(t);
    +    deserialize(t);
     }
     
     Vector3::Vector3(BinaryInput& b) {
    @@ -178,22 +230,6 @@ Vector3 Vector3::random(Random& r) {
     }
     
     
    -float Vector3::unitize(float fTolerance) {
    -    float fMagnitude = magnitude();
    -
    -    if (fMagnitude > fTolerance) {
    -        float fInvMagnitude = 1.0f / fMagnitude;
    -        x *= fInvMagnitude;
    -        y *= fInvMagnitude;
    -        z *= fInvMagnitude;
    -    } else {
    -        fMagnitude = 0.0f;
    -    }
    -
    -    return fMagnitude;
    -}
    -
    -
     Vector3 Vector3::reflectAbout(const Vector3& normal) const {
         Vector3 out;
     
    @@ -224,6 +260,26 @@ Vector3 Vector3::cosHemiRandom(const Vector3& normal, Random& r) {
     }
     
     
    +Vector3 Vector3::cosSphereRandom(const Vector3& normal, Random& r) {
    +    debugAssertM(G3D::fuzzyEq(normal.length(), 1.0f), 
    +                 "cosSphereRandom requires its argument to have unit length");
    +
    +    float x, y, z;
    +    r.cosSphere(x, y, z);
    +
    +    // Make a coordinate system
    +    const Vector3& Z = normal;
    +
    +    Vector3 X, Y;
    +    normal.getTangents(X, Y);
    +
    +    return 
    +        x * X +
    +        y * Y +
    +        z * Z;
    +}
    +
    +
     Vector3 Vector3::cosPowHemiRandom(const Vector3& normal, const float k, Random& r) {
         debugAssertM(G3D::fuzzyEq(normal.length(), 1.0f), 
                      "cosPowHemiRandom requires its argument to have unit length");
    @@ -310,40 +366,20 @@ void Vector3::orthonormalize (Vector3 akVector[3]) {
         // product of vectors A and B.
     
         // compute u0
    -    akVector[0].unitize();
    +    akVector[0] = akVector[0].direction();
     
         // compute u1
    -	float fDot0 = akVector[0].dot(akVector[1]);
    +    float fDot0 = akVector[0].dot(akVector[1]);
         akVector[1] -= akVector[0] * fDot0;
    -    akVector[1].unitize();
    +    akVector[1] = akVector[1].direction();
     
         // compute u2
    -	float fDot1 = akVector[1].dot(akVector[2]);
    +    float fDot1 = akVector[1].dot(akVector[2]);
         fDot0 = akVector[0].dot(akVector[2]);
         akVector[2] -= akVector[0] * fDot0 + akVector[1] * fDot1;
    -    akVector[2].unitize();
    +    akVector[2] = akVector[2].direction();
     }
     
    -//----------------------------------------------------------------------------
    -void Vector3::generateOrthonormalBasis (Vector3& rkU, Vector3& rkV,
    -                                        Vector3& rkW, bool bUnitLengthW) {
    -    if ( !bUnitLengthW )
    -        rkW.unitize();
    -
    -    if ( G3D::abs(rkW.x) >= G3D::abs(rkW.y)
    -            && G3D::abs(rkW.x) >= G3D::abs(rkW.z) ) {
    -        rkU.x = -rkW.y;
    -        rkU.y = + rkW.x;
    -        rkU.z = 0.0;
    -    } else {
    -        rkU.x = 0.0;
    -        rkU.y = + rkW.z;
    -        rkU.z = -rkW.y;
    -    }
    -
    -    rkU.unitize();
    -    rkV = rkW.cross(rkU);
    -}
     
     //----------------------------------------------------------------------------
     
    @@ -497,8 +533,12 @@ Vector4 Vector3::yzzz() const  { return Vector4       (y, z, z, z); }
     Vector4 Vector3::zzzz() const  { return Vector4       (z, z, z, z); }
     
     
    +void serialize(const Vector3& v, class BinaryOutput& b) {
    +    v.serialize(b);
    +}
     
    -
    -
    +void deserialize(Vector3& v, class BinaryInput& b) {
    +    v.deserialize(b);
    +}
     
     } // namespace
    diff --git a/deps/g3dlite/source/Vector3int16.cpp b/deps/g3dlite/source/Vector3int16.cpp
    index 44069b85d..3c9c5dc92 100644
    --- a/deps/g3dlite/source/Vector3int16.cpp
    +++ b/deps/g3dlite/source/Vector3int16.cpp
    @@ -46,4 +46,14 @@ std::string Vector3int16::toString() const {
         return G3D::format("(%d, %d, %d)", x, y, z);
     }
     
    +    
    +Vector3int16 Vector3int16::floor(const Vector3& v) {
    +    return Vector3int16(iFloor(v.x), iFloor(v.y), iFloor(v.z));
    +}
    +
    +
    +Vector3int16 Vector3int16::ceil(const Vector3& v) {
    +    return Vector3int16(iCeil(v.x), iCeil(v.y), iCeil(v.z));
    +}
    +
     }
    diff --git a/deps/g3dlite/source/Vector3int32.cpp b/deps/g3dlite/source/Vector3int32.cpp
    index 3bd8e9f2b..a4867ba01 100644
    --- a/deps/g3dlite/source/Vector3int32.cpp
    +++ b/deps/g3dlite/source/Vector3int32.cpp
    @@ -4,7 +4,7 @@
      @author Morgan McGuire, http://graphics.cs.williams.edu
       
      @created 2008-07-01
    - @edited  2008-07-01
    + @edited  2010-10-20
      */
     
     #include "G3D/platform.h"
    @@ -15,13 +15,76 @@
     #include "G3D/BinaryInput.h"
     #include "G3D/BinaryOutput.h"
     #include "G3D/format.h"
    +#include "G3D/Vector2int32.h"
    +#include "G3D/Vector2int16.h"
    +#include "G3D/Any.h"
     
     namespace G3D {
    +Vector3int32 iFloor(const Vector3& v) {
    +    return Vector3int32(iFloor(v.x), iFloor(v.y), iFloor(v.z));
    +}
    +
    +Vector3int32::Vector3int32(const Any& any) {
    +    *this = Vector3int32();
    +    any.verifyNameBeginsWith("Vector3int32", "Point3int32");
    +    
    +    switch (any.type()) {
    +    case Any::TABLE:
    +        
    +        for (Any::AnyTable::Iterator it = any.table().begin(); it.isValid(); ++it) {
    +            const std::string& key = toLower(it->key);
    +            
    +            if (key == "x") {
    +                x = it->value;
    +            } else if (key == "y") {
    +                y = it->value;
    +            } else if (key == "z") {
    +                z = it->value;
    +            } else {
    +                any.verify(false, "Illegal key: " + it->key);
    +            }
    +        }
    +        break;
    +            
    +    case Any::ARRAY:
    +        
    +        (void)any.name();
    +        if (any.size() == 1) {
    +            x = y = z = any[0];
    +        } else {
    +            any.verifySize(3);
    +            x = any[0];
    +            y = any[1];
    +            z = any[2];
    +        }
    +        break;
    +        
    +    default:
    +        any.verify(false, "Bad Vector3int32 constructor");
    +    }
    +}
    +
    +
    +Any Vector3int32::toAny() const {
    +    Any a(Any::ARRAY, "Vector3int32");
    +    a.append(x, y, z);
    +    return a;
    +}
    +
     
     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);
    +    x = (int32)(v.x + 0.5);
    +    y = (int32)(v.y + 0.5);
    +    z = (int32)(v.z + 0.5);
    +}
    +
    +Vector3int32::Vector3int32(const class Vector2int32& v, int _z) : x(v.x), y(v.y), z(_z) {}
    +
    +Vector3int32::Vector3int32(const class Vector2int16& v, int _z) : x(v.x), y(v.y), z(_z) {}
    +
    +
    +Vector3int32 Vector3int32::truncate(const class Vector3& v) {
    +    return Vector3int32(int32(v.x), int32(v.y), int32(v.z));
     }
     
     
    @@ -54,4 +117,16 @@ std::string Vector3int32::toString() const {
         return G3D::format("(%d, %d, %d)", x, y, z);
     }
     
    +//----------------------------------------------------------------------------
    +// 2-char swizzles
    +
    +Vector2int32 Vector3int32::xx() const  { return Vector2int32       (x, x); }
    +Vector2int32 Vector3int32::yx() const  { return Vector2int32       (y, x); }
    +Vector2int32 Vector3int32::zx() const  { return Vector2int32       (z, x); }
    +Vector2int32 Vector3int32::xy() const  { return Vector2int32       (x, y); }
    +Vector2int32 Vector3int32::yy() const  { return Vector2int32       (y, y); }
    +Vector2int32 Vector3int32::zy() const  { return Vector2int32       (z, y); }
    +Vector2int32 Vector3int32::xz() const  { return Vector2int32       (x, z); }
    +Vector2int32 Vector3int32::yz() const  { return Vector2int32       (y, z); }
    +Vector2int32 Vector3int32::zz() const  { return Vector2int32       (z, z); }
     }
    diff --git a/deps/g3dlite/source/Vector4.cpp b/deps/g3dlite/source/Vector4.cpp
    index b5f23d699..0b19fa5b8 100644
    --- a/deps/g3dlite/source/Vector4.cpp
    +++ b/deps/g3dlite/source/Vector4.cpp
    @@ -4,7 +4,7 @@
      @maintainer Morgan McGuire, http://graphics.cs.williams.edu
       
      @created 2001-07-09
    - @edited  2010-07-05
    + @edited  2010-11-05
      */
     
     #include 
    @@ -21,6 +21,12 @@
     
     namespace G3D {
     
    +Vector4& Vector4::operator=(const Any& a) {
    +    *this = Vector4(a);
    +    return *this;
    +}
    +
    +
     Vector4::Vector4(const Any& any) {
         any.verifyName("Vector4");
         any.verifyType(Any::TABLE, Any::ARRAY);
    @@ -40,7 +46,8 @@ Vector4::Vector4(const Any& any) {
         }
     }
     
    -Vector4::operator Any() const {
    +
    +Any Vector4::toAny() const {
         Any any(Any::ARRAY, "Vector4");
         any.append(x, y, z, w);
         return any;
    @@ -134,7 +141,7 @@ Vector4 Vector4::operator/ (float fScalar) const {
         Vector4 kQuot;
     
         if ( fScalar != 0.0 ) {
    -		float fInvScalar = 1.0f / fScalar;
    +        float fInvScalar = 1.0f / fScalar;
             kQuot.x = fInvScalar * x;
             kQuot.y = fInvScalar * y;
             kQuot.z = fInvScalar * z;
    @@ -148,13 +155,13 @@ Vector4 Vector4::operator/ (float fScalar) const {
     //----------------------------------------------------------------------------
     Vector4& Vector4::operator/= (float fScalar) {
         if (fScalar != 0.0f) {
    -		float fInvScalar = 1.0f / fScalar;
    +        float fInvScalar = 1.0f / fScalar;
             x *= fInvScalar;
             y *= fInvScalar;
             z *= fInvScalar;
             w *= fInvScalar;
         } else {
    -		*this = Vector4::inf();
    +        *this = Vector4::inf();
         }
     
         return *this;
    @@ -511,5 +518,12 @@ Vector4 Vector4::ywww() const  { return Vector4       (y, w, w, w); }
     Vector4 Vector4::zwww() const  { return Vector4       (z, w, w, w); }
     Vector4 Vector4::wwww() const  { return Vector4       (w, w, w, w); }
     
    +void serialize(const Vector4& v, class BinaryOutput& b) {
    +    v.serialize(b);
    +}
    +
    +void deserialize(Vector4& v, class BinaryInput& b) {
    +    v.deserialize(b);
    +}
     
     }; // namespace
    diff --git a/deps/g3dlite/source/Welder.cpp b/deps/g3dlite/source/Welder.cpp
    index 2db47722e..55a888590 100644
    --- a/deps/g3dlite/source/Welder.cpp
    +++ b/deps/g3dlite/source/Welder.cpp
    @@ -1,10 +1,10 @@
     /**
    - @file Welder.cpp
    + \file Welder.cpp
     
    - @author Morgan McGuire, Kyle Whitson, Corey Taylor
    + \author Morgan McGuire, Kyle Whitson, Corey Taylor
     
    - @created 2008-07-30
    - @edited  2009-11-29
    + \created 2008-07-30
    + \edited  2011-07-04
      */
     
     #include "G3D/platform.h"
    @@ -17,9 +17,14 @@
     #include "G3D/AreaMemoryManager.h"
     #include "G3D/Any.h"
     #include "G3D/stringutils.h"
    +#include "G3D/BinaryInput.h"
    +#include "G3D/BinaryOutput.h"
     
     namespace G3D { namespace _internal{
     
    +// Uncomment to print information that can help with performance
    +// profiling.
    +//#define VERBOSE
     
     /** Used by WeldHelper2::smoothNormals. */
     class VN {
    @@ -98,11 +103,11 @@ private:
          */
         int getIndex(const Vector3& v, const Vector3& n, const Vector2& t) {
             PointHashGrid::SphereIterator it = 
    -                weldGrid.beginSphereIntersection(Sphere(v, vertexWeldRadius));
    +                weldGrid.begin(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()) {
    +            while (it.isValid()) {
                     if ((t - it->texCoord).squaredLength() <= texCoordWeldRadius2) {
                         // This is the vertex
                         return it->index;
    @@ -110,7 +115,7 @@ private:
                     ++it;
                 }
             } else {
    -            while (it.hasMore()) {
    +            while (it.isValid()) {
                     if (((n - it->normal).squaredLength() <= normalWeldRadius2) &&
                         ((t - it->texCoord).squaredLength() <= texCoordWeldRadius2)) {
                         // This is the vertex
    @@ -142,12 +147,16 @@ private:
     
          Called from process()
          */
    -    void updateTriLists(
    -        Array*>&         indexArrayArray, 
    -        const Array&       vertexArray,
    -        const Array&       normalArray,
    -        const Array&       texCoordArray) {
    -        
    +    void updateTriLists
    +    (Array*>&         indexArrayArray, 
    +     const Array&       vertexArray,
    +     const Array&       normalArray,
    +     const Array&       texCoordArray) {
    +     
    +#       ifdef VERBOSE
    +            debugPrintf("WeldHelper::updateTriLists\n");
    +#       endif
    +          
             // Compute a hash grid so that we can find neighbors quickly.
             // It begins empty and is extended as the tri lists are iterated
             // through.
    @@ -183,13 +192,17 @@ private:
         /** Expands the indexed triangle lists into a triangle list.
     
             Called from process() */
    -    void unroll(
    -        const Array*>&   indexArrayArray, 
    -        const Array&       vertexArray, 
    -        const Array&       texCoordArray, 
    -        Array&             unrolledVertexArray, 
    -        Array&             unrolledTexCoordArray) {
    +    void unroll
    +    (const Array*>&   indexArrayArray, 
    +     const Array&       vertexArray, 
    +     const Array&       texCoordArray, 
    +     Array&             unrolledVertexArray, 
    +     Array&             unrolledTexCoordArray) {
     
    +#       ifdef VERBOSE
    +            debugPrintf("WeldHelper::unroll\n");
    +#       endif
    +       
             int numTriLists = indexArrayArray.size();
             for (int t = 0; t < numTriLists; ++t) {
                 if (indexArrayArray[t] != NULL) {
    @@ -206,9 +219,12 @@ private:
         /** 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&  vertexArray, 
    -        Array&        faceNormalArray) {
    +    void computeFaceNormals
    +    (const Array&  vertexArray, 
    +     Array&        faceNormalArray) {
    +#       ifdef VERBOSE
    +            debugPrintf("WeldHelper::computeFaceNormals\n");
    +#       endif
     
             debugAssertM(vertexArray.size() % 3 == 0, "Input is not a triangle soup");
             debugAssertM(faceNormalArray.size() == 0, "Output must start empty.");
    @@ -231,17 +247,19 @@ private:
          Computes @a smoothNormalArray, whose elements are those of normalArray averaged
          with neighbors within the angular cutoff.
          */
    -    void smoothNormals(
    -        const Array& vertexArray, 
    -        const Array& normalArray, 
    -        Array&       smoothNormalArray) {
    -        
    +    void smoothNormals
    +    (const Array& vertexArray, 
    +     const Array& normalArray, 
    +     Array&       smoothNormalArray) {
             if (normalSmoothingAngle <= 0) {
                 smoothNormalArray = normalArray;
                 return;
             }
     
    -        
    +#       ifdef VERBOSE
    +            debugPrintf("WeldHelper::smoothNormals\n");
    +#       endif
    +
             // Create an area memory manager for fast deallocation
             MemoryManager::Ref mm = AreaMemoryManager::create(iRound(sizeof(VN) * normalArray.size() * 1.5));
     
    @@ -250,53 +268,110 @@ private:
             debugAssert(vertexArray.size() == normalArray.size());
             smoothNormalArray.resize(normalArray.size());
     
    -        // Compute a hash grid so that we can find neighbors quickly.
    -        PointHashGrid grid(vertexWeldRadius, mm);
    -        for (int v = 0; v < normalArray.size(); ++v) {
    -            grid.insert(VN(vertexArray[v], normalArray[v]));
    -        }
    +        if (vertexWeldRadius == 0) {
    +            // Look for vertices with the exactly identical normal only
    +#           ifdef VERBOSE
    +                debugPrintf("Taking fast path\n");
    +#           endif
     
    -        // TODO: this step could be done on multiple threads
    -        for (int v = 0; v < normalArray.size(); ++v) {            
    -            // Compute the sum of all nearby normals within the cutoff angle.
    -            // Search within the vertexWeldRadius, since those are the vertices
    -            // that will collapse to the same point.
    -            PointHashGrid::SphereIterator it = 
    -                grid.beginSphereIntersection(Sphere(vertexArray[v], vertexWeldRadius));
    +            // Maximum expected faces that meet at a vertex
    +            static const int k = 8;
     
    -            Vector3 sum;
    -
    -            const Vector3& original = normalArray[v];
    -            while (it.hasMore()) {
    -                const Vector3& N = it->normal;
    -                const float cosAngle = N.dot(original);
    -
    -                if (cosAngle > cosThresholdAngle) {
    -                    // This normal is close enough to consider.  Avoid underflow by scaling up
    -                    sum += (N * 256.0f);
    -                }
    -                ++it;
    +            // Maps vertices to the indices of normals at that vertex
    +            Table > normalTable;
    +            for (int v = 0; v < vertexArray.size(); ++v) {
    +                bool ignore = false;
    +                SmallArray& list = normalTable.getCreate(vertexArray[v], ignore);
    +                list.append(normalArray[v]);
                 }
     
    -            const Vector3& average = sum.directionOrZero();
    +            for (int v = 0; v < vertexArray.size(); ++v) {
    +                Vector3 sum;
     
    -            const bool indeterminate = average.isZero();
    -            // Never "smooth" a normal so far that it points backwards
    -            const bool backFacing    = original.dot(average) < 0;
    +                const Vector3& original = normalArray[v];
     
    -            if (indeterminate || backFacing) {
    -                // Revert to the face normal
    -                smoothNormalArray[v] = original;
    -            } else {
    -                // Average available normals
    -                smoothNormalArray[v] = average;
    +                const SmallArray& list = normalTable[vertexArray[v]];
    +
    +                for (int i = 0; i < list.size(); ++i) {
    +                    const Vector3& N = list[i];
    +                    const float cosAngle = N.dot(original);
    +
    +                    if (cosAngle > cosThresholdAngle) {
    +                        // This normal is close enough to consider.  Avoid underflow by scaling up
    +                        sum += (N * 256.0f);
    +                    }
    +                }
    +
    +                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;
    +                }
    +            }
    +
    +        } else {
    +            // Non-zero vertex normal welding
    +#           ifdef VERBOSE
    +                debugPrintf("Taking slower weld path because vertexWeldRadius = %f\n",
    +                            vertexWeldRadius);
    +#           endif
    +
    +            // Compute a hash grid so that we can find neighbors quickly.
    +            alwaysAssertM(vertexWeldRadius > 0, "Cannot smooth with zero vertex weld radius");
    +            PointHashGrid grid(vertexWeldRadius, mm);
    +            for (int v = 0; v < normalArray.size(); ++v) {
    +                grid.insert(VN(vertexArray[v], normalArray[v]));
    +            }
    +            
    +            // OPT: this step could be done on multiple threads
    +            for (int v = 0; v < normalArray.size(); ++v) {            
    +                // Compute the sum of all nearby normals within the cutoff angle.
    +                // Search within the vertexWeldRadius, since those are the vertices
    +                // that will collapse to the same point.
    +                PointHashGrid::SphereIterator it = 
    +                    grid.begin(Sphere(vertexArray[v], vertexWeldRadius));
    +                
    +                Vector3 sum;
    +                
    +                const Vector3& original = normalArray[v];
    +                while (it.isValid()) {
    +                    const Vector3& N = it->normal;
    +                    const float cosAngle = N.dot(original);
    +                    
    +                    if (cosAngle > cosThresholdAngle) {
    +                        // This normal is close enough to consider.  Avoid underflow by scaling up
    +                        sum += (N * 256.0f);
    +                    }
    +                    ++it;
    +                }
    +                
    +                const Vector3& average = sum.directionOrZero();
    +                
    +                const bool indeterminate = average.isZero();
    +                // Never "smooth" a normal so far that it points backwards
    +                const bool backFacing    = original.dot(average) < 0;
    +                
    +                if (indeterminate || backFacing) {
    +                    // Revert to the face normal
    +                    smoothNormalArray[v] = original;
    +                } else {
    +                    // Average available normals
    +                    smoothNormalArray[v] = average;
    +                }
                 }
             }
         }
     
     public:
     
    -
         /**
         Algorithm:
     
    @@ -311,14 +386,17 @@ public:
         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&     vertexArray,
    -        Array&     texCoordArray, 
    -        Array&     normalArray,
    -        Array*>& indexArrayArray,
    -        float               normAngle,
    -        float               texRadius,
    -        float               normRadius) {
    +    void process
    +    ( Array&     vertexArray,
    +      Array&     texCoordArray, 
    +      Array&     normalArray,
    +      Array*>& indexArrayArray,
    +      float               normAngle,
    +      float               texRadius,
    +      float               normRadius) {
    +#       ifdef VERBOSE
    +            debugPrintf("WeldHelper::process\n");
    +#       endif
     
             normalSmoothingAngle = normAngle;
             normalWeldRadius2    = square(normRadius);
    @@ -331,11 +409,17 @@ public:
                     "Input arrays are not parallel.");
             }
     
    +        // Create an area memory manager for fast deallocation
             Array unrolledVertexArray;
             Array unrolledFaceNormalArray;
             Array unrolledSmoothNormalArray;
             Array unrolledTexCoordArray;
     
    +        unrolledVertexArray.reserve(vertexArray.size());
    +        unrolledFaceNormalArray.reserve(vertexArray.size());
    +        unrolledSmoothNormalArray.reserve(vertexArray.size());
    +        unrolledTexCoordArray.reserve(vertexArray.size());
    +
             if (! hasTexCoords) {
                 // Generate all zero texture coordinates
                 texCoordArray.resize(vertexArray.size());
    @@ -373,23 +457,40 @@ public:
         }
     
         WeldHelper(float vertRadius) :
    -        weldGrid(vertRadius, AreaMemoryManager::create()),
    +        weldGrid(max(vertRadius, 0.1f), AreaMemoryManager::create()),
             vertexWeldRadius(vertRadius) {
         }
     
     };
     } // Internal
     
    -void Welder::weld(
    -    Array&     vertexArray,
    -    Array&     texCoordArray, 
    -    Array&     normalArray,
    -    Array*>& indexArrayArray,
    -    const Welder::Settings& settings) {
     
    -    _internal::WeldHelper(settings.vertexWeldRadius).process(
    -        vertexArray, texCoordArray, normalArray, indexArrayArray, 
    -        settings.normalSmoothingAngle, settings.textureWeldRadius, settings.normalWeldRadius);
    +void Welder::Settings::serialize(class BinaryOutput& b) const {
    +    b.writeFloat32(normalSmoothingAngle);
    +    b.writeFloat32(vertexWeldRadius);
    +    b.writeFloat32(textureWeldRadius);
    +    b.writeFloat32(normalWeldRadius);
    +}
    +
    +
    +void Welder::Settings::deserialize(class BinaryInput& b) {
    +    normalSmoothingAngle    = b.readFloat32();
    +    vertexWeldRadius        = b.readFloat32();
    +    textureWeldRadius       = b.readFloat32();
    +    normalWeldRadius        = b.readFloat32();
    +}
    +
    +
    +void Welder::weld
    +(Array&     vertexArray,
    + Array&     texCoordArray, 
    + Array&     normalArray,
    + Array*>& indexArrayArray,
    + const Welder::Settings& settings) {
    +
    +    _internal::WeldHelper(settings.vertexWeldRadius).process
    +        (vertexArray, texCoordArray, normalArray, indexArrayArray, 
    +         settings.normalSmoothingAngle, settings.textureWeldRadius, settings.normalWeldRadius);
             
     }
     
    @@ -397,7 +498,7 @@ void Welder::weld(
     Welder::Settings::Settings(const Any& any) {
         *this = Settings();
         any.verifyName("Welder::Settings");
    -    for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
    +    for (Any::AnyTable::Iterator it = any.table().begin(); it.isValid(); ++it) {
             const std::string& key = toLower(it->key);
             if (key == "normalsmoothingangle") {
                 normalSmoothingAngle = it->value;
    @@ -413,12 +514,13 @@ Welder::Settings::Settings(const Any& any) {
         }
     }
     
    -Welder::Settings::operator Any() const {
    +
    +Any Welder::Settings::toAny() const {
         Any a(Any::TABLE, "Welder::Settings");
    -    a.set("normalSmoothingAngle", normalSmoothingAngle);
    -    a.set("vertexWeldRadius", vertexWeldRadius);
    -    a.set("textureWeldRadius", textureWeldRadius);
    -    a.set("normalWeldRadius", normalWeldRadius);
    +    a["normalSmoothingAngle"]   = normalSmoothingAngle;
    +    a["vertexWeldRadius"]       = vertexWeldRadius;
    +    a["textureWeldRadius"]      = textureWeldRadius;
    +    a["normalWeldRadius"]       = normalWeldRadius;
         return a;
     }
     
    diff --git a/deps/g3dlite/source/WinMain.cpp b/deps/g3dlite/source/WinMain.cpp
    index 3cee71084..197530060 100644
    --- a/deps/g3dlite/source/WinMain.cpp
    +++ b/deps/g3dlite/source/WinMain.cpp
    @@ -6,7 +6,7 @@
     
     #include "G3D/platform.h"
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     
     #include 
     #include 
    diff --git a/deps/g3dlite/source/XML.cpp b/deps/g3dlite/source/XML.cpp
    index 51f1a549b..f347548b2 100644
    --- a/deps/g3dlite/source/XML.cpp
    +++ b/deps/g3dlite/source/XML.cpp
    @@ -7,7 +7,7 @@
      \created 2010-02-11
      \edited  2010-02-24
     
    - Copyright 2000-2010, Morgan McGuire.
    + Copyright 2000-2012, Morgan McGuire.
      All rights reserved.
      */
     
    @@ -68,7 +68,7 @@ void XML::serialize(TextOutput& t) const {
             t.writeSymbol(m_value);
         } else {
             t.printf("<%s", m_name.c_str());
    -        for (AttributeTable::Iterator it = m_attribute.begin(); it.hasMore(); ++it) {
    +        for (AttributeTable::Iterator it = m_attribute.begin(); it.isValid(); ++it) {
                 t.printf(" %s=\"%s\"", it->key.c_str(), it->value.m_value.c_str());
             }
             t.printf(">");
    diff --git a/deps/g3dlite/source/constants.cpp b/deps/g3dlite/source/constants.cpp
    index 9ee3eb873..53a33faa8 100644
    --- a/deps/g3dlite/source/constants.cpp
    +++ b/deps/g3dlite/source/constants.cpp
    @@ -11,6 +11,34 @@
     
     namespace G3D {
     
    +    const char* PrimitiveType::toString(int i, Value& v) {
    +        static const char* str[] = {"POINTS", "LINES", "LINE_STRIP", "TRIANGLES", "TRIANGLE_FAN", "QUADS", "QUAD_STRIP", NULL}; 
    +        static const Value val[] = {POINTS, LINES, LINE_STRIP, TRIANGLES, TRIANGLE_FAN, QUADS, QUAD_STRIP};
    +        const char* s = str[i];
    +        if (s) {
    +            v = val[i];
    +        }
    +        return s; 
    +    }
     
    +    const char* RefractionQuality::toString(int i, Value& v) {
    +        static const char* str[] = {"NONE", "STATIC_ENV", "DYNAMIC_FLAT", "DYNAMIC_FLAT_MULTILAYER", "DYNAMIC_ENV", "BEST", NULL}; 
    +        static const Value val[] = {NONE, STATIC_ENV, DYNAMIC_FLAT, DYNAMIC_FLAT_MULTILAYER, DYNAMIC_ENV, BEST};
    +        const char* s = str[i];
    +        if (s) {
    +            v = val[i];
    +        }
    +        return s;
    +    }
    +
    +    const char* MirrorQuality::toString(int i, Value& v) {
    +        static const char* str[] = {"NONE", "STATIC_ENV", "DYNAMIC_PLANAR", "DYNAMIC_ENV", "BEST", NULL}; 
    +        static const Value val[] = {NONE, STATIC_ENV, DYNAMIC_PLANAR, DYNAMIC_ENV, BEST};
    +        const char* s = str[i];
    +        if (s) {
    +            v = val[i];
    +        }
    +        return s;
    +    }
     
     } // G3D
    diff --git a/deps/g3dlite/source/debugAssert.cpp b/deps/g3dlite/source/debugAssert.cpp
    index 41aad02c6..cfccf9a0c 100644
    --- a/deps/g3dlite/source/debugAssert.cpp
    +++ b/deps/g3dlite/source/debugAssert.cpp
    @@ -11,7 +11,7 @@
     
     #include "G3D/debugAssert.h"
     #include "G3D/platform.h"
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         #include 
     #endif
     #include "G3D/format.h"
    @@ -44,7 +44,7 @@ AssertionHook _failureHook = _handleErrorCheck_;
     #endif
     
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     static void postToClipboard(const char *text) {
         if (OpenClipboard(NULL)) {
             HGLOBAL hMem = GlobalAlloc(GHND | GMEM_DDESHARE, strlen(text) + 1);
    @@ -77,7 +77,7 @@ static void createErrorMessage(
         std::string le = "";
         const char* newline = "\n";
     
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
             newline = "\r\n";
     
             // The last error value.  (Which is preserved across the call).
    @@ -106,9 +106,9 @@ static void createErrorMessage(
                 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);
    -		}
    +        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) {
    @@ -121,6 +121,8 @@ static void createErrorMessage(
             const char* moduleName = strrchr(modulePath, '\\');
             outTitle = outTitle + string(" - ") + string(moduleName ? (moduleName + 1) : modulePath);
     
    +    #else
    +        (void)outTitle;
         #endif
     
         // Build the message.
    @@ -142,7 +144,7 @@ bool _handleDebugAssert_(
         std::string dialogText = "";
         createErrorMessage(expression, message, filename, lineNumber, dialogTitle, dialogText);
     
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
             DWORD lastErr = GetLastError();
             postToClipboard(dialogText.c_str());
             debugPrintf("\n%s\n", dialogText.c_str());
    @@ -159,7 +161,7 @@ bool _handleDebugAssert_(
     
         int result = G3D::prompt(dialogTitle.c_str(), dialogText.c_str(), (const char**)choices, 3, useGuiPrompt);
     
    -#    ifdef G3D_WIN32
    +#    ifdef G3D_WINDOWS
             // Put the incoming last error back.
             SetLastError(lastErr);
     #    endif
    @@ -200,7 +202,7 @@ bool _handleErrorCheck_(
     
         // Log the error
         Log::common()->print(std::string("\n**************************\n\n") + dialogTitle + "\n" + dialogText);
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
             DWORD lastErr = GetLastError();
             (void)lastErr;
             postToClipboard(dialogText.c_str());
    @@ -212,7 +214,7 @@ bool _handleErrorCheck_(
         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;
    +            Log::getCommonLogFilename() + "\".\n\n" + dialogText;
     
         int result = G3D::prompt("Error", m.c_str(), (const char**)choices, 1, useGuiPrompt);
         (void)result;
    @@ -221,7 +223,7 @@ bool _handleErrorCheck_(
     }
     
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     static HCURSOR oldCursor;
     static RECT    oldCursorRect;
     static POINT   oldCursorPos;
    @@ -229,7 +231,7 @@ static int     oldShowCursorCount;
     #endif
     
     void _releaseInputGrab_() {
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
     
             GetCursorPos(&oldCursorPos);
     
    @@ -275,7 +277,7 @@ void _releaseInputGrab_() {
     
     
     void _restoreInputGrab_() {
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
     
             // Restore the old clipping region
             ClipCursor(&oldCursorRect);
    @@ -307,7 +309,7 @@ void setAssertionHook(AssertionHook hook) {
     }
     
     AssertionHook assertionHook() {
    -    return 	G3D::_internal::_debugHook;
    +    return     G3D::_internal::_debugHook;
     }
     
     void setFailureHook(AssertionHook hook) {
    @@ -329,7 +331,7 @@ ConsolePrintHook consolePrintHook() {
     
     
     std::string __cdecl debugPrint(const std::string& s) {
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
             const int MAX_STRING_LEN = 1024;
         
             // Windows can't handle really long strings sent to
    diff --git a/deps/g3dlite/source/fileutils.cpp b/deps/g3dlite/source/fileutils.cpp
    index 1867bf333..f5310084c 100644
    --- a/deps/g3dlite/source/fileutils.cpp
    +++ b/deps/g3dlite/source/fileutils.cpp
    @@ -25,7 +25,7 @@
         #include "zip.h"
     #endif
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
        // Needed for _getcwd
        #include 
        #include 
    @@ -63,7 +63,7 @@ std::string resolveFilename(const std::string& filename) {
                 return filename;
             } else {
     
    -            #ifdef G3D_WIN32
    +            #ifdef G3D_WINDOWS
                     if ((filename.size() >= 2) && (filename[1] == ':')) {
                         // There is a drive spec on the front.
                         if ((filename.size() >= 3) && ((filename[2] == '\\') || 
    @@ -86,36 +86,43 @@ std::string resolveFilename(const std::string& filename) {
         char buffer[1024];
     
         // Prepend the working directory.
    -    _getcwd(buffer, 1024);
    +    (void)_getcwd(buffer, 1024);
     
         return format("%s/%s", buffer, filename.c_str());
     }
     
     bool zipfileExists(const std::string& filename) {
    -	std::string	outZipfile;
    -	std::string	outInternalFile;
    +    std::string    outZipfile;
    +    std::string    outInternalFile;
         return zipfileExists(filename, outZipfile, outInternalFile);
     }
     
    -std::string readWholeFile(
    -    const std::string& filename) {
     
    -    _internal::currentFilesUsed.insert(filename);
    +std::string readWholeFile(const std::string& filename) {
     
         std::string s;
     
         debugAssert(filename != "");
    -    debugAssertM(FileSystem::exists(filename), filename + " not found");
    +    if (!  FileSystem::exists(filename)) {
    +        throw (filename + " not found");
    +    }
    +    FileSystem::markFileUsed(filename);
    +    std::string zipfile;
    +
    +    if (! FileSystem::inZipfile(filename, zipfile)) {
    +        // Not in zipfile
    +        if (! FileSystem::exists(filename)) {
    +            throw FileNotFound(filename, std::string("File not found in readWholeFile: ") + filename);
    +        }
     
    -    if (! FileSystem::inZipfile(filename)) {
             int64 length = FileSystem::size(filename);
     
             char* buffer = (char*)System::alignedMalloc(length + 1, 16);
             debugAssert(buffer);
             FILE* f = FileSystem::fopen(filename.c_str(), "rb");
             debugAssert(f);
    -        int ret = fread(buffer, 1, length, f);
    -	    debugAssert(ret == length);(void)ret;
    +        int64 ret = fread(buffer, 1, length, f);
    +        debugAssert(ret == length);(void)ret;
             FileSystem::fclose(f);
     
             buffer[length] = '\0';    
    @@ -123,60 +130,43 @@ std::string readWholeFile(
     
             System::alignedFree(buffer);
     
    -    } else if (zipfileExists(filename)) {
    +    } else {
     
    -        void* zipBuffer;
    -        size_t length;
    -        zipRead(filename, zipBuffer, length);
    +        // In zipfile
    +        FileSystem::markFileUsed(zipfile);
     
    -        char* buffer = (char*)System::alignedMalloc(length + 1, 16);
    -        System::memcpy(buffer,zipBuffer, length + 1);
    -        zipClose(zipBuffer);
    -
    -        buffer[length] = '\0';
    -        s = std::string(buffer);
    -        System::alignedFree(buffer);
    -    }
    -
    -    return s;
    -}
    -
    -
    -void zipRead(const std::string& file,
    -             void*& data,
    -             size_t& length) {
    -    std::string zip, desiredFile;
     #if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */    
    -    if (zipfileExists(file, zip, desiredFile)) {
    -        struct zip *z = zip_open( zip.c_str(), ZIP_CHECKCONS, NULL );
    +        // Zipfiles require Unix-style slashes
    +        std::string internalFile = FilePath::canonicalize(filename.substr(zipfile.length() + 1));
    +        struct zip* z = zip_open(zipfile.c_str(), ZIP_CHECKCONS, NULL);
             {
                 struct zip_stat info;
                 zip_stat_init( &info );    // TODO: Docs unclear if zip_stat_init is required.
    -            zip_stat( z, desiredFile.c_str(), ZIP_FL_NOCASE, &info );
    -            length = info.size;
    -            // sets machines up to use MMX, if they want
    -            data = System::alignedMalloc(length, 16);
    -            struct zip_file *zf = zip_fopen( z, desiredFile.c_str(), ZIP_FL_NOCASE );
    -            {
    -                int test = zip_fread( zf, data, length );
    -                debugAssertM((size_t)test == length,
    -                             desiredFile + " was corrupt because it unzipped to the wrong size.");
    -                (void)test;
    +            zip_stat(z, internalFile.c_str(), ZIP_FL_NOCASE, &info);
    +
    +            // Add NULL termination
    +            char* buffer = reinterpret_cast(System::alignedMalloc(info.size + 1, 16));
    +            buffer[info.size] = '\0';
    +
    +            struct zip_file* zf = zip_fopen( z, internalFile.c_str(), ZIP_FL_NOCASE );
    +            if (zf == NULL) {
    +                throw std::string("\"") + internalFile + "\" inside \"" + zipfile + "\" could not be opened.";
    +            } else {
    +                const int64 bytesRead = zip_fread( zf, buffer, (info.size));
    +                debugAssertM((int64)bytesRead == (int64)info.size,
    +                             internalFile + " was corrupt because it unzipped to the wrong size.");
    +                (void)bytesRead;
    +                zip_fclose( zf );
                 }
    -            zip_fclose( zf );
    +            // Copy the string
    +            s = buffer;
    +            System::alignedFree(buffer);
             }
             zip_close( z );
    -    } else {
    -        data = NULL;
    -    }
    -#else
    -    data = NULL;
     #endif
    -}
    +    }
     
    -
    -void zipClose(void* data) {
    -	System::alignedFree(data);
    +    return s;
     }
     
     
    @@ -186,25 +176,25 @@ int64 fileLength(const std::string& filename) {
         
         if (result == -1) {
     #if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
    -		std::string zip, contents;
    -		if(zipfileExists(filename, zip, contents)){
    -			int64 requiredMem;
    +        std::string zip, contents;
    +        if(zipfileExists(filename, zip, contents)){
    +            int64 requiredMem;
     
                             struct zip *z = zip_open( zip.c_str(), ZIP_CHECKCONS, NULL );
                             debugAssertM(z != NULL, zip + ": zip open failed.");
    -			{
    +            {
                                     struct zip_stat info;
                                     zip_stat_init( &info );    // TODO: Docs unclear if zip_stat_init is required.
                                     int success = zip_stat( z, contents.c_str(), ZIP_FL_NOCASE, &info );
    -				(void)success;
    +                (void)success;
                                     debugAssertM(success == 0, zip + ": " + contents + ": zip stat failed.");
                                     requiredMem = info.size;
    -			}
    +            }
                             zip_close( z );
    -			return requiredMem;
    -		} else {
    +            return requiredMem;
    +        } else {
             return -1;
    -		}
    +        }
     #else
             return -1;
     #endif
    @@ -251,9 +241,9 @@ void writeWholeFile(
     void createDirectory(
         const std::string&  dir) {
         
    -	if (dir == "") {
    -		return;
    -	}
    +    if (dir == "") {
    +        return;
    +    }
     
         std::string d;
     
    @@ -292,11 +282,11 @@ void createDirectory(
             if (! FileSystem::exists(p)) {
                 // Windows only requires one argument to mkdir,
                 // where as unix also requires the permissions.
    -#           ifndef G3D_WIN32
    +#           ifndef G3D_WINDOWS
                     mkdir(p.c_str(), 0777);
    -#	        else
    +#            else
                     _mkdir(p.c_str());
    -#	        endif
    +#            endif
             }
         }
     }
    @@ -308,39 +298,40 @@ void createDirectory(
     /* Helper methods for zipfileExists()*/
     // Given a string (the drive) and an array (the path), computes the directory
     static void _zip_resolveDirectory(std::string& completeDir, const std::string& drive, const Array& path, const int length){
    -	completeDir = drive;
    -	int tempLength;
    -	// if the given length is longer than the array, we correct it
    -	if(length > path.length()){
    -		tempLength = path.length();
    -	} else{
    -		tempLength = length;
    -	}
    +    completeDir = drive;
    +    int tempLength;
    +    // if the given length is longer than the array, we correct it
    +    if(length > path.length()){
    +        tempLength = path.length();
    +    } else{
    +        tempLength = length;
    +    }
     
    -	for(int t = 0; t < tempLength; ++t){
    -		if(t > 0){
    -			completeDir += "/";
    -		}
    -		completeDir += path[t];
    -	}
    +    for(int t = 0; t < tempLength; ++t){
    +        if(t > 0){
    +            completeDir += "/";
    +        }
    +        completeDir += path[t];
    +    }
     }
     
     
    -// assumes that zipDir references a .zip file
    +/** assumes that zipDir references a .zip file */
     static bool _zip_zipContains(const std::string& zipDir, const std::string& desiredFile){
             struct zip *z = zip_open( zipDir.c_str(), ZIP_CHECKCONS, NULL );
    -	//the last parameter, an int, determines case sensitivity:
    -	//1 is sensitive, 2 is not, 0 is default
    +    //the last parameter, an int, determines case sensitivity:
    +    //1 is sensitive, 2 is not, 0 is default
             int test = zip_name_locate( z, desiredFile.c_str(), ZIP_FL_NOCASE );
             zip_close( z );
    -	if(test == -1){
    -		return false;
    -	}
    -	return true;
    +    if(test == -1){
    +        return false;
    +    }
    +    return true;
     }
     #endif
     
    -// If no zipfile exists, outZipfile and outInternalFile are unchanged
    +
    +/** If no zipfile exists, outZipfile and outInternalFile are unchanged */
     bool zipfileExists(const std::string& filename, std::string& outZipfile,
                        std::string& outInternalFile){
     #if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
    @@ -355,7 +346,7 @@ bool zipfileExists(const std::string& filename, std::string& outZipfile,
             infile = base + ext;
         }
         
    -    // Remove "." from path
    +    // Remove all standalone single dots (".") from path
         for (int i = 0; i < path.length(); ++i) {
             if (path[i] == ".") {
                 path.remove(i);
    @@ -363,7 +354,7 @@ bool zipfileExists(const std::string& filename, std::string& outZipfile,
             }
         }
         
    -    // Remove ".." from path
    +    // Remove non-leading ".." from path
         for (int i = 1; i < path.length(); ++i) {
             if ((path[i] == "..") && (i > 0) && (path[i - 1] != "..")) {
                 // Remove both i and i - 1
    @@ -405,11 +396,15 @@ bool zipfileExists(const std::string& filename, std::string& outZipfile,
             }
             
         }
    +#else
    +    (void)filename;
    +    (void)outZipfile;
    +    (void)outInternalFile;
     #endif
         // not a valid directory structure ever, 
         // obviously no .zip was found within the path 
         return false;
    -}	
    +}    
     
     ///////////////////////////////////////////////////////////////////////////////
     
    @@ -418,11 +413,14 @@ std::string generateFilenameBase(const std::string& prefix, const std::string& s
     
         // Note "template" is a reserved word in C++
         std::string templat = prefix + System::currentDateString() + "_";
    -    FileSystem::getFiles(templat + "*", exist);
    +    FileSystem::getFiles(templat + "*", exist, true);
         
         // Remove extensions
         for (int i = 0; i < exist.size(); ++i) {
    -        exist[i] = filenameBase(exist[i]);
    +        const std::string ext = FilePath::ext(exist[i]);
    +        if (ext.length() > 0) {
    +            exist[i] = exist[i].substr(0, exist[i].length() - ext.length() - 1);
    +        }
         }
     
         int num = 0;
    @@ -442,7 +440,7 @@ void copyFile(
         const std::string&          source,
         const std::string&          dest) {
     
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
             CopyFileA(source.c_str(), dest.c_str(), FALSE);
         #else
             // TODO: don't use BinaryInput and BinaryOutput
    @@ -492,7 +490,7 @@ void parseFilename(
     
             }
     
    -    } else if ((f.size() >= 2) & isSlash(f[0]) && isSlash(f[1])) {
    +    } else if ((f.size() >= 2) && isSlash(f[0]) && isSlash(f[1])) {
             
             // e.g. //foo
             root = f.substr(0, 2);
    @@ -512,7 +510,7 @@ void parseFilename(
     
             if (i != std::string::npos) {
                 // Make sure it is after the last slash!
    -            size_t j = iMax(f.rfind('/'), f.rfind('\\'));
    +            size_t j = maxNotNPOS(f.rfind('/'), f.rfind('\\'));
                 if ((j == std::string::npos) || (i > j)) {
                     ext = f.substr(i + 1, f.size() - i - 1);
                     f = f.substr(0, i);
    @@ -523,7 +521,7 @@ void parseFilename(
         // Pull the basename off
         {
             // Find the last slash
    -        size_t i = iMax(f.rfind('/'), f.rfind('\\'));
    +        size_t i = maxNotNPOS(f.rfind('/'), f.rfind('\\'));
             
             if (i == std::string::npos) {
                 
    @@ -556,7 +554,7 @@ void parseFilename(
                 j = f.size();
             }
     
    -        cur = iMin(i, j);
    +        cur = min(i, j);
     
             if (cur == std::string::npos) {
                 cur = f.size();
    @@ -576,9 +574,9 @@ void parseFilename(
      @param includePath     If true, the names include paths
      */
     static void getFileOrDirListNormal
    -(const std::string&	filespec,
    - Array&	files,
    - bool			wantFiles,
    +(const std::string&    filespec,
    + Array&    files,
    + bool            wantFiles,
      bool                   includePath) {
         
         bool test = wantFiles ? true : false;
    @@ -614,11 +612,11 @@ static void getFileOrDirListNormal
             path = path.substr(0, path.size() - 1);
         }
     
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
         {
            struct _finddata_t fileinfo;
     
    -        long handle = _findfirst(filespec.c_str(), &fileinfo);
    +        long handle = (long)_findfirst(filespec.c_str(), &fileinfo);
             int result = handle;
     
             while (result != -1) {
    @@ -695,10 +693,10 @@ static void getFileOrDirListNormal
      */
     static void _zip_addEntry(const std::string& path,
                               const std::string& prefix,
    -						  const std::string& file,
    -						  Set& files,
    -						  bool wantFiles,
    -						  bool includePath) {
    +                          const std::string& file,
    +                          Set& files,
    +                          bool wantFiles,
    +                          bool includePath) {
     
         // Make certain we are within the desired parent folder (prefix)
         if (beginsWith(file, prefix)) {
    @@ -740,6 +738,7 @@ static void _zip_addEntry(const std::string& path,
     }
     #endif
     
    +
     static void getFileOrDirListZip(const std::string& path,
                                     const std::string& prefix,
                                     Array& files,
    @@ -761,18 +760,24 @@ static void getFileOrDirListZip(const std::string& path,
         zip_close( z );
         
         fileSet.getMembers(files);
    +#else
    +    (void)path;
    +    (void)prefix;
    +    (void)files;
    +    (void)wantFiles;
    +    (void)includePath;
     #endif
     }
     
     
     static void determineFileOrDirList(
    -	const std::string&			filespec,
    -	Array&			files,
    -	bool						wantFiles,
    -	bool						includePath) {
    +    const std::string&            filespec,
    +    Array&            files,
    +    bool                        wantFiles,
    +    bool                        includePath) {
     
    -	// if it is a .zip, prefix will specify the folder within
    -	// whose contents we want to see
    +    // if it is a .zip, prefix will specify the folder within
    +    // whose contents we want to see
         std::string prefix = "";
         std::string path = filenamePath(filespec);
     
    @@ -800,39 +805,39 @@ static void determineFileOrDirList(
     }
     
     
    -void getFiles(const std::string&			filespec,
    -              Array&			files,
    -              bool					includePath) {
    +void getFiles(const std::string&            filespec,
    +              Array&            files,
    +              bool                    includePath) {
         
         determineFileOrDirList(filespec, files, true, includePath);
     }
     
     
     void getDirs(
    -	const std::string&			filespec,
    -	Array&			files,
    -	bool						includePath) {
    +    const std::string&            filespec,
    +    Array&            files,
    +    bool                        includePath) {
     
    -	determineFileOrDirList(filespec, files, false, includePath);
    +    determineFileOrDirList(filespec, files, false, includePath);
     }
     
     
     std::string filenameBaseExt(const std::string& filename) {
    -    int i = filename.rfind("/");
    -    int j = filename.rfind("\\");
    +    size_t i = filename.rfind("/");
    +    size_t j = filename.rfind("\\");
     
    -    if ((j > i) && (j >= 0)) {
    +    if ((j > i) && (j != std::string::npos)) {
             i = j;
         }
     
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
             j = filename.rfind(":");
    -        if ((i == -1) && (j >= 0)) {
    +        if ((i == std::string::npos) && (j != std::string::npos)) {
                 i = j;
             }
     #   endif
     
    -    if (i == -1) {
    +    if (i == std::string::npos) {
             return filename;
         } else {
             return filename.substr(i + 1, filename.length() - i);
    @@ -852,8 +857,8 @@ std::string filenameBase(const std::string& s) {
     
     
     std::string filenameExt(const std::string& filename) {
    -    int i = filename.rfind(".");
    -    if (i >= 0) {
    +    size_t i = filename.rfind(".");
    +    if (i != std::string::npos) {
             return filename.substr(i + 1, filename.length() - i);
         } else {
             return "";
    @@ -862,21 +867,21 @@ std::string filenameExt(const std::string& filename) {
     
     
     std::string filenamePath(const std::string& filename) {
    -    int i = filename.rfind("/");
    -    int j = filename.rfind("\\");
    +    size_t i = filename.rfind("/");
    +    size_t j = filename.rfind("\\");
     
    -    if ((j > i) && (j >= 0)) {
    +    if ((j > i) && (j != std::string::npos)) {
             i = j;
         }
     
    -#   ifdef G3D_WIN32
    +#   ifdef G3D_WINDOWS
             j = filename.rfind(":");
    -        if ((i == -1) && (j >= 0)) {
    +        if ((i == std::string::npos) && (j != std::string::npos)) {
                 i = j;
             }
     #   endif
     
    -    if (i == -1) {
    +    if (i == std::string::npos) {
             return "";
         } else {
             return filename.substr(0, i+1);
    @@ -886,23 +891,23 @@ std::string filenamePath(const std::string& filename) {
     
     bool isZipfile(const std::string& filename) {
     
    -	FILE* f = fopen(filename.c_str(), "r");
    -	if (f == NULL) {
    -		return false;
    -	}
    -	uint8 header[4];
    -	fread(header, 4, 1, f);
    -	
    -	const uint8 zipHeader[4] = {0x50, 0x4b, 0x03, 0x04};
    -	for (int i = 0; i < 4; ++i) {
    -		if (header[i] != zipHeader[i]) {
    -			fclose(f);
    -			return false;
    -		}
    -	}
    +    FILE* f = fopen(filename.c_str(), "r");
    +    if (f == NULL) {
    +        return false;
    +    }
    +    uint8 header[4];
    +    (void)fread(header, 4, 1, f);
    +    
    +    const uint8 zipHeader[4] = {0x50, 0x4b, 0x03, 0x04};
    +    for (int i = 0; i < 4; ++i) {
    +        if (header[i] != zipHeader[i]) {
    +            fclose(f);
    +            return false;
    +        }
    +    }
     
    -	fclose(f);
    -	return true;
    +    fclose(f);
    +    return true;
     }
     
     
    @@ -928,15 +933,8 @@ bool fileIsNewer(const std::string& src, const std::string& dst) {
         return sexists && ((! dexists) || (sts.st_mtime > dts.st_mtime));
     }
     
    -
    -Array filesUsed() {
    -    Array f;
    -    _internal::currentFilesUsed.getMembers(f);
    -    return f;
     }
     
    -}
    -
    -#ifndef G3D_WIN32
    +#ifndef G3D_WINDOWS
       #undef _stat
     #endif
    diff --git a/deps/g3dlite/source/format.cpp b/deps/g3dlite/source/format.cpp
    index d9d1b5163..b77b30c73 100644
    --- a/deps/g3dlite/source/format.cpp
    +++ b/deps/g3dlite/source/format.cpp
    @@ -43,7 +43,7 @@ std::string vformat(const char *fmt, va_list argPtr) {
         // allocate it on the stack because this saves
         // the malloc/free time.
         const int bufSize = 161;
    -	char stackBuffer[bufSize];
    +    char stackBuffer[bufSize];
     
         // MSVC does not support va_copy
         int actualSize = _vscprintf(fmt, argPtr) + 1;
    @@ -83,12 +83,12 @@ std::string vformat(const char *fmt, va_list argPtr) {
         // allocate it on the stack because this saves
         // the malloc/free time.
         const int bufSize = 161;
    -	char stackBuffer[bufSize];
    +    char stackBuffer[bufSize];
     
    -	// MSVC6 doesn't support va_copy, however it also seems to compile
    -	// correctly if we just pass our argument list along.  Note that 
    -	// this whole code block is only compiled if we're on MSVC6 anyway
    -	int actualWritten = _vsnprintf(stackBuffer, bufSize, fmt, argPtr);
    +    // 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) {
    diff --git a/deps/g3dlite/source/g3dfnmatch.cpp b/deps/g3dlite/source/g3dfnmatch.cpp
    index 2d24c4126..1902d71fc 100644
    --- a/deps/g3dlite/source/g3dfnmatch.cpp
    +++ b/deps/g3dlite/source/g3dfnmatch.cpp
    @@ -1,10 +1,10 @@
     /* $Id: g3dfnmatch.cpp,v 1.3 2010/03/15 05:01:23 morgan3d Exp $ */
     
    -/*	$OpenBSD: fnmatch.c,v 1.7 2000/03/23 19:13:51 millert Exp $	*/
    +/*    $OpenBSD: fnmatch.c,v 1.7 2000/03/23 19:13:51 millert Exp $    */
     
     /*
      * Copyright (c) 1989, 1993, 1994
    - *	The Regents of the University of California.  All rights reserved.
    + *    The Regents of the University of California.  All rights reserved.
      *
      * This code is derived from software contributed to Berkeley by
      * Guido van Rossum.
    @@ -19,8 +19,8 @@
      *    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.
    + *    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.
    @@ -39,7 +39,7 @@
      */
     #include "G3D/g3dfnmatch.h"
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     
     #include 
     #include 
    @@ -47,166 +47,166 @@
     
     namespace G3D {
     
    -#define	EOS	'\0'
    +#define    EOS    '\0'
     
    -#define	RANGE_MATCH	1
    -#define	RANGE_NOMATCH	0
    -#define	RANGE_ERROR	(-1)
    +#define    RANGE_MATCH    1
    +#define    RANGE_NOMATCH    0
    +#define    RANGE_ERROR    (-1)
     
     static int rangematch(const char *, char, int, char **);
     
     int
     g3dfnmatch(const char *pattern, const char *string, int flags)
     {
    -	const char *stringstart;
    -	char *newp;
    -	char c, test;
    +    const char *stringstart;
    +    char *newp;
    +    char c, test;
     
    -	for (stringstart = string;;)
    -		switch (c = *pattern++) {
    -		case EOS:
    -			if ((flags & FNM_LEADING_DIR) && *string == '/')
    -				return (0);
    -			return (*string == EOS ? 0 : FNM_NOMATCH);
    -		case '?':
    -			if (*string == EOS)
    -				return (FNM_NOMATCH);
    -			if (*string == '/' && (flags & FNM_PATHNAME))
    -				return (FNM_NOMATCH);
    -			if (*string == '.' && (flags & FNM_PERIOD) &&
    -			    (string == stringstart ||
    -			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
    -				return (FNM_NOMATCH);
    -			++string;
    -			break;
    -		case '*':
    -			c = *pattern;
    -			/* Collapse multiple stars. */
    -			while (c == '*')
    -				c = *++pattern;
    +    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);
    +            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;
    -			}
    +            /* Optimize for pattern with * at end or before /. */
    +            if (c == EOS) {
    +                if (flags & FNM_PATHNAME)
    +                    return ((flags & FNM_LEADING_DIR) ||
    +                        strchr(string, '/') == NULL ?
    +                        0 : FNM_NOMATCH);
    +                else
    +                    return (0);
    +            } else if (c == '/' && (flags & FNM_PATHNAME)) {
    +                if ((string = strchr(string, '/')) == NULL)
    +                    return (FNM_NOMATCH);
    +                break;
    +            }
     
    -			/* General case, use recursion. */
    -			while ((test = *string) != EOS) {
    -				if (!g3dfnmatch(pattern, string, flags & ~FNM_PERIOD))
    -					return (0);
    -				if (test == '/' && (flags & FNM_PATHNAME))
    -					break;
    -				++string;
    -			}
    -			return (FNM_NOMATCH);
    -		case '[':
    -			if (*string == EOS)
    -				return (FNM_NOMATCH);
    -			if (*string == '/' && (flags & FNM_PATHNAME))
    -				return (FNM_NOMATCH);
    -			if (*string == '.' && (flags & FNM_PERIOD) &&
    -			    (string == stringstart ||
    -			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
    -				return (FNM_NOMATCH);
    +            /* General case, use recursion. */
    +            while ((test = *string) != EOS) {
    +                if (!g3dfnmatch(pattern, string, flags & ~FNM_PERIOD))
    +                    return (0);
    +                if (test == '/' && (flags & FNM_PATHNAME))
    +                    break;
    +                ++string;
    +            }
    +            return (FNM_NOMATCH);
    +        case '[':
    +            if (*string == EOS)
    +                return (FNM_NOMATCH);
    +            if (*string == '/' && (flags & FNM_PATHNAME))
    +                return (FNM_NOMATCH);
    +            if (*string == '.' && (flags & FNM_PERIOD) &&
    +                (string == stringstart ||
    +                ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
    +                return (FNM_NOMATCH);
     
    -			switch (rangematch(pattern, *string, flags, &newp)) {
    -			case RANGE_ERROR:
    -				/* not a good range, treat as normal text */
    -				goto normal;
    -			case RANGE_MATCH:
    -				pattern = newp;
    -				break;
    -			case RANGE_NOMATCH:
    -				return (FNM_NOMATCH);
    -			}
    -			++string;
    -			break;
    -		case '\\':
    -			if (!(flags & FNM_NOESCAPE)) {
    -				if ((c = *pattern++) == EOS) {
    -					c = '\\';
    -					--pattern;
    -				}
    -			}
    -			/* FALLTHROUGH */
    -		default:
    -		normal:
    -			if (c != *string && !((flags & FNM_CASEFOLD) &&
    -				 (tolower((unsigned char)c) ==
    -				 tolower((unsigned char)*string))))
    -				return (FNM_NOMATCH);
    -			++string;
    -			break;
    -		}
    -	/* NOTREACHED */
    +            switch (rangematch(pattern, *string, flags, &newp)) {
    +            case RANGE_ERROR:
    +                /* not a good range, treat as normal text */
    +                goto normal;
    +            case RANGE_MATCH:
    +                pattern = newp;
    +                break;
    +            case RANGE_NOMATCH:
    +                return (FNM_NOMATCH);
    +            }
    +            ++string;
    +            break;
    +        case '\\':
    +            if (!(flags & FNM_NOESCAPE)) {
    +                if ((c = *pattern++) == EOS) {
    +                    c = '\\';
    +                    --pattern;
    +                }
    +            }
    +            /* FALLTHROUGH */
    +        default:
    +        normal:
    +            if (c != *string && !((flags & FNM_CASEFOLD) &&
    +                 (tolower((unsigned char)c) ==
    +                 tolower((unsigned char)*string))))
    +                return (FNM_NOMATCH);
    +            ++string;
    +            break;
    +        }
    +    /* NOTREACHED */
     }
     
     static int
     rangematch(const char *pattern, char test, int flags, char **newp)
     {
    -	int negate, ok;
    -	char c, c2;
    +    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;
    +    /*
    +     * 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);
    +    if (flags & FNM_CASEFOLD)
    +        test = tolower((unsigned char)test);
     
    -	/*
    -	 * A right bracket shall lose its special meaning and represent
    -	 * itself in a bracket expression if it occurs first in the list.
    -	 * -- POSIX.2 2.8.3.2
    -	 */
    -	ok = 0;
    -	c = *pattern++;
    -	do {
    -		if (c == '\\' && !(flags & FNM_NOESCAPE))
    -			c = *pattern++;
    -		if (c == EOS)
    -			return (RANGE_ERROR);
    -		if (c == '/' && (flags & FNM_PATHNAME))
    -			return (RANGE_NOMATCH);
    -		if ((flags & FNM_CASEFOLD))
    -			c = tolower((unsigned char)c);
    -		if (*pattern == '-'
    -		    && (c2 = *(pattern+1)) != EOS && c2 != ']') {
    -			pattern += 2;
    -			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
    -				c2 = *pattern++;
    -			if (c2 == EOS)
    -				return (RANGE_ERROR);
    -			if (flags & FNM_CASEFOLD)
    -				c2 = tolower((unsigned char)c2);
    -			if (c <= test && test <= c2)
    -				ok = 1;
    -		} else if (c == test)
    -			ok = 1;
    -	} while ((c = *pattern++) != ']');
    +    /*
    +     * A right bracket shall lose its special meaning and represent
    +     * itself in a bracket expression if it occurs first in the list.
    +     * -- POSIX.2 2.8.3.2
    +     */
    +    ok = 0;
    +    c = *pattern++;
    +    do {
    +        if (c == '\\' && !(flags & FNM_NOESCAPE))
    +            c = *pattern++;
    +        if (c == EOS)
    +            return (RANGE_ERROR);
    +        if (c == '/' && (flags & FNM_PATHNAME))
    +            return (RANGE_NOMATCH);
    +        if ((flags & FNM_CASEFOLD))
    +            c = tolower((unsigned char)c);
    +        if (*pattern == '-'
    +            && (c2 = *(pattern+1)) != EOS && c2 != ']') {
    +            pattern += 2;
    +            if (c2 == '\\' && !(flags & FNM_NOESCAPE))
    +                c2 = *pattern++;
    +            if (c2 == EOS)
    +                return (RANGE_ERROR);
    +            if (flags & FNM_CASEFOLD)
    +                c2 = tolower((unsigned char)c2);
    +            if (c <= test && test <= c2)
    +                ok = 1;
    +        } else if (c == test)
    +            ok = 1;
    +    } while ((c = *pattern++) != ']');
     
    -	*newp = (char *)pattern;
    -	return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
    +    *newp = (char *)pattern;
    +    return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
     }
     
     }
    diff --git a/deps/g3dlite/source/g3dmath.cpp b/deps/g3dlite/source/g3dmath.cpp
    index e846f8c60..a6ce20d87 100644
    --- a/deps/g3dlite/source/g3dmath.cpp
    +++ b/deps/g3dlite/source/g3dmath.cpp
    @@ -10,6 +10,7 @@
     #include "G3D/g3dmath.h"
     #include 
     #include 
    +#include "G3D/BIN.h"
     
     
     namespace G3D {
    @@ -40,14 +41,27 @@ double inf() {
         return std::numeric_limits::infinity();
     }
     
    +// --fast-math breaks other methods of testing for NaN on g++ 4.x,
    +// including isnan(x) and !(x == x)
    +
     bool isNaN(float x) {
    -    static const float n = fnan();
    -    return memcmp(&x, &n, sizeof(float)) == 0;
    +    // Wipe out the sign bit
    +    const uint32 y = *(uint32*)(&x) & BIN32(01111111,11111111,11111111,11111111);
    +
    +    // If the remaining number has all of the exponent bits set and atleast one
    +    // fraction bit set, then it is NaN
    +    return (y > 0x7F800000);
     }
     
     bool isNaN(double x) {
    -    static const double n = nan();
    -    return memcmp(&x, &n, sizeof(double)) == 0;
    +    // Wipe out the sign bit
    +    const uint64 y = *(uint64*)(&x) &
    +        ((uint64(BIN32(01111111,11111111,11111111,11111111)) << 32) +
    +         0xFFFFFFFF);
    +
    +    // If the remaining number has all of the exponent bits set and atleast one
    +    // fraction bit set, then it is NaN
    +    return (y > (uint64(BIN32(01111111,11110000,00000000,00000000)) << 32));
     }
     
     
    @@ -75,7 +89,7 @@ int highestBit(uint32 x) {
         // Binary search.
         int base = 0;
     
    -    if (x & 0xffff0000)	{
    +    if (x & 0xffff0000)    {
             base = 16;
             x >>= 16;
         }
    diff --git a/deps/g3dlite/source/license.cpp b/deps/g3dlite/source/license.cpp
    index ada04bbd4..e2b9f2583 100644
    --- a/deps/g3dlite/source/license.cpp
    +++ b/deps/g3dlite/source/license.cpp
    @@ -24,7 +24,7 @@ std::string license() {
     "%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"
    +"source code is Copyright  2000-2011, 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"
    @@ -59,7 +59,7 @@ std::string license() {
     "\n\n"
     "G3D VERSION %d\n", 
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         "" // Win32 doesn't use SDL
     #else
         "This software uses the Simple DirectMedia Layer library (\"SDL\",\n"
    diff --git a/deps/g3dlite/source/prompt.cpp b/deps/g3dlite/source/prompt.cpp
    index d2c6f0980..6927fd03b 100644
    --- a/deps/g3dlite/source/prompt.cpp
    +++ b/deps/g3dlite/source/prompt.cpp
    @@ -14,7 +14,7 @@
     
     #include 
     
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     #    include 
     #    include 
     #else
    @@ -29,7 +29,7 @@
     #endif
     */
     
    -#    include 
    +#    include "G3D/prompt_cocoa.h"
     
     /*
     #ifdef G3D_64BIT
    @@ -43,7 +43,7 @@
     namespace G3D {
     
     #if 0 /* G3DFIX: exclude GUI prompt code */
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
     
     namespace _internal {
     /**
    @@ -360,8 +360,8 @@ static int guiPrompt(
         const char**        choice,
         int                 numChoices) {
     
    -    int width = 280;
    -    int height = 128;
    +    int width = 340;
    +    int height = 220;
     
         const int buttonSpacing = 2;
         const int buttonWidth = 
    @@ -381,7 +381,7 @@ static int guiPrompt(
             2, 2, width - 4, height - buttonHeight - 7, IDC_MESSAGE);
     
         int i;
    -    for (i = 0; i < numChoices; i++) {
    +    for (i = 0; i < numChoices; ++i) {
     
             int x = buttonSpacing + i * (buttonWidth + buttonSpacing);
             int y = height - buttonHeight - buttonSpacing;
    @@ -429,7 +429,7 @@ static int guiPrompt(
         params.title    = windowTitle;
     
         HMODULE module = GetModuleHandle(0);
    -    int ret = DialogBoxIndirectParam(module, dialogTemplate, NULL, (DLGPROC) PromptDlgProc, (DWORD)¶ms);
    +    int ret = (int)DialogBoxIndirectParam(module, dialogTemplate, NULL, (DLGPROC) PromptDlgProc, (DWORD)¶ms);
     
         free(newStr);
     
    @@ -500,7 +500,7 @@ static int textPrompt(
             while ((c < 0) || (c >= numChoices)) { 
                 printf("\n");
     
    -            for (int i = 0; i < numChoices; i++) {
    +            for (int i = 0; i < numChoices; ++i) {
                     if (numChoices <= 3) {
                         printf("  (%d) %s ", i, choice[i]);
                     } else {
    @@ -536,167 +536,20 @@ static int textPrompt(
     }
     
     #if 0 /* G3DFIX: exclude GUI prompt code */
    -
     #ifdef G3D_OSX
     
    -// See http://developer.apple.com/documentation/Carbon/Reference/Carbon_Event_Manager_Ref/index.html
    -
    -#define CARBON_COMMANDID_START	128
    -#define CARBON_BUTTON_SPACING	12
    -#define CARBON_BUTTON_HEIGHT	20
    -#define CARBON_BUTTON_MINWIDTH	69
    -#define CARBON_WINDOW_PADDING	20
    -
    -struct CallbackData {
    -    WindowRef	refWindow;
    -
    -    /** Index of this particular button */
    -    int         myIndex;
    -
    -    /** Buttons store their index into here when pressed. */
    -    int*        whichButton;
    -};
    -
    -/**
    - Assumes that userData is a pointer to a carbon_evt_data_t.
    - 
    - */
    -static pascal OSStatus DoCommandEvent(EventHandlerCallRef handlerRef, EventRef event, void* userData) {
    -    // See http://developer.apple.com/documentation/Carbon/Conceptual/HandlingWindowsControls/index.html
    -
    -    CallbackData& callbackData = *(CallbackData*)userData;
    -
    -#   pragma unused(handlerRef)
    -	
    -    callbackData.whichButton[0] = callbackData.myIndex;
    -	
    -    // If we get here we can close the window
    -    ::QuitAppModalLoopForWindow(callbackData.refWindow);
    -	
    -    // Return noErr to indicate that we handled the event
    -    return noErr;
    -}
    -
     static int guiPrompt
     (const char*         windowTitle,
      const char*         prompt,
      const char**        choice,
      int                 numChoices) {
    -
    -    WindowRef	 window;
    -
    -    int          iNumButtonRows	= 0;
    -    int          iButtonWidth   = -1;
    -    OSStatus	 err            = noErr;
    -    
    -    // Determine number of rows of buttons
    -    while (iButtonWidth < CARBON_BUTTON_MINWIDTH) {
    -        ++iNumButtonRows;
    -        iButtonWidth = 
    -            (550 - (CARBON_WINDOW_PADDING*2 + 
    -                    (CARBON_BUTTON_SPACING*numChoices))) / 
    -            (numChoices/iNumButtonRows);
    -    }
    -	
    -    // Window Variables
    -    Rect	rectWin = {0, 0, 200 + ((iNumButtonRows-1) * (CARBON_BUTTON_HEIGHT+CARBON_BUTTON_SPACING)), 550};			// top, left, bottom, right
    -    CFStringRef	szWindowTitle = CFStringCreateWithCString(kCFAllocatorDefault, windowTitle, kCFStringEncodingUTF8);
    -
    -    window = NULL;
    -
    -    err = CreateNewWindow(kMovableAlertWindowClass, kWindowStandardHandlerAttribute|kWindowCompositingAttribute, &rectWin, &window);
    -    err = SetWindowTitleWithCFString(window, szWindowTitle);
    -    err = SetThemeWindowBackground(window, kThemeBrushAlertBackgroundActive, false);
    -    assert(err == noErr);
    -    
    -    // Event Handler Variables
    -    EventTypeSpec	buttonSpec[] = {{ kEventClassControl, kEventControlHit }, { kEventClassCommand, kEventCommandProcess }};
    -    EventHandlerUPP	buttonHandler = NewEventHandlerUPP(DoCommandEvent);
    -    
    -    // Static Text Variables
    -    Rect		rectStatic = {20, 20, 152, 530};
    -    CFStringRef		szStaticText = CFStringCreateWithCString(kCFAllocatorDefault, prompt, kCFStringEncodingUTF8);
    -    ControlRef		refStaticText = NULL;
    -    err = CreateStaticTextControl(window, &rectStatic, szStaticText, NULL, &refStaticText);
    -    
    -    // Button Variables
    -    Rect		bounds[numChoices];
    -    CFStringRef		caption[numChoices];
    -    ControlRef		button[numChoices];
    -
    -    int whichButton=-1;
    -    CallbackData        callbackData[numChoices];
    -	
    -    // Create the Buttons and assign event handlers
    -    for (int i = 0; i < numChoices; ++i) {
    -        bounds[i].top	 = 160 + ((CARBON_BUTTON_HEIGHT+CARBON_BUTTON_SPACING)*(i%iNumButtonRows));
    -        bounds[i].right	 = 530 - ((iButtonWidth+CARBON_BUTTON_SPACING)*(i/iNumButtonRows));
    -        bounds[i].left	 = bounds[i].right - iButtonWidth;
    -        bounds[i].bottom = bounds[i].top + CARBON_BUTTON_HEIGHT;
    -        
    -        // Convert the button captions to Apple strings
    -        caption[i] = CFStringCreateWithCString(kCFAllocatorDefault, choice[i], kCFStringEncodingUTF8);
    -    
    -        err = CreatePushButtonControl(window, &bounds[i], caption[i], &button[i]);
    -        assert(err == noErr);
    -
    -        err = SetControlCommandID(button[i], CARBON_COMMANDID_START + i);
    -        assert(err == noErr);
    -
    -        callbackData[i].refWindow   = window;
    -        callbackData[i].myIndex     = i;
    -        callbackData[i].whichButton = &whichButton;
    -
    -        err = InstallControlEventHandler(button[i], buttonHandler, 
    -                                         GetEventTypeCount(buttonSpec), buttonSpec,
    -                                         &callbackData[i], NULL);
    -        assert(err == noErr);
    -    }
    -    
    -    // Show Dialog
    -    err = RepositionWindow(window, NULL, kWindowCenterOnMainScreen);
    -    ShowWindow(window);
    -    BringToFront(window);
    -    err = ActivateWindow(window, true);
    -    
    -    // Hack to get our window/process to the front...
    -    ProcessSerialNumber psn = { 0, kCurrentProcess};    
    -    TransformProcessType(&psn, kProcessTransformToForegroundApplication);
    -    SetFrontProcess (&psn);
    -    
    -    // Run in Modal State
    -    err = RunAppModalLoopForWindow(window);
    -
    -    // Dispose of Button Related Data
    -    for (int i = 0; i < numChoices; ++i) {
    -        // Dispose of controls
    -        DisposeControl(button[i]);
    -        
    -        // Release CFStrings
    -        CFRelease(caption[i]);
    -    }
    -    
    -    // Dispose of Other Controls
    -    DisposeControl(refStaticText);
    -    
    -    // Dispose of Event Handlers
    -    DisposeEventHandlerUPP(buttonHandler);
    -    
    -    // Dispose of Window
    -    DisposeWindow(window);
    -    
    -    // Release CFStrings
    -    CFRelease(szWindowTitle);
    -    CFRelease(szStaticText);
    -    
    -    // Return Selection
    -    return whichButton;
    +  
    +  return prompt_cocoa(windowTitle, prompt, choice, numChoices);
     }
     
     #endif
     
     #endif /* G3DFIX: exclude GUI prompt code */
    -
     int prompt(
         const char*      windowTitle,
         const char*      prompt, 
    @@ -704,7 +557,7 @@ int prompt(
         int              numChoices,
         bool             useGui) {
     #if 0 /* G3DFIX: exclude GUI prompt code */
    -    #ifdef G3D_WIN32
    +    #ifdef G3D_WINDOWS
             if (useGui) {
                 // Build the message box
                 return guiPrompt(windowTitle, prompt, choice, numChoices);
    @@ -713,10 +566,14 @@ int prompt(
         
             #ifdef G3D_OSX
                     if (useGui){
    -                        //Will default to text prompt if numChoices > 4
    -                        return guiPrompt(windowTitle, prompt, choice, numChoices);
    +                    //Will default to text prompt if numChoices > 4
    +		  int result = guiPrompt(windowTitle, prompt, choice, numChoices);
    +		  fprintf(stderr, "%d\n", result);
    +		  return result;
                     }
             #endif
    +#else
    +    (void)useGui;
     #endif /* G3DFIX: exclude GUI prompt code */
         return textPrompt(windowTitle, prompt, choice, numChoices);
     }
    @@ -730,9 +587,9 @@ void msgBox(
         prompt(title.c_str(), message.c_str(), choice, 1, true); 
     }
     
    -#ifndef G3D_WIN32
    +#ifndef G3D_WINDOWS
         #undef _getch
     #endif
     
    -};// namespace
    +}// namespace
     
    diff --git a/deps/g3dlite/source/stringutils.cpp b/deps/g3dlite/source/stringutils.cpp
    index c3876ebb6..ff7185170 100644
    --- a/deps/g3dlite/source/stringutils.cpp
    +++ b/deps/g3dlite/source/stringutils.cpp
    @@ -1,10 +1,10 @@
     /**
    - @file stringutils.cpp
    + \file stringutils.cpp
     
    - @maintainer Morgan McGuire, http://graphics.cs.williams.edu
    + \maintainer Morgan McGuire, http://graphics.cs.williams.edu
     
    - @created 2000-09-09
    - @edited  2008-01-10
    + \created 2000-09-09
    + \edited  2011-08-20
     */
     
     #include "G3D/platform.h"
    @@ -12,6 +12,14 @@
     #include "G3D/BinaryInput.h"
     #include 
     
    +#ifdef G3D_WINDOWS
    +extern "C" {    
    +    // Define functions for ffmpeg since we don't link in gcc's c library
    +    extern int strncasecmp(const char *string1, const char *string2, size_t count) { return _strnicmp(string1, string2, count); }
    +    extern int strcasecmp(const char *string1, const char *string2) { return _stricmp(string1, string2); }
    +}
    +#endif
    +
     namespace G3D {
     
     #ifdef _MSC_VER
    @@ -19,7 +27,7 @@ namespace G3D {
     #   pragma warning (push)
     #   pragma warning (disable : 4530)
     #endif
    -#ifdef G3D_WIN32
    +#ifdef G3D_WINDOWS
         const char* NEWLINE = "\r\n";
     #else
         const char* NEWLINE = "\n";
    @@ -56,7 +64,7 @@ void parseCommaSeparated(const std::string s, Array& array, bool st
         if (stripQuotes) {
             for (int i = 0; i < array.length(); ++i) {
                 std::string& t = array[i];
    -            int L = t.length();
    +            size_t 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
    @@ -86,15 +94,44 @@ bool beginsWith(
         }
     }
     
    +std::string replace(const std::string& s, const std::string& pattern, const std::string& replacement) {
    +    if (pattern.length() == 0) {
    +        return s;
    +    }
    +	std::string temp = "";
    +    size_t lastindex = 0;
    +    size_t nextindex = 0;
    +    do {
    +        nextindex = s.find(pattern, lastindex);
    +        if (nextindex == std::string::npos) {
    +            break;
    +        }
    +        temp += s.substr(lastindex, nextindex - lastindex) + replacement;
    +        lastindex = nextindex + pattern.length();
    +    } while (lastindex + pattern.length() <= s.length());
    +    return temp + (lastindex < s.length() ? s.substr(lastindex) : "");
    +}
    +
    +bool isValidIdentifier(const std::string& s) {
    +    if (s.length() > 0 && (isLetter(s[0]) || s[0] == '_')) {   
    +        for (size_t i = 1; i < s.length() ; ++i) {
    +            if (!( isLetter(s[i]) || (s[i] == '_') || isDigit(s[i]) )) {
    +                return false;
    +            }
    +        }
    +        return true;
    +    }
    +    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) {
    +        size_t te = test.size() - 1;
    +        size_t pe = pattern.size() - 1;
    +        for (int i = (int)pattern.size() - 1; i >= 0; --i) {
                 if (pattern[pe - i] != test[te - i]) {
                     return false;
                 }
    @@ -151,7 +188,7 @@ std::string wordWrap(
             if (c < input.size()) {
                 // Collapse multiple spaces.
                 while ((input[c] == ' ') && (c < input.size())) {
    -                c++;
    +                ++c;
                 }
             }
         }
    @@ -248,9 +285,11 @@ std::string stringJoin(
     }
     
     
    -std::string trimWhitespace(
    -    const std::string&              s) {
    +std::string trimWhitespace(const std::string& s) {
     
    +    if (s.length() == 0) {
    +        return s;
    +    }
         size_t left = 0;
         
         // Trim from left
    @@ -258,15 +297,16 @@ std::string trimWhitespace(
             ++left;
         }
     
    -    int right = s.length() - 1;
    +    size_t right = s.length() - 1;
         // Trim from right
    -    while ((right > (int)left) && iswspace(s[right])) {
    +    while ((right > left) && iswspace(s[right])) {
             --right;
         }
         
         return s.substr(left, right - left + 1);
     }
     
    +
     }; // namespace
     
     #undef NEWLINE
    diff --git a/deps/g3dlite/source/uint128.cpp b/deps/g3dlite/source/uint128.cpp
    index 1f596fc3e..2fd58a332 100644
    --- a/deps/g3dlite/source/uint128.cpp
    +++ b/deps/g3dlite/source/uint128.cpp
    @@ -17,8 +17,8 @@ static void addAndCarry(const uint64& _a, const uint64& _b, uint64& carry, uint6
             
         // 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};
    +    uint32 a [2] = {static_cast(_a & 0xFFFFFFFF), static_cast(_a >> 32)};
    +    uint32 b [2] = {static_cast(_b & 0xFFFFFFFF), static_cast(_b >> 32)};
     
         uint64 tmp = uint64(a[0]) + b[0];
     
    @@ -35,8 +35,8 @@ void multiplyAndCarry(const uint64& _a, const uint64& _b, uint64& carry, uint64&
     
         // 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};
    +    uint32 a [2] = {static_cast(_a & 0xFFFFFFFF), static_cast(_a >> 32)};
    +    uint32 b [2] = {static_cast(_b & 0xFFFFFFFF), static_cast(_b >> 32)};
     
         uint64 prod [2][2];
         for(int i = 0; i < 2; ++i) {