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
source/AABox.cpp
source/Any.cpp
source/AnyTableReader.cpp
source/BinaryFormat.cpp
source/BinaryInput.cpp
source/BinaryOutput.cpp
@@ -26,6 +27,7 @@ set(g3dlib_STAT_SRCS
source/format.cpp
source/g3dfnmatch.cpp
source/g3dmath.cpp
source/GThread.cpp
source/Line.cpp
source/LineSegment.cpp
source/Log.cpp
@@ -38,7 +40,6 @@ set(g3dlib_STAT_SRCS
source/Quat.cpp
source/Random.cpp
source/Ray.cpp
source/ReferenceCount.cpp
source/RegistryUtil.cpp
source/Sphere.cpp
source/stringutils.cpp
@@ -55,9 +56,6 @@ set(g3dlib_STAT_SRCS
add_library(g3dlib STATIC ${g3dlib_STAT_SRCS})
# Group sources
GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(g3dlib
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include)
@@ -70,6 +68,6 @@ target_link_libraries(g3dlib
threads)
set_target_properties(g3dlib
PROPERTIES
FOLDER
"deps")
PROPERTIES
FOLDER
"deps")

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_hotfix7.diff - 2013-08-31 - fix typo in Matrix4 == operator
G3D-v8.0_hotfix8.diff - 2013-09-01 - fix typo in Vector3int32 += operator
G3D-v8.0_hotfix9.diff - 2014-06-01 - only VS < 10 don't ship inttypes.h
G3D-v9.0 hotfix1.diff - 2014-08-22 - updated to G3D9, reapplied previous patches and removed unneeded changes
G3D-v9.0 hotfix2.diff - 2014-08-23 - fix some -Wconversion warnings
G3D-v9.0 hotfix3.diff - 2015-06-28 - fix some warnings
G3D-v9.0 hotfix4.diff - 2015-07-02 - backport G3D10 fix
G3D-v9.0 hotfix5.diff - 2015-07-31 - fix MSVC 2015 warning: dep/g3dlite/include/G3D/Quat.h(352): warning C4458: declaration of 'x' hides class member
G3D-v9.0 hotfix6.diff - 2015-11-04 - fix adding std::shared_ptr, std::weak_ptr, std::dynamic_pointer_cast, std::static_pointer_cast and std::enable_shared_from_this to global namespace
G3D-v9.0 hotfix7.diff - 2016-10-10 - fix warning on clang 3.8 backported from G3D 10

View File

@@ -1,29 +1,31 @@
/**
@file AABox.h
\file G3D/AABox.h
Axis-aligned box class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2004-01-10
@edited 2009-02-10
\created 2004-01-10
\edited 2013-04-13
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2013, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_AABOX_H
#define G3D_AABOX_H
#ifndef G3D_AABox_h
#define G3D_AABox_h
#include "G3D/platform.h"
#include "G3D/Vector3.h"
#include "G3D/debug.h"
#include "G3D/Array.h"
#include "G3D/Plane.h"
#include "G3D/Sphere.h"
#include "G3D/Vector3.h"
namespace G3D {
class Any;
/**
An axis-aligned box.
*/
@@ -34,66 +36,109 @@ private:
/** Optional argument placeholder */
static int dummy;
Vector3 lo;
Vector3 hi;
/** NaN if empty */
Point3 lo;
/** NaN if empty */
Point3 hi;
public:
/** Does not initialize the fields */
inline AABox() {}
/** Creates the empty bounds, i.e., an empty set of points. */
AABox() : lo(fnan(), fnan(), fnan()), hi(fnan(), fnan(), fnan()) {}
/**
Constructs a zero-area AABox at v.
Constructs a zero-volume AABox at v.
*/
inline explicit AABox(const Vector3& v) {
explicit AABox(const Point3& v) {
lo = hi = v;
}
/** Format is one of:
- AABox(lowpoint, highpoint)
- AABox(point)
- AABox::empty()
- AABox::inf()
*/
explicit AABox(const class Any& a);
Any toAny() const;
bool isEmpty() const {
return lo.isNaN();
}
/** Assumes that low is less than or equal to high along each dimension.
To have this automatically enforced, use
<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);
}
AABox operator*(float f) const {
if (f < 0) {
return AABox(hi * f, lo * f);
} else {
return AABox(lo * f, hi * f);
}
}
AABox operator/(float f) const {
return *this * (1.0f / f);
}
/** Assumes that low is less than or equal to high along each dimension.
*/
inline void set(const Vector3& low, const Vector3& high) {
inline void set(const Point3& low, const Point3& high) {
debugAssert(
(low.x <= high.x) &&
(low.y <= high.y) &&
(low.z <= high.z));
debugAssert(! low.isNaN() && ! high.isNaN());
lo = low;
hi = high;
}
/**
Grows to include the bounds of a
Grows to include the bounds of \a a
*/
inline void merge(const AABox& a) {
lo = lo.min(a.lo);
hi = hi.max(a.hi);
if (isEmpty()) {
lo = a.lo;
hi = a.hi;
} else if (! a.isEmpty()) {
lo = lo.min(a.lo);
hi = hi.max(a.hi);
}
}
inline void merge(const Vector3& a) {
lo = lo.min(a);
hi = hi.max(a);
inline void merge(const Point3& a) {
if (isEmpty()) {
lo = hi = a;
} else {
lo = lo.min(a);
hi = hi.max(a);
}
}
void merge(const class Box& b);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
inline bool isFinite() const {
return lo.isFinite() && hi.isFinite();
return isEmpty() || (lo.isFinite() && hi.isFinite());
}
inline const Vector3& low() const {
/** Returns not-a-number if empty */
inline const Point3& low() const {
return lo;
}
inline const Vector3& high() const {
/** Returns not-a-number if empty */
inline const Point3& high() const {
return hi;
}
@@ -110,25 +155,33 @@ public:
static const AABox& zero();
static const AABox& empty();
/**
Returns the centroid of the box.
Returns the centroid of the box (NaN if empty)
*/
inline Vector3 center() const {
inline Point3 center() const {
return (lo + hi) * 0.5;
}
Vector3 corner(int index) const;
Point3 corner(int index) const;
/**
Distance from corner(0) to the next corner along axis a.
*/
inline float extent(int a) const {
if (isEmpty()) {
return 0.0f;
}
debugAssert(a < 3);
return hi[a] - lo[a];
}
inline Vector3 extent() const {
if (isEmpty()) {
return Vector3::zero();
}
return hi - lo;
}
@@ -140,46 +193,46 @@ public:
*/
void split(const Vector3::Axis& axis, float location, AABox& low, AABox& high) const;
/**
Conservative culling test for up to 32 planes.
Returns true if there exists a <CODE>plane[p]</CODE> for
/**
Conservative culling test for up to 32 planes.
Returns true if there exists a <CODE>plane[p]</CODE> for
which the entire object is in the negative half space
(opposite the plane normal).
<CODE>testMask</CODE> and <CODE>childMask</CODE>
are used for optimizing bounding volume hierarchies.
<CODE>testMask</CODE> and <CODE>childMask</CODE>
are used for optimizing bounding volume hierarchies.
The version of this method that produces childMask
is slower than the version without; it should only
be used for parent nodes.
@param cullingPlaneIndex The index of the first plane for which
the entire object is in the negative half-space. The function
exits early when one plane is found. -1 when the function
returns false (i.e. when no plane culls the whole object).
@param cullingPlaneIndex The index of the first plane for which
the entire object is in the negative half-space. The function
exits early when one plane is found. -1 when the function
returns false (i.e. when no plane culls the whole object).
@param testMask If bit <I>p</I> is 0, the
bounding volume automatically passes the culling test for
<CODE>plane[p]</CODE> (i.e. it is known that the volume
is entirely within the positive half space). The function
@param testMask If bit <I>p</I> is 0, the
bounding volume automatically passes the culling test for
<CODE>plane[p]</CODE> (i.e. it is known that the volume
is entirely within the positive half space). The function
must return false if testMask is 0 and test all planes
when testMask is -1 (0xFFFFFFFF).
@param childMask Test mask for the children of this volume.
*/
bool culledBy(
const Array<Plane>& plane,
int32& cullingPlaneIndex,
const uint32 testMask,
uint32& childMask) const;
*/
bool culledBy
(const Array<Plane>& plane,
int32& cullingPlaneIndex,
const uint32 testMask,
uint32& childMask) const;
/**
Conservative culling test that does not produce a mask for children.
*/
bool culledBy(
const Array<Plane>& plane,
int32& cullingPlaneIndex = dummy,
const uint32 testMask = 0xFFFFFFFF) const;
bool culledBy
(const Array<Plane>& plane,
int32& cullingPlaneIndex = dummy,
const uint32 testMask = 0xFFFFFFFF) const;
/** less than or equal to containment */
inline bool contains(const AABox& other) const {
@@ -192,8 +245,7 @@ public:
(other.lo.z >= lo.z);
}
inline bool contains(
const Vector3& point) const {
inline bool contains(const Point3& point) const {
return
(point.x >= lo.x) &&
(point.y >= lo.y) &&
@@ -204,31 +256,42 @@ public:
}
inline float area() const {
if (isEmpty()) { return 0; }
Vector3 diag = hi - lo;
return 2.0f * (diag.x * diag.y + diag.y * diag.z + diag.x * diag.z);
}
inline float volume() const {
if (isEmpty()) { return 0; }
Vector3 diag = hi - lo;
return diag.x * diag.y * diag.z;
}
Vector3 randomInteriorPoint() const;
Point3 randomInteriorPoint() const;
Vector3 randomSurfacePoint() const;
Point3 randomSurfacePoint() const;
/** Returns true if there is any overlap */
bool intersects(const AABox& other) const;
/** Returns true if there is any overlap.
@cite Jim Arvo's algorithm from Graphics Gems II*/
bool intersects(const class Sphere& other) const;
bool intersects(const Sphere& other) const;
/** Return the intersection of the two boxes */
AABox intersect(const AABox& other) const {
Vector3 H = hi.min(other.hi);
Vector3 L = lo.max(other.lo).min(H);
return AABox(L, H);
if (isEmpty() || other.isEmpty()) {
return empty();
}
const Point3& H = hi.min(other.hi);
const Point3& L = lo.max(other.lo).min(H);
if (H.x < L.x && H.y < L.y && H.z < L.z) {
return empty();
} else {
return AABox(L, H);
}
}
inline size_t hashCode() const {
@@ -236,11 +299,19 @@ public:
}
inline bool operator==(const AABox& b) const {
return (lo == b.lo) && (hi == b.hi);
if (isEmpty() && b.isEmpty()) {
return true;
} else {
return (lo == b.lo) && (hi == b.hi);
}
}
inline bool operator!=(const AABox& b) const {
return !((lo == b.lo) && (hi == b.hi));
if (isEmpty()) {
return b.isEmpty();
} else {
return !((lo == b.lo) && (hi == b.hi));
}
}
inline AABox operator+(const Vector3& v) const {

View File

@@ -1,13 +1,13 @@
/**
@file Any.h
\file Any.h
@author Morgan McGuire, Shawn Yarbrough, and Corey Taylor
@maintainer Morgan McGuire
\author Morgan McGuire, Shawn Yarbrough, and Corey Taylor
\maintainer Morgan McGuire
@created 2006-06-11
@edited 2010-03-16
\created 2006-06-11
\edited 2013-03-29
Copyright 2000-2010, Morgan McGuire.
Copyright 2000-2013, Morgan McGuire.
All rights reserved.
*/
@@ -17,13 +17,13 @@
#include "G3D/platform.h"
#include "G3D/Table.h"
#include "G3D/Array.h"
#include "G3D/Set.h"
#include "G3D/AtomicInt32.h"
#include "G3D/stringutils.h"
#include <string>
// needed for Token
#include "G3D/TextInput.h"
#include "G3D/TextOutput.h"
#ifdef verify
#undef verify
@@ -38,7 +38,8 @@ class TextOutput;
Any encodes typed, structured data and can serialize it to a human
readable format that is very similar to the Python language's data
syntax. It is well-suited for quickly creating human-readable file
syntax, and fully supports Python's data syntax as well.
It is well-suited for quickly creating human-readable file
formats, especially since deserialization and serialization preserve
comments and an Any can tell you what file and line it came from. The
syntax allows most C++ editors to properly highlight Any files, and
@@ -61,7 +62,7 @@ Sample File:
position = Vector3(1.0, -1.0, 0.0),
video = { format = "RGB8", size = (320, 200)},
material = #include("rocks.mat")
material = \#include("rocks.mat")
}
</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
chosen over formats like XML, YAML, JSON, S-expressions, and Protocol
Buffers, although there is no reason you could not write readers and
writers for G3D::Any that support those.
writers for G3D::Any that support those. Any also currently supports
the JSON format.
G3D::Any assumes that structures do not contain cycles; it is an
error to create a structure like:
@@ -91,6 +93,17 @@ x.array().append(x); // don't do this!
although no exception will be thrown at runtime during that append.
\section includes
When parsing an Any from a file, the syntax
<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
@@ -117,24 +130,12 @@ Vector3::Vector3(const Any& any) {
}
</pre>
It is often convenient to iterate through the table portion:
<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>
It is often convenient to iterate through the table portion using G3D::AnyTableReader.
\section BNF
Serialized format BNF:
\htmlonly
<pre>
identifier ::= (letter | "_") (letter | digit | "_")*
identifier-op ::= "::" | "->" | "."
@@ -145,18 +146,19 @@ comment ::= C++ single or multi-line comments
separator ::= "," | ";"
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"
none ::= "None"
array ::= ("(" | "[") [ value (separator value)* [separator] ] (")" | "]")
pair ::= (identifier | string) "=" value
table ::= "{" [ pair (separator pair)* [separator] ] "}"
nil ::= "Nil" <not case sensitive> | "None" <case sensitive>
array ::= ("(" | "[" | "{") [value (separator value)* [separator] ] (")" | "]" | "}")
pair ::= (identifier | string) ("=" | ":") value
table ::= ("(" | "[" | "{") [ pair (separator pair)* [separator] ] (")" | "]" | "}")
named-array ::= identifier-exp array
named-table ::= identifier-exp table
include ::= "#" "include" "(" string ")"
value ::= [comment] (none | number | boolean | string | array | table | named-array | named-table | include)
value ::= [comment] (nil | number | boolean | string | array | table | named-array | named-table | include)
</pre>
\endhtmlonly
Except for single-line comments, whitespace is not significant.
All parsing is case-insensitive.
@@ -167,7 +169,7 @@ can only appear in the locations where a value is expected. This means
that it cannot yield more than one element of an array and cannot serve
as the pair in a table.
The deserializer allows the substitution of [] for () when writing
The deserializer allows the substitution of [] or {} for () when writing
tuples and ";" for ",". These are convenient when mimicing a
programming language, e.g., <code>"[ printf("hello world."); clearScreen();]"</code>
parses as an array containing two named arrays within it. The
@@ -176,11 +178,13 @@ which also convenient when commenting out the last element.
The serializer indents four spaces for each level of nesting.
Tables are written with the keys in alphabetic order.
\sa G3D::AnyTableReader
*/
class Any {
public:
enum Type {NONE, BOOLEAN, NUMBER, STRING, ARRAY, TABLE};
enum Type {NIL, BOOLEAN, NUMBER, STRING, ARRAY, TABLE, EMPTY_CONTAINER};
static std::string toString(Type t);
@@ -208,7 +212,7 @@ private:
/** Called from deserialize() */
static void deserializeComment(TextInput& ti, Token& token, std::string& comment);
/** NONE, BOOLEAN, and NUMBER are stored directly in the Any */
/** NIL, BOOLEAN, and NUMBER are stored directly in the Any */
union SimpleValue {
bool b;
double n;
@@ -218,6 +222,11 @@ private:
inline SimpleValue(double x) : n(x) {}
};
/** The three options for Data::bracket */
static const char* PAREN;
static const char* BRACKET;
static const char* BRACE;
class Data {
public:
/** ARRAY, TABLE, or STRING value only. NULL otherwise. */
@@ -240,6 +249,16 @@ private:
std::string name;
/** If this Any was created by parsing an #include expression and
has not been modified since, this is the original comment and
include statement, as
it originally appeared in the file (e.g., it may contain a relative
filename). If this is non-empty, then when serialized, this
Any will turn into an #include expression instead of unparsing
its contents of the any.
*/
std::string includeLine;
/** For STRING, ARRAY and TABLE types, m_value is shared between
multiple instances. Mutation is allowed only if the reference
count is exactly 1, otherwise the mutating instance must copy
@@ -249,10 +268,16 @@ private:
Source source;
/** Two-character string of "{}", "[]", or "()"; to be used when unparsing. */
const char* bracket;
/** ';' or ',' separator to be used when unparsing */
char separator;
private:
/** Called by create() */
inline Data(Type t) : type(t), referenceCount(1) {}
inline Data(Type t, const char* b, char s) : type(t), referenceCount(1), bracket(b), separator(s) {}
/** Called by destroy */
~Data();
@@ -261,12 +286,11 @@ private:
/** Clones the argument */
static Data* create(const Data* d);
static Data* create(Type t);
static Data* create(Type t, const char* b = NULL, char s = '\0');
/** Free d, invoking its destructor and freeing the memory for
the value. */
static void destroy(Data* d);
};
/** If not empty, this Any was created from operator[] on a table
@@ -283,12 +307,11 @@ private:
SimpleValue m_simpleValue;
mutable Data* m_data;
/** Called before every read operation to ensure that this object
is not a placeholder. */
/** Called before every read operation. */
void beforeRead() const;
/** Called before every write operation to wipe the placeholder
status. */
/** Called before every write operation to this Any. Wipes the placeholder
status and includedFrom entry. */
void beforeWrite();
/** Decrements the reference count (if there is one). If the
@@ -316,43 +339,61 @@ private:
/** Read the name of a named Array or Table. */
static void deserializeName(TextInput& ti, Token& token, std::string& name);
/** Read until a comma is consumed or a close paren is hit, and
/** Read until a separator is consumed or a close paren is hit, and
return that token. Considers the passed in token to be the first
value read. */
static void readUntilCommaOrClose(TextInput& ti, Token& token);
static void readUntilSeparatorOrClose(TextInput& ti, Token& token);
/** Construct an Any that is a proxy for a table fetch from \a data.
This proxy can be copied exactly once on return from operator[].*/
Any(const std::string& key, Data* data);
inline bool isPlaceholder() const {
bool isPlaceholder() const {
return ! m_placeholderName.empty();
}
void _append(const Any& v0);
void _append(const Any& v0, const Any& v1);
void _append(const Any& v0, const Any& v1, const Any& v2);
void _append(const Any& v0, const Any& v1, const Any& v2, const Any& v3);
Any _get(const std::string& key, const Any& defaultVal) const;
void _set(const std::string& key, const Any& val);
void _parse(const std::string& src);
public:
/** Base class for all Any exceptions.*/
class Exception {
public:
virtual ~Exception() {}
};
/** Thrown by operator[] when a key is not present in a const table. */
class KeyNotFound : public ParseError {
public:
std::string key;
KeyNotFound(const Data* data) {
if (data) {
filename = data->source.filename;
line = data->source.line;
character = data->source.character;
}
}
};
/** Thrown by operator[] when an array index is not present. */
class IndexOutOfBounds : public Exception {
class IndexOutOfBounds : public ParseError {
public:
int index;
int size;
inline IndexOutOfBounds() : index(0), size(0) {}
inline IndexOutOfBounds(int i, int s) : index(i), size(s) {}
IndexOutOfBounds() : index(0), size(0) {}
IndexOutOfBounds(const Data* data, int i, int s) : index(i), size(s) {
if (data) {
filename = data->source.filename;
line = data->source.line;
character = data->source.character;
}
message = format("Index out of bounds: index = %d, array size = %d", i, s);
}
};
/** NONE constructor */
/** NIL constructor */
Any();
/** Deserialize */
@@ -361,108 +402,133 @@ public:
Any(const Any& x);
/** NUMBER constructor */
Any(double x);
explicit Any(double x);
#ifdef G3D_32BIT
/** NUMBER constructor */
Any(int64 x);
#endif // G3D_32BIT
explicit Any(float x);
#if 0
#if defined(G3D_32Bit) || defined(_MSC_VER)
/** NUMBER constructor */
Any(int32 x);
#endif // 0
explicit Any(int64 x) : m_type(NUMBER), m_simpleValue((double)x), m_data(NULL) {}
#endif
/** NUMBER constructor */
Any(long x);
explicit Any(long x);
/** NUMBER constructor */
Any(int x);
explicit Any(int x);
/** NUMBER constructor */
Any(short x);
explicit Any(char x);
/** NUMBER constructor */
explicit Any(short x);
/** BOOLEAN constructor */
Any(bool x);
explicit Any(bool x);
/** STRING constructor */
Any(const std::string& x);
explicit Any(const std::string& x);
/** STRING constructor */
Any(const char* x);
explicit Any(const char* x);
/** \a t must be ARRAY or TABLE
\param brackets must be "" (defaults to {} for table, () for array), "[]", "()", or "{}"
\param separator must be ';', ',', or '\0' (defaults to ',' for array and ';' for table)
*/
explicit Any(Type t, const std::string& name = "", const std::string& brackets = "", const char separator = '\0');
/** Extensible constructor: call the toAny() method of any class. */
template<class T>
explicit Any(const T& v) : m_type(NIL), m_data(NULL) {
*this = v.toAny();
}
/** \a t must be ARRAY or TABLE */
Any(Type t, const std::string& name = "");
~Any();
/** Removes the comment and name */
Any& operator=(const Any& x);
/** Removes the comment and name */
Any& operator=(double x);
/** Removes the comment and name */
Any& operator=(int x);
/** Removes the comment and name */
Any& operator=(bool x);
/** Removes the comment and name */
Any& operator=(const std::string& x);
/** Removes the comment and name */
Any& operator=(const char* x);
/** \a t must be ARRAY, TABLE, or NONE. Removes the comment and name */
/** \a t must be ARRAY, TABLE, or NIL. Removes the comment and name */
Any& operator=(Type t);
/** Assigns from an array. Assumes that T can be converted to Any. Removes the comment and name */
template<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;
/** Same as deserialize or load, but operates on a string instead
of a stream or file.
\sa deserialize, load
\sa deserialize, load, unparse
*/
void parse(const std::string& src);
static Any parse(const std::string& src);
std::string unparse() const;
std::string unparse(const TextOutput::Settings& s = TextOutput::Settings()) const;
/** \param allowCoercion If false, throws an error if the Any uses features that are not
supported by JSON such as named arrays. Otherwise, silently coerces to JSON. */
std::string unparseJSON(const TextOutput::Settings& s = TextOutput::Settings(), bool allowCoercion = true) const;
/** Comments appear before values when they are in serialized form.*/
const std::string& comment() const;
void setComment(const std::string& c);
/** True if this is the NONE value */
bool isNone() const;
/** True if this is the NIL value */
bool isNil() const;
/** Throws a ParseError exception if this is not a number */
double number() const;
float floatValue() const;
const std::string& string() const;
bool boolean() const;
/** If a valid string, takes the string value and creates a fully qualified filename.
If not found, the returned string is empty.
/** If a valid string, takes the string value and creates a fully
qualified filename.
The file is searched for the following ways:
- In the directory from which the Any was loaded.
- By calling System::findDataFile as you would with other data files.
Strings that begin with '<' and end with '>' are treated as
escape sequences and are returned unmodifed.
*/
std::string resolveStringAsFilename() const;
std::string resolveStringAsFilename(bool errorIfNotFound = true) const;
/** If this is named ARRAY or TABLE, returns the name. */
const std::string& name() const;
/** If this is named ARRAY or TABLE, returns true if the name begins with \a s. The comparision is case insensitive. */
/** If this is named ARRAY or TABLE, returns true if the name
begins with \a s. The comparision is case insensitive. */
bool nameBeginsWith(const std::string& s) const;
/** If this is named ARRAY or TABLE, returns true if the name begins with \a s. The comparision is case insensitive. */
/** If this is named ARRAY or TABLE, returns true if the name
begins with \a s. The comparision is case insensitive. */
bool nameBeginsWith(const char* s) const;
/** If this is named ARRAY or TABLE, returns true if the name is \a s. The comparision is case insensitive. */
/** If this is named ARRAY or TABLE, returns true if the name is
\a s. The comparision is case insensitive. */
bool nameEquals(const std::string& s) const;
/** If this is named ARRAY or TABLE, returns true if the name is\a s. The comparision is case insensitive. */
/** If this is named ARRAY or TABLE, returns true if the name is\a
s. The comparision is case insensitive. */
bool nameEquals(const char* s) const;
/** \brief Set the name used when serializing an ARRAY or TABLE.
@@ -504,12 +570,29 @@ public:
/** Directly exposes the underlying data structure for an ARRAY. */
const Array<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;
/** For a table, returns the element for \a key. Throws KeyNotFound
@@ -549,19 +632,25 @@ public:
Any& operator[](const std::string& key);
/** \copydoc Any::operator[](const std::string&) */
Any& operator[](const char* key) {
inline Any& operator[](const char* key) {
return operator[](std::string(key));
}
/** For a table, returns the element for key \a x and \a
defaultVal if it does not exist. */
const Any& get(const std::string& key, const Any& defaultVal) const;
template<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. */
bool containsKey(const std::string& key) const;
/** For a table, assigns the element for key k. */
void set(const std::string& key, const Any& val);
template<class T>
void set(const std::string& key, const T& val) {
_set(key, Any(val));
}
/** for an ARRAY, resizes and returns the last element */
Any& next();
@@ -573,14 +662,64 @@ public:
/** True if the Anys are exactly equal, ignoring comments. Applies deeply on arrays and tables. */
bool operator==(const Any& x) const;
bool operator==(const std::string& s) const {
return *this == Any(s);
}
bool operator==(const double& v) const {
return *this == Any(v);
}
bool operator==(int v) const {
return *this == Any(v);
}
bool operator==(bool v) const {
return *this == Any(v);
}
bool operator!=(const Any& x) const;
bool operator!=(const std::string& s) const {
return *this != Any(s);
}
bool operator!=(const double& v) const {
return *this != Any(v);
}
bool operator!=(int v) const {
return *this != Any(v);
}
bool operator!=(bool v) const {
return *this != Any(v);
}
operator int() const;
operator uint32() const;
operator float() const;
operator double() const;
operator bool() const;
operator std::string() const;
operator char() const {
return char(int(*this));
}
operator uint8() const {
return uint8(int(*this));
}
operator int16() const {
return int16(int(*this));
}
operator uint16() const {
return uint16(int(*this));
}
/** Resize to \a n elements, where new elements are NIL
It is an error to call this method if this is not an Any::ARRAY */
void resize(int n);
@@ -591,33 +730,88 @@ public:
void clear();
/** Parse from a file.
\sa deserialize, parse */
\sa deserialize, parse, fromFile, loadIfExists
*/
void load(const std::string& filename);
/** Load a new Any from \a filename. \sa load, save, loadIfExists */
static Any fromFile(const std::string& filename);
/** Load \a filename file if it exists, otherwise do not modify this */
void loadIfExists(const std::string& filename);
/** Uses the serialize method. */
void save(const std::string& filename) const;
void serialize(TextOutput& to) const;
void serialize(TextOutput& to, bool json = false, bool coerce = false) const;
void serialize(class BinaryOutput& b) const;
/** Parse from a stream.
\sa load, parse */
void deserialize(TextInput& ti);
void deserialize(class BinaryInput& b);
const Source& source() const;
/** Removes this key from the Any, which must be a table. */
void remove(const std::string& key);
/** Removes this key from the Any, which must be an array, and
shifts other elements down to maintain order. */
void remove(int index);
/** Throws a ParseError if \a value is false. Useful for quickly
creating parse rules in classes that deserialize from Any.
*/
void verify(bool value, const std::string& message = "") const;
/** Verifies that the name <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 */
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 */
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. */
void verifyType(Type t) const;
@@ -630,14 +824,49 @@ public:
/** Verifies that the size is exactly \a s */
void verifySize(int s) const;
/** Assumes that Any(T) is well-defined, e.g., by T defining a
T::toAny() method. */
template<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:
void deserializeTable(TextInput& ti);
void deserializeArray(TextInput& ti,const std::string& term);
/** Turns an empty container into a table or an array */
void become(const Type& t);
}; // class Any
/**
Convenient iteration over the keys of a Any::TABLE, usually
for implementing construction of an object from an Any.
@@ -647,14 +876,14 @@ private:
It is an error to consume the same element more than once from
the same iterator.
<pre>
AnyKeyIterator r(a);
r.getIfPresent("enabled", enabled);
r.getIfPresent("showSamples", showSamples);
r.getIfPresent("showTiles", showTiles);
\code
AnyTableReader r(a);
r.getIfPresent("enabled", enabled);
r.getIfPresent("showSamples", showSamples);
r.get("showTiles", showTiles);
r.verifyDone();
</pre>
\endcode
\beta
*/
@@ -665,44 +894,21 @@ private:
public:
/** Verifies that \a is a TABLE with the given \a name. */
AnyTableReader(const std::string& name, const Any& a) : m_any(a) {
try {
m_any.verifyType(Any::TABLE);
m_any.verifyName(name);
} catch (const ParseError& e) {
// If an exception is thrown, the destructors will not be
// invoked automatically.
m_any.~Any();
m_alreadyRead.~Set();
throw e;
}
}
AnyTableReader(const std::string& name, const Any& a);
/** Verifies that \a is a TABLE. */
AnyTableReader(const Any& a) : m_any(a) {
try {
m_any.verifyType(Any::TABLE);
} catch (const ParseError& e) {
// If an exception is thrown, the destructors will not be
// invoked automatically.
m_any.~Any();
m_alreadyRead.~Set();
throw e;
}
}
AnyTableReader(const Any& a);
bool hasMore() const {
return m_any.size() > m_alreadyRead.size();
}
/** Verifies that all keys have been read. */
void verifyDone() const {
if (hasMore()) {
// Generate all keys
// Remove the ones we've read
// Assert the rest
// any.verify("");
}
void verifyDone() const;
/** Return the underlying Any. */
const Any& any() const {
return m_any;
}
#if 0
@@ -714,30 +920,67 @@ public:
AnyKeyIterator& operator++();
#endif
/** \copydoc get(const std::string& s, ValueType& v) */
void get(const std::string& s, std::string& v) {
v = m_any[s].string();
m_alreadyRead.insert(s);
}
/** \copydoc get(const std::string& s, ValueType& v) */
void get(const std::string& s, uint8& v) {
v = uint8(m_any[s].number());
m_alreadyRead.insert(s);
}
/** \copydoc get(const std::string& s, ValueType& v) */
void get(const std::string& s, uint16& v) {
v = uint16(m_any[s].number());
m_alreadyRead.insert(s);
}
/** Read an entire array at once.*/
template<class T>
void get(const std::string& s, Array<T>& v) {
m_any[s].getArray(v);
m_alreadyRead.insert(s);
}
/** If key \s appears in the any, reads its value into \a v and
template<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.
If key \s does not appear in the any, throws a G3D::ParseError.
If key \a s does not appear in the any, throws a G3D::ParseError.
Assumes that if key \s appears in the any it has not already been extracted
Assumes that if key \a s appears in the any it has not already been extracted
by this iterator. If it has been read before, an assertion will fail in debug mode.
*/
template<class ValueType>
void get(const std::string& s, ValueType& v) {
v = m_any[s];
m_alreadyRead.insert(toLower(s));
v = ValueType(m_any[s]);
m_alreadyRead.insert(s);
}
/** Same as get() */
const Any& operator[](const std::string& s) {
m_alreadyRead.insert(s);
return m_any[s];
}
/** Get the value associated with a key only if the key is actually present.
If key \s appears in the any, reads its value into \a v and
If key \a s appears in the any, reads its value into \a v and
removes that key from the ones available to iterate over.
If key \s does not appear in the any, does nothing.
If key \a s does not appear in the any, does nothing.
Assumes that if key \s appears in the any it has not already been extracted
Assumes that if key \a s appears in the any it has not already been extracted
by this iterator. If it has been read before, an assertion will fail in debug mode.
\return True if the value was read.
@@ -745,7 +988,7 @@ public:
template<class ValueType>
bool getIfPresent(const std::string& s, ValueType& v) {
if (m_any.containsKey(s)) {
debugAssertM(! m_alreadyRead.contains(toLower(s)), "read twice");
debugAssertM(! m_alreadyRead.contains(s), "read twice");
get(s, v);
return true;
@@ -753,8 +996,29 @@ public:
return false;
}
}
/** \return True if \a s is in the table and has not yet been read
using get() or getIfPresent(). */
bool containsUnread(const std::string& s) const {
return m_any.containsKey(s) && ! m_alreadyRead.contains(s);
}
};
} // namespace G3D
/**
\def PARSE_ANY(expression)
\brief Create an G3D::Any from an unquoted string.
e.g.,
\code
Any x = PARSE_ANY( { a = 3.0; b = false; } );
\endcode
*/
#define PARSE_ANY(x) Any::parse(#x)
#endif

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
@edited 2009-05-29
\created 2009-01-20
\edited 2010-10-29
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
@@ -57,7 +57,7 @@ private:
public:
typedef ReferenceCountedPointer<AreaMemoryManager> Ref;
typedef shared_ptr<AreaMemoryManager> Ref;
/**
\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
@cite Portions written by Aaron Orenstein, a@orenstein.name
\maintainer Morgan McGuire, graphics3d.com
\cite Portions written by Aaron Orenstein, a@orenstein.name
@created 2001-03-11
@edited 2009-05-29
\created 2001-03-11
\edited 2013-01-28
Copyright 2000-2009, Morgan McGuire, http://graphics.cs.williams.edu
Copyright 2000-2012, Morgan McGuire, http://graphics.cs.williams.edu
All rights reserved.
*/
@@ -16,8 +16,8 @@
#include "G3D/platform.h"
#include "G3D/debug.h"
#include "G3D/System.h"
#include "G3D/MemoryManager.h"
#include "G3D/System.h"
#ifdef G3D_DEBUG
// For formatting error messages
# include "G3D/format.h"
@@ -47,6 +47,8 @@ const int SORT_INCREASING = 1;
/** Constant for Array::sort */
const int SORT_DECREASING = -1;
/**
\brief Dynamic 1D array tuned for performance.
@@ -89,22 +91,26 @@ const int SORT_DECREASING = -1;
\sa G3D::SmallArray
*/
template <class T, int MIN_ELEMENTS = 10, size_t MIN_BYTES = 32>
template <class T, size_t MIN_ELEMENTS = 10>
class Array {
private:
/** Once the array has been allocated, it will never deallocate the underlying
array unless MIN_ELEMENTS is set to 0, MIN_BYTES is 0, and the array is empty. */
static const size_t MIN_BYTES = 32;
/** 0...num-1 are initialized elements, num...numAllocated-1 are not */
T* data;
int num;
int numAllocated;
size_t num;
size_t numAllocated;
MemoryManager::Ref m_memoryManager;
/** \param n Number of elements
*/
void init(int n, const MemoryManager::Ref& m) {
void init(size_t n, const MemoryManager::Ref& m) {
m_memoryManager = m;
debugAssert(n >= 0);
this->num = 0;
this->numAllocated = 0;
data = NULL;
@@ -117,7 +123,7 @@ private:
void _copy(const Array &other) {
init(other.num, MemoryManager::create());
for (int i = 0; i < num; i++) {
for (size_t i = 0; i < num; ++i) {
data[i] = other.data[i];
}
}
@@ -142,7 +148,7 @@ private:
and then copies at most oldNum elements from the old array to it. Destructors are
called for oldNum elements of the old array.
*/
void realloc(int oldNum) {
void realloc(size_t oldNum) {
T* oldData = data;
// The allocation is separate from the constructor invocation because we don't want
@@ -154,7 +160,7 @@ private:
alwaysAssertM(data, "Memory manager returned NULL: out of memory?");
// Call the copy constructors
{const int N = G3D::min(oldNum, numAllocated);
{const size_t N = G3D::min(oldNum, numAllocated);
const T* end = data + N;
T* oldPtr = oldData;
for (T* ptr = data; ptr < end; ++ptr, ++oldPtr) {
@@ -177,6 +183,27 @@ private:
m_memoryManager->free(oldData);
}
public:
/**
Assignment operator. Will be private in a future release because this is slow and can be invoked by accident by novice C++ programmers.
If you really want to copy an Array, use the explicit copy constructor.
*/
Array& operator=(const Array& other) {
resize(other.num);
for (int i = 0; i < (int)num; ++i) {
data[i] = other[i];
}
return *this;
}
Array& operator=(const std::vector<T>& other) {
resize(other.size());
for (size_t i = 0; i < num; ++i) {
data[i] = other[i];
}
return *this;
}
public:
/**
@@ -211,7 +238,7 @@ public:
return data;
}
/**
C++ STL style iterator method. Returns one after the last iterator
C++ STL style iterator method. Returns one after the last valid iterator
element.
*/
ConstIterator end() const {
@@ -224,15 +251,27 @@ public:
/**
The array returned is only valid until the next append() or resize call, or
the Array is deallocated.
the Array is deallocated.
*/
T* getCArray() {
return data;
}
/** Exchanges all data between the two arrays, which are required to have a common MemoryManager.
This is a convenient
way to avoid large array copies when handing off data without involving reference counting
or manual memory management. Beware that pointers or references into the arrays will
access memory in the <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 is deallocated.
the Array is deallocated.
*/
const T* getCArray() const {
return data;
@@ -241,12 +280,11 @@ public:
/** Creates a zero length array (no heap allocation occurs until resize). */
Array() : num(0) {
init(0, MemoryManager::create());
debugAssert(num >= 0);
}
/** Creates an array containing v0. */
Array(const T& v0) {
explicit Array(const T& v0) {
init(1, MemoryManager::create());
(*this)[0] = v0;
}
@@ -287,11 +325,60 @@ public:
/**
Copy constructor
Copy constructor. Copying arrays is slow...perhaps you want to pass a reference or a pointer instead?
*/
Array(const Array& other) : num(0) {
//TODO: patch rest of the API to prevent returning Arrays by value, then make explicit
Array(const Array& other) : num(0) {
_copy(other);
debugAssert(num >= 0);
}
explicit Array(const std::vector<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,14 +390,14 @@ public:
*/
~Array() {
// Invoke the destructors on the elements
for (int i = 0; i < num; i++) {
for (size_t i = 0; i < num; ++i) {
(data + i)->~T();
}
m_memoryManager->free(data);
// Set to 0 in case this Array is global and gets referenced during app exit
data = NULL;
num = 0;
num = 0;
numAllocated = 0;
}
@@ -335,26 +422,6 @@ public:
clear(false);
}
/**
Assignment operator.
*/
Array& operator=(const Array& other) {
debugAssert(num >= 0);
resize(other.num); for (int i = 0; i < num; ++i) {
data[i] = other[i];
}
debugAssert(num >= 0);
return *this;
}
Array& operator=(const std::vector<T>& other) {
resize((int)other.size());
for (int i = 0; i < num; ++i) {
data[i] = other[i];
}
return *this;
}
inline MemoryManager::Ref memoryManager() const {
return m_memoryManager;
}
@@ -363,7 +430,7 @@ public:
Number of elements in the array.
*/
inline int size() const {
return num;
return (int)num;
}
/**
@@ -379,8 +446,7 @@ public:
shrinks the array by one.
*/
void fastRemove(int index, bool shrinkIfNecessary = false) {
debugAssert(index >= 0);
debugAssert(index < num);
debugAssert(index < (int)num);
data[index] = data[num - 1];
resize(size() - 1, shrinkIfNecessary);
}
@@ -393,32 +459,52 @@ public:
// Add space for the extra element
resize(num + 1, false);
for (int i = num - 1; i > n; --i) {
for (size_t i = (size_t)(num - 1); i > (size_t)n; --i) {
data[i] = data[i - 1];
}
data[n] = value;
}
/** Sets all elements currently in the array to \param value */
void setAll(const T& value) {
for (size_t i = 0; i < num; ++i) {
data[i] = value;
}
}
/** Resize this array to consume exactly the capacity required by its size.
\sa clear, resize, capacity, size
*/
void trimToSize() {
if (size() != capacity()) {
size_t oldNum = numAllocated;
numAllocated = size();
realloc(oldNum);
}
}
/** @param shrinkIfNecessary if false, memory will never be
reallocated when the array shrinks. This makes resizing much
faster but can waste memory.
faster but can waste memory. Default = true.
\sa clear, trimToSize
*/
void resize(int n, bool shrinkIfNecessary = true) {
debugAssert(n >= 0);
void resize(size_t n, bool shrinkIfNecessary = true) {
alwaysAssertM(n < 0xFFFFFFFF, "This implementation does not support arrays with more than 2^32 elements, although the size in memory may be larger.");
if (num == n) {
return;
}
int oldNum = num;
size_t oldNum = num;
num = n;
// Call the destructors on newly hidden elements if there are any
for (int i = num; i < oldNum; ++i) {
for (size_t i = num; i < oldNum; ++i) {
(data + i)->~T();
}
// Once allocated, always maintain MIN_ELEMENTS elements or 32 bytes, whichever is higher.
const int minSize = std::max(MIN_ELEMENTS, (int)(MIN_BYTES / sizeof(T)));
const size_t minSize = G3D::max(MIN_ELEMENTS, (size_t)(MIN_BYTES / sizeof(T)));
if ((MIN_ELEMENTS == 0) && (MIN_BYTES == 0) && (n == 0) && shrinkIfNecessary) {
// Deallocate the array completely
@@ -450,18 +536,21 @@ public:
//
// These numbers are tweaked according to performance tests.
float growFactor = 3.0;
double growFactor = 3.0f;
int oldSizeBytes = numAllocated * sizeof(T);
if (oldSizeBytes > 400000) {
// Avoid bloat
growFactor = 1.5;
size_t oldSizeBytes = numAllocated * sizeof(T);
if (oldSizeBytes > 10000000) {
// Conserve memory more tightly above 10 MB
growFactor = 1.2f;
} else if (oldSizeBytes > 400000) {
// Avoid bloat above 400k
growFactor = 1.5f;
} else if (oldSizeBytes > 64000) {
// This is what std:: uses at all times
growFactor = 2.0;
growFactor = 2.0f;
}
numAllocated = (num - numAllocated) + (int)(numAllocated * growFactor);
numAllocated = (num - numAllocated) + (size_t)(numAllocated * growFactor);
if (numAllocated < minSize) {
numAllocated = minSize;
@@ -476,14 +565,14 @@ public:
// Only copy over old elements that still remain after resizing
// (destructors were called for others if we're shrinking)
realloc(iMin(num, oldNum));
realloc(min(num, oldNum));
}
// Call the constructors on newly revealed elements.
// Do not use parens because we don't want the intializer
// invoked for POD types.
for (int i = oldNum; i < num; ++i) {
for (size_t i = oldNum; i < num; ++i) {
new (data + i) T;
}
}
@@ -583,6 +672,62 @@ public:
}
}
void append(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) {
if (inArray(&v1) || inArray(&v2) || inArray(&v3) || inArray(&v4) || inArray(&v5)) {
T t1 = v1;
T t2 = v2;
T t3 = v3;
T t4 = v4;
T t5 = v5;
append(t1, t2, t3, t4, t5);
} else if (num + 4 < numAllocated) {
// This is a simple situation; just stick it in the next free slot using
// the copy constructor.
new (data + num) T(v1);
new (data + num + 1) T(v2);
new (data + num + 2) T(v3);
new (data + num + 3) T(v4);
new (data + num + 4) T(v5);
num += 5;
} else {
resize(num + 5, DONT_SHRINK_UNDERLYING_ARRAY);
data[num - 5] = v1;
data[num - 4] = v2;
data[num - 3] = v3;
data[num - 2] = v4;
data[num - 1] = v5;
}
}
void append(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6) {
if (inArray(&v1) || inArray(&v2) || inArray(&v3) || inArray(&v4) || inArray(&v5) || inArray(&v6)) {
T t1 = v1;
T t2 = v2;
T t3 = v3;
T t4 = v4;
T t5 = v5;
T t6 = v6;
append(t1, t2, t3, t4, t5, t6);
} else if (num + 5 < numAllocated) {
// This is a simple situation; just stick it in the next free slot using
// the copy constructor.
new (data + num) T(v1);
new (data + num + 1) T(v2);
new (data + num + 2) T(v3);
new (data + num + 3) T(v4);
new (data + num + 4) T(v5);
new (data + num + 5) T(v6);
num += 6;
} else {
resize(num + 6, DONT_SHRINK_UNDERLYING_ARRAY);
data[num - 6] = v1;
data[num - 5] = v2;
data[num - 4] = v3;
data[num - 3] = v4;
data[num - 2] = v5;
data[num - 1] = v6;
}
}
/**
Returns true if the given element is in the array.
*/
@@ -602,12 +747,12 @@ public:
*/
void append(const Array<T>& array) {
debugAssert(this != &array);
int oldNum = num;
int arrayLength = array.length();
size_t oldNum = num;
size_t arrayLength = array.length();
resize(num + arrayLength, false);
for (int i = 0; i < arrayLength; i++) {
for (size_t i = 0; i < arrayLength; ++i) {
data[oldNum + i] = array.data[i];
}
}
@@ -648,8 +793,8 @@ public:
sequence, a value at least as large as size()"
For compatibility with std::vector.
*/
int capacity() const {
return numAllocated;
int capacity() const {
return (int)numAllocated;
}
/**
@@ -723,27 +868,40 @@ public:
Performs bounds checks in debug mode
*/
inline T& operator[](int n) {
debugAssertM((n >= 0) && (n < num), format("Array index out of bounds. n = %d, size() = %d", n, num));
debugAssertM((n >= 0) && (n < (int)num),
format("Array index out of bounds. n = %d, size() = %d", (int)n, (int)num));
debugAssert(data!=NULL);
return data[n];
}
inline T& operator[](unsigned int n) {
debugAssertM(n < (unsigned int)num, format("Array index out of bounds. n = %d, size() = %d", n, num));
return data[n];
inline T& operator[](uint32 n) {
debugAssertM(n < (uint32)num, format("Array index out of bounds. n = %d, size() = %d",
(int)n, (int)num));
return data[n];
}
inline T& operator[](uint64 n) {
debugAssertM(n < (uint64)num, format("Array index out of bounds. n = %d, size() = %d", (int)n, (int)num));
return data[n];
}
/**
Performs bounds checks in debug mode
*/
inline const T& operator[](int n) const {
debugAssert((n >= 0) && (n < num));
debugAssert((n >= 0) && (n < (int)num));
debugAssert(data != NULL);
return data[n];
}
inline const T& operator[](uint32 n) const {
debugAssert((n < (uint32)num));
debugAssert(data!=NULL);
return data[n];
}
inline const T& operator[](unsigned int n) const {
debugAssert((n < (unsigned int)num));
inline const T& operator[](uint64 n) const {
debugAssert((n < (uint64)num));
debugAssert(data!=NULL);
return data[n];
}
@@ -751,7 +909,7 @@ public:
inline T& randomElement() {
debugAssert(num > 0);
debugAssert(data!=NULL);
return data[iRandom(0, num - 1)];
return data[iRandom(0, (int)num - 1)];
}
inline const T& randomElement() const {
@@ -821,13 +979,18 @@ public:
Calls delete on all objects[0...size-1]
and sets the size to zero.
*/
void deleteAll() {
for (int i = 0; i < num; i++) {
void invokeDeleteOnAllElements() {
for (size_t i = 0; i < num; ++i) {
delete data[i];
}
resize(0);
}
/** \deprecated */
void G3D_DEPRECATED deleteAll() {
invokeDeleteOnAllElements();
}
/**
Returns the index of (the first occurance of) an index or -1 if
not found. Searches from the right.
@@ -846,9 +1009,9 @@ public:
not found.
*/
int findIndex(const T& value) const {
for (int i = 0; i < num; ++i) {
for (size_t i = 0; i < num; ++i) {
if (data[i] == value) {
return i;
return (int)i;
}
}
return -1;
@@ -894,8 +1057,8 @@ public:
}
void remove(int index, int count = 1) {
debugAssert((index >= 0) && (index < num));
debugAssert((count > 0) && (index + count <= num));
debugAssert((index >= 0) && (index < (int)num));
debugAssert((count > 0) && (index + count <= (int)num));
remove(begin() + index, count);
}
@@ -906,8 +1069,8 @@ public:
void reverse() {
T temp;
int n2 = num / 2;
for (int i = 0; i < n2; ++i) {
size_t n2 = num / 2;
for (size_t i = 0; i < n2; ++i) {
temp = data[num - 1 - i];
data[num - 1 - i] = data[i];
data[i] = temp;
@@ -917,29 +1080,29 @@ public:
/**
Sort using a specific less-than function, e.g.:
<PRE>
\code
bool __cdecl myLT(const MyClass& elem1, const MyClass& elem2) {
return elem1.x < elem2.x;
}
</PRE>
\endcode
Note that for pointer arrays, the <CODE>const</CODE> must come
<I>after</I> the class name, e.g., <CODE>Array<MyClass*></CODE> uses:
<PRE>
\code
bool __cdecl myLT(MyClass*const& elem1, MyClass*const& elem2) {
return elem1->x < elem2->x;
}
</PRE>
\endcode
or a functor, e.g.,
<pre>
\code
bool
less_than_functor::operator()( const double& lhs, const double& rhs ) const
{
return( lhs < rhs? true : false );
}
</pre>
\endcode
*/
// void sort(bool (__cdecl *lessThan)(const T& elem1, const T& elem2)) {
// std::sort(data, data + num, lessThan);
@@ -955,14 +1118,14 @@ return( lhs < rhs? true : false );
Sorts the array in increasing order using the > or < operator. To
invoke this method on Array<T>, T must override those operator.
You can overide these operators as follows:
<code>
\code
bool T::operator>(const T& other) const {
return ...;
}
bool T::operator<(const T& other) const {
return ...;
}
</code>
\endcode
*/
void sort(int direction = SORT_INCREASING) {
if (direction == SORT_INCREASING) {
@@ -1053,7 +1216,7 @@ return( lhs < rhs? true : false );
// Form a table of buckets for lt, eq, and gt
Array<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]);
debugAssertM(c >= -1 && c <= 1, "Comparator returned an illegal value.");
@@ -1236,6 +1399,8 @@ return( lhs < rhs? true : false );
medianPartition(ltMedian, eqMedian, gtMedian, temp, DefaultComparator());
}
/** Redistributes the elements so that the new order is statistically independent
of the original order. O(n) time.*/
@@ -1252,6 +1417,35 @@ return( lhs < rhs? true : false );
}
/** Ensures that future append() calls can grow up to size \a n without allocating memory.*/
void reserve(int n) {
debugAssert(n >= size());
const int oldSize = size();
resize(n);
resize(oldSize, false);
}
/** Number of bytes used by the array object and the memory allocated for it's data pointer. Does *not*
* include the memory of objects pointed to by objects in the data array */
size_t sizeInMemory() const {
return sizeof(Array<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 {
private:
# if defined(G3D_WIN32)
# if defined(G3D_WINDOWS)
volatile long m_value;
# elif defined(G3D_OSX)
int32_t m_value;
@@ -70,18 +70,22 @@ public:
/** Returns the old value, before the add. */
int32 add(const int32 x) {
# if defined(G3D_WIN32)
# if defined(G3D_WINDOWS)
return InterlockedExchangeAdd(&m_value, x);
# elif defined(G3D_LINUX) || defined(G3D_FREEBSD)
int32 old;
asm volatile ("lock; xaddl %0,%1"
: "=r"(old), "=m"(m_value) /* outputs */
: "0"(x), "m"(m_value) /* inputs */
: "memory", "cc");
return old;
# if defined(__aarch64__)
return __sync_fetch_and_add(&m_value, x);
# else
int32 old;
asm volatile ("lock; xaddl %0,%1"
: "=r"(old), "=m"(m_value) /* outputs */
: "0"(x), "m"(m_value) /* inputs */
: "memory", "cc");
return old;
# endif
# elif defined(G3D_OSX)
@@ -98,7 +102,7 @@ public:
}
void increment() {
# if defined(G3D_WIN32)
# if defined(G3D_WINDOWS)
// Note: returns the newly incremented value
InterlockedIncrement(&m_value);
# elif defined(G3D_LINUX) || defined(G3D_FREEBSD)
@@ -111,18 +115,22 @@ public:
/** Returns zero if the result is zero after decrement, non-zero otherwise.*/
int32 decrement() {
# if defined(G3D_WIN32)
# if defined(G3D_WINDOWS)
// Note: returns the newly decremented value
return InterlockedDecrement(&m_value);
# elif defined(G3D_LINUX) || defined(G3D_FREEBSD)
unsigned char nz;
# if defined(__aarch64__)
return __sync_sub_and_fetch(&m_value, 1);
# else
unsigned char nz;
asm volatile ("lock; decl %1;\n\t"
"setnz %%al"
: "=a" (nz)
: "m" (m_value)
: "memory", "cc");
return nz;
asm volatile ("lock; decl %1;\n\t"
"setnz %%al"
: "=a" (nz)
: "m" (m_value)
: "memory", "cc");
return nz;
# endif
# elif defined(G3D_OSX)
// Note: returns the newly decremented value
return OSAtomicDecrement32(&m_value);
@@ -140,20 +148,24 @@ public:
Under VC6 the sign bit may be lost.
*/
int32 compareAndSet(const int32 comperand, const int32 exchange) {
# if defined(G3D_WIN32)
# if defined(G3D_WINDOWS)
return InterlockedCompareExchange(&m_value, exchange, comperand);
# elif defined(G3D_LINUX) || defined(G3D_FREEBSD) || defined(G3D_OSX)
// Based on Apache Portable Runtime
// http://koders.com/c/fid3B6631EE94542CDBAA03E822CA780CBA1B024822.aspx
int32 ret;
asm volatile ("lock; cmpxchgl %1, %2"
: "=a" (ret)
: "r" (exchange), "m" (m_value), "0"(comperand)
: "memory", "cc");
return ret;
# if defined(__aarch64__)
return __sync_val_compare_and_swap(&m_value, comperand, exchange);
# else
// Based on Apache Portable Runtime
// http://koders.com/c/fid3B6631EE94542CDBAA03E822CA780CBA1B024822.aspx
int32 ret;
asm volatile ("lock; cmpxchgl %1, %2"
: "=a" (ret)
: "r" (exchange), "m" (m_value), "0"(comperand)
: "memory", "cc");
return ret;
// Note that OSAtomicCompareAndSwap32 does not return a useful value for us
// so it can't satisfy the cmpxchgl contract.
// Note that OSAtomicCompareAndSwap32 does not return a useful value for us
// so it can't satisfy the cmpxchgl contract.
# endif
# endif
}

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

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

View File

@@ -1,20 +1,20 @@
/**
@file Box.h
\file G3D/Box.h
Box class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
@cite Portions based on Dave Eberly's Magic Software Library at <A HREF="http://www.magic-software.com">http://www.magic-software.com</A>
@created 2001-06-02
@edited 2007-06-05
\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
\edited 2013-04-13
Copyright 2000-2006, Morgan McGuire.
Copyright 2000-2013, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_BOX_H
#define G3D_BOX_H
#ifndef G3D_Box_h
#define G3D_Box_h
#include "G3D/platform.h"
#include "G3D/Vector3.h"
@@ -24,13 +24,12 @@
namespace G3D {
class CoordinateFrame;
class Any;
/**
An arbitrary 3D box, useful as a bounding box.
To construct a box from a coordinate frame, center and extent, use the idiom:
\brief An arbitrary (oriented) 3D box, useful as a bounding box.
To construct a box from a coordinate frame, center and extent, use the idiom:
<CODE>Box box = cframe.toObjectSpace(Box(center - extent/2, center + extent/2));</CODE>
*/
class Box {
@@ -41,29 +40,14 @@ private:
friend class CoordinateFrame;
/**
<PRE>
3 2 7 6
0 1 4 5
front back (seen through front)
</PRE>
Axes with length equal to the 4 edges that run along each of them
*/
Vector3 _corner[8];
/**
Unit axes.
*/
Vector3 _axis[3];
Vector3 _edgeVector[3];
Vector3 _center;
/**
Extent along each axis.
*/
Vector3 _extent;
Point3 _center;
float _area;
float _volume;
void init(
@@ -72,38 +56,47 @@ private:
public:
/**
Does not initialize the fields.
*/
Box();
explicit Box(const Any& a);
/**
Constructs a box from two opposite corners.
*/
Box(
const Vector3& min,
Box(const Vector3& min,
const Vector3& max);
static Box inf();
Box(const Vector3& osMin,
const Vector3& osMax,
const CoordinateFrame& frame);
Box(class BinaryInput& b);
Box(class BinaryInput& b);
Box(const class AABox& b);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
explicit Box(const Point3& p);
static Box inf();
Any toAny() const;
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
/**
Returns the object to world transformation for
this box. localFrame().worldToObject(...) takes
this box, where the origin is the center of the box. localFrame().worldToObject(...) takes
objects into the space where the box axes are
(1,0,0), (0,1,0), (0,0,1). Note that there
is no scaling in this transformation.
*/
CoordinateFrame localFrame() const;
/** \sa localFrame */
void getLocalFrame(CoordinateFrame& frame) const;
Box operator*(float f) const;
/**
Returns the centroid of the box.
*/
@@ -111,18 +104,39 @@ public:
return _center;
}
/**
\htmlonly
<PRE>
inline Vector3 corner(int i) const {
debugAssert(i < 8);
return _corner[i];
}
2--------3
/ : /|
/ : / |
6--------7 |
| : | |
| 0....|..1
| / | /
|/ |/
4--------5
y
^
|
|-->x
z/
</PRE>
\endhtmlonly
*/
Vector3 corner(int i) const;
/**
Unit length.
*/
inline Vector3 axis(int a) const {
debugAssert(a < 3);
return _axis[a];
return _edgeVector[a].direction();
}
/**
@@ -131,17 +145,43 @@ public:
*/
inline float extent(int a) const {
debugAssert(a < 3);
return (float)_extent[a];
return _edgeVector[a].length();
}
inline Vector3 extent() const {
return _extent;
return Vector3(_edgeVector[0].length(), _edgeVector[1].length(), _edgeVector[2].length());
}
/**
Returns the four corners of a face (0 <= f < 6).
The corners are returned to form a counter clockwise quad facing outwards.
*/
The corners are returned to form a clockwise quad facing outwards.
+--------+
/ : /|
/ : / |
+--------+ |
| : | |
| +....|..+
| / | /
|/ |/
+--------+
y
^
|
|-->x
z/
Faces are in the following order:
0: -Z
1: X
2: Z
3: Y
4: -X
5: -Y
*/
void getFaceCorners(
int f,
Vector3& v0,
@@ -150,24 +190,24 @@ public:
Vector3& v3) const;
/**
/**
See AABox::culledBy
*/
*/
bool culledBy
(
const Array<Plane>& plane,
int32& cullingPlaneIndex,
const uint32 testMask,
uint32& childMask) const;
const Array<Plane>& plane,
int32& cullingPlaneIndex,
const uint32 testMask,
uint32& childMask) const;
/**
Conservative culling test that does not produce a mask for children.
*/
bool culledBy
(
const Array<Plane>& plane,
int32& cullingPlaneIndex = dummy,
const uint32 testMask = -1) const;
const Array<Plane>& plane,
int32& cullingPlaneIndex = dummy,
const uint32 testMask = -1) const;
bool contains(
const Vector3& point) const;

View File

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

View File

@@ -26,32 +26,32 @@ class AABox;
*/
class Capsule {
private:
Vector3 p1;
Vector3 p2;
Vector3 p1;
Vector3 p2;
float _radius;
float _radius;
public:
/** Uninitialized */
Capsule();
Capsule(class BinaryInput& b);
Capsule(const Vector3& _p1, const Vector3& _p2, float _r);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
/** The line down the center of the capsule */
Line axis() const;
Capsule(const Vector3& _p1, const Vector3& _p2, float _r);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
/** The line down the center of the capsule */
Line axis() const;
inline float radius() const {
return _radius;
}
inline float radius() const {
return _radius;
}
/** Argument may be 0 or 1 */
inline Vector3 point(int i) const {
debugAssert(i == 0 || i == 1);
return (i == 0) ? p1 : p2;
}
/** Argument may be 0 or 1 */
inline Vector3 point(int i) const {
debugAssert(i == 0 || i == 1);
return (i == 0) ? p1 : p2;
}
/** Distance between the sphere centers. The total extent of the cylinder is
2r + h. */

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,16 +1,16 @@
/**
@file Color3.h
\file Color3.h
Color class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@cite Portions based on Dave Eberly's Magic Software Library
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
\cite Portions based on Dave Eberly's Magic Software Library
at <A HREF="http://www.magic-software.com">http://www.magic-software.com</A>
@created 2001-06-02
@edited 2009-04-28
\created 2001-06-02
\edited 2013-03-29
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2013, Morgan McGuire.
All rights reserved.
*/
@@ -40,26 +40,41 @@ private:
public:
/**
Does not initialize fields.
\brief Initializes to all zero.
*/
Color3();
Color3() : r(0), g(0), b(0) {}
bool nonZero() const {
return (r != 0) || (g != 0) || (b != 0);
}
/** \param any Must be in one of the following forms:
- Color3(#, #, #)
- Color3(#)
- Color3::fromARGB(#)
- Color3::fromASRGB(#)
- Color3{r = #, g = #, b = #)
- Color3::one()
- Color3::zero()
In the current implementation, G3D::Power3, G3D::Radiance3,
and G3D::Irradiance3 are typedefs for Color3, so Color3
accepts "Power3" and "Radiance3" as a prefixes as well, e.g.,
Power3(1,0,0).
*/
Color3(const Any& any);
explicit Color3(const Any& any);
Color3& operator=(const Any& a);
/** Converts the Color3 to an Any. */
operator Any() const;
Any toAny() const;
explicit Color3(class BinaryInput& bi);
Color3(float r, float g, float b);
Color3(float v) : r(v), g(v), b(v) {}
/** \brief Initializes all channels to \a v */
explicit Color3(float v) : r(v), g(v), b(v) {}
explicit Color3(const class Vector3& v);
@@ -75,7 +90,7 @@ public:
*/
Color3 (const Color3& other);
Color3 (const class Color3uint8& other);
Color3 (const class Color3unorm8& other);
inline bool isZero() const {
return (r == 0.0f) && (g == 0.0f) && (b == 0.0f);
@@ -92,6 +107,12 @@ public:
*/
static Color3 fromARGB(uint32);
/**
Initialize from an HTML-style color (e.g. 0xFF0000 == RED) by converting from sRGB to RGB.
*/
static Color3 fromASRGB(uint32);
/** Returns one of the color wheel colors (e.g. RED, GREEN, CYAN).
Does not include white, black, or gray. */
static const Color3& wheelRandom();
@@ -140,10 +161,15 @@ public:
inline Color3 operator* (float s) const {
return Color3(r * s, g * s, b * s);
}
inline Color3 operator/ (const Color3& rkVector) const {
return Color3(r / rkVector.r, g / rkVector.g, b / rkVector.b);
}
Color3 operator* (const Color3& rkVector) const;
inline Color3 operator/ (float fScalar) const {
return (*this) * (1.0f / fScalar);
}
Color3 operator- () const;
// arithmetic updates
@@ -161,7 +187,7 @@ public:
Color3 direction() const;
float squaredLength () const;
float dot (const Color3& rkVector) const;
float unitize (float fTolerance = 1e-06);
float unitize (float fTolerance = 1e-06f);
Color3 cross (const Color3& rkVector) const;
Color3 unitCross (const Color3& rkVector) const;
@@ -258,11 +284,11 @@ inline G3D::Color3 operator* (const G3D::Color3& c, G3D::Color1& s) {
return c * s.value;
}
//----------------------------------------------------------------------------
inline Color3::Color3 () {
inline G3D::Color3 operator/ (float s, const G3D::Color3& c) {
return c * (1.0f/s);
}
//----------------------------------------------------------------------------
inline Color3::Color3(float fX, float fY, float fZ) {
@@ -414,11 +440,36 @@ inline Color3 Color3::cross (const Color3& rkVector) const {
inline Color3 Color3::unitCross (const Color3& rkVector) const {
Color3 kCross(g*rkVector.b - b*rkVector.g, b*rkVector.r - r*rkVector.b,
r*rkVector.g - g*rkVector.r);
kCross.unitize();
return kCross;
return kCross.direction();
}
/** Radiance * measure(Solid Angle) between two points, measured at the receiver orthogonal to the axis between them; W/m^2 */
typedef Color3 Biradiance3;
/** Power per (measure(SolidAngle) * measure(Area)); W / (m^2 sr) */
typedef Color3 Radiance3;
/** Power per area; J / m^2 */
typedef Color3 Radiosity3;
/** Force * distance; J */
typedef Color3 Energy3;
/** Incident power per area; W/m^2*/
typedef Color3 Irradiance3;
/** Energy per time; W*/
typedef Color3 Power3;
#if 0 // Disabled to avoid taking these useful names from the namespace
typedef float Power;
typedef float Biradiance;
typedef float Radiance;
typedef float Radiosity;
typedef float Energy;
typedef float Irradiance;
#endif
} // namespace

View File

@@ -48,16 +48,16 @@ public:
Color4(const Any& any);
/** Converts the Color4 to an Any. */
operator Any() const;
Any toAny() const;
/**
* Does not initialize fields.
Initializes to all zero
*/
Color4 ();
Color4() : r(0), g(0), b(0), a(0) {}
Color4(const Color3& c3, float a = 1.0);
Color4(const class Color4uint8& c);
Color4(const class Color4unorm8& c);
Color4(class BinaryInput& bi);
@@ -191,12 +191,6 @@ inline Color4 operator*(const Color3& c3, const Color4& c4) {
//----------------------------------------------------------------------------
inline Color4::Color4 () {
// For efficiency in construction of large arrays of vectors, the
// default constructor does not initialize the vector.
}
//----------------------------------------------------------------------------
inline Color4::Color4(const Color3& c3, float a) {
r = c3.r;

View File

@@ -61,6 +61,19 @@ public:
True if v is a point inside the cone.
*/
bool contains(const class Vector3& v) const;
/** Returns the solid angle (in steradians) subtended by a cone with half-angle \a halfAngle */
static float solidAngleFromHalfAngle(float halfAngle);
static double solidAngleFromHalfAngle(double halfAngle);
/** Returns the half-angle (in radians) of a cone that subtends \a solidAngle (in steradians) */
static float halfAngleFromSolidAngle(float solidAngle);
static double halfAngleFromSolidAngle(double solidAngle);
Vector3 randomDirectionInCone(Random& rng) const;
};
} // namespace

View File

@@ -34,7 +34,7 @@ private:
friend class ConvexPolyhedron;
Array<Vector3> _vertex;
Array<Vector3> _vertex;
public:

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
@edited 2009-04-29
\created 2001-03-04
\edited 2012-07-29
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
@@ -33,9 +33,10 @@
namespace G3D {
class Any;
class Frustum;
/**
A rigid body RT (rotation-translation) transformation.
\brief A rigid body RT (rotation-translation) transformation.
CoordinateFrame abstracts a 4x4 matrix that maps object space to world space:
@@ -53,28 +54,28 @@ Convert to Matrix4 using CoordinateFrame::toMatrix4. You <I>can</I> construct a
from a Matrix4 using Matrix4::approxCoordinateFrame, however, because a Matrix4 is more
general than a CoordinateFrame, some information may be lost.
@sa G3D::UprightFrame, G3D::PhysicsFrame, G3D::Matrix4, G3D::Quat
\sa G3D::UprightFrame, G3D::PhysicsFrame, G3D::Matrix4, G3D::Quat
*/
class CoordinateFrame {
public:
/** Takes object space points to world space. */
Matrix3 rotation;
Matrix3 rotation;
/** Takes object space points to world space. */
Vector3 translation;
/** The origin of this coordinate frame in world space (or its parent's space, if nested). */
Point3 translation;
/** \param any Must be in one of the following forms:
- CFrame((matrix3 expr), (vector3 expr))
- CFrame((matrix3 expr), (Point3 expr))
- CFrame::fromXYZYPRDegrees(#, #, #, #, #, #)
- CFrame { rotation = (matrix3 expr), translation = (vector3 expr) }
- Vector3( ... )
- CFrame { rotation = (Matrix3 expr), translation = (Point3 expr) }
- Point3( ... )
- Matrix3( ... )
*/
CoordinateFrame(const Any& any);
/** Converts the CFrame to an Any. */
operator Any() const;
Any toAny() const;
inline bool operator==(const CoordinateFrame& other) const {
return (translation == other.translation) && (rotation == other.rotation);
@@ -95,16 +96,16 @@ public:
*/
CoordinateFrame();
CoordinateFrame(const Vector3& _translation) :
CoordinateFrame(const Point3& _translation) :
rotation(Matrix3::identity()), translation(_translation) {
}
CoordinateFrame(const Matrix3 &rotation, const Vector3 &translation) :
CoordinateFrame(const Matrix3& rotation, const Point3& translation) :
rotation(rotation), translation(translation) {
}
CoordinateFrame(const Matrix3 &rotation) :
rotation(rotation), translation(Vector3::zero()) {
CoordinateFrame(const Matrix3& rotation) :
rotation(rotation), translation(Point3::zero()) {
}
CoordinateFrame(const class UprightFrame& f);
@@ -187,26 +188,25 @@ public:
/**
Transforms the point into world space.
*/
inline Vector3 pointToWorldSpace(const Vector3& v) const {
return Vector3(
rotation[0][0] * v[0] + rotation[0][1] * v[1] + rotation[0][2] * v[2] + translation[0],
rotation[1][0] * v[0] + rotation[1][1] * v[1] + rotation[1][2] * v[2] + translation[1],
rotation[2][0] * v[0] + rotation[2][1] * v[1] + rotation[2][2] * v[2] + translation[2]);
inline Point3 pointToWorldSpace(const Point3& v) const {
return Point3
(rotation[0][0] * v[0] + rotation[0][1] * v[1] + rotation[0][2] * v[2] + translation[0],
rotation[1][0] * v[0] + rotation[1][1] * v[1] + rotation[1][2] * v[2] + translation[1],
rotation[2][0] * v[0] + rotation[2][1] * v[1] + rotation[2][2] * v[2] + translation[2]);
}
/**
Transforms the point into object space. Assumes that the rotation matrix is orthonormal.
*/
inline Vector3 pointToObjectSpace(const Vector3& v) const {
inline Point3 pointToObjectSpace(const Point3& v) const {
float p[3];
p[0] = v[0] - translation[0];
p[1] = v[1] - translation[1];
p[2] = v[2] - translation[2];
debugAssert(G3D::fuzzyEq(rotation.determinant(), 1.0f));
return Vector3(
rotation[0][0] * p[0] + rotation[1][0] * p[1] + rotation[2][0] * p[2],
rotation[0][1] * p[0] + rotation[1][1] * p[1] + rotation[2][1] * p[2],
rotation[0][2] * p[0] + rotation[1][2] * p[1] + rotation[2][2] * p[2]);
debugAssert(G3D::fuzzyEq(fabsf(rotation.determinant()), 1.0f));
return Point3(rotation[0][0] * p[0] + rotation[1][0] * p[1] + rotation[2][0] * p[2],
rotation[0][1] * p[0] + rotation[1][1] * p[1] + rotation[2][1] * p[2],
rotation[0][2] * p[0] + rotation[1][2] * p[1] + rotation[2][2] * p[2]);
}
/**
@@ -224,6 +224,8 @@ public:
Ray toWorldSpace(const Ray& r) const;
Frustum toWorldSpace(const Frustum& f) const;
/**
Transforms the vector into object space (no translation).
*/
@@ -237,18 +239,20 @@ public:
return v * rotation;
}
void pointToWorldSpace(const Array<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 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 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 Box& b) const;
@@ -260,7 +264,7 @@ public:
class Plane toWorldSpace(const class Plane& p) const;
class Sphere toWorldSpace(const class Sphere& b) const;
class Triangle toWorldSpace(const class Triangle& t) const;
class Box toObjectSpace(const AABox& b) const;
@@ -287,17 +291,32 @@ public:
return CoordinateFrame(rotation, translation - v);
}
void lookAt(const Vector3& target);
void lookAt(
const Vector3& target,
Vector3 up);
/**
Transform this coordinate frame towards \a goal, but not past it, goverened by maximum
rotation and translations. This is a useful alternative to \a lerp, especially if the
goal is expected to change every transformation step so that constant start and end positions will
not be available.
\param goal Step from this towards goal
\param maxTranslation Meters
\param maxRotation Radians
\sa lerp
*/
void moveTowards(const CoordinateFrame& goal, float maxTranslation, float maxRotation);
void lookAt(const Point3& target);
void lookAt
(const Point3& target,
Vector3 up);
/** The direction this camera is looking (its negative z axis)*/
inline Vector3 lookVector() const {
return -rotation.column(2);
}
inline Vector3 lookVector() const {
return -rotation.column(2);
}
/** Returns the ray starting at the camera origin travelling in direction CoordinateFrame::lookVector. */
class Ray lookRay() const;
@@ -307,24 +326,26 @@ public:
}
inline Vector3 rightVector() const {
return rotation.column(0);
}
return rotation.column(0);
}
/**
If a viewer looks along the look vector, this is the viewer's "left".
Useful for strafing motions and building alternative coordinate frames.
*/
inline Vector3 leftVector() const {
return -rotation.column(0);
return -rotation.column(0);
}
/**
Linearly interpolates between two coordinate frames, using
Quat::slerp for the rotations.
\sa moveTowards
*/
CoordinateFrame lerp(
const CoordinateFrame& other,
float alpha) const;
CoordinateFrame lerp
(const CoordinateFrame& other,
float alpha) const;
};

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
@edited 2006-04-06
\created 2006-03-29
\edited 2011-06-21
*/
#ifndef G3D_CRYPTO_H
#define G3D_CRYPTO_H
#ifndef G3D_Crypto_h
#define G3D_Crypto_h
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
#include "G3D/System.h"
#include <string>
namespace G3D {
@@ -33,6 +34,24 @@ public:
explicit MD5Hash(class BinaryInput& b);
/** Rotates the bytes once */
void rotateBytes() {
uint8 temp = value[0];
for (int i = 0; i < 15; ++i) {
value[i] = value[i + 1];
}
value[15] = temp;
}
/** Rotates by n bytes */
void rotateBytes(int n) {
uint8 temp[16];
System::memcpy(temp, value, 16);
for (int i = 0; i < 16; ++i) {
value[i] = value[(i + n) & 15];
}
}
uint8& operator[](int i) {
return value[i];
}
@@ -56,6 +75,18 @@ public:
void deserialize(class BinaryInput& b);
void serialize(class BinaryOutput& b) const;
static size_t hashCode(const MD5Hash& key) {
size_t h = 0;
for (int i = 0; i < 4; ++i) {
const int x = i * 4;
h ^= (((uint32)key.value[x + 0]) << 24) |
(((uint32)key.value[x + 1]) << 16) |
(((uint32)key.value[x + 2]) << 8) |
((uint32)key.value[x + 3]);
}
return h;
}
};
@@ -79,7 +110,7 @@ public:
@cite Based on implementation by L. Peter Deutsch, ghost@aladdin.com
*/
MD5Hash md5(const void* bytes, size_t numBytes);
static MD5Hash md5(const void* bytes, size_t numBytes);
/**
Returns the nth prime less than 2000 in constant time. The first prime has index

View File

@@ -26,22 +26,22 @@ class AABox;
*/
class Cylinder {
private:
Vector3 p1;
Vector3 p2;
Vector3 p1;
Vector3 p2;
float mRadius;
float mRadius;
public:
/** Uninitialized */
Cylinder();
Cylinder(class BinaryInput& b);
Cylinder(const Vector3& _p1, const Vector3& _p2, float _r);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
/** The line down the center of the Cylinder */
Line axis() const;
Cylinder(const Vector3& _p1, const Vector3& _p2, float _r);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
/** The line down the center of the Cylinder */
Line axis() const;
/**
A reference frame in which the center of mass is at the origin and

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
@edited 2010-02-05
\author 2002-06-06
\edited 2012-03-26
*/
#ifndef G3D_FileSystem_h
#define G3D_FileSystem_h
@@ -12,6 +12,8 @@
#include "G3D/platform.h"
#include "G3D/Array.h"
#include "G3D/Table.h"
#include "G3D/Set.h"
#include "G3D/GMutex.h"
namespace G3D {
@@ -34,11 +36,12 @@ namespace G3D {
<li> There are no nested zipfiles
</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
zipfile without forcing it to open all parent directories for reading.
\sa FilePath
TODO: make threadsafe!
*/
class FileSystem {
public:
@@ -63,7 +66,7 @@ public:
ListSettings() :
files(true),
directories(true),
# ifdef G3D_WIN32
# ifdef G3D_WINDOWS
caseSensitive(true),
# else
caseSensitive(false),
@@ -111,8 +114,13 @@ private:
/** When this entry was last updated */
double lastChecked;
/** Case-independent comparison on Windows */
bool contains(const std::string& child) const;
bool contains(const std::string& child, bool caseSensitive =
#ifdef G3D_WINDOWS
false
#else
true
#endif
) const;
/** Compute the contents of nodeArray from this zipfile. */
void computeZipListing(const std::string& zipfile, const std::string& pathInsideZipfile);
@@ -132,116 +140,80 @@ private:
FileSystem();
static FileSystem& instance();
static GMutex mutex;
# ifdef G3D_WIN32
/** On Windows, the drive letters that form the file system roots.*/
# ifdef G3D_WINDOWS
/** \copydoc drives */
const Array<std::string>& _drives();
# endif
/** Returns true if some sub-path of \a path is a zipfile.
If the path itself is a zipfile, returns false.
\param zipfile The part of \a path that was the zipfile */
/** \copydoc inZipfile */
bool _inZipfile(const std::string& path, std::string& zipfile);
/** Clears old cache entries so that exists() and list() will reflect recent changes to the file system.
\param path Clear only \a path and its subdirectories ("" means clear the entire cache) */
/** \copydoc clearCache */
void _clearCache(const std::string& path);
/** \copydoc inZipfile */
bool _inZipfile(const std::string& path) {
std::string ignore;
return inZipfile(path, ignore);
}
/** Set the cacheLifetime().
\param t in seconds */
/** \copydoc setCacheLifetime */
void _setCacheLifetime(float t);
/** A cache is used to optimize repeated calls. A cache entry is considered
valid for this many seconds after it has been checked. */
/** \copydoc cacheLifetime */
float _cacheLifetime() const {
return m_cacheLifetime;
}
/** Creates the directory named, including any subdirectories
that do not already exist.
The directory must not be inside a zipfile.
Flushes the cache.
*/
/** \copydoc createDirectory */
void _createDirectory(const std::string& path);
/** Returns true if a node named \a f exists.
/** \copydoc exists */
bool _exists(const std::string& f, bool trustCache = true, bool caseSensitive =
#ifdef G3D_WINDOWS
false
#else
true
#endif
);
\param f If \a f contains wildcards, the function returns true if any file
matches those wildcards. Wildcards may only appear in the base or ext, not the
path.
\param trustCache If true, uses the cache for optimizing repeated calls
in the same parent directory.
*/
bool _exists(const std::string& f, bool trustCache = true);
/** Known bug: does not work inside zipfiles */
/** \copydoc isDirectory */
bool _isDirectory(const std::string& path);
/** Known bug: does not work inside zipfiles */
/** \copydoc isFile */
bool _isFile(const std::string& path) {
return ! isDirectory(path);
}
/**
\param srcPath Must name a file.
\param dstPath Must not contain a zipfile.
Flushes the cache.
*/
/** \copydoc copyFile */
void _copyFile(const std::string& srcPath, const std::string& dstPath);
/** Fully qualifies a filename.
The filename may contain wildcards, in which case the wildcards will be preserved in the returned value.
\param cwd The directory to treat as the "current" directory when resolving a relative path. The default
value is the actual current directory. (G3D::Any::sourceDirectory is a common alternative)
*/
/** \copydoc resolve */
std::string _resolve(const std::string& path, const std::string& cwd = currentDirectory());
/** Returns true if \param dst does not exist or \param src is newer than \param dst,
according to their time stamps.
Known bug: does not work inside zipfiles.
*/
/** \copydoc isNewer */
bool _isNewer(const std::string& src, const std::string& dst);
/** The current working directory (cwd). Only ends in a slash if this is the root of the file system. */
/** \copydoc currentDirectory */
std::string _currentDirectory();
/** Returns the length of the file in bytes, or -1 if the file could not be opened. */
/** \copydoc size */
int64 _size(const std::string& path);
/** Called from list() */
void listHelper(const std::string& shortSpec, const std::string& parentPath, Array<std::string>& result, const ListSettings& settings);
/** Appends all nodes matching \a spec to the \a result array.
Wildcards can only appear to the right of the last slash in \a spec.
The names will not contain parent paths unless \a includePath == true.
These may be relative to the current directory unless \a spec
is fully qualified (can be done with resolveFilename).
*/
/** \copydoc list */
void _list(const std::string& spec, Array<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" */
/** \copydoc isZipfile */
bool _isZipfile(const std::string& path);
/** list() files */
/** \copydoc getFiles */
void _getFiles(const std::string& spec, Array<std::string>& result, bool includeParentPath = false) {
ListSettings set;
set.includeParentPath = includeParentPath;
@@ -250,7 +222,7 @@ private:
return list(spec, result, set);
}
/** list() directories */
/** \copydoc getDirectories */
void _getDirectories(const std::string& spec, Array<std::string>& result, bool includeParentPath = false) {
ListSettings set;
set.includeParentPath = includeParentPath;
@@ -259,12 +231,13 @@ private:
return list(spec, result, set);
}
/** Same as the C standard library fopen, but updates the file cache
to acknowledge the new file on a write operation. */
/** \copydoc fopen */
FILE* _fopen(const char* filename, const char* mode);
public:
/** \copydoc removeFile */
void _removeFile(const std::string& path);
public:
/** Create the common instance. */
static void init();
@@ -272,111 +245,267 @@ public:
/** Destroy the common instance. */
static void cleanup();
# ifdef G3D_WIN32
/** \copydoc _drives */
# ifdef G3D_WINDOWS
/** On Windows, the drive letters that form the file system roots.*/
static const Array<std::string>& drives() {
return instance()._drives();
mutex.lock();
const Array<std::string>& s = instance()._drives();
mutex.unlock();
return s;
}
# endif
/** \copydoc _inZipfile */
/** Returns true if some sub-path of \a path is a zipfile.
If the path itself is a zipfile, returns false.
\param zipfile The part of \a path that was the zipfile
*/
static bool inZipfile(const std::string& path, std::string& zipfile) {
return instance()._inZipfile(path, zipfile);
mutex.lock();
bool b = instance()._inZipfile(path, zipfile);
mutex.unlock();
return b;
}
/** \copydoc _clearCache */
/** Clears old cache entries so that exists() and list() will reflect recent changes to the file system.
\param path Clear only \a path and its subdirectories ("" means clear the entire cache) */
static void clearCache(const std::string& path = "") {
mutex.lock();
instance()._clearCache(path);
mutex.unlock();
}
/** \copydoc _fopen */
/** Same as the C standard library fopen, but updates the file cache
to acknowledge the new file on a write operation. */
static FILE* fopen(const char* filename, const char* mode) {
return instance()._fopen(filename, mode);
mutex.lock();
FILE* f = instance()._fopen(filename, mode);
mutex.unlock();
return f;
}
static void fclose(FILE* f) {
mutex.lock();
::fclose(f);
mutex.unlock();
}
/** Returns true if some sub-path of \a path is a zipfile.
If the path itself is a zipfile, returns false.
*/
static bool inZipfile(const std::string& path) {
return instance()._inZipfile(path);
mutex.lock();
bool b = instance()._inZipfile(path);
mutex.unlock();
return b;
}
/** \copydoc isZipfile */
/**
\brief Delete this file.
No effect if \a path does not exist.
\param path May contain wildcards. May not be inside a zipfile.
*/
static void removeFile(const std::string& path) {
mutex.lock();
instance()._removeFile(path);
mutex.unlock();
}
/** Returns true if \a path is a file that is a zipfile. Note that G3D requires zipfiles to have
some extension, although it is not required to be "zip" */
static bool isZipfile(const std::string& path) {
return instance()._isZipfile(path);
mutex.lock();
bool b = instance()._isZipfile(path);
mutex.unlock();
return b;
}
/** \copydoc _setCacheLifetime */
/** Set the cacheLifetime().
\param t in seconds */
void setCacheLifetime(float t) {
mutex.lock();
instance()._setCacheLifetime(t);
mutex.unlock();
}
/** \copydoc _cacheLifetime */
/** A cache is used to optimize repeated calls. A cache entry is considered
valid for this many seconds after it has been checked. */
static float cacheLifetime() {
return instance()._cacheLifetime();
mutex.lock();
float f = instance()._cacheLifetime();
mutex.unlock();
return f;
}
/** \copydoc _createDirectory */
/** Creates the directory named, including any subdirectories
that do not already exist.
The directory must not be inside a zipfile.
Flushes the cache.
*/
static void createDirectory(const std::string& path) {
mutex.lock();
instance()._createDirectory(path);
mutex.unlock();
}
/** \copydoc _currentDirectory */
/** The current working directory (cwd). Only ends in a slash if this is the root of the file system. */
static std::string currentDirectory() {
return instance()._currentDirectory();
mutex.lock();
const std::string& s = instance()._currentDirectory();
mutex.unlock();
return s;
}
/** \copydoc _copyFile */
/**
\param srcPath Must name a file.
\param dstPath Must not contain a zipfile.
Flushes the cache.
*/
static void copyFile(const std::string& srcPath, const std::string& dstPath) {
mutex.lock();
instance()._copyFile(srcPath, dstPath);
mutex.unlock();
}
/** \copydoc _exists */
static bool exists(const std::string& f, bool trustCache = true) {
return instance()._exists(f, trustCache);
/** Returns true if a node named \a f exists.
\param f If \a f contains wildcards, the function returns true if any file
matches those wildcards. Wildcards may only appear in the base or ext, not the
path. Environment variables beginning with dollar signs (e.g., in "$G3DDATA/cubemap"),
with optional parens ("$(G3DDATA)") are
automatically expanded in \a f. Default share names on Windows (e.g., "\\mycomputer\c$")
are correctly distinguished from empty environment variables.
\param trustCache If true, uses the cache for optimizing repeated calls
in the same parent directory.
\param caseSensitive If true, the match must have exactly the same case for the base and extension. If false,
case is ignored. The default on Windows is false and the default on other operating systems is true.
*/
static bool exists(const std::string& f, bool trustCache = true, bool caseSensitive =
#ifdef G3D_WINDOWS
false
#else
true
#endif
) {
mutex.lock();
bool e = instance()._exists(f, trustCache, caseSensitive);
mutex.unlock();
return e;
}
/** \copydoc _isDirectory */
/** Known bug: does not work inside zipfiles */
static bool isDirectory(const std::string& path) {
return instance()._isDirectory(path);
mutex.lock();
bool b = instance()._isDirectory(path);
mutex.unlock();
return b;
}
/** \copydoc _isFile */
/** Known bug: does not work inside zipfiles */
static bool isFile(const std::string& path) {
return instance()._isFile(path);
mutex.lock();
bool b = instance()._isFile(path);
mutex.unlock();
return b;
}
/** \copydoc _resolve */
/** Fully qualifies a filename.
The filename may contain wildcards, in which case the wildcards will be preserved in the returned value.
\param cwd The directory to treat as the "current" directory when resolving a relative path. The default
value is the actual current directory. (G3D::Any::sourceDirectory is a common alternative)
*/
static std::string resolve(const std::string& path, const std::string& cwd = currentDirectory()) {
return instance()._resolve(path, cwd);
mutex.lock();
const std::string& s = instance()._resolve(path, cwd);
mutex.unlock();
return s;
}
/** \copydoc _isNewer */
/** Returns true if \a dst does not exist or \a src is newer than \a dst,
according to their time stamps.
Known bug: does not work inside zipfiles.
*/
static bool isNewer(const std::string& src, const std::string& dst) {
return instance()._isNewer(src, dst);
mutex.lock();
bool b = instance()._isNewer(src, dst);
mutex.unlock();
return b;
}
/** \copydoc _size */
/** Returns the length of the file in bytes, or -1 if the file could not be opened. */
static int64 size(const std::string& path) {
return instance()._size(path);
mutex.lock();
int64 i = instance()._size(path);
mutex.unlock();
return i;
}
/** \copydoc _list */
/** Appends all nodes matching \a spec to the \a result array.
Wildcards can only appear to the right of the last slash in \a spec.
The names will not contain parent paths unless \a includePath == true.
These may be relative to the current directory unless \a spec
is fully qualified (can be done with resolveFilename).
*/
static void list(const std::string& spec, Array<std::string>& result,
const ListSettings& listSettings = ListSettings()) {
return instance()._list(spec, result, listSettings);
mutex.lock();
instance()._list(spec, result, listSettings);
mutex.unlock();
}
/** \copydoc _getFiles */
/** list() files */
static void getFiles(const std::string& spec, Array<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) {
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. */
static std::string concat(const std::string& a, const std::string& b);
/** Returns true if \a f specifies a path that parses as root of the filesystem.
On OS X and other Unix-based operating systems, "/" is the only root.
On Windows, drive letters and shares are roots, e.g., "c:\", "\\foo\".
Does not check on Windows to see if the root is actually mounted or a legal
drive letter--this is a purely string based test. */
static bool isRoot(const std::string& f);
/** Removes the trailing slash unless \a f is a filesystem root */
@@ -423,6 +557,11 @@ public:
/** Convert all slashes to '/' */
static std::string canonicalize(std::string x);
/** \brief Replaces <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.
@@ -454,11 +593,13 @@ public:
std::string& base,
std::string& ext);
/**
Returns true if \a path matches \a pattern, with standard filesystem wildcards.
*/
static bool matches(const std::string& path, const std::string& pattern, bool caseSensitive = true);
/** Replaces characters that are illegal in a filename with legal equivalents.*/
static std::string makeLegalFilename(const std::string& f, size_t maxLength = 100000);
};
} // namespace G3D

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
appropriate namespaces.
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-08-25
@edited 2010-03-20
\created 2001-08-25
\edited 2013-03-24
Copyright 2000-2010, Morgan McGuire.
Copyright 2000-2013, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_G3D_h
#define G3D_G3D_h
#define NOMINMAX 1
#ifndef NOMINMAX
#define NOMINMAX 1
#endif
#ifdef min
#undef min
#endif
@@ -24,18 +25,30 @@
#undef max
#endif
#include "G3D/HaltonSequence.h"
#include "G3D/platform.h"
#include "G3D/Proxy.h"
#include "G3D/BIN.h"
#include "G3D/FileNotFound.h"
#include "G3D/units.h"
#include "G3D/ParseError.h"
#include "G3D/Random.h"
#include "G3D/Noise.h"
#include "G3D/Array.h"
#include "G3D/SmallArray.h"
#include "G3D/Queue.h"
#include "G3D/Crypto.h"
#include "G3D/format.h"
#include "G3D/Vector2.h"
#include "G3D/Vector2int32.h"
#include "G3D/Vector2int16.h"
#include "G3D/Vector2unorm16.h"
#include "G3D/Vector3.h"
#include "G3D/Vector3int16.h"
#include "G3D/Vector3int32.h"
#include "G3D/Vector4.h"
#include "G3D/Vector4int16.h"
#include "G3D/Vector4int8.h"
#include "G3D/Color1.h"
#include "G3D/Color3.h"
#include "G3D/Color4.h"
@@ -43,6 +56,7 @@
#include "G3D/Matrix3.h"
#include "G3D/Matrix4.h"
#include "G3D/CoordinateFrame.h"
#include "G3D/Projection.h"
#include "G3D/PhysicsFrame.h"
#include "G3D/PhysicsFrameSpline.h"
#include "G3D/Plane.h"
@@ -53,6 +67,7 @@
#include "G3D/Box2D.h"
#include "G3D/AABox.h"
#include "G3D/WrapMode.h"
#include "G3D/CullFace.h"
#include "G3D/Cone.h"
#include "G3D/Quat.h"
#include "G3D/stringutils.h"
@@ -61,6 +76,7 @@
#include "G3D/FileSystem.h"
#include "G3D/Set.h"
#include "G3D/GUniqueID.h"
#include "G3D/RayGridIterator.h"
#include "G3D/BinaryFormat.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
@@ -68,6 +84,10 @@
#include "G3D/g3dfnmatch.h"
#include "G3D/G3DGameUnits.h"
#include "G3D/g3dmath.h"
#include "G3D/unorm8.h"
#include "G3D/unorm16.h"
#include "G3D/snorm8.h"
#include "G3D/snorm16.h"
#include "G3D/uint128.h"
#include "G3D/fileutils.h"
#include "G3D/ReferenceCount.h"
@@ -75,14 +95,19 @@
#include "G3D/GMutex.h"
#include "G3D/PrecomputedRandom.h"
#include "G3D/MemoryManager.h"
#include "G3D/BlockPoolMemoryManager.h"
#include "G3D/AreaMemoryManager.h"
#include "G3D/BumpMapPreprocess.h"
#include "G3D/CubeFace.h"
#include "G3D/Line2D.h"
#include "G3D/ThreadsafeQueue.h"
#include "G3D/network.h"
template<class T> struct HashTrait< G3D::ReferenceCountedPointer<T> > {
static size_t hashCode(G3D::ReferenceCountedPointer<T> key) { return reinterpret_cast<size_t>( key.pointer() ); }
template<class T> struct HashTrait< shared_ptr<T> > {
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/Intersect.h"
#include "G3D/Log.h"
@@ -98,18 +123,14 @@ template<class T> struct HashTrait< G3D::ReferenceCountedPointer<T> > {
#include "G3D/Capsule.h"
#include "G3D/Cylinder.h"
#include "G3D/Triangle.h"
#include "G3D/Color3uint8.h"
#include "G3D/Color4uint8.h"
#include "G3D/Vector2int16.h"
#include "G3D/Vector3int16.h"
#include "G3D/Vector3int32.h"
#include "G3D/Vector4int8.h"
#include "G3D/Color1unorm8.h"
#include "G3D/Color2unorm8.h"
#include "G3D/Color3unorm8.h"
#include "G3D/Color4unorm8.h"
#include "G3D/ConvexPolyhedron.h"
#include "G3D/MeshAlg.h"
#include "G3D/vectorMath.h"
#include "G3D/Rect2D.h"
#include "G3D/GCamera.h"
#include "G3D/GLight.h"
#include "G3D/KDTree.h"
#include "G3D/PointKDTree.h"
#include "G3D/TextOutput.h"
@@ -124,40 +145,82 @@ template<class T> struct HashTrait< G3D::ReferenceCountedPointer<T> > {
#include "G3D/PointHashGrid.h"
#include "G3D/Map2D.h"
#include "G3D/Image1.h"
#include "G3D/Image1uint8.h"
#include "G3D/Image1unorm8.h"
#include "G3D/Image3.h"
#include "G3D/Image3uint8.h"
#include "G3D/Image3unorm8.h"
#include "G3D/Image4.h"
#include "G3D/Image4uint8.h"
#include "G3D/Image4unorm8.h"
#include "G3D/filter.h"
#include "G3D/WeakCache.h"
#include "G3D/Pointer.h"
#include "G3D/Matrix.h"
#include "G3D/ImageFormat.h"
#include "G3D/PixelTransferBuffer.h"
#include "G3D/typeutils.h"
#include "G3D/SpeedLoad.h"
#include "G3D/ParseMTL.h"
#include "G3D/ParseOBJ.h"
#include "G3D/ParsePLY.h"
#include "G3D/Parse3DS.h"
#include "G3D/PathDirection.h"
#include "G3D/FastPODTable.h"
#include "G3D/FastPointHashGrid.h"
#include "G3D/PixelTransferBuffer.h"
#include "G3D/CPUPixelTransferBuffer.h"
#include "G3D/CompassDirection.h"
#include "G3D/Access.h"
namespace G3D {
/**
Call from main() to initialize the G3D library state and register
shutdown memory managers. This does not initialize OpenGL.
If you invoke initGLG3D, then it will automatically call initG3D.
It is safe to call this function more than once--it simply ignores
multiple calls.
\see System, GLCaps, OSWindow, RenderDevice, initGLG3D.
*/
void initG3D(const G3DSpecification& spec = G3DSpecification());
}
#ifdef _MSC_VER
# pragma comment(lib, "zlib")
# pragma comment(lib, "ws2_32")
# pragma comment(lib, "winmm")
# pragma comment(lib, "imagehlp")
# pragma comment(lib, "ws2_32")
# pragma comment(lib, "gdi32")
# pragma comment(lib, "user32")
# pragma comment(lib, "kernel32")
# pragma comment(lib, "version")
# pragma comment(lib, "advapi32")
# pragma comment(lib, "png")
# pragma comment(lib, "jpeg")
# pragma comment(lib, "zip")
# ifdef _DEBUG
// Don't link against G3D when building G3D itself.
# ifndef G3D_BUILDING_LIBRARY_DLL
# pragma comment(lib, "G3Dd.lib")
# endif
# pragma comment(lib, "shell32")
# pragma comment(lib, "version")
# ifdef G3D_64BIT
# pragma comment(lib, "zlib_x64")
# pragma comment(lib, "zip_x64")
# pragma comment(lib, "enet_x64")
# else
// Don't link against G3D when building G3D itself.
# ifndef G3D_BUILDING_LIBRARY_DLL
# pragma comment(lib, "G3D.lib")
# endif
# pragma comment(lib, "zlib")
# pragma comment(lib, "zip")
# pragma comment(lib, "enet")
# endif
# if defined(_DEBUG)
# ifdef G3D_64BIT
# pragma comment(lib, "G3D_x64d")
# pragma comment(lib, "freeimage_x64d")
# else
# pragma comment(lib, "G3Dd")
# pragma comment(lib, "freeimaged")
# endif
# else
# ifdef G3D_64BIT
# pragma comment(lib, "G3D_x64")
# pragma comment(lib, "freeimage_x64")
# else
# pragma comment(lib, "G3D")
# pragma comment(lib, "freeimage")
# endif
# endif
#endif

View File

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

View File

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

View File

@@ -2,18 +2,21 @@
@file GThread.h
@created 2005-09-22
@edited 2007-01-31
@edited 2010-09-10
*/
#ifndef G3D_GTHREAD_H
#define G3D_GTHREAD_H
#ifndef G3D_GThread_h
#define G3D_GThread_h
#include "G3D/platform.h"
#include "G3D/ReferenceCount.h"
#include "G3D/ThreadSet.h"
#include "G3D/Vector2int32.h"
#include "G3D/SpawnBehavior.h"
#include <string>
#ifndef G3D_WIN32
#ifndef G3D_WINDOWS
# include <pthread.h>
# include <signal.h>
#endif
@@ -21,7 +24,9 @@
namespace G3D {
typedef ReferenceCountedPointer<class GThread> GThreadRef;
typedef shared_ptr<class GThread> GThreadRef;
/**
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
stop the underlying process.
@sa G3D::GMutex, G3D::Spinlock, G3D::AtomicInt32
\sa G3D::GMutex, G3D::Spinlock, G3D::AtomicInt32, G3D::ThreadSet
*/
class GThread : public ReferenceCountedObject {
private:
// "Status" is a reserved work on FreeBSD
// "Status" is a reserved word on FreeBSD
enum GStatus {STATUS_CREATED, STATUS_STARTED, STATUS_RUNNING, STATUS_COMPLETED};
// Not implemented on purpose, don't use
@@ -44,21 +49,21 @@ private:
GThread& operator=(const GThread&);
bool operator==(const GThread&);
#ifdef G3D_WIN32
#ifdef G3D_WINDOWS
static DWORD WINAPI internalThreadProc(LPVOID param);
#else
static void* internalThreadProc(void* param);
#endif //G3D_WIN32
#endif //G3D_WINDOWS
volatile GStatus m_status;
// Thread handle to hold HANDLE and pthread_t
#ifdef G3D_WIN32
#ifdef G3D_WINDOWS
HANDLE m_handle;
HANDLE m_event;
#else
pthread_t m_handle;
#endif //G3D_WIN32
#endif //G3D_WINDOWS
std::string m_name;
@@ -68,8 +73,11 @@ protected:
virtual void threadMain() = 0;
public:
typedef ReferenceCountedPointer<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);
@@ -110,12 +118,153 @@ public:
void waitForCompletion();
/** Returns thread name */
inline const std::string& name() {
const std::string& name() {
return m_name;
}
/** For backwards compatibility to G3D 8.xx */
static const SpawnBehavior USE_CURRENT_THREAD = G3D::USE_CURRENT_THREAD;
/** For backwards compatibility to G3D 8.xx */
static const SpawnBehavior USE_NEW_THREAD = G3D::USE_NEW_THREAD;
enum {
/** Tells GThread::runConcurrently() and GThread::runConcurrently2D() to
use System::numCores() threads.*/
NUM_CORES = -100
};
/**
\brief Iterates over a 2D region using multiple threads and
blocks until all threads have completed. <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
#endif //G3D_GTHREAD_H

View File

@@ -1,16 +1,18 @@
/**
@file GUniqueID.h
@author Morgan McGuire, http://graphics.cs.williams.edu
\file G3D/GUniqueID.h
\author Morgan McGuire, http://graphics.cs.williams.edu
*/
#ifndef G3D_GUNIQUEID_H
#define G3D_GUNIQUEID_H
#ifndef G3D_GUniqueID_h
#define G3D_GUniqueID_h
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
#include "G3D/Table.h"
namespace G3D {
class Any;
/** Globally unique identifiers. The probability of two different
programs generating the same value from UniqueID::create is
vanishingly small.
@@ -25,8 +27,27 @@ private:
public:
/** \sa create */
GUniqueID() : id(0) {}
GUniqueID& operator=(const Any& a);
/** \sa create */
GUniqueID(const Any& a) {
*this = a;
}
Any toAny() const;
/** Returns a 16-character string equivalent to this GUniqueID's uint64 value. */
std::string toString16() const;
static GUniqueID fromString16(const std::string& s);
/** Returns the ID that has the specified tag (so that it is not uninitialized), but
which is a common sentinel "none" value. */
static GUniqueID NONE(uint16 tag);
bool uninitialized() const {
return id == 0;
}
@@ -37,7 +58,7 @@ public:
operator uint64() const {
return id;
}
}
bool operator==(const GUniqueID& other) const {
return id == other.id;

View File

@@ -1,11 +1,11 @@
/**
@file HashTrait.h
\file G3D/HashTrait.h
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2008-10-01
@edited 2009-11-01
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
\created 2008-10-01
\edited 2011-06-09
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
@@ -16,6 +16,88 @@
#include "G3D/Crypto.h"
#include "G3D/g3dmath.h"
#include "G3D/uint128.h"
#include <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.
@see G3D::Table for specialization requirements.
@@ -23,14 +105,19 @@
template <typename T> struct HashTrait{};
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
template <> struct HashTrait <int> {
static size_t hashCode(int k) { return static_cast<size_t>(k); }
/** For use with \code Table<std::type_info* const, ValueType> \endcode. */
template <> struct HashTrait <std::type_info* const> {
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> {
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); }
};
//template <> struct HashTrait <int> {
// static size_t hashCode(int k) { return static_cast<size_t>(k); }
//};
template <> struct HashTrait <G3D::int32> {
static size_t hashCode(G3D::int32 k) { return static_cast<size_t>(k); }
};
@@ -58,21 +141,30 @@ template <> struct HashTrait <long unsigned int> {
};
#endif
template <> struct HashTrait <G3D::int64> {
static size_t hashCode(G3D::int64 k) { return static_cast<size_t>(k); }
};
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> {
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> {
// Use the FNV-1 hash (http://isthe.com/chongo/tech/comp/fnv/#FNV-1).
static size_t hashCode(G3D::uint128 key) {
return G3D::superFastHash(&key, sizeof(key));
//return HashTrait<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_OFFSET_128(0xCF470AAC6CB293D2ULL, 0xF52F88BF32307F8FULL);
@@ -83,9 +175,10 @@ template <> struct HashTrait<G3D::uint128> {
hash ^= (mask & key);
key >>= 8;
}
G3D::uint64 foldedHash = hash.hi ^ hash.lo;
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
@edited 2007-01-31
\created 2007-01-31
\edited 2011-08-31
*/
#ifndef G3D_IMAGE1_H
#define G3D_IMAGE1_H
#ifndef G3D_Image1_h
#define G3D_Image1_h
#include "G3D/platform.h"
#include "G3D/Map2D.h"
#include "G3D/Color1.h"
#include "G3D/GImage.h"
namespace G3D {
typedef ReferenceCountedPointer<class Image1> Image1Ref;
typedef shared_ptr<class Image1> Image1Ref;
/**
Luminance image with 32-bit floating point storage.
See also G3D::Image1uint8, G3D::GImage.
See also G3D::Image1unorm8, G3D::GImage.
*/
class Image1 : public Map2D<Color1, Color1> {
public:
typedef Image1 Type;
typedef ReferenceCountedPointer<class Image1> Ref;
typedef shared_ptr<class Image1> Ref;
typedef Color1 Storage;
typedef Color1 Compute;
@@ -41,9 +40,9 @@ protected:
void copyArray(const Color1* src, int w, int h);
void copyArray(const Color3* src, int w, int h);
void copyArray(const Color4* src, int w, int h);
void copyArray(const Color1uint8* src, int w, int h);
void copyArray(const Color3uint8* src, int w, int h);
void copyArray(const Color4uint8* src, int w, int h);
void copyArray(const Color1unorm8* src, int w, int h);
void copyArray(const Color3unorm8* src, int w, int h);
void copyArray(const Color4unorm8* src, int w, int h);
public:
@@ -55,25 +54,28 @@ public:
/** Creates a 0 x 0 image. */
static Ref createEmpty(WrapMode wrap = WrapMode::ERROR);
static Ref fromFile(const std::string& filename, WrapMode wrap = WrapMode::ERROR, GImage::Format fmt = GImage::AUTODETECT);
static Ref fromFile(const std::string& filename, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color1uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color3uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color4uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color1unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color3unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color4unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color1* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color3* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color4* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromImage1uint8(const ReferenceCountedPointer<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,
it is stripped. */
void load(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT);
If there is an alpha channel on the input, it is stripped.
Values are automatically scaled to the range [0, 1]. */
void load(const std::string& filename);
/** Saves in any of the formats supported by G3D::GImage. */
void save(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT);
/** Saves in any of the formats supported by G3D::Image.
The data values are assumed to be on the range [0, 1] and will
be scaled appropriately for the save format.*/
void save(const std::string& filename);
};
} // G3D

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

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
@edited 2007-01-31
\created 2007-01-31
\edited 2011-08-11
*/
#ifndef G3D_IMAGE4_H
#define G3D_IMAGE4_H
#ifndef G3D_Image4_h
#define G3D_Image4_h
#include "G3D/platform.h"
#include "G3D/Map2D.h"
#include "G3D/Color4.h"
#include "G3D/GImage.h"
namespace G3D {
typedef ReferenceCountedPointer<class Image4> Image4Ref;
typedef shared_ptr<class Image4> Image4Ref;
/**
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.
Bilinear interpolation on Image4 is about 8x faster than on
Image4uint8 due to the large cost of converting int->float on modern
Image4unorm8 due to the large cost of converting int->float on modern
machines.
@sa G3D::Image4uint8, G3D::GImage.
@sa G3D::Image4unorm8, G3D::GImage.
*/
class Image4 : public Map2D<Color4, Color4> {
public:
typedef Image4 Type;
typedef ReferenceCountedPointer<class Image4> Ref;
typedef Color4 Storage;
typedef Color4 Compute;
typedef shared_ptr<class Image4> Ref;
protected:
Image4(int w, int h, WrapMode wrap);
void copyGImage(const class GImage& im);
void copyArray(const Color1* src, int w, int h);
void copyArray(const Color3* src, int w, int h);
void copyArray(const Color4* src, int w, int h);
void copyArray(const Color1uint8* src, int w, int h);
void copyArray(const Color3uint8* src, int w, int h);
void copyArray(const Color4uint8* src, int w, int h);
void copyArray(const Color1unorm8* src, int w, int h);
void copyArray(const Color3unorm8* src, int w, int h);
void copyArray(const Color4unorm8* src, int w, int h);
public:
@@ -61,24 +57,22 @@ public:
/** Creates a 0 x 0 image. */
static Ref createEmpty(WrapMode wrap = WrapMode::ERROR);
static Ref fromFile(const std::string& filename, WrapMode wrap = WrapMode::ERROR, GImage::Format fmt = GImage::AUTODETECT);
static Ref fromFile(const std::string& filename, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color1uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color3uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color4uint8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color1unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color3unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color4unorm8* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color1* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color3* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromArray(const class Color4* ptr, int width, int height, WrapMode wrap = WrapMode::ERROR);
static Ref fromImage4uint8(const ReferenceCountedPointer<class Image4uint8>& im);
static Ref fromGImage(const class GImage& im, WrapMode wrap = WrapMode::ERROR);
static Ref fromImage4unorm8(const shared_ptr<class Image4unorm8>& im);
/** Loads from any of the file formats supported by G3D::GImage. */
void load(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT);
void load(const std::string& filename);
/** Saves in any of the formats supported by G3D::GImage. */
void save(const std::string& filename, GImage::Format fmt = GImage::AUTODETECT);
void save(const std::string& filename);
};
} // G3D

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
@edited 2010-05-01
\created 2003-05-23
\edited 2013-06-06
*/
#ifndef GLG3D_ImageFormat_H
#define GLG3D_ImageFormat_H
#ifndef GLG3D_ImageFormat_h
#define GLG3D_ImageFormat_h
#include "G3D/platform.h"
#include "G3D/Table.h"
@@ -17,16 +17,22 @@
namespace G3D {
/** Information about common image formats.
Don't construct these; use the methods provided.
/** Information about common image formats. Don't construct these;
use the methods provided to access the const instances.
For most formats, the number indicates the number of bits per channel and a suffix of "F" indicates
floating point. This does not hold for the YUV and DXT formats.*/
For most formats, the number indicates the number of bits per
channel and a suffix of "F" indicates floating point (following
OpenGL conventions). This does not hold for the YUV and DXT
formats.
\sa G3D::Image, G3D::Texture, G3D::ImageConvert
*/
class ImageFormat {
public:
// Must update ImageFormat::name() when this enum changes.
enum Code {
CODE_AUTO = -2,
CODE_NONE = -1,
CODE_L8,
CODE_L16,
@@ -58,24 +64,57 @@ public:
CODE_RGB8I,
CODE_RGB8UI,
CODE_RGBA8I,
CODE_RGBA8UI,
CODE_RGB8_SNORM,
CODE_RGBA8_SNORM,
CODE_RGB16_SNORM,
CODE_RGBA16_SNORM,
CODE_ARGB8,
CODE_BGR8,
CODE_BGRA8,
CODE_R8,
CODE_R8I,
CODE_R8UI,
CODE_R16,
CODE_R16I,
CODE_R16UI,
CODE_R32I,
CODE_R32UI,
CODE_RG8,
CODE_RG8I,
CODE_RG8UI,
CODE_RG16,
CODE_RG16I,
CODE_RG16UI,
CODE_R16F,
CODE_RG16F,
CODE_RG32I,
CODE_RG32UI,
CODE_R32F,
CODE_RG32F,
CODE_RGBA8,
CODE_RGBA16,
CODE_RGBA16F,
CODE_RGBA32F,
CODE_RGBA16I,
CODE_RGBA16UI,
CODE_RGB32I,
CODE_RGB32UI,
CODE_RGBA32I,
CODE_RGBA32UI,
CODE_BAYER_RGGB8,
@@ -141,6 +180,14 @@ public:
BAYER_PATTERN_BGGR
};
enum NumberFormat {
FLOATING_POINT_FORMAT,
INTEGER_FORMAT,
NORMALIZED_FIXED_POINT_FORMAT,
OTHER // e.g. DXT
};
/** Number of channels (1 for a depth texture). */
int numComponents;
bool compressed;
@@ -182,10 +229,6 @@ public:
/** Amount of CPU memory per pixel when packed into an array, discounting any end-of-row padding. */
int cpuBitsPerPixel;
/** Amount of CPU memory per pixel when packed into an array, discounting any end-of-row padding.
@deprecated Use cpuBitsPerPixel*/
int packedBitsPerTexel;
/**
Amount of GPU memory per pixel on most graphics cards, for formats supported by OpenGL. This is
only an estimate--the actual amount of memory may be different on your actual card.
@@ -196,24 +239,38 @@ public:
*/
int openGLBitsPerPixel;
/** @deprecated Use openGLBitsPerPixel */
int hardwareBitsPerTexel;
/** The OpenGL bytes (type) format of the data buffer used with this texture format, e.g., GL_UNSIGNED_BYTE */
int openGLDataFormat;
/** True if there is no alpha channel for this texture. */
bool opaque;
/** True if the bit depths specified are for float formats. */
/** True if the bit depths specified are for float formats. TODO: Remove, replace with function keying off numberFormat */
bool floatingPoint;
/** Indicates whether this format treats numbers as integers, floating point, or normalized fixed point */
NumberFormat numberFormat;
/** Human readable name of this format.*/
const std::string& name() const;
/** True if data in otherFormat is binary compatible */
bool canInterpretAs(const ImageFormat* otherFormat) const;
/** Returns ImageFormat representing the same channels as \a
otherFormat plus an alpha channel, all with at least the same
precision as \a otherFormat, or returns NULL if an equivalent
format is unavailable. Will return itself if already contains
an alpha channel. */
static const ImageFormat* getFormatWithAlpha(const ImageFormat* otherFormat);
static const ImageFormat* getSRGBFormat(const ImageFormat* otherFormat);
/** Takes the same values that name() returns */
static const ImageFormat* fromString(const std::string& s);
private:
ImageFormat
@@ -228,11 +285,11 @@ private:
int blueBits,
int depthBits,
int stencilBits,
int hardwareBitsPerTexel,
int packedBitsPerTexel,
int openGLBitsPerPixel,
int cpuBitsPerPixel,
int glDataFormat,
bool opaque,
bool floatingPoint,
NumberFormat numberFormat,
Code code,
ColorSpace colorSpace,
BayerPattern bayerPattern = BAYER_PATTERN_NONE);
@@ -267,14 +324,36 @@ public:
static const ImageFormat* BGR8();
static const ImageFormat* BGRA8();
static const ImageFormat* R8();
static const ImageFormat* R8I();
static const ImageFormat* R8UI();
static const ImageFormat* R16();
static const ImageFormat* R16I();
static const ImageFormat* R16UI();
static const ImageFormat* R32I();
static const ImageFormat* R32UI();
static const ImageFormat* RG8();
static const ImageFormat* RG8I();
static const ImageFormat* RG8UI();
static const ImageFormat* RG16();
static const ImageFormat* RG16I();
static const ImageFormat* RG16UI();
static const ImageFormat* R16F();
static const ImageFormat* RG16F();
static const ImageFormat* RG32I();
static const ImageFormat* RG32UI();
static const ImageFormat* R32F();
static const ImageFormat* RG32F();
static const ImageFormat* RGB5();
static const ImageFormat* RGB5A1();
@@ -299,6 +378,12 @@ public:
static const ImageFormat* RGBA32F();
static const ImageFormat* RGBA16I();
static const ImageFormat* RGBA16UI();
static const ImageFormat* RGB32UI();
static const ImageFormat* RGB32I();
static const ImageFormat* RGBA32I();
static const ImageFormat* RGBA32UI();
static const ImageFormat* R11G11B10F();
@@ -309,8 +394,15 @@ public:
static const ImageFormat* RGB8UI();
static const ImageFormat* RGBA8I();
static const ImageFormat* RGBA8UI();
static const ImageFormat* RGB8_SNORM();
static const ImageFormat* RGBA8_SNORM();
static const ImageFormat* RGB16_SNORM();
static const ImageFormat* RGBA16_SNORM();
static const ImageFormat* RGB_DXT1();
static const ImageFormat* RGBA_DXT1();
@@ -359,7 +451,7 @@ public:
static const ImageFormat* YUV444();
/**
/**
NULL pointer; indicates that the G3D::Texture class should choose
either RGBA8 or RGB8 depending on the presence of an alpha channel
in the input.
@@ -381,7 +473,6 @@ public:
static const ImageFormat* fromCode(ImageFormat::Code code);
/** For use with ImageFormat::convert. */
class BayerAlgorithm {
public:
@@ -418,13 +509,48 @@ public:
YUV422 expects data in YUY2 format (Y, U, Y2, v). Most YUV formats require width and heights that are multiples of 2.
Returns true if a conversion was available, false if none occurred.
\deprecated
\sa G3D::ImageConvert
*/
static bool convert(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits,
const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits,
bool invertY = false, BayerAlgorithm bayerAlg = BayerAlgorithm::MHC);
const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits,
bool invertY = false, BayerAlgorithm bayerAlg = BayerAlgorithm::MHC);
/* Checks if a conversion between two formats is available. */
/**
Checks if a conversion between two formats is available.
\deprecated
\sa G3D::ImageConvert
*/
static bool conversionAvailable(const ImageFormat* srcFormat, int srcRowPadBits, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY = false);
/** Does this contain exactly one unorm8 component? */
bool representableAsColor1unorm8() const;
/** Does this contain exactly two unorm8 components? */
bool representableAsColor2unorm8() const;
/** Does this contain exactly three unorm8 components? */
bool representableAsColor3unorm8() const;
/** Does this contain exactly four unorm8 components? */
bool representableAsColor4unorm8() const;
/** Returns a Color4 that masks off unused components in the format, given in RGBA
For example, the mask for R32F is (1,0,0,0), for A32F is (0,0,0,1), for RGB32F is (1,1,1,0).
(Note that luminance is interpreted as using only the R channel, even though RGB would make more sense
to me...)
*/
Color4 channelMask() const;
bool isIntegerFormat() const{
return (numberFormat == INTEGER_FORMAT);
}
/** Returns true if these formats have the same components
(possibly in different NumberFormat%s or sizes) */
bool sameComponents(const ImageFormat* other) const;
};
typedef ImageFormat TextureFormat;

View File

@@ -27,27 +27,27 @@ namespace G3D {
class Intersect {
public:
/** \brief Returns true if the intersection of the ray and the solid box is non-empty.
/** \brief Returns true if the intersection of the ray and the solid box is non-empty.
\cite "Fast Ray / Axis-Aligned Bounding Box Overlap Tests using Ray Slopes"
by Martin Eisemann, Thorsten Grosch, Stefan M<>ller and Marcus Magnor
by Martin Eisemann, Thorsten Grosch, Stefan M<>ller and Marcus Magnor
Computer Graphics Lab, TU Braunschweig, Germany and
University of Koblenz-Landau, Germany
*/
static bool __fastcall rayAABox(const Ray& ray, const AABox& box);
static bool __fastcall rayAABox(const Ray& ray, const AABox& box);
/** \brief Returns true if the intersection of the ray and the solid box is non-empty.
/** \brief Returns true if the intersection of the ray and the solid box is non-empty.
\param time If there is an intersection, set to the time to that intersection. If the ray origin is inside the box,
this is a negative value indicating the distance backwards from the ray origin to the first intersection.
\a time is not set if there is no intersection.
\cite Slope-Mul method from "Fast Ray / Axis-Aligned Bounding Box Overlap Tests using Ray Slopes"
by Martin Eisemann, Thorsten Grosch, Stefan M<>ller and Marcus Magnor
by Martin Eisemann, Thorsten Grosch, Stefan M<>ller and Marcus Magnor
Computer Graphics Lab, TU Braunschweig, Germany and
University of Koblenz-Landau, Germany
*/
static bool __fastcall rayAABox(const Ray& ray, const AABox& box, float& time);
static bool __fastcall rayAABox(const Ray& ray, const AABox& box, float& time);
};
}

View File

@@ -10,8 +10,8 @@
All rights reserved.
*/
#ifndef G3D_KDTREE_H
#define G3D_KDTREE_H
#ifndef G3D_KDTree_h
#define G3D_KDTree_h
#include "G3D/platform.h"
#include "G3D/Array.h"
@@ -24,11 +24,10 @@
#include "G3D/Box.h"
#include "G3D/Triangle.h"
#include "G3D/Ray.h"
#include "G3D/GCamera.h"
#include "G3D/Frustum.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/CollisionDetection.h"
#include "G3D/GCamera.h"
#include "G3D/BoundsTrait.h"
#include <algorithm>
@@ -260,11 +259,11 @@ protected:
/** Compares centers */
class CenterComparator {
public:
Vector3::Axis sortAxis;
Vector3::Axis sortAxis;
CenterComparator(Vector3::Axis a) : sortAxis(a) {}
CenterComparator(Vector3::Axis a) : sortAxis(a) {}
inline int operator()(Handle* A, const Handle* B) const {
inline int operator()(Handle* A, const Handle* B) const {
float a = A->center[sortAxis];
float b = B->center[sortAxis];
@@ -275,18 +274,18 @@ protected:
} else {
return 0;
}
}
}
};
/** Compares bounds for strict >, <, or overlap*/
class BoundsComparator {
public:
Vector3::Axis sortAxis;
Vector3::Axis sortAxis;
BoundsComparator(Vector3::Axis a) : sortAxis(a) {}
BoundsComparator(Vector3::Axis a) : sortAxis(a) {}
inline int operator()(Handle* A, const Handle* B) const {
inline int operator()(Handle* A, const Handle* B) const {
const AABox& a = A->bounds;
const AABox& b = B->bounds;
@@ -297,34 +296,34 @@ protected:
} else {
return 0;
}
}
}
};
/** Compares bounds to the sort location */
class Comparator {
public:
Vector3::Axis sortAxis;
float sortLocation;
Vector3::Axis sortAxis;
float sortLocation;
Comparator(Vector3::Axis a, float l) : sortAxis(a), sortLocation(l) {}
Comparator(Vector3::Axis a, float l) : sortAxis(a), sortLocation(l) {}
inline int operator()(Handle* ignore, const Handle* handle) const {
inline int operator()(Handle* ignore, const Handle* handle) const {
(void)ignore;
const AABox& box = handle->bounds;
debugAssert(ignore == NULL);
if (box.high()[sortAxis] < sortLocation) {
if (box.high()[sortAxis] < sortLocation) {
// Box is strictly below the sort location
return -1;
} else if (box.low()[sortAxis] > sortLocation) {
} else if (box.low()[sortAxis] > sortLocation) {
// Box is strictly above the sort location
return 1;
} else {
return 1;
} else {
// Box overlaps the sort location
return 0;
}
}
return 0;
}
}
};
// Using System::malloc with this class provided no speed improvement.
@@ -433,8 +432,8 @@ protected:
}
void verifyNode(const Vector3& lo, const Vector3& hi) {
// debugPrintf("Verifying: split %d @ %f [%f, %f, %f], [%f, %f, %f]\n",
// splitAxis, splitLocation, lo.x, lo.y, lo.z, hi.x, hi.y, hi.z);
// debugPrintf("Verifying: split %d @ %f [%f, %f, %f], [%f, %f, %f]\n",
// splitAxis, splitLocation, lo.x, lo.y, lo.z, hi.x, hi.y, hi.z);
debugAssertM(lo == splitBounds.low(),
format("lo = %s, splitBounds.lo = %s",
@@ -444,6 +443,7 @@ protected:
for (int i = 0; i < valueArray.length(); ++i) {
const AABox& b = valueArray[i]->bounds;
debugAssert(b == boundsArray[i]);
(void)b;
for(int axis = 0; axis < 3; ++axis) {
debugAssert(b.low()[axis] <= b.high()[axis]);
@@ -714,27 +714,27 @@ protected:
int numMeanSplits,
Array<Handle*>& temp) {
Node* node = NULL;
if (source.size() <= valuesPerNode) {
// Make a new leaf node
node = new Node(source);
// Set the pointers in the memberTable
for (int i = 0; i < source.size(); ++i) {
memberTable.set(Member(source[i]), node);
}
Node* node = NULL;
if (source.size() <= valuesPerNode) {
// Make a new leaf node
node = new Node(source);
// Set the pointers in the memberTable
for (int i = 0; i < source.size(); ++i) {
memberTable.set(Member(source[i]), node);
}
source.clear();
} else {
// Make a new internal node
node = new Node();
// Make a new internal node
node = new Node();
const AABox& bounds = computeBounds(source, 0, source.size() - 1);
const Vector3& extent = bounds.high() - bounds.low();
Vector3::Axis splitAxis = extent.primaryAxis();
const Vector3& extent = bounds.high() - bounds.low();
Vector3::Axis splitAxis = extent.primaryAxis();
float splitLocation;
// Arrays for holding the children
@@ -829,20 +829,20 @@ protected:
for (int i = 0; i < node->valueArray.size(); ++i) {
Handle* v = node->valueArray[i];
node->boundsArray[i] = v->bounds;
memberTable.set(Member(v), node);
memberTable.set(Member(v), node);
}
if (lt.size() > 0) {
node->child[0] = makeNode(lt, valuesPerNode, numMeanSplits - 1, temp);
}
if (gt.size() > 0) {
node->child[1] = makeNode(gt, valuesPerNode, numMeanSplits - 1, temp);
}
}
return node;
if (lt.size() > 0) {
node->child[0] = makeNode(lt, valuesPerNode, numMeanSplits - 1, temp);
}
if (gt.size() > 0) {
node->child[1] = makeNode(gt, valuesPerNode, numMeanSplits - 1, temp);
}
}
return node;
}
/**
@@ -1211,7 +1211,7 @@ public:
/**
Typically used to find all visible
objects inside the view frustum (see also GCamera::getClipPlanes)... i.e. all objects
objects inside the view frustum (see also Camera::getClipPlanes)... i.e. all objects
<B>not</B> culled by frustum.
Example:
@@ -1222,7 +1222,7 @@ public:
</PRE>
@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;
for (int i = 0; i < frustum.faceArray.size(); ++i) {
@@ -1232,7 +1232,7 @@ public:
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;
getIntersectingMembers(frustum, temp);
for (int i = 0; i < temp.size(); ++i) {
@@ -1450,49 +1450,50 @@ public:
/**
Invoke a callback for every member along a ray until the closest intersection is found.
@param callback either a function or an instance of a class with an overloaded operator() of the form:
<code>void callback(const Ray& ray, const T& object, float& distance)</code>. 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:
@param intersectCallback Either a function or an instance of a class with an overloaded operator() of the form:
<pre>
void callback(const Ray& ray, const T& object, float& distance).
</pre>
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>
class Entity {
public:
void intersect(const Ray& ray, float& maxDist, Vector3& outLocation, Vector3& outNormal) {
float d = maxDist;
void intersect(const Ray& ray, float& maxDist, Vector3& outLocation, Vector3& outNormal) {
float d = maxDist;
// ... search for intersection distance d
// ... search for intersection distance d
if ((d > 0) && (d < maxDist)) {
// Intersection occured
maxDist = d;
outLocation = ...;
outNormal = ...;
}
}
};
if ((d > 0) && (d < maxDist)) {
// Intersection occured
maxDist = d;
outLocation = ...;
outNormal = ...;
}
}
};
// Finds the surface normal and location of the first intersection with the scene
class Intersection {
public:
Entity* closestEntity;
Vector3 hitLocation;
Vector3 hitNormal;
// Finds the surface normal and location of the first intersection with the scene
class Intersection {
public:
Entity* closestEntity;
Vector3 hitLocation;
Vector3 hitNormal;
void operator()(const Ray& ray, const Entity* entity, float& distance) {
entity->intersect(ray, distance, hitLocation, hitNormal);
}
};
void operator()(const Ray& ray, const Entity* entity, float& distance) {
entity->intersect(ray, distance, hitLocation, hitNormal);
}
};
KDTree<Entity*> scene;
Intersection intersection;
float distance = finf();
scene.intersectRay(camera.worldRay(x, y), intersection, distance);
</pre>
KDTree<Entity*> scene;
Intersection intersection;
float distance = finf();
scene.intersectRay(camera.worldRay(x, y), intersection, distance);
</pre>
\endhtmlonly
@param distance When the method is invoked, this is the maximum
distance that the tree should search for an intersection. On

View File

@@ -38,11 +38,11 @@ public:
/** Undefined (provided for creating Array<Line> only) */
inline Line() {}
Line(class BinaryInput& b);
Line(class BinaryInput& b);
void serialize(class BinaryOutput& b) const;
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
void deserialize(class BinaryInput& b);
virtual ~Line() {}

View File

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

View File

@@ -14,7 +14,7 @@
#include <string>
#include "G3D/platform.h"
#ifndef G3D_WIN32
#ifndef G3D_WINDOWS
#include <stdarg.h>
#endif
@@ -57,9 +57,9 @@ private:
static Log* commonLog;
public:
int stripFromStackBottom;
public:
/**
@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::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.
@@ -181,7 +181,7 @@ public:
typedef Storage StorageType;
typedef Compute ComputeType;
typedef Map2D<Storage, Compute> Type;
typedef ReferenceCountedPointer<Map2D> Ref;
typedef shared_ptr<Map2D> Ref;
protected:
@@ -296,7 +296,7 @@ public:
GMutex mutex;
static Ref create(int w = 0, int h = 0, WrapMode wrap = WrapMode::ERROR) {
return new Map2D(w, h, wrap);
return Ref(new Map2D(w, h, wrap));
}
/** Resizes without clearing, leaving garbage.
@@ -372,7 +372,7 @@ public:
// (we're returning a const reference so this is ok)
return const_cast<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;
// we use this line to supress the warning.
return ZERO;
@@ -393,7 +393,7 @@ public:
inline Storage& get(int x, int y, WrapMode wrap) {
return const_cast<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;
// we use this line to supress the warning.
return ZERO;
@@ -402,7 +402,7 @@ public:
inline Storage& get(int x, int y) {
return const_cast<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;
// we use this line to supress the warning.
return ZERO;
@@ -441,6 +441,19 @@ public:
setChanged(true);
}
/** Copy values from \a src, which must have the same size */
template<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*/
void maybeFlipVertical(bool flip) {
if (flip) {
@@ -448,38 +461,38 @@ public:
}
}
virtual void flipVertical() {
int halfHeight = h/2;
Storage* d = data.getCArray();
for (int y = 0; y < halfHeight; ++y) {
int o1 = y * w;
int o2 = (h - y - 1) * w;
for (int x = 0; x < (int)w; ++x) {
int i1 = o1 + x;
int i2 = o2 + x;
Storage temp = d[i1];
d[i1] = d[i2];
d[i2] = temp;
}
}
virtual void flipVertical() {
int halfHeight = h/2;
Storage* d = data.getCArray();
for (int y = 0; y < halfHeight; ++y) {
int o1 = y * w;
int o2 = (h - y - 1) * w;
for (int x = 0; x < (int)w; ++x) {
int i1 = o1 + x;
int i2 = o2 + x;
Storage temp = d[i1];
d[i1] = d[i2];
d[i2] = temp;
}
}
setChanged(true);
}
virtual void flipHorizontal() {
int halfWidth = w / 2;
Storage* d = data.getCArray();
for (int x = 0; x < halfWidth; ++x) {
for (int y = 0; y < (int)h; ++y) {
int i1 = y * w + x;
int i2 = y * w + (w - x - 1);
Storage temp = d[i1];
d[i1] = d[i2];
d[i2] = temp;
}
}
}
virtual void flipHorizontal() {
int halfWidth = w / 2;
Storage* d = data.getCArray();
for (int x = 0; x < halfWidth; ++x) {
for (int y = 0; y < (int)h; ++y) {
int i1 = y * w + x;
int i2 = y * w + (w - x - 1);
Storage temp = d[i1];
d[i1] = d[i2];
d[i2] = temp;
}
}
setChanged(true);
}
}
/**
Crops this map so that it only contains pixels between (x, y) and (x + w - 1, y + h - 1) inclusive.
*/

View File

@@ -234,7 +234,7 @@ public:
};
private:
typedef ReferenceCountedPointer<Impl> ImplRef;
typedef shared_ptr<Impl> ImplRef;
ImplRef impl;
@@ -501,10 +501,13 @@ public:
}
/**
(A<SUP>T</SUP>A)<SUP>-1</SUP>A<SUP>T</SUP>) computed
using SVD.
\brief Computes the Moore-Penrose pseudo inverse, equivalent to
(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;
@@ -576,7 +579,7 @@ public:
/** Serializes in Matlab source format */
void serialize(TextOutput& t) const;
std::string toString(const std::string& name) const;
std::string toString(const std::string& name) const;
std::string toString() const {
static const std::string name = "";

View File

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

View File

@@ -1,14 +1,14 @@
/**
@file Matrix3.h
\file Matrix3.h
3x3 matrix class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
@cite Portions based on Dave Eberly's Magic Software Library at <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
@edited 2006-04-05
\created 2001-06-02
\edited 2011-05-05
*/
#ifndef G3D_Matrix3_h
@@ -32,11 +32,12 @@ namespace G3D {
class Any;
/**
3x3 matrix. Do not subclass.
A 3x3 matrix. Do not subclass. Data is unitializd when default constructed.
*/
class Matrix3 {
private:
// Row, column
float elt[3][3];
// Hidden operators
@@ -47,13 +48,39 @@ private:
public:
/** Must be in one of the following forms:
- Matrix3(#, #, # .... #)
- Matrix3::fromAxisAngle(#, #)
- Matrix3::diagonal(#, #, #)
- Matrix3::identity()
*/
Matrix3(const Any& any);
operator Any() const;
static Matrix3 fromColumns(const Vector3& c0, const Vector3& c1, const Vector3& c2) {
Matrix3 m;
for (int r = 0; r < 3; ++r) {
m.elt[r][0] = c0[r];
m.elt[r][1] = c1[r];
m.elt[r][2] = c2[r];
}
return m;
}
/** Initial values are undefined for performance. See also
Matrix3::zero(), Matrix3::identity(), Matrix3::fromAxisAngle, etc.*/
inline Matrix3() {}
static Matrix3 fromRows(const Vector3& r0, const Vector3& r1, const Vector3& r2) {
Matrix3 m;
for (int c = 0; c < 3; ++c) {
m.elt[0][c] = r0[c];
m.elt[1][c] = r1[c];
m.elt[2][c] = r2[c];
}
return m;
}
Any toAny() const;
/** Initial values are undefined for performance.
\sa Matrix3::zero, Matrix3::identity, Matrix3::fromAxisAngle, etc.*/
Matrix3() {}
Matrix3 (class BinaryInput& b);
Matrix3 (const float aafEntry[3][3]);
@@ -62,13 +89,19 @@ public:
float fEntry10, float fEntry11, float fEntry12,
float fEntry20, float fEntry21, float fEntry22);
bool fuzzyEq(const Matrix3& b) const;
bool fuzzyEq(const Matrix3& b) const;
/** Constructs a matrix from a quaternion.
@cite Graphics Gems II, p. 351--354
@cite Implementation from Watt and Watt, pg 362*/
@cite Implementation from Watt and Watt, pg 362*/
Matrix3(const class Quat& q);
static Matrix3 diagonal(float e00, float e11, float e22) {
return Matrix3(e00, 0, 0,
0, e11, 0,
0, 0, e22);
}
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
@@ -83,7 +116,7 @@ public:
float fEntry20, float fEntry21, float fEntry22);
/**
* member access, allows use of construct mat[r][c]
Member access, allows use of construct mat[r][c]
*/
inline float* operator[] (int iRow) {
debugAssert(iRow >= 0);
@@ -209,8 +242,8 @@ public:
bool isOrthonormal() const;
Matrix3 transpose () const;
bool inverse (Matrix3& rkInverse, float fTolerance = 1e-06) const;
Matrix3 inverse (float fTolerance = 1e-06) const;
bool inverse (Matrix3& rkInverse, float fTolerance = 1e-06f) const;
Matrix3 inverse (float fTolerance = 1e-06f) const;
float determinant () const;
/** singular value decomposition */
@@ -267,8 +300,12 @@ public:
0, 0, d.z);
}
/** \sa fromUnitAxisAngle */
static Matrix3 fromAxisAngle(const Vector3& rkAxis, float fRadians);
/** Assumes that rkAxis has unit length */
static Matrix3 fromUnitAxisAngle(const Vector3& rkAxis, float fRadians);
/**
* The matrix must be orthonormal. The decomposition is yaw*pitch*roll
* where yaw is rotation about the Up vector, pitch is rotation about the
@@ -312,7 +349,7 @@ public:
// "You might be tempted to write [...] them as inline functions
// inside their respective header files, but this is something you
// must definitely not do. An inline function can be duplicated
// in every file in which it appears <20><><EFBFBD><EFBFBD> and this duplication
// in every file in which it appears and this duplication
// includes the static object definition. Because inline functions
// automatically default to internal linkage, this would result in
// having multiple static objects across the various translation

View File

@@ -5,8 +5,8 @@
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2003-10-02
@edited 2009-10-20
\created 2003-10-02
\edited 2012-12-25
*/
#ifndef G3D_Matrix4_h
@@ -26,11 +26,12 @@
namespace G3D {
class Any;
class Matrix2;
/**
A 4x4 matrix.
A 4x4 matrix. Do not subclass. Data is initialized to 0 when default constructed.
See also G3D::CoordinateFrame, G3D::Matrix3, G3D::Quat
\sa G3D::CoordinateFrame, G3D::Matrix3, G3D::Quat
*/
class Matrix4 {
private:
@@ -50,10 +51,20 @@ private:
bool operator>=(const Matrix4&) const;
public:
/** Must be of the form: <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(
float r1c1, float r1c2, float r1c3, float r1c4,
@@ -66,17 +77,25 @@ public:
*/
Matrix4(const float* init);
/**
a is the upper left 3x3 submatrix and b is the upper right 3x1 submatrix. The last row of the created matrix is (0,0,0,1).
*/
/**
a is the upper left 3x3 submatrix and b is the upper right 3x1 submatrix. The last row of the created matrix is (0,0,0,1).
*/
Matrix4(const class Matrix3& upper3x3, const class Vector3& lastCol = Vector3::zero());
Matrix4(const class CoordinateFrame& c);
Matrix4(const double* init);
/** Matrix4::zero() */
Matrix4();
static Matrix4 diagonal(float e00, float e11, float e22, float e33) {
return Matrix4(e00, 0, 0, 0,
0, e11, 0, 0,
0, 0, e22, 0,
0, 0, 0, e33);
}
/** Produces an RT transformation that nearly matches this Matrix4.
Because a Matrix4 may not be precisely a rotation and translation,
this may introduce error. */
@@ -88,14 +107,19 @@ public:
static const Matrix4& zero();
/** If this is a perspective projection matrix created by
Matrix4::perspectiveProjection, extract its parameters. */
Matrix4::perspectiveProjection, extract its parameters.
Uses double precision because the operations involved in
projection involve divisions that can significantly impact
precision.
*/
void getPerspectiveProjectionParameters
(float& left,
float& right,
float& bottom,
float& top,
float& nearval,
float& farval,
(double& left,
double& right,
double& bottom,
double& top,
double& nearval,
double& farval,
float updirection = -1.0f) const;
inline float* operator[](int r) {
@@ -110,6 +134,7 @@ public:
return (const float*)&elt[r];
}
/** Returns a row-major pointer. */
inline operator float* () {
return (float*)&elt[0][0];
}
@@ -131,6 +156,8 @@ public:
class Matrix3 upper3x3() const;
class Matrix2 upper2x2() const;
/** Homogeneous multiplication. Let k = M * [v w]^T. result = k.xyz() / k.w */
class Vector3 homoMul(const class Vector3& v, float w) const;
@@ -151,7 +178,6 @@ public:
float farval,
float upDirection = -1.0f);
/** \param upDirection Use -1.0 for 2D Y increasing downwards (the G3D 8.x default convention),
1.0 for 2D Y increasing upwards (the G3D 7.x default and OpenGL convention)
*/
@@ -163,15 +189,18 @@ public:
/** \param upDirection Use -1.0 for 2D Y increasing downwards (the G3D 8.x default convention),
1.0 for 2D Y increasing upwards (the G3D 7.x default and OpenGL convention)
*/
Uses double precision because the operations involved in
projection involve divisions that can significantly impact
precision. */
static Matrix4 perspectiveProjection(
float left,
float right,
float bottom,
float top,
float nearval,
float farval,
float upDirection = -1.0f);
double left,
double right,
double bottom,
double top,
double nearval,
double farval,
float upDirection = -1.0f);
void setRow(int r, const class Vector4& v);
void setColumn(int c, const Vector4& v);
@@ -248,6 +277,67 @@ public:
};
/** Double-precision 4x4 matrix */
class Matrix4float64 {
private:
double elt[4][4];
public:
explicit Matrix4float64(const Matrix4& m);
/** all zeros */
Matrix4float64();
Matrix4float64(
double r1c1, double r1c2, double r1c3, double r1c4,
double r2c1, double r2c2, double r2c3, double r2c4,
double r3c1, double r3c2, double r3c3, double r3c4,
double r4c1, double r4c2, double r4c3, double r4c4);
// Special values.
// Intentionally not inlined: see Matrix3::identity() for details.
static const Matrix4float64& identity();
static const Matrix4float64& zero();
bool operator!=(const Matrix4float64& other) const;
bool operator==(const Matrix4float64& other) const;
Vector4 operator*(const Vector4& vector) const;
static Matrix4float64 perspectiveProjection(
double left,
double right,
double bottom,
double top,
double nearval,
double farval,
float upDirection = -1.0f);
inline double* operator[](int r) {
debugAssert(r >= 0);
debugAssert(r < 4);
return (double*)&elt[r];
}
inline const double* operator[](int r) const {
debugAssert(r >= 0);
debugAssert(r < 4);
return (const double*)&elt[r];
}
inline operator double* () {
return (double*)&elt[0][0];
}
inline operator const double* () const {
return (const double*)&elt[0][0];
}
};
} // namespace

View File

@@ -20,7 +20,7 @@ namespace G3D {
Abstraction of memory management.
Default implementation uses G3D::System::malloc and is threadsafe.
\sa CRTMemoryManager, AlignedMemoryManager, AreaMemoryManager */
\sa LargePoolMemoryManager, CRTMemoryManager, AlignedMemoryManager, AreaMemoryManager */
class MemoryManager : public ReferenceCountedObject {
protected:
@@ -28,7 +28,7 @@ protected:
public:
typedef ReferenceCountedPointer<class MemoryManager> Ref;
typedef shared_ptr<class MemoryManager> Ref;
/** Return a pointer to \a s bytes of memory that are unused by
the rest of the program. The contents of the memory are
@@ -59,7 +59,7 @@ protected:
public:
typedef ReferenceCountedPointer<class AlignedMemoryManager> Ref;
typedef shared_ptr<class AlignedMemoryManager> Ref;
virtual void* alloc(size_t s);
@@ -72,13 +72,14 @@ public:
};
/** MemoryManager implemented using the C runtime. */
/** A MemoryManager implemented using the C runtime. Not recommended
for general use; this is largely for debugging. */
class CRTMemoryManager : public MemoryManager {
protected:
CRTMemoryManager();
public:
typedef ReferenceCountedPointer<class MemoryManager> Ref;
typedef shared_ptr<class MemoryManager> Ref;
virtual void* alloc(size_t s);
virtual void free(void* ptr);
virtual bool isThreadsafe() const;

View File

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

View File

@@ -34,6 +34,8 @@ private:
typedef Array<int> List;
std::string name;
bool scaleAndCenter;
/**
All of the triangles, as a long triangle list.
@@ -43,14 +45,14 @@ private:
void centerTriList();
void computeBounds(Vector3& min, Vector3& max);
bool _twoSided;
bool _twoSided;
/** Collapse radius */
double close;
public:
inline MeshBuilder(bool twoSided = false) : _twoSided(twoSided), close(AUTO_WELD) {}
inline MeshBuilder(bool twoSided = false, bool scaleAndCenter = true) : scaleAndCenter(scaleAndCenter), _twoSided(twoSided), close(AUTO_WELD) {}
/** Writes the model to the arrays, which can then be used with
G3D::IFSModel::save and G3D::MeshAlg */

View File

@@ -1,3 +1,9 @@
/**
\file G3D/NetAddress.h
\created 2010-01-03
\edited 2013-03-17
*/
#ifndef G3D_NetAddress_h
#define G3D_NetAddress_h
@@ -24,20 +30,31 @@ private:
SOCKADDR_IN addr;
public:
enum {
/**
Use the host portion of the IP address of the default adapter on this machine.
*/
// Must match ENET_HOST_ANY
DEFAULT_ADAPTER_HOST = 0
};
/**
In host byte order
In host byte order.
\sa DEFAULT_ADAPTER_HOST
*/
NetAddress(uint32 host, uint16 port = 0);
explicit NetAddress(uint32 host, uint16 port = 0);
/**
@param port Specified in host byte order (i.e., don't worry about endian issues)
*/
*/
NetAddress(const std::string& hostname, uint16 port);
/**
@param hostnameAndPort in the form "hostname:port" or "ip:port"
*/
NetAddress(const std::string& hostnameAndPort);
explicit NetAddress(const std::string& hostnameAndPort);
/**
@deprecated Use G3D::NetworkDevice::broadcastAddressArray()
@@ -56,6 +73,8 @@ public:
NetAddress();
static void localHostAddresses(Array<NetAddress>& array);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
@@ -76,6 +95,13 @@ public:
std::string ipString() const;
std::string toString() const;
/** Name of this address, without the domain. Performs reverse DNS lookup on this address. This may make a network
connection to a DNS server and block until that communication completes
if the address is one that has not been recently checked.*/
std::string hostname() const;
/** Name of the local machine machine, without the domain. The value is cached after the first call.*/
static std::string localHostname();
};
std::ostream& operator<<(std::ostream& os, const NetAddress&);
@@ -95,7 +121,7 @@ namespace G3D {
they have different IP's.
*/
inline bool operator==(const NetAddress& a, const NetAddress& b) {
return (a.ip() == b.ip()) && (a.port() == b.port());
return (a.ip() == b.ip()) && (a.port() == b.port());
}

View File

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

View File

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

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

View File

@@ -20,16 +20,31 @@ namespace G3D {
*/
class PhysicsFrameSpline : public Spline<PhysicsFrame> {
public:
PhysicsFrameSpline();
/** Accepts a table of properties, or any valid PhysicsFrame specification for a single control*/
PhysicsFrameSpline(const Any& any);
/** Clear and then reset all values from the any */
PhysicsFrameSpline& operator=(const Any& any);
bool operator==(const PhysicsFrameSpline& a) const;
bool operator!=(const PhysicsFrameSpline& a) const {
return ! ((*this) == a);
}
/** Mutates all underlying PhysicsFrames by scaling their translation by \param scaleFactor */
void scaleControlPoints(float scaleFactor);
virtual void correct(PhysicsFrame& frame) const;
virtual void ensureShortestPath(PhysicsFrame* A, int N) const;
virtual Any toAny(const std::string& myName) const override {
return Spline<PhysicsFrame>::toAny(myName);
}
Any toAny() const {
return toAny("PFrameSpline");
}
};
}

View File

@@ -1,16 +1,16 @@
/**
@file Plane.h
\file Plane.h
Plane class
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-06-02
@edited 2004-07-18
\created 2001-06-02
\edited 2010-12-04
*/
#ifndef G3D_PLANE_H
#define G3D_PLANE_H
#ifndef G3D_Plane_h
#define G3D_Plane_h
#include "G3D/platform.h"
#include "G3D/Vector3.h"
@@ -26,8 +26,8 @@ class Plane {
private:
/** normal.Dot(x,y,z) = distance */
Vector3 _normal;
float _distance;
Vector3 _normal;
float _distance;
/**
Assumes the normal has unit length.
@@ -40,43 +40,51 @@ public:
Plane() : _normal(Vector3::unitY()), _distance(0) {
}
/** Format is:
- Plane(normal, point)
*/
explicit Plane(const class Any& a);
Any toAny() const;
/**
Constructs a plane from three points.
*/
Plane(
const Vector3& point0,
const Vector3& point1,
const Vector3& point2);
Plane
(const Point3& point0,
const Point3& point1,
const Point3& point2);
/**
Constructs a plane from three points, where at most two are
at infinity (w = 0, not xyz = inf).
*/
Plane(
Vector4 point0,
Vector4 point1,
Vector4 point2);
Vector4 point0,
Vector4 point1,
Vector4 point2);
/**
The normal will be unitized.
*/
Plane(
const Vector3& __normal,
const Vector3& point);
Plane
(const Vector3& normal,
const Point3& point);
static Plane fromEquation(float a, float b, float c, float d);
Plane(class BinaryInput& b);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
Plane(class BinaryInput& b);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
virtual ~Plane() {}
/**
Returns true if point is on the side the normal points to or
is in the plane.
*/
inline bool halfSpaceContains(Vector3 point) const {
inline bool halfSpaceContains(Point3 point) const {
// Clamp to a finite range for testing
point = point.clamp(Vector3::minFinite(), Vector3::maxFinite());
@@ -101,7 +109,7 @@ public:
Returns true if point is on the side the normal points to or
is in the plane. Only call on finite points. Faster than halfSpaceContains.
*/
inline bool halfSpaceContainsFinite(const Vector3& point) const {
inline bool halfSpaceContainsFinite(const Point3& point) const {
debugAssert(point.isFinite());
return _normal.dot(point) >= _distance;
}
@@ -109,13 +117,13 @@ public:
/**
Returns true if the point is nearly in the plane.
*/
inline bool fuzzyContains(const Vector3 &point) const {
inline bool fuzzyContains(const Point3& point) const {
return fuzzyEq(point.dot(_normal), _distance);
}
inline const Vector3& normal() const {
return _normal;
}
inline const Vector3& normal() const {
return _normal;
}
/**
Returns distance from point to plane. Distance is negative if point is behind (not in plane in direction opposite normal) the plane.
@@ -124,7 +132,7 @@ public:
return (_normal.dot(x) - _distance);
}
inline Vector3 closestPoint(const Vector3& x) const {
inline Point3 closestPoint(const Point3& x) const {
return x + (_normal * (-distance(x)));
}
@@ -144,8 +152,8 @@ public:
<CODE>normal.Dot(Vector3(<I>x</I>, <I>y</I>, <I>z</I>)) + d = 0</CODE>
*/
void getEquation(Vector3 &normal, double& d) const;
void getEquation(Vector3 &normal, float& d) const;
void getEquation(Vector3& normal, double& d) const;
void getEquation(Vector3& normal, float& d) const;
/**
ax + by + cz + d = 0

View File

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

View File

@@ -4,15 +4,15 @@
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2004-01-11
@edited 2008-11-02
@edited 2012-07-30
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
#ifndef X_PointKDTree_H
#define X_PointKDTree_H
#ifndef G3D_PointKDTree_h
#define G3D_PointKDTree_h
#include "G3D/platform.h"
#include "G3D/Array.h"
@@ -26,7 +26,7 @@
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/CollisionDetection.h"
#include "G3D/GCamera.h"
#include "G3D/Frustum.h"
#include "G3D/PositionTrait.h"
#include <algorithm>
@@ -234,36 +234,38 @@ protected:
}
void verifyNode(const Vector3& lo, const Vector3& hi) {
// debugPrintf("Verifying: split %d @ %f [%f, %f, %f], [%f, %f, %f]\n",
// splitAxis, splitLocation, lo.x, lo.y, lo.z, hi.x, hi.y, hi.z);
void verifyNode(const Vector3& lo, const Vector3& hi) {
// debugPrintf("Verifying: split %d @ %f [%f, %f, %f], [%f, %f, %f]\n",
// splitAxis, splitLocation, lo.x, lo.y, lo.z, hi.x, hi.y, hi.z);
debugAssert(lo == splitBounds.low());
debugAssert(hi == splitBounds.high());
for (int i = 0; i < valueArray.length(); ++i) {
const Vector3& b = valueArray[i].position();
# ifdef G3D_DEBUG
for (int i = 0; i < valueArray.length(); ++i) {
const Vector3& b = valueArray[i].position();
debugAssert(splitBounds.contains(b));
}
}
# endif
if (child[0] || child[1]) {
debugAssert(lo[splitAxis] < splitLocation);
debugAssert(hi[splitAxis] > splitLocation);
}
if (child[0] || child[1]) {
debugAssert(lo[splitAxis] < splitLocation);
debugAssert(hi[splitAxis] > splitLocation);
}
Vector3 newLo = lo;
newLo[splitAxis] = splitLocation;
Vector3 newHi = hi;
newHi[splitAxis] = splitLocation;
Vector3 newLo = lo;
newLo[splitAxis] = splitLocation;
Vector3 newHi = hi;
newHi[splitAxis] = splitLocation;
if (child[0] != NULL) {
child[0]->verifyNode(lo, newHi);
}
if (child[0] != NULL) {
child[0]->verifyNode(lo, newHi);
}
if (child[1] != NULL) {
child[1]->verifyNode(newLo, hi);
}
}
if (child[1] != NULL) {
child[1]->verifyNode(newLo, hi);
}
}
/**
@@ -297,6 +299,7 @@ protected:
for (int c = 0; c < 2; ++c) {
n->child[c] = deserializeStructure(bi);
}
return n;
}
}
@@ -484,7 +487,7 @@ protected:
// Compute the mean along the axis
splitLocation = (bounds.high()[splitAxis] +
bounds.low()[splitAxis]) / 2.0;
bounds.low()[splitAxis]) / 2.0f;
Handle splitHandle;
Vector3 v;
@@ -525,10 +528,10 @@ protected:
for(int i = 0; i < node->valueArray.size(); ++i) {
memberTable.set(node->valueArray[i].value, node);
}
}
return node;
}
return node;
}
/**
@@ -611,7 +614,7 @@ public:
}
int size() const {
size_t size() const {
return memberTable.size();
}
@@ -809,7 +812,7 @@ private:
// Test values at this node against remaining planes
for (int p = 0; p < plane.size(); ++p) {
if ((parentMask >> p) & 1 != 0) {
if (((parentMask >> p) & 1) != 0) {
// Test against this plane
const Plane& curPlane = plane[p];
for (int v = node->valueArray.size() - 1; v >= 0; --v) {
@@ -851,7 +854,7 @@ public:
/**
Typically used to find all visible
objects inside the view frustum (see also GCamera::getClipPlanes)... i.e. all objects
objects inside the view frustum (see also Camera::getClipPlanes)... i.e. all objects
<B>not</B> culled by frustum.
Example:
@@ -862,7 +865,7 @@ public:
</PRE>
@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;
for (int i = 0; i < frustum.faceArray.size(); ++i) {
@@ -960,51 +963,51 @@ public:
BoxIntersectionIterator& operator++() {
++nextValueArrayIndex;
bool foundIntersection = false;
bool foundIntersection = false;
while (! isEnd && ! foundIntersection) {
// Search for the next node if we've exhausted this one
// Search for the next node if we've exhausted this one
while ((! isEnd) && (nextValueArrayIndex >= node->valueArray.length())) {
// If we entered this loop, then the iterator has exhausted the elements at
// node (possibly because it just switched to a child node with no members).
// This loop continues until it finds a node with members or reaches
// the end of the whole intersection search.
// If we entered this loop, then the iterator has exhausted the elements at
// node (possibly because it just switched to a child node with no members).
// This loop continues until it finds a node with members or reaches
// the end of the whole intersection search.
// If the right child overlaps the box, push it onto the stack for
// processing.
if ((node->child[1] != NULL) &&
(box.high()[node->splitAxis] > node->splitLocation)) {
stack.push(node->child[1]);
}
// If the right child overlaps the box, push it onto the stack for
// processing.
if ((node->child[1] != NULL) &&
(box.high()[node->splitAxis] > node->splitLocation)) {
stack.push(node->child[1]);
}
// If the left child overlaps the box, push it onto the stack for
// processing.
if ((node->child[0] != NULL) &&
(box.low()[node->splitAxis] < node->splitLocation)) {
stack.push(node->child[0]);
}
// If the left child overlaps the box, push it onto the stack for
// processing.
if ((node->child[0] != NULL) &&
(box.low()[node->splitAxis] < node->splitLocation)) {
stack.push(node->child[0]);
}
if (stack.length() > 0) {
// Go on to the next node (which may be either one of the ones we
// just pushed, or one from farther back the tree).
node = stack.pop();
nextValueArrayIndex = 0;
} else {
// That was the last node; we're done iterating
isEnd = true;
}
}
if (stack.length() > 0) {
// Go on to the next node (which may be either one of the ones we
// just pushed, or one from farther back the tree).
node = stack.pop();
nextValueArrayIndex = 0;
} else {
// That was the last node; we're done iterating
isEnd = true;
}
}
// Search for the next intersection at this node until we run out of children
while (! isEnd && ! foundIntersection && (nextValueArrayIndex < node->valueArray.length())) {
if (box.intersects(node->valueArray[nextValueArrayIndex].bounds)) {
foundIntersection = true;
} else {
++nextValueArrayIndex;
// If we exhaust this node, we'll loop around the master loop
// to find a new node.
}
}
// Search for the next intersection at this node until we run out of children
while (! isEnd && ! foundIntersection && (nextValueArrayIndex < node->valueArray.length())) {
if (box.intersects(node->valueArray[nextValueArrayIndex].bounds)) {
foundIntersection = true;
} else {
++nextValueArrayIndex;
// If we exhaust this node, we'll loop around the master loop
// to find a new node.
}
}
}
return *this;

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
@edited 2009-03-26
\created 2007-05-16
\edited 2012-10-06
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_Pointer_h
@@ -27,7 +27,7 @@ namespace G3D {
Because the accessors require values to be passed by value (instead of by reference)
this is primarily useful for objects whose memory size is small.
<pre>
\code
class Foo {
public:
void setEnabled(bool b);
@@ -51,14 +51,15 @@ namespace G3D {
p2.setValue(p1.getValue());
p2 = p1;
</pre>
\endcode
<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
<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 {
private:
@@ -78,9 +79,7 @@ private:
public:
Memory(ValueType* value) : value(value) {
//debugAssert(value != NULL);
}
Memory(ValueType* value) : value(value) {}
virtual void set(ValueType v) {
*value = v;
@@ -99,6 +98,35 @@ private:
}
};
template<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>
class Accessor : public Interface {
private:
@@ -116,7 +144,9 @@ private:
}
virtual void set(ValueType v) {
(object->*setMethod)(v);
if (setMethod) {
(object->*setMethod)(v);
}
}
virtual ValueType get() const {
@@ -134,17 +164,17 @@ private:
template<class T, typename GetMethod, typename SetMethod>
class RefAccessor : public Interface {
class SharedAccessor : public Interface {
private:
ReferenceCountedPointer<T> object;
GetMethod getMethod;
SetMethod setMethod;
shared_ptr<T> object;
GetMethod getMethod;
SetMethod setMethod;
public:
RefAccessor(
const ReferenceCountedPointer<T>& object,
SharedAccessor
(const shared_ptr<T>& object,
GetMethod getMethod,
SetMethod setMethod) : object(object), getMethod(getMethod), setMethod(setMethod) {
@@ -152,23 +182,24 @@ private:
}
virtual void set(ValueType v) {
(object.pointer()->*setMethod)(v);
if (setMethod) {
(object.get()->*setMethod)(v);
}
}
virtual ValueType get() const {
return (object.pointer()->*getMethod)();
return (object.get()->*getMethod)();
}
virtual Interface* clone() const {
return new RefAccessor(object, getMethod, setMethod);
return new SharedAccessor(object, getMethod, setMethod);
}
virtual bool isNull() const {
return object.isNull();
return (bool)object;
}
};
Interface* m_interface;
public:
@@ -197,48 +228,69 @@ public:
this[0] = p;
}
/** \param setMethod May be NULL */
template<class Class>
Pointer(const ReferenceCountedPointer<Class>& object,
Pointer(const shared_ptr<Class>& object,
ValueType (Class::*getMethod)() const,
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>
Pointer(const ReferenceCountedPointer<Class>& object,
Pointer(const shared_ptr<Class>& object,
const ValueType& (Class::*getMethod)() const,
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>
Pointer(const ReferenceCountedPointer<Class>& object,
Pointer(const shared_ptr<Class>& object,
ValueType (Class::*getMethod)() const,
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>
Pointer(const ReferenceCountedPointer<Class>& object,
Pointer(const shared_ptr<Class>& object,
const ValueType& (Class::*getMethod)() const,
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>
Pointer(Class* object,
const ValueType& (Class::*getMethod)() const,
void (Class::*setMethod)(const ValueType&)) :
m_interface(new Accessor<Class, const ValueType& (Class::*)() const, void (Class::*)(const ValueType&)>(object, getMethod, setMethod)) {}
/** \param setMethod May be NULL */
template<class Class>
Pointer(Class* object,
ValueType (Class::*getMethod)() const,
void (Class::*setMethod)(const ValueType&)) :
m_interface(new Accessor<Class, ValueType (Class::*)() const, void (Class::*)(const ValueType&)>(object, getMethod, setMethod)) {}
/** \param setMethod May be NULL */
template<class Class>
Pointer(Class* object,
const ValueType& (Class::*getMethod)() const,
void (Class::*setMethod)(ValueType)) :
m_interface(new Accessor<Class, const ValueType& (Class::*)() const, void (Class::*)(ValueType)>(object, getMethod, setMethod)) {}
/** \param setMethod May be NULL */
template<class Class>
Pointer(Class* object,
ValueType (Class::*getMethod)() const,
@@ -254,6 +306,8 @@ public:
return m_interface->get();
}
/** \brief Assign a value to the referenced element.
If this Pointer was initialized with a NULL setMethod, the call is ignored */
inline void setValue(const ValueType& v) {
debugAssert(m_interface != NULL);
m_interface->set(v);
@@ -287,6 +341,16 @@ public:
}
};
template<class T>
bool isNull(const Pointer<T>& p) {
return p.isNull();
}
template<class T>
bool notNull(const Pointer<T>& p) {
return ! p.isNull();
}
}
#endif

View File

@@ -1,12 +1,12 @@
/**
@file Quat.h
\file G3D/Quat.h
Quaternion
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2002-01-23
@edited 2009-05-10
\created 2002-01-23
\edited 2011-05-10
*/
#ifndef G3D_Quat_h
@@ -21,9 +21,9 @@
namespace G3D {
/**
Arbitrary quaternion (not necessarily unit)
Arbitrary quaternion (not necessarily unit).
Unit quaternions are used in computer graphics to represent
Unit quaternions (aka versors) are used in computer graphics to represent
rotation about an axis. Any 3x3 rotation matrix can
be stored as a quaternion.
@@ -72,6 +72,8 @@ public:
/** Expects "Quat(x,y,z,w)" or a Matrix3 constructor. */
Quat(const class Any& a);
Any toAny() const;
Quat(const Matrix3& rot);
Quat(float _x, float _y, float _z, float _w) :
@@ -81,6 +83,12 @@ public:
Quat(const Vector3& v, float _w = 0) : x(v.x), y(v.y), z(v.z), w(_w) {
}
/** True if the components are exactly equal. Note that two quaternations may
be unequal but map to the same rotation. */
bool operator==(const Quat& q) const {
return x == q.x && y == q.y && z == q.z && w == q.w;
}
/**
The real part of the quaternion.
*/
@@ -92,9 +100,9 @@ public:
return w;
}
Quat operator-() const {
return Quat(-x, -y, -z, -w);
}
Quat operator-() const {
return Quat(-x, -y, -z, -w);
}
Quat operator-(const Quat& other) const {
return Quat(x - other.x, y - other.y, z - other.z, w - other.w);
@@ -148,7 +156,7 @@ public:
}
/** @cite Based on Watt & Watt, page 360 */
/** @cite Based on Watt & Watt, page 360 */
friend Quat operator* (float s, const Quat& q);
inline Quat operator/(float s) const {
@@ -196,36 +204,69 @@ public:
void toAxisAngleRotation(
Vector3& axis,
float& angle) const {
double d;
toAxisAngleRotation(axis, d);
angle = (float)d;
}
double d;
toAxisAngleRotation(axis, d);
angle = (float)d;
}
Matrix3 toRotationMatrix() const;
void toRotationMatrix(
Matrix3& rot) const;
private:
/** \param maxAngle Maximum angle of rotation allowed. If a larger rotation is required, the angle of rotation applied is clamped to maxAngle */
Quat slerp
(const Quat& other,
float alpha,
float threshold,
float maxAngle) const;
public:
/**
Spherical linear interpolation: linear interpolation along the
shortest (3D) great-circle route between two quaternions.
Assumes that both arguments are unit quaternions.
Note: Correct rotations are expected between 0 and PI in the right order.
@cite Based on Game Physics -- David Eberly pg 538-540
@param threshold Critical angle between between rotations at which
the algorithm switches to normalized lerp, which is more
numerically stable in those situations. 0.0 will always slerp.
\cite Based on Game Physics -- David Eberly pg 538-540
\param threshold Critical angle between between rotations (in radians) at which
the algorithm switches to normalized lerp, which is more
numerically stable in those situations. 0.0 will always slerp.
*/
Quat slerp(
const Quat& other,
Quat slerp
(const Quat& other,
float alpha,
float threshold = 0.05f) const;
float threshold = 0.05f) const {
return slerp(other, alpha, threshold, finf());
}
/** Normalized linear interpolation of quaternion components. */
Quat nlerp(const Quat& other, float alpha) const;
/** Rotates towards \a other by at most \a maxAngle. */
Quat movedTowards
(const Quat& other,
float maxAngle) const {
return slerp(other, 1.0f, 0.05f, maxAngle);
}
/** Rotates towards \a other by at most \a maxAngle. */
void moveTowards
(const Quat& other,
float maxAngle) {
*this = movedTowards(other, maxAngle);
}
/** Returns the angle in radians between this and other, assuming both are unit quaternions.
\returns On the range [0, pif()]*/
float angleBetween(const Quat& other) const;
/** Normalized linear interpolation of quaternion components. */
Quat nlerp(const Quat& other, float alpha) const;
/** Note that q<SUP>-1</SUP> = q.conj() for a unit quaternion.
@cite Dam99 page 13 */
@@ -274,22 +315,6 @@ public:
return Quat(t * x, t * y, t * z, ::logf(len));
}
}
/** log q = [Av, 0] where q = [sin(A) * v, cos(A)].
Only for unit quaternions
debugAssertM(isUnit(), "Log only defined for unit quaternions");
// Solve for A in q = [sin(A)*v, cos(A)]
Vector3 u(x, y, z);
double len = u.magnitude();
if (len == 0.0) {
return
}
double A = atan2((double)w, len);
Vector3 v = u / len;
return Quat(v * A, 0);
}
*/
/** exp q = [sin(A) * v, cos(A)] where q = [Av, 0].
Only defined for pure-vector quaternions */
@@ -310,8 +335,8 @@ public:
Note that q.pow(a).pow(b) == q.pow(a + b)
@cite Dam98 pg 21
*/
inline Quat pow(float x) const {
return (log() * x).exp();
inline Quat pow(float r) const {
return (log() * r).exp();
}
/** Make unit length in place */
@@ -324,9 +349,9 @@ public:
the magnitude.
*/
Quat toUnit() const {
Quat x = *this;
x.unitize();
return x;
Quat copyOfThis = *this;
copyOfThis.unitize();
return copyOfThis;
}
/**
@@ -348,7 +373,7 @@ public:
float& operator[] (int i);
/** Generate uniform random unit quaternion (i.e. random "direction")
@cite From "Uniform Random Rotations", Ken Shoemake, Graphics Gems III.
@cite From "Uniform Random Rotations", Ken Shoemake, Graphics Gems III.
*/
static Quat unitRandom();

View File

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

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
@edited 2009-03-20
\created 2009-01-02
\edited 2012-07-20
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_Random_h
@@ -33,6 +33,8 @@ namespace G3D {
On OS X, Random is about 10x faster than drand48() (which is
threadsafe) and 4x faster than rand() (which is not threadsafe).
\sa Noise
*/
class Random {
protected:
@@ -71,6 +73,23 @@ protected:
public constructor.*/
Random(void*);
private:
Random& operator=(const Random&) {
alwaysAssertM(false,
"There is no copy constructor or assignment operator for Random because you "
"probably didn't actually want to copy the state--it would "
"be slow and duplicate the state of a pseudo-random sequence. Maybe you could "
"provide arguments to a member variable in the constructor, "
"or pass the Random by reference?");
return *this;
}
Random(const Random& r) {
*this = r;
}
public:
/** \param threadsafe Set to false if you know that this random
@@ -81,6 +100,8 @@ public:
virtual ~Random();
virtual void reset(uint32 seed = 0xF018A4D2, bool threadsafe = true);
/** Each bit is random. Subclasses can choose to override just
this method and the other methods will all work automatically. */
virtual uint32 bits();
@@ -109,9 +130,13 @@ public:
virtual float gaussian(float mean, float stdev);
/** Returns 3D unit vectors distributed according to
a cosine distribution about the z-axis. */
a cosine distribution about the positive z-axis. */
virtual void cosHemi(float& x, float& y, float& z);
/** Returns 3D unit vectors distributed according to
a cosine distribution about the z-axis. */
virtual void cosSphere(float& x, float& y, float& z);
/** Returns 3D unit vectors distributed according to a cosine
power distribution (\f$ \cos^k \theta \f$) about
the z-axis. */

View File

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

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

View File

@@ -1,14 +1,12 @@
/**
@file ReferenceCount.h
\file G3D/ReferenceCount.h
Reference Counting Garbage Collector for C++
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@cite Adapted and extended from Justin Miller's "RGC" class that appeared in BYTE magazine.
@cite See also http://www.jelovic.com/articles/cpp_without_memory_errors_slides.htm
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-10-23
@edited 2009-04-25
\created 2001-10-23
\edited 2013-01-05
*/
#ifndef G3D_ReferenceCount_h
#define G3D_ReferenceCount_h
@@ -17,552 +15,40 @@
#include "G3D/debug.h"
#include "G3D/AtomicInt32.h"
#define USE_SHARED_PTR
#define ReferenceCountedPointer shared_ptr
#define WeakReferenceCountedPointer weak_ptr
namespace G3D {
#ifdef _MSC_VER
// Turn off "conditional expression is constant" warning; MSVC generates this
// for debug assertions in inlined methods.
# pragma warning (disable : 4127)
#endif
/** Base class for WeakReferenceCountedPointer */
class _WeakPtr {
class ReferenceCountedObject : public enable_shared_from_this<ReferenceCountedObject> {
public:
inline virtual ~_WeakPtr() {}
protected:
friend class ReferenceCountedObject;
/** Called by ReferenceCountedObject to tell a weak pointer that its underlying object was collected. */
virtual void objectCollected() = 0;
virtual ~ReferenceCountedObject() {};
};
/** Used internally by ReferenceCountedObject */
class _WeakPtrLinkedList {
public:
_WeakPtr* weakPtr;
_WeakPtrLinkedList* next;
} // namespace
inline _WeakPtrLinkedList() : weakPtr(NULL), next(NULL) {}
namespace G3D {
/** Inserts this node into the head of the list that previously had n as its head. */
inline _WeakPtrLinkedList(_WeakPtr* p, _WeakPtrLinkedList* n) : weakPtr(p), next(n) {}
};
/**
Objects that are reference counted inherit from this. Subclasses
<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;
template<class T>
bool isNull(const ReferenceCountedPointer<T>& ptr) {
return ! ptr;
}
</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;
template<class T>
bool notNull(const ReferenceCountedPointer<T>& ptr) {
return (bool)ptr;
}
protected:
template<class T>
bool isNull(const T* ptr) {
return ptr == NULL;
}
ReferenceCountedObject();
public:
/** Automatically called immediately before the object is deleted.
This is not called from the destructor because it needs to be invoked
before the subclass destructor.
*/
void ReferenceCountedObject_zeroWeakPointers();
virtual ~ReferenceCountedObject();
/**
Note: copies will initially start out with 0
references and 0 weak references like any other object.
*/
ReferenceCountedObject(const ReferenceCountedObject& notUsed);
ReferenceCountedObject& operator=(const ReferenceCountedObject& other);
};
/**
Use ReferenceCountedPointer<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>
class ReferenceCountedPointer {
private:
T* m_pointer;
public:
typedef T element_type;
inline T* pointer() const {
return m_pointer;
}
private:
/** Nulls out the pointer and drops a reference. If the reference
count hits zero. */
void zeroPointer() {
if (m_pointer != NULL) {
ReferenceCountedObject* pointer = ((ReferenceCountedObject*)m_pointer);
debugAssert(G3D::isValidHeapPointer(m_pointer));
debugAssertM(pointer->ReferenceCountedObject_refCount.value() > 0,
"Dangling reference detected.");
// Only delete if this instance caused the count to hit
// exactly zero. If there is a race condition, the value
// may be zero after decrement returns, but only one of
// the instances will get a zero return value.
if (pointer->ReferenceCountedObject_refCount.decrement() == 0) {
// We held the last reference, so delete the object.
// This test is threadsafe because there is no way for
// the reference count to increase after the last
// reference was dropped (assuming the application does
// not voilate the class abstraction).
//debugPrintf(" delete 0x%x\n", m_pointer);
// We must zero the weak pointers *before* deletion in case there
// are cycles of weak references.
// Note that since there are no strong references at this point,
// it is perfectly fair to zero the weak pointers anyway.
pointer->ReferenceCountedObject_zeroWeakPointers();
delete pointer;
}
m_pointer = NULL;
}
}
/** Non-atomic (except for the referencec increment). Can only be
called in contexts like the copy constructor or initial
constructor where it is known that the reference count will
not hit zero on some other thread. */
void setPointer(T* x) {
if (x != m_pointer) {
zeroPointer();
if (x != NULL) {
debugAssert(G3D::isValidHeapPointer(x));
m_pointer = x;
// Note that the ref count can be zero if this is the
// first pointer to it
ReferenceCountedObject* pointer = (ReferenceCountedObject*)m_pointer;
debugAssertM(pointer->ReferenceCountedObject_refCount.value() >= 0,
"Negative reference count detected.");
pointer->ReferenceCountedObject_refCount.increment();
}
}
}
public:
inline ReferenceCountedPointer() : m_pointer(NULL) {}
/**
Allow silent cast <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>
class WeakReferenceCountedPointer : public _WeakPtr {
private:
/** NULL if the object has been collected. */
T* pointer;
public:
/**
Creates a strong pointer, which prevents the object from being
garbage collected. The strong pointer may be NULL, which means
that the underlying.
*/
// There is intentionally no way to check if the
// WeakReferenceCountedPointer has a null reference without
// creating a strong pointer since there is no safe way to use
// that information-- the pointer could be collected by a
// subsequent statement.
ReferenceCountedPointer<T> createStrongPtr() const {
// TODO: What if the object's destructor is called while we
// are in this method?
return ReferenceCountedPointer<T>(pointer);
}
private:
/** Thread issues: safe because this is only called when another
object is guaranteed to keep p alive for the duration of this
call. */
void setPointer(T* p) {
// TODO: must prevent the object from being collected while in
// this method
zeroPointer();
pointer = p;
if (pointer != NULL) {
// TODO: threadsafe: must update the list atomically
// Add myself to the head of my target's list of weak pointers
_WeakPtrLinkedList* head =
new _WeakPtrLinkedList
(this,
pointer->ReferenceCountedObject_weakPointer);
pointer->ReferenceCountedObject_weakPointer = head;
} else {
}
}
/**
Removes this from its target's list of weak pointers. Called
when the weak pointer goes out of scope.
Thread issues: depends on the thread safety of createStrongPtr.
*/
void zeroPointer() {
// Grab a strong reference to prevent the object from being collected while we
// are traversing its list.
ReferenceCountedPointer<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;
}
};
template<class T>
bool notNull(const T* ptr) {
return ptr != NULL;
}
} // namespace

View File

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

View File

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

View File

@@ -1,10 +1,10 @@
/**
@file SmallArray.h
\file G3D/SmallArray.h
@created 2009-04-26
@edited 2010-02-26
\created 2009-04-26
\edited 2012-07-23
Copyright 2000-2010, Morgan McGuire, http://graphics.cs.williams.edu
Copyright 2000-2012, Morgan McGuire, http://graphics.cs.williams.edu
All rights reserved.
*/
#ifndef G3D_SmallArray_h
@@ -83,6 +83,35 @@ public:
push(v);
}
inline void append(const T& v, const T& v2) {
push(v);
push(v2);
}
inline void append(const T& v, const T& v2, const T& v3) {
push(v);
push(v2);
push(v3);
}
inline void append(const T& v, const T& v2, const T& v3, const T& v4) {
push(v);
push(v2);
push(v3);
push(v4);
}
/** Find the index of \a v or -1 if not found */
int findIndex(const T& v) {
for (int i = 0; i < N; ++i) {
if (m_embedded[i] == v) {
return i;
}
}
return m_rest.findIndex(v) + N;
}
void fastRemove(int i, bool shrinkIfNecessary = false) {
debugAssert(i < m_size && i >= 0);
if (i < N) {
@@ -139,8 +168,8 @@ public:
return m_rest.contains(value);
}
template<int MIN_ELEMENTS, int MIN_BYTES>
SmallArray<T, N>& operator=(const Array<T, MIN_ELEMENTS, MIN_BYTES>& src) {
template<int MIN_ELEMENTS>
SmallArray<T, N>& operator=(const Array<T, MIN_ELEMENTS>& src) {
resize(src.size());
for (int i = 0; i < src.size(); ++i) {
(*this)[i] = src[i];
@@ -148,13 +177,13 @@ public:
return *this;
}
inline const T& last() const {
return (*this)[size() - 1];
}
inline const T& last() const {
return (*this)[size() - 1];
}
inline T& last() {
return (*this)[size() - 1];
}
inline T& last() {
return (*this)[size() - 1];
}
};
}

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
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-06-02
@edited 2008-10-07
\created 2001-06-02
\edited 2011-02-07
*/
#ifndef G3D_SPHERE_H
#define G3D_SPHERE_H
#ifndef G3D_Sphere_h
#define G3D_Sphere_h
#include "G3D/platform.h"
#include "G3D/Vector3.h"
@@ -27,28 +27,36 @@ private:
static int32 dummy;
public:
Vector3 center;
Point3 center;
float radius;
Sphere() {
center = Vector3::zero();
radius = 0;
Sphere() : center(Point3::zero()), radius(0) {
}
explicit Sphere(float radius) : radius(radius) {}
Sphere(class BinaryInput& b);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
Sphere(
const Vector3& center,
float radius) {
/** Format is one of:
- Sphere(point, radius)
- Sphere(radius)
*/
explicit Sphere(const class Any& a);
this->center = center;
this->radius = radius;
Any toAny() const;
Sphere
(const Point3& center,
float radius) : center(center), radius(radius) {
}
virtual ~Sphere() {}
/** Returns the infinite sphere. */
static const Sphere& inf();
bool operator==(const Sphere& other) const {
return (center == other.center) && (radius == other.radius);
}
@@ -61,7 +69,7 @@ public:
Returns true if point is less than or equal to radius away from
the center.
*/
bool contains(const Vector3& point) const;
bool contains(const Point3& point) const;
bool contains(const Sphere& other) const;
@@ -71,7 +79,7 @@ public:
bool culledBy(
const class Plane* plane,
int numPlanes,
int32& cullingPlaneIndex,
int32& cullingPlaneIndex,
const uint32 testMask,
uint32& childMask) const;
@@ -88,18 +96,18 @@ public:
See AABox::culledBy
*/
bool culledBy(
const Array<Plane>& plane,
int32& cullingPlaneIndex,
const uint32 testMask,
const Array<Plane>& plane,
int32& cullingPlaneIndex,
const uint32 testMask,
uint32& childMask) const;
/**
Conservative culling test that does not produce a mask for children.
*/
bool culledBy(
const Array<Plane>& plane,
int32& cullingPlaneIndex = dummy,
const uint32 testMask = 0xFFFFFFFF) const;
const Array<Plane>& plane,
int32& cullingPlaneIndex = dummy,
const uint32 testMask = 0xFFFFFFFF) const;
virtual std::string toString() const;
@@ -110,12 +118,12 @@ public:
/**
Uniformly distributed on the surface.
*/
Vector3 randomSurfacePoint() const;
Point3 randomSurfacePoint() const;
/**
Uniformly distributed on the interior (includes surface)
*/
Vector3 randomInteriorPoint() const;
Point3 randomInteriorPoint() const;
void getBounds(class AABox& out) const;

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
#define G3D_SPLINE_H
#ifndef G3D_Spline_h
#define G3D_Spline_h
#include "G3D/platform.h"
#include "G3D/Array.h"
#include "G3D/g3dmath.h"
#include "G3D/Matrix4.h"
#include "G3D/Vector4.h"
#include "G3D/Any.h"
#include "G3D/SplineExtrapolationMode.h"
namespace G3D {
@@ -23,10 +25,12 @@ public:
number of elements as Spline::control. */
Array<float> time;
/** If cyclic, then the control points will be assumed to wrap around.
If not cyclic, then the tangents at the ends of the spline
point to the final control points.*/
bool cyclic;
/** If CYCLIC, then the control points will be assumed to wrap around.
If LINEAR, then the tangents at the ends of the spline
point to the final control points. If CONSTANT, the end control
points will be treated as multiple contol points (so the value remains constant at the ends)
*/
SplineExtrapolationMode extrapolationMode;
/** For a cyclic spline, this is the time elapsed between the last
control point and the first. If less than or equal to zero this is
@@ -36,8 +40,13 @@ public:
time[time.size() - 1] - time[time.size() - 2]) / 2.
*/
float finalInterval;
SplineInterpolationMode interpolationMode;
SplineBase() : cyclic(true), finalInterval(-1) {}
SplineBase() :
extrapolationMode(SplineExtrapolationMode::CYCLIC),
finalInterval(-1),
interpolationMode(SplineInterpolationMode::CUBIC) {}
virtual ~SplineBase() {}
@@ -144,11 +153,7 @@ public:
break;
case 1:
if (time[0] == 0) {
append(1, c);
} else {
append(time[0], c);
}
append(time[0] + 1, c);
break;
default:
@@ -192,7 +197,7 @@ public:
if (N == 0) {
c = zero;
t = 0;
} else if (cyclic) {
} else if (extrapolationMode == SplineExtrapolationMode::CYCLIC) {
c = control[iWrap(i, N)];
if (i < 0) {
@@ -222,9 +227,16 @@ public:
// Step away from control point 0
float dt = time[1] - time[0];
// Extrapolate (note; i is negative)
c = control[1] * float(i) + control[0] * float(1 - i);
correct(c);
if (extrapolationMode == SplineExtrapolationMode::LINEAR) {
// Extrapolate (note; i is negative)
c = control[1] * float(i) + control[0] * float(1 - i);
correct(c);
} else if (extrapolationMode == SplineExtrapolationMode::CLAMP){
// Return the first, clamping
c = control[0];
} else {
alwaysAssertM(false, "Invalid extrapolation mode");
}
t = dt * i + time[0];
} else {
@@ -239,9 +251,17 @@ public:
if (N >= 2) {
float dt = time[N - 1] - time[N - 2];
if (extrapolationMode == SplineExtrapolationMode::LINEAR) {
// Extrapolate (note; i is negative)
c = control[N - 1] * float(i - N + 2) + control[N - 2] * -float(i - N + 1);
correct(c);
} else if (extrapolationMode == SplineExtrapolationMode::CLAMP){
// Return the last, clamping
c = control.last();
} else {
alwaysAssertM(false, "Invalid extrapolation mode");
}
// Extrapolate
c = control[N - 1] * float(i - N + 2) + control[N - 2] * -float(i - N + 1);
correct(c);
t = time[N - 1] + dt * (i - N + 1);
} else {
@@ -279,8 +299,47 @@ protected:
/** Normalize or otherwise adjust this interpolated Control. */
virtual void correct(Control& A) const { (void)A; }
/** Does not invoke verifyDone() on the propertyTable because subclasses may have more properties */
virtual void init(AnyTableReader& propertyTable) {
propertyTable.getIfPresent("extrapolationMode", extrapolationMode);
propertyTable.getIfPresent("interpolationMode", interpolationMode);
propertyTable.getIfPresent("finalInterval", finalInterval);
const bool hasTime = propertyTable.getIfPresent("time", time);
if (propertyTable.getIfPresent("control", control)) {
if (! hasTime) {
// Assign unit times
time.resize(control.size());
for (int i = 0; i < time.size(); ++i) {
time[i] = float(i);
}
} // if has time
} // if has control
} // init
public:
/** Accepts a table of properties, or any valid PhysicsFrame specification for a single control*/
explicit Spline(const Any& any) {
AnyTableReader propertyTable(any);
init(propertyTable);
propertyTable.verifyDone();
}
/** Note that invoking classes can call setName on the returned value instead of passing a name in. */
virtual Any toAny(const std::string& myName) const {
Any a(Any::TABLE, myName);
a["extrapolationMode"] = extrapolationMode;
a["interpolationMode"] = interpolationMode;
a["control"] = Any(control);
a["time"] = Any(time);
a["finalInterval"] = finalInterval;
return a;
}
/**
Return the position at time s. The spline is defined outside
@@ -313,6 +372,22 @@ public:
Control p[4];
float t[4];
getControls(i - 1, t, p, 4);
const Control& p0 = p[0];
const Control& p1 = p[1];
const Control& p2 = p[2];
const Control& p3 = p[3];
// Compute the weighted sum of the neighboring control points.
Control sum;
if (interpolationMode == SplineInterpolationMode::LINEAR) {
const float a = (s - t[1]) / (t[2] - t[1]);
sum = p1 * (1.0f - a) + p2 * a;
correct(sum);
return sum;
}
float dt0 = t[1] - t[0];
float dt1 = t[2] - t[1];
float dt2 = t[3] - t[2];
@@ -325,13 +400,6 @@ public:
// Compute the weights on each of the control points.
const Vector4& weights = uvec * basis;
// Compute the weighted sum of the neighboring control points.
Control sum;
const Control& p0 = p[0];
const Control& p1 = p[1];
const Control& p2 = p[2];
const Control& p3 = p[3];
// The factor of 1/2 from averaging two time intervals is
// already factored into the basis

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:
std::string myName;
bool m_enabled;
double startTime;
std::string prevMark;
double prevTime;
@@ -85,6 +88,15 @@ public:
Stopwatch(const std::string& name = "Stopwatch");
void setEnabled(bool e) {
m_enabled = e;
}
/** A stopwatch only prints output when enabled */
bool enabled() const {
return m_enabled;
}
/** Returns the number of times that tick was called per wall-clock second;
e.g. frames-per-second. */
double FPS() const {
@@ -130,7 +142,10 @@ public:
void reset();
/** Call after an operation has completed, with the name of the operation, to
print a debug message listing the time since the previous after() call. */
print a debug message listing the time since the previous after() call.
Does nothing if the stopwatch is disabled.
*/
void after(const std::string& s = "");
};

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 Benjamin Jurke http://www.flipcode.com/cgi-bin/msg.cgi?showThread=COTD-ProcessorDetectionClass&forum=cotd&id=-1
@cite Michael Herf http://www.stereopsis.com/memcpy.html
\cite Rob Wyatt http://www.gamasutra.com/features/wyatts_world/19990709/processor_detection_01.htm
\cite Benjamin Jurke http://www.flipcode.com/cgi-bin/msg.cgi?showThread=COTD-ProcessorDetectionClass&forum=cotd&id=-1
\cite Michael Herf http://www.stereopsis.com/memcpy.html
@created 2003-01-25
@edited 2008-10-14
\created 2003-01-25
\edited 2012-10-02
*/
#ifndef G3D_System_h
@@ -18,28 +18,20 @@
#include "G3D/g3dmath.h"
#include "G3D/G3DGameUnits.h"
#include "G3D/BinaryFormat.h"
#include "G3D/FileNotFound.h"
#include <string>
#ifdef G3D_LINUX
# include <sys/socket.h>
#if defined(__aarch64__)
#include <sys/time.h>
#endif
#ifdef G3D_OSX
#define Zone OSX_Zone
# include <CoreServices/CoreServices.h>
#endif
namespace G3D {
/**
Routine used by the demos to find the data. Searches in
../data, ../../data, etc. up to 5 levels back. Checks
common locations like \verbatim c:\libraries\g3d-<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
to be distributed with your program. This generates the
string that must appear in your documentation.
@@ -118,7 +110,7 @@ private:
std::string m_cpuArch;
std::string m_operatingSystem;
# ifdef G3D_WIN32
# ifdef G3D_WINDOWS
/** Used by getTick() for timing */
LARGE_INTEGER m_start;
LARGE_INTEGER m_counterFrequency;
@@ -167,7 +159,6 @@ private:
*/
static void cpuid(CPUIDFunction func, uint32& areg, uint32& breg, uint32& creg, uint32& dreg);
void init();
/** Called from init() */
void getStandardProcessorExtensions();
@@ -175,7 +166,12 @@ private:
/** Called from init() */
void initTime();
void init();
public:
/** atexit handling code invoked from G3DCleanupHook. */
static void cleanup();
/** Returns the speed of processor 0 in MHz.
Always returns 0 on linux.*/
@@ -243,16 +239,13 @@ public:
*/
static std::string currentDateString();
/**
Guarantees that the start of the array is aligned to the
specified number of bytes.
*/
static void* alignedMalloc(size_t bytes, size_t alignment);
/** Returns the current 24-hour local time as a string in the form HH:MM:SS */
static std::string currentTimeString();
/**
Uses pooled storage to optimize small allocations (1 byte to 5
kilobytes). Can be 10x to 100x faster than calling ::malloc or
new.
kilobytes). Can be 10x to 100x faster than calling \c malloc or
\c new.
The result must be freed with free.
@@ -288,6 +281,12 @@ public:
*/
static void free(void* p);
/**
Guarantees that the start of the array is aligned to the
specified number of bytes.
*/
static void* alignedMalloc(size_t bytes, size_t alignment);
/**
Frees memory allocated with alignedMalloc.
*/
@@ -370,6 +369,7 @@ public:
/**
To count the number of cycles a given operation takes:
\htmlonly
<PRE>
unsigned long count;
System::beginCycleCount(count);
@@ -377,11 +377,12 @@ public:
System::endCycleCount(count);
// count now contains the cycle count for the intervening operation.
</PRE>
\endhtmlonly
*/
/* static void beginCycleCount(uint64& cycleCount);
static void beginCycleCount(uint64& cycleCount);
static void endCycleCount(uint64& cycleCount);
static uint64 getCycleCount(); */
static uint64 getCycleCount();
inline static void setOutOfMemoryCallback(OutOfMemoryCallback c) {
instance().m_outOfMemoryCallback = c;
@@ -404,7 +405,7 @@ public:
/** Set an environment variable for the current process */
static void setEnv(const std::string& name, const std::string& value);
/** Get an environment variable for the current process. Returns NULL if the variable doesn't exist. */
static const char* getEnv(const std::string& name);
@@ -412,25 +413,53 @@ public:
Prints a human-readable description of this machine
to the text output stream. Either argument may be NULL.
*/
static void describeSystem(
class TextOutput& t);
static void describeSystem
(class TextOutput& t);
static void describeSystem(
std::string& s);
/** On Win32, returns the clipboard text contents. Does nothing on other
platforms (yet) */
static std::string getClipboardText();
/** Copies the text to the clipboard on Win32. */
static void setClipboardText(const std::string& s);
static void describeSystem
(std::string& s);
/**
Tries to locate the resource by looking in related directories.
If found, returns the full path to the resource, otherwise
returns the empty string.
Looks in:
- Literal interpretation of full (i.e., if it contains a fully-qualified name)
- Last directory in which a file was found
- Current directory
- System::appDataDir (which is usually GApp::Settings.dataDir, which defaults to the directory containing the program binary)
- $G3D9DATA directory
- System::appDataDir() + "data/" (note that this may be a zipfile named "data" with no extension)
- System::appDataDir() + "data.zip/"
- ../data-files/ (windows)
- ../../data-files/ (windows)
- ../../../data-files/ (windows)
Plus the following subdirectories of those:
- cubemap
- gui
- font
- icon
- models
- image
- sky
- md2
- md3
- ifs
- 3ds
\param exceptionIfNotFound If true and the file is not found, throws G3D::FileNotFound.
*/
static std::string findDataFile(const std::string& full, bool errorIfNotFound = true);
static std::string findDataFile(const std::string& full, bool exceptionIfNotFound = true, bool caseSensitive =
#ifdef G3D_WINDOWS
false
#else
true
#endif
);
/**
Sets the path that the application is using as its data directory.
@@ -441,47 +470,80 @@ public:
};
/* don't need that for Moongose, not portable to Win64...
#ifdef _MSC_VER
inline uint64 System::getCycleCount() {
uint32 timehi, timelo;
# ifdef _M_IX86
// 32-bit
inline uint64 System::getCycleCount() {
uint32 timehi, timelo;
// Use the assembly instruction rdtsc, which gets the current
// cycle count (since the process started) and puts it in edx:eax.
__asm
{
rdtsc;
mov timehi, edx;
mov timelo, eax;
}
// Use the assembly instruction rdtsc, which gets the current
// cycle count (since the process started) and puts it in edx:eax.
__asm
{
rdtsc;
mov timehi, edx;
mov timelo, eax;
}
return ((uint64)timehi << 32) + (uint64)timelo;
}
return ((uint64)timehi << 32) + (uint64)timelo;
}
# else
// 64-bit
inline uint64 System::getCycleCount() {
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return now.QuadPart;
}
# endif
#elif defined(G3D_LINUX)
inline uint64 System::getCycleCount() {
uint32 timehi, timelo;
# if defined(__aarch64__)
# if (__ARM_ARCH >= 6) // V6 is the earliest arch that has a standard cyclecount
uint32_t pmccntr;
uint32_t pmuseren;
uint32_t pmcntenset;
// Read the user mode perf monitor counter access permissions.
__asm__ __volatile__("mrc p15, 0, %w0, c9, c14, 0" : "=r"(pmuseren));
if (pmuseren & 1) { // Allows reading perfmon counters for user mode code.
__asm__ __volatile__("mrc p15, 0, %w0, c9, c12, 1" : "=r"(pmcntenset));
if (pmcntenset & 0x80000000ul) { // Is it counting?
__asm__ __volatile__("mrc p15, 0, %w0, c9, c13, 0" : "=r"(pmccntr));
// The counter is set up to count every 64th cycle
return static_cast<uint64>(pmccntr) * 64; // Should optimize to << 6
}
}
# endif
__asm__ __volatile__ (
"rdtsc "
: "=a" (timelo),
"=d" (timehi)
: );
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<uint64>(tv.tv_sec) * 1000000 + tv.tv_usec;
# else
uint32 timehi, timelo;
return ((uint64)timehi << 32) + (uint64)timelo;
__asm__ __volatile__ (
"rdtsc "
: "=a" (timelo),
"=d" (timehi)
: );
return ((uint64)timehi << 32) + (uint64)timelo;
# endif
}
#elif defined(G3D_OSX)
inline uint64 System::getCycleCount() {
//Note: To put off extra processing until the end, this does not
//return the actual clock cycle count. It is a bus cycle count.
//When endCycleCount() is called, it converts the two into a difference
//of clock cycles
//Note: To put off extra processing until the end, this does not
//return the actual clock cycle count. It is a bus cycle count.
//When endCycleCount() is called, it converts the two into a difference
//of clock cycles
return (uint64) UnsignedWideToUInt64(UpTime());
//return (uint64) mach_absolute_time();
//return (uint64) mach_absolute_time();
}
#endif
@@ -496,15 +558,20 @@ inline void System::endCycleCount(uint64& cycleCount) {
cycleCount = getCycleCount() - cycleCount;
#else
AbsoluteTime end = UpTime();
Nanoseconds diffNS =
Nanoseconds diffNS =
AbsoluteDeltaToNanoseconds(end, UInt64ToUnsignedWide(cycleCount));
cycleCount =
(uint64) ((double) (instance().m_OSXCPUSpeed) *
cycleCount =
(uint64) ((double) (instance().m_OSXCPUSpeed) *
(double) UnsignedWideToUInt64(diffNS) * instance().m_secondsPerNS);
#endif
}
*/
} // namespace
#ifdef G3D_OSX
#undef Zone
#endif
#endif

View File

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

View File

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

View File

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

View File

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

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
@edited 2008-10-06
\created 2003-04-05
\edited 2011-06-20
@cite Random point method by Greg Turk, Generating random points in triangles. In A. S. Glassner, ed., Graphics Gems, pp. 24-28. Academic Press, 1990
\cite Random point method by Greg Turk, Generating random points in triangles. In A. S. Glassner, ed., Graphics Gems, pp. 24-28. Academic Press, 1990
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_TRIANGLE_H
#define G3D_TRIANGLE_H
#ifndef G3D_Triangle_h
#define G3D_Triangle_h
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
@@ -55,19 +55,19 @@ private:
void init(const Vector3& v0, const Vector3& v1, const Vector3& v2);
public:
Triangle(class BinaryInput& b);
void serialize(class BinaryOutput& b);
void deserialize(class BinaryInput& b);
void serialize(class BinaryOutput& b);
void deserialize(class BinaryInput& b);
Triangle();
Triangle(const Vector3& v0, const Vector3& v1, const Vector3& v2);
Triangle(const Point3& v0, const Point3& v1, const Point3& v2);
~Triangle();
/** 0, 1, or 2 */
inline const Vector3& vertex(int n) const {
inline const Point3& vertex(int n) const {
debugAssert((n >= 0) && (n < 3));
return _vertex[n];
}
@@ -91,15 +91,15 @@ public:
const Vector3& normal() const;
/** Barycenter */
Vector3 center() const;
Point3 center() const;
const Plane& plane() const;
/** Returns a random point in the triangle. */
Vector3 randomPoint() const;
Point3 randomPoint() const;
inline void getRandomSurfacePoint
(Vector3& P,
(Point3& P,
Vector3& N = Vector3::ignore()) const {
P = randomPoint();
N = normal();

View File

@@ -1,25 +1,24 @@
/**
@file UprightFrame.h
@author Morgan McGuire, http://graphics.cs.williams.edu
\file G3D/UprightFrame.h
\author Morgan McGuire, http://graphics.cs.williams.edu
*/
#ifndef G3D_UPRIGHTFRAME_H
#define G3D_UPRIGHTFRAME_H
#ifndef G3D_UprightFrame_h
#define G3D_UprightFrame_h
#include "G3D/platform.h"
#include "G3D/Spline.h"
#include "G3D/Vector3.h"
#include "G3D/Any.h"
#include "G3D/CoordinateFrame.h"
namespace G3D {
/**
Coordinate frame expressed in Euler angles.
Unlike a G3D::Quat, UprightFrame always keeps the reference frame from rolling about its own z axis.
Particularly useful for cameras.
\brief Coordinate frame expressed in Euler angles.
Unlike a G3D::Quat, UprightFrame always keeps the reference frame from rolling about its own z axis.
Particularly useful for cameras.
@sa G3D::CoordinateFrame, G3D::Matrix4, G3D::PhysicsFrame, G3D::UprightSpline, G3D::UprightSplineManipulator
\sa G3D::CoordinateFrame, G3D::Matrix4, G3D::PhysicsFrame, G3D::UprightSpline, G3D::UprightSplineManipulator
*/
class UprightFrame {
public:
@@ -32,18 +31,32 @@ public:
/** In radians about the Y-axis */
float yaw;
inline UprightFrame(const Vector3& t = Vector3::zero(), float p = 0, float y = 0)
UprightFrame(const Vector3& t = Vector3::zero(), float p = 0, float y = 0)
: translation(t), pitch(p), yaw(y) {}
UprightFrame(const CoordinateFrame& cframe);
/** Constructs an UprightFrame from an Any object.
The Any format for UprightFrame is:
pitch = ##,
translation = Vector3(),
yaw = ##
*/
explicit UprightFrame(const Any& any);
CoordinateFrame toCoordinateFrame() const;
Any toAny() const;
UprightFrame& operator=(const Any& any);
/** Supports implicit cast to CoordinateFrame */
inline operator CoordinateFrame() const {
operator CoordinateFrame() const {
return toCoordinateFrame();
}
CoordinateFrame toCoordinateFrame() const;
/** Required for use with spline */
UprightFrame operator+(const UprightFrame& other) const;
@@ -61,8 +74,10 @@ public:
void deserialize(class BinaryInput& b);
};
/** Shortest-path linear velocity spline for camera positions. Always keeps the camera from rolling.
@sa G3D::UprightSplineManipulator, G3D::UprightFrame
/**
\brief Shortest-path linear velocity spline for camera positions. Always keeps the camera from rolling.
\sa G3D::UprightSplineManipulator, G3D::UprightFrame
*/
class UprightSpline : public Spline<UprightFrame> {
protected:
@@ -72,10 +87,29 @@ protected:
}
public:
UprightSpline();
/** Constructs an UprightSpline from an Any object.
The Any format for UprightSpline is:
controls = (UprightFrame, ...),
times = (##, ...),
cyclic = bool
The controls and times arrays must have the same length.
*/
explicit UprightSpline(const Any& any);
virtual Any toAny(const std::string& myName) const override;
Any toAny() const;
UprightSpline& operator=(const Any& any);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
};
}

View File

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

View File

@@ -4,14 +4,14 @@
@maintainer Morgan McGuire, matrix@brown.edu
@created 2003-08-09
@edited 2004-01-03
@edited 2010-01-03
Copyright 2000-2006, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
#ifndef VECTOR2INT16_H
#define VECTOR2INT16_H
#ifndef Vector2int16_h
#define Vector2int16_h
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
@@ -19,12 +19,13 @@
namespace G3D {
class Any;
/**
\class Vector2int16
A Vector2 that packs its fields into uint16s.
A Vector2 that packs its fields into G3D::int16 s.
*/
G3D_BEGIN_PACKED_CLASS(2)
class Vector2int16 {
Vector2int16 {
private:
// Hidden operators
bool operator<(const Vector2int16&) const;
@@ -38,8 +39,14 @@ public:
Vector2int16() : x(0), y(0) {}
Vector2int16(G3D::int16 _x, G3D::int16 _y) : x(_x), y(_y){}
Vector2int16(const class Vector2& v);
Vector2int16(class BinaryInput& bi);
explicit Vector2int16(const class Vector2& v);
explicit Vector2int16(class BinaryInput& bi);
explicit Vector2int16(const class Any& a);
explicit Vector2int16(const class Vector2int32& v);
Any toAny() const;
Vector2int16& operator=(const Any& a);
inline G3D::int16& operator[] (int i) {
debugAssert(((unsigned int)i) <= 1);
@@ -63,6 +70,10 @@ public:
return Vector2int16(x * other.x, y * other.y);
}
Vector2int16 operator-() const {
return Vector2int16(-x, -y);
}
inline Vector2int16 operator*(const int s) const {
return Vector2int16(x * s, y * s);
}
@@ -73,6 +84,10 @@ public:
return *this;
}
bool isZero() const {
return (x == 0) && (y == 0);
}
/** Shifts both x and y */
inline Vector2int16 operator>>(const int s) const {
return Vector2int16(x >> s, y >> s);
@@ -118,6 +133,8 @@ public:
}
G3D_END_PACKED_CLASS(2)
typedef Vector2int16 Point2int16;
}
template<> struct HashTrait<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
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
\created 2001-06-02
\edited 2010-12-25
@created 2001-06-02
@edited 2009-11-01
Copyright 2000-2009, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
@@ -36,7 +37,7 @@ class Any;
/**
<B>Swizzles</B>
Vector classes have swizzle operators, e.g. <CODE>v.xy()</CODE>, that
allow selection of arbitrary sub-fields. These cannot be used as write
allow selection of arbitrary sub-fields. These cannot be used as write
masks. Examples
<PRE>
@@ -72,29 +73,37 @@ public:
/** Initializes to zero */
Vector3();
/** \param any Must either Vector3(#, #, #) or Vector3 {x = #, y = #, z = #}*/
Vector3(const Any& any);
/**
\param any Must either Vector3(#, #, #) or Vector3 {x = #, y = #, z = #}.
Because Point3 is a typedef for Vector3 in the current implementation,
this constructor accepts Point3(#, #, #), etc. as well.
*/
explicit Vector3(const Any& any);
/** Converts the Vector3 to an Any, using the specified \a name instead of "Vector3" */
Any toAny(const std::string& name) const;
/** Converts the Vector3 to an Any. */
operator Any() const;
Any toAny() const;
/** Divides by 127 */
Vector3(const Vector4int8&);
Vector3(const class Vector2& v, float z);
Vector3(const class Vector3int32& v);
explicit Vector3(class BinaryInput& b);
Vector3(float _x, float _y, float _z);
explicit Vector3(const class Vector2& v, float _z);
explicit Vector3(float coordinate[3]);
explicit Vector3(double coordinate[3]);
Vector3(const class Vector3int16& v);
explicit Vector3(class TextInput& t);
explicit Vector3(class TextInput& t);
explicit Vector3(const class Color3& c);
/** Format is three float32's */
/** Format is three float32's */
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
/** Format is "(%f, %f, %f)" */
/** Format is "(%f, %f, %f)" */
void serialize(class TextOutput& t) const;
void deserialize(class TextInput& t);
@@ -106,6 +115,10 @@ public:
const float& __fastcall operator[] (int i) const;
float& operator[] (int i);
bool nonZero() const {
return (x != 0) || (y != 0) || (z != 0);
}
enum Axis {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, DETECT_AXIS=-1};
/**
@@ -115,12 +128,8 @@ public:
Axis primaryAxis() const;
// assignment and comparison
Vector3& __fastcall operator= (const Vector3& rkVector);
/* requried as of C++ 11 */
#if __cplusplus >= 201103L
Vector3(const Vector3&) = default;
Vector3(Vector3&&) = default;
#endif
Vector3& operator=(const Vector3& rkVector) = default;
Vector3& operator=(const Any& a);
bool operator== (const Vector3& rkVector) const;
bool operator!= (const Vector3& rkVector) const;
size_t hashCode() const;
@@ -130,12 +139,19 @@ public:
/** Returns true if this vector has finite length. */
bool isFinite() const;
/** True if any field is nan */
bool isNaN() const;
/** Returns true if this vector has length ~= 0 */
bool isZero() const;
/** Returns true if this vector has length ~= 1 */
bool isUnit() const;
/** Returns a vector that is \a this translated towards \a goal with a maximum translation of \a maxTranslation. */
Vector3 movedTowards(const Vector3& goal, float maxTranslation) const;
void moveTowards(const Vector3& goal, float maxTranslation);
// arithmetic operations
Vector3 __fastcall operator+ (const Vector3& v) const;
Vector3 __fastcall operator- (const Vector3& v) const;
@@ -158,12 +174,18 @@ public:
Vector3& __fastcall operator/= (const Vector3& v);
/** Same as magnitude */
float length() const;
float length() const;
float magnitude() const;
/** Raise each component of this vector to a power */
Vector3 pow(float p) const {
return Vector3(powf(x, p), powf(y, p), powf(z, p));
}
/**
The result is a nan vector if the length is almost zero.
Returns a unit-length version of this vector.
Returns nan if length is almost zero.
*/
Vector3 direction() const;
@@ -184,7 +206,7 @@ public:
<PRE>
V' N V
r ^ -,
\ | /
\|/
@@ -196,17 +218,17 @@ public:
/**
See also G3D::Ray::reflect.
The length is 1.
The length is 1.
<PRE>
V' N V
r ^ /
\ | /
\|'-
</PRE>
*/
Vector3 reflectionDirection(const Vector3& normal) const;
/**
Returns Vector3::zero() if the length is nearly zero, otherwise
@@ -228,7 +250,7 @@ public:
where iExit is the index of refraction for the
previous material and iEnter is the index of refraction
for the new material. Like Vector3::reflectionDirection,
the result has length 1 and is
the result has length 1 and is
pointed <I>away</I> from the intersection.
Returns Vector3::zero() in the case of total internal refraction.
@@ -242,7 +264,7 @@ public:
See also G3D::Ray::refract.
<PRE>
N V
^ /
| /
|'-
@@ -270,11 +292,9 @@ public:
float squaredLength() const;
float squaredMagnitude () const;
float __fastcall dot(const Vector3& rkVector) const;
float unitize(float tolerance = 1e-06);
/** Cross product. Note that two cross products in a row
can be computed more cheaply: v1 x (v2 x v3) = (v1 dot v3) v2 - (v1 dot v2) v3.
*/
@@ -320,18 +340,29 @@ public:
G3D::clamp(z, low, high));
}
inline Vector3 floor() const {
return G3D::Vector3(::floor(x), ::floor(y), ::floor(z));
}
inline Vector3 round() const {
return Vector3(G3D::round(x), G3D::round(y), G3D::round(z));
}
/**
Linear interpolation
*/
inline Vector3 lerp(const Vector3& v, float alpha) const {
return (*this) + (v - *this) * alpha;
return (*this) + (v - *this) * alpha;
}
/** Gram-Schmidt orthonormalization. */
static void orthonormalize (Vector3 akVector[3]);
/** \brief Random unit vector, uniformly distributed on the sphere.
/** \brief Random unit vector, uniformly distributed on the sphere.
Distribution rendered by G3D::DirectionHistogram:
\image html vector3-random.png
*/
@@ -339,8 +370,8 @@ public:
/** \brief Random unit vector, distributed according to \f$\max(\cos \theta,0)\f$.
That is, so that the probability of \f$\vec{V}\f$ is proportional
to \f$\max(\vec{v} \cdot \vec{n}, 0)\f$. Useful in photon mapping for
That is, so that the probability of \f$\vec{V}\f$ is proportional
to \f$\max(\vec{v} \cdot \vec{n}, 0)\f$. Useful in photon mapping for
Lambertian scattering.
Distribution rendered by G3D::DirectionHistogram:
@@ -352,6 +383,8 @@ public:
*/
static Vector3 cosHemiRandom(const Vector3& n, Random& r = Random::common());
static Vector3 cosSphereRandom(const Vector3& n, Random& r = Random::common());
/** \brief Random unit vector, distributed according to \f$\max(\cos^k \theta,0)\f$.
That is, so that the probability of \f$\vec{V}\f$ is
@@ -375,14 +408,6 @@ public:
*/
static Vector3 hemiRandom(const Vector3& normal, Random& r = Random::common());
/** Input W must be initialize to a nonzero vector, output is {U,V,W}
an orthonormal basis. A hint is provided about whether or not W
is already unit length.
@deprecated Use getTangents
*/
static void generateOrthonormalBasis (Vector3& rkU, Vector3& rkV,
Vector3& rkW, bool bUnitLengthW = true);
inline float sum() const {
return x + y + z;
}
@@ -399,7 +424,7 @@ public:
static const Vector3& unitZ();
static const Vector3& inf();
static const Vector3& nan();
/** Smallest (most negative) representable vector */
static const Vector3& minFinite();
@@ -410,16 +435,16 @@ public:
/** Creates two orthonormal tangent vectors X and Y such that
if Z = this, X x Y = Z.*/
inline void getTangents(Vector3& X, Vector3& Y) const {
debugAssertM(G3D::fuzzyEq(length(), 1.0f),
debugAssertM(G3D::fuzzyEq(length(), 1.0f),
"makeAxes requires Z to have unit length");
// Choose another vector not perpendicular
X = (abs(x) < 0.9f) ? Vector3::unitX() : Vector3::unitY();
// Remove the part that is parallel to Z
X -= *this * this->dot(X);
X /= X.length();
Y = this->cross(X);
}
@@ -554,6 +579,8 @@ public:
static Vector3& ignore();
};
inline G3D::Vector3 operator*(float s, const G3D::Vector3& v) {
return v * s;
}
@@ -600,14 +627,6 @@ inline float& Vector3::operator[] (int i) {
}
//----------------------------------------------------------------------------
inline Vector3& Vector3::operator= (const Vector3& rkVector) {
x = rkVector.x;
y = rkVector.y;
z = rkVector.z;
return *this;
}
//----------------------------------------------------------------------------
inline bool Vector3::fuzzyEq(const Vector3& other) const {
@@ -755,8 +774,7 @@ inline Vector3 Vector3::cross (const Vector3& rkVector) const {
inline Vector3 Vector3::unitCross (const Vector3& rkVector) const {
Vector3 kCross(y*rkVector.z - z*rkVector.y, z*rkVector.x - x*rkVector.z,
x*rkVector.y - y*rkVector.x);
kCross.unitize();
return kCross;
return kCross.direction();
}
//----------------------------------------------------------------------------
@@ -771,7 +789,7 @@ inline Vector3 Vector3::max(const Vector3 &v) const {
//----------------------------------------------------------------------------
inline bool Vector3::isZero() const {
return G3D::fuzzyEq(squaredMagnitude(), 0.0f);
return G3D::fuzzyEq(fabsf(x) + fabsf(y) + fabsf(z), 0.0f);
}
//----------------------------------------------------------------------------
@@ -780,6 +798,22 @@ inline bool Vector3::isUnit() const {
return G3D::fuzzyEq(squaredMagnitude(), 1.0f);
}
/**
Points are technically distinct mathematical entities from vectors.
Actually distinguishing them at the class level tends to add lots of
boilerplate (e.g., (P - Point3::zero()).direction()
vs. P.direction()), so many programmers prefer use a single class,
as GLSL does.
G3D provides this typedef as a way of documenting arguments that are
locations in space and not directions. Beware that points and
vectors are interchangable from the compiler's point of view, and
that the programmer must track which is really which. */
typedef Vector3 Point3;
void serialize(const Vector3& v, class BinaryOutput& b);
void deserialize(Vector3& v, class BinaryInput& b);
} // namespace G3D

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

View File

@@ -1,29 +1,32 @@
/**
@file Vector3int32.h
@file G3D/Vector3int32.h
@maintainer Morgan McGuire, matrix@brown.edu
@created 2008-07-01
@edited 2008-07-01
Copyright 2000-2009, Morgan McGuire.
@edited 2011-01-01
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
#ifndef VECTOR3INT32_H
#define VECTOR3INT32_H
#ifndef G3D_Vector3int32_h
#define G3D_Vector3int32_h
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
#include "G3D/HashTrait.h"
#include "G3D/Crypto.h"
namespace G3D {
class Any;
/**
\ Vector3int32
A Vector3 that packs its fields into uint32s.
*/
G3D_BEGIN_PACKED_CLASS(4)
class Vector3int32 {
Vector3int32 {
private:
// Hidden operators
bool operator<(const Vector3int32&) const;
@@ -38,9 +41,21 @@ public:
Vector3int32() : x(0), y(0), z(0) {}
Vector3int32(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {}
Vector3int32(const class Vector2int32& v, int _z);
Vector3int32(const class Vector2int16& v, int _z);
Vector3int32(const class Vector3int16& v);
Vector3int32(const class Vector3& v);
Vector3int32(class BinaryInput& bi);
Vector3int32(const Any& any);
Any toAny() const;
/** Rounds to the nearest int */
explicit Vector3int32(const class Vector3& v);
explicit Vector3int32(class BinaryInput& bi);
static Vector3int32 truncate(const class Vector3& v);
bool nonZero() const {
return (x != 0) || (y != 0) || (z != 0);
}
void serialize(class BinaryOutput& bo) const;
void deserialize(class BinaryInput& bi);
@@ -71,32 +86,42 @@ public:
return Vector3int32(x * s, y * s, z * s);
}
inline Vector3int32& operator+=(const Vector3int32& other) {
/** Integer division */
inline Vector3int32 operator/(const Vector3int32& other) const {
return Vector3int32(x / other.x, y / other.y, z / other.z);
}
/** Integer division */
inline Vector3int32 operator/(const int s) const {
return Vector3int32(x / s, y / s, z / s);
}
Vector3int32& operator+=(const Vector3int32& other) {
x += other.x;
y += other.y;
z += other.z;
return *this;
}
inline Vector3int32& operator-=(const Vector3int32& other) {
Vector3int32& operator-=(const Vector3int32& other) {
x -= other.x;
y -= other.y;
z -= other.z;
return *this;
}
inline Vector3int32& operator*=(const Vector3int32& other) {
Vector3int32& operator*=(const Vector3int32& other) {
x *= other.x;
y *= other.y;
z *= other.z;
return *this;
}
inline bool operator== (const Vector3int32& rkVector) const {
bool operator== (const Vector3int32& rkVector) const {
return ( x == rkVector.x && y == rkVector.y && z == rkVector.z );
}
inline bool operator!= (const Vector3int32& rkVector) const {
bool operator!= (const Vector3int32& rkVector) const {
return ( x != rkVector.x || y != rkVector.y || z != rkVector.z );
}
@@ -108,20 +133,64 @@ public:
return Vector3int32(iMin(x, v.x), iMin(y, v.y), iMin(z, v.z));
}
Vector3int32 operator-() const {
return Vector3int32(-x, -y, -z);
}
std::string toString() const;
Vector3int32 operator<<(int i) const {
return Vector3int32(x << i, y << i, z << i);
}
Vector3int32 operator>>(int i) const {
return Vector3int32(x >> i, y >> i, z >> i);
}
Vector3int32 operator>>(const Vector3int32& v) const {
return Vector3int32(x >> v.x, y >> v.y, z >> v.z);
}
Vector3int32 operator<<(const Vector3int32& v) const {
return Vector3int32(x << v.x, y << v.y, z << v.z);
}
Vector3int32 operator&(int16 i) const {
return Vector3int32(x & i, y & i, z & i);
}
// 2-char swizzles
Vector2int32 xx() const;
Vector2int32 yx() const;
Vector2int32 zx() const;
Vector2int32 xy() const;
Vector2int32 yy() const;
Vector2int32 zy() const;
Vector2int32 xz() const;
Vector2int32 yz() const;
Vector2int32 zz() const;
}
G3D_END_PACKED_CLASS(4)
}
typedef Vector3int32 Point3int32;
Vector3int32 iFloor(const Vector3&);
} // namespace G3D
template <> struct HashTrait<G3D::Vector3int32> {
static size_t hashCode(const G3D::Vector3int32& key) {
return G3D::superFastHash(&key, sizeof(key));
//return G3D::Crypto::crc32(&key, sizeof(key));
/*
// Mask for the top bit of a uint32
const G3D::uint32 top = (1UL << 31);
// Mask for the bottom 10 bits of a uint32
const G3D::uint32 bot = 0x000003FF;
return static_cast<size_t>(((key.x & top) | ((key.y & top) >> 1) | ((key.z & top) >> 2)) |
(((key.x & bot) << 19) ^ ((key.y & bot) << 10) ^ (key.z & bot)));
*/
}
};

View File

@@ -47,10 +47,11 @@ private:
public:
/** \param any Must either Vector4(#, #, #, #) or Vector3 {x = #, y = #, z = #, w =#}*/
Vector4(const Any& any);
explicit Vector4(const Any& any);
Vector4& operator=(const Any& a);
/** Converts the Vector4 to an Any. */
operator Any() const;
Any toAny() const;
// construction
Vector4();
@@ -698,7 +699,11 @@ inline float Vector4::squaredLength() const {
return x * x + y * y + z * z + w * w;
}
}
void serialize(const Vector4& v, class BinaryOutput& b);
void deserialize(Vector4& v, class BinaryInput& b);
} // G3D
template <> struct HashTrait<G3D::Vector4> {
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) {}
/** Multiplies the source by 127 and clamps to (-128, 127) when converting */
Vector4int8(const Vector4& source);
explicit Vector4int8(const Vector4& source);
/** Multiplies the source by 127 and clamps to (-128, 127) when converting */
Vector4int8(const Vector3& source, int8 w);
explicit Vector4int8(const Vector3& source, int8 w);
inline Vector4int8(int8 x, int8 y, int8 z, int8 w) : x(x), y(y), z(z), w(w) {}
Vector4int8(class BinaryInput& b);
explicit Vector4int8(class BinaryInput& b);
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);

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

View File

@@ -22,30 +22,38 @@ public:
/** Surfaces with normals that are within this angle of each
other are considered to be curved. Default value is toRadians(70.0f).*/
float normalSmoothingAngle;
float vertexWeldRadius;
float textureWeldRadius;
float normalWeldRadius;
/** Default value is 0 */
float vertexWeldRadius;
float textureWeldRadius;
float normalWeldRadius;
inline Settings(float normalSmoothAngle = toRadians(70.0f)) :
normalSmoothingAngle(normalSmoothAngle),
vertexWeldRadius(0.0001f),
vertexWeldRadius(0.001f),
textureWeldRadius(0.0001f),
normalWeldRadius(0.01f) {}
Settings(const Any& any);
operator Any() const;
Any toAny() const;
void serialize(class BinaryOutput& b) const;
void deserialize(class BinaryInput& b);
};
/**
Mutates geometry, texCoord, and indexArray so that the output has collocated vertices collapsed (welded).
Mutates geometry, texCoord, and indexArray so that the output has
collocated vertices collapsed (welded).
@param vertices Input and output
@param textureCoords Input and output
@param normals Output only
@param indices Input and output. This is an array of trilist indices.
@param oldToNewIndex Output argument
@param normalSmoothingAngle Varies from 0 (flat shading) to toRadians(180) for extremely smooth shading. Default is toRadians(70)
*/
static void weld(
Array<Vector3>& vertices,
@@ -61,8 +69,6 @@ public:
@param textureCoords Input and output
@param normals Output only
@param indices Input and output. This is an array of trilist indices.
@param oldToNewIndex Output argument
@param normalSmoothingAngle Varies from 0 (flat shading) to toRadians(180) for extremely smooth shading. Default is toRadians(70)
*/
inline static void weld(
Array<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
@edited 2010-04-17
\created 2007-04-17
\edited 2010-04-17
Copyright 2000-2010, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
@@ -15,7 +15,6 @@
#include "G3D/platform.h"
#include "G3D/enumclass.h"
#include "G3D/Any.h"
#ifdef IGNORE
# undef IGNORE
@@ -62,9 +61,7 @@ public:
ZERO,
IGNORE,
ERROR
};
private:
} value;
static const char* toString(int i, Value& v) {
static const char* str[] = {"CLAMP", "TILE", "ZERO", "IGNORE", "ERROR", NULL};
@@ -76,14 +73,11 @@ private:
return s;
}
Value value;
public:
G3D_DECLARE_ENUM_CLASS_METHODS(WrapMode);
};
} // namespace G3D
G3D_DECLARE_ENUM_CLASS_HASHCODE(G3D::WrapMode);

View File

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

View File

@@ -26,20 +26,13 @@ public:
TRIANGLE_STRIP = 0x0005,
TRIANGLE_FAN = 0x0006,
QUADS = 0x0007,
QUAD_STRIP = 0x0008
QUAD_STRIP = 0x0008,
PATCHES = 0x000E
};
private:
static const char* toString(int i, Value& v) {
static const char* str[] = {"POINTS", "LINES", "LINE_STRIP", "TRIANGLES", "TRIANGLE_FAN", "QUADS", "QUAD_STRIP", NULL};
static const Value val[] = {POINTS, LINES, LINE_STRIP, TRIANGLES, TRIANGLE_FAN, QUADS, QUAD_STRIP};
const char* s = str[i];
if (s) {
v = val[i];
}
return s;
}
static const char* toString(int i, Value& v);
Value value;
@@ -49,7 +42,7 @@ public:
};
/** Values for SuperSurface::GPUGeom::refractionHint. */
/** Values for UniversalSurface::GPUGeom::refractionHint. */
class RefractionQuality {
public:
enum Value {
@@ -77,15 +70,7 @@ public:
private:
static const char* toString(int i, Value& v) {
static const char* str[] = {"NONE", "STATIC_ENV", "DYNAMIC_FLAT", "DYNAMIC_FLAT_MULTILAYER", "DYNAMIC_ENV", "BEST", NULL};
static const Value val[] = {NONE, STATIC_ENV, DYNAMIC_FLAT, DYNAMIC_FLAT_MULTILAYER, DYNAMIC_ENV, BEST};
const char* s = str[i];
if (s) {
v = val[i];
}
return s;
}
static const char* toString(int i, Value& v);
Value value;
@@ -95,7 +80,7 @@ public:
};
/** Values for SuperSurface::GPUGeom::mirrorHint. */
/** Values for UniversalSurface::GPUGeom::mirrorHint. */
class MirrorQuality {
public:
@@ -119,15 +104,7 @@ public:
private:
static const char* toString(int i, Value& v) {
static const char* str[] = {"NONE", "STATIC_ENV", "DYNAMIC_PLANAR", "DYNAMIC_ENV", "BEST", NULL};
static const Value val[] = {NONE, STATIC_ENV, DYNAMIC_PLANAR, DYNAMIC_ENV, BEST};
const char* s = str[i];
if (s) {
v = val[i];
}
return s;
}
static const char* toString(int i, Value& v);
Value value;

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

View File

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

View File

@@ -4,9 +4,9 @@
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@author 2002-06-06
@edited 2010-03-06
@edited 2011-03-06
Copyright 2000-2010, Morgan McGuire.
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
*/
@@ -20,42 +20,16 @@
#include "G3D/Set.h"
#include "G3D/g3dmath.h"
#ifdef G3D_WIN32
#ifdef G3D_WINDOWS
// For chdir, mkdir, etc.
# include <direct.h>
#endif
namespace G3D {
namespace _internal {
extern Set<std::string> currentFilesUsed;
}
/** 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);
/** Returns the contents of a text file as a single string */
std::string readWholeFile
(const std::string& filename);
/**
@@ -88,8 +62,8 @@ FILE* createTempFile();
*/
bool zipfileExists
(const std::string& filename,
std::string& outZipfile,
std::string& outInternalFile);
std::string& outZipfile,
std::string& outInternalFile);
bool zipfileExists(const std::string& filename);

View File

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

View File

@@ -7,9 +7,9 @@
@cite highestBit by Jukka Liimatta
@created 2001-06-02
@edited 2009-04-07
@edited 2013-01-27
Copyright 2000-2006, Morgan McGuire.
Copyright 2000-2013, Morgan McGuire.
All rights reserved.
*/
@@ -29,8 +29,9 @@
#include <float.h>
#include <limits>
#include <stdlib.h>
#include <stdint.h>
#ifdef _MSC_VER
#if defined(_MSC_VER) && (_MSC_VER < 1000)
// Visual Studio is missing inttypes.h
# ifndef PRId64
# define PRId64 "I64d"
@@ -58,6 +59,16 @@
#undef min
#undef max
/**
\def G3D_DECLARE_SYMBOL(s)
Defines SYMBOL_s as a static const std::string with the value s.
Useful for avoiding heap allocation from C-string constants being
converted at runtime.
*/
#define G3D_DECLARE_SYMBOL(s) \
static const std::string SYMBOL_##s = #s
namespace G3D {
#ifdef _MSC_VER
@@ -65,59 +76,61 @@ inline double __fastcall drand48() {
return ::rand() / double(RAND_MAX);
}
#if !defined(_WIN64)
/**
Win32 implementation of the C99 fast rounding routines.
# ifdef _M_IX86
// 32-bit
/**
Win32 implementation of the C99 fast rounding routines.
@cite routines are
Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
@cite routines are
Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
Permission to use, copy, modify, distribute, and sell this file for any
purpose is hereby granted without fee, provided that the above copyright
and this permission notice appear in all copies. No representations are
made about the suitability of this software for any purpose. It is
provided "as is" without express or implied warranty.
*/
Permission to use, copy, modify, distribute, and sell this file for any
purpose is hereby granted without fee, provided that the above copyright
and this permission notice appear in all copies. No representations are
made about the suitability of this software for any purpose. It is
provided "as is" without express or implied warranty.
*/
__inline long int lrint (double flt) {
int intgr;
_asm {
fld flt
fistp intgr
};
__inline long int lrint (double flt) {
int intgr;
return intgr;
}
_asm {
fld flt
fistp intgr
};
__inline long int lrintf(float flt) {
int intgr;
return intgr;
}
_asm {
fld flt
fistp intgr
};
__inline long int lrintf(float flt) {
int intgr;
return intgr;
}
_asm {
fld flt
fistp intgr
};
#else
return intgr;
}
# else
// 64-bit
__inline long int lrintf(float flt) {
return (long int)(flt + 0.5f);
}
__inline long int lrint (double flt) {
return (long int)floor(flt+0.5f);
return (long int)(flt + 0.5);
}
__inline long int lrintf(float flt) {
return (long int)floorf(flt+0.5f);
}
#endif
# endif
#endif
#define fuzzyEpsilon (0.00001f)
#define fuzzyEpsilon64 (0.0000005)
#define fuzzyEpsilon32 (0.00001f)
/**
This value should not be tested against directly, instead
G3D::isNan() and G3D::isFinite() will return reliable results. */
@@ -147,23 +160,14 @@ inline double twoPi() {
return 6.28318531;
}
typedef signed char int8;
typedef unsigned char uint8;
typedef short int16;
typedef unsigned short uint16;
typedef int int32;
typedef unsigned int uint32;
#ifdef _MSC_EXTENSIONS
typedef __int64 int64;
typedef unsigned __int64 uint64;
#elif ! defined(_MSC_VER)
typedef int64_t int64;
typedef uint64_t uint64;
#else
typedef long long int64;
typedef unsigned long long uint64;
#endif
typedef int8_t int8;
typedef uint8_t uint8;
typedef int16_t int16;
typedef uint16_t uint16;
typedef int32_t int32;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
typedef float float32;
typedef double float64;
@@ -207,7 +211,14 @@ inline int iSign(float f) {
return iSign((double)f);
}
inline double round(double f) {
return floor(f + 0.5f);
}
inline float round(float f) {
return floor(f + 0.5f);
}
/**
Fast round to integer using the lrint routine.
Typically 6x faster than casting to integer.
@@ -256,6 +267,11 @@ inline bool isNaN(int x) {
return false;
}
inline bool isNaN(uint64 x) {
(void)x;
return false;
}
/**
Computes x % 3.
*/
@@ -339,6 +355,7 @@ int highestBit(uint32 x);
*/
bool fuzzyEq(double a, double b);
/** True if a is definitely not equal to b.
Guaranteed false if a == b.
Possibly false when a != b.*/
@@ -393,6 +410,7 @@ inline double log2(int x) {
* True if num is a power of two.
*/
bool isPow2(int num);
bool isPow2(uint64 num);
bool isOdd(int num);
bool isEven(int num);
@@ -455,7 +473,7 @@ inline double rsqrt(double x) {
/** @deprecated Use rsq */
inline float rsqrt(float x) {
// TODO: default this to using the SSE2 instruction
return 1.0 / sqrtf(x);
return 1.0f / sqrtf(x);
}
/**
@@ -526,59 +544,59 @@ inline int iCeil (double fValue) {
inline int iClamp(int val, int low, int hi) {
debugAssert(low <= hi);
if (val <= low) {
return low;
} else if (val >= hi) {
return hi;
} else {
return val;
}
if (val <= low) {
return low;
} else if (val >= hi) {
return hi;
} else {
return val;
}
}
//----------------------------------------------------------------------------
inline int16 iClamp(int16 val, int16 low, int16 hi) {
debugAssert(low <= hi);
if (val <= low) {
return low;
} else if (val >= hi) {
return hi;
} else {
return val;
}
if (val <= low) {
return low;
} else if (val >= hi) {
return hi;
} else {
return val;
}
}
//----------------------------------------------------------------------------
inline double clamp(double val, double low, double hi) {
debugAssert(low <= hi);
if (val <= low) {
return low;
} else if (val >= hi) {
return hi;
} else {
return val;
}
if (val <= low) {
return low;
} else if (val >= hi) {
return hi;
} else {
return val;
}
}
inline float clamp(float val, float low, float hi) {
debugAssert(low <= hi);
if (val <= low) {
return low;
} else if (val >= hi) {
return hi;
} else {
return val;
}
if (val <= low) {
return low;
} else if (val >= hi) {
return hi;
} else {
return val;
}
}
//----------------------------------------------------------------------------
inline int iWrap(int val, int hi) {
if (val < 0) {
return ((val % hi) + hi) % hi;
} else {
return val % hi;
}
if (val < 0) {
return ((val % hi) + hi) % hi;
} else {
return val % hi;
}
}
//----------------------------------------------------------------------------
@@ -651,11 +669,11 @@ inline double aTan2 (double fY, double fX) {
inline double sign (double fValue) {
if (fValue > 0.0) {
return 1.0;
}
}
if (fValue < 0.0) {
return -1.0;
}
}
return 0.0;
}
@@ -663,11 +681,11 @@ inline double sign (double fValue) {
inline float sign (float fValue) {
if (fValue > 0.0f) {
return 1.0f;
}
}
if (fValue < 0.0f) {
return -1.0f;
}
}
return 0.0f;
}
@@ -759,6 +777,16 @@ inline bool isPow2(int num) {
return ((num & -num) == num);
}
inline bool isPow2(uint64 x) {
// See http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/, method #9
return ((x != 0) && !(x & (x - 1)));
}
inline bool isPow2(uint32 x) {
// See http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/, method #9
return ((x != 0) && !(x & (x - 1)));
}
inline bool isOdd(int num) {
return (num & 1) == 1;
}
@@ -801,12 +829,31 @@ inline double eps(double a, double b) {
(void)b;
const double aa = abs(a) + 1.0;
if (aa == inf()) {
return fuzzyEpsilon;
return fuzzyEpsilon64;
} else {
return fuzzyEpsilon * aa;
return fuzzyEpsilon64 * aa;
}
}
inline float eps(float a, float b) {
// For a and b to be nearly equal, they must have nearly
// the same magnitude. This means that we can ignore b
// since it either has the same magnitude or the comparison
// will fail anyway.
(void)b;
const float aa = (float)abs(a) + 1.0f;
if (aa == inf()) {
return fuzzyEpsilon32;
} else {
return fuzzyEpsilon32 * aa;
}
}
inline bool fuzzyEq(float a, float b) {
return (a == b) || (abs(a - b) <= eps(a, b));
}
inline bool fuzzyEq(double a, double b) {
return (a == b) || (abs(a - b) <= eps(a, b));
}
@@ -850,9 +897,47 @@ inline uint16 flipEndian16(const uint16 x) {
return (x << 8) | ((x & 0xFF00) >> 8);
}
/** The GLSL smoothstep function */
inline float smoothstep(float edge0, float edge1, float x) {
// Scale, bias and saturate x to 0..1 range
x = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
// Evaluate polynomial
return x * x * (3 - 2 * x);
}
/** Perlin's C2 continous variation on smoothstep() */
inline float smootherstep(float edge0, float edge1, float x) {
// Scale, and saturate x to 0..1 range
x = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
// Evaluate polynomial
return x * x * x * (x * (x * 6 - 15) + 10);
}
/** Computes |b|^e * sign(b) */
inline float signedPow(float b, float e) {
return sign(b) * powf(fabsf(b), e);
}
/** Computes |b|^e * sign(b) */
inline double signedPow(double b, double e) {
return sign(b) * pow(abs(b), e);
}
} // namespace
namespace std {
inline int pow(int a, int b) {
return (int)::pow(double(a), double(b));
}
}
#ifdef _MSC_VER
# pragma warning (pop)
#endif

View File

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

View File

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

View File

@@ -1,22 +1,26 @@
/**
@file platform.h
\file platform.h
\#defines for platform specific issues.
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2003-06-09
@edited 2010-08-11
Copyright 2000-2012, Morgan McGuire.
All rights reserved.
\created 2003-06-09
\edited 2013-01-03
*/
#ifndef G3D_platform_h
#define G3D_platform_h
/**
\def G3D_VER
The version number of G3D in the form: MmmBB ->
version M.mm [beta BB]
*/
#define G3D_VER 80100
#define G3D_VER 90000
// fatal error for unsupported architectures
#if defined(__powerpc__)
@@ -31,13 +35,15 @@
# undef _DEBUG
#endif
/** @def G3D_DEBUG()
/** \def G3D_DEBUG
Defined if G3D is built in debug mode. */
#if !defined(G3D_DEBUG) && (defined(_DEBUG) || defined(G3D_DEBUGRELEASE))
# define G3D_DEBUG
#endif
/** These control the version of Winsock used by G3D.
/**
\def G3D_WINSOCK_MAJOR_VERSION
These control the version of Winsock used by G3D.
Version 2.0 is standard for G3D 6.09 and later.
Version 1.1 is standard for G3D 6.08 and earlier.
*/
@@ -49,10 +55,15 @@
#define __fastcall
#endif
/** \def G3D_WINDOWS*/
/** \def G3D_FREEBSD2*/
/** \def G3D_LINUX*/
/** \def G3D_OSX */
#ifdef _MSC_VER
#define G3D_WIN32
# define G3D_WINDOWS
#elif defined(__MINGW32__)
#define G3D_WIN32
#define G3D_WINDOWS
#undef __MSVCRT_VERSION__
#define __MSVCRT_VERSION__ 0x0601
#include <windows.h>
@@ -61,8 +72,6 @@
#define G3D_LINUX
#elif defined(__linux__)
#define G3D_LINUX
#elif defined(__CYGWIN__)
#define G3D_LINUX
#elif defined(__APPLE__)
#define G3D_LINUX
@@ -70,25 +79,26 @@
// pi as a constant, which creates a conflict with G3D
#define __FP__
#else
#error Unknown platform
#error Unknown platform
#endif
/** \def G3D_64BIT */
/** \def G3D_32BIT */
/** Define the g++ thread-local syntax on all platforms (since the MSVC version would be hard to emulate with a macro) */
#if defined(_MSC_VER)
# define __thread __declspec(thread)
#endif
// Detect 64-bit under various compilers
#if (defined(_M_X64) || defined(_WIN64) || defined(__LP64__) || defined(_LP64))
# define G3D_64BIT
#if defined(WIN32)
#include <intrin.h>
#endif
#else
# define G3D_32BIT
#endif
// Strongly encourage inlining on gcc
#ifdef __GNUC__
#define inline __inline__
#endif
// Verify that the supported compilers are being used and that this is a known
// processor.
@@ -96,13 +106,14 @@
# ifndef __GNUC__
# error G3D only supports the gcc compiler on Linux.
# endif
# define G3D_NO_FFMPEG
#endif
#ifdef G3D_OSX
# ifndef __GNUC__
# error G3D only supports the gcc compiler on OS X.
# endif
# if defined(__i386__)
# define G3D_OSX_INTEL
# elif defined(__PPC__)
@@ -115,11 +126,13 @@
#ifdef _MSC_VER
// Microsoft Visual C++ 10.0 = 1600
// Microsoft Visual C++ 9.0 = 1500
// Microsoft Visual C++ 8.0 ("Express") = 1400
// Microsoft Visual C++ 7.1 ("2003") _MSC_VER = 1310
// Microsoft Visual C++ 7.0 ("2002") _MSC_VER = 1300
// Microsoft Visual C++ 6.0 _MSC_VER = 1200
// Microsoft Visual C++ 5.0 _MSC_VER = 1100
// Microsoft Visual C++ 7.1 ("2003") _MSC_VER = 1310
// Microsoft Visual C++ 7.0 ("2002") _MSC_VER = 1300
// Microsoft Visual C++ 6.0 _MSC_VER = 1200
// Microsoft Visual C++ 5.0 _MSC_VER = 1100
// Turn off warnings about deprecated C routines
# pragma warning (disable : 4996)
@@ -128,8 +141,16 @@
// for debug assertions in inlined methods.
# pragma warning (disable : 4127)
/** @def G3D_DEPRECATED()
Creates deprecated warning. */
/** \def G3D_DEPRECATED()
Creates deprecated warning at compile time when used.
Example:
\code
int G3D_DEPRECATED sum(int a, int b) {
return a + b;
}
\endcode
*/
# define G3D_DEPRECATED __declspec(deprecated)
// Prevent Winsock conflicts by hiding the winsock API
@@ -140,14 +161,12 @@
// Disable 'name too long for browse information' warning
# pragma warning (disable : 4786)
// TODO: remove
# pragma warning (disable : 4244)
# define restrict
/** @def G3D_CHECK_PRINTF_METHOD_ARGS()
Enables printf parameter validation on gcc. */
# define G3D_CHECK_PRINTF_ARGS
# define G3D_CHECK_PRINTF_ARGS
/** @def G3D_CHECK_PRINTF_METHOD_ARGS()
Enables printf parameter validation on gcc. */
@@ -173,50 +192,34 @@
// DLL runtime
#ifndef _DLL
#define _DLL
#define _DLL
#endif
// Multithreaded runtime
#ifndef _MT
#define _MT 1
#define _MT 1
#endif
// Ensure that we aren't forced into the static lib
#ifdef _STATIC_CPPLIB
#undef _STATIC_CPPLIB
#undef _STATIC_CPPLIB
#endif
#ifdef _DEBUG
#pragma comment (linker, "/NODEFAULTLIB:LIBCMTD.LIB")
#pragma comment (linker, "/NODEFAULTLIB:LIBCPMTD.LIB")
#pragma comment (linker, "/NODEFAULTLIB:LIBCPD.LIB")
#pragma comment (linker, "/DEFAULTLIB:MSVCPRTD.LIB")
#pragma comment(linker, "/NODEFAULTLIB:LIBCD.LIB")
#pragma comment(linker, "/DEFAULTLIB:MSVCRTD.LIB")
#else
#pragma comment(linker, "/NODEFAULTLIB:LIBC.LIB")
#pragma comment(linker, "/DEFAULTLIB:MSVCRT.LIB")
#pragma comment (linker, "/NODEFAULTLIB:LIBCMT.LIB")
#pragma comment (linker, "/NODEFAULTLIB:LIBCPMT.LIB")
#pragma comment(linker, "/NODEFAULTLIB:LIBCP.LIB")
#pragma comment (linker, "/DEFAULTLIB:MSVCPRT.LIB")
#endif
// Now set up external linking
# ifdef _DEBUG
// zlib was linked against the release MSVCRT; force
// the debug version.
# pragma comment(linker, "/NODEFAULTLIB:MSVCRT.LIB")
# endif
#ifdef _DEBUG
// Some of the support libraries are always built in Release.
// Make sure the debug runtime library is linked in
#pragma comment(linker, "/NODEFAULTLIB:MSVCRT.LIB")
#pragma comment(linker, "/NODEFAULTLIB:MSVCPRT.LIB")
#endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN 1
# endif
# define NOMINMAX 1
# ifndef NOMINMAX
# define NOMINMAX 1
# endif
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0500
# endif
@@ -230,8 +233,9 @@
# endif
/** @def G3D_START_AT_MAIN()
Defines necessary wrapper around WinMain on Windows to allow transfer of execution to main(). */
/** \def G3D_START_AT_MAIN()
Makes Windows programs using the WINDOWS subsystem invoke main() at program start by
defining a WinMain(). Does nothing on other operating systems.*/
# define G3D_START_AT_MAIN()\
int WINAPI G3D_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw);\
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\
@@ -269,7 +273,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\
# define __stdcall __attribute__((stdcall))
# endif
# elif defined(__x86_64__)
# elif defined(__x86_64__) || defined(__arm) || defined(__aarch64__)
# ifndef __cdecl
# define __cdecl
@@ -299,7 +303,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\
/**
@def STR(expression)
\def STR(expression)
Creates a string from the expression. Frequently used with G3D::Shader
to express shading programs inline.
@@ -319,26 +323,100 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\
# define PRAGMA(x) _Pragma(#x)
#endif
/** @def G3D_BEGIN_PACKED_CLASS(byteAlign)
Switch to tight alignment
/** \def G3D_BEGIN_PACKED_CLASS(byteAlign)
Switch to tight alignment.
\code
G3D_BEGIN_PACKED_CLASS(1)
ThreeBytes {
public:
uint8 a, b, c;
}
G3D_END_PACKED_CLASS(1)
\endcode
See G3D::Color3uint8 for an example.*/
#ifdef _MSC_VER
# define G3D_BEGIN_PACKED_CLASS(byteAlign) PRAGMA( pack(push, byteAlign) )
#ifdef __GNUC__
# define G3D_BEGIN_PACKED_CLASS(byteAlign) class __attribute((__packed__))
#elif defined(_MSC_VER)
# define G3D_BEGIN_PACKED_CLASS(byteAlign) PRAGMA( pack(push, byteAlign) ) class
#else
# define G3D_BEGIN_PACKED_CLASS(byteAlign)
# define G3D_BEGIN_PACKED_CLASS(byteAlign) class
#endif
/** @def G3D_END_PACKED_CLASS(byteAlign)
/** \def G3D_END_PACKED_CLASS(byteAlign)
End switch to tight alignment
See G3D::Color3uint8 for an example.*/
#ifdef _MSC_VER
# define G3D_END_PACKED_CLASS(byteAlign) ; PRAGMA( pack(pop) )
#elif defined(__GNUC__)
#ifdef __GNUC__
# define G3D_END_PACKED_CLASS(byteAlign) __attribute((aligned(byteAlign))) ;
#elif defined(_MSC_VER)
# define G3D_END_PACKED_CLASS(byteAlign) ; PRAGMA( pack(pop) )
#else
# define G3D_END_PACKED_CLASS(byteAlign) ;
#endif
// Header guard
// Bring in shared_ptr and weak_ptr
#if (defined(__GNUC__) && defined(__APPLE__)) || defined(__linux__)
#include <ciso646> // Defines _LIBCC_VERSION if linking against libc++ or does nothing
#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

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