Core/Misc: update g3dlite lib (#2904)

* Core/Misc: update g3dlite lib

* update

Co-authored-by: Francesco Borzì <borzifrancesco@gmail.com>
This commit is contained in:
Viste
2020-07-30 13:35:45 +03:00
committed by GitHub
parent 91bbbf08eb
commit fcaf91b8b2
183 changed files with 13258 additions and 8022 deletions

View File

@@ -11,6 +11,7 @@
set(g3dlib_STAT_SRCS set(g3dlib_STAT_SRCS
source/AABox.cpp source/AABox.cpp
source/Any.cpp source/Any.cpp
source/AnyTableReader.cpp
source/BinaryFormat.cpp source/BinaryFormat.cpp
source/BinaryInput.cpp source/BinaryInput.cpp
source/BinaryOutput.cpp source/BinaryOutput.cpp
@@ -26,6 +27,7 @@ set(g3dlib_STAT_SRCS
source/format.cpp source/format.cpp
source/g3dfnmatch.cpp source/g3dfnmatch.cpp
source/g3dmath.cpp source/g3dmath.cpp
source/GThread.cpp
source/Line.cpp source/Line.cpp
source/LineSegment.cpp source/LineSegment.cpp
source/Log.cpp source/Log.cpp
@@ -38,7 +40,6 @@ set(g3dlib_STAT_SRCS
source/Quat.cpp source/Quat.cpp
source/Random.cpp source/Random.cpp
source/Ray.cpp source/Ray.cpp
source/ReferenceCount.cpp
source/RegistryUtil.cpp source/RegistryUtil.cpp
source/Sphere.cpp source/Sphere.cpp
source/stringutils.cpp source/stringutils.cpp
@@ -55,9 +56,6 @@ set(g3dlib_STAT_SRCS
add_library(g3dlib STATIC ${g3dlib_STAT_SRCS}) add_library(g3dlib STATIC ${g3dlib_STAT_SRCS})
# Group sources
GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(g3dlib target_include_directories(g3dlib
PUBLIC PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include) ${CMAKE_CURRENT_SOURCE_DIR}/include)

View File

@@ -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_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_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_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

View File

@@ -1,29 +1,31 @@
/** /**
@file AABox.h \file G3D/AABox.h
Axis-aligned box class Axis-aligned box class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2004-01-10 \created 2004-01-10
@edited 2009-02-10 \edited 2013-04-13
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2013, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_AABOX_H #ifndef G3D_AABox_h
#define G3D_AABOX_H #define G3D_AABox_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Vector3.h"
#include "G3D/debug.h" #include "G3D/debug.h"
#include "G3D/Array.h" #include "G3D/Array.h"
#include "G3D/Plane.h" #include "G3D/Plane.h"
#include "G3D/Sphere.h" #include "G3D/Sphere.h"
#include "G3D/Vector3.h"
namespace G3D { namespace G3D {
class Any;
/** /**
An axis-aligned box. An axis-aligned box.
*/ */
@@ -34,66 +36,109 @@ private:
/** Optional argument placeholder */ /** Optional argument placeholder */
static int dummy; static int dummy;
Vector3 lo; /** NaN if empty */
Vector3 hi; Point3 lo;
/** NaN if empty */
Point3 hi;
public: public:
/** Does not initialize the fields */ /** Creates the empty bounds, i.e., an empty set of points. */
inline AABox() {} 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; 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. /** Assumes that low is less than or equal to high along each dimension.
To have this automatically enforced, use To have this automatically enforced, use
<code>AABox(low.min(high), low.max(high));</code> <code>AABox(low.min(high), low.max(high));</code>
*/ */
inline AABox(const Vector3& low, const Vector3& high) { AABox(const Point3& low, const Point3& high) {
set(low, 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. /** 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( debugAssert(
(low.x <= high.x) && (low.x <= high.x) &&
(low.y <= high.y) && (low.y <= high.y) &&
(low.z <= high.z)); (low.z <= high.z));
debugAssert(! low.isNaN() && ! high.isNaN());
lo = low; lo = low;
hi = high; hi = high;
} }
/** /**
Grows to include the bounds of a Grows to include the bounds of \a a
*/ */
inline void merge(const AABox& a) { inline void merge(const AABox& a) {
if (isEmpty()) {
lo = a.lo;
hi = a.hi;
} else if (! a.isEmpty()) {
lo = lo.min(a.lo); lo = lo.min(a.lo);
hi = hi.max(a.hi); hi = hi.max(a.hi);
} }
}
inline void merge(const Vector3& a) { inline void merge(const Point3& a) {
if (isEmpty()) {
lo = hi = a;
} else {
lo = lo.min(a); lo = lo.min(a);
hi = hi.max(a); hi = hi.max(a);
} }
}
void merge(const class Box& b);
void serialize(class BinaryOutput& b) const; void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b); void deserialize(class BinaryInput& b);
inline bool isFinite() const { 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; return lo;
} }
inline const Vector3& high() const { /** Returns not-a-number if empty */
inline const Point3& high() const {
return hi; return hi;
} }
@@ -110,25 +155,33 @@ public:
static const AABox& zero(); 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; 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. Distance from corner(0) to the next corner along axis a.
*/ */
inline float extent(int a) const { inline float extent(int a) const {
if (isEmpty()) {
return 0.0f;
}
debugAssert(a < 3); debugAssert(a < 3);
return hi[a] - lo[a]; return hi[a] - lo[a];
} }
inline Vector3 extent() const { inline Vector3 extent() const {
if (isEmpty()) {
return Vector3::zero();
}
return hi - lo; return hi - lo;
} }
@@ -167,8 +220,8 @@ public:
@param childMask Test mask for the children of this volume. @param childMask Test mask for the children of this volume.
*/ */
bool culledBy( bool culledBy
const Array<Plane>& plane, (const Array<Plane>& plane,
int32& cullingPlaneIndex, int32& cullingPlaneIndex,
const uint32 testMask, const uint32 testMask,
uint32& childMask) const; uint32& childMask) const;
@@ -176,8 +229,8 @@ public:
/** /**
Conservative culling test that does not produce a mask for children. Conservative culling test that does not produce a mask for children.
*/ */
bool culledBy( bool culledBy
const Array<Plane>& plane, (const Array<Plane>& plane,
int32& cullingPlaneIndex = dummy, int32& cullingPlaneIndex = dummy,
const uint32 testMask = 0xFFFFFFFF) const; const uint32 testMask = 0xFFFFFFFF) const;
@@ -192,8 +245,7 @@ public:
(other.lo.z >= lo.z); (other.lo.z >= lo.z);
} }
inline bool contains( inline bool contains(const Point3& point) const {
const Vector3& point) const {
return return
(point.x >= lo.x) && (point.x >= lo.x) &&
(point.y >= lo.y) && (point.y >= lo.y) &&
@@ -204,44 +256,63 @@ public:
} }
inline float area() const { inline float area() const {
if (isEmpty()) { return 0; }
Vector3 diag = hi - lo; Vector3 diag = hi - lo;
return 2.0f * (diag.x * diag.y + diag.y * diag.z + diag.x * diag.z); return 2.0f * (diag.x * diag.y + diag.y * diag.z + diag.x * diag.z);
} }
inline float volume() const { inline float volume() const {
if (isEmpty()) { return 0; }
Vector3 diag = hi - lo; Vector3 diag = hi - lo;
return diag.x * diag.y * diag.z; 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 */ /** Returns true if there is any overlap */
bool intersects(const AABox& other) const; bool intersects(const AABox& other) const;
/** Returns true if there is any overlap. /** Returns true if there is any overlap.
@cite Jim Arvo's algorithm from Graphics Gems II*/ @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 */ /** Return the intersection of the two boxes */
AABox intersect(const AABox& other) const { AABox intersect(const AABox& other) const {
Vector3 H = hi.min(other.hi); if (isEmpty() || other.isEmpty()) {
Vector3 L = lo.max(other.lo).min(H); 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); return AABox(L, H);
} }
}
inline size_t hashCode() const { inline size_t hashCode() const {
return lo.hashCode() + hi.hashCode(); return lo.hashCode() + hi.hashCode();
} }
inline bool operator==(const AABox& b) const { inline bool operator==(const AABox& b) const {
if (isEmpty() && b.isEmpty()) {
return true;
} else {
return (lo == b.lo) && (hi == b.hi); return (lo == b.lo) && (hi == b.hi);
} }
}
inline bool operator!=(const AABox& b) const { inline bool operator!=(const AABox& b) const {
if (isEmpty()) {
return b.isEmpty();
} else {
return !((lo == b.lo) && (hi == b.hi)); return !((lo == b.lo) && (hi == b.hi));
} }
}
inline AABox operator+(const Vector3& v) const { inline AABox operator+(const Vector3& v) const {
AABox out; AABox out;

View File

@@ -1,13 +1,13 @@
/** /**
@file Any.h \file Any.h
@author Morgan McGuire, Shawn Yarbrough, and Corey Taylor \author Morgan McGuire, Shawn Yarbrough, and Corey Taylor
@maintainer Morgan McGuire \maintainer Morgan McGuire
@created 2006-06-11 \created 2006-06-11
@edited 2010-03-16 \edited 2013-03-29
Copyright 2000-2010, Morgan McGuire. Copyright 2000-2013, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -17,13 +17,13 @@
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Table.h" #include "G3D/Table.h"
#include "G3D/Array.h" #include "G3D/Array.h"
#include "G3D/Set.h"
#include "G3D/AtomicInt32.h" #include "G3D/AtomicInt32.h"
#include "G3D/stringutils.h" #include "G3D/stringutils.h"
#include <string> #include <string>
// needed for Token // needed for Token
#include "G3D/TextInput.h" #include "G3D/TextInput.h"
#include "G3D/TextOutput.h"
#ifdef verify #ifdef verify
#undef verify #undef verify
@@ -38,7 +38,8 @@ class TextOutput;
Any encodes typed, structured data and can serialize it to a human Any encodes typed, structured data and can serialize it to a human
readable format that is very similar to the Python language's data 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 formats, especially since deserialization and serialization preserve
comments and an Any can tell you what file and line it came from. The 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 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), position = Vector3(1.0, -1.0, 0.0),
video = { format = "RGB8", size = (320, 200)}, video = { format = "RGB8", size = (320, 200)},
material = #include("rocks.mat") material = \#include("rocks.mat")
} }
</pre> </pre>
@@ -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 humans to read, and easy for machines to parse. It was specifically
chosen over formats like XML, YAML, JSON, S-expressions, and Protocol chosen over formats like XML, YAML, JSON, S-expressions, and Protocol
Buffers, although there is no reason you could not write readers and 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 G3D::Any assumes that structures do not contain cycles; it is an
error to create a structure like: 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. although no exception will be thrown at runtime during that append.
\section includes
When parsing an Any from a file, the syntax
<code>\#include(<i>filename</i>)</code> allows subsitution of the contents of
<i>filename</i> 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 \section Parsing
@@ -117,24 +130,12 @@ Vector3::Vector3(const Any& any) {
} }
</pre> </pre>
It is often convenient to iterate through the table portion: It is often convenient to iterate through the table portion using G3D::AnyTableReader.
<pre>
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);
}
}
</pre>
\section BNF \section BNF
Serialized format BNF: Serialized format BNF:
\htmlonly
<pre> <pre>
identifier ::= (letter | "_") (letter | digit | "_")* identifier ::= (letter | "_") (letter | digit | "_")*
identifier-op ::= "::" | "->" | "." identifier-op ::= "::" | "->" | "."
@@ -145,18 +146,19 @@ comment ::= C++ single or multi-line comments
separator ::= "," | ";" separator ::= "," | ";"
number ::= <legal C printf number format> number ::= <legal C printf number format>
string ::= <legal C double-quoted string; backslashes must be escaped> string ::= <legal C double-quoted or unquoted string; backslashes must be escaped>
boolean ::= "True" | "False" boolean ::= "True" | "False"
none ::= "None" nil ::= "Nil" <not case sensitive> | "None" <case sensitive>
array ::= ("(" | "[") [ value (separator value)* [separator] ] (")" | "]") array ::= ("(" | "[" | "{") [value (separator value)* [separator] ] (")" | "]" | "}")
pair ::= (identifier | string) "=" value pair ::= (identifier | string) ("=" | ":") value
table ::= "{" [ pair (separator pair)* [separator] ] "}" table ::= ("(" | "[" | "{") [ pair (separator pair)* [separator] ] (")" | "]" | "}")
named-array ::= identifier-exp array named-array ::= identifier-exp array
named-table ::= identifier-exp table named-table ::= identifier-exp table
include ::= "#" "include" "(" string ")" 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)
</pre> </pre>
\endhtmlonly
Except for single-line comments, whitespace is not significant. Except for single-line comments, whitespace is not significant.
All parsing is case-insensitive. 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 that it cannot yield more than one element of an array and cannot serve
as the pair in a table. 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 tuples and ";" for ",". These are convenient when mimicing a
programming language, e.g., <code>"[ printf("hello world."); clearScreen();]"</code> programming language, e.g., <code>"[ printf("hello world."); clearScreen();]"</code>
parses as an array containing two named arrays within it. The 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. The serializer indents four spaces for each level of nesting.
Tables are written with the keys in alphabetic order. Tables are written with the keys in alphabetic order.
\sa G3D::AnyTableReader
*/ */
class Any { class Any {
public: 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); static std::string toString(Type t);
@@ -208,7 +212,7 @@ private:
/** Called from deserialize() */ /** Called from deserialize() */
static void deserializeComment(TextInput& ti, Token& token, std::string& comment); 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 { union SimpleValue {
bool b; bool b;
double n; double n;
@@ -218,6 +222,11 @@ private:
inline SimpleValue(double x) : n(x) {} 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 { class Data {
public: public:
/** ARRAY, TABLE, or STRING value only. NULL otherwise. */ /** ARRAY, TABLE, or STRING value only. NULL otherwise. */
@@ -240,6 +249,16 @@ private:
std::string name; 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 /** For STRING, ARRAY and TABLE types, m_value is shared between
multiple instances. Mutation is allowed only if the reference multiple instances. Mutation is allowed only if the reference
count is exactly 1, otherwise the mutating instance must copy count is exactly 1, otherwise the mutating instance must copy
@@ -249,10 +268,16 @@ private:
Source source; 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: private:
/** Called by create() */ /** 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 */ /** Called by destroy */
~Data(); ~Data();
@@ -261,12 +286,11 @@ private:
/** Clones the argument */ /** Clones the argument */
static Data* create(const Data* d); 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 /** Free d, invoking its destructor and freeing the memory for
the value. */ the value. */
static void destroy(Data* d); static void destroy(Data* d);
}; };
/** If not empty, this Any was created from operator[] on a table /** If not empty, this Any was created from operator[] on a table
@@ -283,12 +307,11 @@ private:
SimpleValue m_simpleValue; SimpleValue m_simpleValue;
mutable Data* m_data; mutable Data* m_data;
/** Called before every read operation to ensure that this object /** Called before every read operation. */
is not a placeholder. */
void beforeRead() const; void beforeRead() const;
/** Called before every write operation to wipe the placeholder /** Called before every write operation to this Any. Wipes the placeholder
status. */ status and includedFrom entry. */
void beforeWrite(); void beforeWrite();
/** Decrements the reference count (if there is one). If the /** Decrements the reference count (if there is one). If the
@@ -316,43 +339,61 @@ private:
/** Read the name of a named Array or Table. */ /** Read the name of a named Array or Table. */
static void deserializeName(TextInput& ti, Token& token, std::string& name); 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 return that token. Considers the passed in token to be the first
value read. */ 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. /** 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[].*/ This proxy can be copied exactly once on return from operator[].*/
Any(const std::string& key, Data* data); Any(const std::string& key, Data* data);
inline bool isPlaceholder() const { bool isPlaceholder() const {
return ! m_placeholderName.empty(); return ! m_placeholderName.empty();
} }
public: 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);
/** Base class for all Any exceptions.*/
class Exception {
public: public:
virtual ~Exception() {}
};
/** Thrown by operator[] when a key is not present in a const table. */ /** Thrown by operator[] when a key is not present in a const table. */
class KeyNotFound : public ParseError { class KeyNotFound : public ParseError {
public: public:
std::string key; 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. */ /** Thrown by operator[] when an array index is not present. */
class IndexOutOfBounds : public Exception { class IndexOutOfBounds : public ParseError {
public: public:
int index; int index;
int size; int size;
inline IndexOutOfBounds() : index(0), size(0) {} IndexOutOfBounds() : index(0), size(0) {}
inline IndexOutOfBounds(int i, int s) : index(i), size(s) {} 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(); Any();
/** Deserialize */ /** Deserialize */
@@ -361,108 +402,133 @@ public:
Any(const Any& x); Any(const Any& x);
/** NUMBER constructor */ /** NUMBER constructor */
Any(double x); explicit Any(double x);
#ifdef G3D_32BIT explicit Any(float x);
/** NUMBER constructor */
Any(int64 x);
#endif // G3D_32BIT
#if 0 #if defined(G3D_32Bit) || defined(_MSC_VER)
/** NUMBER constructor */ /** NUMBER constructor */
Any(int32 x); explicit Any(int64 x) : m_type(NUMBER), m_simpleValue((double)x), m_data(NULL) {}
#endif // 0 #endif
/** NUMBER constructor */ /** NUMBER constructor */
Any(long x); explicit Any(long x);
/** NUMBER constructor */ /** NUMBER constructor */
Any(int x); explicit Any(int x);
/** NUMBER constructor */ /** NUMBER constructor */
Any(short x); explicit Any(char x);
/** NUMBER constructor */
explicit Any(short x);
/** BOOLEAN constructor */ /** BOOLEAN constructor */
Any(bool x); explicit Any(bool x);
/** STRING constructor */ /** STRING constructor */
Any(const std::string& x); explicit Any(const std::string& x);
/** STRING constructor */ /** STRING constructor */
Any(const char* x); explicit Any(const char* x);
/** \a t must be ARRAY or TABLE */ /** \a t must be ARRAY or TABLE
Any(Type t, const std::string& name = ""); \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<class T>
explicit Any(const T& v) : m_type(NIL), m_data(NULL) {
*this = v.toAny();
}
~Any(); ~Any();
/** Removes the comment and name */ /** Removes the comment and name */
Any& operator=(const Any& x); Any& operator=(const Any& x);
/** Removes the comment and name */ /** \a t must be ARRAY, TABLE, or NIL. 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 */
Any& operator=(Type t); Any& operator=(Type t);
/** Assigns from an array. Assumes that T can be converted to Any. Removes the comment and name */
template<class T>
Any& operator=(const Array<T>& 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<class T>
Any& operator=(const T& v) {
*this = Any(v);
return *this;
}
Type type() const; Type type() const;
/** Same as deserialize or load, but operates on a string instead /** Same as deserialize or load, but operates on a string instead
of a stream or file. 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.*/ /** Comments appear before values when they are in serialized form.*/
const std::string& comment() const; const std::string& comment() const;
void setComment(const std::string& c); void setComment(const std::string& c);
/** True if this is the NONE value */ /** True if this is the NIL value */
bool isNone() const; bool isNil() const;
/** Throws a ParseError exception if this is not a number */ /** Throws a ParseError exception if this is not a number */
double number() const; double number() const;
float floatValue() const;
const std::string& string() const; const std::string& string() const;
bool boolean() const; bool boolean() const;
/** If a valid string, takes the string value and creates a fully qualified filename. /** If a valid string, takes the string value and creates a fully
If not found, the returned string is empty. qualified filename.
The file is searched for the following ways: The file is searched for the following ways:
- In the directory from which the Any was loaded. - In the directory from which the Any was loaded.
- By calling System::findDataFile as you would with other data files. - 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. */ /** If this is named ARRAY or TABLE, returns the name. */
const std::string& name() const; 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; 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; 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; 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; bool nameEquals(const char* s) const;
/** \brief Set the name used when serializing an ARRAY or TABLE. /** \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. */ /** Directly exposes the underlying data structure for an ARRAY. */
const Array<Any>& array() const; const Array<Any>& 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<class T0>
void append(const T0& v0) {
_append(Any(v0));
}
template<class T0, class T1>
void append(const T0& v0, const T1& v1) {
_append(Any(v0), Any(v1));
}
template<class T0, class T1, class T2>
void append(const T0& v0, const T1& v1, const T2& v2) {
_append(Any(v0), Any(v1), Any(v2));
}
template<class T0, class T1, class T2, class T3>
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<std::string, Any>& table() const; const Table<std::string, Any>& table() const;
/** For a table, returns the element for \a key. Throws KeyNotFound /** For a table, returns the element for \a key. Throws KeyNotFound
@@ -549,19 +632,25 @@ public:
Any& operator[](const std::string& key); Any& operator[](const std::string& key);
/** \copydoc Any::operator[](const std::string&) */ /** \copydoc Any::operator[](const std::string&) */
Any& operator[](const char* key) { inline Any& operator[](const char* key) {
return operator[](std::string(key)); return operator[](std::string(key));
} }
/** For a table, returns the element for key \a x and \a /** For a table, returns the element for key \a x and \a
defaultVal if it does not exist. */ defaultVal if it does not exist. */
const Any& get(const std::string& key, const Any& defaultVal) const; template<class T>
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. */ /** 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; bool containsKey(const std::string& key) const;
/** For a table, assigns the element for key k. */ /** For a table, assigns the element for key k. */
void set(const std::string& key, const Any& val); template<class T>
void set(const std::string& key, const T& val) {
_set(key, Any(val));
}
/** for an ARRAY, resizes and returns the last element */ /** for an ARRAY, resizes and returns the last element */
Any& next(); Any& next();
@@ -573,14 +662,64 @@ public:
/** True if the Anys are exactly equal, ignoring comments. Applies deeply on arrays and tables. */ /** True if the Anys are exactly equal, ignoring comments. Applies deeply on arrays and tables. */
bool operator==(const Any& x) const; 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 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 int() const;
operator uint32() const;
operator float() const; operator float() const;
operator double() const; operator double() const;
operator bool() const; operator bool() const;
operator std::string() 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 /** 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 */ It is an error to call this method if this is not an Any::ARRAY */
void resize(int n); void resize(int n);
@@ -591,33 +730,88 @@ public:
void clear(); void clear();
/** Parse from a file. /** Parse from a file.
\sa deserialize, parse */ \sa deserialize, parse, fromFile, loadIfExists
*/
void load(const std::string& filename); 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. */ /** Uses the serialize method. */
void save(const std::string& filename) const; 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. /** Parse from a stream.
\sa load, parse */ \sa load, parse */
void deserialize(TextInput& ti); void deserialize(TextInput& ti);
void deserialize(class BinaryInput& b);
const Source& source() const; 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 /** Throws a ParseError if \a value is false. Useful for quickly
creating parse rules in classes that deserialize from Any. creating parse rules in classes that deserialize from Any.
*/ */
void verify(bool value, const std::string& message = "") const; void verify(bool value, const std::string& message = "") const;
/** Verifies that the name <i>begins with</i> identifier \a n (case insensitive). /** Verifies that the name is identifier \a n (case sensitive).
It may contain identifier operators after this */ It may contain identifier operators after this */
void verifyName(const std::string& n) const; void verifyName(const std::string& n) const;
/** Verifies that the name <i>begins with</i> 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 */ It may contain identifier operators after this */
void verifyName(const std::string& n, const std::string& m) const; 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 <i>begins with</i> identifier \a n (case sensitive).
It may contain identifier operators after this */
void verifyNameBeginsWith(const std::string& n) const;
/** Verifies that the name <i>begins with</i> 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 <i>begins with</i> 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 <i>begins with</i> 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 <i>begins with</i> 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 <i>begins with</i> 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 <i>begins with</i> 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. */ /** Verifies that the type is \a t. */
void verifyType(Type t) const; void verifyType(Type t) const;
@@ -630,14 +824,49 @@ public:
/** Verifies that the size is exactly \a s */ /** Verifies that the size is exactly \a s */
void verifySize(int s) const; void verifySize(int s) const;
/** Assumes that Any(T) is well-defined, e.g., by T defining a
T::toAny() method. */
template<class T>
explicit Any(const Array<T>& 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<class T>
void getArray(Array<T>& 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<class T>
void getTable(Table<std::string, T>& table) const {
verifyType(TABLE);
for (Table<std::string, Any>::Iterator it = this->table().begin(); it.isValid(); ++it) {
table.set(it.key(), T(it.value()));
}
}
private: private:
void deserializeTable(TextInput& ti); void deserializeTable(TextInput& ti);
void deserializeArray(TextInput& ti,const std::string& term); 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 }; // class Any
/** /**
Convenient iteration over the keys of a Any::TABLE, usually Convenient iteration over the keys of a Any::TABLE, usually
for implementing construction of an object from an Any. 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 It is an error to consume the same element more than once from
the same iterator. the same iterator.
<pre> \code
AnyKeyIterator r(a); AnyTableReader r(a);
r.getIfPresent("enabled", enabled); r.getIfPresent("enabled", enabled);
r.getIfPresent("showSamples", showSamples); r.getIfPresent("showSamples", showSamples);
r.getIfPresent("showTiles", showTiles); r.get("showTiles", showTiles);
r.verifyDone(); r.verifyDone();
</pre> \endcode
\beta \beta
*/ */
@@ -665,44 +894,21 @@ private:
public: public:
/** Verifies that \a is a TABLE with the given \a name. */ /** Verifies that \a is a TABLE with the given \a name. */
AnyTableReader(const std::string& name, const Any& a) : m_any(a) { AnyTableReader(const std::string& name, const 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;
}
}
/** Verifies that \a is a TABLE. */ /** Verifies that \a is a TABLE. */
AnyTableReader(const Any& a) : m_any(a) { AnyTableReader(const 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;
}
}
bool hasMore() const { bool hasMore() const {
return m_any.size() > m_alreadyRead.size(); return m_any.size() > m_alreadyRead.size();
} }
/** Verifies that all keys have been read. */ /** Verifies that all keys have been read. */
void verifyDone() const { void verifyDone() const;
if (hasMore()) {
// Generate all keys /** Return the underlying Any. */
// Remove the ones we've read const Any& any() const {
// Assert the rest return m_any;
// any.verify("");
}
} }
#if 0 #if 0
@@ -715,29 +921,66 @@ public:
AnyKeyIterator& operator++(); AnyKeyIterator& operator++();
#endif #endif
/** If key \s appears in the any, reads its value into \a v and /** \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<class T>
void get(const std::string& s, Array<T>& v) {
m_any[s].getArray(v);
m_alreadyRead.insert(s);
}
template<class T>
void get(const std::string& s, Table<std::string, T>& 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. 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. by this iterator. If it has been read before, an assertion will fail in debug mode.
*/ */
template<class ValueType> template<class ValueType>
void get(const std::string& s, ValueType& v) { void get(const std::string& s, ValueType& v) {
v = m_any[s]; v = ValueType(m_any[s]);
m_alreadyRead.insert(toLower(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. /** 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. 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. by this iterator. If it has been read before, an assertion will fail in debug mode.
\return True if the value was read. \return True if the value was read.
@@ -745,7 +988,7 @@ public:
template<class ValueType> template<class ValueType>
bool getIfPresent(const std::string& s, ValueType& v) { bool getIfPresent(const std::string& s, ValueType& v) {
if (m_any.containsKey(s)) { if (m_any.containsKey(s)) {
debugAssertM(! m_alreadyRead.contains(toLower(s)), "read twice"); debugAssertM(! m_alreadyRead.contains(s), "read twice");
get(s, v); get(s, v);
return true; return true;
@@ -753,8 +996,29 @@ public:
return false; 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 } // 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 #endif

View File

@@ -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 \created 2009-01-20
@edited 2009-05-29 \edited 2010-10-29
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -57,7 +57,7 @@ private:
public: public:
typedef ReferenceCountedPointer<AreaMemoryManager> Ref; typedef shared_ptr<AreaMemoryManager> Ref;
/** /**
\param sizeHint Total amount of memory expected to be allocated. \param sizeHint Total amount of memory expected to be allocated.

View File

@@ -1,13 +1,13 @@
/** /**
@file Array.h \file Array.h
@maintainer Morgan McGuire, graphics3d.com \maintainer Morgan McGuire, graphics3d.com
@cite Portions written by Aaron Orenstein, a@orenstein.name \cite Portions written by Aaron Orenstein, a@orenstein.name
@created 2001-03-11 \created 2001-03-11
@edited 2009-05-29 \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. All rights reserved.
*/ */
@@ -16,8 +16,8 @@
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/debug.h" #include "G3D/debug.h"
#include "G3D/System.h"
#include "G3D/MemoryManager.h" #include "G3D/MemoryManager.h"
#include "G3D/System.h"
#ifdef G3D_DEBUG #ifdef G3D_DEBUG
// For formatting error messages // For formatting error messages
# include "G3D/format.h" # include "G3D/format.h"
@@ -47,6 +47,8 @@ const int SORT_INCREASING = 1;
/** Constant for Array::sort */ /** Constant for Array::sort */
const int SORT_DECREASING = -1; const int SORT_DECREASING = -1;
/** /**
\brief Dynamic 1D array tuned for performance. \brief Dynamic 1D array tuned for performance.
@@ -89,22 +91,26 @@ const int SORT_DECREASING = -1;
\sa G3D::SmallArray \sa G3D::SmallArray
*/ */
template <class T, int MIN_ELEMENTS = 10, size_t MIN_BYTES = 32> template <class T, size_t MIN_ELEMENTS = 10>
class Array { class Array {
private: 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 */ /** 0...num-1 are initialized elements, num...numAllocated-1 are not */
T* data; T* data;
int num; size_t num;
int numAllocated; size_t numAllocated;
MemoryManager::Ref m_memoryManager; MemoryManager::Ref m_memoryManager;
/** \param n Number of elements /** \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; m_memoryManager = m;
debugAssert(n >= 0);
this->num = 0; this->num = 0;
this->numAllocated = 0; this->numAllocated = 0;
data = NULL; data = NULL;
@@ -117,7 +123,7 @@ private:
void _copy(const Array &other) { void _copy(const Array &other) {
init(other.num, MemoryManager::create()); 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]; 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 and then copies at most oldNum elements from the old array to it. Destructors are
called for oldNum elements of the old array. called for oldNum elements of the old array.
*/ */
void realloc(int oldNum) { void realloc(size_t oldNum) {
T* oldData = data; T* oldData = data;
// The allocation is separate from the constructor invocation because we don't want // 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?"); alwaysAssertM(data, "Memory manager returned NULL: out of memory?");
// Call the copy constructors // Call the copy constructors
{const int N = G3D::min(oldNum, numAllocated); {const size_t N = G3D::min(oldNum, numAllocated);
const T* end = data + N; const T* end = data + N;
T* oldPtr = oldData; T* oldPtr = oldData;
for (T* ptr = data; ptr < end; ++ptr, ++oldPtr) { for (T* ptr = data; ptr < end; ++ptr, ++oldPtr) {
@@ -177,6 +183,27 @@ private:
m_memoryManager->free(oldData); 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<T>& other) {
resize(other.size());
for (size_t i = 0; i < num; ++i) {
data[i] = other[i];
}
return *this;
}
public: public:
/** /**
@@ -211,7 +238,7 @@ public:
return data; 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. element.
*/ */
ConstIterator end() const { ConstIterator end() const {
@@ -230,6 +257,18 @@ public:
return data; 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 <i>other</i> array after the swap. */
static void swap(Array<T, MIN_ELEMENTS>& a, Array<T, MIN_ELEMENTS>& 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 returned is only valid until the next append() or resize call, or
the Array is deallocated. the Array is deallocated.
@@ -241,12 +280,11 @@ public:
/** Creates a zero length array (no heap allocation occurs until resize). */ /** Creates a zero length array (no heap allocation occurs until resize). */
Array() : num(0) { Array() : num(0) {
init(0, MemoryManager::create()); init(0, MemoryManager::create());
debugAssert(num >= 0);
} }
/** Creates an array containing v0. */ /** Creates an array containing v0. */
Array(const T& v0) { explicit Array(const T& v0) {
init(1, MemoryManager::create()); init(1, MemoryManager::create());
(*this)[0] = v0; (*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?
*/ */
//TODO: patch rest of the API to prevent returning Arrays by value, then make explicit
Array(const Array& other) : num(0) { Array(const Array& other) : num(0) {
_copy(other); _copy(other);
debugAssert(num >= 0); }
explicit Array(const std::vector<T>& 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<T>& 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<T>& other) {
static_assert(std::is_pod<T>::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<T>& other) {
static_assert(std::is_pod<T>::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,7 +390,7 @@ public:
*/ */
~Array() { ~Array() {
// Invoke the destructors on the elements // Invoke the destructors on the elements
for (int i = 0; i < num; i++) { for (size_t i = 0; i < num; ++i) {
(data + i)->~T(); (data + i)->~T();
} }
@@ -335,26 +422,6 @@ public:
clear(false); 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<T>& other) {
resize((int)other.size());
for (int i = 0; i < num; ++i) {
data[i] = other[i];
}
return *this;
}
inline MemoryManager::Ref memoryManager() const { inline MemoryManager::Ref memoryManager() const {
return m_memoryManager; return m_memoryManager;
} }
@@ -363,7 +430,7 @@ public:
Number of elements in the array. Number of elements in the array.
*/ */
inline int size() const { inline int size() const {
return num; return (int)num;
} }
/** /**
@@ -379,8 +446,7 @@ public:
shrinks the array by one. shrinks the array by one.
*/ */
void fastRemove(int index, bool shrinkIfNecessary = false) { void fastRemove(int index, bool shrinkIfNecessary = false) {
debugAssert(index >= 0); debugAssert(index < (int)num);
debugAssert(index < num);
data[index] = data[num - 1]; data[index] = data[num - 1];
resize(size() - 1, shrinkIfNecessary); resize(size() - 1, shrinkIfNecessary);
} }
@@ -393,32 +459,52 @@ public:
// Add space for the extra element // Add space for the extra element
resize(num + 1, false); 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[i] = data[i - 1];
} }
data[n] = value; 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 /** @param shrinkIfNecessary if false, memory will never be
reallocated when the array shrinks. This makes resizing much 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) { void resize(size_t n, bool shrinkIfNecessary = true) {
debugAssert(n >= 0); 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) { if (num == n) {
return; return;
} }
int oldNum = num; size_t oldNum = num;
num = n; num = n;
// Call the destructors on newly hidden elements if there are any // 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(); (data + i)->~T();
} }
// Once allocated, always maintain MIN_ELEMENTS elements or 32 bytes, whichever is higher. // 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) { if ((MIN_ELEMENTS == 0) && (MIN_BYTES == 0) && (n == 0) && shrinkIfNecessary) {
// Deallocate the array completely // Deallocate the array completely
@@ -450,18 +536,21 @@ public:
// //
// These numbers are tweaked according to performance tests. // These numbers are tweaked according to performance tests.
float growFactor = 3.0; double growFactor = 3.0f;
int oldSizeBytes = numAllocated * sizeof(T); size_t oldSizeBytes = numAllocated * sizeof(T);
if (oldSizeBytes > 400000) { if (oldSizeBytes > 10000000) {
// Avoid bloat // Conserve memory more tightly above 10 MB
growFactor = 1.5; growFactor = 1.2f;
} else if (oldSizeBytes > 400000) {
// Avoid bloat above 400k
growFactor = 1.5f;
} else if (oldSizeBytes > 64000) { } else if (oldSizeBytes > 64000) {
// This is what std:: uses at all times // 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) { if (numAllocated < minSize) {
numAllocated = minSize; numAllocated = minSize;
@@ -476,14 +565,14 @@ public:
// Only copy over old elements that still remain after resizing // Only copy over old elements that still remain after resizing
// (destructors were called for others if we're shrinking) // (destructors were called for others if we're shrinking)
realloc(iMin(num, oldNum)); realloc(min(num, oldNum));
} }
// Call the constructors on newly revealed elements. // Call the constructors on newly revealed elements.
// Do not use parens because we don't want the intializer // Do not use parens because we don't want the intializer
// invoked for POD types. // invoked for POD types.
for (int i = oldNum; i < num; ++i) { for (size_t i = oldNum; i < num; ++i) {
new (data + i) T; 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. Returns true if the given element is in the array.
*/ */
@@ -602,12 +747,12 @@ public:
*/ */
void append(const Array<T>& array) { void append(const Array<T>& array) {
debugAssert(this != &array); debugAssert(this != &array);
int oldNum = num; size_t oldNum = num;
int arrayLength = array.length(); size_t arrayLength = array.length();
resize(num + arrayLength, false); 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]; data[oldNum + i] = array.data[i];
} }
} }
@@ -649,7 +794,7 @@ public:
For compatibility with std::vector. For compatibility with std::vector.
*/ */
int capacity() const { int capacity() const {
return numAllocated; return (int)numAllocated;
} }
/** /**
@@ -723,13 +868,20 @@ public:
Performs bounds checks in debug mode Performs bounds checks in debug mode
*/ */
inline T& operator[](int n) { 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); debugAssert(data!=NULL);
return data[n]; return data[n];
} }
inline T& operator[](unsigned int n) { inline T& operator[](uint32 n) {
debugAssertM(n < (unsigned int)num, format("Array index out of bounds. n = %d, size() = %d", n, num)); 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]; return data[n];
} }
@@ -737,13 +889,19 @@ public:
Performs bounds checks in debug mode Performs bounds checks in debug mode
*/ */
inline const T& operator[](int n) const { inline const T& operator[](int n) const {
debugAssert((n >= 0) && (n < num)); debugAssert((n >= 0) && (n < (int)num));
debugAssert(data != NULL); debugAssert(data != NULL);
return data[n]; return data[n];
} }
inline const T& operator[](unsigned int n) const { inline const T& operator[](uint32 n) const {
debugAssert((n < (unsigned int)num)); debugAssert((n < (uint32)num));
debugAssert(data!=NULL);
return data[n];
}
inline const T& operator[](uint64 n) const {
debugAssert((n < (uint64)num));
debugAssert(data!=NULL); debugAssert(data!=NULL);
return data[n]; return data[n];
} }
@@ -751,7 +909,7 @@ public:
inline T& randomElement() { inline T& randomElement() {
debugAssert(num > 0); debugAssert(num > 0);
debugAssert(data!=NULL); debugAssert(data!=NULL);
return data[iRandom(0, num - 1)]; return data[iRandom(0, (int)num - 1)];
} }
inline const T& randomElement() const { inline const T& randomElement() const {
@@ -821,13 +979,18 @@ public:
Calls delete on all objects[0...size-1] Calls delete on all objects[0...size-1]
and sets the size to zero. and sets the size to zero.
*/ */
void deleteAll() { void invokeDeleteOnAllElements() {
for (int i = 0; i < num; i++) { for (size_t i = 0; i < num; ++i) {
delete data[i]; delete data[i];
} }
resize(0); resize(0);
} }
/** \deprecated */
void G3D_DEPRECATED deleteAll() {
invokeDeleteOnAllElements();
}
/** /**
Returns the index of (the first occurance of) an index or -1 if Returns the index of (the first occurance of) an index or -1 if
not found. Searches from the right. not found. Searches from the right.
@@ -846,9 +1009,9 @@ public:
not found. not found.
*/ */
int findIndex(const T& value) const { 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) { if (data[i] == value) {
return i; return (int)i;
} }
} }
return -1; return -1;
@@ -894,8 +1057,8 @@ public:
} }
void remove(int index, int count = 1) { void remove(int index, int count = 1) {
debugAssert((index >= 0) && (index < num)); debugAssert((index >= 0) && (index < (int)num));
debugAssert((count > 0) && (index + count <= num)); debugAssert((count > 0) && (index + count <= (int)num));
remove(begin() + index, count); remove(begin() + index, count);
} }
@@ -906,8 +1069,8 @@ public:
void reverse() { void reverse() {
T temp; T temp;
int n2 = num / 2; size_t n2 = num / 2;
for (int i = 0; i < n2; ++i) { for (size_t i = 0; i < n2; ++i) {
temp = data[num - 1 - i]; temp = data[num - 1 - i];
data[num - 1 - i] = data[i]; data[num - 1 - i] = data[i];
data[i] = temp; data[i] = temp;
@@ -917,29 +1080,29 @@ public:
/** /**
Sort using a specific less-than function, e.g.: Sort using a specific less-than function, e.g.:
<PRE> \code
bool __cdecl myLT(const MyClass& elem1, const MyClass& elem2) { bool __cdecl myLT(const MyClass& elem1, const MyClass& elem2) {
return elem1.x < elem2.x; return elem1.x < elem2.x;
} }
</PRE> \endcode
Note that for pointer arrays, the <CODE>const</CODE> must come Note that for pointer arrays, the <CODE>const</CODE> must come
<I>after</I> the class name, e.g., <CODE>Array<MyClass*></CODE> uses: <I>after</I> the class name, e.g., <CODE>Array<MyClass*></CODE> uses:
<PRE> \code
bool __cdecl myLT(MyClass*const& elem1, MyClass*const& elem2) { bool __cdecl myLT(MyClass*const& elem1, MyClass*const& elem2) {
return elem1->x < elem2->x; return elem1->x < elem2->x;
} }
</PRE> \endcode
or a functor, e.g., or a functor, e.g.,
<pre> \code
bool bool
less_than_functor::operator()( const double& lhs, const double& rhs ) const less_than_functor::operator()( const double& lhs, const double& rhs ) const
{ {
return( lhs < rhs? true : false ); return( lhs < rhs? true : false );
} }
</pre> \endcode
*/ */
// void sort(bool (__cdecl *lessThan)(const T& elem1, const T& elem2)) { // void sort(bool (__cdecl *lessThan)(const T& elem1, const T& elem2)) {
// std::sort(data, data + num, lessThan); // 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 Sorts the array in increasing order using the > or < operator. To
invoke this method on Array<T>, T must override those operator. invoke this method on Array<T>, T must override those operator.
You can overide these operators as follows: You can overide these operators as follows:
<code> \code
bool T::operator>(const T& other) const { bool T::operator>(const T& other) const {
return ...; return ...;
} }
bool T::operator<(const T& other) const { bool T::operator<(const T& other) const {
return ...; return ...;
} }
</code> \endcode
*/ */
void sort(int direction = SORT_INCREASING) { void sort(int direction = SORT_INCREASING) {
if (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 // Form a table of buckets for lt, eq, and gt
Array<T>* bucket[3] = {&ltArray, &eqArray, &gtArray}; Array<T>* bucket[3] = {&ltArray, &eqArray, &gtArray};
for (int i = 0; i < num; ++i) { for (size_t i = 0; i < num; ++i) {
int c = comparator(partitionElement, data[i]); int c = comparator(partitionElement, data[i]);
debugAssertM(c >= -1 && c <= 1, "Comparator returned an illegal value."); debugAssertM(c >= -1 && c <= 1, "Comparator returned an illegal value.");
@@ -1237,6 +1400,8 @@ return( lhs < rhs? true : false );
} }
/** Redistributes the elements so that the new order is statistically independent /** Redistributes the elements so that the new order is statistically independent
of the original order. O(n) time.*/ of the original order. O(n) time.*/
void randomize() { void randomize() {
@@ -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<T>) + (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);
}
}; };

View File

@@ -28,7 +28,7 @@ namespace G3D {
*/ */
class AtomicInt32 { class AtomicInt32 {
private: private:
# if defined(G3D_WIN32) # if defined(G3D_WINDOWS)
volatile long m_value; volatile long m_value;
# elif defined(G3D_OSX) # elif defined(G3D_OSX)
int32_t m_value; int32_t m_value;
@@ -70,18 +70,22 @@ public:
/** Returns the old value, before the add. */ /** Returns the old value, before the add. */
int32 add(const int32 x) { int32 add(const int32 x) {
# if defined(G3D_WIN32) # if defined(G3D_WINDOWS)
return InterlockedExchangeAdd(&m_value, x); return InterlockedExchangeAdd(&m_value, x);
# elif defined(G3D_LINUX) || defined(G3D_FREEBSD) # elif defined(G3D_LINUX) || defined(G3D_FREEBSD)
# if defined(__aarch64__)
return __sync_fetch_and_add(&m_value, x);
# else
int32 old; int32 old;
asm volatile ("lock; xaddl %0,%1" asm volatile ("lock; xaddl %0,%1"
: "=r"(old), "=m"(m_value) /* outputs */ : "=r"(old), "=m"(m_value) /* outputs */
: "0"(x), "m"(m_value) /* inputs */ : "0"(x), "m"(m_value) /* inputs */
: "memory", "cc"); : "memory", "cc");
return old; return old;
# endif
# elif defined(G3D_OSX) # elif defined(G3D_OSX)
@@ -98,7 +102,7 @@ public:
} }
void increment() { void increment() {
# if defined(G3D_WIN32) # if defined(G3D_WINDOWS)
// Note: returns the newly incremented value // Note: returns the newly incremented value
InterlockedIncrement(&m_value); InterlockedIncrement(&m_value);
# elif defined(G3D_LINUX) || defined(G3D_FREEBSD) # elif defined(G3D_LINUX) || defined(G3D_FREEBSD)
@@ -111,10 +115,13 @@ public:
/** Returns zero if the result is zero after decrement, non-zero otherwise.*/ /** Returns zero if the result is zero after decrement, non-zero otherwise.*/
int32 decrement() { int32 decrement() {
# if defined(G3D_WIN32) # if defined(G3D_WINDOWS)
// Note: returns the newly decremented value // Note: returns the newly decremented value
return InterlockedDecrement(&m_value); return InterlockedDecrement(&m_value);
# elif defined(G3D_LINUX) || defined(G3D_FREEBSD) # elif defined(G3D_LINUX) || defined(G3D_FREEBSD)
# if defined(__aarch64__)
return __sync_sub_and_fetch(&m_value, 1);
# else
unsigned char nz; unsigned char nz;
asm volatile ("lock; decl %1;\n\t" asm volatile ("lock; decl %1;\n\t"
@@ -123,6 +130,7 @@ public:
: "m" (m_value) : "m" (m_value)
: "memory", "cc"); : "memory", "cc");
return nz; return nz;
# endif
# elif defined(G3D_OSX) # elif defined(G3D_OSX)
// Note: returns the newly decremented value // Note: returns the newly decremented value
return OSAtomicDecrement32(&m_value); return OSAtomicDecrement32(&m_value);
@@ -140,9 +148,12 @@ public:
Under VC6 the sign bit may be lost. Under VC6 the sign bit may be lost.
*/ */
int32 compareAndSet(const int32 comperand, const int32 exchange) { int32 compareAndSet(const int32 comperand, const int32 exchange) {
# if defined(G3D_WIN32) # if defined(G3D_WINDOWS)
return InterlockedCompareExchange(&m_value, exchange, comperand); return InterlockedCompareExchange(&m_value, exchange, comperand);
# elif defined(G3D_LINUX) || defined(G3D_FREEBSD) || defined(G3D_OSX) # elif defined(G3D_LINUX) || defined(G3D_FREEBSD) || defined(G3D_OSX)
# if defined(__aarch64__)
return __sync_val_compare_and_swap(&m_value, comperand, exchange);
# else
// Based on Apache Portable Runtime // Based on Apache Portable Runtime
// http://koders.com/c/fid3B6631EE94542CDBAA03E822CA780CBA1B024822.aspx // http://koders.com/c/fid3B6631EE94542CDBAA03E822CA780CBA1B024822.aspx
int32 ret; int32 ret;
@@ -154,6 +165,7 @@ public:
// Note that OSAtomicCompareAndSwap32 does not return a useful value for us // Note that OSAtomicCompareAndSwap32 does not return a useful value for us
// so it can't satisfy the cmpxchgl contract. // so it can't satisfy the cmpxchgl contract.
# endif
# endif # endif
} }

92
deps/g3dlite/include/G3D/BIN.h vendored Normal file
View File

@@ -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

View File

@@ -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 \created 2001-08-09
@edited 2010-03-19 \edited 2013-01-03
Copyright 2000-2010, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -26,6 +26,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/unorm8.h"
#include "G3D/Array.h" #include "G3D/Array.h"
#include "G3D/Color4.h" #include "G3D/Color4.h"
#include "G3D/Color3.h" #include "G3D/Color3.h"
@@ -39,7 +40,7 @@
namespace G3D { 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. // Allow writing of integers to non-word aligned locations.
// This is legal on x86, but not on other platforms. // This is legal on x86, but not on other platforms.
#define G3D_ALLOW_UNALIGNED_WRITES #define G3D_ALLOW_UNALIGNED_WRITES
@@ -69,8 +70,15 @@ class BinaryInput {
private: private:
// The initial buffer will be no larger than this, but // The initial buffer will be no larger than this, but
// may grow if a large memory read occurs. 50 MB // may grow if a large memory read occurs. 750 MB
enum {INITIAL_BUFFER_LENGTH = 50000000}; static const int64
INITIAL_BUFFER_LENGTH =
#ifdef G3D_64BIT
5000000000L // 5 GB
#else
750000000 // 750 MB
#endif
;
/** /**
is the file big or little endian 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. /** When operating on huge files, we cannot load the whole file into memory.
This is the file position to which buffer[0] corresponds. 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; int64 m_alreadyRead;
@@ -122,14 +131,8 @@ private:
void loadIntoMemory(int64 startPosition, int64 minLength = 0); void loadIntoMemory(int64 startPosition, int64 minLength = 0);
/** Verifies that at least this number of bytes can be read.*/ /** Verifies that at least this number of bytes can be read.*/
inline void prepareToRead(int64 nbytes) { 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.");
if (m_pos + nbytes > m_bufferLength) {
loadIntoMemory(m_pos + m_alreadyRead, nbytes);
}
}
// Not implemented on purpose, don't use // Not implemented on purpose, don't use
BinaryInput(const BinaryInput&); BinaryInput(const BinaryInput&);
@@ -165,6 +168,7 @@ public:
To decompress part of a file, you can follow the following paradigm: To decompress part of a file, you can follow the following paradigm:
\htmlonly
<PRE> <PRE>
BinaryInput master(...); BinaryInput master(...);
@@ -176,6 +180,7 @@ public:
// Now read from subset (it is ok for master to go out of scope) // Now read from subset (it is ok for master to go out of scope)
</PRE> </PRE>
\endhtmlonly
*/ */
BinaryInput( BinaryInput(
const uint8* data, const uint8* data,
@@ -199,24 +204,13 @@ public:
return m_filename; 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 Performs bounds checks in debug mode. [] are relative to
the start of the file, not the current position. the start of the file, not the current position.
Seeks to the new position before reading (and leaves Seeks to the new position before reading (and leaves
that as the current position) that as the current position)
*/ */
inline uint8 operator[](int64 n) { uint8 operator[](int64 n) {
setPosition(n); setPosition(n);
return readUInt8(); return readUInt8();
} }
@@ -224,11 +218,11 @@ public:
/** /**
Returns the length of the file in bytes. Returns the length of the file in bytes.
*/ */
inline int64 getLength() const { int64 getLength() const {
return m_length; return m_length;
} }
inline int64 size() const { int64 size() const {
return getLength(); return getLength();
} }
@@ -236,15 +230,26 @@ public:
Returns the current byte position in the file, Returns the current byte position in the file,
where 0 is the beginning and getLength() - 1 is the end. where 0 is the beginning and getLength() - 1 is the end.
*/ */
inline int64 getPosition() const { int64 getPosition() const {
return m_pos + m_alreadyRead; 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. Sets the position. Cannot set past length.
May throw a char* when seeking backwards more than 10 MB on a huge file. 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"); debugAssertM(p <= m_length, "Read past end of file");
m_pos = p - m_alreadyRead; m_pos = p - m_alreadyRead;
if ((m_pos < 0) || (m_pos > m_bufferLength)) { if ((m_pos < 0) || (m_pos > m_bufferLength)) {
@@ -255,25 +260,31 @@ public:
/** /**
Goes back to the beginning of the file. Goes back to the beginning of the file.
*/ */
inline void reset() { void reset() {
setPosition(0); setPosition(0);
} }
inline int8 readInt8() { void readBytes(void* bytes, int64 n);
int8 readInt8() {
prepareToRead(1); prepareToRead(1);
return m_buffer[m_pos++]; return m_buffer[m_pos++];
} }
inline bool readBool8() { bool readBool8() {
return (readInt8() != 0); return (readInt8() != 0);
} }
inline uint8 readUInt8() { uint8 readUInt8() {
prepareToRead(1); prepareToRead(1);
return ((uint8*)m_buffer)[m_pos++]; return ((uint8*)m_buffer)[m_pos++];
} }
uint16 inline readUInt16() { unorm8 readUNorm8() {
return unorm8::fromBits(readUInt8());
}
uint16 readUInt16() {
prepareToRead(2); prepareToRead(2);
m_pos += 2; m_pos += 2;
@@ -295,12 +306,12 @@ public:
} }
inline int16 readInt16() { int16 readInt16() {
uint16 a = readUInt16(); uint16 a = readUInt16();
return *(int16*)&a; return *(int16*)&a;
} }
inline uint32 readUInt32() { uint32 readUInt32() {
prepareToRead(4); prepareToRead(4);
m_pos += 4; m_pos += 4;
@@ -326,19 +337,19 @@ public:
} }
inline int32 readInt32() { int32 readInt32() {
uint32 a = readUInt32(); uint32 a = readUInt32();
return *(int32*)&a; return *(int32*)&a;
} }
uint64 readUInt64(); uint64 readUInt64();
inline int64 readInt64() { int64 readInt64() {
uint64 a = readUInt64(); uint64 a = readUInt64();
return *(int64*)&a; return *(int64*)&a;
} }
inline float32 readFloat32() { float32 readFloat32() {
union { union {
uint32 a; uint32 a;
float32 b; float32 b;
@@ -347,7 +358,7 @@ public:
return b; return b;
} }
inline float64 readFloat64() { float64 readFloat64() {
union { union {
uint64 a; uint64 a;
float64 b; float64 b;
@@ -356,31 +367,34 @@ public:
return b; return b;
} }
void readBytes(void* bytes, int64 n);
/** /**
Reads an n character string. The string is not Always consumes \a maxLength characters. Reads a string until NULL or \a maxLength characters. Does not require NULL termination.
required to end in NULL in the file but will
always be a proper std::string when returned.
*/ */
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(); 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 ("&#92;r", "&#92;n", "&#92;r&#92;n", "&#92;n&#92;r") or the end of the file is encountered. Consumes the newline.
*/
std::string readStringNewline(); std::string readStringNewline();
/** /**
Reads until NULL or the end of the file is encountered. Reads until NULL or the end of the file is encountered.
If the string has odd length (including NULL), reads 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(); std::string readStringEven();
/** Reads a uint32 and then calls readString(maxLength) with that value as the length. */
std::string readString32(); std::string readString32();
Vector4 readVector4(); Vector4 readVector4();
@@ -393,14 +407,14 @@ public:
/** /**
Skips ahead n bytes. Skips ahead n bytes.
*/ */
inline void skip(int64 n) { void skip(int64 n) {
setPosition(m_pos + m_alreadyRead + n); setPosition(m_pos + m_alreadyRead + n);
} }
/** /**
Returns true if the position is not at the end of the file Returns true if the position is not at the end of the file
*/ */
inline bool hasMore() const { bool hasMore() const {
return m_pos + m_alreadyRead < m_length; return m_pos + m_alreadyRead < m_length;
} }

View File

@@ -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 \created 2001-08-09
@edited 2008-01-24 \edited 2011-08-24
Copyright 2000-2006, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_BINARYOUTPUT_H #ifndef G3D_BinaryOutput_h
#define G3D_BINARYOUTPUT_H #define G3D_BinaryOutput_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include <assert.h> #include <assert.h>
@@ -19,6 +19,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
#include "G3D/unorm8.h"
#include "G3D/Color4.h" #include "G3D/Color4.h"
#include "G3D/Color3.h" #include "G3D/Color3.h"
#include "G3D/Vector4.h" #include "G3D/Vector4.h"
@@ -73,19 +74,19 @@ private:
uint8* m_buffer; uint8* m_buffer;
/** Size of the elements used */ /** Size of the elements used */
int m_bufferLen; size_t m_bufferLen;
/** Underlying size of memory allocaded */ /** Underlying size of memory allocaded */
int m_maxBufferLen; size_t m_maxBufferLen;
/** Next byte in file */ /** Next byte in file */
int m_pos; int64 m_pos;
/** is this initialized? */ /** is this initialized? */
bool m_init; bool m_init;
/** Number of bytes already written to the file.*/ /** Number of bytes already written to the file. Even on 32-bit OS, this can be 64-bits*/
size_t m_alreadyWritten; int64 m_alreadyWritten;
bool m_ok; bool m_ok;
@@ -97,11 +98,11 @@ private:
Make sure at least bytes can be written, resizing if Make sure at least bytes can be written, resizing if
necessary. necessary.
*/ */
inline void reserveBytes(int bytes) { inline void reserveBytes(size_t bytes) {
debugAssert(bytes > 0); 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) { if (m_bufferLen > m_maxBufferLen) {
reallocBuffer(bytes, oldBufferLen); reallocBuffer(bytes, oldBufferLen);
} }
@@ -138,8 +139,10 @@ public:
Cannot be used for huge files (ones where the data Cannot be used for huge files (ones where the data
was already written to disk)-- will throw char*. 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.*/ /** True if no errors have been encountered.*/
bool ok() const; bool ok() const;
@@ -190,11 +193,11 @@ public:
void reset(); void reset();
inline int length() const { inline int64 length() const {
return (int)m_bufferLen + (int)m_alreadyWritten; return m_bufferLen + m_alreadyWritten;
} }
inline int size() const { inline int64 size() const {
return length(); return length();
} }
@@ -207,18 +210,18 @@ public:
Throws char* when resetting a huge file to be shorter Throws char* when resetting a huge file to be shorter
than its current length. than its current length.
*/ */
inline void setLength(int n) { inline void setLength(int64 n) {
n = n - (int)m_alreadyWritten; n = n - m_alreadyWritten;
if (n < 0) { if (n < 0) {
throw "Cannot resize huge files to be shorter."; throw "Cannot resize huge files to be shorter.";
} }
if (n < m_bufferLen) { if (n < (int64)m_bufferLen) {
m_pos = n; m_pos = n;
} }
if (n > m_bufferLen) { if (n > (int64)m_bufferLen) {
reserveBytes(n - m_bufferLen); reserveBytes((size_t)(n - m_bufferLen));
} }
} }
@@ -227,7 +230,7 @@ public:
where 0 is the beginning and getLength() - 1 is the end. where 0 is the beginning and getLength() - 1 is the end.
*/ */
inline int64 position() const { 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. May throw a char* exception when seeking backwards on a huge file.
*/ */
inline void setPosition(int64 p) { 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)); setLength((int)(p + (int64)m_alreadyWritten));
} }
@@ -253,9 +256,9 @@ public:
} }
void writeBytes( void writeBytes
const void* b, (const void* b,
int count) { size_t count) {
reserveBytes(count); reserveBytes(count);
debugAssert(m_pos >= 0); debugAssert(m_pos >= 0);
@@ -270,7 +273,7 @@ public:
inline void writeInt8(int8 i) { inline void writeInt8(int8 i) {
reserveBytes(1); reserveBytes(1);
m_buffer[m_pos] = *(uint8*)&i; m_buffer[m_pos] = *(uint8*)&i;
m_pos++; ++m_pos;
} }
inline void writeBool8(bool b) { inline void writeBool8(bool b) {
@@ -280,7 +283,11 @@ public:
inline void writeUInt8(uint8 i) { inline void writeUInt8(uint8 i) {
reserveBytes(1); reserveBytes(1);
m_buffer[m_pos] = i; m_buffer[m_pos] = i;
m_pos++; ++m_pos;
}
inline void writeUNorm8(unorm8 i) {
writeUInt8(i.bits());
} }
void writeUInt16(uint16 u); void writeUInt16(uint16 u);
@@ -328,6 +335,20 @@ public:
writeString(s.c_str()); 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); void writeString(const char* s);
/** /**
@@ -340,12 +361,11 @@ public:
void writeStringEven(const char* s); void writeStringEven(const char* s);
void writeString32(const char* s); void writeString32(const char* s);
/** /**
Write a string with a 32-bit length field in front Write a NULL-terminated string with a 32-bit length field in front
of it. of it. The NULL character is included in the length count.
*/ */
void writeString32(const std::string& s) { void writeString32(const std::string& s) {
writeString32(s.c_str()); writeString32(s.c_str());
@@ -365,8 +385,8 @@ public:
Skips ahead n bytes. Skips ahead n bytes.
*/ */
inline void skip(int n) { inline void skip(int n) {
if (m_pos + n > m_bufferLen) { if (m_pos + n > (int64)m_bufferLen) {
setLength((int)m_pos + (int)m_alreadyWritten + n); setLength(m_pos + m_alreadyWritten + n);
} }
m_pos += n; m_pos += n;
} }

View File

@@ -1,20 +1,20 @@
/** /**
@file Box.h \file G3D/Box.h
Box class 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 <A HREF="http://www.magic-software.com">http://www.magic-software.com</A> \cite Portions based on Dave Eberly's Magic Software Library at <A HREF="http://www.magic-software.com">http://www.magic-software.com</A>
@created 2001-06-02 \created 2001-06-02
@edited 2007-06-05 \edited 2013-04-13
Copyright 2000-2006, Morgan McGuire. Copyright 2000-2013, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_BOX_H #ifndef G3D_Box_h
#define G3D_BOX_H #define G3D_Box_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Vector3.h" #include "G3D/Vector3.h"
@@ -24,13 +24,12 @@
namespace G3D { namespace G3D {
class CoordinateFrame; class CoordinateFrame;
class Any;
/** /**
An arbitrary 3D box, useful as a bounding box. \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: To construct a box from a coordinate frame, center and extent, use the idiom:
<CODE>Box box = cframe.toObjectSpace(Box(center - extent/2, center + extent/2));</CODE> <CODE>Box box = cframe.toObjectSpace(Box(center - extent/2, center + extent/2));</CODE>
*/ */
class Box { class Box {
@@ -41,29 +40,14 @@ private:
friend class CoordinateFrame; friend class CoordinateFrame;
/** /**
<PRE> Axes with length equal to the 4 edges that run along each of them
3 2 7 6
0 1 4 5
front back (seen through front)
</PRE>
*/ */
Vector3 _corner[8]; Vector3 _edgeVector[3];
/** Point3 _center;
Unit axes.
*/
Vector3 _axis[3];
Vector3 _center;
/**
Extent along each axis.
*/
Vector3 _extent;
float _area; float _area;
float _volume; float _volume;
void init( void init(
@@ -72,38 +56,47 @@ private:
public: public:
/**
Does not initialize the fields.
*/
Box(); Box();
explicit Box(const Any& a);
/** /**
Constructs a box from two opposite corners. Constructs a box from two opposite corners.
*/ */
Box( Box(const Vector3& min,
const Vector3& min,
const Vector3& max); 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); Box(const class AABox& b);
explicit Box(const Point3& p);
static Box inf();
Any toAny() const;
void serialize(class BinaryOutput& b) const; void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b); void deserialize(class BinaryInput& b);
/** /**
Returns the object to world transformation for 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 objects into the space where the box axes are
(1,0,0), (0,1,0), (0,0,1). Note that there (1,0,0), (0,1,0), (0,0,1). Note that there
is no scaling in this transformation. is no scaling in this transformation.
*/ */
CoordinateFrame localFrame() const; CoordinateFrame localFrame() const;
/** \sa localFrame */
void getLocalFrame(CoordinateFrame& frame) const; void getLocalFrame(CoordinateFrame& frame) const;
Box operator*(float f) const;
/** /**
Returns the centroid of the box. Returns the centroid of the box.
*/ */
@@ -111,18 +104,39 @@ public:
return _center; return _center;
} }
/**
\htmlonly
<PRE>
inline Vector3 corner(int i) const {
debugAssert(i < 8); 2--------3
return _corner[i]; / : /|
} / : / |
6--------7 |
| : | |
| 0....|..1
| / | /
|/ |/
4--------5
y
^
|
|-->x
z/
</PRE>
\endhtmlonly
*/
Vector3 corner(int i) const;
/** /**
Unit length. Unit length.
*/ */
inline Vector3 axis(int a) const { inline Vector3 axis(int a) const {
debugAssert(a < 3); debugAssert(a < 3);
return _axis[a]; return _edgeVector[a].direction();
} }
/** /**
@@ -131,16 +145,42 @@ public:
*/ */
inline float extent(int a) const { inline float extent(int a) const {
debugAssert(a < 3); debugAssert(a < 3);
return (float)_extent[a]; return _edgeVector[a].length();
} }
inline Vector3 extent() const { 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). 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( void getFaceCorners(
int f, int f,

View File

@@ -6,7 +6,7 @@
\created 2010-01-28 \created 2010-01-28
\edited 2010-01-28 \edited 2010-01-28
Copyright 2000-2010, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -20,7 +20,7 @@ class Any;
/** /**
Not in the BumpMap class to avoid a circular dependency between Texture and BumpMap. Not in the BumpMap class to avoid a circular dependency between Texture and BumpMap.
G3D::GImage::computeNormalMap(). G3D::Image::computeNormalMap().
*/ */
class BumpMapPreprocess { class BumpMapPreprocess {
public: public:
@@ -46,7 +46,7 @@ public:
BumpMapPreprocess(const Any& any); BumpMapPreprocess(const Any& any);
operator Any() const; Any toAny() const;
bool operator==(const BumpMapPreprocess& other) const { bool operator==(const BumpMapPreprocess& other) const {
return return

View File

@@ -1,5 +1,5 @@
/** /**
@file CollisionDetection.h \file CollisionDetection.h
Moving collision detection for simple primitives. Moving collision detection for simple primitives.
@@ -12,15 +12,15 @@
Thanks to Max McGuire of Iron Lore for various bug fixes. Thanks to Max McGuire of Iron Lore for various bug fixes.
Box-Triangle by Tomas Akenine-Moller Box-Triangle by Tomas Akenine-Moller
@created 2001-11-19 \created 2001-11-19
@edited 2008-12-19 \edited 2010-11-10
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_COLLISIONDETECTION_H #ifndef G3D_CollisionDetection_h
#define G3D_COLLISIONDETECTION_H #define G3D_CollisionDetection_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Vector3.h" #include "G3D/Vector3.h"
@@ -68,16 +68,17 @@ namespace G3D {
<b>Static Collision Detection:</b> (Neither object is moving) <b>Static Collision Detection:</b> (Neither object is moving)
<table> <table>
<tr><td></td><td><b>Vector3</b></td><td><b>LineSegment</b></td><td><b>Ray *</b></td><td><b>Line</b></td><td><b>Plane</b></td><td><b>Triangle</b></td><td><b>Sphere</b></td><td><b>Cylinder</b></td><td><b>Capsule</b></td><td><b>AABox</b></td><td><b>Box</b></td></tr> <tr><td></td><td><b>Point3</b></td><td><b>LineSegment</b></td><td><b>Ray *</b></td><td><b>Line</b></td><td><b>Plane</b></td><td><b>Triangle</b></td><td><b>Sphere</b></td><td><b>Cylinder</b></td><td><b>Capsule</b></td><td><b>AABox</b></td><td><b>Box</b></td></tr>
<tr><td><b>Vector3</b></td><td>\link Vector3::operator== V3::==\endlink \link Vector3::fuzzyEq V3::fuzzy \endlink \link G3D::distance distance \endlink</td><td bgcolor=#C0C0C0 colspan=10 ></td></tr> <tr><td><b>Point3</b></td><td>\link Vector3::operator== P3::==\endlink \link Vector3::fuzzyEq V3::fuzzy \endlink \link G3D::distance distance \endlink</td><td bgcolor=#C0C0C0 colspan=10 ></td></tr>
<tr><td><b>LineSegment</b></td><td>\link LineSegment::closestPoint LS::closestPoint\endlink \link LineSegment::distance LS::distance\endlink \link CollisionDetection::closestPointOnLineSegment CD\endlink</td><td></td><td bgcolor=#C0C0C0 colspan=9 ></td></tr> <tr><td><b>LineSegment</b></td><td>\link LineSegment::closestPoint LS::closestPoint\endlink \link LineSegment::distance LS::distance\endlink \link CollisionDetection::closestPointOnLineSegment CD\endlink</td><td></td><td bgcolor=#C0C0C0 colspan=9 ></td></tr>
<tr><td><b>Ray *</b></td><td>Ray::closestPoint Ray::distance</td><td></td><td></td><td bgcolor=#C0C0C0 colspan=8 ></td></tr> <tr><td><b>Ray *</b></td><td>Ray::closestPoint Ray::distance</td><td></td><td></td><td bgcolor=#C0C0C0 colspan=8 ></td></tr>
<tr><td><b>Line</b></td><td>Line::closestPoint Line::distance</td><td></td><td>\link CollisionDetection::closestPointsBetweenLineAndLine CD\endlink</td><td></td><td bgcolor=#C0C0C0 colspan=7 ></td></tr> <tr><td><b>Line</b></td><td>Line::closestPoint Line::distance</td><td></td><td>\link CollisionDetection::closestPointsBetweenLineAndLine CD\endlink</td><td></td><td bgcolor=#C0C0C0 colspan=7 ></td></tr>
<tr><td><b>Plane</b></td><td></td><td></td><td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=6 ></td></tr> <tr><td><b>Plane</b></td><td></td><td></td><td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=6 ></td></tr>
<tr><td><b>Triangle</b></td><td></td><td></td><td></td><td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=5 ></td></tr> <tr><td><b>Triangle</b></td><td></td><td></td><td></td><td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=5 ></td></tr>
<tr><td><b>Sphere</b></td><td>Sphere::contains</td><td></td><td>\link CollisionDetection::collisionTimeForMovingPointFixedSphere CD \endlink, \link Ray::intersectionTime R::time\endlink</td><td></td><td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=4 ></td></tr> <tr><td><b>Sphere</b></td><td>Sphere::contains</td><td></td><td>\link CollisionDetection::collisionTimeForMovingPointFixedSphere CD \endlink, \link Ray::intersectionTime R::time\endlink</td><td></td><td></td><td>\link G3D::CollisionDetection::fixedSolidSphereIntersectsFixedTriangle CD\endlink</td><td>
\link G3D::CollisionDetection::penetrationDepthForFixedSphereFixedSphere CD\endlink</td><td bgcolor=#C0C0C0 colspan=4 ></td></tr>
<tr><td><b>Cylinder</b></td><td>Cylinder::contains</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=3 ></td></tr> <tr><td><b>Cylinder</b></td><td>Cylinder::contains</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=3 ></td></tr>
<tr><td><b>Capsule</b></td><td>Capsule::contains</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=2 ></td></tr> <tr><td><b>Capsule</b></td><td>Capsule::contains</td> <td></td> <td></td> <td></td> <td></td> <td>\link G3D::CollisionDetection::collisionTimeForMovingSphereFixedTriangle CD\endlink</td> <td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=2 ></td></tr>
<tr><td><b>AABox</b></td><td>AABox::contains</td><td></td><td></td><td></td><td></td><td>\link CollisionDetection::fixedSolidBoxIntersectsFixedTriangle CD\endlink</td><td></td><td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=1 ></td></tr> <tr><td><b>AABox</b></td><td>AABox::contains</td><td></td><td></td><td></td><td></td><td>\link CollisionDetection::fixedSolidBoxIntersectsFixedTriangle CD\endlink</td><td></td><td></td><td></td><td></td><td bgcolor=#C0C0C0 colspan=1 ></td></tr>
<tr><td><b>Box</b></td><td>Box::contains</td><td>(treat as Ray)</td><td>\link CollisionDetection::collisionTimeForMovingPointFixedBox CD\endlink</td><td>(treat as Ray)</td><td>\link CollisionDetection::penetrationDepthForFixedBoxFixedPlane CD \endlink</td><td>\link CollisionDetection::penetrationDepthForFixedBoxFixedPlane CD\endlink</td><td>\link CollisionDetection::penetrationDepthForFixedSphereFixedBox CD\endlink</td><td>None (use OPCODE)</td><td>\link CollisionDetection::movingSpherePassesThroughFixedBox CD \endlink</td><td>\link CollisionDetection::penetrationDepthForFixedBoxFixedBox CD\endlink</td><td>\link CollisionDetection::penetrationDepthForFixedBoxFixedBox CD\endlink</td></tr> <tr><td><b>Box</b></td><td>Box::contains</td><td>(treat as Ray)</td><td>\link CollisionDetection::collisionTimeForMovingPointFixedBox CD\endlink</td><td>(treat as Ray)</td><td>\link CollisionDetection::penetrationDepthForFixedBoxFixedPlane CD \endlink</td><td>\link CollisionDetection::penetrationDepthForFixedBoxFixedPlane CD\endlink</td><td>\link CollisionDetection::penetrationDepthForFixedSphereFixedBox CD\endlink</td><td>None (use OPCODE)</td><td>\link CollisionDetection::movingSpherePassesThroughFixedBox CD \endlink</td><td>\link CollisionDetection::penetrationDepthForFixedBoxFixedBox CD\endlink</td><td>\link CollisionDetection::penetrationDepthForFixedBoxFixedBox CD\endlink</td></tr>
</table> </table>
@@ -88,7 +89,7 @@ namespace G3D {
<i>* Note: Moving collision detection against certain primitives is equivalent to static collision <i>* 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''</i> detection against a bigger primitive. Ray, Line Segment == ``moving Point''; Capsule ==``moving Sphere''; Plane == ``moving Line''</i>
@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 { class CollisionDetection {
private: private:
@@ -111,7 +112,6 @@ private:
*/ */
static Array<Vector3> ignoreArray; static Array<Vector3> ignoreArray;
// Static class! // Static class!
CollisionDetection() {} CollisionDetection() {}
virtual ~CollisionDetection() {} virtual ~CollisionDetection() {}
@@ -453,7 +453,7 @@ public:
@param point Moving point. @param point Moving point.
@param velocity Point's velocity. @param velocity Point's velocity.
@param plane Fixed plane. @param plane Fixed plane.
@param location Location of collision. [Post Condition] @param outLocation Location of collision. [Post Condition]
(Infinite vector on no collision) (Infinite vector on no collision)
@param outNormal Plane's surface normal. [Post Condition] @param outNormal Plane's surface normal. [Post Condition]
@@ -624,8 +624,8 @@ public:
@param point Moving point. @param point Moving point.
@param velocity Sphere's velocity. @param velocity Sphere's velocity.
@param box Fixed AAbox. @param box Fixed AAbox.
@param location Location of collision. [Post Condition] @param outLocation Location of collision. [Post Condition]
@param Inside Does the ray originate inside the box? [Post Condition] @param inside Does the ray originate inside the box? [Post Condition]
@param normal Box's surface normal to collision [Post Condition] @param normal Box's surface normal to collision [Post Condition]
@return Time til collision. If there is no collision then the return @return Time til collision. If there is no collision then the return
@@ -696,7 +696,7 @@ public:
@param point Moving point. @param point Moving point.
@param velocity Sphere's velocity. @param velocity Sphere's velocity.
@param box Fixed box. @param box Fixed box.
@param location Position of collision. [Post Condition] @param outLocation Position of collision. [Post Condition]
@param outNormal Box's surface normal to 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 @return Time til collision. If there is no collision then the return
@@ -723,7 +723,7 @@ public:
@param v1 Rectangle vertex 2. @param v1 Rectangle vertex 2.
@param v2 Rectangle vertex 3 @param v2 Rectangle vertex 3
@param v3 Rectangle vertex 4. @param v3 Rectangle vertex 4.
@param location Location of collision [Post Condition] @param outLocation Location of collision [Post Condition]
@param outNormal Rectangle's surface normal. [Post Condition] @param outNormal Rectangle's surface normal. [Post Condition]
@return Time til collision. If there is no collision then the return @return Time til collision. If there is no collision then the return
@@ -784,16 +784,16 @@ public:
Calculates time between the intersection of a moving sphere and a fixed Calculates time between the intersection of a moving sphere and a fixed
triangle. triangle.
@param sphere Moving sphere. @param sphere The moving sphere.
@param velocity Sphere's velocity. @param velocity The sphere's velocity.
@param triangle Fixed Triangle. (collisions can happen on the back side of the triangle) @param triangle Single-sided fixed triangle.
@param outLocation Location of collision, if collision occurs -- not center position of sphere @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 at the collision time. If there is interpenetration at the start, this point may be inside
the sphere. the sphere.
@param b Barycentric coordinates. These are not valid unless collision occurs. @param b Barycentric coordinates. These are not valid unless collision occurs.
@return Time til collision. If there is no collision then the return @return Time until collision. If there is no collision then the return
value will be inf(). value will be finf().
*/ */
static float collisionTimeForMovingSphereFixedTriangle( static float collisionTimeForMovingSphereFixedTriangle(
const class Sphere& sphere, const class Sphere& sphere,
@@ -839,7 +839,7 @@ public:
@param sphere Moving sphere. @param sphere Moving sphere.
@param velocity Sphere's velocity. @param velocity Sphere's velocity.
@param box Fixed box. @param box Fixed box.
@param location Location of collision -- not center position of sphere @param outLocation Location of collision -- not center position of sphere
at the collision time. [Post Condition] at the collision time. [Post Condition]
@param outNormal Box's surface normal to collision [Post Condition] @param outNormal Box's surface normal to collision [Post Condition]
@@ -887,7 +887,7 @@ public:
@param sphere Moving sphere. @param sphere Moving sphere.
@param velocity Sphere's velocity. @param velocity Sphere's velocity.
@param capsule Fixed capsule. @param capsule Fixed capsule.
@param location Location of collision -- not center position of sphere @param outLocation Location of collision -- not center position of sphere
at the collision time. [Post Condition] at the collision time. [Post Condition]
@param outNormal Capsule's surface normal to the collision [Post Condition] @param outNormal Capsule's surface normal to the collision [Post Condition]

View File

@@ -1,30 +1,29 @@
/** /**
@file Color1.h \file G3D/Color1.h
Monochrome Color class Monochrome Color class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2007-01-31 \created 2007-01-31
@edited 2009-03-20 \edited 2011-08-20
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_COLOR1_H #ifndef G3D_Color1_h
#define G3D_COLOR1_H #define G3D_Color1_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
#include "G3D/unorm8.h"
#include "G3D/HashTrait.h" #include "G3D/HashTrait.h"
#include <string> #include <string>
namespace G3D { namespace G3D {
/** /**
Monochrome color. This is just a float, but it has nice semantics Monochrome color.
because a scaling by 255 automatically occurs when switching between
fixed point (Color1uint8) and floating point (Color1) formats.
*/ */
class Color1 { class Color1 {
private: private:
@@ -47,6 +46,9 @@ public:
inline explicit Color1(float v) : value(v) { inline explicit Color1(float v) : value(v) {
} }
inline explicit Color1(unorm8 v) : value(v) {
}
inline bool isZero() const { inline bool isZero() const {
return value == 0.0f; return value == 0.0f;
} }
@@ -62,7 +64,7 @@ public:
/** Returns the value three times */ /** Returns the value three times */
class Color3 rgb() const; class Color3 rgb() const;
Color1 (const class Color1uint8& other); explicit Color1(const class Color1unorm8& other);
void serialize(class BinaryOutput& bo) const; void serialize(class BinaryOutput& bo) const;
void deserialize(class BinaryInput& bi); void deserialize(class BinaryInput& bi);
@@ -71,6 +73,7 @@ public:
return Color1(value + other.value); return Color1(value + other.value);
} }
/** \deprecated */
Color1 operator+ (const float other) const { Color1 operator+ (const float other) const {
return Color1(value + other); return Color1(value + other);
} }
@@ -89,6 +92,7 @@ public:
return Color1(value - other.value); return Color1(value - other.value);
} }
/** \deprecated */
Color1 operator- (const float other) const { Color1 operator- (const float other) const {
return Color1(value - other); return Color1(value - other);
} }
@@ -101,6 +105,26 @@ public:
return Color1(value * other.value); 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 { Color1 operator* (const float other) const {
return Color1(value * other); return Color1(value * other);
} }
@@ -140,5 +164,8 @@ struct HashTrait<G3D::Color1> {
} }
}; };
inline G3D::Color1 operator*(float f, G3D::Color1 c) {
return c * f;
}
#endif #endif

View File

@@ -1,16 +1,16 @@
/** /**
@file Color3.h \file Color3.h
Color class Color 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 \cite Portions based on Dave Eberly's Magic Software Library
at <A HREF="http://www.magic-software.com">http://www.magic-software.com</A> at <A HREF="http://www.magic-software.com">http://www.magic-software.com</A>
@created 2001-06-02 \created 2001-06-02
@edited 2009-04-28 \edited 2013-03-29
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2013, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -40,26 +40,41 @@ private:
public: 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: /** \param any Must be in one of the following forms:
- Color3(#, #, #) - Color3(#, #, #)
- Color3(#)
- Color3::fromARGB(#) - Color3::fromARGB(#)
- Color3::fromASRGB(#)
- Color3{r = #, g = #, b = #) - Color3{r = #, g = #, b = #)
- Color3::one() - Color3::one()
- Color3::zero() - 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. */ /** Converts the Color3 to an Any. */
operator Any() const; Any toAny() const;
explicit Color3(class BinaryInput& bi); explicit Color3(class BinaryInput& bi);
Color3(float r, float g, float b); 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); explicit Color3(const class Vector3& v);
@@ -75,7 +90,7 @@ public:
*/ */
Color3 (const Color3& other); Color3 (const Color3& other);
Color3 (const class Color3uint8& other); Color3 (const class Color3unorm8& other);
inline bool isZero() const { inline bool isZero() const {
return (r == 0.0f) && (g == 0.0f) && (b == 0.0f); return (r == 0.0f) && (g == 0.0f) && (b == 0.0f);
@@ -92,6 +107,12 @@ public:
*/ */
static Color3 fromARGB(uint32); 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). /** Returns one of the color wheel colors (e.g. RED, GREEN, CYAN).
Does not include white, black, or gray. */ Does not include white, black, or gray. */
static const Color3& wheelRandom(); static const Color3& wheelRandom();
@@ -140,10 +161,15 @@ public:
inline Color3 operator* (float s) const { inline Color3 operator* (float s) const {
return Color3(r * s, g * s, b * s); 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; Color3 operator* (const Color3& rkVector) const;
inline Color3 operator/ (float fScalar) const { inline Color3 operator/ (float fScalar) const {
return (*this) * (1.0f / fScalar); return (*this) * (1.0f / fScalar);
} }
Color3 operator- () const; Color3 operator- () const;
// arithmetic updates // arithmetic updates
@@ -161,7 +187,7 @@ public:
Color3 direction() const; Color3 direction() const;
float squaredLength () const; float squaredLength () const;
float dot (const Color3& rkVector) 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 cross (const Color3& rkVector) const;
Color3 unitCross (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; return c * s.value;
} }
inline G3D::Color3 operator/ (float s, const G3D::Color3& c) {
//---------------------------------------------------------------------------- return c * (1.0f/s);
inline Color3::Color3 () {
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
inline Color3::Color3(float fX, float fY, float fZ) { 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 { inline Color3 Color3::unitCross (const Color3& rkVector) const {
Color3 kCross(g*rkVector.b - b*rkVector.g, b*rkVector.r - r*rkVector.b, Color3 kCross(g*rkVector.b - b*rkVector.g, b*rkVector.r - r*rkVector.b,
r*rkVector.g - g*rkVector.r); r*rkVector.g - g*rkVector.r);
kCross.unitize(); return kCross.direction();
return kCross;
} }
/** 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 } // namespace

View File

@@ -48,16 +48,16 @@ public:
Color4(const Any& any); Color4(const Any& any);
/** Converts the Color4 to an 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 Color3& c3, float a = 1.0);
Color4(const class Color4uint8& c); Color4(const class Color4unorm8& c);
Color4(class BinaryInput& bi); 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) { inline Color4::Color4(const Color3& c3, float a) {
r = c3.r; r = c3.r;

View File

@@ -61,6 +61,19 @@ public:
True if v is a point inside the cone. True if v is a point inside the cone.
*/ */
bool contains(const class Vector3& v) const; 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 } // namespace

View File

@@ -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 \created 2001-03-04
@edited 2009-04-29 \edited 2012-07-29
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -33,9 +33,10 @@
namespace G3D { namespace G3D {
class Any; 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: CoordinateFrame abstracts a 4x4 matrix that maps object space to world space:
@@ -53,7 +54,7 @@ Convert to Matrix4 using CoordinateFrame::toMatrix4. You <I>can</I> construct a
from a Matrix4 using Matrix4::approxCoordinateFrame, however, because a Matrix4 is more from a Matrix4 using Matrix4::approxCoordinateFrame, however, because a Matrix4 is more
general than a CoordinateFrame, some information may be lost. 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 { class CoordinateFrame {
public: public:
@@ -61,20 +62,20 @@ public:
/** Takes object space points to world space. */ /** Takes object space points to world space. */
Matrix3 rotation; Matrix3 rotation;
/** Takes object space points to world space. */ /** The origin of this coordinate frame in world space (or its parent's space, if nested). */
Vector3 translation; Point3 translation;
/** \param any Must be in one of the following forms: /** \param any Must be in one of the following forms:
- CFrame((matrix3 expr), (vector3 expr)) - CFrame((matrix3 expr), (Point3 expr))
- CFrame::fromXYZYPRDegrees(#, #, #, #, #, #) - CFrame::fromXYZYPRDegrees(#, #, #, #, #, #)
- CFrame { rotation = (matrix3 expr), translation = (vector3 expr) } - CFrame { rotation = (Matrix3 expr), translation = (Point3 expr) }
- Vector3( ... ) - Point3( ... )
- Matrix3( ... ) - Matrix3( ... )
*/ */
CoordinateFrame(const Any& any); CoordinateFrame(const Any& any);
/** Converts the CFrame to an Any. */ /** Converts the CFrame to an Any. */
operator Any() const; Any toAny() const;
inline bool operator==(const CoordinateFrame& other) const { inline bool operator==(const CoordinateFrame& other) const {
return (translation == other.translation) && (rotation == other.rotation); return (translation == other.translation) && (rotation == other.rotation);
@@ -95,16 +96,16 @@ public:
*/ */
CoordinateFrame(); CoordinateFrame();
CoordinateFrame(const Vector3& _translation) : CoordinateFrame(const Point3& _translation) :
rotation(Matrix3::identity()), translation(_translation) { rotation(Matrix3::identity()), translation(_translation) {
} }
CoordinateFrame(const Matrix3 &rotation, const Vector3 &translation) : CoordinateFrame(const Matrix3& rotation, const Point3& translation) :
rotation(rotation), translation(translation) { rotation(rotation), translation(translation) {
} }
CoordinateFrame(const Matrix3& rotation) : CoordinateFrame(const Matrix3& rotation) :
rotation(rotation), translation(Vector3::zero()) { rotation(rotation), translation(Point3::zero()) {
} }
CoordinateFrame(const class UprightFrame& f); CoordinateFrame(const class UprightFrame& f);
@@ -187,9 +188,9 @@ public:
/** /**
Transforms the point into world space. Transforms the point into world space.
*/ */
inline Vector3 pointToWorldSpace(const Vector3& v) const { inline Point3 pointToWorldSpace(const Point3& v) const {
return Vector3( return Point3
rotation[0][0] * v[0] + rotation[0][1] * v[1] + rotation[0][2] * v[2] + translation[0], (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[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]); rotation[2][0] * v[0] + rotation[2][1] * v[1] + rotation[2][2] * v[2] + translation[2]);
} }
@@ -197,14 +198,13 @@ public:
/** /**
Transforms the point into object space. Assumes that the rotation matrix is orthonormal. 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]; float p[3];
p[0] = v[0] - translation[0]; p[0] = v[0] - translation[0];
p[1] = v[1] - translation[1]; p[1] = v[1] - translation[1];
p[2] = v[2] - translation[2]; p[2] = v[2] - translation[2];
debugAssert(G3D::fuzzyEq(rotation.determinant(), 1.0f)); debugAssert(G3D::fuzzyEq(fabsf(rotation.determinant()), 1.0f));
return Vector3( return Point3(rotation[0][0] * p[0] + rotation[1][0] * p[1] + rotation[2][0] * p[2],
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][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]); 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; Ray toWorldSpace(const Ray& r) const;
Frustum toWorldSpace(const Frustum& f) const;
/** /**
Transforms the vector into object space (no translation). Transforms the vector into object space (no translation).
*/ */
@@ -237,18 +239,20 @@ public:
return v * rotation; return v * rotation;
} }
void pointToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const; void pointToWorldSpace(const Array<Point3>& v, Array<Point3>& vout) const;
void normalToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const; void normalToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const;
void vectorToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const; void vectorToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const;
void pointToObjectSpace(const Array<Vector3>& v, Array<Vector3>& vout) const; void pointToObjectSpace(const Array<Point3>& v, Array<Point3>& vout) const;
void normalToObjectSpace(const Array<Vector3>& v, Array<Vector3>& vout) const; void normalToObjectSpace(const Array<Vector3>& v, Array<Vector3>& vout) const;
void vectorToObjectSpace(const Array<Vector3>& v, Array<Vector3>& vout) const; void vectorToObjectSpace(const Array<Vector3>& v, Array<Vector3>& 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 AABox& b) const;
class Box toWorldSpace(const class Box& b) const; class Box toWorldSpace(const class Box& b) const;
@@ -287,10 +291,25 @@ public:
return CoordinateFrame(rotation, translation - v); return CoordinateFrame(rotation, translation - v);
} }
void lookAt(const Vector3& target);
void lookAt( /**
const Vector3& target, 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); Vector3 up);
/** The direction this camera is looking (its negative z axis)*/ /** The direction this camera is looking (its negative z axis)*/
@@ -321,9 +340,11 @@ public:
/** /**
Linearly interpolates between two coordinate frames, using Linearly interpolates between two coordinate frames, using
Quat::slerp for the rotations. Quat::slerp for the rotations.
\sa moveTowards
*/ */
CoordinateFrame lerp( CoordinateFrame lerp
const CoordinateFrame& other, (const CoordinateFrame& other,
float alpha) const; float alpha) const;
}; };

View File

@@ -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 \created 2006-03-29
@edited 2006-04-06 \edited 2011-06-21
*/ */
#ifndef G3D_CRYPTO_H #ifndef G3D_Crypto_h
#define G3D_CRYPTO_H #define G3D_Crypto_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
#include "G3D/System.h"
#include <string> #include <string>
namespace G3D { namespace G3D {
@@ -33,6 +34,24 @@ public:
explicit MD5Hash(class BinaryInput& b); 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) { uint8& operator[](int i) {
return value[i]; return value[i];
} }
@@ -56,6 +75,18 @@ public:
void deserialize(class BinaryInput& b); void deserialize(class BinaryInput& b);
void serialize(class BinaryOutput& b) const; 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 @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 Returns the nth prime less than 2000 in constant time. The first prime has index

32
deps/g3dlite/include/G3D/FileNotFound.h vendored Normal file
View File

@@ -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 <string>
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

View File

@@ -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 \author 2002-06-06
@edited 2010-02-05 \edited 2012-03-26
*/ */
#ifndef G3D_FileSystem_h #ifndef G3D_FileSystem_h
#define G3D_FileSystem_h #define G3D_FileSystem_h
@@ -12,6 +12,8 @@
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Array.h" #include "G3D/Array.h"
#include "G3D/Table.h" #include "G3D/Table.h"
#include "G3D/Set.h"
#include "G3D/GMutex.h"
namespace G3D { namespace G3D {
@@ -34,11 +36,12 @@ namespace G3D {
<li> There are no nested zipfiles <li> There are no nested zipfiles
</ul> </ul>
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 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. zipfile without forcing it to open all parent directories for reading.
\sa FilePath \sa FilePath
TODO: make threadsafe!
*/ */
class FileSystem { class FileSystem {
public: public:
@@ -63,7 +66,7 @@ public:
ListSettings() : ListSettings() :
files(true), files(true),
directories(true), directories(true),
# ifdef G3D_WIN32 # ifdef G3D_WINDOWS
caseSensitive(true), caseSensitive(true),
# else # else
caseSensitive(false), caseSensitive(false),
@@ -111,8 +114,13 @@ private:
/** When this entry was last updated */ /** When this entry was last updated */
double lastChecked; double lastChecked;
/** Case-independent comparison on Windows */ bool contains(const std::string& child, bool caseSensitive =
bool contains(const std::string& child) const; #ifdef G3D_WINDOWS
false
#else
true
#endif
) const;
/** Compute the contents of nodeArray from this zipfile. */ /** Compute the contents of nodeArray from this zipfile. */
void computeZipListing(const std::string& zipfile, const std::string& pathInsideZipfile); void computeZipListing(const std::string& zipfile, const std::string& pathInsideZipfile);
@@ -132,39 +140,212 @@ private:
FileSystem(); FileSystem();
static FileSystem& instance(); 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<std::string>& _drives(); const Array<std::string>& _drives();
# endif # endif
/** \copydoc inZipfile */
bool _inZipfile(const std::string& path, std::string& zipfile);
/** \copydoc clearCache */
void _clearCache(const std::string& path);
/** \copydoc inZipfile */
bool _inZipfile(const std::string& path) {
std::string ignore;
return inZipfile(path, ignore);
}
/** \copydoc setCacheLifetime */
void _setCacheLifetime(float t);
/** \copydoc cacheLifetime */
float _cacheLifetime() const {
return m_cacheLifetime;
}
/** \copydoc createDirectory */
void _createDirectory(const std::string& path);
/** \copydoc exists */
bool _exists(const std::string& f, bool trustCache = true, bool caseSensitive =
#ifdef G3D_WINDOWS
false
#else
true
#endif
);
/** \copydoc isDirectory */
bool _isDirectory(const std::string& path);
/** \copydoc isFile */
bool _isFile(const std::string& path) {
return ! isDirectory(path);
}
/** \copydoc copyFile */
void _copyFile(const std::string& srcPath, const std::string& dstPath);
/** \copydoc resolve */
std::string _resolve(const std::string& path, const std::string& cwd = currentDirectory());
/** \copydoc isNewer */
bool _isNewer(const std::string& src, const std::string& dst);
/** \copydoc currentDirectory */
std::string _currentDirectory();
/** \copydoc size */
int64 _size(const std::string& path);
/** Called from list() */
void listHelper(const std::string& shortSpec, const std::string& parentPath, Array<std::string>& result, const ListSettings& settings);
/** \copydoc list */
void _list(const std::string& spec, Array<std::string>& result, const ListSettings& listSettings = ListSettings());
/** \copydoc isZipfile */
bool _isZipfile(const std::string& path);
/** \copydoc getFiles */
void _getFiles(const std::string& spec, Array<std::string>& result, bool includeParentPath = false) {
ListSettings set;
set.includeParentPath = includeParentPath;
set.directories = false;
set.files = true;
return list(spec, result, set);
}
/** \copydoc getDirectories */
void _getDirectories(const std::string& spec, Array<std::string>& result, bool includeParentPath = false) {
ListSettings set;
set.includeParentPath = includeParentPath;
set.directories = true;
set.files = false;
return list(spec, result, set);
}
/** \copydoc fopen */
FILE* _fopen(const char* filename, const char* mode);
/** \copydoc removeFile */
void _removeFile(const std::string& path);
public:
/** Create the common instance. */
static void init();
/** Destroy the common instance. */
static void cleanup();
# ifdef G3D_WINDOWS
/** On Windows, the drive letters that form the file system roots.*/
static const Array<std::string>& drives() {
mutex.lock();
const Array<std::string>& s = instance()._drives();
mutex.unlock();
return s;
}
# endif
/** Returns true if some sub-path of \a path is a zipfile. /** Returns true if some sub-path of \a path is a zipfile.
If the path itself is a zipfile, returns false. If the path itself is a zipfile, returns false.
\param zipfile The part of \a path that was the zipfile */ \param zipfile The part of \a path that was the zipfile
bool _inZipfile(const std::string& path, std::string& zipfile); */
static bool inZipfile(const std::string& path, std::string& zipfile) {
mutex.lock();
bool b = instance()._inZipfile(path, zipfile);
mutex.unlock();
return b;
}
/** Clears old cache entries so that exists() and list() will reflect recent changes to the file system. /** 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) */ \param path Clear only \a path and its subdirectories ("" means clear the entire cache) */
void _clearCache(const std::string& path); static void clearCache(const std::string& path = "") {
mutex.lock();
bool _inZipfile(const std::string& path) { instance()._clearCache(path);
std::string ignore; mutex.unlock();
return inZipfile(path, ignore);
} }
/** 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) {
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) {
mutex.lock();
bool b = instance()._inZipfile(path);
mutex.unlock();
return b;
}
/**
\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) {
mutex.lock();
bool b = instance()._isZipfile(path);
mutex.unlock();
return b;
}
/** Set the cacheLifetime(). /** Set the cacheLifetime().
\param t in seconds */ \param t in seconds */
void _setCacheLifetime(float t); void setCacheLifetime(float t) {
mutex.lock();
instance()._setCacheLifetime(t);
mutex.unlock();
}
/** A cache is used to optimize repeated calls. A cache entry is considered /** A cache is used to optimize repeated calls. A cache entry is considered
valid for this many seconds after it has been checked. */ valid for this many seconds after it has been checked. */
float _cacheLifetime() const { static float cacheLifetime() {
return m_cacheLifetime; mutex.lock();
float f = instance()._cacheLifetime();
mutex.unlock();
return f;
} }
/** Creates the directory named, including any subdirectories /** Creates the directory named, including any subdirectories
that do not already exist. that do not already exist.
@@ -172,34 +353,82 @@ private:
Flushes the cache. Flushes the cache.
*/ */
void _createDirectory(const std::string& path); static void createDirectory(const std::string& path) {
mutex.lock();
/** Returns true if a node named \a f exists. instance()._createDirectory(path);
mutex.unlock();
\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 */
bool _isDirectory(const std::string& path);
/** Known bug: does not work inside zipfiles */
bool _isFile(const std::string& path) {
return ! isDirectory(path);
} }
/** The current working directory (cwd). Only ends in a slash if this is the root of the file system. */
static std::string currentDirectory() {
mutex.lock();
const std::string& s = instance()._currentDirectory();
mutex.unlock();
return s;
}
/** /**
\param srcPath Must name a file. \param srcPath Must name a file.
\param dstPath Must not contain a zipfile. \param dstPath Must not contain a zipfile.
Flushes the cache. Flushes the cache.
*/ */
void _copyFile(const std::string& srcPath, const std::string& dstPath); static void copyFile(const std::string& srcPath, const std::string& dstPath) {
mutex.lock();
instance()._copyFile(srcPath, dstPath);
mutex.unlock();
}
/** 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;
}
/** Known bug: does not work inside zipfiles */
static bool isDirectory(const std::string& path) {
mutex.lock();
bool b = instance()._isDirectory(path);
mutex.unlock();
return b;
}
/** Known bug: does not work inside zipfiles */
static bool isFile(const std::string& path) {
mutex.lock();
bool b = instance()._isFile(path);
mutex.unlock();
return b;
}
/** Fully qualifies a filename. /** Fully qualifies a filename.
@@ -208,23 +437,35 @@ private:
\param cwd The directory to treat as the "current" directory when resolving a relative path. The default \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) value is the actual current directory. (G3D::Any::sourceDirectory is a common alternative)
*/ */
std::string _resolve(const std::string& path, const std::string& cwd = currentDirectory()); static std::string resolve(const std::string& path, const std::string& cwd = currentDirectory()) {
mutex.lock();
const std::string& s = instance()._resolve(path, cwd);
mutex.unlock();
return s;
}
/** Returns true if \param dst does not exist or \param src is newer than \param dst,
/** Returns true if \a dst does not exist or \a src is newer than \a dst,
according to their time stamps. according to their time stamps.
Known bug: does not work inside zipfiles. Known bug: does not work inside zipfiles.
*/ */
bool _isNewer(const std::string& src, const std::string& dst); static bool isNewer(const std::string& src, const std::string& dst) {
mutex.lock();
bool b = instance()._isNewer(src, dst);
mutex.unlock();
return b;
}
/** The current working directory (cwd). Only ends in a slash if this is the root of the file system. */
std::string _currentDirectory();
/** Returns the length of the file in bytes, or -1 if the file could not be opened. */ /** Returns the length of the file in bytes, or -1 if the file could not be opened. */
int64 _size(const std::string& path); static int64 size(const std::string& path) {
mutex.lock();
int64 i = instance()._size(path);
mutex.unlock();
return i;
}
/** Called from list() */
void listHelper(const std::string& shortSpec, const std::string& parentPath, Array<std::string>& result, const ListSettings& settings);
/** Appends all nodes matching \a spec to the \a result array. /** Appends all nodes matching \a spec to the \a result array.
@@ -235,148 +476,36 @@ private:
is fully qualified (can be done with resolveFilename). is fully qualified (can be done with resolveFilename).
*/ */
void _list(const std::string& spec, Array<std::string>& 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" */
bool _isZipfile(const std::string& path);
/** list() files */
void _getFiles(const std::string& spec, Array<std::string>& result, bool includeParentPath = false) {
ListSettings set;
set.includeParentPath = includeParentPath;
set.directories = false;
set.files = true;
return list(spec, result, set);
}
/** list() directories */
void _getDirectories(const std::string& spec, Array<std::string>& result, bool includeParentPath = false) {
ListSettings set;
set.includeParentPath = includeParentPath;
set.directories = true;
set.files = false;
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. */
FILE* _fopen(const char* filename, const char* mode);
public:
/** Create the common instance. */
static void init();
/** Destroy the common instance. */
static void cleanup();
# ifdef G3D_WIN32
/** \copydoc _drives */
static const Array<std::string>& drives() {
return instance()._drives();
}
# endif
/** \copydoc _inZipfile */
static bool inZipfile(const std::string& path, std::string& zipfile) {
return instance()._inZipfile(path, zipfile);
}
/** \copydoc _clearCache */
static void clearCache(const std::string& path = "") {
instance()._clearCache(path);
}
/** \copydoc _fopen */
static FILE* fopen(const char* filename, const char* mode) {
return instance()._fopen(filename, mode);
}
static void fclose(FILE* f) {
::fclose(f);
}
static bool inZipfile(const std::string& path) {
return instance()._inZipfile(path);
}
/** \copydoc isZipfile */
static bool isZipfile(const std::string& path) {
return instance()._isZipfile(path);
}
/** \copydoc _setCacheLifetime */
void setCacheLifetime(float t) {
instance()._setCacheLifetime(t);
}
/** \copydoc _cacheLifetime */
static float cacheLifetime() {
return instance()._cacheLifetime();
}
/** \copydoc _createDirectory */
static void createDirectory(const std::string& path) {
instance()._createDirectory(path);
}
/** \copydoc _currentDirectory */
static std::string currentDirectory() {
return instance()._currentDirectory();
}
/** \copydoc _copyFile */
static void copyFile(const std::string& srcPath, const std::string& dstPath) {
instance()._copyFile(srcPath, dstPath);
}
/** \copydoc _exists */
static bool exists(const std::string& f, bool trustCache = true) {
return instance()._exists(f, trustCache);
}
/** \copydoc _isDirectory */
static bool isDirectory(const std::string& path) {
return instance()._isDirectory(path);
}
/** \copydoc _isFile */
static bool isFile(const std::string& path) {
return instance()._isFile(path);
}
/** \copydoc _resolve */
static std::string resolve(const std::string& path, const std::string& cwd = currentDirectory()) {
return instance()._resolve(path, cwd);
}
/** \copydoc _isNewer */
static bool isNewer(const std::string& src, const std::string& dst) {
return instance()._isNewer(src, dst);
}
/** \copydoc _size */
static int64 size(const std::string& path) {
return instance()._size(path);
}
/** \copydoc _list */
static void list(const std::string& spec, Array<std::string>& result, static void list(const std::string& spec, Array<std::string>& result,
const ListSettings& listSettings = ListSettings()) { 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<std::string>& result, bool includeParentPath = false) { static void getFiles(const std::string& spec, Array<std::string>& 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<std::string>& result, bool includeParentPath = false) { static void getDirectories(const std::string& spec, Array<std::string>& 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<std::string>& usedFiles();
}; };
@@ -400,6 +529,11 @@ public:
/** Appends file onto dirname, ensuring a / if needed. */ /** Appends file onto dirname, ensuring a / if needed. */
static std::string concat(const std::string& a, const std::string& b); 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); static bool isRoot(const std::string& f);
/** Removes the trailing slash unless \a f is a filesystem root */ /** Removes the trailing slash unless \a f is a filesystem root */
@@ -423,6 +557,11 @@ public:
/** Convert all slashes to '/' */ /** Convert all slashes to '/' */
static std::string canonicalize(std::string x); static std::string canonicalize(std::string x);
/** \brief Replaces <code>$VAR</code> and <code>$(VAR)</code> 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. Parses a filename into four useful pieces.
@@ -454,11 +593,13 @@ public:
std::string& base, std::string& base,
std::string& ext); std::string& ext);
/** /**
Returns true if \a path matches \a pattern, with standard filesystem wildcards. 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); 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 } // namespace G3D

57
deps/g3dlite/include/G3D/Frustum.h vendored Normal file
View File

@@ -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<Vector4, 8> 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<Face, 6> 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

View File

@@ -1,22 +1,23 @@
/** /**
@file G3D.h \file G3D.h
This header includes all of the G3D libraries in This header includes all of the G3D libraries in
appropriate namespaces. appropriate namespaces.
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-08-25 \created 2001-08-25
@edited 2010-03-20 \edited 2013-03-24
Copyright 2000-2010, Morgan McGuire. Copyright 2000-2013, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_G3D_h #ifndef G3D_G3D_h
#define G3D_G3D_h #define G3D_G3D_h
#ifndef NOMINMAX
#define NOMINMAX 1 #define NOMINMAX 1
#endif
#ifdef min #ifdef min
#undef min #undef min
#endif #endif
@@ -24,18 +25,30 @@
#undef max #undef max
#endif #endif
#include "G3D/HaltonSequence.h"
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Proxy.h"
#include "G3D/BIN.h"
#include "G3D/FileNotFound.h"
#include "G3D/units.h" #include "G3D/units.h"
#include "G3D/ParseError.h" #include "G3D/ParseError.h"
#include "G3D/Random.h" #include "G3D/Random.h"
#include "G3D/Noise.h"
#include "G3D/Array.h" #include "G3D/Array.h"
#include "G3D/SmallArray.h" #include "G3D/SmallArray.h"
#include "G3D/Queue.h" #include "G3D/Queue.h"
#include "G3D/Crypto.h" #include "G3D/Crypto.h"
#include "G3D/format.h" #include "G3D/format.h"
#include "G3D/Vector2.h" #include "G3D/Vector2.h"
#include "G3D/Vector2int32.h"
#include "G3D/Vector2int16.h"
#include "G3D/Vector2unorm16.h"
#include "G3D/Vector3.h" #include "G3D/Vector3.h"
#include "G3D/Vector3int16.h"
#include "G3D/Vector3int32.h"
#include "G3D/Vector4.h" #include "G3D/Vector4.h"
#include "G3D/Vector4int16.h"
#include "G3D/Vector4int8.h"
#include "G3D/Color1.h" #include "G3D/Color1.h"
#include "G3D/Color3.h" #include "G3D/Color3.h"
#include "G3D/Color4.h" #include "G3D/Color4.h"
@@ -43,6 +56,7 @@
#include "G3D/Matrix3.h" #include "G3D/Matrix3.h"
#include "G3D/Matrix4.h" #include "G3D/Matrix4.h"
#include "G3D/CoordinateFrame.h" #include "G3D/CoordinateFrame.h"
#include "G3D/Projection.h"
#include "G3D/PhysicsFrame.h" #include "G3D/PhysicsFrame.h"
#include "G3D/PhysicsFrameSpline.h" #include "G3D/PhysicsFrameSpline.h"
#include "G3D/Plane.h" #include "G3D/Plane.h"
@@ -53,6 +67,7 @@
#include "G3D/Box2D.h" #include "G3D/Box2D.h"
#include "G3D/AABox.h" #include "G3D/AABox.h"
#include "G3D/WrapMode.h" #include "G3D/WrapMode.h"
#include "G3D/CullFace.h"
#include "G3D/Cone.h" #include "G3D/Cone.h"
#include "G3D/Quat.h" #include "G3D/Quat.h"
#include "G3D/stringutils.h" #include "G3D/stringutils.h"
@@ -61,6 +76,7 @@
#include "G3D/FileSystem.h" #include "G3D/FileSystem.h"
#include "G3D/Set.h" #include "G3D/Set.h"
#include "G3D/GUniqueID.h" #include "G3D/GUniqueID.h"
#include "G3D/RayGridIterator.h"
#include "G3D/BinaryFormat.h" #include "G3D/BinaryFormat.h"
#include "G3D/BinaryInput.h" #include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h" #include "G3D/BinaryOutput.h"
@@ -68,6 +84,10 @@
#include "G3D/g3dfnmatch.h" #include "G3D/g3dfnmatch.h"
#include "G3D/G3DGameUnits.h" #include "G3D/G3DGameUnits.h"
#include "G3D/g3dmath.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/uint128.h"
#include "G3D/fileutils.h" #include "G3D/fileutils.h"
#include "G3D/ReferenceCount.h" #include "G3D/ReferenceCount.h"
@@ -75,14 +95,19 @@
#include "G3D/GMutex.h" #include "G3D/GMutex.h"
#include "G3D/PrecomputedRandom.h" #include "G3D/PrecomputedRandom.h"
#include "G3D/MemoryManager.h" #include "G3D/MemoryManager.h"
#include "G3D/BlockPoolMemoryManager.h"
#include "G3D/AreaMemoryManager.h" #include "G3D/AreaMemoryManager.h"
#include "G3D/BumpMapPreprocess.h" #include "G3D/BumpMapPreprocess.h"
#include "G3D/CubeFace.h"
#include "G3D/Line2D.h"
#include "G3D/ThreadsafeQueue.h"
#include "G3D/network.h"
template<class T> struct HashTrait< G3D::ReferenceCountedPointer<T> > { template<class T> struct HashTrait< shared_ptr<T> > {
static size_t hashCode(G3D::ReferenceCountedPointer<T> key) { return reinterpret_cast<size_t>( key.pointer() ); } static size_t hashCode(shared_ptr<T> key) { return reinterpret_cast<size_t>( key.get() ); }
}; };
#include "G3D/GImage.h" #include "G3D/Image.h"
#include "G3D/CollisionDetection.h" #include "G3D/CollisionDetection.h"
#include "G3D/Intersect.h" #include "G3D/Intersect.h"
#include "G3D/Log.h" #include "G3D/Log.h"
@@ -98,18 +123,14 @@ template<class T> struct HashTrait< G3D::ReferenceCountedPointer<T> > {
#include "G3D/Capsule.h" #include "G3D/Capsule.h"
#include "G3D/Cylinder.h" #include "G3D/Cylinder.h"
#include "G3D/Triangle.h" #include "G3D/Triangle.h"
#include "G3D/Color3uint8.h" #include "G3D/Color1unorm8.h"
#include "G3D/Color4uint8.h" #include "G3D/Color2unorm8.h"
#include "G3D/Vector2int16.h" #include "G3D/Color3unorm8.h"
#include "G3D/Vector3int16.h" #include "G3D/Color4unorm8.h"
#include "G3D/Vector3int32.h"
#include "G3D/Vector4int8.h"
#include "G3D/ConvexPolyhedron.h" #include "G3D/ConvexPolyhedron.h"
#include "G3D/MeshAlg.h" #include "G3D/MeshAlg.h"
#include "G3D/vectorMath.h" #include "G3D/vectorMath.h"
#include "G3D/Rect2D.h" #include "G3D/Rect2D.h"
#include "G3D/GCamera.h"
#include "G3D/GLight.h"
#include "G3D/KDTree.h" #include "G3D/KDTree.h"
#include "G3D/PointKDTree.h" #include "G3D/PointKDTree.h"
#include "G3D/TextOutput.h" #include "G3D/TextOutput.h"
@@ -124,39 +145,81 @@ template<class T> struct HashTrait< G3D::ReferenceCountedPointer<T> > {
#include "G3D/PointHashGrid.h" #include "G3D/PointHashGrid.h"
#include "G3D/Map2D.h" #include "G3D/Map2D.h"
#include "G3D/Image1.h" #include "G3D/Image1.h"
#include "G3D/Image1uint8.h" #include "G3D/Image1unorm8.h"
#include "G3D/Image3.h" #include "G3D/Image3.h"
#include "G3D/Image3uint8.h" #include "G3D/Image3unorm8.h"
#include "G3D/Image4.h" #include "G3D/Image4.h"
#include "G3D/Image4uint8.h" #include "G3D/Image4unorm8.h"
#include "G3D/filter.h" #include "G3D/filter.h"
#include "G3D/WeakCache.h" #include "G3D/WeakCache.h"
#include "G3D/Pointer.h" #include "G3D/Pointer.h"
#include "G3D/Matrix.h" #include "G3D/Matrix.h"
#include "G3D/ImageFormat.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 #ifdef _MSC_VER
# pragma comment(lib, "zlib")
# pragma comment(lib, "ws2_32")
# pragma comment(lib, "winmm") # pragma comment(lib, "winmm")
# pragma comment(lib, "imagehlp") # pragma comment(lib, "imagehlp")
# pragma comment(lib, "ws2_32")
# pragma comment(lib, "gdi32") # pragma comment(lib, "gdi32")
# pragma comment(lib, "user32") # pragma comment(lib, "user32")
# pragma comment(lib, "kernel32") # pragma comment(lib, "kernel32")
# pragma comment(lib, "version")
# pragma comment(lib, "advapi32") # pragma comment(lib, "advapi32")
# pragma comment(lib, "png") # pragma comment(lib, "shell32")
# pragma comment(lib, "jpeg") # pragma comment(lib, "version")
# ifdef G3D_64BIT
# pragma comment(lib, "zlib_x64")
# pragma comment(lib, "zip_x64")
# pragma comment(lib, "enet_x64")
# else
# pragma comment(lib, "zlib")
# pragma comment(lib, "zip") # pragma comment(lib, "zip")
# ifdef _DEBUG # pragma comment(lib, "enet")
// Don't link against G3D when building G3D itself. # endif
# ifndef G3D_BUILDING_LIBRARY_DLL # if defined(_DEBUG)
# pragma comment(lib, "G3Dd.lib") # ifdef G3D_64BIT
# pragma comment(lib, "G3D_x64d")
# pragma comment(lib, "freeimage_x64d")
# else
# pragma comment(lib, "G3Dd")
# pragma comment(lib, "freeimaged")
# endif # endif
# else # else
// Don't link against G3D when building G3D itself. # ifdef G3D_64BIT
# ifndef G3D_BUILDING_LIBRARY_DLL # pragma comment(lib, "G3D_x64")
# pragma comment(lib, "G3D.lib") # pragma comment(lib, "freeimage_x64")
# else
# pragma comment(lib, "G3D")
# pragma comment(lib, "freeimage")
# endif # endif
# endif # endif
#endif #endif

View File

@@ -3,7 +3,7 @@
@maintainer Morgan McGuire, http://graphics.cs.williams.edu @maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2002-10-05 @created 2002-10-05
@edited 2006-11-10 @edited 2012-02-19
*/ */
#ifndef G3D_GAMEUNITS_H #ifndef G3D_GAMEUNITS_H
@@ -12,14 +12,17 @@
#include "G3D/platform.h" #include "G3D/platform.h"
namespace G3D { namespace G3D {
/** \deprecated use SimTime */
typedef double GameTime;
/** /**
Time, in seconds. Time, in seconds.
*/ */
typedef double GameTime;
typedef double SimTime; typedef double SimTime;
/** /**
Actual wall clock time in seconds. Actual wall clock time in seconds (Unix time).
*/ */
typedef double RealTime; typedef double RealTime;

View File

@@ -1,8 +1,8 @@
/** /**
@file GMutex.h \file G3D/GMutex.h
@created 2005-09-22 \created 2005-09-22
@edited 2009-03-25 \edited 2013-04-03
*/ */
#ifndef G3D_GMutex_h #ifndef G3D_GMutex_h
@@ -13,10 +13,13 @@
#include "G3D/debugAssert.h" #include "G3D/debugAssert.h"
#include <string> #include <string>
#ifndef G3D_WIN32 #ifndef G3D_WINDOWS
# include <pthread.h> # include <pthread.h>
# include <signal.h> # include <signal.h>
# include <unistd.h> #endif
#if defined(G3D_LINUX) || defined(G3D_OSX)
# include <unistd.h> // For usleep
#endif #endif
@@ -26,7 +29,7 @@ namespace G3D {
\brief A mutual exclusion lock that busy-waits when locking. \brief A mutual exclusion lock that busy-waits when locking.
On a machine with one (significant) thread per processor core, 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 \sa G3D::GThread, G3D::GMutex, G3D::AtomicInt32
*/ */
@@ -41,12 +44,16 @@ public:
/** Busy waits until the lock is unlocked, then locks it /** Busy waits until the lock is unlocked, then locks it
exclusively. Returns true if the lock succeeded on the first 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() { inline bool lock() {
bool first = true; bool first = true;
while (x.compareAndSet(0, 1) == 1) { while (x.compareAndSet(0, 1) == 1) {
first = false; first = false;
# ifdef G3D_WIN32 # ifdef G3D_WINDOWS
Sleep(0); Sleep(0);
# else # else
usleep(0); usleep(0);
@@ -68,7 +75,7 @@ public:
*/ */
class GMutex { class GMutex {
private: private:
# ifdef G3D_WIN32 # ifdef G3D_WINDOWS
CRITICAL_SECTION m_handle; CRITICAL_SECTION m_handle;
# else # else
pthread_mutex_t m_handle; pthread_mutex_t m_handle;

View File

@@ -2,18 +2,21 @@
@file GThread.h @file GThread.h
@created 2005-09-22 @created 2005-09-22
@edited 2007-01-31 @edited 2010-09-10
*/ */
#ifndef G3D_GTHREAD_H #ifndef G3D_GThread_h
#define G3D_GTHREAD_H #define G3D_GThread_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/ReferenceCount.h" #include "G3D/ReferenceCount.h"
#include "G3D/ThreadSet.h"
#include "G3D/Vector2int32.h"
#include "G3D/SpawnBehavior.h"
#include <string> #include <string>
#ifndef G3D_WIN32 #ifndef G3D_WINDOWS
# include <pthread.h> # include <pthread.h>
# include <signal.h> # include <signal.h>
#endif #endif
@@ -21,7 +24,9 @@
namespace G3D { namespace G3D {
typedef ReferenceCountedPointer<class GThread> GThreadRef; typedef shared_ptr<class GThread> GThreadRef;
/** /**
Platform independent thread implementation. You can either subclass and Platform independent thread implementation. You can either subclass and
@@ -32,11 +37,11 @@ typedef ReferenceCountedPointer<class GThread> GThreadRef;
dropping all pointers (and causing deallocation) of a GThread does NOT dropping all pointers (and causing deallocation) of a GThread does NOT
stop the underlying process. stop the underlying process.
@sa G3D::GMutex, G3D::Spinlock, G3D::AtomicInt32 \sa G3D::GMutex, G3D::Spinlock, G3D::AtomicInt32, G3D::ThreadSet
*/ */
class GThread : public ReferenceCountedObject { class GThread : public ReferenceCountedObject {
private: 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}; enum GStatus {STATUS_CREATED, STATUS_STARTED, STATUS_RUNNING, STATUS_COMPLETED};
// Not implemented on purpose, don't use // Not implemented on purpose, don't use
@@ -44,21 +49,21 @@ private:
GThread& operator=(const GThread&); GThread& operator=(const GThread&);
bool operator==(const GThread&); bool operator==(const GThread&);
#ifdef G3D_WIN32 #ifdef G3D_WINDOWS
static DWORD WINAPI internalThreadProc(LPVOID param); static DWORD WINAPI internalThreadProc(LPVOID param);
#else #else
static void* internalThreadProc(void* param); static void* internalThreadProc(void* param);
#endif //G3D_WIN32 #endif //G3D_WINDOWS
volatile GStatus m_status; volatile GStatus m_status;
// Thread handle to hold HANDLE and pthread_t // Thread handle to hold HANDLE and pthread_t
#ifdef G3D_WIN32 #ifdef G3D_WINDOWS
HANDLE m_handle; HANDLE m_handle;
HANDLE m_event; HANDLE m_event;
#else #else
pthread_t m_handle; pthread_t m_handle;
#endif //G3D_WIN32 #endif //G3D_WINDOWS
std::string m_name; std::string m_name;
@@ -68,8 +73,11 @@ protected:
virtual void threadMain() = 0; virtual void threadMain() = 0;
public: public:
typedef ReferenceCountedPointer<class GThread> 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<class GThread> Ref;
GThread(const std::string& name); GThread(const std::string& name);
@@ -110,11 +118,152 @@ public:
void waitForCompletion(); void waitForCompletion();
/** Returns thread name */ /** Returns thread name */
inline const std::string& name() { const std::string& name() {
return m_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. <p> Evaluates \a
object->\a method(\a x, \a y) for every <code>start.x <= x <
upTo.x</code> and <code>start.y <= y < upTo.y</code>.
Iteration is row major, so each thread can expect to see
successive x values. </p>
\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<class Class>
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<void (Class::*)(int, int, int)>(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<class Class>
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<void (Class::*)(int, int)>(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 Class>
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<class Class>
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<Class> >(new _internalGThreadWorker<Class>(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 } // namespace G3D

View File

@@ -1,9 +1,9 @@
/** /**
@file GUniqueID.h \file G3D/GUniqueID.h
@author Morgan McGuire, http://graphics.cs.williams.edu \author Morgan McGuire, http://graphics.cs.williams.edu
*/ */
#ifndef G3D_GUNIQUEID_H #ifndef G3D_GUniqueID_h
#define G3D_GUNIQUEID_H #define G3D_GUniqueID_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
@@ -11,6 +11,8 @@
namespace G3D { namespace G3D {
class Any;
/** Globally unique identifiers. The probability of two different /** Globally unique identifiers. The probability of two different
programs generating the same value from UniqueID::create is programs generating the same value from UniqueID::create is
vanishingly small. vanishingly small.
@@ -25,8 +27,27 @@ private:
public: public:
/** \sa create */
GUniqueID() : id(0) {} 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 { bool uninitialized() const {
return id == 0; return id == 0;
} }

View File

@@ -1,11 +1,11 @@
/** /**
@file HashTrait.h \file G3D/HashTrait.h
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2008-10-01 \created 2008-10-01
@edited 2009-11-01 \edited 2011-06-09
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -16,6 +16,88 @@
#include "G3D/Crypto.h" #include "G3D/Crypto.h"
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
#include "G3D/uint128.h" #include "G3D/uint128.h"
#include <typeinfo>
#include <stdint.h>
#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. /** Must be specialized for custom types.
@see G3D::Table for specialization requirements. @see G3D::Table for specialization requirements.
@@ -23,14 +105,19 @@
template <typename T> struct HashTrait{}; template <typename T> struct HashTrait{};
template <typename T> struct HashTrait<T*> { template <typename T> struct HashTrait<T*> {
static size_t hashCode(const void* k) { return reinterpret_cast<size_t>(k); } static size_t hashCode(const void* k) { return reinterpret_cast<size_t>(k) >> 1; }
}; };
#if 0 /** For use with \code Table<std::type_info* const, ValueType> \endcode. */
template <> struct HashTrait <int> { template <> struct HashTrait <std::type_info* const> {
static size_t hashCode(int k) { return static_cast<size_t>(k); } static size_t hashCode(const std::type_info* const t) {
}; # ifdef _MSC_VER
return t->hash_code();
# else
return reinterpret_cast<size_t>(t) >> 1;
# endif # endif
}
};
template <> struct HashTrait <G3D::int16> { template <> struct HashTrait <G3D::int16> {
static size_t hashCode(G3D::int16 k) { return static_cast<size_t>(k); } static size_t hashCode(G3D::int16 k) { return static_cast<size_t>(k); }
@@ -40,10 +127,6 @@ template <> struct HashTrait <G3D::uint16> {
static size_t hashCode(G3D::uint16 k) { return static_cast<size_t>(k); } static size_t hashCode(G3D::uint16 k) { return static_cast<size_t>(k); }
}; };
//template <> struct HashTrait <int> {
// static size_t hashCode(int k) { return static_cast<size_t>(k); }
//};
template <> struct HashTrait <G3D::int32> { template <> struct HashTrait <G3D::int32> {
static size_t hashCode(G3D::int32 k) { return static_cast<size_t>(k); } static size_t hashCode(G3D::int32 k) { return static_cast<size_t>(k); }
}; };
@@ -58,21 +141,30 @@ template <> struct HashTrait <long unsigned int> {
}; };
#endif #endif
template <> struct HashTrait <G3D::int64> {
static size_t hashCode(G3D::int64 k) { return static_cast<size_t>(k); }
};
template <> struct HashTrait <G3D::uint64> { template <> struct HashTrait <G3D::uint64> {
static size_t hashCode(G3D::uint64 k) { return static_cast<size_t>(k); } static size_t hashCode(G3D::uint64 k) { return static_cast<size_t>(k) ^ static_cast<size_t>(k >> 32); }
}; };
template <> struct HashTrait <G3D::int64> {
static size_t hashCode(G3D::int64 k) { return HashTrait<G3D::uint64>::hashCode(G3D::uint64(k)); }
};
template <> struct HashTrait <std::string> { template <> struct HashTrait <std::string> {
static size_t hashCode(const std::string& k) { return static_cast<size_t>(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<size_t>(G3D::Crypto::crc32(k.c_str(), k.size()));
}
}; };
template <> struct HashTrait<G3D::uint128> { template <> struct HashTrait<G3D::uint128> {
// Use the FNV-1 hash (http://isthe.com/chongo/tech/comp/fnv/#FNV-1).
static size_t hashCode(G3D::uint128 key) { static size_t hashCode(G3D::uint128 key) {
return G3D::superFastHash(&key, sizeof(key));
//return HashTrait<G3D::uint64>::hashCode(key.hi) ^ HashTrait<G3D::uint64>::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_PRIME_128(1 << 24, 0x159);
static const G3D::uint128 FNV_OFFSET_128(0xCF470AAC6CB293D2ULL, 0xF52F88BF32307F8FULL); static const G3D::uint128 FNV_OFFSET_128(0xCF470AAC6CB293D2ULL, 0xF52F88BF32307F8FULL);
@@ -86,6 +178,7 @@ template <> struct HashTrait<G3D::uint128> {
G3D::uint64 foldedHash = hash.hi ^ hash.lo; G3D::uint64 foldedHash = hash.hi ^ hash.lo;
return static_cast<size_t>((foldedHash >> 32) ^ (foldedHash & 0xFFFFFFFF)); return static_cast<size_t>((foldedHash >> 32) ^ (foldedHash & 0xFFFFFFFF));
#endif
} }
}; };

View File

@@ -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 \created 2007-01-31
@edited 2007-01-31 \edited 2011-08-31
*/ */
#ifndef G3D_IMAGE1_H #ifndef G3D_Image1_h
#define G3D_IMAGE1_H #define G3D_Image1_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Map2D.h" #include "G3D/Map2D.h"
#include "G3D/Color1.h" #include "G3D/Color1.h"
#include "G3D/GImage.h"
namespace G3D { namespace G3D {
typedef ReferenceCountedPointer<class Image1> Image1Ref; typedef shared_ptr<class Image1> Image1Ref;
/** /**
Luminance image with 32-bit floating point storage. Luminance image with 32-bit floating point storage.
See also G3D::Image1uint8, G3D::GImage. See also G3D::Image1unorm8, G3D::GImage.
*/ */
class Image1 : public Map2D<Color1, Color1> { class Image1 : public Map2D<Color1, Color1> {
public: public:
typedef Image1 Type; typedef Image1 Type;
typedef ReferenceCountedPointer<class Image1> Ref; typedef shared_ptr<class Image1> Ref;
typedef Color1 Storage; typedef Color1 Storage;
typedef Color1 Compute; typedef Color1 Compute;
@@ -41,9 +40,9 @@ protected:
void copyArray(const Color1* src, int w, int h); void copyArray(const Color1* src, int w, int h);
void copyArray(const Color3* 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 Color4* src, int w, int h);
void copyArray(const Color1uint8* src, int w, int h); void copyArray(const Color1unorm8* src, int w, int h);
void copyArray(const Color3uint8* src, int w, int h); void copyArray(const Color3unorm8* src, int w, int h);
void copyArray(const Color4uint8* src, int w, int h); void copyArray(const Color4unorm8* src, int w, int h);
public: public:
@@ -55,25 +54,28 @@ public:
/** Creates a 0 x 0 image. */ /** Creates a 0 x 0 image. */
static Ref createEmpty(WrapMode wrap = WrapMode::ERROR); 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 Color1unorm8* 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 Color3unorm8* 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 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 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 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 fromArray(const class Color4* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromImage1uint8(const ReferenceCountedPointer<class Image1uint8>& im); static Ref fromImage1unorm8(const shared_ptr<class Image1unorm8>& 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, If there is an alpha channel on the input, it is stripped.
it is stripped. */ Values are automatically scaled to the range [0, 1]. */
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. */ /** Saves in any of the formats supported by G3D::Image.
void save(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT);
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 } // G3D

View File

@@ -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 \created 2007-01-31
@edited 2007-01-31 \edited 2011-08-31
*/ */
@@ -14,36 +14,32 @@
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Map2D.h" #include "G3D/Map2D.h"
#include "G3D/Color3.h" #include "G3D/Color3.h"
#include "G3D/GImage.h"
namespace G3D { namespace G3D {
typedef ReferenceCountedPointer<class Image3> Image3Ref; typedef shared_ptr<class Image3> Image3Ref;
/** /**
RGB image with 32-bit floating point storage for each channel. 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<Color3, Color3> { class Image3 : public Map2D<Color3, Color3> {
public: public:
typedef Image3 Type; typedef Image3 Type;
typedef ReferenceCountedPointer<class Image3> Ref; typedef shared_ptr<class Image3> Ref;
typedef Color3 Storage;
typedef Color3 Compute;
protected: protected:
Image3(int w, int h, WrapMode wrap); 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 Color1* src, int w, int h);
void copyArray(const Color3* 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 Color4* src, int w, int h);
void copyArray(const Color1uint8* src, int w, int h); void copyArray(const Color1unorm8* src, int w, int h);
void copyArray(const Color3uint8* src, int w, int h); void copyArray(const Color3unorm8* src, int w, int h);
void copyArray(const Color4uint8* src, int w, int h); void copyArray(const Color4unorm8* src, int w, int h);
public: public:
@@ -55,25 +51,23 @@ public:
/** Creates a 0 x 0 image. */ /** Creates a 0 x 0 image. */
static Ref createEmpty(WrapMode wrap = WrapMode::ERROR); 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 Color1unorm8* 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 Color3unorm8* 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 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 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 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 fromArray(const class Color4* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromImage3uint8(const ReferenceCountedPointer<class Image3uint8>& im); static Ref fromImage3unorm8(const shared_ptr<class Image3unorm8>& im);
static Ref fromGImage(const class GImage& im, WrapMode wrap = WrapMode::ERROR);
/** Loads from any of the file formats supported by G3D::GImage. If there is an alpha channel on the input, /** Loads from any of the file formats supported by G3D::GImage. If there is an alpha channel on the input,
it is stripped. */ it is stripped. Converts 8-bit formats to the range (0, 1) */
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. */ /** 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, GImage::Format fmt = GImage::AUTODETECT); void save(const std::string& filename);
}; };
} // G3D } // G3D

View File

@@ -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 \created 2007-01-31
@edited 2007-01-31 \edited 2011-08-11
*/ */
#ifndef G3D_IMAGE4_H #ifndef G3D_Image4_h
#define G3D_IMAGE4_H #define G3D_Image4_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Map2D.h" #include "G3D/Map2D.h"
#include "G3D/Color4.h" #include "G3D/Color4.h"
#include "G3D/GImage.h"
namespace G3D { namespace G3D {
typedef ReferenceCountedPointer<class Image4> Image4Ref; typedef shared_ptr<class Image4> Image4Ref;
/** /**
RGBA image with 32-bit floating point storage for each channel. RGBA image with 32-bit floating point storage for each channel.
@@ -26,30 +25,27 @@ typedef ReferenceCountedPointer<class Image4> Image4Ref;
Whenever a method needs to convert from RGB to RGBA, A=1 is assumed. Whenever a method needs to convert from RGB to RGBA, A=1 is assumed.
Bilinear interpolation on Image4 is about 8x faster than on 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. machines.
@sa G3D::Image4uint8, G3D::GImage. @sa G3D::Image4unorm8, G3D::GImage.
*/ */
class Image4 : public Map2D<Color4, Color4> { class Image4 : public Map2D<Color4, Color4> {
public: public:
typedef Image4 Type; typedef Image4 Type;
typedef ReferenceCountedPointer<class Image4> Ref; typedef shared_ptr<class Image4> Ref;
typedef Color4 Storage;
typedef Color4 Compute;
protected: protected:
Image4(int w, int h, WrapMode wrap); 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 Color1* src, int w, int h);
void copyArray(const Color3* 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 Color4* src, int w, int h);
void copyArray(const Color1uint8* src, int w, int h); void copyArray(const Color1unorm8* src, int w, int h);
void copyArray(const Color3uint8* src, int w, int h); void copyArray(const Color3unorm8* src, int w, int h);
void copyArray(const Color4uint8* src, int w, int h); void copyArray(const Color4unorm8* src, int w, int h);
public: public:
@@ -61,24 +57,22 @@ public:
/** Creates a 0 x 0 image. */ /** Creates a 0 x 0 image. */
static Ref createEmpty(WrapMode wrap = WrapMode::ERROR); 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 Color1unorm8* 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 Color3unorm8* 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 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 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 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 fromArray(const class Color4* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromImage4uint8(const ReferenceCountedPointer<class Image4uint8>& im); static Ref fromImage4unorm8(const shared_ptr<class Image4unorm8>& im);
static Ref fromGImage(const class GImage& im, WrapMode wrap = WrapMode::ERROR);
/** Loads from any of the file formats supported by G3D::GImage. */ /** 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. */ /** 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 } // G3D

View File

@@ -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 \created 2003-05-23
@edited 2010-05-01 \edited 2013-06-06
*/ */
#ifndef GLG3D_ImageFormat_H #ifndef GLG3D_ImageFormat_h
#define GLG3D_ImageFormat_H #define GLG3D_ImageFormat_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Table.h" #include "G3D/Table.h"
@@ -17,16 +17,22 @@
namespace G3D { namespace G3D {
/** Information about common image formats. /** Information about common image formats. Don't construct these;
Don't construct these; use the methods provided. 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 For most formats, the number indicates the number of bits per
floating point. This does not hold for the YUV and DXT formats.*/ 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 { class ImageFormat {
public: public:
// Must update ImageFormat::name() when this enum changes. // Must update ImageFormat::name() when this enum changes.
enum Code { enum Code {
CODE_AUTO = -2,
CODE_NONE = -1, CODE_NONE = -1,
CODE_L8, CODE_L8,
CODE_L16, CODE_L16,
@@ -58,24 +64,57 @@ public:
CODE_RGB8I, CODE_RGB8I,
CODE_RGB8UI, CODE_RGB8UI,
CODE_RGBA8I,
CODE_RGBA8UI, CODE_RGBA8UI,
CODE_RGB8_SNORM,
CODE_RGBA8_SNORM,
CODE_RGB16_SNORM,
CODE_RGBA16_SNORM,
CODE_ARGB8, CODE_ARGB8,
CODE_BGR8, CODE_BGR8,
CODE_BGRA8,
CODE_R8, CODE_R8,
CODE_R8I,
CODE_R8UI,
CODE_R16,
CODE_R16I,
CODE_R16UI,
CODE_R32I,
CODE_R32UI,
CODE_RG8, CODE_RG8,
CODE_RG8I, CODE_RG8I,
CODE_RG8UI, CODE_RG8UI,
CODE_RG16,
CODE_RG16I,
CODE_RG16UI,
CODE_R16F,
CODE_RG16F, CODE_RG16F,
CODE_RG32I,
CODE_RG32UI,
CODE_R32F,
CODE_RG32F,
CODE_RGBA8, CODE_RGBA8,
CODE_RGBA16, CODE_RGBA16,
CODE_RGBA16F, CODE_RGBA16F,
CODE_RGBA32F, CODE_RGBA32F,
CODE_RGBA16I,
CODE_RGBA16UI,
CODE_RGB32I,
CODE_RGB32UI,
CODE_RGBA32I,
CODE_RGBA32UI, CODE_RGBA32UI,
CODE_BAYER_RGGB8, CODE_BAYER_RGGB8,
@@ -141,6 +180,14 @@ public:
BAYER_PATTERN_BGGR 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). */ /** Number of channels (1 for a depth texture). */
int numComponents; int numComponents;
bool compressed; bool compressed;
@@ -182,10 +229,6 @@ public:
/** Amount of CPU memory per pixel when packed into an array, discounting any end-of-row padding. */ /** Amount of CPU memory per pixel when packed into an array, discounting any end-of-row padding. */
int cpuBitsPerPixel; 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 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. only an estimate--the actual amount of memory may be different on your actual card.
@@ -196,24 +239,38 @@ public:
*/ */
int openGLBitsPerPixel; 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 */ /** The OpenGL bytes (type) format of the data buffer used with this texture format, e.g., GL_UNSIGNED_BYTE */
int openGLDataFormat; int openGLDataFormat;
/** True if there is no alpha channel for this texture. */ /** True if there is no alpha channel for this texture. */
bool opaque; 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; bool floatingPoint;
/** Indicates whether this format treats numbers as integers, floating point, or normalized fixed point */
NumberFormat numberFormat;
/** Human readable name of this format.*/ /** Human readable name of this format.*/
const std::string& name() const; 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 */ /** Takes the same values that name() returns */
static const ImageFormat* fromString(const std::string& s); static const ImageFormat* fromString(const std::string& s);
private: private:
ImageFormat ImageFormat
@@ -228,11 +285,11 @@ private:
int blueBits, int blueBits,
int depthBits, int depthBits,
int stencilBits, int stencilBits,
int hardwareBitsPerTexel, int openGLBitsPerPixel,
int packedBitsPerTexel, int cpuBitsPerPixel,
int glDataFormat, int glDataFormat,
bool opaque, bool opaque,
bool floatingPoint, NumberFormat numberFormat,
Code code, Code code,
ColorSpace colorSpace, ColorSpace colorSpace,
BayerPattern bayerPattern = BAYER_PATTERN_NONE); BayerPattern bayerPattern = BAYER_PATTERN_NONE);
@@ -267,14 +324,36 @@ public:
static const ImageFormat* BGR8(); static const ImageFormat* BGR8();
static const ImageFormat* BGRA8();
static const ImageFormat* R8(); 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* RG8();
static const ImageFormat* RG8I(); static const ImageFormat* RG8I();
static const ImageFormat* RG8UI(); 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* RG16F();
static const ImageFormat* RG32I();
static const ImageFormat* RG32UI();
static const ImageFormat* R32F();
static const ImageFormat* RG32F();
static const ImageFormat* RGB5(); static const ImageFormat* RGB5();
static const ImageFormat* RGB5A1(); static const ImageFormat* RGB5A1();
@@ -299,6 +378,12 @@ public:
static const ImageFormat* RGBA32F(); 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* RGBA32UI();
static const ImageFormat* R11G11B10F(); static const ImageFormat* R11G11B10F();
@@ -309,8 +394,15 @@ public:
static const ImageFormat* RGB8UI(); static const ImageFormat* RGB8UI();
static const ImageFormat* RGBA8I();
static const ImageFormat* RGBA8UI(); 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* RGB_DXT1();
static const ImageFormat* RGBA_DXT1(); static const ImageFormat* RGBA_DXT1();
@@ -381,7 +473,6 @@ public:
static const ImageFormat* fromCode(ImageFormat::Code code); static const ImageFormat* fromCode(ImageFormat::Code code);
/** For use with ImageFormat::convert. */ /** For use with ImageFormat::convert. */
class BayerAlgorithm { class BayerAlgorithm {
public: 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. 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. Returns true if a conversion was available, false if none occurred.
\deprecated
\sa G3D::ImageConvert
*/ */
static bool convert(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, static bool convert(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits,
const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits,
bool invertY = false, BayerAlgorithm bayerAlg = BayerAlgorithm::MHC); 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); 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; typedef ImageFormat TextureFormat;

View File

@@ -30,7 +30,7 @@ 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" \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 M<>ller and Marcus Magnor
Computer Graphics Lab, TU Braunschweig, Germany and Computer Graphics Lab, TU Braunschweig, Germany and
University of Koblenz-Landau, Germany University of Koblenz-Landau, Germany
*/ */
@@ -43,7 +43,7 @@ public:
\a time is not set if there is no 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" \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 M<>ller and Marcus Magnor
Computer Graphics Lab, TU Braunschweig, Germany and Computer Graphics Lab, TU Braunschweig, Germany and
University of Koblenz-Landau, Germany University of Koblenz-Landau, Germany
*/ */

View File

@@ -10,8 +10,8 @@
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_KDTREE_H #ifndef G3D_KDTree_h
#define G3D_KDTREE_H #define G3D_KDTree_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Array.h" #include "G3D/Array.h"
@@ -24,11 +24,10 @@
#include "G3D/Box.h" #include "G3D/Box.h"
#include "G3D/Triangle.h" #include "G3D/Triangle.h"
#include "G3D/Ray.h" #include "G3D/Ray.h"
#include "G3D/GCamera.h" #include "G3D/Frustum.h"
#include "G3D/BinaryInput.h" #include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h" #include "G3D/BinaryOutput.h"
#include "G3D/CollisionDetection.h" #include "G3D/CollisionDetection.h"
#include "G3D/GCamera.h"
#include "G3D/BoundsTrait.h" #include "G3D/BoundsTrait.h"
#include <algorithm> #include <algorithm>
@@ -444,6 +443,7 @@ protected:
for (int i = 0; i < valueArray.length(); ++i) { for (int i = 0; i < valueArray.length(); ++i) {
const AABox& b = valueArray[i]->bounds; const AABox& b = valueArray[i]->bounds;
debugAssert(b == boundsArray[i]); debugAssert(b == boundsArray[i]);
(void)b;
for(int axis = 0; axis < 3; ++axis) { for(int axis = 0; axis < 3; ++axis) {
debugAssert(b.low()[axis] <= b.high()[axis]); debugAssert(b.low()[axis] <= b.high()[axis]);
@@ -1211,7 +1211,7 @@ public:
/** /**
Typically used to find all visible 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
<B>not</B> culled by frustum. <B>not</B> culled by frustum.
Example: Example:
@@ -1222,7 +1222,7 @@ public:
</PRE> </PRE>
@param members The results are appended to this array. @param members The results are appended to this array.
*/ */
void getIntersectingMembers(const GCamera::Frustum& frustum, Array<T*>& members) const { void getIntersectingMembers(const Frustum& frustum, Array<T*>& members) const {
Array<Plane> plane; Array<Plane> plane;
for (int i = 0; i < frustum.faceArray.size(); ++i) { for (int i = 0; i < frustum.faceArray.size(); ++i) {
@@ -1232,7 +1232,7 @@ public:
getIntersectingMembers(plane, members); getIntersectingMembers(plane, members);
} }
void getIntersectingMembers(const GCamera::Frustum& frustum, Array<T>& members) const { void getIntersectingMembers(const Frustum& frustum, Array<T>& members) const {
Array<T*> temp; Array<T*> temp;
getIntersectingMembers(frustum, temp); getIntersectingMembers(frustum, temp);
for (int i = 0; i < temp.size(); ++i) { for (int i = 0; i < temp.size(); ++i) {
@@ -1450,16 +1450,17 @@ public:
/** /**
Invoke a callback for every member along a ray until the closest intersection is found. 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: @param intersectCallback Either a function or an instance of a class with an overloaded operator() of the form:
<pre>
<code>void callback(const Ray& ray, const T& object, float& distance)</code>. If the ray hits the object void callback(const Ray& ray, const T& object, float& distance).
before travelling distance <code>distance</code>, updates <code>distance</code> with the new distance to </pre>
the intersection, otherwise leaves it unmodified. A common example is: If the ray hits the object before travelling distance <code>distance</code>, updates
<code>distance</code> with the new distance to the intersection, otherwise leaves it
unmodified. A common example is:
\htmlonly
<pre> <pre>
class Entity { class Entity {
public: public:
void intersect(const Ray& ray, float& maxDist, Vector3& outLocation, Vector3& outNormal) { void intersect(const Ray& ray, float& maxDist, Vector3& outLocation, Vector3& outNormal) {
float d = maxDist; float d = maxDist;
@@ -1492,7 +1493,7 @@ public:
float distance = finf(); float distance = finf();
scene.intersectRay(camera.worldRay(x, y), intersection, distance); scene.intersectRay(camera.worldRay(x, y), intersection, distance);
</pre> </pre>
\endhtmlonly
@param distance When the method is invoked, this is the maximum @param distance When the method is invoked, this is the maximum
distance that the tree should search for an intersection. On distance that the tree should search for an intersection. On

View File

@@ -21,17 +21,17 @@ namespace G3D {
class LineSegment { class LineSegment {
protected: protected:
Vector3 _point; Point3 _point;
/** Not normalized */ /** Not normalized */
Vector3 direction; 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: public:
inline LineSegment() : _point(Vector3::zero()), direction(Vector3::zero()) {} LineSegment() : _point(Point3::zero()), direction(Vector3::zero()) {}
LineSegment(class BinaryInput& b); LineSegment(class BinaryInput& b);
@@ -44,12 +44,16 @@ public:
/** /**
* Constructs a line from two (not equal) points. * 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); return LineSegment(point1, point2 - point1);
} }
/** Call with 0 or 1 */ /** Call with 0 or 1 */
Vector3 point(int i) const; Point3 point(int i) const;
Point3 midpoint() const {
return _point + direction * 0.5f;
}
inline float length() const { inline float length() const {
return direction.magnitude(); return direction.magnitude();
@@ -58,23 +62,23 @@ public:
/** /**
* Returns the closest point on the line segment to point. * 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 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(); return (closestPoint(p) - p).magnitude();
} }
double distanceSquared(const Vector3& p) const { double distanceSquared(const Point3& p) const {
return (closestPoint(p) - p).squaredMagnitude(); return (closestPoint(p) - p).squaredMagnitude();
} }
/** Returns true if some part of this segment is inside the sphere */ /** Returns true if some part of this segment is inside the sphere */
bool intersectsSolidSphere(const class Sphere& s) const; bool intersectsSolidSphere(const class Sphere& s) const;
Vector3 randomPoint() const; Point3 randomPoint() const;
}; };
@@ -82,7 +86,7 @@ public:
class LineSegment2D { class LineSegment2D {
private: private:
Vector2 m_origin; Point2 m_origin;
/** Not normalized */ /** Not normalized */
Vector2 m_direction; Vector2 m_direction;
@@ -94,17 +98,17 @@ public:
LineSegment2D() {} 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 /** Returns the intersection of these segements (including
testing endpoints), or Vector2::inf() if they do not intersect. */ testing endpoints), or Point2::inf() if they do not intersect. */
Vector2 intersection(const LineSegment2D& other) const; 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; float length() const;
}; };

View File

@@ -14,7 +14,7 @@
#include <string> #include <string>
#include "G3D/platform.h" #include "G3D/platform.h"
#ifndef G3D_WIN32 #ifndef G3D_WINDOWS
#include <stdarg.h> #include <stdarg.h>
#endif #endif
@@ -57,9 +57,9 @@ private:
static Log* commonLog; static Log* commonLog;
public:
int stripFromStackBottom; int stripFromStackBottom;
public:
/** /**
@param stripFromStackBottom Number of call stacks to strip from the @param stripFromStackBottom Number of call stacks to strip from the

View File

@@ -87,7 +87,7 @@ namespace G3D {
G3D::GImage - Supports file formats, fast, Color3uint8 and Color4uint8 formats. No interpolation. 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<Texture> - 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<Color3> that supports image loading and saving and conversion to Texture. G3D::Image3 - A subclass of Map2D<Color3> that supports image loading and saving and conversion to Texture.
@@ -181,7 +181,7 @@ public:
typedef Storage StorageType; typedef Storage StorageType;
typedef Compute ComputeType; typedef Compute ComputeType;
typedef Map2D<Storage, Compute> Type; typedef Map2D<Storage, Compute> Type;
typedef ReferenceCountedPointer<Map2D> Ref; typedef shared_ptr<Map2D> Ref;
protected: protected:
@@ -296,7 +296,7 @@ public:
GMutex mutex; GMutex mutex;
static Ref create(int w = 0, int h = 0, WrapMode wrap = WrapMode::ERROR) { 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. /** Resizes without clearing, leaving garbage.
@@ -372,7 +372,7 @@ public:
// (we're returning a const reference so this is ok) // (we're returning a const reference so this is ok)
return const_cast<Type*>(this)->slowGet(x, y, wrap); return const_cast<Type*>(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; // gcc gives a useless warning that the above code might reach the end of the function;
// we use this line to supress the warning. // we use this line to supress the warning.
return ZERO; return ZERO;
@@ -393,7 +393,7 @@ public:
inline Storage& get(int x, int y, WrapMode wrap) { inline Storage& get(int x, int y, WrapMode wrap) {
return const_cast<Storage&>(const_cast<const Type*>(this)->get(x, y, wrap)); return const_cast<Storage&>(const_cast<const Type*>(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; // gcc gives a useless warning that the above code might reach the end of the function;
// we use this line to supress the warning. // we use this line to supress the warning.
return ZERO; return ZERO;
@@ -402,7 +402,7 @@ public:
inline Storage& get(int x, int y) { inline Storage& get(int x, int y) {
return const_cast<Storage&>(const_cast<const Type*>(this)->get(x, y)); return const_cast<Storage&>(const_cast<const Type*>(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; // gcc gives a useless warning that the above code might reach the end of the function;
// we use this line to supress the warning. // we use this line to supress the warning.
return ZERO; return ZERO;
@@ -441,6 +441,19 @@ public:
setChanged(true); setChanged(true);
} }
/** Copy values from \a src, which must have the same size */
template<class T>
void set(const shared_ptr<Map2D<Storage, T> >& src) {
debugAssert(src->width() == width());
debugAssert(src->height() == height());
const Array<Storage>& 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*/ /** flips if @a flip is true*/
void maybeFlipVertical(bool flip) { void maybeFlipVertical(bool flip) {
if (flip) { if (flip) {

View File

@@ -234,7 +234,7 @@ public:
}; };
private: private:
typedef ReferenceCountedPointer<Impl> ImplRef; typedef shared_ptr<Impl> ImplRef;
ImplRef impl; ImplRef impl;
@@ -501,10 +501,13 @@ public:
} }
/** /**
(A<SUP>T</SUP>A)<SUP>-1</SUP>A<SUP>T</SUP>) computed \brief Computes the Moore-Penrose pseudo inverse, equivalent to
using SVD. (A<SUP>T</SUP>A)<SUP>-1</SUP>A<SUP>T</SUP>). 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; Matrix pseudoInverse(float tolerance = -1) const;

View File

@@ -9,7 +9,7 @@ namespace G3D {
/** @beta */ /** @beta */
class Matrix2 { class Matrix2 {
private: private:
// Row, column
float data[2][2]; float data[2][2];
public: public:
@@ -57,14 +57,22 @@ public:
data[1][0] / f, data[1][1] / f); data[1][0] / f, data[1][1] / f);
} }
float* operator[](int i) { inline float* operator[] (int i) {
debugAssert(i >= 0 && i <= 2); debugAssert(i >= 0 && i <= 1);
return data[i]; return (float*)&data[i][0];
} }
const float* operator[](int i) const { inline const float* operator[] (int i) const {
debugAssert(i >= 0 && i <= 1); 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];
} }
}; };

View File

@@ -1,14 +1,14 @@
/** /**
@file Matrix3.h \file Matrix3.h
3x3 matrix class 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 <A HREF="http://www.magic-software.com">http://www.magic-software.com</A> \cite Portions based on Dave Eberly's Magic Software Library at <A HREF="http://www.magic-software.com">http://www.magic-software.com</A>
@created 2001-06-02 \created 2001-06-02
@edited 2006-04-05 \edited 2011-05-05
*/ */
#ifndef G3D_Matrix3_h #ifndef G3D_Matrix3_h
@@ -32,11 +32,12 @@ namespace G3D {
class Any; class Any;
/** /**
3x3 matrix. Do not subclass. A 3x3 matrix. Do not subclass. Data is unitializd when default constructed.
*/ */
class Matrix3 { class Matrix3 {
private: private:
// Row, column
float elt[3][3]; float elt[3][3];
// Hidden operators // Hidden operators
@@ -47,13 +48,39 @@ private:
public: public:
/** Must be in one of the following forms:
- Matrix3(#, #, # .... #)
- Matrix3::fromAxisAngle(#, #)
- Matrix3::diagonal(#, #, #)
- Matrix3::identity()
*/
Matrix3(const Any& any); 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 static Matrix3 fromRows(const Vector3& r0, const Vector3& r1, const Vector3& r2) {
Matrix3::zero(), Matrix3::identity(), Matrix3::fromAxisAngle, etc.*/ Matrix3 m;
inline Matrix3() {} 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 (class BinaryInput& b);
Matrix3 (const float aafEntry[3][3]); Matrix3 (const float aafEntry[3][3]);
@@ -69,6 +96,12 @@ public:
@cite Implementation from Watt and Watt, pg 362*/ @cite Implementation from Watt and Watt, pg 362*/
Matrix3(const class Quat& q); 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 serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b); void deserialize(class BinaryInput& b);
@@ -83,7 +116,7 @@ public:
float fEntry20, float fEntry21, float fEntry22); 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) { inline float* operator[] (int iRow) {
debugAssert(iRow >= 0); debugAssert(iRow >= 0);
@@ -209,8 +242,8 @@ public:
bool isOrthonormal() const; bool isOrthonormal() const;
Matrix3 transpose () const; Matrix3 transpose () const;
bool inverse (Matrix3& rkInverse, float fTolerance = 1e-06) const; bool inverse (Matrix3& rkInverse, float fTolerance = 1e-06f) const;
Matrix3 inverse (float fTolerance = 1e-06) const; Matrix3 inverse (float fTolerance = 1e-06f) const;
float determinant () const; float determinant () const;
/** singular value decomposition */ /** singular value decomposition */
@@ -267,8 +300,12 @@ public:
0, 0, d.z); 0, 0, d.z);
} }
/** \sa fromUnitAxisAngle */
static Matrix3 fromAxisAngle(const Vector3& rkAxis, float fRadians); 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 * The matrix must be orthonormal. The decomposition is yaw*pitch*roll
* where yaw is rotation about the Up vector, pitch is rotation about the * 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 // "You might be tempted to write [...] them as inline functions
// inside their respective header files, but this is something you // inside their respective header files, but this is something you
// must definitely not do. An inline function can be duplicated // must definitely not do. An inline function can be duplicated
// in every file in which it appears <20><><EFBFBD><EFBFBD> and this duplication // in every file in which it appears and this duplication
// includes the static object definition. Because inline functions // includes the static object definition. Because inline functions
// automatically default to internal linkage, this would result in // automatically default to internal linkage, this would result in
// having multiple static objects across the various translation // having multiple static objects across the various translation

View File

@@ -5,8 +5,8 @@
@maintainer Morgan McGuire, http://graphics.cs.williams.edu @maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2003-10-02 \created 2003-10-02
@edited 2009-10-20 \edited 2012-12-25
*/ */
#ifndef G3D_Matrix4_h #ifndef G3D_Matrix4_h
@@ -26,11 +26,12 @@
namespace G3D { namespace G3D {
class Any; 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 { class Matrix4 {
private: private:
@@ -50,10 +51,20 @@ private:
bool operator>=(const Matrix4&) const; bool operator>=(const Matrix4&) const;
public: public:
/** Must be of the form: <code>Matrix4(#, #, # .... #)</code>*/
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( Matrix4(
float r1c1, float r1c2, float r1c3, float r1c4, float r1c1, float r1c2, float r1c3, float r1c4,
@@ -75,8 +86,16 @@ public:
Matrix4(const double* init); Matrix4(const double* init);
/** Matrix4::zero() */
Matrix4(); 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. /** Produces an RT transformation that nearly matches this Matrix4.
Because a Matrix4 may not be precisely a rotation and translation, Because a Matrix4 may not be precisely a rotation and translation,
this may introduce error. */ this may introduce error. */
@@ -88,14 +107,19 @@ public:
static const Matrix4& zero(); static const Matrix4& zero();
/** If this is a perspective projection matrix created by /** 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 void getPerspectiveProjectionParameters
(float& left, (double& left,
float& right, double& right,
float& bottom, double& bottom,
float& top, double& top,
float& nearval, double& nearval,
float& farval, double& farval,
float updirection = -1.0f) const; float updirection = -1.0f) const;
inline float* operator[](int r) { inline float* operator[](int r) {
@@ -110,6 +134,7 @@ public:
return (const float*)&elt[r]; return (const float*)&elt[r];
} }
/** Returns a row-major pointer. */
inline operator float* () { inline operator float* () {
return (float*)&elt[0][0]; return (float*)&elt[0][0];
} }
@@ -131,6 +156,8 @@ public:
class Matrix3 upper3x3() const; class Matrix3 upper3x3() const;
class Matrix2 upper2x2() const;
/** Homogeneous multiplication. Let k = M * [v w]^T. result = k.xyz() / k.w */ /** Homogeneous multiplication. Let k = M * [v w]^T. result = k.xyz() / k.w */
class Vector3 homoMul(const class Vector3& v, float w) const; class Vector3 homoMul(const class Vector3& v, float w) const;
@@ -151,7 +178,6 @@ public:
float farval, float farval,
float upDirection = -1.0f); float upDirection = -1.0f);
/** \param upDirection Use -1.0 for 2D Y increasing downwards (the G3D 8.x default convention), /** \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) 1.0 for 2D Y increasing upwards (the G3D 7.x default and OpenGL convention)
*/ */
@@ -163,14 +189,17 @@ public:
/** \param upDirection Use -1.0 for 2D Y increasing downwards (the G3D 8.x default convention), /** \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) 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( static Matrix4 perspectiveProjection(
float left, double left,
float right, double right,
float bottom, double bottom,
float top, double top,
float nearval, double nearval,
float farval, double farval,
float upDirection = -1.0f); float upDirection = -1.0f);
void setRow(int r, const class Vector4& v); void setRow(int r, const class 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 } // namespace

View File

@@ -20,7 +20,7 @@ namespace G3D {
Abstraction of memory management. Abstraction of memory management.
Default implementation uses G3D::System::malloc and is threadsafe. Default implementation uses G3D::System::malloc and is threadsafe.
\sa CRTMemoryManager, AlignedMemoryManager, AreaMemoryManager */ \sa LargePoolMemoryManager, CRTMemoryManager, AlignedMemoryManager, AreaMemoryManager */
class MemoryManager : public ReferenceCountedObject { class MemoryManager : public ReferenceCountedObject {
protected: protected:
@@ -28,7 +28,7 @@ protected:
public: public:
typedef ReferenceCountedPointer<class MemoryManager> Ref; typedef shared_ptr<class MemoryManager> Ref;
/** Return a pointer to \a s bytes of memory that are unused by /** Return a pointer to \a s bytes of memory that are unused by
the rest of the program. The contents of the memory are the rest of the program. The contents of the memory are
@@ -59,7 +59,7 @@ protected:
public: public:
typedef ReferenceCountedPointer<class AlignedMemoryManager> Ref; typedef shared_ptr<class AlignedMemoryManager> Ref;
virtual void* alloc(size_t s); 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 { class CRTMemoryManager : public MemoryManager {
protected: protected:
CRTMemoryManager(); CRTMemoryManager();
public: public:
typedef ReferenceCountedPointer<class MemoryManager> Ref; typedef shared_ptr<class MemoryManager> Ref;
virtual void* alloc(size_t s); virtual void* alloc(size_t s);
virtual void free(void* ptr); virtual void free(void* ptr);
virtual bool isThreadsafe() const; virtual bool isThreadsafe() const;

View File

@@ -20,9 +20,10 @@
#include "G3D/constants.h" #include "G3D/constants.h"
#include "G3D/Image1.h" #include "G3D/Image1.h"
#ifdef G3D_WIN32 #ifdef G3D_WINDOWS
// Turn off "conditional expression is constant" warning; MSVC generates this // Turn off "conditional expression is constant" warning; MSVC generates this
// for debug assertions in inlined methods. // for debug assertions in inlined methods.
#pragma warning( push )
#pragma warning (disable : 4127) #pragma warning (disable : 4127)
#endif #endif
@@ -444,7 +445,7 @@ public:
Array<Vector3>& newVertexPositions, Array<Vector3>& newVertexPositions,
Array<int>& toNew, Array<int>& toNew,
Array<int>& toOld, Array<int>& toOld,
double radius = fuzzyEpsilon); float radius = fuzzyEpsilon32);
/** /**
Modifies the face, edge, and vertex arrays in place so that Modifies the face, edge, and vertex arrays in place so that
@@ -479,7 +480,7 @@ public:
Array<Face>& faceArray, Array<Face>& faceArray,
Array<Edge>& edgeArray, Array<Edge>& edgeArray,
Array<Vertex>& vertexArray, Array<Vertex>& 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 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 vertex Output vertices
@param texCoord Output texture coordinates @param texCoord Output texture coordinates
@@ -545,8 +546,8 @@ public:
@param twoSided If true, matching top and bottom planes are generated. @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 \param elevation If non-NULL, values from this image are used as elevations. Apply an \a xform to adjust the scale
*/ */
static void generateGrid( static void generateGrid
Array<Vector3>& vertex, (Array<Vector3>& vertex,
Array<Vector2>& texCoord, Array<Vector2>& texCoord,
Array<int>& index, Array<int>& index,
int wCells = 10, int wCells = 10,
@@ -555,7 +556,7 @@ public:
bool spaceCentered = true, bool spaceCentered = true,
bool twoSided = true, bool twoSided = true,
const CoordinateFrame& xform = CoordinateFrame(), const CoordinateFrame& xform = CoordinateFrame(),
const Image1::Ref& elevation = NULL); const Image1::Ref& elevation = Image1::Ref());
/** Converts quadlist (QUADS), /** Converts quadlist (QUADS),
triangle fan (TRIANGLE_FAN), triangle fan (TRIANGLE_FAN),
@@ -679,5 +680,11 @@ protected:
int i0, int i1, int f, double area); int i0, int i1, int f, double area);
}; };
} }
#ifdef G3D_WINDOWS
#pragma warning( pop )
#endif
#endif #endif

View File

@@ -35,6 +35,8 @@ private:
std::string name; std::string name;
bool scaleAndCenter;
/** /**
All of the triangles, as a long triangle list. All of the triangles, as a long triangle list.
*/ */
@@ -50,7 +52,7 @@ private:
public: 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 /** Writes the model to the arrays, which can then be used with
G3D::IFSModel::save and G3D::MeshAlg */ G3D::IFSModel::save and G3D::MeshAlg */

View File

@@ -1,3 +1,9 @@
/**
\file G3D/NetAddress.h
\created 2010-01-03
\edited 2013-03-17
*/
#ifndef G3D_NetAddress_h #ifndef G3D_NetAddress_h
#define G3D_NetAddress_h #define G3D_NetAddress_h
@@ -24,10 +30,21 @@ private:
SOCKADDR_IN addr; SOCKADDR_IN addr;
public: public:
enum {
/** /**
In host byte order Use the host portion of the IP address of the default adapter on this machine.
*/ */
NetAddress(uint32 host, uint16 port = 0); // Must match ENET_HOST_ANY
DEFAULT_ADAPTER_HOST = 0
};
/**
In host byte order.
\sa DEFAULT_ADAPTER_HOST
*/
explicit NetAddress(uint32 host, uint16 port = 0);
/** /**
@param port Specified in host byte order (i.e., don't worry about endian issues) @param port Specified in host byte order (i.e., don't worry about endian issues)
@@ -37,7 +54,7 @@ public:
/** /**
@param hostnameAndPort in the form "hostname:port" or "ip: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() @deprecated Use G3D::NetworkDevice::broadcastAddressArray()
@@ -56,6 +73,8 @@ public:
NetAddress(); NetAddress();
static void localHostAddresses(Array<NetAddress>& array);
void serialize(class BinaryOutput& b) const; void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b); void deserialize(class BinaryInput& b);
@@ -76,6 +95,13 @@ public:
std::string ipString() const; std::string ipString() const;
std::string toString() 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&); std::ostream& operator<<(std::ostream& os, const NetAddress&);

View File

@@ -1,6 +1,5 @@
/** /**
@file NetworkDevice.h @file NetworkDevice.h
These classes abstract networking from the socket level to a These classes abstract networking from the socket level to a
serialized messaging style that is more appropriate for games. The serialized messaging style that is more appropriate for games. The
performance has been tuned for sending many small messages. The performance has been tuned for sending many small messages. The
@@ -54,7 +53,7 @@
namespace G3D { namespace G3D {
class TextOutput; class TextOutput;
/** \deprecated */
class Conduit : public ReferenceCountedObject { class Conduit : public ReferenceCountedObject {
protected: protected:
friend class NetworkDevice; friend class NetworkDevice;
@@ -134,7 +133,7 @@ public:
bool ok() const; bool ok() const;
}; };
typedef ReferenceCountedPointer<class ReliableConduit> ReliableConduitRef; typedef shared_ptr<class ReliableConduit> ReliableConduitRef;
#ifdef __GNUC__ #ifdef __GNUC__
// Workaround for a known bug in gcc 4.x where htonl produces // 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 You will need the server's G3D::NetAddress. Consider using
G3D::Discovery::Client to find it via broadcasting. G3D::Discovery::Client to find it via broadcasting.
</OL> </OL>
\deprecated
*/ */
class ReliableConduit : public Conduit { class ReliableConduit : public Conduit {
private: private:
@@ -209,7 +208,7 @@ private:
// Reserve space for the 4 byte size header // Reserve space for the 4 byte size header
b.writeUInt32(0); b.writeUInt32(0);
size_t L = b.length(); size_t L = (size_t)b.length();
m.serialize(b); m.serialize(b);
if ((size_t)b.length() == L) { if ((size_t)b.length() == L) {
// No data was created by serialization. // No data was created by serialization.
@@ -218,7 +217,7 @@ private:
b.writeUInt8(0xFF); 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. // We send the length first to tell recv how much data to read.
// Here we abuse BinaryOutput a bit and write directly into // Here we abuse BinaryOutput a bit and write directly into
@@ -353,7 +352,7 @@ public:
}; };
typedef ReferenceCountedPointer<class LightweightConduit> LightweightConduitRef; typedef shared_ptr<class LightweightConduit> LightweightConduitRef;
/** /**
Provides fast but unreliable transfer of messages. On a LAN, 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. it go out of scope and the conduit cleans itself up automatically.
</OL> </OL>
\deprecated
*/ */
class LightweightConduit : public Conduit { class LightweightConduit : public Conduit {
private: private:
@@ -458,7 +459,7 @@ private:
format("This LightweightConduit is limited to messages of " format("This LightweightConduit is limited to messages of "
"%d bytes (Ethernet hardware limit; this is the " "%d bytes (Ethernet hardware limit; this is the "
"'UDP MTU')", maxMessageSize()), "'UDP MTU')", maxMessageSize()),
b.size() - 4, // Don't count the type header (int)b.size() - 4, // Don't count the type header
maxMessageSize()); maxMessageSize());
} }
} }
@@ -536,10 +537,12 @@ public:
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
typedef ReferenceCountedPointer<class NetListener> NetListenerRef; typedef shared_ptr<class NetListener> NetListenerRef;
/** /**
Runs on the server listening for clients trying to make reliable connections. Runs on the server listening for clients trying to make reliable connections.
\deprecated
*/ */
class NetListener : public ReferenceCountedObject { class NetListener : public ReferenceCountedObject {
private: private:
@@ -600,6 +603,7 @@ public:
values between these formats. G3D only ever exposes host byte order, values between these formats. G3D only ever exposes host byte order,
so programmers rarely need to be aware of the distinction. so programmers rarely need to be aware of the distinction.
\deprecated
*/ */
class NetworkDevice { class NetworkDevice {
public: public:

View File

@@ -52,6 +52,9 @@ public:
ParseError(const std::string& f, int64 b, const std::string& m) : ParseError(const std::string& f, int64 b, const std::string& m) :
filename (f), byte(b), line(UNKNOWN), character(UNKNOWN), message(m) {} filename (f), byte(b), line(UNKNOWN), character(UNKNOWN), message(m) {}
/** If information is known, ends in ": ", otherwise empty */
std::string formatFileInfo() const;
}; };
} }

View File

@@ -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 \created 2002-07-08
@edited 2006-01-10 \edited 2011-05-10
*/ */
#ifndef G3D_PHYSICSFRAME_H #ifndef G3D_PhysicsFrame_h
#define G3D_PHYSICSFRAME_H #define G3D_PhysicsFrame_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Vector3.h" #include "G3D/Vector3.h"
@@ -33,9 +33,9 @@ public:
Quat rotation; 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. Initializes to the identity frame.
@@ -51,6 +51,13 @@ public:
PhysicsFrame(const Matrix3& rot) : rotation(rot), translation(Vector3::zero()) {} PhysicsFrame(const Matrix3& rot) : rotation(rot), translation(Vector3::zero()) {}
PhysicsFrame(const CoordinateFrame& coordinateFrame); PhysicsFrame(const CoordinateFrame& coordinateFrame);
PhysicsFrame& operator=(const PhysicsFrame& p) {
rotation = p.rotation;
translation = p.translation;
return *this;
}
/** /**
- PhysicsFrame( [quat], [vec3] ) - PhysicsFrame( [quat], [vec3] )
- Vector3( ... ) - Vector3( ... )
@@ -59,6 +66,8 @@ public:
*/ */
PhysicsFrame(const class Any& any); PhysicsFrame(const class Any& any);
Any toAny() const;
/** Compose: create the transformation that is <I>other</I> followed by <I>this</I>.*/ /** Compose: create the transformation that is <I>other</I> followed by <I>this</I>.*/
PhysicsFrame operator*(const PhysicsFrame& other) const; PhysicsFrame operator*(const PhysicsFrame& other) const;
@@ -100,6 +109,16 @@ public:
translation += f.translation; translation += f.translation;
return *this; 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; typedef PhysicsFrame PFrame;

View File

@@ -20,16 +20,31 @@ namespace G3D {
*/ */
class PhysicsFrameSpline : public Spline<PhysicsFrame> { class PhysicsFrameSpline : public Spline<PhysicsFrame> {
public: public:
PhysicsFrameSpline(); PhysicsFrameSpline();
/** Accepts a table of properties, or any valid PhysicsFrame specification for a single control*/ /** Accepts a table of properties, or any valid PhysicsFrame specification for a single control*/
PhysicsFrameSpline(const Any& any); PhysicsFrameSpline(const Any& any);
/** Clear and then reset all values from the any */ bool operator==(const PhysicsFrameSpline& a) const;
PhysicsFrameSpline& operator=(const Any& any);
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 correct(PhysicsFrame& frame) const;
virtual void ensureShortestPath(PhysicsFrame* A, int N) const; virtual void ensureShortestPath(PhysicsFrame* A, int N) const;
virtual Any toAny(const std::string& myName) const override {
return Spline<PhysicsFrame>::toAny(myName);
}
Any toAny() const {
return toAny("PFrameSpline");
}
}; };
} }

View File

@@ -1,16 +1,16 @@
/** /**
@file Plane.h \file Plane.h
Plane class Plane class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-06-02 \created 2001-06-02
@edited 2004-07-18 \edited 2010-12-04
*/ */
#ifndef G3D_PLANE_H #ifndef G3D_Plane_h
#define G3D_PLANE_H #define G3D_Plane_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Vector3.h" #include "G3D/Vector3.h"
@@ -40,13 +40,20 @@ public:
Plane() : _normal(Vector3::unitY()), _distance(0) { 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. Constructs a plane from three points.
*/ */
Plane( Plane
const Vector3& point0, (const Point3& point0,
const Vector3& point1, const Point3& point1,
const Vector3& point2); const Point3& point2);
/** /**
Constructs a plane from three points, where at most two are Constructs a plane from three points, where at most two are
@@ -60,13 +67,14 @@ public:
/** /**
The normal will be unitized. The normal will be unitized.
*/ */
Plane( Plane
const Vector3& __normal, (const Vector3& normal,
const Vector3& point); const Point3& point);
static Plane fromEquation(float a, float b, float c, float d); static Plane fromEquation(float a, float b, float c, float d);
Plane(class BinaryInput& b); Plane(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);
@@ -76,7 +84,7 @@ public:
Returns true if point is on the side the normal points to or Returns true if point is on the side the normal points to or
is in the plane. is in the plane.
*/ */
inline bool halfSpaceContains(Vector3 point) const { inline bool halfSpaceContains(Point3 point) const {
// Clamp to a finite range for testing // Clamp to a finite range for testing
point = point.clamp(Vector3::minFinite(), Vector3::maxFinite()); 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 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. 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()); debugAssert(point.isFinite());
return _normal.dot(point) >= _distance; return _normal.dot(point) >= _distance;
} }
@@ -109,7 +117,7 @@ public:
/** /**
Returns true if the point is nearly in the plane. 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); return fuzzyEq(point.dot(_normal), _distance);
} }
@@ -124,7 +132,7 @@ public:
return (_normal.dot(x) - _distance); return (_normal.dot(x) - _distance);
} }
inline Vector3 closestPoint(const Vector3& x) const { inline Point3 closestPoint(const Point3& x) const {
return x + (_normal * (-distance(x))); return x + (_normal * (-distance(x)));
} }

View File

@@ -1,11 +1,11 @@
/** /**
@file PointHashGrid.h \file PointHashGrid.h
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2008-07-01 \created 2008-07-01
@edited 2009-05-28 \edited 2010-11-28
Copyright 2000-2010, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_PointHashGrid_h #ifndef G3D_PointHashGrid_h
@@ -25,23 +25,23 @@
namespace G3D { namespace G3D {
/** /**
Storage of data in a sparse 3D grid of point-based data. The \brief A sparse 3D grid of point-based data.
space cost for <I>n</I> elements is O(<I>n</I>). For data with
The space cost for <I>n</I> elements is O(<I>n</I>). For data with
approximately uniform density (with respect to the radius hint), approximately uniform density (with respect to the radius hint),
the time cost of searching for neighbors is O(1). the time cost of searching for neighbors is O(1).
<i>Value</i> must be supported by a G3D::PositionTrait and You can move members of the data set by first removing them and then
G3D::EqualsTrait. Overloads are provided for adding them with a new location.
common G3D classes like G3D::Vector3. For example:
<pre> Template argument \a PosFunc must provide a static <code>getPosition</code> method
class EqualsFunc { and \a EqualsFunc must provide a static <code>equals</code> method, as described below.
public: You can either write classes that support these yourself, provide template specializations of
static bool equals(const Data& p, const Data& q) { G3D::PositionTrait and
return p == q; G3D::EqualsTrait, or rely on the default template specializations, which already exist for
} common G3D classes like G3D::Point3. For example:
};
\code
class PosFunc { class PosFunc {
public: public:
static void getPosition(const Data& d, Vector3& pos) { 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<Data, Data::PosFunc, Data::EqualsFunc> grid; PointHashGrid<Data, Data::PosFunc, Data::EqualsFunc> grid;
</pre> \endcode
If the Value class defines operator==, the Equalsfunc is optional: If the \a Value class defines <code>operator==</code>, then the \a Equalsfunc is optional, so you can just write:
<pre> \code
PointHashGrid<Data, Data::PosFunc> grid; PointHashGrid<Data, Data::PosFunc> grid;
</pre> \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<Data, Data> DataGrid;
\endcode
*/ */
template<class Value, template<class Value,
@@ -65,20 +94,20 @@ template<class Value,
class PointHashGrid { class PointHashGrid {
private: private:
# define expectedCellSize (3) # define expectedCellSize (10)
# define ThisType PointHashGrid<Value, PosFunc, EqualsFunc> # define ThisType PointHashGrid<Value, PosFunc, EqualsFunc>
/** A value annotated with precomputed position and hash code.*/ /** A value annotated with precomputed position and hash code.*/
class Entry { class Entry {
public: public:
Vector3 position; Point3 position;
Value value; Value value;
}; };
/** One cell of the grid. */ /** One cell of the grid. */
typedef SmallArray<Entry, expectedCellSize> Cell; typedef SmallArray<Entry, expectedCellSize> Cell;
typedef Table<Vector3int32, Cell > CellTable; typedef Table<Point3int32, Cell > CellTable;
/** The cube of +/-1 along each dimension. Initialized by initOffsetArray.*/ /** The cube of +/-1 along each dimension. Initialized by initOffsetArray.*/
Vector3int32 m_offsetArray[3*3*3]; Vector3int32 m_offsetArray[3*3*3];
@@ -116,18 +145,19 @@ private:
/** Locate the cell and index within that cell containing v. Called by /** Locate the cell and index within that cell containing v. Called by
remove() and contains(). */ remove() and contains(). */
bool find(const Value& v, bool find
Vector3int32& foundCellCoord, (const Value& v,
Point3int32& foundCellCoord,
Cell*& foundCell, Cell*& foundCell,
int& index) { int& index) {
Vector3 pos; Point3 pos;
PosFunc::getPosition(v, pos); PosFunc::getPosition(v, pos);
Vector3int32 cellCoord; Point3int32 cellCoord;
getCellCoord(pos, cellCoord); getCellCoord(pos, cellCoord);
for (int i = 0; i < 27; ++i) { 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); Cell* cell = m_data.getPointer(c);
if (cell != NULL) { if (cell != NULL) {
// The cell exists // The cell exists
@@ -146,18 +176,25 @@ private:
return false; return false;
} }
/** Given a real-space position, returns the cell coord public:
containing it.*/
inline void getCellCoord(const Vector3& pos, Vector3int32& cellCoord) const { /** \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) { for (int a = 0; a < 3; ++a) {
cellCoord[a] = iFloor(pos[a] * m_invCellWidth); cellCoord[a] = iFloor(pos[a] * m_invCellWidth);
} }
} }
protected:
/** Initializes m_offsetArray. */ /** Initializes m_offsetArray. */
void initOffsetArray() { void initOffsetArray() {
int i = 0; int i = 0;
Vector3int32 d; Point3int32 d;
for (d.x = -1; d.x <= +1; ++d.x) { for (d.x = -1; d.x <= +1; ++d.x) {
for (d.y = -1; d.y <= +1; ++d.y) { for (d.y = -1; d.y <= +1; ++d.y) {
for (d.z = -1; d.z <= +1; ++d.z) { for (d.z = -1; d.z <= +1; ++d.z) {
@@ -179,9 +216,10 @@ private:
public: public:
/** /**
@param radiusHint the radius that will typically be used with \param radiusHint the radius that will typically be used with
beginSphereIntersection and beginBoxIntersection. If two <i>Value</i>s are equal, beginBallIntersection and beginBoxIntersection. If two <i>Value</i>s are equal,
their positions must be within this radius as well. 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) { PointHashGrid(float radiusHint, const MemoryManager::Ref& m = MemoryManager::create()) : m_size(0), m_memoryManager(m) {
initOffsetArray(); initOffsetArray();
@@ -192,23 +230,41 @@ public:
m_invCellWidth = 1.0f / m_cellWidth; 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 about 5 values in each grid cell (which means about 27 * 5
values for each beginIntersection call). values for each beginIntersection call).
\sa clearAndSetRadiusHint()
*/ */
PointHashGrid(const Array<Value>& init, float radiusHint = -1.0f, const MemoryManager::Ref& m = MemoryManager::create()) : m_size(0), m_memoryManager(m) { PointHashGrid(const Array<Value>& init, float radiusHint = -1.0f, const MemoryManager::Ref& m = MemoryManager::create()) : m_size(0), m_memoryManager(m) {
initOffsetArray(); initOffsetArray();
m_data.clearAndSetMemoryManager(m_memoryManager); m_data.clearAndSetMemoryManager(m_memoryManager);
Vector3 lo(Vector3::inf()); Point3 lo(Vector3::inf());
Vector3 hi(-lo); Point3 hi(-lo);
// Compute bounds // Compute bounds
Array<Entry> entry(init.size()); Array<Entry> entry(init.size());
for (int i = 0; i < entry.size(); ++i) { for (int i = 0; i < entry.size(); ++i) {
const Value& value = init[i]; const Value& value = init[i];
Vector3 pos; Point3 pos;
entry[i].value = value; entry[i].value = value;
entry[i].hashCode = m_hashFunc(value); entry[i].hashCode = m_hashFunc(value);
@@ -241,7 +297,7 @@ public:
} }
/** Returns the number of elements. */ /** Returns the number of elements. */
inline int size() const { int size() const {
return m_size; return m_size;
} }
@@ -251,13 +307,19 @@ public:
return m_bounds; 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 <code>getPosition(v, p)</code>. /** Insert @a v at position @a p given by <code>getPosition(v, p)</code>.
Multiple elements that are equal may be inserted; all copies will be Multiple elements that are equal may be inserted; all copies will be
in the data structure. */ in the data structure. */
void insert(const Value& v) { void insert(const Value& v) {
Vector3 pos; Point3 pos;
PosFunc::getPosition(v, pos); PosFunc::getPosition(v, pos);
Vector3int32 cellCoord; Point3int32 cellCoord;
getCellCoord(pos, cellCoord); getCellCoord(pos, cellCoord);
// See if the cell already exists // See if the cell already exists
@@ -316,7 +378,8 @@ public:
// Drop our pointer, which is about to dangle // Drop our pointer, which is about to dangle
cell = NULL; cell = NULL;
bool success = m_data.remove(cellCoord); const bool success = m_data.remove(cellCoord);
(void)success;
debugAssertM(success, "Data structure corrupt: " debugAssertM(success, "Data structure corrupt: "
"tried to remove a cell that doesn't exist."); "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<Value>& v, bool shrink = true) { void remove(const Array<Value>& v, bool shrink = true) {
for (int i = 0; i < v.size(); ++i) { for (int i = 0; i < v.size(); ++i) {
remove(v[i], shrink); remove(v[i], shrink);
@@ -387,6 +450,11 @@ public:
} }
} }
bool isValid() const {
return ! m_isEnd;
}
/** @deprecated Use isValid */
bool hasMore() const { bool hasMore() const {
return ! m_isEnd; return ! m_isEnd;
} }
@@ -615,9 +683,14 @@ public:
const Value* operator->() const { return &value(); } const Value* operator->() const { return &value(); }
operator Value*() const { return &value(); } operator Value*() const { return &value(); }
/** \deprecated Use isValid */
bool hasMore() const { bool hasMore() const {
return ! m_isEnd; return ! m_isEnd;
} }
bool isValid() const {
return ! m_isEnd;
}
}; // BoxIterator }; // BoxIterator
/** /**
@@ -652,7 +725,7 @@ public:
SphereIterator() : m_isEnd(true) {} SphereIterator() : m_isEnd(true) {}
void advance() { void advance() {
if (! m_boxIterator.hasMore()) { if (! m_boxIterator.isValid()) {
m_isEnd = true; m_isEnd = true;
return; return;
} }
@@ -660,7 +733,7 @@ public:
while (! m_sphere.contains(m_boxIterator.position())) { while (! m_sphere.contains(m_boxIterator.position())) {
++m_boxIterator; ++m_boxIterator;
if (! m_boxIterator.hasMore()) { if (! m_boxIterator.isValid()) {
m_isEnd = true; m_isEnd = true;
return; return;
} }
@@ -693,6 +766,7 @@ public:
// Intentionally unimplemented // Intentionally unimplemented
SphereIterator& operator=(const SphereIterator&); SphereIterator& operator=(const SphereIterator&);
public: public:
inline bool operator!=(const SphereIterator& other) const { inline bool operator!=(const SphereIterator& other) const {
@@ -710,8 +784,6 @@ public:
return !(*this != other); return !(*this != other);
} }
/** Preincrement */ /** Preincrement */
SphereIterator& operator++() { SphereIterator& operator++() {
debugAssert(! m_isEnd); debugAssert(! m_isEnd);
@@ -733,30 +805,51 @@ public:
const Value* operator->() const { return &value(); } const Value* operator->() const { return &value(); }
operator Value*() 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; return ! m_isEnd;
} }
}; // SphereIterator }; // SphereIterator
/** /** Finds all values whose positions are within \a sphere. It is
Finds all values whose positions are within @a sphere. It is an error an error to mutate the PointHashGrid while iterating through
to mutate the HashGrid while iterating through it. it. */
*/ SphereIterator begin(const Sphere& sphere) const {
SphereIterator beginSphereIntersection(const Sphere& sphere) const {
return SphereIterator(this, sphere); 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 { const SphereIterator& endSphereIntersection() const {
static const SphereIterator it; static const SphereIterator it;
return it; return it;
} }
/** Appends results */
void getIntersectingMembers(const Sphere& sphere, Array<Value>& 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 Dereference to access the bounds() and size() [element count] of the underlying
cell objet. cell object.
Example: Example:
<pre> <pre>
@@ -793,8 +886,8 @@ public:
/** Returns the bounds on this cell */ /** Returns the bounds on this cell */
AABox bounds() const { AABox bounds() const {
const Vector3int32& k = m_parent->m_tableIterator->key; const Vector3int32& k = m_parent->m_tableIterator->key;
return AABox(Vector3(k) * m_parent->m_cellWidth, return AABox(Vector3(k) * m_parent->m_grid->m_cellWidth,
Vector3(k + Vector3int32(1, 1, 1)) * m_parent->m_cellWidth); Vector3(k + Vector3int32(1, 1, 1)) * m_parent->m_grid->m_cellWidth);
} }
/** Number of elements inside this cell */ /** Number of elements inside this cell */
@@ -823,7 +916,7 @@ public:
m_tableIterator( grid->m_data.begin()), m_tableIterator( grid->m_data.begin()),
m_epoch(grid->m_epoch) { m_epoch(grid->m_epoch) {
m_indirection.m_parent = this; m_indirection.m_parent = this;
m_isEnd = ! m_tableIterator.hasMore(); m_isEnd = ! m_tableIterator.isValid();
} }
// Intentionally unimplemented // Intentionally unimplemented
@@ -853,7 +946,7 @@ public:
"It is illegal to mutate the HashGrid while " "It is illegal to mutate the HashGrid while "
"iterating through it."); "iterating through it.");
++m_tableIterator; ++m_tableIterator;
m_isEnd = ! m_tableIterator.hasMore(); m_isEnd = ! m_tableIterator.isValid();
return *this; return *this;
} }
@@ -864,9 +957,14 @@ public:
return old; return old;
} }
/** \deprecated Use isValid */
bool hasMore() const { bool hasMore() const {
return ! m_isEnd; return ! m_isEnd;
} }
bool isValid() const {
return ! m_isEnd;
}
}; // CellIterator }; // CellIterator
/** Iterates through the non-empty cells. This is intended primarily for /** Iterates through the non-empty cells. This is intended primarily for
@@ -901,7 +999,7 @@ public:
Using objects (instead of pointers) or reference counted pointers is Using objects (instead of pointers) or reference counted pointers is
recommended over using pointers and this deleteAll method.*/ recommended over using pointers and this deleteAll method.*/
void deleteAll() { void deleteAll() {
for (Iterator it = begin(); it.hasMore(); ++it) { for (Iterator it = begin(); it.isValid(); ++it) {
delete *it; delete *it;
} }
clear(); clear();
@@ -924,7 +1022,7 @@ public:
m_bounds = AABox(); m_bounds = AABox();
if (! shrink) { if (! shrink) {
// Remove all data // Remove all data
for (CellIterator it = beginCells(); it.hasMore(); ++it) { for (CellIterator it = beginCells(); it.isValid(); ++it) {
it.cell().clear(true); it.cell().clear(true);
} }
} else { } else {
@@ -934,7 +1032,7 @@ public:
} }
int debugGetDeepestBucketSize() const { int debugGetDeepestBucketSize() const {
return m_data.debugGetDeepestBucketSize(); return (int)m_data.debugGetDeepestBucketSize();
} }
float debugGetAverageBucketSize() const { float debugGetAverageBucketSize() const {

View File

@@ -4,15 +4,15 @@
@maintainer Morgan McGuire, http://graphics.cs.williams.edu @maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2004-01-11 @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. All rights reserved.
*/ */
#ifndef X_PointKDTree_H #ifndef G3D_PointKDTree_h
#define X_PointKDTree_H #define G3D_PointKDTree_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Array.h" #include "G3D/Array.h"
@@ -26,7 +26,7 @@
#include "G3D/BinaryInput.h" #include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h" #include "G3D/BinaryOutput.h"
#include "G3D/CollisionDetection.h" #include "G3D/CollisionDetection.h"
#include "G3D/GCamera.h" #include "G3D/Frustum.h"
#include "G3D/PositionTrait.h" #include "G3D/PositionTrait.h"
#include <algorithm> #include <algorithm>
@@ -241,10 +241,12 @@ protected:
debugAssert(lo == splitBounds.low()); debugAssert(lo == splitBounds.low());
debugAssert(hi == splitBounds.high()); debugAssert(hi == splitBounds.high());
# ifdef G3D_DEBUG
for (int i = 0; i < valueArray.length(); ++i) { for (int i = 0; i < valueArray.length(); ++i) {
const Vector3& b = valueArray[i].position(); const Vector3& b = valueArray[i].position();
debugAssert(splitBounds.contains(b)); debugAssert(splitBounds.contains(b));
} }
# endif
if (child[0] || child[1]) { if (child[0] || child[1]) {
debugAssert(lo[splitAxis] < splitLocation); debugAssert(lo[splitAxis] < splitLocation);
@@ -297,6 +299,7 @@ protected:
for (int c = 0; c < 2; ++c) { for (int c = 0; c < 2; ++c) {
n->child[c] = deserializeStructure(bi); n->child[c] = deserializeStructure(bi);
} }
return n;
} }
} }
@@ -484,7 +487,7 @@ protected:
// Compute the mean along the axis // Compute the mean along the axis
splitLocation = (bounds.high()[splitAxis] + splitLocation = (bounds.high()[splitAxis] +
bounds.low()[splitAxis]) / 2.0; bounds.low()[splitAxis]) / 2.0f;
Handle splitHandle; Handle splitHandle;
Vector3 v; Vector3 v;
@@ -611,7 +614,7 @@ public:
} }
int size() const { size_t size() const {
return memberTable.size(); return memberTable.size();
} }
@@ -809,7 +812,7 @@ private:
// Test values at this node against remaining planes // Test values at this node against remaining planes
for (int p = 0; p < plane.size(); ++p) { for (int p = 0; p < plane.size(); ++p) {
if ((parentMask >> p) & 1 != 0) { if (((parentMask >> p) & 1) != 0) {
// Test against this plane // Test against this plane
const Plane& curPlane = plane[p]; const Plane& curPlane = plane[p];
for (int v = node->valueArray.size() - 1; v >= 0; --v) { for (int v = node->valueArray.size() - 1; v >= 0; --v) {
@@ -851,7 +854,7 @@ public:
/** /**
Typically used to find all visible 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
<B>not</B> culled by frustum. <B>not</B> culled by frustum.
Example: Example:
@@ -862,7 +865,7 @@ public:
</PRE> </PRE>
@param members The results are appended to this array. @param members The results are appended to this array.
*/ */
void getIntersectingMembers(const GCamera::Frustum& frustum, Array<T>& members) const { void getIntersectingMembers(const Frustum& frustum, Array<T>& members) const {
Array<Plane> plane; Array<Plane> plane;
for (int i = 0; i < frustum.faceArray.size(); ++i) { for (int i = 0; i < frustum.faceArray.size(); ++i) {

View File

@@ -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 \created 2007-05-16
@edited 2009-03-26 \edited 2012-10-06
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_Pointer_h #ifndef G3D_Pointer_h
@@ -27,7 +27,7 @@ namespace G3D {
Because the accessors require values to be passed by value (instead of by reference) 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. this is primarily useful for objects whose memory size is small.
<pre> \code
class Foo { class Foo {
public: public:
void setEnabled(bool b); void setEnabled(bool b);
@@ -51,14 +51,15 @@ namespace G3D {
p2.setValue(p1.getValue()); p2.setValue(p1.getValue());
p2 = p1; p2 = p1;
</pre> \endcode
<i>Note:</i> Because of the way that dereference is implemented, you cannot pass <code>*p</code> through a function <i>Note:</i> Because of the way that dereference is implemented, you cannot pass <code>*p</code> through a function
that takes varargs (...), e.g., <code>printf("%d", *p)</code> will produce a compile-time error. Instead use that takes varargs (...), e.g., <code>printf("%d", *p)</code> will produce a compile-time error. Instead use
<code>printf("%d",(bool)*p)</code> or <code>printf("%d", p.getValue())</code>. <code>printf("%d",(bool)*p)</code> or <code>printf("%d", p.getValue())</code>.
\cite McGuire, GUIs for Real-time Programs, using Universal Pointers, SIGGRAPH 2008 Poster.
*/ */
template<class ValueType> template<typename ValueType>
class Pointer { class Pointer {
private: private:
@@ -78,9 +79,7 @@ private:
public: public:
Memory(ValueType* value) : value(value) { Memory(ValueType* value) : value(value) {}
//debugAssert(value != NULL);
}
virtual void set(ValueType v) { virtual void set(ValueType v) {
*value = v; *value = v;
@@ -99,6 +98,35 @@ private:
} }
}; };
template<typename GetMethod, typename SetMethod>
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 T, typename GetMethod, typename SetMethod> template<class T, typename GetMethod, typename SetMethod>
class Accessor : public Interface { class Accessor : public Interface {
private: private:
@@ -116,8 +144,10 @@ private:
} }
virtual void set(ValueType v) { virtual void set(ValueType v) {
if (setMethod) {
(object->*setMethod)(v); (object->*setMethod)(v);
} }
}
virtual ValueType get() const { virtual ValueType get() const {
return (object->*getMethod)(); return (object->*getMethod)();
@@ -134,17 +164,17 @@ private:
template<class T, typename GetMethod, typename SetMethod> template<class T, typename GetMethod, typename SetMethod>
class RefAccessor : public Interface { class SharedAccessor : public Interface {
private: private:
ReferenceCountedPointer<T> object; shared_ptr<T> object;
GetMethod getMethod; GetMethod getMethod;
SetMethod setMethod; SetMethod setMethod;
public: public:
RefAccessor( SharedAccessor
const ReferenceCountedPointer<T>& object, (const shared_ptr<T>& object,
GetMethod getMethod, GetMethod getMethod,
SetMethod setMethod) : object(object), getMethod(getMethod), setMethod(setMethod) { SetMethod setMethod) : object(object), getMethod(getMethod), setMethod(setMethod) {
@@ -152,23 +182,24 @@ private:
} }
virtual void set(ValueType v) { virtual void set(ValueType v) {
(object.pointer()->*setMethod)(v); if (setMethod) {
(object.get()->*setMethod)(v);
}
} }
virtual ValueType get() const { virtual ValueType get() const {
return (object.pointer()->*getMethod)(); return (object.get()->*getMethod)();
} }
virtual Interface* clone() const { virtual Interface* clone() const {
return new RefAccessor(object, getMethod, setMethod); return new SharedAccessor(object, getMethod, setMethod);
} }
virtual bool isNull() const { virtual bool isNull() const {
return object.isNull(); return (bool)object;
} }
}; };
Interface* m_interface; Interface* m_interface;
public: public:
@@ -197,48 +228,69 @@ public:
this[0] = p; this[0] = p;
} }
/** \param setMethod May be NULL */
template<class Class> template<class Class>
Pointer(const ReferenceCountedPointer<Class>& object, Pointer(const shared_ptr<Class>& object,
ValueType (Class::*getMethod)() const, ValueType (Class::*getMethod)() const,
void (Class::*setMethod)(ValueType)) : void (Class::*setMethod)(ValueType)) :
m_interface(new RefAccessor<Class, ValueType (Class::*)() const, void (Class::*)(ValueType)>(object, getMethod, setMethod)) {} m_interface(new SharedAccessor<Class, ValueType (Class::*)() const, void (Class::*)(ValueType)>(object, getMethod, setMethod)) {}
/** \param setMethod May be NULL */
template<class Class> template<class Class>
Pointer(const ReferenceCountedPointer<Class>& object, Pointer(const shared_ptr<Class>& object,
const ValueType& (Class::*getMethod)() const, const ValueType& (Class::*getMethod)() const,
void (Class::*setMethod)(ValueType)) : void (Class::*setMethod)(ValueType)) :
m_interface(new RefAccessor<Class, const ValueType& (Class::*)() const, void (Class::*)(ValueType)>(object, getMethod, setMethod)) {} m_interface(new SharedAccessor<Class, const ValueType& (Class::*)() const, void (Class::*)(ValueType)>(object, getMethod, setMethod)) {}
/** \param setMethod May be NULL */
Pointer(ValueType (*getMethod)(),
void (*setMethod)(ValueType)) :
m_interface(new FcnAccessor<ValueType (*)(), void (*)(ValueType)>(getMethod, setMethod)) {}
/** \param setMethod May be NULL */
Pointer(const ValueType& (*getMethod)(),
void (*setMethod)(ValueType)) :
m_interface(new FcnAccessor<const ValueType& (*)(), void (*)(ValueType)>(getMethod, setMethod)) {}
/** \param setMethod May be NULL */
template<class Class> template<class Class>
Pointer(const ReferenceCountedPointer<Class>& object, Pointer(const shared_ptr<Class>& object,
ValueType (Class::*getMethod)() const, ValueType (Class::*getMethod)() const,
void (Class::*setMethod)(const ValueType&)) : void (Class::*setMethod)(const ValueType&)) :
m_interface(new RefAccessor<Class, ValueType (Class::*)() const, void (Class::*)(const ValueType&)>(object, getMethod, setMethod)) {} m_interface(new SharedAccessor<Class, ValueType (Class::*)() const, void (Class::*)(const ValueType&)>(object, getMethod, setMethod)) {}
/** \param setMethod May be NULL */
template<class Class> template<class Class>
Pointer(const ReferenceCountedPointer<Class>& object, Pointer(const shared_ptr<Class>& object,
const ValueType& (Class::*getMethod)() const, const ValueType& (Class::*getMethod)() const,
void (Class::*setMethod)(const ValueType&)) : void (Class::*setMethod)(const ValueType&)) :
m_interface(new RefAccessor<Class, const ValueType& (Class::*)() const, void (Class::*)(const ValueType&)>(object, getMethod, setMethod)) {} m_interface(new SharedAccessor<Class, const ValueType& (Class::*)() const, void (Class::*)(const ValueType&)>(object, getMethod, setMethod)) {}
/** \param setMethod May be NULL */
template<class Class> template<class Class>
Pointer(Class* object, Pointer(Class* object,
const ValueType& (Class::*getMethod)() const, const ValueType& (Class::*getMethod)() const,
void (Class::*setMethod)(const ValueType&)) : void (Class::*setMethod)(const ValueType&)) :
m_interface(new Accessor<Class, const ValueType& (Class::*)() const, void (Class::*)(const ValueType&)>(object, getMethod, setMethod)) {} m_interface(new Accessor<Class, const ValueType& (Class::*)() const, void (Class::*)(const ValueType&)>(object, getMethod, setMethod)) {}
/** \param setMethod May be NULL */
template<class Class> template<class Class>
Pointer(Class* object, Pointer(Class* object,
ValueType (Class::*getMethod)() const, ValueType (Class::*getMethod)() const,
void (Class::*setMethod)(const ValueType&)) : void (Class::*setMethod)(const ValueType&)) :
m_interface(new Accessor<Class, ValueType (Class::*)() const, void (Class::*)(const ValueType&)>(object, getMethod, setMethod)) {} m_interface(new Accessor<Class, ValueType (Class::*)() const, void (Class::*)(const ValueType&)>(object, getMethod, setMethod)) {}
/** \param setMethod May be NULL */
template<class Class> template<class Class>
Pointer(Class* object, Pointer(Class* object,
const ValueType& (Class::*getMethod)() const, const ValueType& (Class::*getMethod)() const,
void (Class::*setMethod)(ValueType)) : void (Class::*setMethod)(ValueType)) :
m_interface(new Accessor<Class, const ValueType& (Class::*)() const, void (Class::*)(ValueType)>(object, getMethod, setMethod)) {} m_interface(new Accessor<Class, const ValueType& (Class::*)() const, void (Class::*)(ValueType)>(object, getMethod, setMethod)) {}
/** \param setMethod May be NULL */
template<class Class> template<class Class>
Pointer(Class* object, Pointer(Class* object,
ValueType (Class::*getMethod)() const, ValueType (Class::*getMethod)() const,
@@ -254,6 +306,8 @@ public:
return m_interface->get(); 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) { inline void setValue(const ValueType& v) {
debugAssert(m_interface != NULL); debugAssert(m_interface != NULL);
m_interface->set(v); m_interface->set(v);
@@ -287,6 +341,16 @@ public:
} }
}; };
template<class T>
bool isNull(const Pointer<T>& p) {
return p.isNull();
}
template<class T>
bool notNull(const Pointer<T>& p) {
return ! p.isNull();
}
} }
#endif #endif

View File

@@ -1,12 +1,12 @@
/** /**
@file Quat.h \file G3D/Quat.h
Quaternion Quaternion
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2002-01-23 \created 2002-01-23
@edited 2009-05-10 \edited 2011-05-10
*/ */
#ifndef G3D_Quat_h #ifndef G3D_Quat_h
@@ -21,9 +21,9 @@
namespace G3D { 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 rotation about an axis. Any 3x3 rotation matrix can
be stored as a quaternion. be stored as a quaternion.
@@ -72,6 +72,8 @@ public:
/** Expects "Quat(x,y,z,w)" or a Matrix3 constructor. */ /** Expects "Quat(x,y,z,w)" or a Matrix3 constructor. */
Quat(const class Any& a); Quat(const class Any& a);
Any toAny() const;
Quat(const Matrix3& rot); Quat(const Matrix3& rot);
Quat(float _x, float _y, float _z, float _w) : 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) { 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. The real part of the quaternion.
*/ */
@@ -206,27 +214,60 @@ public:
void toRotationMatrix( void toRotationMatrix(
Matrix3& rot) const; 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 Spherical linear interpolation: linear interpolation along the
shortest (3D) great-circle route between two quaternions. 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. Note: Correct rotations are expected between 0 and PI in the right order.
@cite Based on Game Physics -- David Eberly pg 538-540 \cite Based on Game Physics -- David Eberly pg 538-540
@param threshold Critical angle between between rotations at which
\param threshold Critical angle between between rotations (in radians) at which
the algorithm switches to normalized lerp, which is more the algorithm switches to normalized lerp, which is more
numerically stable in those situations. 0.0 will always slerp. numerically stable in those situations. 0.0 will always slerp.
*/ */
Quat slerp( Quat slerp
const Quat& other, (const Quat& other,
float alpha, float alpha,
float threshold = 0.05f) const; float threshold = 0.05f) const {
return slerp(other, alpha, threshold, finf());
}
/** 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. */ /** Normalized linear interpolation of quaternion components. */
Quat nlerp(const Quat& other, float alpha) const; Quat nlerp(const Quat& other, float alpha) const;
/** Note that q<SUP>-1</SUP> = q.conj() for a unit quaternion. /** Note that q<SUP>-1</SUP> = q.conj() for a unit quaternion.
@cite Dam99 page 13 */ @cite Dam99 page 13 */
inline Quat inverse() const { inline Quat inverse() const {
@@ -274,22 +315,6 @@ public:
return Quat(t * x, t * y, t * z, ::logf(len)); 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]. /** exp q = [sin(A) * v, cos(A)] where q = [Av, 0].
Only defined for pure-vector quaternions */ Only defined for pure-vector quaternions */
@@ -310,8 +335,8 @@ public:
Note that q.pow(a).pow(b) == q.pow(a + b) Note that q.pow(a).pow(b) == q.pow(a + b)
@cite Dam98 pg 21 @cite Dam98 pg 21
*/ */
inline Quat pow(float x) const { inline Quat pow(float r) const {
return (log() * x).exp(); return (log() * r).exp();
} }
/** Make unit length in place */ /** Make unit length in place */
@@ -324,9 +349,9 @@ public:
the magnitude. the magnitude.
*/ */
Quat toUnit() const { Quat toUnit() const {
Quat x = *this; Quat copyOfThis = *this;
x.unitize(); copyOfThis.unitize();
return x; return copyOfThis;
} }
/** /**

View File

@@ -7,8 +7,8 @@
@edited 2008-12-20 @edited 2008-12-20
*/ */
#ifndef G3D_QUEUE_H #ifndef G3D_Queue_h
#define G3D_QUEUE_H #define G3D_Queue_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/System.h" #include "G3D/System.h"
@@ -23,6 +23,8 @@ namespace G3D {
sequence without using the modulo operator. sequence without using the modulo operator.
[0 ... secondEnd) [head .... firstEnd) [0 ... secondEnd) [head .... firstEnd)
\sa ThreadsafeQueue
*/ */
#define FIND_ENDS \ #define FIND_ENDS \
int firstEnd = head + num;\ int firstEnd = head + num;\
@@ -325,6 +327,10 @@ public:
return (*this)[size() - 1]; return (*this)[size() - 1];
} }
bool empty() const {
return size() == 0;
}
/** /**
Returns true if the given element is in the queue. Returns true if the given element is in the queue.
*/ */

View File

@@ -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 \created 2009-01-02
@edited 2009-03-20 \edited 2012-07-20
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_Random_h #ifndef G3D_Random_h
@@ -33,6 +33,8 @@ namespace G3D {
On OS X, Random is about 10x faster than drand48() (which is On OS X, Random is about 10x faster than drand48() (which is
threadsafe) and 4x faster than rand() (which is not threadsafe). threadsafe) and 4x faster than rand() (which is not threadsafe).
\sa Noise
*/ */
class Random { class Random {
protected: protected:
@@ -71,6 +73,23 @@ protected:
public constructor.*/ public constructor.*/
Random(void*); 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: public:
/** \param threadsafe Set to false if you know that this random /** \param threadsafe Set to false if you know that this random
@@ -81,6 +100,8 @@ public:
virtual ~Random(); virtual ~Random();
virtual void reset(uint32 seed = 0xF018A4D2, bool threadsafe = true);
/** Each bit is random. Subclasses can choose to override just /** Each bit is random. Subclasses can choose to override just
this method and the other methods will all work automatically. */ this method and the other methods will all work automatically. */
virtual uint32 bits(); virtual uint32 bits();
@@ -109,9 +130,13 @@ public:
virtual float gaussian(float mean, float stdev); virtual float gaussian(float mean, float stdev);
/** Returns 3D unit vectors distributed according to /** 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); 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 /** Returns 3D unit vectors distributed according to a cosine
power distribution (\f$ \cos^k \theta \f$) about power distribution (\f$ \cos^k \theta \f$) about
the z-axis. */ the z-axis. */

View File

@@ -25,7 +25,7 @@ class Ray {
private: private:
friend class Intersect; friend class Intersect;
Vector3 m_origin; Point3 m_origin;
/** Unit length */ /** Unit length */
Vector3 m_direction; Vector3 m_direction;
@@ -34,40 +34,45 @@ private:
Vector3 m_invDirection; Vector3 m_invDirection;
// The following are for the "ray slope" optimization from /** The following are for the "ray slope" optimization from
// "Fast Ray / Axis-Aligned Bounding Box Overlap Tests using Ray Slopes" "Fast Ray / Axis-Aligned Bounding Box Overlap Tests using Ray Slopes"
// by Martin Eisemann, Thorsten Grosch, Stefan M<EFBFBD>ller and Marcus Magnor by Martin Eisemann, Thorsten Grosch, Stefan Müller and Marcus Magnor
// Computer Graphics Lab, TU Braunschweig, Germany and Computer Graphics Lab, TU Braunschweig, Germany and
// University of Koblenz-Landau, Germany*/ 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; 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};
// ray slope
Classification classification;
/** ray slope */
float ibyj, jbyi, kbyj, jbyk, ibyk, kbyi; float ibyj, jbyi, kbyj, jbyk, ibyk, kbyi;
// Precomputed components
/** Precomputed components */
float c_xy, c_xz, c_yx, c_yz, c_zx, c_zy; float c_xy, c_xz, c_yx, c_yz, c_zx, c_zy;
public: public:
/** \param direction Assumed to have unit length */
void set(const Point3& origin, const Vector3& direction);
void set(const Vector3& origin, const Vector3& direction); const Point3& origin() const {
inline const Vector3& origin() const {
return m_origin; return m_origin;
} }
/** Unit direction vector. */ /** Unit direction vector. */
inline const Vector3& direction() const { const Vector3& direction() const {
return m_direction; return m_direction;
} }
/** Component-wise inverse of direction vector. May have inf() components */ /** Component-wise inverse of direction vector. May have inf() components */
inline const Vector3& invDirection() const { const Vector3& invDirection() const {
return m_invDirection; return m_invDirection;
} }
inline Ray() { Ray() {
set(Vector3::zero(), Vector3::unitX()); set(Point3::zero(), Vector3::unitX());
} }
inline Ray(const Vector3& origin, const Vector3& direction) { /** \param direction Assumed to have unit length */
Ray(const Point3& origin, const Vector3& direction) {
set(origin, direction); set(origin, direction);
} }
@@ -79,24 +84,26 @@ public:
/** /**
Creates a Ray from a origin and a (nonzero) unit direction. Creates a Ray from a origin and a (nonzero) unit direction.
*/ */
static Ray fromOriginAndDirection(const Vector3& point, const Vector3& direction) { static Ray fromOriginAndDirection(const Point3& point, const Vector3& direction) {
return Ray(point, direction); return Ray(point, direction);
} }
/** Advances the origin along the direction by @a distance */ /** Returns a new ray which has the same direction but an origin
inline Ray bump(float distance) const { advanced along direction by @a distance */
Ray bumpedRay(float distance) const {
return Ray(m_origin + m_direction * distance, m_direction); return Ray(m_origin + m_direction * distance, m_direction);
} }
/** Advances the origin along the @a bumpDirection by @a distance and returns the new ray*/ /** Returns a new ray which has the same direction but an origin
inline Ray bump(float distance, const Vector3& bumpDirection) const { advanced by \a distance * \a bumpDirection */
Ray bumpedRay(float distance, const Vector3& bumpDirection) const {
return Ray(m_origin + bumpDirection * distance, m_direction); return Ray(m_origin + bumpDirection * distance, m_direction);
} }
/** /**
Returns the closest point on the Ray to point. \brief Returns the closest point on the Ray to point.
*/ */
Vector3 closestPoint(const Vector3& point) const { Point3 closestPoint(const Point3& point) const {
float t = m_direction.dot(point - m_origin); float t = m_direction.dot(point - m_origin);
if (t < 0) { if (t < 0) {
return m_origin; return m_origin;
@@ -108,7 +115,7 @@ public:
/** /**
Returns the closest distance between point and the Ray 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(); return (closestPoint(point) - point).magnitude();
} }
@@ -119,7 +126,7 @@ public:
Planes are considered one-sided, so the ray will not intersect Planes are considered one-sided, so the ray will not intersect
a plane where the normal faces in the traveling direction. 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. Returns the distance until intersection with the sphere or the (solid) ball bounded by the sphere.
@@ -151,54 +158,56 @@ public:
float intersectionTime( float intersectionTime(
const Vector3& v0, const Vector3& v1, const Vector3& v2, const Vector3& v0, const Vector3& v1, const Vector3& v2,
const Vector3& edge01, const Vector3& edge02, 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. Ray-triangle intersection for a 1-sided triangle. Fastest version.
@cite http://www.acm.org/jgt/papers/MollerTrumbore97/ @cite http://www.acm.org/jgt/papers/MollerTrumbore97/
http://www.graphics.cornell.edu/pubs/1997/MT97.html http://www.graphics.cornell.edu/pubs/1997/MT97.html
*/ */
inline float intersectionTime( float intersectionTime(
const Vector3& vert0, const Point3& vert0,
const Vector3& vert1, const Point3& vert1,
const Vector3& vert2, const Point3& vert2,
const Vector3& edge01, const Vector3& edge01,
const Vector3& edge02) const; const Vector3& edge02) const;
inline float intersectionTime( float intersectionTime(
const Vector3& vert0, const Point3& vert0,
const Vector3& vert1, const Point3& vert1,
const Vector3& vert2) const { const Point3& vert2) const {
return intersectionTime(vert0, vert1, vert2, vert1 - vert0, vert2 - vert0); return intersectionTime(vert0, vert1, vert2, vert1 - vert0, vert2 - vert0);
} }
inline float intersectionTime( float intersectionTime(
const Vector3& vert0, const Point3& vert0,
const Vector3& vert1, const Point3& vert1,
const Vector3& vert2, const Point3& vert2,
double& w0, float& w0,
double& w1, float& w1,
double& w2) const { float& w2) const {
return intersectionTime(vert0, vert1, vert2, vert1 - vert0, vert2 - vert0, w0, w1, w2); return intersectionTime(vert0, vert1, vert2, vert1 - vert0, vert2 - vert0, w0, w1, w2);
} }
/* One-sided triangle /* One-sided triangle
*/ */
inline float intersectionTime(const Triangle& triangle) const { float intersectionTime(const Triangle& triangle) const {
return intersectionTime( return intersectionTime(
triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), triangle.vertex(0), triangle.vertex(1), triangle.vertex(2),
triangle.edge01(), triangle.edge02()); triangle.edge01(), triangle.edge02());
} }
inline float intersectionTime(
const Triangle& triangle, float intersectionTime
double& w0, (const Triangle& triangle,
double& w1, float& w0,
double& w2) const { float& w1,
float& w2) const {
return intersectionTime(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), return intersectionTime(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2),
triangle.edge01(), triangle.edge02(), w0, w1, w2); triangle.edge01(), triangle.edge02(), w0, w1, w2);
} }
@@ -236,9 +245,9 @@ public:
dest[2]=v1[2]-v2[2]; dest[2]=v1[2]-v2[2];
inline float Ray::intersectionTime( inline float Ray::intersectionTime(
const Vector3& vert0, const Point3& vert0,
const Vector3& vert1, const Point3& vert1,
const Vector3& vert2, const Point3& vert2,
const Vector3& edge1, const Vector3& edge1,
const Vector3& edge2) const { const Vector3& edge2) const {
@@ -294,15 +303,15 @@ inline float Ray::intersectionTime(
} }
inline float Ray::intersectionTime( inline float Ray::intersectionTime
const Vector3& vert0, (const Point3& vert0,
const Vector3& vert1, const Point3& vert1,
const Vector3& vert2, const Point3& vert2,
const Vector3& edge1, const Vector3& edge1,
const Vector3& edge2, const Vector3& edge2,
double& w0, float& w0,
double& w1, float& w1,
double& w2) const { float& w2) const {
(void)vert1; (void)vert1;
(void)vert2; (void)vert2;

View File

@@ -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 2003-11-13
@created 2009-11-16 \created 2011-06-16
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -39,7 +39,7 @@ class Any;
*/ */
class Rect2D { class Rect2D {
private: private:
Vector2 min, max; Point2 min, max;
/** /**
Returns true if the whole polygon is clipped. Returns true if the whole polygon is clipped.
@@ -117,39 +117,61 @@ private:
return false; return false;
} }
/** Uninitialized constructor */
Rect2D(bool /*b*/) {}
public: public:
/** \param any Must either Rect2D::xywh(#, #, #, #) or Rect2D::xyxy(#, #, #, #)*/ /** \param any Must either Rect2D::xywh(#, #, #, #) or Rect2D::xyxy(#, #, #, #)*/
Rect2D(const Any& any); Rect2D(const Any& any);
/** Converts the Rect2D to an 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*/ /** Creates a rectangle at 0,0 with the given width and height*/
Rect2D(const Vector2& wh) : min(0, 0), max(wh.x, wh.y) {} Rect2D(const Vector2& wh) : min(0, 0), max(wh.x, wh.y) {}
/** Computes a rectangle that contains both @a a and @a b. Vector2 extent() const {
Note that even if @a or @b has zero area, its origin will be included.*/ if (isEmpty()) {
Rect2D(const Rect2D& a, const Rect2D& b) { return Vector2::zero();
min = a.min.min(b.min); } else {
max = a.max.max(b.max); return max - min;
}
} }
/** @brief Uniformly random point on the interior */ /** @brief Uniformly random point on the interior */
Vector2 randomPoint() const { Point2 randomPoint() const {
return Vector2(uniformRandom(0, max.x - min.x) + min.x, return Point2(uniformRandom(0, max.x - min.x) + min.x,
uniformRandom(0, max.y - min.y) + min.y); uniformRandom(0, max.y - min.y) + min.y);
} }
float width() const { float width() const {
if (isEmpty()) {
return 0;
} else {
return max.x - min.x; return max.x - min.x;
} }
}
float height() const { float height() const {
if (isEmpty()) {
return 0;
} else {
return max.y - min.y; return max.y - min.y;
} }
}
float x0() const { float x0() const {
return min.x; return min.x;
@@ -168,29 +190,33 @@ public:
} }
/** Min, min corner */ /** Min, min corner */
Vector2 x0y0() const { Point2 x0y0() const {
return min; return min;
} }
Vector2 x1y0() const { Point2 x1y0() const {
return Vector2(max.x, min.y); return Point2(max.x, min.y);
} }
Vector2 x0y1() const { Point2 x0y1() const {
return Vector2(min.x, max.y); return Point2(min.x, max.y);
} }
/** Max,max corner */ /** Max,max corner */
Vector2 x1y1() const { Point2 x1y1() const {
return max; return max;
} }
/** Width and height */ /** Width and height */
Vector2 wh() const { Vector2 wh() const {
if (isEmpty()) {
return Vector2::zero();
} else {
return max - min; return max - min;
} }
}
Vector2 center() const { Point2 center() const {
return (max + min) * 0.5; return (max + min) * 0.5;
} }
@@ -203,7 +229,7 @@ public:
} }
Rect2D lerp(const Rect2D& other, float alpha) const { Rect2D lerp(const Rect2D& other, float alpha) const {
Rect2D out; Rect2D out(false);
out.min = min.lerp(other.min, alpha); out.min = min.lerp(other.min, alpha);
out.max = max.lerp(other.max, alpha); out.max = max.lerp(other.max, alpha);
@@ -212,7 +238,7 @@ public:
} }
static Rect2D xyxy(float x0, float y0, float x1, float y1) { 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.x = G3D::min(x0, x1);
r.min.y = G3D::min(y0, y1); r.min.y = G3D::min(y0, y1);
@@ -222,8 +248,8 @@ public:
return r; return r;
} }
static Rect2D xyxy(const Vector2& v0, const Vector2& v1) { static Rect2D xyxy(const Point2& v0, const Point2& v1) {
Rect2D r; Rect2D r(false);
r.min = v0.min(v1); r.min = v0.min(v1);
r.max = v0.max(v1); r.max = v0.max(v1);
@@ -235,7 +261,7 @@ public:
return xyxy(x, y, x + w, y + h); 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); 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()); 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); return (v.x >= min.x) && (v.y >= min.y) && (v.x <= max.x) && (v.y <= max.y);
} }
bool contains(const Rect2D& r) const { bool contains(const Rect2D& r) const {
// This will automatically return false if isEmpty()
return (min.x <= r.min.x) && (min.y <= r.min.y) && return (min.x <= r.min.x) && (min.y <= r.min.y) &&
(max.x >= r.max.x) && (max.y >= r.max.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 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.*/ zero area to the overlap, even though one of them "contains" the corners of the other.*/
bool intersects(const Rect2D& r) const { bool intersects(const Rect2D& r) const {
// This will automatically return false if isEmpty()
return (min.x < r.max.x) && (min.y < r.max.y) && return (min.x < r.max.x) && (min.y < r.max.y) &&
(max.x > r.min.x) && (max.y > r.min.y); (max.x > r.min.x) && (max.y > r.min.y);
} }
/** Like intersection, but counts the adjacent case as touching. */ /** Like intersection, but counts the adjacent case as touching. */
bool intersectsOrTouches(const Rect2D& r) const { bool intersectsOrTouches(const Rect2D& r) const {
// This will automatically return false if isEmpty()
return (min.x <= r.max.x) && (min.y <= r.max.y) && return (min.x <= r.max.x) && (min.y <= r.max.y) &&
(max.x >= r.min.x) && (max.y >= r.min.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); 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 { Rect2D operator/(float s) const {
return xyxy(min / s, max / s); return xyxy(min / s, max / s);
} }
@@ -297,21 +331,25 @@ public:
return (min != other.min) || (max != other.max); 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). */ /** 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); debugAssert(i >= 0 && i < 4);
switch (i & 3) { switch (i & 3) {
case 0: case 0:
return Vector2(min.x, min.y); return Point2(min.x, min.y);
case 1: case 1:
return Vector2(max.x, min.y); return Point2(max.x, min.y);
case 2: case 2:
return Vector2(max.x, max.y); return Point2(max.x, max.y);
case 3: case 3:
return Vector2(min.x, max.y); return Point2(min.x, max.y);
default: default:
// Should never get here // Should never get here
return Vector2(0, 0); return Point2(0, 0);
} }
} }
@@ -345,6 +383,22 @@ public:
return Rect2D::xywh(newX, newY, newW, newH); 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 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. 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 Returns the overlap region between the two rectangles. This may
if they do not intersect. See the two-Rect2D constructor for a way to compute have zero area if they do not intersect. See the two-Rect2D
a union-like rectangle. constructor and merge() for a way to compute a union-like
rectangle.
*/ */
Rect2D intersect(const Rect2D& other) const { Rect2D intersect(const Rect2D& other) const {
if (intersects(other)) { if (intersects(other)) {
return Rect2D::xyxy(min.max(other.min), max.min(other.max)); return Rect2D::xyxy(min.max(other.min), max.min(other.max));
} else { } else {
return Rect2D::xywh(0, 0, 0, 0); return empty();
} }
} }
}; };

View File

@@ -1,14 +1,12 @@
/** /**
@file ReferenceCount.h \file G3D/ReferenceCount.h
Reference Counting Garbage Collector for C++ Reference Counting Garbage Collector for C++
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@cite Adapted and extended from Justin Miller's "RGC" class that appeared in BYTE magazine.
@cite See also http://www.jelovic.com/articles/cpp_without_memory_errors_slides.htm
@created 2001-10-23 \created 2001-10-23
@edited 2009-04-25 \edited 2013-01-05
*/ */
#ifndef G3D_ReferenceCount_h #ifndef G3D_ReferenceCount_h
#define G3D_ReferenceCount_h #define G3D_ReferenceCount_h
@@ -17,553 +15,41 @@
#include "G3D/debug.h" #include "G3D/debug.h"
#include "G3D/AtomicInt32.h" #include "G3D/AtomicInt32.h"
#define USE_SHARED_PTR
#define ReferenceCountedPointer shared_ptr
#define WeakReferenceCountedPointer weak_ptr
namespace G3D { namespace G3D {
#ifdef _MSC_VER class ReferenceCountedObject : public enable_shared_from_this<ReferenceCountedObject> {
// 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 {
public: public:
inline virtual ~_WeakPtr() {} virtual ~ReferenceCountedObject() {};
protected:
friend class ReferenceCountedObject;
/** Called by ReferenceCountedObject to tell a weak pointer that its underlying object was collected. */
virtual void objectCollected() = 0;
}; };
/** Used internally by ReferenceCountedObject */ } // namespace
class _WeakPtrLinkedList {
public:
_WeakPtr* weakPtr;
_WeakPtrLinkedList* next;
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
<B>must</B> have a public destructor (the default destructor is fine)
and <B>publicly</B> 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 <i>not</i>
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.)
<B>Usage Example</B>
<PRE>
class Foo : public G3D::ReferenceCountedObject {
public:
int x;
};
class Bar : public Foo {};
typedef G3D::ReferenceCountedPointer<Foo> FooRef;
typedef G3D::WeakReferenceCountedPointer<Foo> WeakFooRef;
typedef G3D::ReferenceCountedPointer<Bar> 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<Bar*>(&*f);
return 0;
}
</PRE>
*/
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;
protected:
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<T> in place of T* in your program.
T must subclass ReferenceCountedObject.
@deprecated To be replaced by boost::shared_ptr in 7.0
*/
template<class T> template<class T>
class ReferenceCountedPointer { bool isNull(const ReferenceCountedPointer<T>& ptr) {
private: return ! ptr;
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 <i>to</i> the base class.
<pre>
SubRef s = new Sub();
BaseRef b = s;
</pre>
i.e., compile-time subtyping rule
RCP&lt;<I>T</I>&gt; &lt;: RCP&lt;<I>S</I>&gt; if <I>T</I> &lt;: <I>S</I>
*/
template <class S>
inline ReferenceCountedPointer(const ReferenceCountedPointer<S>& 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.
<pre>
SubRef s = new Sub();
BaseRef b = s;
s = b.downcast<Sub>(); // Note that the template argument is the object type, not the pointer type.
</pre>
*/
template <class S>
ReferenceCountedPointer<S> downcast() {
return ReferenceCountedPointer<S>(dynamic_cast<S*>(m_pointer));
}
template <class S>
const ReferenceCountedPointer<S> downcast() const {
return ReferenceCountedPointer<S>(dynamic_cast<const S*>(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<T>& 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<T*>(p));
}
inline ~ReferenceCountedPointer() {
zeroPointer();
}
inline size_t hashCode() const {
return reinterpret_cast<size_t>(m_pointer);;
}
inline const ReferenceCountedPointer<T>& operator=(const ReferenceCountedPointer<T>& p) {
setPointer(p.m_pointer);
return *this;
}
inline ReferenceCountedPointer<T>& operator=(T* p) {
setPointer(p);
return *this;
}
inline bool operator==(const ReferenceCountedPointer<T>& y) const {
return (m_pointer == y.m_pointer);
}
inline bool operator!=(const ReferenceCountedPointer<T>& y) const {
return (m_pointer != y.m_pointer);
}
bool operator < (const ReferenceCountedPointer<T>& y) const {
return (m_pointer < y.m_pointer);
}
bool operator > (const ReferenceCountedPointer<T>& y) const {
return (m_pointer > y.m_pointer);
}
bool operator <= (const ReferenceCountedPointer<T>& y) const {
return (m_pointer <= y.m_pointer);
}
bool operator >= (const ReferenceCountedPointer<T>& 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.
<b>Not threadsafe.</b>
@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 <B>outside</B> 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 T> template<class T>
class WeakReferenceCountedPointer : public _WeakPtr { bool notNull(const ReferenceCountedPointer<T>& ptr) {
private: return (bool)ptr;
/** 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<T> createStrongPtr() const {
// TODO: What if the object's destructor is called while we
// are in this method?
return ReferenceCountedPointer<T>(pointer);
} }
private: template<class T>
bool isNull(const T* ptr) {
/** Thread issues: safe because this is only called when another return ptr == NULL;
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 {
}
} }
template<class T>
/** bool notNull(const T* ptr) {
Removes this from its target's list of weak pointers. Called return ptr != NULL;
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<T> 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&lt;<I>T</I>&gt; &lt;: RCP&lt;<I>S</I>&gt; if <I>T</I> &lt;: <I>S</I>
*/
template <class S>
inline WeakReferenceCountedPointer(const WeakReferenceCountedPointer<S>& p) : pointer(0) {
// Threadsafe: the object cannot be collected while the other pointer exists.
setPointer(p.pointer);
}
template <class S>
inline WeakReferenceCountedPointer(const ReferenceCountedPointer<S>& 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<T>& weakPtr) : pointer(0) {
setPointer(weakPtr.pointer);
}
WeakReferenceCountedPointer(
const ReferenceCountedPointer<T>& strongPtr) : pointer(0) {
setPointer(strongPtr.pointer());
}
~WeakReferenceCountedPointer() {
zeroPointer();
}
WeakReferenceCountedPointer<T>& operator=(const WeakReferenceCountedPointer<T>& 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<T>& operator=(const ReferenceCountedPointer<T>& 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<T>& other) const {
return pointer == other.pointer;
}
bool operator!=(const WeakReferenceCountedPointer<T>& other) const {
return pointer != other.pointer;
}
bool operator < (const WeakReferenceCountedPointer<T>& y) const {
return (pointer < y.pointer);
}
bool operator > (const WeakReferenceCountedPointer<T>& y) const {
return (pointer > y.pointer);
}
bool operator <= (const WeakReferenceCountedPointer<T>& y) const {
return (pointer <= y.pointer);
}
bool operator >= (const ReferenceCountedPointer<T>& 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;
}
};
} // namespace } // namespace
#endif #endif

View File

@@ -15,7 +15,7 @@
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
// This file is only used on Windows // This file is only used on Windows
#ifdef G3D_WIN32 #ifdef G3D_WINDOWS
#include <string> #include <string>
@@ -92,6 +92,6 @@ public:
} // namespace G3D } // namespace G3D
#endif // G3D_WIN32 #endif // G3D_WINDOWS
#endif // G3D_REGISTRYTUIL_H #endif // G3D_REGISTRYTUIL_H

View File

@@ -125,8 +125,13 @@ public:
return !(*this == other); return !(*this == other);
} }
bool isValid() const {
return it.isValid();
}
/** @deprecated Use isValid */
bool hasMore() const { bool hasMore() const {
return it.hasMore(); return it.isValid();
} }
bool operator==(const Iterator& other) const { bool operator==(const Iterator& other) const {

View File

@@ -1,10 +1,10 @@
/** /**
@file SmallArray.h \file G3D/SmallArray.h
@created 2009-04-26 \created 2009-04-26
@edited 2010-02-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. All rights reserved.
*/ */
#ifndef G3D_SmallArray_h #ifndef G3D_SmallArray_h
@@ -83,6 +83,35 @@ public:
push(v); 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) { void fastRemove(int i, bool shrinkIfNecessary = false) {
debugAssert(i < m_size && i >= 0); debugAssert(i < m_size && i >= 0);
if (i < N) { if (i < N) {
@@ -139,8 +168,8 @@ public:
return m_rest.contains(value); return m_rest.contains(value);
} }
template<int MIN_ELEMENTS, int MIN_BYTES> template<int MIN_ELEMENTS>
SmallArray<T, N>& operator=(const Array<T, MIN_ELEMENTS, MIN_BYTES>& src) { SmallArray<T, N>& operator=(const Array<T, MIN_ELEMENTS>& src) {
resize(src.size()); resize(src.size());
for (int i = 0; i < src.size(); ++i) { for (int i = 0; i < src.size(); ++i) {
(*this)[i] = src[i]; (*this)[i] = src[i];

View File

@@ -0,0 +1,6 @@
#ifndef SpawnBehavior_h
#define SpawnBehavior_h
namespace G3D {
enum SpawnBehavior {USE_NEW_THREAD, USE_CURRENT_THREAD};
}
#endif

View File

@@ -1,16 +1,16 @@
/** /**
@file Sphere.h \file G3D/Sphere.h
Sphere class Sphere class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-06-02 \created 2001-06-02
@edited 2008-10-07 \edited 2011-02-07
*/ */
#ifndef G3D_SPHERE_H #ifndef G3D_Sphere_h
#define G3D_SPHERE_H #define G3D_Sphere_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Vector3.h" #include "G3D/Vector3.h"
@@ -27,28 +27,36 @@ private:
static int32 dummy; static int32 dummy;
public: public:
Vector3 center; Point3 center;
float radius; float radius;
Sphere() { Sphere() : center(Point3::zero()), radius(0) {
center = Vector3::zero();
radius = 0;
} }
explicit Sphere(float radius) : radius(radius) {}
Sphere(class BinaryInput& b); Sphere(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);
Sphere( /** Format is one of:
const Vector3& center, - Sphere(point, radius)
float radius) { - Sphere(radius)
*/
explicit Sphere(const class Any& a);
this->center = center; Any toAny() const;
this->radius = radius;
Sphere
(const Point3& center,
float radius) : center(center), radius(radius) {
} }
virtual ~Sphere() {} virtual ~Sphere() {}
/** Returns the infinite sphere. */
static const Sphere& inf();
bool operator==(const Sphere& other) const { bool operator==(const Sphere& other) const {
return (center == other.center) && (radius == other.radius); 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 Returns true if point is less than or equal to radius away from
the center. the center.
*/ */
bool contains(const Vector3& point) const; bool contains(const Point3& point) const;
bool contains(const Sphere& other) const; bool contains(const Sphere& other) const;
@@ -110,12 +118,12 @@ public:
/** /**
Uniformly distributed on the surface. Uniformly distributed on the surface.
*/ */
Vector3 randomSurfacePoint() const; Point3 randomSurfacePoint() const;
/** /**
Uniformly distributed on the interior (includes surface) Uniformly distributed on the interior (includes surface)
*/ */
Vector3 randomInteriorPoint() const; Point3 randomInteriorPoint() const;
void getBounds(class AABox& out) const; void getBounds(class AABox& out) const;

View File

@@ -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 #ifndef G3D_Spline_h
#define G3D_SPLINE_H #define G3D_Spline_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Array.h" #include "G3D/Array.h"
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
#include "G3D/Matrix4.h" #include "G3D/Matrix4.h"
#include "G3D/Vector4.h" #include "G3D/Vector4.h"
#include "G3D/Any.h"
#include "G3D/SplineExtrapolationMode.h"
namespace G3D { namespace G3D {
@@ -23,10 +25,12 @@ public:
number of elements as Spline::control. */ number of elements as Spline::control. */
Array<float> time; Array<float> time;
/** If cyclic, then the control points will be assumed to wrap around. /** If CYCLIC, then the control points will be assumed to wrap around.
If not cyclic, then the tangents at the ends of the spline If LINEAR, then the tangents at the ends of the spline
point to the final control points.*/ point to the final control points. If CONSTANT, the end control
bool cyclic; 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 /** 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 control point and the first. If less than or equal to zero this is
@@ -37,7 +41,12 @@ public:
*/ */
float finalInterval; float finalInterval;
SplineBase() : cyclic(true), finalInterval(-1) {} SplineInterpolationMode interpolationMode;
SplineBase() :
extrapolationMode(SplineExtrapolationMode::CYCLIC),
finalInterval(-1),
interpolationMode(SplineInterpolationMode::CUBIC) {}
virtual ~SplineBase() {} virtual ~SplineBase() {}
@@ -144,11 +153,7 @@ public:
break; break;
case 1: case 1:
if (time[0] == 0) { append(time[0] + 1, c);
append(1, c);
} else {
append(time[0], c);
}
break; break;
default: default:
@@ -192,7 +197,7 @@ public:
if (N == 0) { if (N == 0) {
c = zero; c = zero;
t = 0; t = 0;
} else if (cyclic) { } else if (extrapolationMode == SplineExtrapolationMode::CYCLIC) {
c = control[iWrap(i, N)]; c = control[iWrap(i, N)];
if (i < 0) { if (i < 0) {
@@ -222,9 +227,16 @@ public:
// Step away from control point 0 // Step away from control point 0
float dt = time[1] - time[0]; float dt = time[1] - time[0];
if (extrapolationMode == SplineExtrapolationMode::LINEAR) {
// Extrapolate (note; i is negative) // Extrapolate (note; i is negative)
c = control[1] * float(i) + control[0] * float(1 - i); c = control[1] * float(i) + control[0] * float(1 - i);
correct(c); 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]; t = dt * i + time[0];
} else { } else {
@@ -239,9 +251,17 @@ public:
if (N >= 2) { if (N >= 2) {
float dt = time[N - 1] - time[N - 2]; float dt = time[N - 1] - time[N - 2];
// Extrapolate if (extrapolationMode == SplineExtrapolationMode::LINEAR) {
// Extrapolate (note; i is negative)
c = control[N - 1] * float(i - N + 2) + control[N - 2] * -float(i - N + 1); c = control[N - 1] * float(i - N + 2) + control[N - 2] * -float(i - N + 1);
correct(c); correct(c);
} else if (extrapolationMode == SplineExtrapolationMode::CLAMP){
// Return the last, clamping
c = control.last();
} else {
alwaysAssertM(false, "Invalid extrapolation mode");
}
// Extrapolate
t = time[N - 1] + dt * (i - N + 1); t = time[N - 1] + dt * (i - N + 1);
} else { } else {
@@ -279,8 +299,47 @@ protected:
/** Normalize or otherwise adjust this interpolated Control. */ /** Normalize or otherwise adjust this interpolated Control. */
virtual void correct(Control& A) const { (void)A; } 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: 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 Return the position at time s. The spline is defined outside
@@ -313,6 +372,22 @@ public:
Control p[4]; Control p[4];
float t[4]; float t[4];
getControls(i - 1, t, p, 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 dt0 = t[1] - t[0];
float dt1 = t[2] - t[1]; float dt1 = t[2] - t[1];
float dt2 = t[3] - t[2]; float dt2 = t[3] - t[2];
@@ -325,13 +400,6 @@ public:
// Compute the weights on each of the control points. // Compute the weights on each of the control points.
const Vector4& weights = uvec * basis; 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 // The factor of 1/2 from averaging two time intervals is
// already factored into the basis // already factored into the basis

View File

@@ -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., <code>SplineExtrapolationMode m = SplineExtrapolationMode::CLAMP;</code>.
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

View File

@@ -46,6 +46,9 @@ class Stopwatch {
private: private:
std::string myName; std::string myName;
bool m_enabled;
double startTime; double startTime;
std::string prevMark; std::string prevMark;
double prevTime; double prevTime;
@@ -85,6 +88,15 @@ public:
Stopwatch(const std::string& name = "Stopwatch"); 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; /** Returns the number of times that tick was called per wall-clock second;
e.g. frames-per-second. */ e.g. frames-per-second. */
double FPS() const { double FPS() const {
@@ -130,7 +142,10 @@ public:
void reset(); void reset();
/** Call after an operation has completed, with the name of the operation, to /** 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 = ""); void after(const std::string& s = "");
}; };

View File

@@ -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 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 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 Michael Herf http://www.stereopsis.com/memcpy.html
@created 2003-01-25 \created 2003-01-25
@edited 2008-10-14 \edited 2012-10-02
*/ */
#ifndef G3D_System_h #ifndef G3D_System_h
@@ -18,28 +18,20 @@
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
#include "G3D/G3DGameUnits.h" #include "G3D/G3DGameUnits.h"
#include "G3D/BinaryFormat.h" #include "G3D/BinaryFormat.h"
#include "G3D/FileNotFound.h"
#include <string> #include <string>
#ifdef G3D_LINUX
# include <sys/socket.h> #if defined(__aarch64__)
#include <sys/time.h>
#endif #endif
#ifdef G3D_OSX #ifdef G3D_OSX
#define Zone OSX_Zone
# include <CoreServices/CoreServices.h> # include <CoreServices/CoreServices.h>
#endif #endif
namespace G3D { 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-<version>\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 /** G3D, SDL, and IJG libraries require license documentation
to be distributed with your program. This generates the to be distributed with your program. This generates the
string that must appear in your documentation. string that must appear in your documentation.
@@ -118,7 +110,7 @@ private:
std::string m_cpuArch; std::string m_cpuArch;
std::string m_operatingSystem; std::string m_operatingSystem;
# ifdef G3D_WIN32 # ifdef G3D_WINDOWS
/** Used by getTick() for timing */ /** Used by getTick() for timing */
LARGE_INTEGER m_start; LARGE_INTEGER m_start;
LARGE_INTEGER m_counterFrequency; LARGE_INTEGER m_counterFrequency;
@@ -167,7 +159,6 @@ private:
*/ */
static void cpuid(CPUIDFunction func, uint32& areg, uint32& breg, uint32& creg, uint32& dreg); static void cpuid(CPUIDFunction func, uint32& areg, uint32& breg, uint32& creg, uint32& dreg);
void init();
/** Called from init() */ /** Called from init() */
void getStandardProcessorExtensions(); void getStandardProcessorExtensions();
@@ -175,8 +166,13 @@ private:
/** Called from init() */ /** Called from init() */
void initTime(); void initTime();
void init();
public: public:
/** atexit handling code invoked from G3DCleanupHook. */
static void cleanup();
/** Returns the speed of processor 0 in MHz. /** Returns the speed of processor 0 in MHz.
Always returns 0 on linux.*/ Always returns 0 on linux.*/
inline static int cpuSpeedMHz() { inline static int cpuSpeedMHz() {
@@ -243,16 +239,13 @@ public:
*/ */
static std::string currentDateString(); static std::string currentDateString();
/** /** Returns the current 24-hour local time as a string in the form HH:MM:SS */
Guarantees that the start of the array is aligned to the static std::string currentTimeString();
specified number of bytes.
*/
static void* alignedMalloc(size_t bytes, size_t alignment);
/** /**
Uses pooled storage to optimize small allocations (1 byte to 5 Uses pooled storage to optimize small allocations (1 byte to 5
kilobytes). Can be 10x to 100x faster than calling ::malloc or kilobytes). Can be 10x to 100x faster than calling \c malloc or
new. \c new.
The result must be freed with free. The result must be freed with free.
@@ -288,6 +281,12 @@ public:
*/ */
static void free(void* p); 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. Frees memory allocated with alignedMalloc.
*/ */
@@ -370,6 +369,7 @@ public:
/** /**
To count the number of cycles a given operation takes: To count the number of cycles a given operation takes:
\htmlonly
<PRE> <PRE>
unsigned long count; unsigned long count;
System::beginCycleCount(count); System::beginCycleCount(count);
@@ -377,11 +377,12 @@ public:
System::endCycleCount(count); System::endCycleCount(count);
// count now contains the cycle count for the intervening operation. // count now contains the cycle count for the intervening operation.
</PRE> </PRE>
\endhtmlonly
*/ */
/* static void beginCycleCount(uint64& cycleCount); static void beginCycleCount(uint64& cycleCount);
static void endCycleCount(uint64& cycleCount); static void endCycleCount(uint64& cycleCount);
static uint64 getCycleCount(); */ static uint64 getCycleCount();
inline static void setOutOfMemoryCallback(OutOfMemoryCallback c) { inline static void setOutOfMemoryCallback(OutOfMemoryCallback c) {
instance().m_outOfMemoryCallback = c; instance().m_outOfMemoryCallback = c;
@@ -412,25 +413,53 @@ public:
Prints a human-readable description of this machine Prints a human-readable description of this machine
to the text output stream. Either argument may be NULL. to the text output stream. Either argument may be NULL.
*/ */
static void describeSystem( static void describeSystem
class TextOutput& t); (class TextOutput& t);
static void describeSystem( static void describeSystem
std::string& s); (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);
/** /**
Tries to locate the resource by looking in related directories. Tries to locate the resource by looking in related directories.
If found, returns the full path to the resource, otherwise If found, returns the full path to the resource, otherwise
returns the empty string. 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. Sets the path that the application is using as its data directory.
@@ -441,8 +470,10 @@ public:
}; };
/* don't need that for Moongose, not portable to Win64...
#ifdef _MSC_VER #ifdef _MSC_VER
# ifdef _M_IX86
// 32-bit
inline uint64 System::getCycleCount() { inline uint64 System::getCycleCount() {
uint32 timehi, timelo; uint32 timehi, timelo;
@@ -457,10 +488,40 @@ public:
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) #elif defined(G3D_LINUX)
inline uint64 System::getCycleCount() { inline uint64 System::getCycleCount() {
# 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<uint64>(pmccntr) * 64; // Should optimize to << 6
}
}
# endif
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<uint64>(tv.tv_sec) * 1000000 + tv.tv_usec;
# else
uint32 timehi, timelo; uint32 timehi, timelo;
__asm__ __volatile__ ( __asm__ __volatile__ (
@@ -470,6 +531,7 @@ public:
: ); : );
return ((uint64)timehi << 32) + (uint64)timelo; return ((uint64)timehi << 32) + (uint64)timelo;
# endif
} }
#elif defined(G3D_OSX) #elif defined(G3D_OSX)
@@ -503,8 +565,13 @@ inline void System::endCycleCount(uint64& cycleCount) {
(double) UnsignedWideToUInt64(diffNS) * instance().m_secondsPerNS); (double) UnsignedWideToUInt64(diffNS) * instance().m_secondsPerNS);
#endif #endif
} }
*/
} // namespace } // namespace
#ifdef G3D_OSX
#undef Zone
#endif
#endif #endif

View File

@@ -5,8 +5,8 @@
@maintainer Morgan McGuire, http://graphics.cs.williams.edu @maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-04-22 @created 2001-04-22
@edited 2010-01-28 @edited 2013-01-22
Copyright 2000-2010, Morgan McGuire. Copyright 2000-2013, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -90,7 +90,8 @@ namespace G3D {
}; };
</PRE> </PRE>
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 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 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 // Private to require use of the allocator
Node(const Key& k, const Value& v, size_t h, Node* n) Node(const Key& k, const Value& v, size_t h, Node* n)
: entry(k, v), hashCode(h), next(n) { : entry(k, v), hashCode(h), next(n) {
debugAssert((next == NULL) || isValidHeapPointer(next));
} }
Node(const Key& k, size_t h, Node* n) Node(const Key& k, size_t h, Node* n)
: entry(k), hashCode(h), next(n) { : entry(k), hashCode(h), next(n) {
debugAssert((next == NULL) || isValidHeapPointer(next));
} }
public: public:
@@ -213,9 +216,9 @@ private:
// Allocate a new m_bucket array with the new size // Allocate a new m_bucket array with the new size
m_bucket = (Node**)alloc(sizeof(Node*) * newSize); m_bucket = (Node**)alloc(sizeof(Node*) * newSize);
alwaysAssertM(m_bucket != NULL, "MemoryManager::alloc returned NULL. Out of memory.");
// Set all pointers to NULL // Set all pointers to NULL
System::memset(m_bucket, 0, newSize * sizeof(Node*)); 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 // Move each node to its new hash location
for (size_t b = 0; b < m_numBuckets; ++b) { for (size_t b = 0; b < m_numBuckets; ++b) {
Node* node = oldBucket[b]; Node* node = oldBucket[b];
@@ -274,7 +277,7 @@ private:
void freeMemory() { void freeMemory() {
checkIntegrity(); checkIntegrity();
for (size_t b = 0; b < m_numBuckets; b++) { for (size_t b = 0; b < m_numBuckets; ++b) {
Node* node = m_bucket[b]; Node* node = m_bucket[b];
while (node != NULL) { while (node != NULL) {
Node* next = node->next; Node* next = node->next;
@@ -357,7 +360,7 @@ public:
size_t debugGetDeepestBucketSize() const { size_t debugGetDeepestBucketSize() const {
size_t deepest = 0; 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; size_t count = 0;
Node* node = m_bucket[b]; Node* node = m_bucket[b];
while (node != NULL) { while (node != NULL) {
@@ -377,21 +380,16 @@ public:
Returns the average size of non-empty buckets. Returns the average size of non-empty buckets.
*/ */
float debugGetAverageBucketSize() const { float debugGetAverageBucketSize() const {
size_t num = 0; uint64 num = 0;
size_t count = 0;
for (size_t b = 0; b < m_numBuckets; b++) { for (size_t b = 0; b < m_numBuckets; ++b) {
Node* node = m_bucket[b]; Node* node = m_bucket[b];
if (node != NULL) { if (node != NULL) {
++num; ++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. many keys to the same code.
*/ */
double debugGetLoad() const { double debugGetLoad() const {
return debugGetDeepestBucketSize() / (double)size(); return (double)size() / m_numBuckets;
} }
/** /**
@@ -428,7 +426,7 @@ public:
Linked list node. Linked list node.
*/ */
Node* node; Node* node;
ThisType* table;
size_t m_numBuckets; size_t m_numBuckets;
Node** m_bucket; Node** m_bucket;
bool isDone; bool isDone;
@@ -436,13 +434,14 @@ public:
/** /**
Creates the end iterator. Creates the end iterator.
*/ */
Iterator(const ThisType* table) : table(const_cast<ThisType*>(table)) { Iterator() : index(0), node(NULL), m_bucket(NULL) {
isDone = true; isDone = true;
} }
Iterator(const ThisType* table, size_t m_numBuckets, Node** m_bucket) : Iterator(size_t numBuckets, Node** m_bucket) :
table(const_cast<ThisType*>(table)), index(0),
m_numBuckets(m_numBuckets), node(NULL),
m_numBuckets(numBuckets),
m_bucket(m_bucket) { m_bucket(m_bucket) {
if (m_numBuckets == 0) { if (m_numBuckets == 0) {
@@ -451,26 +450,38 @@ public:
return; 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; index = 0;
node = m_bucket[index]; node = m_bucket[index];
debugAssert((node == NULL) || isValidHeapPointer(node));
isDone = false; isDone = false;
findNext(); findNext();
debugAssert((node == NULL) || isValidHeapPointer(node));
} }
/** /**
Finds the next element, setting isDone if one can't be found. If node is NULL, then finds the next element by searching through the bucket array.
Looks at the current element first. Sets isDone if no more nodes are available.
*/ */
void findNext() { void findNext() {
while (node == NULL) { while (node == NULL) {
index++; ++index;
if (index >= m_numBuckets) { if (index >= m_numBuckets) {
m_bucket = NULL;
index = 0;
isDone = true; isDone = true;
break; return;
} else { } else {
node = m_bucket[index]; node = m_bucket[index];
debugAssert((node == NULL) || isValidHeapPointer(node));
} }
} }
debugAssert(isValidHeapPointer(node));
} }
public: public:
@@ -481,12 +492,9 @@ public:
bool operator==(const Iterator& other) const { bool operator==(const Iterator& other) const {
if (other.isDone || isDone) { if (other.isDone || isDone) {
// Common case; check against isDone. // Common case; check against isDone.
return (isDone == other.isDone) && (other.table == table); return (isDone == other.isDone);
} else { } else {
return return (node == other.node) && (index == other.index);
(table == other.table) &&
(node == other.node) &&
(index == other.index);
} }
} }
@@ -494,8 +502,13 @@ public:
Pre increment. Pre increment.
*/ */
Iterator& operator++() { Iterator& operator++() {
debugAssert(! isDone);
debugAssert(node != NULL);
debugAssert(isValidHeapPointer(node));
debugAssert((node->next == NULL) || isValidHeapPointer(node->next));
node = node->next; node = node->next;
findNext(); findNext();
debugAssert(isDone || isValidHeapPointer(node));
return *this; return *this;
} }
@@ -512,14 +525,29 @@ public:
return node->entry; return node->entry;
} }
const Value& value() const {
return node->entry.value;
}
const Key& key() const {
return node->entry.key;
}
Entry* operator->() const { Entry* operator->() const {
debugAssert(isValidHeapPointer(node));
return &(node->entry); return &(node->entry);
} }
operator Entry*() const { operator Entry*() const {
debugAssert(isValidHeapPointer(node));
return &(node->entry); return &(node->entry);
} }
bool isValid() const {
return ! isDone;
}
/** @deprecated Use isValid */
bool hasMore() const { bool hasMore() const {
return ! isDone; return ! isDone;
} }
@@ -532,7 +560,7 @@ public:
the next element. Do not modify the table while iterating. the next element. Do not modify the table while iterating.
*/ */
Iterator begin() const { Iterator begin() const {
return Iterator(this, m_numBuckets, m_bucket); return Iterator(m_numBuckets, m_bucket);
} }
/** /**
@@ -540,11 +568,12 @@ public:
element. element.
*/ */
const Iterator end() const { 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() { void clear() {
freeMemory(); freeMemory();
@@ -578,8 +607,9 @@ private:
if (m_numBuckets == 0) { if (m_numBuckets == 0) {
return false; 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 // Go to the m_bucket
Node* n = m_bucket[b]; Node* n = m_bucket[b];
@@ -609,6 +639,8 @@ private:
// Delete the node // Delete the node
Node::destroy(n, m_memoryManager); Node::destroy(n, m_memoryManager);
--m_size; --m_size;
//checkIntegrity();
return true; return true;
} }
@@ -616,8 +648,8 @@ private:
n = n->next; n = n->next;
} while (n != NULL); } while (n != NULL);
//checkIntegrity();
return false; return false;
//alwaysAssertM(false, "Tried to remove a key that was not in the table.");
} }
public: public:
@@ -733,7 +765,6 @@ public:
} }
/** Called by getCreate() and set() /** Called by getCreate() and set()
\param created Set to true if the entry was created by this method. \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_bucket[b] = Node::create(key, code, NULL, m_memoryManager);
++m_size; ++m_size;
created = true; created = true;
//checkIntegrity();
return m_bucket[b]->entry; return m_bucket[b]->entry;
} }
@@ -772,6 +804,7 @@ public:
if ((code == n->hashCode) && EqualsFunc::equals(n->entry.key, key)) { if ((code == n->hashCode) && EqualsFunc::equals(n->entry.key, key)) {
// This is the a pre-existing node // This is the a pre-existing node
//checkIntegrity();
return n->entry; return n->entry;
} }
@@ -779,12 +812,18 @@ public:
++bucketLength; ++bucketLength;
} while (n != NULL); } 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; const size_t maxBucketLength = 3;
// (Don't bother changing the size of the table if all entries // (Don't bother changing the size of the table if all entries
// have the same hashcode--they'll still collide) // have the same hashcode--they'll still collide)
if ((bucketLength > maxBucketLength) && if ((bucketLength > maxBucketLength) &&
! allSameCode && ! allSameCode &&
(m_numBuckets < m_size * 15)) { (m_numBuckets < m_size * bucketsPerElement)) {
// This m_bucket was really large; rehash if all elements // This m_bucket was really large; rehash if all elements
// don't have the same hashcode the number of buckets is // don't have the same hashcode the number of buckets is
@@ -807,6 +846,8 @@ public:
m_bucket[b] = Node::create(key, code, m_bucket[b], m_memoryManager); m_bucket[b] = Node::create(key, code, m_bucket[b], m_memoryManager);
++m_size; ++m_size;
created = true; created = true;
//checkIntegrity();
return m_bucket[b]->entry; return m_bucket[b]->entry;
} }
@@ -871,7 +912,7 @@ public:
void getKeys(Array<Key>& keyArray) const { void getKeys(Array<Key>& keyArray) const {
keyArray.resize(0, DONT_SHRINK_UNDERLYING_ARRAY); 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]; Node* node = m_bucket[i];
while (node != NULL) { while (node != NULL) {
keyArray.append(node->entry.key); 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<Value>& 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. Calls delete on all of the keys and then clears the table.
*/ */
void deleteKeys() { 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]; Node* node = m_bucket[i];
while (node != NULL) { while (node != NULL) {
delete node->entry.key; delete node->entry.key;
node->entry.key = NULL;
node = node->next; node = node->next;
} }
} }
@@ -912,6 +966,37 @@ public:
} }
} }
} }
template<class H, class E>
bool operator==(const Table<Key, Value, H, E>& 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<class H, class E>
bool operator!=(const Table<Key, Value, H, E>& 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 } // namespace

View File

@@ -1,16 +1,16 @@
/** /**
@file TextInput.h \file G3D/TextInput.h
Simple text lexer/tokenizer. 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 \created 2002-11-27
@edited 2010-07-03 \edited 2013-03-25
Copyright 2000-2010, Morgan McGuire. Copyright 2000-2013, Morgan McGuire.
All rights reserved. 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 superset of C++,Java, Matlab, and Bash code text including single
line comments, block comments, quoted strings with escape sequences, line comments, block comments, quoted strings with escape sequences,
and operators. TextInput recognizes several categories of tokens, and operators. TextInput recognizes several categories of tokens,
@@ -191,7 +193,7 @@ public:
<B>Examples</B> <B>Examples</B>
<PRE> \code
TextInput ti(TextInput::FROM_STRING, "name = \"Max\", height = 6"); TextInput ti(TextInput::FROM_STRING, "name = \"Max\", height = 6");
Token t; Token t;
@@ -206,15 +208,15 @@ public:
std::string name = ti.read().sval; std::string name = ti.read().sval;
ti.read(); ti.read();
</PRE> \endcode
<PRE> \code
TextInput ti(TextInput::FROM_STRING, "name = \"Max\", height = 6"); TextInput ti(TextInput::FROM_STRING, "name = \"Max\", height = 6");
ti.readSymbols("name", "="); ti.readSymbols("name", "=");
std::string name = ti.readString(); std::string name = ti.readString();
ti.readSymbols(",", "height", "="); ti.readSymbols(",", "height", "=");
double height = ti. readNumber(); double height = ti. readNumber();
</PRE> \endcode
Assumes that the file is not modified once opened. Assumes that the file is not modified once opened.
*/ */
@@ -329,14 +331,15 @@ public:
int startingLineNumberOffset; int startingLineNumberOffset;
/** /**
Parse -1.#IND00 as the floating point number returned by Parse "-1.#IND00" as the floating point number returned by
nan(), -1.#INF00 as -G3D::inf(), and 1.#INF00 as G3D::inf(). G3D::nan(), "-1.#INF00" as - G3D::inf(), and "1.#INF00" as G3D::inf().
Note that the C99 standard specifies that a variety of formats Note that the C99 standard specifies that a variety of formats
like "nan" are to be used; these are supported by like "nan" are to be used; these are supported by
G3D::TextInput::Settings::simpleFloatSpecials. G3D::TextInput::Settings::simpleFloatSpecials.
An alternative to specifying msvcFloatSpecials is to read numbers as: An alternative to specifying msvcFloatSpecials is to read numbers as:
\htmlonly
<pre> <pre>
Token x = t.read(); Token x = t.read();
Token y = t.peek(); Token y = t.peek();
@@ -349,6 +352,7 @@ public:
} }
// ... similar cases for inf // ... similar cases for inf
</pre> </pre>
\endhtmlonly
If the single-comment character was #, the floating point If the single-comment character was #, the floating point
special format overrides the comment and will be parsed special format overrides the comment and will be parsed
@@ -401,6 +405,9 @@ public:
private: private:
/** \sa pushSettings / popSettings */
Array<Settings> settingsStack;
std::deque<Token> stack; std::deque<Token> stack;
/** /**
@@ -477,7 +484,7 @@ private:
Read the next token, returning an END token if no more input is Read the next token, returning an END token if no more input is
available. available.
*/ */
Token nextToken(); void nextToken(Token& t);
/** /**
Helper for nextToken. Appends characters to t._string until the end Helper for nextToken. Appends characters to t._string until the end
@@ -488,6 +495,8 @@ private:
*/ */
void parseQuotedString(unsigned char delimiter, Token& t); void parseQuotedString(unsigned char delimiter, Token& t);
void initFromString(const char* str, int len, const Settings& settings);
public: public:
class TokenException : public ParseError { class TokenException : public ParseError {
@@ -569,9 +578,25 @@ public:
*/ */
TextInput(FS fs, const std::string& str, const Settings& settings = Settings()); 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. */ /** Returns true while there are tokens remaining. */
bool hasMore(); 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()). /** 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 Signed numbers can be handled in one of two modes. If the option
@@ -589,10 +614,13 @@ public:
*/ */
Token read(); Token read();
/** Avoids the copy of read() */
void read(Token& t);
/** Calls read() until the result is not a newline or comment */ /** Calls read() until the result is not a newline or comment */
Token readSignificant(); 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. WrongTokenType, and returns the number.
If the first token in the input is a number, it is returned directly. If the first token in the input is a number, it is returned directly.
@@ -608,6 +636,10 @@ public:
*/ */
double readNumber(); double readNumber();
/** Reads a number that must be in C integer format:
<code> [ '+' | '-' ] #+ | '0x'#+</code> */
int readInteger();
bool readBoolean(); bool readBoolean();
/** Reads a string token or throws WrongTokenType, and returns the token. /** 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 input stream is a string but does not match the @p s parameter. When
an exception is thrown, no tokens are consumed. an exception is thrown, no tokens are consumed.
\sa readString(), readStringToken(), readUntilNewlineAsString() \sa readString(), readStringToken(), readUntilNewlineAsString(), readUntilDelimiterAsString()
*/ */
void readString(const std::string& s); void readString(const std::string& s);
@@ -653,6 +685,12 @@ public:
end of file token (if they are enabled for parsing).*/ end of file token (if they are enabled for parsing).*/
std::string readUntilNewlineAsString(); 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. /** Reads a comment token or throws WrongTokenType, and returns the token.
Use this method (rather than readComment) if you want the token's Use this method (rather than readComment) if you want the token's
@@ -734,6 +772,9 @@ public:
*/ */
Token readSymbolToken(); Token readSymbolToken();
/** Avoids the copy of readSymbolToken() */
void readSymbolToken(Token& t);
/** Like readSymbolToken, but returns the token's string. /** Like readSymbolToken, but returns the token's string.
Use this method (rather than readSymbolToken) if you want the token's Use this method (rather than readSymbolToken) if you want the token's

View File

@@ -1,16 +1,16 @@
/** /**
@file TextOutput.h \file G3D/TextOutput.h
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2004-06-21 \created 2004-06-21
@edited 2006-10-24 \edited 2011-05-24
Copyright 2000-2007, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_TEXTOUTPUT_H #ifndef G3D_TextOutput_h
#define G3D_TEXTOUTPUT_H #define G3D_TextOutput_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Array.h" #include "G3D/Array.h"
@@ -112,7 +112,7 @@ public:
convertNewlines(true), convertNewlines(true),
trueSymbol("true"), trueSymbol("true"),
falseSymbol("false") { falseSymbol("false") {
#ifdef G3D_WIN32 #ifdef G3D_WINDOWS
newlineStyle = NEWLINE_WINDOWS; newlineStyle = NEWLINE_WINDOWS;
#else #else
newlineStyle = NEWLINE_UNIX; newlineStyle = NEWLINE_UNIX;
@@ -156,6 +156,9 @@ private:
/** the newline character(s) */ /** the newline character(s) */
std::string newline; std::string newline;
/** Starts at 1 */
int m_currentLine;
void setOptions(const Settings& _opt); void setOptions(const Settings& _opt);
/** Converts to the desired newlines. Called from vprintf */ /** 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.*/ /** Constructs a text output that can later be commited to a string instead of a file.*/
explicit TextOutput(const Settings& options = Settings()); 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. /** Commit to the filename specified on the constructor.
<B>Not</B> called from the destructor; you must call <B>Not</B> called from the destructor; you must call
it yourself. it yourself.
@@ -206,6 +214,9 @@ public:
void writeNewline(); void writeNewline();
void writeNewlines(int numLines); 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 /** The symbol is written without quotes. Symbols are required to begin with a
letter or underscore and contain only letters, underscores, and numbers letter or underscore and contain only letters, underscores, and numbers
or be a C++ symbol (e.g. "{", "(", "++", etc.) or be a C++ symbol (e.g. "{", "(", "++", etc.)
@@ -213,6 +224,8 @@ public:
printed with a trailing space.*/ printed with a trailing space.*/
void writeSymbol(const std::string& string); void writeSymbol(const std::string& string);
void writeSymbol(char s);
/** Convenient idiom for writing multiple symbols in a row, e.g. /** Convenient idiom for writing multiple symbols in a row, e.g.
writeSymbols("name", "="); The empty symbols are not written. writeSymbols("name", "="); The empty symbols are not written.
*/ */

View File

@@ -1,14 +1,16 @@
#ifndef G3D_THREADSET_H #ifndef G3D_ThreadSet_h
#define G3D_THREADSET_H #define G3D_ThreadSet_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Array.h" #include "G3D/Array.h"
#include "G3D/ReferenceCount.h" #include "G3D/ReferenceCount.h"
#include "G3D/GThread.h"
#include "G3D/GMutex.h" #include "G3D/GMutex.h"
#include "G3D/SpawnBehavior.h"
namespace G3D { namespace G3D {
class GThread;
/** Manages a set of threads. All methods are threadsafe except for /** Manages a set of threads. All methods are threadsafe except for
the iterator begin/end. the iterator begin/end.
@@ -18,8 +20,8 @@ public:
/** Intended to allow future use with a template parameter.*/ /** Intended to allow future use with a template parameter.*/
typedef GThread Thread; typedef GThread Thread;
typedef ReferenceCountedPointer<Thread> ThreadRef; typedef shared_ptr<Thread> ThreadRef;
typedef ReferenceCountedPointer<ThreadSet> Ref; typedef shared_ptr<ThreadSet> Ref;
typedef Array<ThreadRef>::Iterator Iterator; typedef Array<ThreadRef>::Iterator Iterator;
typedef Array<ThreadRef>::ConstIterator ConstIterator; typedef Array<ThreadRef>::ConstIterator ConstIterator;
@@ -41,13 +43,14 @@ public:
/** Start all threads that are not currently started. /** Start all threads that are not currently started.
@param lastThreadBehavior If USE_CURRENT_THREAD, takes the last unstarted thread and executes it manually on @param lastThreadBehavior If USE_CURRENT_THREAD, takes the
the current thread. This helps to take full advantage of the machine when last unstarted thread and executes it manually on the current
running a large number of jobs and avoids the overhead of a thread start for single-thread groups. thread. This helps to take full advantage of the machine when
Note that this forces start() to block until running a large number of jobs and avoids the overhead of a
that thread is complete. 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 */ /** Terminate all threads that are currently started */
void terminate() const; void terminate() const;

View File

@@ -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 \created 2003-04-05
@edited 2008-10-06 \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. All rights reserved.
*/ */
#ifndef G3D_TRIANGLE_H #ifndef G3D_Triangle_h
#define G3D_TRIANGLE_H #define G3D_Triangle_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
@@ -62,12 +62,12 @@ public:
Triangle(); Triangle();
Triangle(const Vector3& v0, const Vector3& v1, const Vector3& v2); Triangle(const Point3& v0, const Point3& v1, const Point3& v2);
~Triangle(); ~Triangle();
/** 0, 1, or 2 */ /** 0, 1, or 2 */
inline const Vector3& vertex(int n) const { inline const Point3& vertex(int n) const {
debugAssert((n >= 0) && (n < 3)); debugAssert((n >= 0) && (n < 3));
return _vertex[n]; return _vertex[n];
} }
@@ -91,15 +91,15 @@ public:
const Vector3& normal() const; const Vector3& normal() const;
/** Barycenter */ /** Barycenter */
Vector3 center() const; Point3 center() const;
const Plane& plane() const; const Plane& plane() const;
/** Returns a random point in the triangle. */ /** Returns a random point in the triangle. */
Vector3 randomPoint() const; Point3 randomPoint() const;
inline void getRandomSurfacePoint inline void getRandomSurfacePoint
(Vector3& P, (Point3& P,
Vector3& N = Vector3::ignore()) const { Vector3& N = Vector3::ignore()) const {
P = randomPoint(); P = randomPoint();
N = normal(); N = normal();

View File

@@ -1,25 +1,24 @@
/** /**
@file UprightFrame.h \file G3D/UprightFrame.h
\author Morgan McGuire, http://graphics.cs.williams.edu
@author Morgan McGuire, http://graphics.cs.williams.edu
*/ */
#ifndef G3D_UPRIGHTFRAME_H #ifndef G3D_UprightFrame_h
#define G3D_UPRIGHTFRAME_H #define G3D_UprightFrame_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/Spline.h" #include "G3D/Spline.h"
#include "G3D/Vector3.h" #include "G3D/Any.h"
#include "G3D/CoordinateFrame.h" #include "G3D/CoordinateFrame.h"
namespace G3D { namespace G3D {
/** /**
Coordinate frame expressed in Euler angles. \brief Coordinate frame expressed in Euler angles.
Unlike a G3D::Quat, UprightFrame always keeps the reference frame from rolling about its own z axis. Unlike a G3D::Quat, UprightFrame always keeps the reference frame from rolling about its own z axis.
Particularly useful for cameras. 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 { class UprightFrame {
public: public:
@@ -32,18 +31,32 @@ public:
/** In radians about the Y-axis */ /** In radians about the Y-axis */
float yaw; 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) {} : translation(t), pitch(p), yaw(y) {}
UprightFrame(const CoordinateFrame& cframe); UprightFrame(const CoordinateFrame& cframe);
CoordinateFrame toCoordinateFrame() const; /** Constructs an UprightFrame from an Any object.
The Any format for UprightFrame is:
pitch = ##,
translation = Vector3(),
yaw = ##
*/
explicit UprightFrame(const Any& any);
Any toAny() const;
UprightFrame& operator=(const Any& any);
/** Supports implicit cast to CoordinateFrame */ /** Supports implicit cast to CoordinateFrame */
inline operator CoordinateFrame() const { operator CoordinateFrame() const {
return toCoordinateFrame(); return toCoordinateFrame();
} }
CoordinateFrame toCoordinateFrame() const;
/** Required for use with spline */ /** Required for use with spline */
UprightFrame operator+(const UprightFrame& other) const; UprightFrame operator+(const UprightFrame& other) const;
@@ -61,8 +74,10 @@ public:
void deserialize(class BinaryInput& b); 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<UprightFrame> { class UprightSpline : public Spline<UprightFrame> {
protected: protected:
@@ -72,10 +87,29 @@ protected:
} }
public: 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 serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b); void deserialize(class BinaryInput& b);
}; };
} }

View File

@@ -1,19 +1,19 @@
/** /**
@file Vector2.h \file G3D/Vector2.h
2D vector class 2D vector class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-06-02 \created 2001-06-02
@edited 2008-11-30 \edited 2011-11-30
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_VECTOR2_H #ifndef G3D_Vector2_h
#define G3D_VECTOR2_H #define G3D_Vector2_h
#include <string> #include <string>
@@ -22,6 +22,7 @@
#include "G3D/Table.h" #include "G3D/Table.h"
#include "G3D/HashTrait.h" #include "G3D/HashTrait.h"
#include "G3D/Vector2int16.h" #include "G3D/Vector2int16.h"
#include "G3D/Vector2unorm16.h"
#include "G3D/Random.h" #include "G3D/Random.h"
namespace G3D { namespace G3D {
@@ -29,6 +30,7 @@ namespace G3D {
class Vector2; class Vector2;
class Vector3; class Vector3;
class Vector4; class Vector4;
class Vector2int32;
class Any; class Any;
/** /**
@@ -51,7 +53,7 @@ public:
Vector2(const Any& any); Vector2(const Any& any);
/** Converts the Vector2 to an Any. */ /** Converts the Vector2 to an Any. */
operator Any() const; Any toAny() const;
/** Creates the zero vector */ /** Creates the zero vector */
Vector2(); Vector2();
@@ -62,6 +64,12 @@ public:
Vector2(double coordinate[2]); Vector2(double coordinate[2]);
Vector2(const Vector2& other); Vector2(const Vector2& other);
Vector2(const Vector2int16& 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 serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b); void deserialize(class BinaryInput& b);
@@ -83,6 +91,11 @@ public:
/** Returns true if this vector has finite length */ /** Returns true if this vector has finite length */
bool isFinite() const; 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 */ /** Returns true if this vector has length == 0 */
bool isZero() const; bool isZero() const;
@@ -94,6 +107,11 @@ public:
Vector2 operator-(const Vector2& v) const; Vector2 operator-(const Vector2& v) const;
Vector2 operator*(float s) 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 */ /** Array (pointwise) multiplication */
Vector2 operator*(const Vector2& v) const; Vector2 operator*(const Vector2& v) const;
@@ -138,12 +156,19 @@ public:
// vector operations // vector operations
/** */ /** Magnitude of the vector */
float length() const; 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; 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(). Potentially less accurate but faster than direction().
Only works if System::hasSSE is true. Only works if System::hasSSE is true.
@@ -155,15 +180,35 @@ public:
float squaredLength() const; float squaredLength() const;
float dot(const Vector2& s) const; float dot(const Vector2& s) const;
/** /** Componentwise absolute value */
Make this vector have unit length and return the old length. Vector2 abs() const {
If the vector length was less than tolerance, do not normalize. return Vector2(fabs(x), fabs(y));
*/ }
float unitize(float fTolerance = 1e-06);
/** Component-wise minimum */
Vector2 min(const Vector2& v) const; Vector2 min(const Vector2& v) const;
/** Component-wise maximum */
Vector2 max(const Vector2& v) const; Vector2 max(const Vector2& v) const;
/** Component-wise argmax(abs(), v.abs()).
For the larger magnitude vector, simply use <code>(a.squaredMagnitude() > b.squaredMagnitude) ? a : b</code>.
\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 <code>(a.squaredMagnitude() < b.squaredMagnitude) ? a : b</code>.
\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 */ /** Uniformly distributed random vector on the unit sphere */
static Vector2 random(Random& r = Random::common()); 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 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) { inline float& Vector2::operator[] (int i) {
return ((float*)this)[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 { inline float Vector2::dot (const Vector2& rkVector) const {
@@ -424,15 +480,19 @@ inline bool Vector2::isFinite() const {
inline bool Vector2::isZero() 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 { 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 } // namespace G3D
template <> template <>

View File

@@ -4,14 +4,14 @@
@maintainer Morgan McGuire, matrix@brown.edu @maintainer Morgan McGuire, matrix@brown.edu
@created 2003-08-09 @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. All rights reserved.
*/ */
#ifndef VECTOR2INT16_H #ifndef Vector2int16_h
#define VECTOR2INT16_H #define Vector2int16_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
@@ -19,12 +19,13 @@
namespace G3D { namespace G3D {
class Any;
/** /**
\class Vector2int16 \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) G3D_BEGIN_PACKED_CLASS(2)
class Vector2int16 { Vector2int16 {
private: private:
// Hidden operators // Hidden operators
bool operator<(const Vector2int16&) const; bool operator<(const Vector2int16&) const;
@@ -38,8 +39,14 @@ public:
Vector2int16() : x(0), y(0) {} Vector2int16() : x(0), y(0) {}
Vector2int16(G3D::int16 _x, G3D::int16 _y) : x(_x), y(_y){} Vector2int16(G3D::int16 _x, G3D::int16 _y) : x(_x), y(_y){}
Vector2int16(const class Vector2& v); explicit Vector2int16(const class Vector2& v);
Vector2int16(class BinaryInput& bi); 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) { inline G3D::int16& operator[] (int i) {
debugAssert(((unsigned int)i) <= 1); debugAssert(((unsigned int)i) <= 1);
@@ -63,6 +70,10 @@ public:
return Vector2int16(x * other.x, y * other.y); return Vector2int16(x * other.x, y * other.y);
} }
Vector2int16 operator-() const {
return Vector2int16(-x, -y);
}
inline Vector2int16 operator*(const int s) const { inline Vector2int16 operator*(const int s) const {
return Vector2int16(x * s, y * s); return Vector2int16(x * s, y * s);
} }
@@ -73,6 +84,10 @@ public:
return *this; return *this;
} }
bool isZero() const {
return (x == 0) && (y == 0);
}
/** Shifts both x and y */ /** Shifts both x and y */
inline Vector2int16 operator>>(const int s) const { inline Vector2int16 operator>>(const int s) const {
return Vector2int16(x >> s, y >> s); return Vector2int16(x >> s, y >> s);
@@ -118,6 +133,8 @@ public:
} }
G3D_END_PACKED_CLASS(2) G3D_END_PACKED_CLASS(2)
typedef Vector2int16 Point2int16;
} }
template<> struct HashTrait<G3D::Vector2int16> { template<> struct HashTrait<G3D::Vector2int16> {

134
deps/g3dlite/include/G3D/Vector2int32.h vendored Normal file
View File

@@ -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<G3D::Vector2int32> {
static size_t hashCode(const G3D::Vector2int32& key) { return static_cast<size_t>(key.x ^ ((int)key.y << 1)); }
};
#endif

View File

@@ -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<size_t>(x.bits() + ((int)y.bits() << 16));
}
}
G3D_END_PACKED_CLASS(2)
typedef Vector2unorm16 Point2unorm16;
}
template<> struct HashTrait<G3D::Vector2unorm16> {
static size_t hashCode(const G3D::Vector2unorm16& key) { return key.hashCode(); }
};
#endif

View File

@@ -1,13 +1,14 @@
/** /**
@file Vector3.h \file Vector3.h
3D vector class 3D vector class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-06-02 \created 2001-06-02
@edited 2009-11-01 \edited 2010-12-25
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -72,18 +73,26 @@ public:
/** Initializes to zero */ /** Initializes to zero */
Vector3(); 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. */ /** Converts the Vector3 to an Any. */
operator Any() const; Any toAny() const;
/** Divides by 127 */ /** Divides by 127 */
Vector3(const Vector4int8&); Vector3(const Vector4int8&);
Vector3(const class Vector2& v, float z);
Vector3(const class Vector3int32& v); Vector3(const class Vector3int32& v);
explicit Vector3(class BinaryInput& b); explicit Vector3(class BinaryInput& b);
Vector3(float _x, float _y, float _z); Vector3(float _x, float _y, float _z);
explicit Vector3(const class Vector2& v, float _z);
explicit Vector3(float coordinate[3]); explicit Vector3(float coordinate[3]);
explicit Vector3(double coordinate[3]); explicit Vector3(double coordinate[3]);
Vector3(const class Vector3int16& v); Vector3(const class Vector3int16& v);
@@ -106,6 +115,10 @@ public:
const float& __fastcall operator[] (int i) const; const float& __fastcall operator[] (int i) const;
float& operator[] (int i); 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}; enum Axis {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, DETECT_AXIS=-1};
/** /**
@@ -115,12 +128,8 @@ public:
Axis primaryAxis() const; Axis primaryAxis() const;
// assignment and comparison // assignment and comparison
Vector3& __fastcall operator= (const Vector3& rkVector); Vector3& operator=(const Vector3& rkVector) = default;
/* requried as of C++ 11 */ Vector3& operator=(const Any& a);
#if __cplusplus >= 201103L
Vector3(const Vector3&) = default;
Vector3(Vector3&&) = default;
#endif
bool operator== (const Vector3& rkVector) const; bool operator== (const Vector3& rkVector) const;
bool operator!= (const Vector3& rkVector) const; bool operator!= (const Vector3& rkVector) const;
size_t hashCode() const; size_t hashCode() const;
@@ -130,12 +139,19 @@ public:
/** Returns true if this vector has finite length. */ /** Returns true if this vector has finite length. */
bool isFinite() const; bool isFinite() const;
/** True if any field is nan */
bool isNaN() const;
/** Returns true if this vector has length ~= 0 */ /** Returns true if this vector has length ~= 0 */
bool isZero() const; bool isZero() const;
/** Returns true if this vector has length ~= 1 */ /** Returns true if this vector has length ~= 1 */
bool isUnit() const; 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 // arithmetic operations
Vector3 __fastcall operator+ (const Vector3& v) const; Vector3 __fastcall operator+ (const Vector3& v) const;
Vector3 __fastcall operator- (const Vector3& v) const; Vector3 __fastcall operator- (const Vector3& v) const;
@@ -162,8 +178,14 @@ public:
float magnitude() 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; Vector3 direction() const;
@@ -273,8 +295,6 @@ public:
float __fastcall dot(const Vector3& rkVector) const; float __fastcall dot(const Vector3& rkVector) const;
float unitize(float tolerance = 1e-06);
/** Cross product. Note that two cross products in a row /** 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. can be computed more cheaply: v1 x (v2 x v3) = (v1 dot v3) v2 - (v1 dot v2) v3.
*/ */
@@ -320,6 +340,17 @@ public:
G3D::clamp(z, low, high)); 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 Linear interpolation
*/ */
@@ -352,6 +383,8 @@ public:
*/ */
static Vector3 cosHemiRandom(const Vector3& n, Random& r = Random::common()); 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$. /** \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 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()); 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 { inline float sum() const {
return x + y + z; return x + y + z;
} }
@@ -554,6 +579,8 @@ public:
static Vector3& ignore(); static Vector3& ignore();
}; };
inline G3D::Vector3 operator*(float s, const G3D::Vector3& v) { inline G3D::Vector3 operator*(float s, const G3D::Vector3& v) {
return v * s; 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 { 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 { inline Vector3 Vector3::unitCross (const Vector3& rkVector) const {
Vector3 kCross(y*rkVector.z - z*rkVector.y, z*rkVector.x - x*rkVector.z, Vector3 kCross(y*rkVector.z - z*rkVector.y, z*rkVector.x - x*rkVector.z,
x*rkVector.y - y*rkVector.x); x*rkVector.y - y*rkVector.x);
kCross.unitize(); return kCross.direction();
return kCross;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -771,7 +789,7 @@ inline Vector3 Vector3::max(const Vector3 &v) const {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
inline bool Vector3::isZero() 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); 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 } // namespace G3D

View File

@@ -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 \created 2003-04-07
@edited 2003-06-24 \edited 2011-06-24
Copyright 2000-2004, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef VECTOR3INT16_H #ifndef G3D_Vector3int16_h
#define VECTOR3INT16_H #define G3D_Vector3int16_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
@@ -19,6 +20,7 @@
#ifdef _MSC_VER #ifdef _MSC_VER
// Turn off "conditional expression is constant" warning; MSVC generates this // Turn off "conditional expression is constant" warning; MSVC generates this
// for debug assertions in inlined methods. // for debug assertions in inlined methods.
#pragma warning (push)
#pragma warning (disable : 4127) #pragma warning (disable : 4127)
#endif #endif
@@ -30,7 +32,7 @@ namespace G3D {
A Vector3 that packs its fields into uint16s. A Vector3 that packs its fields into uint16s.
*/ */
G3D_BEGIN_PACKED_CLASS(2) G3D_BEGIN_PACKED_CLASS(2)
class Vector3int16 { Vector3int16 {
private: private:
// Hidden operators // Hidden operators
bool operator<(const Vector3int16&) const; bool operator<(const Vector3int16&) const;
@@ -45,8 +47,8 @@ public:
Vector3int16() : x(0), y(0), z(0) {} Vector3int16() : x(0), y(0), z(0) {}
Vector3int16(G3D::int16 _x, G3D::int16 _y, G3D::int16 _z) : x(_x), y(_y), z(_z) {} Vector3int16(G3D::int16 _x, G3D::int16 _y, G3D::int16 _z) : x(_x), y(_y), z(_z) {}
Vector3int16(const class Vector3& v); explicit Vector3int16(const class Vector3& v);
Vector3int16(class BinaryInput& bi); explicit Vector3int16(class BinaryInput& bi);
void serialize(class BinaryOutput& bo) const; void serialize(class BinaryOutput& bo) const;
void deserialize(class BinaryInput& bi); void deserialize(class BinaryInput& bi);
@@ -98,6 +100,9 @@ public:
return *this; return *this;
} }
static Vector3int16 floor(const Vector3& v);
static Vector3int16 ceil(const Vector3& v);
inline bool operator== (const Vector3int16& rkVector) const { inline bool operator== (const Vector3int16& rkVector) const {
return ( x == rkVector.x && y == rkVector.y && z == rkVector.z ); 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 ); 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 { Vector3int16 max(const Vector3int16& v) const {
return Vector3int16(std::max(x, v.x), std::max(y, v.y), std::max(z, v.z)); 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; 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) G3D_END_PACKED_CLASS(2)
} typedef Vector3int16 Point3int16;
} // namespace G3D
template <> struct HashTrait<G3D::Vector3int16> { template <> struct HashTrait<G3D::Vector3int16> {
static size_t hashCode(const G3D::Vector3int16& key) { return static_cast<size_t>(key.x + ((int)key.y << 5) + ((int)key.z << 10)); } static size_t hashCode(const G3D::Vector3int16& key) { return static_cast<size_t>(key.x + ((int)key.y << 5) + ((int)key.z << 10)); }
}; };
#ifdef G3D_WINDOWS
#pragma warning( pop )
#endif
#endif #endif

View File

@@ -1,29 +1,32 @@
/** /**
@file Vector3int32.h @file G3D/Vector3int32.h
@maintainer Morgan McGuire, matrix@brown.edu @maintainer Morgan McGuire, matrix@brown.edu
@created 2008-07-01 @created 2008-07-01
@edited 2008-07-01 @edited 2011-01-01
Copyright 2000-2009, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef VECTOR3INT32_H #ifndef G3D_Vector3int32_h
#define VECTOR3INT32_H #define G3D_Vector3int32_h
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
#include "G3D/HashTrait.h" #include "G3D/HashTrait.h"
#include "G3D/Crypto.h"
namespace G3D { namespace G3D {
class Any;
/** /**
\ Vector3int32 \ Vector3int32
A Vector3 that packs its fields into uint32s. A Vector3 that packs its fields into uint32s.
*/ */
G3D_BEGIN_PACKED_CLASS(4) G3D_BEGIN_PACKED_CLASS(4)
class Vector3int32 { Vector3int32 {
private: private:
// Hidden operators // Hidden operators
bool operator<(const Vector3int32&) const; bool operator<(const Vector3int32&) const;
@@ -38,9 +41,21 @@ public:
Vector3int32() : x(0), y(0), z(0) {} Vector3int32() : x(0), y(0), z(0) {}
Vector3int32(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {} 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 Vector3int16& v);
Vector3int32(const class Vector3& v); Vector3int32(const Any& any);
Vector3int32(class BinaryInput& bi); 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 serialize(class BinaryOutput& bo) const;
void deserialize(class BinaryInput& bi); void deserialize(class BinaryInput& bi);
@@ -71,32 +86,42 @@ public:
return Vector3int32(x * s, y * s, z * s); 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; x += other.x;
y += other.y; y += other.y;
z += other.z; z += other.z;
return *this; return *this;
} }
inline Vector3int32& operator-=(const Vector3int32& other) { Vector3int32& operator-=(const Vector3int32& other) {
x -= other.x; x -= other.x;
y -= other.y; y -= other.y;
z -= other.z; z -= other.z;
return *this; return *this;
} }
inline Vector3int32& operator*=(const Vector3int32& other) { Vector3int32& operator*=(const Vector3int32& other) {
x *= other.x; x *= other.x;
y *= other.y; y *= other.y;
z *= other.z; z *= other.z;
return *this; 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 ); 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 ); 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)); 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; 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) G3D_END_PACKED_CLASS(4)
} typedef Vector3int32 Point3int32;
Vector3int32 iFloor(const Vector3&);
} // namespace G3D
template <> struct HashTrait<G3D::Vector3int32> { template <> struct HashTrait<G3D::Vector3int32> {
static size_t hashCode(const G3D::Vector3int32& key) { 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 // Mask for the top bit of a uint32
const G3D::uint32 top = (1UL << 31); const G3D::uint32 top = (1UL << 31);
// Mask for the bottom 10 bits of a uint32 // Mask for the bottom 10 bits of a uint32
const G3D::uint32 bot = 0x000003FF; const G3D::uint32 bot = 0x000003FF;
return static_cast<size_t>(((key.x & top) | ((key.y & top) >> 1) | ((key.z & top) >> 2)) | return static_cast<size_t>(((key.x & top) | ((key.y & top) >> 1) | ((key.z & top) >> 2)) |
(((key.x & bot) << 19) ^ ((key.y & bot) << 10) ^ (key.z & bot))); (((key.x & bot) << 19) ^ ((key.y & bot) << 10) ^ (key.z & bot)));
*/
} }
}; };

View File

@@ -47,10 +47,11 @@ private:
public: public:
/** \param any Must either Vector4(#, #, #, #) or Vector3 {x = #, y = #, z = #, w =#}*/ /** \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. */ /** Converts the Vector4 to an Any. */
operator Any() const; Any toAny() const;
// construction // construction
Vector4(); Vector4();
@@ -698,7 +699,11 @@ inline float Vector4::squaredLength() const {
return x * x + y * y + z * z + w * w; 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<G3D::Vector4> { template <> struct HashTrait<G3D::Vector4> {
static size_t hashCode(const G3D::Vector4& key) { return key.hashCode(); } static size_t hashCode(const G3D::Vector4& key) { return key.hashCode(); }

View File

@@ -51,14 +51,14 @@ public:
inline Vector4int8() : x(0), y(0), z(0), w(0) {} inline Vector4int8() : x(0), y(0), z(0), w(0) {}
/** Multiplies the source by 127 and clamps to (-128, 127) when converting */ /** 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 */ /** 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) {} 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 serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b); void deserialize(class BinaryInput& b);

View File

@@ -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 \created 2007-05-16
@edited 2007-05-16 \edited 2012-01-02
Copyright 2000-2007, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_WEAKCACHE_H #ifndef G3D_WeakCache_h
#define G3D_WEAKCACHE_H #define G3D_WeakCache_h
#include "G3D/ReferenceCount.h" #include "G3D/ReferenceCount.h"
#include "G3D/Table.h" #include "G3D/Table.h"
@@ -31,10 +31,10 @@ namespace G3D {
Example: Example:
<pre> <pre>
WeakCache<std::string, TextureRef> textureCache; WeakCache<std::string, shared_ptr<Texture>> textureCache;
TextureRef loadTexture(std::string s) { shared_ptr<Texture> loadTexture(std::string s) {
TextureRef t = textureCache[s]; shared_ptr<Texture> t = textureCache[s];
if (t.isNull()) { if (t.isNull()) {
t = Texture::fromFile(s); t = Texture::fromFile(s);
@@ -49,7 +49,7 @@ namespace G3D {
*/ */
template<class Key, class ValueRef> template<class Key, class ValueRef>
class WeakCache { class WeakCache {
typedef WeakReferenceCountedPointer<typename ValueRef::element_type> ValueWeakRef; typedef weak_ptr<typename ValueRef::element_type> ValueWeakRef;
private: private:
@@ -62,17 +62,34 @@ public:
ValueRef operator[](const Key& k) { ValueRef operator[](const Key& k) {
if (table.containsKey(k)) { if (table.containsKey(k)) {
ValueWeakRef w = table[k]; ValueWeakRef w = table[k];
ValueRef s = w.createStrongPtr(); ValueRef s = w.lock();
if (s.isNull()) { if (! s) {
// This object has been collected; clean out its key // This object has been collected; clean out its key
table.remove(k); table.remove(k);
} }
return s; return s;
} else { } else {
return NULL; return ValueRef();
} }
} }
void getValues(Array<ValueRef>& values) {
Array<Key> 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) { void set(const Key& k, ValueRef v) {
table.set(k, v); table.set(k, v);
} }
@@ -85,38 +102,6 @@ public:
} }
}; };
#if 0 // To turn off all WeakCaching
template<class Key, class ValueRef>
class WeakCache {
private:
Table<Key, ValueRef> 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 #endif

View File

@@ -22,30 +22,38 @@ public:
/** Surfaces with normals that are within this angle of each /** Surfaces with normals that are within this angle of each
other are considered to be curved. Default value is toRadians(70.0f).*/ other are considered to be curved. Default value is toRadians(70.0f).*/
float normalSmoothingAngle; float normalSmoothingAngle;
/** Default value is 0 */
float vertexWeldRadius; float vertexWeldRadius;
float textureWeldRadius; float textureWeldRadius;
float normalWeldRadius; float normalWeldRadius;
inline Settings(float normalSmoothAngle = toRadians(70.0f)) : inline Settings(float normalSmoothAngle = toRadians(70.0f)) :
normalSmoothingAngle(normalSmoothAngle), normalSmoothingAngle(normalSmoothAngle),
vertexWeldRadius(0.0001f), vertexWeldRadius(0.001f),
textureWeldRadius(0.0001f), textureWeldRadius(0.0001f),
normalWeldRadius(0.01f) {} normalWeldRadius(0.01f) {}
Settings(const Any& any); 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 vertices Input and output
@param textureCoords Input and output @param textureCoords Input and output
@param normals Output only @param normals Output only
@param indices Input and output. This is an array of trilist indices. @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( static void weld(
Array<Vector3>& vertices, Array<Vector3>& vertices,
@@ -61,8 +69,6 @@ public:
@param textureCoords Input and output @param textureCoords Input and output
@param normals Output only @param normals Output only
@param indices Input and output. This is an array of trilist indices. @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( inline static void weld(
Array<Vector3>& vertices, Array<Vector3>& vertices,

View File

@@ -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 \created 2007-04-17
@edited 2010-04-17 \edited 2010-04-17
Copyright 2000-2010, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -15,7 +15,6 @@
#include "G3D/platform.h" #include "G3D/platform.h"
#include "G3D/enumclass.h" #include "G3D/enumclass.h"
#include "G3D/Any.h"
#ifdef IGNORE #ifdef IGNORE
# undef IGNORE # undef IGNORE
@@ -62,9 +61,7 @@ public:
ZERO, ZERO,
IGNORE, IGNORE,
ERROR ERROR
}; } value;
private:
static const char* toString(int i, Value& v) { static const char* toString(int i, Value& v) {
static const char* str[] = {"CLAMP", "TILE", "ZERO", "IGNORE", "ERROR", NULL}; static const char* str[] = {"CLAMP", "TILE", "ZERO", "IGNORE", "ERROR", NULL};
@@ -76,14 +73,11 @@ private:
return s; return s;
} }
Value value;
public:
G3D_DECLARE_ENUM_CLASS_METHODS(WrapMode); G3D_DECLARE_ENUM_CLASS_METHODS(WrapMode);
}; };
} // namespace G3D } // namespace G3D
G3D_DECLARE_ENUM_CLASS_HASHCODE(G3D::WrapMode); G3D_DECLARE_ENUM_CLASS_HASHCODE(G3D::WrapMode);

View File

@@ -7,7 +7,7 @@
@created 2010-02-11 @created 2010-02-11
@edited 2010-02-24 @edited 2010-02-24
Copyright 2000-2010, Morgan McGuire. Copyright 2000-2012, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
@@ -52,6 +52,7 @@ end with "-->" e.g.,
\sa G3D::Any, http://www.grinninglizard.com/tinyxml/ \sa G3D::Any, http://www.grinninglizard.com/tinyxml/
\htmlonly
<pre> <pre>
<foo key0="value0" key1="value1"> <foo key0="value0" key1="value1">
child0 ... child0 ...
@@ -59,6 +60,7 @@ end with "-->" e.g.,
child2 ... child2 ...
</foo> </foo>
</pre> </pre>
\endhtmlonly
*/ */
class XML { class XML {
public: public:
@@ -117,7 +119,7 @@ public:
return m_attribute; return m_attribute;
} }
const Array<XML> childArray() const { const Array<XML>& childArray() const {
return m_child; return m_child;
} }
@@ -127,7 +129,7 @@ public:
} }
/** Attribute table size; zero for a TAG */ /** Attribute table size; zero for a TAG */
int numAttributes() const { size_t numAttributes() const {
return m_attribute.size(); return m_attribute.size();
} }
@@ -142,7 +144,7 @@ public:
return m_attribute[k]; return m_attribute[k];
} }
const bool containsAttribute(const std::string& k) const { bool containsAttribute(const std::string& k) const {
return m_attribute.containsKey(k); return m_attribute.containsKey(k);
} }

View File

@@ -26,20 +26,13 @@ public:
TRIANGLE_STRIP = 0x0005, TRIANGLE_STRIP = 0x0005,
TRIANGLE_FAN = 0x0006, TRIANGLE_FAN = 0x0006,
QUADS = 0x0007, QUADS = 0x0007,
QUAD_STRIP = 0x0008 QUAD_STRIP = 0x0008,
PATCHES = 0x000E
}; };
private: private:
static const char* toString(int i, Value& v) { 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;
}
Value value; Value value;
@@ -49,7 +42,7 @@ public:
}; };
/** Values for SuperSurface::GPUGeom::refractionHint. */ /** Values for UniversalSurface::GPUGeom::refractionHint. */
class RefractionQuality { class RefractionQuality {
public: public:
enum Value { enum Value {
@@ -77,15 +70,7 @@ public:
private: private:
static const char* toString(int i, Value& v) { 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;
}
Value value; Value value;
@@ -95,7 +80,7 @@ public:
}; };
/** Values for SuperSurface::GPUGeom::mirrorHint. */ /** Values for UniversalSurface::GPUGeom::mirrorHint. */
class MirrorQuality { class MirrorQuality {
public: public:
@@ -119,15 +104,7 @@ public:
private: private:
static const char* toString(int i, Value& v) { 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;
}
Value value; Value value;

View File

@@ -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 \created 2001-08-26
@edited 2006-02-16 \edited 2008-08-16
Copyright 2000-2006, Morgan McGuire. Copyright 2000-2006, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_DEBUG_H #ifndef G3D_debug_h
#define G3D_DEBUG_H #define G3D_debug_h
#include "G3D/platform.h" #include "G3D/platform.h"
#ifdef _MSC_VER #ifdef _MSC_VER
@@ -38,7 +38,9 @@ namespace G3D {
inline bool isValidHeapPointer(const void* x) { inline bool isValidHeapPointer(const void* x) {
#ifdef _MSC_VER #ifdef _MSC_VER
return 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 #else
return x != NULL; return x != NULL;
#endif #endif
@@ -51,7 +53,9 @@ inline bool isValidHeapPointer(const void* x) {
*/ */
inline bool isValidPointer(const void* x) { inline bool isValidPointer(const void* x) {
#ifdef _MSC_VER #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 #else
return x != NULL; return x != NULL;
#endif #endif

View File

@@ -1,30 +1,39 @@
/** /**
@file G3D/enumclass.h \file G3D/enumclass.h
@maintainer Morgan McGuire, http://graphics.cs.williams.edu \maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2007-01-27 \created 2007-01-27
@edited 2007-07-20 \edited 2013-04-09
*/ */
#ifndef G3D_enumclass_h #ifndef G3D_enumclass_h
#define G3D_enumclass_h #define G3D_enumclass_h
#include "G3D/platform.h"
#include "G3D/HashTrait.h" #include "G3D/HashTrait.h"
#include "G3D/BinaryInput.h" #include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.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 \def G3D_DECLARE_ENUM_CLASS_METHODS
\brief Creates a series of methods that turn a class into a scoped enumeration. \brief Creates a series of methods that turn a class into a scoped enumeration.
Uses the "Intelligent Enum" design pattern Example of use:
http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4001/
Enum classes are initialized to their zero value by default. \code
class Resource {
public:
enum Value {FUEL, FOOD, WATER} value;
You must implement the following method before calling G3D_DECLARE_ENUM_CLASS_METHODS, as either: // i is the position the enum value in Value (not the enum value itself)
<pre>
static const char* toString(int i, Value& v) { static const char* toString(int i, Value& v) {
static const char* str[] = {"FUEL", "FOOD", "WATER", NULL}; // Whatever your enum values are 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 static const Value val[] = {FUEL, FOOD, WATER}; // Whatever your enum values are
@@ -34,29 +43,42 @@
} }
return s; return s;
} }
</pre>
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 \sa G3D_DECLARE_ENUM_CLASS_HASHCODE
*/ */
#define G3D_DECLARE_ENUM_CLASS_METHODS(Classname)\ #define G3D_DECLARE_ENUM_CLASS_METHODS(Classname)\
private: \ private: \
void fromString(const std::string& x) {\ void fromString(const std::string& x) {\
Value v;\ Value v = (Value)0;\
const char* s;\ const char* s;\
int i = 0;\ int i = 0;\
\ \
do {\ do {\
s = toString(i, v);\ s = toString(i, v);\
if (s == NULL) { return; /** Needed to get correct compilation on gcc */ } \
if (x == s) {\ if (x == s) {\
value = v;\ value = v;\
return;\ return;\
}\ }\
++i;\ ++i;\
} while (s);\ } while (true);\
}\ }\
\ \
public:\ public:\
static const char* classname() {\
return #Classname;\
}\
\ \
const char* toString() const {\ const char* toString() const {\
const char* s;\ const char* s;\
@@ -69,37 +91,36 @@ public:\
}\ }\
++i;\ ++i;\
}\ }\
return NULL;\
}\ }\
\ \
explicit Classname(const std::string& x) : value((Value)0) {\ explicit Classname(const std::string& x) : value((Value)0) {\
fromString(x);\ fromString(x);\
}\ }\
\ \
Classname(const Any& a) : value((Value)0) {\ explicit Classname(const G3D::Any& a) : value((Value)0) { \
fromString(a.string());\ fromString(a.string());\
}\ }\
\ \
operator Any() const {\ G3D::Any toAny() const { \
return Any(toString());\ return G3D::Any(toString()); \
}\ }\
\ \
Classname(char v) : value((Value)v) {}\ explicit Classname(char v) : value((Value)v) {}\
\ \
Classname() : value((Value)0) {}\ Classname() : value((Value)0) {}\
\ \
Classname(const Value v) : value(v) {}\ Classname(const Value v) : value(v) {}\
\ \
explicit Classname(int v) : value((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 {\ operator int() const {\
return (int)value;\ return (int)value;\
}\ }\
\
Classname& operator=(const Any& a) {\
value = Classname(a).value;\
return *this;\
}\
\ \
bool operator== (const Classname other) const {\ bool operator== (const Classname other) const {\
return value == other.value;\ return value == other.value;\
@@ -181,15 +202,16 @@ public:\
return (unsigned int)value;\ return (unsigned int)value;\
}\ }\
\ \
void serialize(BinaryOutput& b) const {\ void serialize(G3D::BinaryOutput& b) const { \
b.writeInt32(value);\ b.writeInt32(value);\
}\ }\
\ \
void deserialize(BinaryInput& b) {\ void deserialize(G3D::BinaryInput& b) { \
value = (Value)b.readInt32();\ value = (Value)b.readInt32();\
} }
/** \def G3D_DECLARE_ENUM_CLASS_HASHCODE /** \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)\ #define G3D_DECLARE_ENUM_CLASS_HASHCODE(Classname)\
template <> struct HashTrait<Classname::Value> \ template <> struct HashTrait<Classname::Value> \
@@ -202,4 +224,108 @@ template <> struct HashTrait<Classname>
static size_t hashCode(Classname key) { return static_cast<size_t>(key.hashCode()); } \ static size_t hashCode(Classname key) { return static_cast<size_t>(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<WrapMode, WrapMode::Value>(t);
t.commit();
\endcode
*/
template<class EnumClass, class EnumClassValue>
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 #endif

View File

@@ -4,9 +4,9 @@
@maintainer Morgan McGuire, http://graphics.cs.williams.edu @maintainer Morgan McGuire, http://graphics.cs.williams.edu
@author 2002-06-06 @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. All rights reserved.
*/ */
@@ -20,42 +20,16 @@
#include "G3D/Set.h" #include "G3D/Set.h"
#include "G3D/g3dmath.h" #include "G3D/g3dmath.h"
#ifdef G3D_WIN32 #ifdef G3D_WINDOWS
// For chdir, mkdir, etc. // For chdir, mkdir, etc.
# include <direct.h> # include <direct.h>
#endif #endif
namespace G3D { namespace G3D {
namespace _internal { /** Returns the contents of a text file as a single string */
extern Set<std::string> currentFilesUsed; std::string readWholeFile
} (const std::string& filename);
/** Returns all the files used by G3D and GLG3D during the current execution. */
Array<std::string> 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);
/** /**

View File

@@ -42,7 +42,7 @@
namespace G3D { namespace G3D {
#if defined(G3D_WIN32) #if defined(G3D_WINDOWS)
# if ! defined(FNM_NOMATCH) # if ! defined(FNM_NOMATCH)
# define FNM_NOMATCH 1 /* Match failed. */ # define FNM_NOMATCH 1 /* Match failed. */

View File

@@ -7,9 +7,9 @@
@cite highestBit by Jukka Liimatta @cite highestBit by Jukka Liimatta
@created 2001-06-02 @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. All rights reserved.
*/ */
@@ -29,8 +29,9 @@
#include <float.h> #include <float.h>
#include <limits> #include <limits>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#ifdef _MSC_VER #if defined(_MSC_VER) && (_MSC_VER < 1000)
// Visual Studio is missing inttypes.h // Visual Studio is missing inttypes.h
# ifndef PRId64 # ifndef PRId64
# define PRId64 "I64d" # define PRId64 "I64d"
@@ -58,6 +59,16 @@
#undef min #undef min
#undef max #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 { namespace G3D {
#ifdef _MSC_VER #ifdef _MSC_VER
@@ -65,8 +76,8 @@ inline double __fastcall drand48() {
return ::rand() / double(RAND_MAX); return ::rand() / double(RAND_MAX);
} }
#if !defined(_WIN64) # ifdef _M_IX86
// 32-bit
/** /**
Win32 implementation of the C99 fast rounding routines. Win32 implementation of the C99 fast rounding routines.
@@ -80,6 +91,7 @@ inline double __fastcall drand48() {
provided "as is" without express or implied warranty. provided "as is" without express or implied warranty.
*/ */
__inline long int lrint (double flt) { __inline long int lrint (double flt) {
int intgr; int intgr;
@@ -101,23 +113,24 @@ __inline long int lrintf(float flt) {
return intgr; return intgr;
} }
# else # else
// 64-bit
__inline long int lrint (double flt) {
return (long int)floor(flt+0.5f);
}
__inline long int lrintf(float flt) { __inline long int lrintf(float flt) {
return (long int)floorf(flt+0.5f); return (long int)(flt + 0.5f);
}
__inline long int lrint (double flt) {
return (long int)(flt + 0.5);
} }
# endif # endif
#endif #endif
#define fuzzyEpsilon (0.00001f) #define fuzzyEpsilon64 (0.0000005)
#define fuzzyEpsilon32 (0.00001f)
/** /**
This value should not be tested against directly, instead This value should not be tested against directly, instead
G3D::isNan() and G3D::isFinite() will return reliable results. */ G3D::isNan() and G3D::isFinite() will return reliable results. */
@@ -147,23 +160,14 @@ inline double twoPi() {
return 6.28318531; return 6.28318531;
} }
typedef signed char int8; typedef int8_t int8;
typedef unsigned char uint8; typedef uint8_t uint8;
typedef short int16; typedef int16_t int16;
typedef unsigned short uint16; typedef uint16_t uint16;
typedef int int32; typedef int32_t int32;
typedef unsigned int uint32; typedef uint32_t uint32;
#ifdef _MSC_EXTENSIONS
typedef __int64 int64;
typedef unsigned __int64 uint64;
#elif ! defined(_MSC_VER)
typedef int64_t int64; typedef int64_t int64;
typedef uint64_t uint64; typedef uint64_t uint64;
#else
typedef long long int64;
typedef unsigned long long uint64;
#endif
typedef float float32; typedef float float32;
typedef double float64; typedef double float64;
@@ -207,6 +211,13 @@ inline int iSign(float f) {
return iSign((double)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. Fast round to integer using the lrint routine.
@@ -256,6 +267,11 @@ inline bool isNaN(int x) {
return false; return false;
} }
inline bool isNaN(uint64 x) {
(void)x;
return false;
}
/** /**
Computes x % 3. Computes x % 3.
*/ */
@@ -339,6 +355,7 @@ int highestBit(uint32 x);
*/ */
bool fuzzyEq(double a, double b); bool fuzzyEq(double a, double b);
/** True if a is definitely not equal to b. /** True if a is definitely not equal to b.
Guaranteed false if a == b. Guaranteed false if a == b.
Possibly false when a != b.*/ Possibly false when a != b.*/
@@ -393,6 +410,7 @@ inline double log2(int x) {
* True if num is a power of two. * True if num is a power of two.
*/ */
bool isPow2(int num); bool isPow2(int num);
bool isPow2(uint64 num);
bool isOdd(int num); bool isOdd(int num);
bool isEven(int num); bool isEven(int num);
@@ -455,7 +473,7 @@ inline double rsqrt(double x) {
/** @deprecated Use rsq */ /** @deprecated Use rsq */
inline float rsqrt(float x) { inline float rsqrt(float x) {
// TODO: default this to using the SSE2 instruction // TODO: default this to using the SSE2 instruction
return 1.0 / sqrtf(x); return 1.0f / sqrtf(x);
} }
/** /**
@@ -759,6 +777,16 @@ inline bool isPow2(int num) {
return ((num & -num) == 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) { inline bool isOdd(int num) {
return (num & 1) == 1; return (num & 1) == 1;
} }
@@ -801,12 +829,31 @@ inline double eps(double a, double b) {
(void)b; (void)b;
const double aa = abs(a) + 1.0; const double aa = abs(a) + 1.0;
if (aa == inf()) { if (aa == inf()) {
return fuzzyEpsilon; return fuzzyEpsilon64;
} else { } 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) { inline bool fuzzyEq(double a, double b) {
return (a == b) || (abs(a - b) <= eps(a, 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); 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
namespace std {
inline int pow(int a, int b) {
return (int)::pow(double(a), double(b));
}
}
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning (pop) # pragma warning (pop)
#endif #endif

View File

@@ -3,7 +3,7 @@
#include "G3D/platform.h" #include "G3D/platform.h"
#ifdef G3D_WIN32 #ifdef G3D_WINDOWS
# if (G3D_WINSOCK_MAJOR_VERSION == 2) # if (G3D_WINSOCK_MAJOR_VERSION == 2)
# include <winsock2.h> # include <winsock2.h>
# elif (G3D_WINSOCK_MAJOR_VERSION == 1) # elif (G3D_WINSOCK_MAJOR_VERSION == 1)

View File

@@ -85,7 +85,7 @@
#ifndef _SOCKLEN_T #ifndef _SOCKLEN_T
# if defined(G3D_WIN32) || defined(G3D_OSX) # if defined(G3D_WINDOWS) || defined(G3D_OSX)
typedef int socklen_t; typedef int socklen_t;
# endif # endif
#endif #endif

View File

@@ -1,22 +1,26 @@
/** /**
@file platform.h \file platform.h
\#defines for platform specific issues. \#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 Copyright 2000-2012, Morgan McGuire.
@edited 2010-08-11 All rights reserved.
\created 2003-06-09
\edited 2013-01-03
*/ */
#ifndef G3D_platform_h #ifndef G3D_platform_h
#define G3D_platform_h #define G3D_platform_h
/** /**
\def G3D_VER
The version number of G3D in the form: MmmBB -> The version number of G3D in the form: MmmBB ->
version M.mm [beta BB] version M.mm [beta BB]
*/ */
#define G3D_VER 80100 #define G3D_VER 90000
// fatal error for unsupported architectures // fatal error for unsupported architectures
#if defined(__powerpc__) #if defined(__powerpc__)
@@ -31,13 +35,15 @@
# undef _DEBUG # undef _DEBUG
#endif #endif
/** @def G3D_DEBUG() /** \def G3D_DEBUG
Defined if G3D is built in debug mode. */ Defined if G3D is built in debug mode. */
#if !defined(G3D_DEBUG) && (defined(_DEBUG) || defined(G3D_DEBUGRELEASE)) #if !defined(G3D_DEBUG) && (defined(_DEBUG) || defined(G3D_DEBUGRELEASE))
# define G3D_DEBUG # define G3D_DEBUG
#endif #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 2.0 is standard for G3D 6.09 and later.
Version 1.1 is standard for G3D 6.08 and earlier. Version 1.1 is standard for G3D 6.08 and earlier.
*/ */
@@ -49,10 +55,15 @@
#define __fastcall #define __fastcall
#endif #endif
/** \def G3D_WINDOWS*/
/** \def G3D_FREEBSD2*/
/** \def G3D_LINUX*/
/** \def G3D_OSX */
#ifdef _MSC_VER #ifdef _MSC_VER
#define G3D_WIN32 # define G3D_WINDOWS
#elif defined(__MINGW32__) #elif defined(__MINGW32__)
#define G3D_WIN32 #define G3D_WINDOWS
#undef __MSVCRT_VERSION__ #undef __MSVCRT_VERSION__
#define __MSVCRT_VERSION__ 0x0601 #define __MSVCRT_VERSION__ 0x0601
#include <windows.h> #include <windows.h>
@@ -61,8 +72,6 @@
#define G3D_LINUX #define G3D_LINUX
#elif defined(__linux__) #elif defined(__linux__)
#define G3D_LINUX #define G3D_LINUX
#elif defined(__CYGWIN__)
#define G3D_LINUX
#elif defined(__APPLE__) #elif defined(__APPLE__)
#define G3D_LINUX #define G3D_LINUX
@@ -73,22 +82,23 @@
#error Unknown platform #error Unknown platform
#endif #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 // Detect 64-bit under various compilers
#if (defined(_M_X64) || defined(_WIN64) || defined(__LP64__) || defined(_LP64)) #if (defined(_M_X64) || defined(_WIN64) || defined(__LP64__) || defined(_LP64))
# define G3D_64BIT # define G3D_64BIT
#if defined(WIN32)
#include <intrin.h>
#endif
#else #else
# define G3D_32BIT # define G3D_32BIT
#endif #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 // Verify that the supported compilers are being used and that this is a known
// processor. // processor.
@@ -96,6 +106,7 @@
# ifndef __GNUC__ # ifndef __GNUC__
# error G3D only supports the gcc compiler on Linux. # error G3D only supports the gcc compiler on Linux.
# endif # endif
# define G3D_NO_FFMPEG
#endif #endif
#ifdef G3D_OSX #ifdef G3D_OSX
@@ -115,6 +126,8 @@
#ifdef _MSC_VER #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++ 8.0 ("Express") = 1400
// Microsoft Visual C++ 7.1 ("2003") _MSC_VER = 1310 // Microsoft Visual C++ 7.1 ("2003") _MSC_VER = 1310
// Microsoft Visual C++ 7.0 ("2002") _MSC_VER = 1300 // Microsoft Visual C++ 7.0 ("2002") _MSC_VER = 1300
@@ -128,8 +141,16 @@
// for debug assertions in inlined methods. // for debug assertions in inlined methods.
# pragma warning (disable : 4127) # pragma warning (disable : 4127)
/** @def G3D_DEPRECATED() /** \def G3D_DEPRECATED()
Creates deprecated warning. */ 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) # define G3D_DEPRECATED __declspec(deprecated)
// Prevent Winsock conflicts by hiding the winsock API // Prevent Winsock conflicts by hiding the winsock API
@@ -140,8 +161,6 @@
// Disable 'name too long for browse information' warning // Disable 'name too long for browse information' warning
# pragma warning (disable : 4786) # pragma warning (disable : 4786)
// TODO: remove
# pragma warning (disable : 4244)
# define restrict # define restrict
@@ -187,27 +206,10 @@
#endif #endif
#ifdef _DEBUG #ifdef _DEBUG
#pragma comment (linker, "/NODEFAULTLIB:LIBCMTD.LIB") // Some of the support libraries are always built in Release.
#pragma comment (linker, "/NODEFAULTLIB:LIBCPMTD.LIB") // Make sure the debug runtime library is linked in
#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") #pragma comment(linker, "/NODEFAULTLIB:MSVCRT.LIB")
#pragma comment(linker, "/NODEFAULTLIB:MSVCPRT.LIB")
#endif #endif
@@ -215,8 +217,9 @@
# define WIN32_LEAN_AND_MEAN 1 # define WIN32_LEAN_AND_MEAN 1
# endif # endif
# ifndef NOMINMAX
# define NOMINMAX 1 # define NOMINMAX 1
# endif
# ifndef _WIN32_WINNT # ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0500 # define _WIN32_WINNT 0x0500
# endif # endif
@@ -230,8 +233,9 @@
# endif # endif
/** @def G3D_START_AT_MAIN() /** \def G3D_START_AT_MAIN()
Defines necessary wrapper around WinMain on Windows to allow transfer of execution to 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()\ # define G3D_START_AT_MAIN()\
int WINAPI G3D_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw);\ int WINAPI G3D_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw);\
int WINAPI 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)) # define __stdcall __attribute__((stdcall))
# endif # endif
# elif defined(__x86_64__) # elif defined(__x86_64__) || defined(__arm) || defined(__aarch64__)
# ifndef __cdecl # ifndef __cdecl
# define __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 Creates a string from the expression. Frequently used with G3D::Shader
to express shading programs inline. 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) # define PRAGMA(x) _Pragma(#x)
#endif #endif
/** @def G3D_BEGIN_PACKED_CLASS(byteAlign) /** \def G3D_BEGIN_PACKED_CLASS(byteAlign)
Switch to tight alignment 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.*/ See G3D::Color3uint8 for an example.*/
#ifdef _MSC_VER #ifdef __GNUC__
# define G3D_BEGIN_PACKED_CLASS(byteAlign) PRAGMA( pack(push, byteAlign) ) # 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 #else
# define G3D_BEGIN_PACKED_CLASS(byteAlign) # define G3D_BEGIN_PACKED_CLASS(byteAlign) class
#endif #endif
/** @def G3D_END_PACKED_CLASS(byteAlign) /** \def G3D_END_PACKED_CLASS(byteAlign)
End switch to tight alignment End switch to tight alignment
See G3D::Color3uint8 for an example.*/ See G3D::Color3uint8 for an example.*/
#ifdef _MSC_VER #ifdef __GNUC__
# define G3D_END_PACKED_CLASS(byteAlign) ; PRAGMA( pack(pop) )
#elif defined(__GNUC__)
# define G3D_END_PACKED_CLASS(byteAlign) __attribute((aligned(byteAlign))) ; # define G3D_END_PACKED_CLASS(byteAlign) __attribute((aligned(byteAlign))) ;
#elif defined(_MSC_VER)
# define G3D_END_PACKED_CLASS(byteAlign) ; PRAGMA( pack(pop) )
#else #else
# define G3D_END_PACKED_CLASS(byteAlign) ; # define G3D_END_PACKED_CLASS(byteAlign) ;
#endif #endif
// Header guard // Bring in shared_ptr and weak_ptr
#if (defined(__GNUC__) && defined(__APPLE__)) || defined(__linux__)
#include <ciso646> // Defines _LIBCC_VERSION if linking against libc++ or does nothing
#endif #endif
#if (!defined(_LIBCPP_VERSION) && defined(__APPLE__)) || (!defined(_LIBCPP_VERSION) && defined(__linux__))
# include <tr1/memory>
#else
# include <memory>
#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

View File

@@ -1,13 +1,63 @@
#ifndef G3D_SERIALIZE_H #ifndef G3D_serialize_h
#define G3D_SERIALIZE_H #define G3D_serialize_h
#include "G3D/BinaryInput.h" #include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h" #include "G3D/BinaryOutput.h"
#include "G3D/Array.h" #include "G3D/Array.h"
#include <string>
namespace G3D { 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<typename T> template<typename T>
void serialize(const Array<T>& array, BinaryOutput& b) { void serialize(const Array<T>& array, BinaryOutput& b) {
b.writeInt32(array.size()); b.writeInt32(array.size());
@@ -25,6 +75,6 @@ void deserialize(Array<T>& array, BinaryInput& b) {
} }
} }
} } // G3D
#endif #endif //G3D_serialize_h

View File

@@ -31,53 +31,72 @@ void parseCommaSeparated(const std::string s, Array<std::string>& array, bool st
/** Finds the index of the first '\\' or '/' character, starting at index \a start. /** Finds the index of the first '\\' or '/' character, starting at index \a start.
\sa G3D::findLastSlash, G3D::isSlash \sa G3D::findLastSlash, G3D::isSlash
*/ */
inline int findSlash(const std::string& f, int start = 0) { inline size_t findSlash(const std::string& f, size_t start = 0) {
int i = f.find('/', start); size_t i = f.find('/', start);
int j = f.find('\\', start); size_t j = f.find('\\', start);
if (((i != -1) && (i < j)) || (j == -1)) { if ((i != std::string::npos) && (i < j)) {
return i; return i;
} else { } else {
return j; 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). /** 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 \sa G3D::findSlash, G3D::isSlash
*/ */
inline int findLastSlash(const std::string& f, int start = -1) { inline size_t findLastSlash(const std::string& f, size_t start = std::string::npos) {
if (start == -1) { if (start == std::string::npos) {
start = f.length() - 1; start = f.length() - 1;
} }
int i = f.rfind('/', start); size_t i = f.rfind('/', start);
int j = f.rfind('\\', start); size_t j = f.rfind('\\', start);
return max(i, j); 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( bool beginsWith
const std::string& test, (const std::string& test,
const std::string& pattern); 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( bool endsWith
const std::string& test, (const std::string& test,
const std::string& pattern); 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 wrapped at a certain number of columns (where
the line is broken at the latest space before the the line is broken at the latest space before the
column limit.) Platform specific NEWLINEs column limit.) Platform specific NEWLINEs
are inserted to wrap. are inserted to wrap.
\sa G3D::GFont::wordWrapCut, G3D::TextOutput::Settings::WordWrapMode
*/ */
std::string wordWrap( std::string wordWrap
const std::string& input, (const std::string& input,
int numCols); int numCols);
/** /**
@@ -161,6 +180,17 @@ inline bool isQuote(const unsigned char c) {
return (c == '\'') || (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 }; // namespace
#endif #endif

View File

@@ -44,7 +44,6 @@ public:
uint128& operator<<=(const int x); uint128& operator<<=(const int x);
uint128 operator&(const uint128& x); uint128 operator&(const uint128& x);
}; };
} }

View File

@@ -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 \created 2009-08-21
@edited 2009-08-21 \edited 2011-07-08
*/ */
#ifndef G3D_units_h #ifndef G3D_units_h
#define G3D_units_h #define G3D_units_h
@@ -46,7 +46,7 @@ inline float meters() {
/** 1000 m */ /** 1000 m */
inline float kilometers() { inline float kilometers() {
return 100.0f; return 1000.0f;
} }
/** 0.0254 m */ /** 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 #endif

Some files were not shown because too many files have changed in this diff Show More