* Reverted to the old G3D library, however collision still will not compile

* and is therefore commented out.

--HG--
branch : trunk
This commit is contained in:
Brian
2010-06-07 18:32:20 -06:00
parent 726a76e93a
commit 1fd7082712
223 changed files with 5783 additions and 42123 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ ACE (ADAPTIVE Communication Environment)
bzip2 (a freely available, patent free, high-quality data compressor)
http://www.bzip.org/
G3D (a commercial-grade C++ 3D engine available as Open Source (BSD License)
G3D 6.09 (a commercial-grade C++ 3D engine available as Open Source (BSD License)
http://g3d.sourceforge.net/
jemalloc (a general-purpose scalable concurrent malloc-implementation)
-589
View File
@@ -1,589 +0,0 @@
/**
@file Discovery.h
<H2>Discovery</H2>
Discovery is the process by which computers on a Local Area Network (LAN) find
one another. The Discovery API allows clients to make a list of servers running
the same application. The application typically presents this list to the user
so he can choose which server to connect to.
<P>
Features of the Discovery API:
<P>
Low network traffic
<BR> - Broadcasts mainly occur only when a new machine enters/leaves the network
<BR>Responsive
<BR> - Servers appear immediately after launching
<BR> - Servers disappear immedatiately after they shut down
<BR>Extensible
<BR> - Add your own game information (e.g. score, num players, map name)
<BR>Versioned
<BR> - Tracks incompatible servers so end-users know to upgrade their client/server
<H2>Using the Discovery API</H2>
Subclass DiscoveryAdvertisement to add fields describing a server running your
application. For a game, these might be the current map name and the number
of players.
<P>
On the client, create an instance of DiscoveryClient<your advertisement subclass>.
On the server, create an instance of DiscoveryServer and initialize it with an
instance of your advertisement subclass. From your main loop, call doNetwork()
on the client and server instances. When your server shuts down, invoke cleanup()
on it.
@maintainer Morgan McGuire, [email protected]
@created 2003-06-26
@edited 2008-11-24
*/
#ifndef G3D_DISCOVERY_H
#define G3D_DISCOVERY_H
#include "G3D/platform.h"
#include "G3D/G3DGameUnits.h"
#include "G3D/NetworkDevice.h"
#include "G3D/Log.h"
#include <time.h>
/**
Different versions of G3D discovery protocols can't communicate with each other.
*/
#define G3D_DISCOVERY_PROTOCOL_NAME "G3D DISC"
#define G3D_DISCOVERY_PROTOCOL_VERSION 1
namespace G3D {
/**
If a machine is running two different programs using discovery they
must have different ports. However different programs can share the
same ports if they run on the same LAN with different servers.
@deprecated See Discovery2::Settings
*/
class DiscoverySettings {
public:
/**
Name of the program using discovery; used so that mutliple
programs can use the same discovery ports on the same network.
*/
const char* appProtocolName;
/**
Version of the network protocol of the program using discovery.
Used so that discovery can identify incompatible versions of
the server.
*/
int appProtocolVersion;
/**
Port on which the server broadcasts its identity. The client
and server must agree on this value.
*/
uint16 serverBroadcastPort;
/**
Port on which the client broadcasts a server request. The client
and server must agree on this value.
*/
uint16 clientBroadcastPort;
/**
Clients connect into this port using a reliable conduit
to receive the advertisement from a server. The client
doesn't look at this value; it uses whatever the server
sends it.
*/
uint16 serverAdvertisementPort;
/**
You can use the default G3D discovery ports as long as no other
program with the same protocol name is using this port. You
<B>can</B> run two different G3D discovery programs on the same
two ports as long as they have different application protocol
strings.
*/
DiscoverySettings(
const char* _appProtocolName,
int _appProtocolVersion,
uint16 _serverBroadcast = 6173,
uint16 _clientBroadcast = 6174,
uint16 _serverAdvertisementPort = 6175) :
appProtocolName(_appProtocolName),
appProtocolVersion(_appProtocolVersion),
serverBroadcastPort(_serverBroadcast),
clientBroadcastPort(_clientBroadcast),
serverAdvertisementPort(_serverAdvertisementPort) {}
};
/**
Make your own subclass of this advertisement. Add fields
(e.g. numPlayers, currentScore) to increase the amount
of information advertised.
Overrides must provide a default constructor.
@deprecated See Discovery2::Settings
*/
class DiscoveryAdvertisement {
public:
/**
Address to connect to on the server for the actual game.
The IP portion is ignored (the client figures out the IP
address from the packet itself) but the port is essential.
Note that this port must not be the discovery port.
*/
NetAddress address;
/**
(Only used on the client)
Time since this advertisement was updated.
*/
RealTime lastUpdateTime;
/**
Overrides must call DiscoveryAdvertisement::serialize(b) first.
*/
virtual void serialize(BinaryOutput& b) const;
/**
Overrides must call DiscoveryAdvertisement::deserialize(b) first.
*/
virtual void deserialize(BinaryInput& b);
/**
An empty virtual destructor for virtual methods.
*/
virtual ~DiscoveryAdvertisement() {}
};
/**
Sent by servers to describe their location.
*/
class DiscoveryServerAddressMessage {
public:
/**
Not part of the message; these settings are used to determine
if the correct protocol is being used.
*/
const DiscoverySettings* settings;
/**
Set to true if this server is running the correct protocol.
*/
bool correctProtocol;
/**
This is set during the serialize process from the server's settings.
If different from the client's settings the discovery system will
classify this server as incompatible.
*/
int serverProtocolVersion[2];
Array<NetAddress> address;
DiscoveryServerAddressMessage() {}
DiscoveryServerAddressMessage(const DiscoverySettings* s) : settings(s) {}
void serialize(BinaryOutput& b) const;
void deserialize(BinaryInput& b);
};
/**
Base class for DiscoveryClient and DiscoveryServer.
*/
class Discovery {
public:
const DiscoverySettings* settings;
enum {
SERVER_SHUTDOWN_MESSAGE = 2,
SERVER_BROADCAST_MESSAGE = 3,
CLIENT_BROADCAST_MESSAGE = 4};
/**
Only called from subclasses.
*/
virtual void init(
const DiscoverySettings* _settings) {
settings = _settings;
}
/**
An empty virtual destructor for virtual methods.
*/
virtual ~Discovery() {}
};
/** @deprecated See Discovery2::Server*/
class DiscoveryServer : private Discovery {
private:
class ShutdownMessage {
public:
void serialize(BinaryOutput& b) const { (void)b; }
void deserialize(BinaryInput& b) { (void)b; }
};
/**
For broadcast.
*/
LightweightConduitRef net;
/**
Listen for clients wanting to hear the advertisement over
a reliable connection.
*/
NetListenerRef listener;
DiscoveryAdvertisement* advertisement;
/**
Broadcast across the lightweight conduit.
*/
DiscoveryServerAddressMessage addressMessage;
/**
Servers periodically broadcast (unsolicited) in case
anyone missed the previous message.
*/
RealTime lastBroadcast;
void sendAnnouncement() const;
void sendShutDown() const;
public:
/**
You may update the advertisement (synchronously with calling doNetwork)
after it has been passed in. This allows a server to change the advertised
number of players or score for a game, for example.
You must set the port of the @a _advertisement G3D::DiscoveryAdvertisement::address
to the port which the G3D::NetListener for the actual program protocol (not discovery)
is running. That field how the client knows what address to connect to using
G3D::ReliableConduit or G3D::LightweightConduit to actually initiate communication.
*/
virtual void init(
const DiscoverySettings* _settings,
DiscoveryAdvertisement* _advertisement);
/** Returns the broadcast address in use.*/
NetAddress broadcastAddress() const;
/**
Returns true if this discovery server has been initialized
and is functioning properly.
*/
bool ok() const;
/**
Call periodically to let the server do its job.
*/
void doNetwork();
/**
Broadcast a shutdown message.
*/
void cleanup();
};
/**
Used by DiscoveryClient to report servers running a different version
of this application's protocol.
*/
class IncompatibleServerDescription {
public:
NetAddress address;
int protocolVersion[2];
RealTime lastUpdateTime;
std::string toString() const;
};
/**
Only one DiscoveryClient can be active on a given port at a time on
a single computer.
AdType must be a subclass of DiscoveryAdvertisement.
@deprecated See Discovery2::Client
*/
template<class AdType>
class DiscoveryClient : private Discovery {
public:
/**
List of servers. Do not access on a second thread while in
doNetwork.
*/
Array<AdType> serverList;
/**
List of servers running the same application but a different protocol.
It is useful to show these to users to help them recognize version
conflicts between client and server.
Do not access on a second thread while in doNetwork.
*/
Array<IncompatibleServerDescription> incompatibleServerList;
private:
class BroadcastMessage {
public:
void serialize(BinaryOutput& b) const {}
void deserialize(BinaryInput& b) {}
};
/**
The client periodically checks servers to make sure they are still up
and to update its information about them.
*/
RealTime lastServerCheck;
LightweightConduitRef net;
/**
Returns an index in serverList of the server with the given address.
Returns -1 if there is none. Only checks IP addresses.
*/
int findServerListIndex(const NetAddress& addr) const {
for (int i = 0; i < serverList.size(); ++i) {
if (addr.ip() == serverList[i].address.ip()) {
return i;
}
}
return -1;
}
/**
Returns true if this discovery client has been initialized
and is functioning properly.
*/
bool ok() const {
return net->ok();
}
/**
Adds a server to the incompatible list if it is not already there.
*/
void addToIncompatibleList(const NetAddress& addr, uint32 p0, uint32 p1) {
const RealTime now = System::time();
bool alreadyHere = false;
// Incorrect protocol; add to the incompatible list
for (int i = 0; i < incompatibleServerList.size(); ++i) {
IncompatibleServerDescription& server = incompatibleServerList[i];
if (server.address == addr) {
server.lastUpdateTime = now;
alreadyHere = true;
break;
}
}
if (! alreadyHere) {
IncompatibleServerDescription server;
server.lastUpdateTime = now;
server.address = addr;
server.protocolVersion[0] = p0;
server.protocolVersion[1] = p1;
incompatibleServerList.append(server);
}
}
/**
Connects to the specified server, reads its advertisement,
and adds it to the active server list. Returns true if the server
can be reached.
*/
bool readAdvertisement(const NetAddress& address) {
std::string hostname = address.toString();
RealTime TIMEOUT = 2.0;
ReliableConduitRef server = ReliableConduit::create(address);
if (! server->ok()) {
return false;
}
AdType advertisement;
// Read the advertisement
RealTime stopWaiting = System::time() + TIMEOUT;
bool timedOut = false;
while (! server->messageWaiting() && ! timedOut && server->ok()) {
System::sleep(0.1);
timedOut = (System::time() > stopWaiting);
}
if (timedOut) {
Log::common()->printf("Discovery: Timed out while reading advertisment from %s\n",
hostname.c_str());
return false;
}
if (! server->ok()) {
Log::common()->printf("Discovery: Server %s dropped connection\n", hostname.c_str());
return false;
}
// Read the advertisement
debugAssert(server->messageWaiting());
if (! server->receive(advertisement)) {
Log::common()->printf("Discovery: Server %s failed to send advertisement\n", hostname.c_str());
return false;
}
// Update existing server info or create a new entry
int index = findServerListIndex(address);
if (index == -1) {
index = serverList.size();
serverList.resize(index + 1);
}
// Update element index
advertisement.address = address;
serverList[index] = advertisement;
return true;
}
/**
Remove this address from our list if we previously
had a server there.
*/
void removeServer(const NetAddress& address) {
int index = findServerListIndex(address);
if (index > -1) {
serverList.fastRemove(index);
}
}
/**
Tries to connect to the server through the addresses in the array.
*/
void addToServerList(const Array<NetAddress>& addressArray) {
// Try to connect to each address listed
for (int a = addressArray.size() - 1; a >= 0; --a) {
const NetAddress& address = addressArray[a];
if (readAdvertisement(address)) {
// We've connected to the server
break;
} else {
removeServer(address);
}
}
}
void checkRandomServer() {
if (serverList.size() >= 1) {
int index = iRandom(0, serverList.size() - 1);
Array<NetAddress> address;
address.append(serverList[index].address);
// Remove this server
serverList.fastRemove(index);
// Add it back with new info (or leave it removed if no response)
addToServerList(address);
}
}
public:
void init(
const DiscoverySettings* _settings) {
Discovery::init(_settings);
lastServerCheck = System::time();
net = LightweightConduit::create(settings->serverBroadcastPort, true, true);
// Send announcement
NetAddress broadcast(NetworkDevice::instance()->broadcastAddressArray()[0],
settings->clientBroadcastPort);
BroadcastMessage tmp;
net->send(broadcast, CLIENT_BROADCAST_MESSAGE, tmp);
}
/** Shut down the discovery client. */
void cleanup() {
net = NULL;
}
/**
Call this regularly (several times per second) to
update the server list. Not threadsafe-- you must not touch
the server list while this is running. This will not block.
*/
void doNetwork() {
if (net->messageWaiting()) {
NetAddress sender;
switch (net->waitingMessageType()) {
case SERVER_SHUTDOWN_MESSAGE:
// Remove the server
net->receive(sender);
removeServer(sender);
break;
case SERVER_BROADCAST_MESSAGE:
// Check the G3D protocol and the network protocol, then read the ad
DiscoveryServerAddressMessage msg(settings);
net->receive(sender, msg);
if (msg.correctProtocol && (msg.address.size() > 0)) {
// Add the actual return address as the first one to be tried.
msg.address.append(NetAddress(sender.ip(), msg.address[0].port()));
addToServerList(msg.address);
} else {
addToIncompatibleList(
sender,
msg.serverProtocolVersion[0],
msg.serverProtocolVersion[1]);
}
break;
}
}
// Periodically re-check servers in the list to see if they crashed
// (if they shut down, they should have broadcast a shut down message).
RealTime now = System::time();
const RealTime UPDATE_TIME_INTERVAL = 30;
if (now > lastServerCheck + UPDATE_TIME_INTERVAL) {
lastServerCheck = now;
checkRandomServer();
}
}
};
}
#endif
-342
View File
@@ -1,342 +0,0 @@
/**
@file AABox.cpp
@maintainer Morgan McGuire, [email protected]
@created 2004-01-10
@edited 2006-01-11
*/
#include "G3D/platform.h"
#include "G3D/AABox.h"
#include "G3D/Box.h"
#include "G3D/Plane.h"
#include "G3D/Sphere.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
namespace G3D {
void AABox::serialize(class BinaryOutput& b) const {
b.writeVector3(lo);
b.writeVector3(hi);
}
void AABox::deserialize(class BinaryInput& b) {
lo = b.readVector3();
hi = b.readVector3();
}
void AABox::split(const Vector3::Axis& axis, float location, AABox& low, AABox& high) const {
// Low, medium, and high along the chosen axis
float L = G3D::min(location, lo[axis]);
float M = G3D::min(G3D::max(location, lo[axis]), hi[axis]);
float H = G3D::max(location, hi[axis]);
// Copy over this box.
high = low = *this;
// Now move the split points along the special axis
low.lo[axis] = L;
low.hi[axis] = M;
high.lo[axis] = M;
high.hi[axis] = H;
}
Vector3 AABox::randomSurfacePoint() const {
Vector3 extent = hi - lo;
float aXY = extent.x * extent.y;
float aYZ = extent.y * extent.z;
float aZX = extent.z * extent.x;
float r = (float)uniformRandom(0.0f, aXY + aYZ + aZX);
// Choose evenly between positive and negative face planes
float d = ((float)uniformRandom(0, 1) < 0.5f) ? 0.0f : 1.0f;
// The probability of choosing a given face is proportional to
// its area.
if (r < aXY) {
return
lo +
Vector3(
(float)uniformRandom(0.0f, extent.x),
(float)uniformRandom(0.0f, extent.y),
d * extent.z);
} else if (r < aYZ) {
return
lo +
Vector3(
d * extent.x,
(float)uniformRandom(0, extent.y),
(float)uniformRandom(0, extent.z));
} else {
return
lo +
Vector3(
(float)uniformRandom(0, extent.x),
d * extent.y,
(float)uniformRandom(0, extent.z));
}
}
Vector3 AABox::randomInteriorPoint() const {
return Vector3(
(float)uniformRandom(lo.x, hi.x),
(float)uniformRandom(lo.y, hi.y),
(float)uniformRandom(lo.z, hi.z));
}
bool AABox::intersects(const AABox& other) const {
// Must be overlap along all three axes.
// Try to find a separating axis.
for (int a = 0; a < 3; ++a) {
// |--------|
// |------|
if ((lo[a] > other.hi[a]) ||
(hi[a] < other.lo[a])) {
return false;
}
}
return true;
}
int AABox::dummy = 0;
bool AABox::culledBy(
const Array<Plane>& plane,
int& cullingPlane,
const uint32 _inMask,
uint32& childMask) const {
uint32 inMask = _inMask;
assert(plane.size() < 31);
childMask = 0;
const bool finite =
(abs(lo.x) < G3D::inf()) &&
(abs(hi.x) < G3D::inf()) &&
(abs(lo.y) < G3D::inf()) &&
(abs(hi.y) < G3D::inf()) &&
(abs(lo.z) < G3D::inf()) &&
(abs(hi.z) < G3D::inf());
// See if there is one plane for which all of the
// vertices are in the negative half space.
for (int p = 0; p < plane.size(); ++p) {
// Only test planes that are not masked
if ((inMask & 1) != 0) {
Vector3 corner;
int numContained = 0;
int v = 0;
// We can early-out only if we have found one point on each
// side of the plane (i.e. if we are straddling). That
// occurs when (numContained < v) && (numContained > 0)
for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) {
// Unrolling these 3 if's into a switch decreases performance
// by about 2x
corner.x = (v & 1) ? hi.x : lo.x;
corner.y = (v & 2) ? hi.y : lo.y;
corner.z = (v & 4) ? hi.z : lo.z;
if (finite) { // this branch is highly predictable
if (plane[p].halfSpaceContainsFinite(corner)) {
++numContained;
}
} else {
if (plane[p].halfSpaceContains(corner)) {
++numContained;
}
}
}
if (numContained == 0) {
// Plane p culled the box
cullingPlane = p;
// The caller should not recurse into the children,
// since the parent is culled. If they do recurse,
// make them only test against this one plane, which
// will immediately cull the volume.
childMask = 1 << p;
return true;
} else if (numContained < v) {
// The bounding volume straddled the plane; we have
// to keep testing against this plane
childMask |= (1 << p);
}
}
// Move on to the next bit.
inMask = inMask >> 1;
}
// None of the planes could cull this box
cullingPlane = -1;
return false;
}
bool AABox::culledBy(
const Array<Plane>& plane,
int& cullingPlane,
const uint32 _inMask) const {
uint32 inMask = _inMask;
assert(plane.size() < 31);
const bool finite =
(abs(lo.x) < G3D::inf()) &&
(abs(hi.x) < G3D::inf()) &&
(abs(lo.y) < G3D::inf()) &&
(abs(hi.y) < G3D::inf()) &&
(abs(lo.z) < G3D::inf()) &&
(abs(hi.z) < G3D::inf());
// See if there is one plane for which all of the
// vertices are in the negative half space.
for (int p = 0; p < plane.size(); ++p) {
// Only test planes that are not masked
if ((inMask & 1) != 0) {
bool culled = true;
Vector3 corner;
int v;
// Assume this plane culls all points. See if there is a point
// not culled by the plane... early out when at least one point
// is in the positive half space.
for (v = 0; (v < 8) && culled; ++v) {
// Unrolling these 3 if's into a switch decreases performance
// by about 2x
corner.x = (v & 1) ? hi.x : lo.x;
corner.y = (v & 2) ? hi.y : lo.y;
corner.z = (v & 4) ? hi.z : lo.z;
if (finite) { // this branch is highly predictable
culled = ! plane[p].halfSpaceContainsFinite(corner);
} else {
culled = ! plane[p].halfSpaceContains(corner);
}
}
if (culled) {
// Plane p culled the box
cullingPlane = p;
return true;
}
}
// Move on to the next bit.
inMask = inMask >> 1;
}
// None of the planes could cull this box
cullingPlane = -1;
return false;
}
bool AABox::intersects(const class Sphere& sphere) const {
double d = 0;
//find the square of the distance
//from the sphere to the box
for (int i = 0; i < 3; ++i) {
if (sphere.center[i] < lo[i]) {
d += square(sphere.center[i] - lo[i]);
} else if (sphere.center[i] > hi[i]) {
d += square(sphere.center[i] - hi[i]);
}
}
return d <= square(sphere.radius);
}
Vector3 AABox::corner(int index) const {
// default constructor inits all components to 0
Vector3 v;
switch (index)
{
case 0:
v.x = lo.x;
v.y = lo.y;
v.z = hi.z;
break;
case 1:
v.x = hi.x;
v.y = lo.y;
v.z = hi.z;
break;
case 2:
v.x = hi.x;
v.y = hi.y;
v.z = hi.z;
break;
case 3:
v.x = lo.x;
v.y = hi.y;
v.z = hi.z;
break;
case 4:
v.x = lo.x;
v.y = lo.y;
v.z = lo.z;
break;
case 5:
v.x = hi.x;
v.y = lo.y;
v.z = lo.z;
break;
case 6:
v.x = hi.x;
v.y = hi.y;
v.z = lo.z;
break;
case 7:
v.x = lo.x;
v.y = hi.y;
v.z = lo.z;
break;
default:
debugAssertM(false, "Invalid corner index");
break;
}
return v;
}
}
File diff suppressed because it is too large Load Diff
-81
View File
@@ -1,81 +0,0 @@
/**
@file BinaryFormat.cpp
@maintainer Morgan McGuire, [email protected]
@created 2005-06-10
@edited 2005-06-10
*/
#include "G3D/BinaryFormat.h"
namespace G3D {
int32 byteSize(BinaryFormat f) {
switch (f) {
case BOOL8_BINFMT:
case UINT8_BINFMT:
case INT8_BINFMT:
return 1;
case UINT16_BINFMT:
case INT16_BINFMT:
return 2;
case FLOAT16_BINFMT:
return 2;
case UINT32_BINFMT:
case INT32_BINFMT:
case FLOAT32_BINFMT:
return 4;
case FLOAT64_BINFMT:
case UINT64_BINFMT:
case INT64_BINFMT:
return 8;
case INT128_BINFMT:
case UINT128_BINFMT:
return 16;
case VECTOR2_BINFMT:
return 2 * 4;
case VECTOR2INT16_BINFMT:
return 2 * 2;
case VECTOR3_BINFMT:
return 3 * 4;
case VECTOR3INT16_BINFMT:
return 3 * 2;
case VECTOR4_BINFMT:
return 4 * 4;
case VECTOR4INT16_BINFMT:
return 4 * 4;
case COLOR3_BINFMT:
return 3 * 4;
case COLOR3UINT8_BINFMT:
return 3 * 1;
case COLOR3INT16_BINFMT:
return 3 * 2;
case COLOR4_BINFMT:
return 4 * 4;
case COLOR4UINT8_BINFMT:
return 4 * 1;
case COLOR4INT16_BINFMT:
return 4 * 2;
default:
return -1;
}
}
}
-568
View File
@@ -1,568 +0,0 @@
/**
@file BinaryInput.cpp
@author Morgan McGuire, graphics3d.com
Copyright 2001-2007, Morgan McGuire. All rights reserved.
@created 2001-08-09
@edited 2005-02-24
<PRE>
{
BinaryOutput b("c:/tmp/test.b", BinaryOutput::LITTLE_ENDIAN);
float f = 3.1415926;
int i = 1027221;
std::string s = "Hello World!";
b.writeFloat32(f);
b.writeInt32(i);
b.writeString(s);
b.commit();
BinaryInput in("c:/tmp/test.b", BinaryInput::LITTLE_ENDIAN);
debugAssert(f == in.readFloat32());
int ii = in.readInt32();
debugAssert(i == ii);
debugAssert(s == in.readString());
}
</PRE>
*/
#include "G3D/platform.h"
#include "G3D/BinaryInput.h"
#include "G3D/Array.h"
#include "G3D/fileutils.h"
#include "G3D/Log.h"
#include <zlib.h>
#include <cstring>
namespace G3D {
void BinaryInput::readBool8(std::vector<bool>& out, int64 n) {
out.resize((int)n);
// std::vector optimizes bool in a way that prevents fast reading
for (int64 i = 0; i < n ; ++i) {
out[i] = readBool8();
}
}
void BinaryInput::readBool8(Array<bool>& out, int64 n) {
out.resize(n);
readBool8(out.begin(), n);
}
#define IMPLEMENT_READER(ucase, lcase)\
void BinaryInput::read##ucase(std::vector<lcase>& out, int64 n) {\
out.resize(n);\
read##ucase(&out[0], n);\
}\
\
\
void BinaryInput::read##ucase(Array<lcase>& out, int64 n) {\
out.resize(n);\
read##ucase(out.begin(), n);\
}
IMPLEMENT_READER(UInt8, uint8)
IMPLEMENT_READER(Int8, int8)
IMPLEMENT_READER(UInt16, uint16)
IMPLEMENT_READER(Int16, int16)
IMPLEMENT_READER(UInt32, uint32)
IMPLEMENT_READER(Int32, int32)
IMPLEMENT_READER(UInt64, uint64)
IMPLEMENT_READER(Int64, int64)
IMPLEMENT_READER(Float32, float32)
IMPLEMENT_READER(Float64, float64)
#undef IMPLEMENT_READER
// Data structures that are one byte per element can be
// directly copied, regardles of endian-ness.
#define IMPLEMENT_READER(ucase, lcase)\
void BinaryInput::read##ucase(lcase* out, int64 n) {\
if (sizeof(lcase) == 1) {\
readBytes(out, n);\
} else {\
for (int64 i = 0; i < n ; ++i) {\
out[i] = read##ucase();\
}\
}\
}
IMPLEMENT_READER(Bool8, bool)
IMPLEMENT_READER(UInt8, uint8)
IMPLEMENT_READER(Int8, int8)
#undef IMPLEMENT_READER
#define IMPLEMENT_READER(ucase, lcase)\
void BinaryInput::read##ucase(lcase* out, int64 n) {\
if (m_swapBytes) {\
for (int64 i = 0; i < n; ++i) {\
out[i] = read##ucase();\
}\
} else {\
readBytes(out, sizeof(lcase) * n);\
}\
}
IMPLEMENT_READER(UInt16, uint16)
IMPLEMENT_READER(Int16, int16)
IMPLEMENT_READER(UInt32, uint32)
IMPLEMENT_READER(Int32, int32)
IMPLEMENT_READER(UInt64, uint64)
IMPLEMENT_READER(Int64, int64)
IMPLEMENT_READER(Float32, float32)
IMPLEMENT_READER(Float64, float64)
#undef IMPLEMENT_READER
void BinaryInput::loadIntoMemory(int64 startPosition, int64 minLength) {
// Load the next section of the file
debugAssertM(m_filename != "<memory>", "Read past end of file.");
int64 absPos = m_alreadyRead + m_pos;
if (m_bufferLength < minLength) {
// The current buffer isn't big enough to hold the chunk we want to read.
// This happens if there was little memory available during the initial constructor
// read but more memory has since been freed.
m_bufferLength = minLength;
debugAssert(m_freeBuffer);
m_buffer = (uint8*)System::realloc(m_buffer, m_bufferLength);
if (m_buffer == NULL) {
throw "Tried to read a larger memory chunk than could fit in memory. (2)";
}
}
m_alreadyRead = startPosition;
# ifdef G3D_WIN32
FILE* file = fopen(m_filename.c_str(), "rb");
debugAssert(file);
int ret = fseek(file, (off_t)m_alreadyRead, SEEK_SET);
debugAssert(ret == 0);
size_t toRead = (size_t)G3D::min(m_bufferLength, m_length - m_alreadyRead);
ret = fread(m_buffer, 1, toRead, file);
debugAssert(ret == toRead);
fclose(file);
file = NULL;
# else
FILE* file = fopen(m_filename.c_str(), "rb");
debugAssert(file);
int ret = fseeko(file, (off_t)m_alreadyRead, SEEK_SET);
debugAssert(ret == 0);
size_t toRead = (size_t)G3D::min<int64>(m_bufferLength, m_length - m_alreadyRead);
ret = fread(m_buffer, 1, toRead, file);
debugAssert((size_t)ret == (size_t)toRead);
fclose(file);
file = NULL;
# endif
m_pos = absPos - m_alreadyRead;
debugAssert(m_pos >= 0);
}
const bool BinaryInput::NO_COPY = false;
static bool needSwapBytes(G3DEndian fileEndian) {
return (fileEndian != System::machineEndian());
}
/** Helper used by the constructors for decompression */
static uint32 readUInt32(const uint8* data, bool swapBytes) {
if (swapBytes) {
uint8 out[4];
out[0] = data[3];
out[1] = data[2];
out[2] = data[1];
out[3] = data[0];
return *((uint32*)out);
} else {
return *((uint32*)data);
}
}
void BinaryInput::setEndian(G3DEndian e) {
m_fileEndian = e;
m_swapBytes = needSwapBytes(m_fileEndian);
}
BinaryInput::BinaryInput(
const uint8* data,
int64 dataLen,
G3DEndian dataEndian,
bool compressed,
bool copyMemory) :
m_filename("<memory>"),
m_bitPos(0),
m_bitString(0),
m_beginEndBits(0),
m_alreadyRead(0),
m_bufferLength(0),
m_pos(0) {
m_freeBuffer = copyMemory || compressed;
setEndian(dataEndian);
if (compressed) {
// Read the decompressed size from the first 4 bytes
m_length = G3D::readUInt32(data, m_swapBytes);
debugAssert(m_freeBuffer);
m_buffer = (uint8*)System::alignedMalloc(m_length, 16);
unsigned long L = m_length;
// Decompress with zlib
int64 result = uncompress(m_buffer, (unsigned long*)&L, data + 4, dataLen - 4);
m_length = L;
m_bufferLength = L;
debugAssert(result == Z_OK); (void)result;
} else {
m_length = dataLen;
m_bufferLength = m_length;
if (! copyMemory) {
debugAssert(!m_freeBuffer);
m_buffer = const_cast<uint8*>(data);
} else {
debugAssert(m_freeBuffer);
m_buffer = (uint8*)System::alignedMalloc(m_length, 16);
System::memcpy(m_buffer, data, dataLen);
}
}
}
BinaryInput::BinaryInput(
const std::string& filename,
G3DEndian fileEndian,
bool compressed) :
m_filename(filename),
m_bitPos(0),
m_bitString(0),
m_beginEndBits(0),
m_alreadyRead(0),
m_length(0),
m_bufferLength(0),
m_buffer(NULL),
m_pos(0),
m_freeBuffer(true) {
setEndian(fileEndian);
// Update global file tracker
_internal::currentFilesUsed.insert(m_filename);
if (! fileExists(m_filename, false)) {
std::string zipfile;
std::string internalfile;
if (zipfileExists(m_filename, zipfile, internalfile)) {
// Load from zipfile
void* v;
size_t s;
zipRead(filename, v, s);
m_buffer = reinterpret_cast<uint8*>(v);
m_bufferLength = m_length = s;
if (compressed) {
decompress();
}
m_freeBuffer = true;
} else {
Log::common()->printf("Warning: File not found: %s\n", m_filename.c_str());
}
return;
}
// Figure out how big the file is and verify that it exists.
m_length = fileLength(m_filename);
// Read the file into memory
FILE* file = fopen(m_filename.c_str(), "rb");
if (! file || (m_length == -1)) {
throw format("File not found: \"%s\"", m_filename.c_str());
return;
}
if (! compressed && (m_length > INITIAL_BUFFER_LENGTH)) {
// Read only a subset of the file so we don't consume
// all available memory.
m_bufferLength = INITIAL_BUFFER_LENGTH;
} else {
// Either the length is fine or the file is compressed
// and requires us to read the whole thing for zlib.
m_bufferLength = m_length;
}
debugAssert(m_freeBuffer);
m_buffer = (uint8*)System::alignedMalloc(m_bufferLength, 16);
if (m_buffer == NULL) {
if (compressed) {
throw "Not enough memory to load compressed file. (1)";
}
// Try to allocate a small array; not much memory is available.
// Give up if we can't allocate even 1k.
while ((m_buffer == NULL) && (m_bufferLength > 1024)) {
m_bufferLength /= 2;
m_buffer = (uint8*)System::alignedMalloc(m_bufferLength, 16);
}
}
debugAssert(m_buffer);
fread(m_buffer, m_bufferLength, sizeof(int8), file);
fclose(file);
file = NULL;
if (compressed) {
if (m_bufferLength != m_length) {
throw "Not enough memory to load compressed file. (2)";
}
decompress();
}
}
void BinaryInput::decompress() {
// Decompress
// Use the existing buffer as the source, allocate
// a new buffer to use as the destination.
int64 tempLength = m_length;
m_length = G3D::readUInt32(m_buffer, m_swapBytes);
// The file couldn't have better than 500:1 compression
alwaysAssertM(m_length < m_bufferLength * 500, "Compressed file header is corrupted");
uint8* tempBuffer = m_buffer;
m_buffer = (uint8*)System::alignedMalloc(m_length, 16);
debugAssert(m_buffer);
debugAssert(isValidHeapPointer(tempBuffer));
debugAssert(isValidHeapPointer(m_buffer));
unsigned long L = m_length;
int64 result = uncompress(m_buffer, &L, tempBuffer + 4, tempLength - 4);
m_length = L;
m_bufferLength = m_length;
debugAssertM(result == Z_OK, "BinaryInput/zlib detected corruption in " + m_filename);
(void)result;
System::alignedFree(tempBuffer);
}
void BinaryInput::readBytes(void* bytes, int64 n) {
prepareToRead(n);
debugAssert(isValidPointer(bytes));
memcpy(bytes, m_buffer + m_pos, n);
m_pos += n;
}
BinaryInput::~BinaryInput() {
if (m_freeBuffer) {
System::alignedFree(m_buffer);
}
m_buffer = NULL;
}
uint64 BinaryInput::readUInt64() {
prepareToRead(8);
uint8 out[8];
if (m_swapBytes) {
out[0] = m_buffer[m_pos + 7];
out[1] = m_buffer[m_pos + 6];
out[2] = m_buffer[m_pos + 5];
out[3] = m_buffer[m_pos + 4];
out[4] = m_buffer[m_pos + 3];
out[5] = m_buffer[m_pos + 2];
out[6] = m_buffer[m_pos + 1];
out[7] = m_buffer[m_pos + 0];
} else {
*(uint64*)out = *(uint64*)(m_buffer + m_pos);
}
m_pos += 8;
return *(uint64*)out;
}
std::string BinaryInput::readString(int64 n) {
prepareToRead(n);
debugAssertM((m_pos + n) <= m_length, "Read past end of file");
char *s = (char*)System::alignedMalloc(n + 1, 16);
assert(s != NULL);
memcpy(s, m_buffer + m_pos, n);
// There may not be a null, so make sure
// we add one.
s[n] = '\0';
std::string out = s;
System::alignedFree(s);
s = NULL;
m_pos += n;
return out;
}
std::string BinaryInput::readString() {
int64 n = 0;
if ((m_pos + m_alreadyRead + n) < (m_length - 1)) {
prepareToRead(1);
}
if ( ((m_pos + m_alreadyRead + n) < (m_length - 1)) &&
(m_buffer[m_pos + n] != '\0')) {
++n;
while ( ((m_pos + m_alreadyRead + n) < (m_length - 1)) &&
(m_buffer[m_pos + n] != '\0')) {
prepareToRead(1);
++n;
}
}
// Consume NULL
++n;
return readString(n);
}
std::string BinaryInput::readStringEven() {
std::string x = readString();
if (hasMore() && (G3D::isOdd(x.length() + 1))) {
skip(1);
}
return x;
}
std::string BinaryInput::readString32() {
int len = readUInt32();
return readString(len);
}
Vector4 BinaryInput::readVector4() {
float x = readFloat32();
float y = readFloat32();
float z = readFloat32();
float w = readFloat32();
return Vector4(x, y, z, w);
}
Vector3 BinaryInput::readVector3() {
float x = readFloat32();
float y = readFloat32();
float z = readFloat32();
return Vector3(x, y, z);
}
Vector2 BinaryInput::readVector2() {
float x = readFloat32();
float y = readFloat32();
return Vector2(x, y);
}
Color4 BinaryInput::readColor4() {
float r = readFloat32();
float g = readFloat32();
float b = readFloat32();
float a = readFloat32();
return Color4(r, g, b, a);
}
Color3 BinaryInput::readColor3() {
float r = readFloat32();
float g = readFloat32();
float b = readFloat32();
return Color3(r, g, b);
}
void BinaryInput::beginBits() {
debugAssert(m_beginEndBits == 0);
m_beginEndBits = 1;
m_bitPos = 0;
debugAssertM(hasMore(), "Can't call beginBits when at the end of a file");
m_bitString = readUInt8();
}
uint32 BinaryInput::readBits(int numBits) {
debugAssert(m_beginEndBits == 1);
uint32 out = 0;
const int total = numBits;
while (numBits > 0) {
if (m_bitPos > 7) {
// Consume a new byte for reading. We do this at the beginning
// of the loop so that we don't try to read past the end of the file.
m_bitPos = 0;
m_bitString = readUInt8();
}
// Slide the lowest bit of the bitString into
// the correct position.
out |= (m_bitString & 1) << (total - numBits);
// Shift over to the next bit
m_bitString = m_bitString >> 1;
++m_bitPos;
--numBits;
}
return out;
}
void BinaryInput::endBits() {
debugAssert(m_beginEndBits == 1);
if (m_bitPos == 0) {
// Put back the last byte we read
--m_pos;
}
m_beginEndBits = 0;
m_bitPos = 0;
}
}
-518
View File
@@ -1,518 +0,0 @@
/**
@file BinaryOutput.cpp
@author Morgan McGuire, graphics3d.com
Copyright 2002-2007, Morgan McGuire, All rights reserved.
@created 2002-02-20
@edited 2008-01-07
*/
#include "G3D/platform.h"
#include "G3D/BinaryOutput.h"
#include "G3D/fileutils.h"
#include "G3D/stringutils.h"
#include "G3D/Array.h"
#include <zlib.h>
#include <cstring>
// Largest memory buffer that the system will use for writing to
// disk. After this (or if the system runs out of memory)
// chunks of the file will be dumped to disk.
//
// Currently 400 MB
#define MAX_BINARYOUTPUT_BUFFER_SIZE 400000000
namespace G3D {
void BinaryOutput::writeBool8(const std::vector<bool>& out, int n) {
for (int i = 0; i < n; ++i) {
writeBool8(out[i]);
}
}
void BinaryOutput::writeBool8(const Array<bool>& out, int n) {
writeBool8(out.getCArray(), n);
}
#define IMPLEMENT_WRITER(ucase, lcase)\
void BinaryOutput::write##ucase(const std::vector<lcase>& out, int n) {\
write##ucase(&out[0], n);\
}\
\
\
void BinaryOutput::write##ucase(const Array<lcase>& out, int n) {\
write##ucase(out.getCArray(), n);\
}
IMPLEMENT_WRITER(UInt8, uint8)
IMPLEMENT_WRITER(Int8, int8)
IMPLEMENT_WRITER(UInt16, uint16)
IMPLEMENT_WRITER(Int16, int16)
IMPLEMENT_WRITER(UInt32, uint32)
IMPLEMENT_WRITER(Int32, int32)
IMPLEMENT_WRITER(UInt64, uint64)
IMPLEMENT_WRITER(Int64, int64)
IMPLEMENT_WRITER(Float32, float32)
IMPLEMENT_WRITER(Float64, float64)
#undef IMPLEMENT_WRITER
// Data structures that are one byte per element can be
// directly copied, regardles of endian-ness.
#define IMPLEMENT_WRITER(ucase, lcase)\
void BinaryOutput::write##ucase(const lcase* out, int n) {\
if (sizeof(lcase) == 1) {\
writeBytes((void*)out, n);\
} else {\
for (int i = 0; i < n ; ++i) {\
write##ucase(out[i]);\
}\
}\
}
IMPLEMENT_WRITER(Bool8, bool)
IMPLEMENT_WRITER(UInt8, uint8)
IMPLEMENT_WRITER(Int8, int8)
#undef IMPLEMENT_WRITER
#define IMPLEMENT_WRITER(ucase, lcase)\
void BinaryOutput::write##ucase(const lcase* out, int n) {\
if (m_swapBytes) {\
for (int i = 0; i < n; ++i) {\
write##ucase(out[i]);\
}\
} else {\
writeBytes((const void*)out, sizeof(lcase) * n);\
}\
}
IMPLEMENT_WRITER(UInt16, uint16)
IMPLEMENT_WRITER(Int16, int16)
IMPLEMENT_WRITER(UInt32, uint32)
IMPLEMENT_WRITER(Int32, int32)
IMPLEMENT_WRITER(UInt64, uint64)
IMPLEMENT_WRITER(Int64, int64)
IMPLEMENT_WRITER(Float32, float32)
IMPLEMENT_WRITER(Float64, float64)
#undef IMPLEMENT_WRITER
void BinaryOutput::reallocBuffer(size_t bytes, size_t oldBufferLen) {
//debugPrintf("reallocBuffer(%d, %d)\n", bytes, oldBufferLen);
size_t newBufferLen = (int)(m_bufferLen * 1.5) + 100;
uint8* newBuffer = NULL;
if ((m_filename == "<memory>") || (newBufferLen < MAX_BINARYOUTPUT_BUFFER_SIZE)) {
// We're either writing to memory (in which case we *have* to try and allocate)
// or we've been asked to allocate a reasonable size buffer.
//debugPrintf(" realloc(%d)\n", newBufferLen);
newBuffer = (uint8*)System::realloc(m_buffer, newBufferLen);
if (newBuffer != NULL) {
m_maxBufferLen = newBufferLen;
}
}
if ((newBuffer == NULL) && (bytes > 0)) {
// Realloc failed; we're probably out of memory. Back out
// the entire call and try to dump some data to disk.
m_bufferLen = oldBufferLen;
reserveBytesWhenOutOfMemory(bytes);
} else {
m_buffer = newBuffer;
debugAssert(isValidHeapPointer(m_buffer));
}
}
void BinaryOutput::reserveBytesWhenOutOfMemory(size_t bytes) {
if (m_filename == "<memory>") {
throw "Out of memory while writing to memory in BinaryOutput (no RAM left).";
} else if ((int)bytes > (int)m_maxBufferLen) {
throw "Out of memory while writing to disk in BinaryOutput (could not create a large enough buffer).";
} else {
// Dump the contents to disk. In order to enable seeking backwards,
// we keep the last 10 MB in memory.
int writeBytes = m_bufferLen - 10 * 1024 * 1024;
if (writeBytes < m_bufferLen / 3) {
// We're going to write less than 1/3 of the file;
// give up and just write the whole thing.
writeBytes = m_bufferLen;
}
debugAssert(writeBytes > 0);
//debugPrintf("Writing %d bytes to disk\n", writeBytes);
const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb";
FILE* file = fopen(m_filename.c_str(), mode);
debugAssert(file);
size_t count = fwrite(m_buffer, 1, writeBytes, file);
debugAssert((int)count == writeBytes); (void)count;
fclose(file);
file = NULL;
// Record that we saved this data.
m_alreadyWritten += writeBytes;
m_bufferLen -= writeBytes;
m_pos -= writeBytes;
debugAssert(m_bufferLen < m_maxBufferLen);
debugAssert(m_bufferLen >= 0);
debugAssert(m_pos >= 0);
debugAssert(m_pos <= m_bufferLen);
// Shift the unwritten data back appropriately in the buffer.
debugAssert(isValidHeapPointer(m_buffer));
System::memcpy(m_buffer, m_buffer + writeBytes, m_bufferLen);
debugAssert(isValidHeapPointer(m_buffer));
// *now* we allocate bytes (there should presumably be enough
// space in the buffer; if not, we'll come back through this
// code and dump the last 10MB to disk as well. Note that the
// bytes > maxBufferLen case above would already have triggered
// if this call couldn't succeed.
reserveBytes(bytes);
}
}
BinaryOutput::BinaryOutput() {
m_alreadyWritten = 0;
m_swapBytes = false;
m_pos = 0;
m_filename = "<memory>";
m_buffer = NULL;
m_bufferLen = 0;
m_maxBufferLen = 0;
m_beginEndBits = 0;
m_bitString = 0;
m_bitPos = 0;
m_ok = true;
m_committed = false;
}
BinaryOutput::BinaryOutput(
const std::string& filename,
G3DEndian fileEndian) {
m_pos = 0;
m_alreadyWritten = 0;
setEndian(fileEndian);
m_filename = filename;
m_buffer = NULL;
m_bufferLen = 0;
m_maxBufferLen = 0;
m_beginEndBits = 0;
m_bitString = 0;
m_bitPos = 0;
m_committed = false;
m_ok = true;
/** Verify ability to write to disk */
commit(false);
m_committed = false;
}
void BinaryOutput::reset() {
debugAssert(m_beginEndBits == 0);
alwaysAssertM(m_filename == "<memory>",
"Can only reset a BinaryOutput that writes to memory.");
// Do not reallocate, just clear the size of the buffer.
m_pos = 0;
m_alreadyWritten = 0;
m_bufferLen = 0;
m_beginEndBits = 0;
m_bitString = 0;
m_bitPos = 0;
m_committed = false;
}
BinaryOutput::~BinaryOutput() {
debugAssert((m_buffer == NULL) || isValidHeapPointer(m_buffer));
System::free(m_buffer);
m_buffer = NULL;
m_bufferLen = 0;
m_maxBufferLen = 0;
}
void BinaryOutput::setEndian(G3DEndian fileEndian) {
m_fileEndian = fileEndian;
m_swapBytes = (fileEndian != System::machineEndian());
}
bool BinaryOutput::ok() const {
return m_ok;
}
void BinaryOutput::compress() {
if (m_alreadyWritten > 0) {
throw "Cannot compress huge files (part of this file has already been written to disk).";
}
// Old buffer size
int L = m_bufferLen;
uint8* convert = (uint8*)&L;
// Zlib requires the output buffer to be this big
unsigned long newSize = iCeil(m_bufferLen * 1.01) + 12;
uint8* temp = (uint8*)System::malloc(newSize);
int result = compress2(temp, &newSize, m_buffer, m_bufferLen, 9);
debugAssert(result == Z_OK); (void)result;
// Write the header
if (m_swapBytes) {
m_buffer[0] = convert[3];
m_buffer[1] = convert[2];
m_buffer[2] = convert[1];
m_buffer[3] = convert[0];
} else {
m_buffer[0] = convert[0];
m_buffer[1] = convert[1];
m_buffer[2] = convert[2];
m_buffer[3] = convert[3];
}
// Write the data
if ((int64)newSize + 4 > (int64)m_maxBufferLen) {
m_maxBufferLen = newSize + 4;
m_buffer = (uint8*)System::realloc(m_buffer, m_maxBufferLen);
}
m_bufferLen = newSize + 4;
System::memcpy(m_buffer + 4, temp, newSize);
m_pos = m_bufferLen;
System::free(temp);
}
void BinaryOutput::commit(bool flush) {
debugAssertM(! m_committed, "Cannot commit twice");
m_committed = true;
debugAssertM(m_beginEndBits == 0, "Missing endBits before commit");
// Make sure the directory exists.
std::string root, base, ext, path;
Array<std::string> pathArray;
parseFilename(m_filename, root, pathArray, base, ext);
path = root + stringJoin(pathArray, '/');
if (! fileExists(path, false)) {
createDirectory(path);
}
const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb";
FILE* file = fopen(m_filename.c_str(), mode);
m_ok = (file != NULL) && m_ok;
if (m_ok) {
debugAssertM(file, std::string("Could not open '") + m_filename + "'");
m_alreadyWritten += m_bufferLen;
fwrite(m_buffer, m_bufferLen, 1, file);
if (flush) {
fflush(file);
}
fclose(file);
file = NULL;
}
}
void BinaryOutput::commit(
uint8* out) {
debugAssertM(! m_committed, "Cannot commit twice");
m_committed = true;
System::memcpy(out, m_buffer, m_bufferLen);
}
void BinaryOutput::writeUInt16(uint16 u) {
reserveBytes(2);
uint8* convert = (uint8*)&u;
if (m_swapBytes) {
m_buffer[m_pos] = convert[1];
m_buffer[m_pos + 1] = convert[0];
} else {
*(uint16*)(m_buffer + m_pos) = u;
}
m_pos += 2;
}
void BinaryOutput::writeUInt32(uint32 u) {
reserveBytes(4);
uint8* convert = (uint8*)&u;
debugAssert(m_beginEndBits == 0);
if (m_swapBytes) {
m_buffer[m_pos] = convert[3];
m_buffer[m_pos + 1] = convert[2];
m_buffer[m_pos + 2] = convert[1];
m_buffer[m_pos + 3] = convert[0];
} else {
*(uint32*)(m_buffer + m_pos) = u;
}
m_pos += 4;
}
void BinaryOutput::writeUInt64(uint64 u) {
reserveBytes(8);
uint8* convert = (uint8*)&u;
if (m_swapBytes) {
m_buffer[m_pos] = convert[7];
m_buffer[m_pos + 1] = convert[6];
m_buffer[m_pos + 2] = convert[5];
m_buffer[m_pos + 3] = convert[4];
m_buffer[m_pos + 4] = convert[3];
m_buffer[m_pos + 5] = convert[2];
m_buffer[m_pos + 6] = convert[1];
m_buffer[m_pos + 7] = convert[0];
} else {
*(uint64*)(m_buffer + m_pos) = u;
}
m_pos += 8;
}
void BinaryOutput::writeString(const char* s) {
// +1 is because strlen doesn't count the null
int len = strlen(s) + 1;
debugAssert(m_beginEndBits == 0);
reserveBytes(len);
System::memcpy(m_buffer + m_pos, s, len);
m_pos += len;
}
void BinaryOutput::writeStringEven(const char* s) {
// +1 is because strlen doesn't count the null
int len = strlen(s) + 1;
reserveBytes(len);
System::memcpy(m_buffer + m_pos, s, len);
m_pos += len;
// Pad with another NULL
if ((len % 2) == 1) {
writeUInt8(0);
}
}
void BinaryOutput::writeString32(const char* s) {
writeUInt32(strlen(s) + 1);
writeString(s);
}
void BinaryOutput::writeVector4(const Vector4& v) {
writeFloat32(v.x);
writeFloat32(v.y);
writeFloat32(v.z);
writeFloat32(v.w);
}
void BinaryOutput::writeVector3(const Vector3& v) {
writeFloat32(v.x);
writeFloat32(v.y);
writeFloat32(v.z);
}
void BinaryOutput::writeVector2(const Vector2& v) {
writeFloat32(v.x);
writeFloat32(v.y);
}
void BinaryOutput::writeColor4(const Color4& v) {
writeFloat32(v.r);
writeFloat32(v.g);
writeFloat32(v.b);
writeFloat32(v.a);
}
void BinaryOutput::writeColor3(const Color3& v) {
writeFloat32(v.r);
writeFloat32(v.g);
writeFloat32(v.b);
}
void BinaryOutput::beginBits() {
debugAssertM(m_beginEndBits == 0, "Already in beginBits...endBits");
m_bitString = 0x00;
m_bitPos = 0;
m_beginEndBits = 1;
}
void BinaryOutput::writeBits(uint32 value, int numBits) {
while (numBits > 0) {
// Extract the current bit of value and
// insert it into the current byte
m_bitString |= (value & 1) << m_bitPos;
++m_bitPos;
value = value >> 1;
--numBits;
if (m_bitPos > 7) {
// We've reached the end of this byte
writeUInt8(m_bitString);
m_bitString = 0x00;
m_bitPos = 0;
}
}
}
void BinaryOutput::endBits() {
debugAssertM(m_beginEndBits == 1, "Not in beginBits...endBits");
if (m_bitPos > 0) {
writeUInt8(m_bitString);
}
m_bitString = 0;
m_bitPos = 0;
m_beginEndBits = 0;
}
}
-393
View File
@@ -1,393 +0,0 @@
/**
@file Box.cpp
Box class
@maintainer Morgan McGuire, [email protected]
@created 2001-06-02
@edited 2006-02-05
*/
#include "G3D/Box.h"
#include "G3D/debug.h"
#include "G3D/Plane.h"
#include "G3D/AABox.h"
#include "G3D/CoordinateFrame.h"
namespace G3D {
/**
Sets a field on four vertices. Used by the constructor.
*/
#define setMany(i0, i1, i2, i3, field, extreme) \
_corner[i0].field = _corner[i1].field = \
_corner[i2].field = _corner[i3].field = \
(extreme).field
Box::Box() {
}
Box::Box(const AABox& b) {
init(b.low(), b.high());
}
Box::Box(class BinaryInput& b) {
deserialize(b);
}
void Box::serialize(class BinaryOutput& b) const {
int i;
for (i = 0; i < 8; ++i) {
_corner[i].serialize(b);
}
// Other state can be reconstructed
}
void Box::deserialize(class BinaryInput& b) {
int i;
_center = Vector3::zero();
for (i = 0; i < 8; ++i) {
_corner[i].deserialize(b);
_center += _corner[i];
}
_center = _center / 8;
// Reconstruct other state from the corners
_axis[0] = _corner[5] - _corner[4];
_axis[1] = _corner[7] - _corner[4];
_axis[2] = _corner[0] - _corner[4];
for (i = 0; i < 3; ++i) {
_extent[i] = _axis[i].magnitude();
_axis[i] /= _extent[i];
}
_volume = _extent.x * _extent.y * _extent.z;
_area = 2 *
(_extent.x * _extent.y +
_extent.y * _extent.z +
_extent.z * _extent.x);
}
Box::Box(
const Vector3& min,
const Vector3& max) {
init(min.min(max), min.max(max));
}
void Box::init(
const Vector3& min,
const Vector3& max) {
debugAssert(
(min.x <= max.x) &&
(min.y <= max.y) &&
(min.z <= max.z));
setMany(0, 1, 2, 3, z, max);
setMany(4, 5, 6, 7, z, min);
setMany(1, 2, 5, 6, x, max);
setMany(0, 3, 4, 7, x, min);
setMany(3, 2, 6, 7, y, max);
setMany(0, 1, 5, 4, y, min);
_extent = max - min;
_axis[0] = Vector3::unitX();
_axis[1] = Vector3::unitY();
_axis[2] = Vector3::unitZ();
if (_extent.isFinite()) {
_volume = _extent.x * _extent.y * _extent.z;
} else {
_volume = G3D::inf();
}
debugAssert(! isNaN(_extent.x));
_area = 2 *
(_extent.x * _extent.y +
_extent.y * _extent.z +
_extent.z * _extent.x);
_center = (max + min) / 2;
// If the extent is infinite along an axis, make the center zero to avoid NaNs
for (int i = 0; i < 3; ++i) {
if (! G3D::isFinite(_extent[i])) {
_center[i] = 0.0f;
}
}
}
float Box::volume() const {
return _volume;
}
float Box::area() const {
return _area;
}
void Box::getLocalFrame(CoordinateFrame& frame) const {
frame.rotation = Matrix3(
_axis[0][0], _axis[1][0], _axis[2][0],
_axis[0][1], _axis[1][1], _axis[2][1],
_axis[0][2], _axis[1][2], _axis[2][2]);
frame.translation = _center;
}
CoordinateFrame Box::localFrame() const {
CoordinateFrame out;
getLocalFrame(out);
return out;
}
void Box::getFaceCorners(int f, Vector3& v0, Vector3& v1, Vector3& v2, Vector3& v3) const {
switch (f) {
case 0:
v0 = _corner[0]; v1 = _corner[1]; v2 = _corner[2]; v3 = _corner[3];
break;
case 1:
v0 = _corner[1]; v1 = _corner[5]; v2 = _corner[6]; v3 = _corner[2];
break;
case 2:
v0 = _corner[7]; v1 = _corner[6]; v2 = _corner[5]; v3 = _corner[4];
break;
case 3:
v0 = _corner[2]; v1 = _corner[6]; v2 = _corner[7]; v3 = _corner[3];
break;
case 4:
v0 = _corner[3]; v1 = _corner[7]; v2 = _corner[4]; v3 = _corner[0];
break;
case 5:
v0 = _corner[1]; v1 = _corner[0]; v2 = _corner[4]; v3 = _corner[5];
break;
default:
debugAssert((f >= 0) && (f < 6));
}
}
int Box::dummy = 0;
bool Box::culledBy(
const Array<Plane>& plane,
int& cullingPlane,
const uint32 _inMask,
uint32& childMask) const {
uint32 inMask = _inMask;
assert(plane.size() < 31);
childMask = 0;
// See if there is one plane for which all of the
// vertices are in the negative half space.
for (int p = 0; p < plane.size(); ++p) {
// Only test planes that are not masked
if ((inMask & 1) != 0) {
Vector3 corner;
int numContained = 0;
int v = 0;
// We can early-out only if we have found one point on each
// side of the plane (i.e. if we are straddling). That
// occurs when (numContained < v) && (numContained > 0)
for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) {
if (plane[p].halfSpaceContains(_corner[v])) {
++numContained;
}
}
if (numContained == 0) {
// Plane p culled the box
cullingPlane = p;
// The caller should not recurse into the children,
// since the parent is culled. If they do recurse,
// make them only test against this one plane, which
// will immediately cull the volume.
childMask = 1 << p;
return true;
} else if (numContained < v) {
// The bounding volume straddled the plane; we have
// to keep testing against this plane
childMask |= (1 << p);
}
}
// Move on to the next bit.
inMask = inMask >> 1;
}
// None of the planes could cull this box
cullingPlane = -1;
return false;
}
bool Box::culledBy(
const Array<Plane>& plane,
int& cullingPlane,
const uint32 _inMask) const {
uint32 inMask = _inMask;
assert(plane.size() < 31);
// See if there is one plane for which all of the
// vertices are in the negative half space.
for (int p = 0; p < plane.size(); ++p) {
// Only test planes that are not masked
if ((inMask & 1) != 0) {
bool culled = true;
int v;
// Assume this plane culls all points. See if there is a point
// not culled by the plane... early out when at least one point
// is in the positive half space.
for (v = 0; (v < 8) && culled; ++v) {
culled = ! plane[p].halfSpaceContains(corner(v));
}
if (culled) {
// Plane p culled the box
cullingPlane = p;
return true;
}
}
// Move on to the next bit.
inMask = inMask >> 1;
}
// None of the planes could cull this box
cullingPlane = -1;
return false;
}
bool Box::contains(
const Vector3& point) const {
// Form axes from three edges, transform the point into that
// space, and perform 3 interval tests
Vector3 u = _corner[4] - _corner[0];
Vector3 v = _corner[3] - _corner[0];
Vector3 w = _corner[1] - _corner[0];
Matrix3 M = Matrix3(u.x, v.x, w.x,
u.y, v.y, w.y,
u.z, v.z, w.z);
// M^-1 * (point - _corner[0]) = point in unit cube's object space
// compute the inverse of M
Vector3 osPoint = M.inverse() * (point - _corner[0]);
return
(osPoint.x >= 0) &&
(osPoint.y >= 0) &&
(osPoint.z >= 0) &&
(osPoint.x <= 1) &&
(osPoint.y <= 1) &&
(osPoint.z <= 1);
}
#undef setMany
void Box::getRandomSurfacePoint(Vector3& P, Vector3& N) const {
float aXY = _extent.x * _extent.y;
float aYZ = _extent.y * _extent.z;
float aZX = _extent.z * _extent.x;
float r = (float)uniformRandom(0, aXY + aYZ + aZX);
// Choose evenly between positive and negative face planes
float d = (uniformRandom(0, 1) < 0.5f) ? -1.0f : 1.0f;
// The probability of choosing a given face is proportional to
// its area.
if (r < aXY) {
P = _axis[0] * (float)uniformRandom(-0.5, 0.5) * _extent.x +
_axis[1] * (float)uniformRandom(-0.5, 0.5) * _extent.y +
_center + _axis[2] * d * _extent.z * 0.5f;
N = _axis[2] * d;
} else if (r < aYZ) {
P = _axis[1] * (float)uniformRandom(-0.5, 0.5) * _extent.y +
_axis[2] * (float)uniformRandom(-0.5, 0.5) * _extent.z +
_center + _axis[0] * d * _extent.x * 0.5f;
N = _axis[0] * d;
} else {
P = _axis[2] * (float)uniformRandom(-0.5, 0.5) * _extent.z +
_axis[0] *(float) uniformRandom(-0.5, 0.5) * _extent.x +
_center + _axis[1] * d * _extent.y * 0.5f;
N = _axis[1] * d;
}
}
Vector3 Box::randomInteriorPoint() const {
Vector3 sum = _center;
for (int a = 0; a < 3; ++a) {
sum += _axis[a] * (float)uniformRandom(-0.5, 0.5) * _extent[a];
}
return sum;
}
Box Box::inf() {
return Box(-Vector3::inf(), Vector3::inf());
}
void Box::getBounds(class AABox& aabb) const {
Vector3 lo = _corner[0];
Vector3 hi = lo;
for (int v = 1; v < 8; ++v) {
const Vector3& C = _corner[v];
lo = lo.min(C);
hi = hi.max(C);
}
aabb = AABox(lo, hi);
}
} // namespace
-179
View File
@@ -1,179 +0,0 @@
/**
@file Capsule.cpp
@maintainer Morgan McGuire, [email protected]
@created 2003-02-07
@edited 2005-08-18
Copyright 2000-2005, Morgan McGuire.
All rights reserved.
*/
#include "G3D/Capsule.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/LineSegment.h"
#include "G3D/Sphere.h"
#include "G3D/CoordinateFrame.h"
#include "G3D/Line.h"
#include "G3D/AABox.h"
namespace G3D {
Capsule::Capsule(class BinaryInput& b) {
deserialize(b);
}
Capsule::Capsule() {
}
Capsule::Capsule(const Vector3& _p1, const Vector3& _p2, float _r)
: p1(_p1), p2(_p2), _radius(_r) {
}
void Capsule::serialize(class BinaryOutput& b) const {
p1.serialize(b);
p2.serialize(b);
b.writeFloat64(_radius);
}
void Capsule::deserialize(class BinaryInput& b) {
p1.deserialize(b);
p2.deserialize(b);
_radius = b.readFloat64();
}
Line Capsule::axis() const {
return Line::fromTwoPoints(p1, p2);
}
float Capsule::volume() const {
return
// Sphere volume
pow(_radius, 3) * pi() * 4 / 3 +
// Cylinder volume
pow(_radius, 2) * (p1 - p2).magnitude();
}
float Capsule::area() const {
return
// Sphere area
pow(_radius, 2) * 4 * pi() +
// Cylinder area
twoPi() * _radius * (p1 - p2).magnitude();
}
void Capsule::getBounds(AABox& out) const {
Vector3 min = p1.min(p2) - (Vector3(1, 1, 1) * _radius);
Vector3 max = p1.max(p2) + (Vector3(1, 1, 1) * _radius);
out = AABox(min, max);
}
bool Capsule::contains(const Vector3& p) const {
return LineSegment::fromTwoPoints(p1, p2).distanceSquared(p) <= square(radius());
}
void Capsule::getRandomSurfacePoint(Vector3& p, Vector3& N) const {
float h = height();
float r = radius();
// Create a random point on a standard capsule and then rotate to the global frame.
// Relative areas
float capRelArea = sqrt(r) / 2.0f;
float sideRelArea = r * h;
float r1 = uniformRandom(0, capRelArea * 2 + sideRelArea);
if (r1 < capRelArea * 2) {
// Select a point uniformly at random on a sphere
N = Sphere(Vector3::zero(), 1).randomSurfacePoint();
p = N * r;
p.y += sign(p.y) * h / 2.0f;
} else {
// Side
float a = uniformRandom(0, (float)twoPi());
N.x = cos(a);
N.y = 0;
N.z = sin(a);
p.x = N.x * r;
p.z = N.y * r;
p.y = uniformRandom(-h / 2.0f, h / 2.0f);
}
// Transform to world space
CoordinateFrame cframe;
getReferenceFrame(cframe);
p = cframe.pointToWorldSpace(p);
N = cframe.normalToWorldSpace(N);
}
void Capsule::getReferenceFrame(CoordinateFrame& cframe) const {
cframe.translation = center();
Vector3 Y = (p1 - p2).direction();
Vector3 X = (abs(Y.dot(Vector3::unitX())) > 0.9) ? Vector3::unitY() : Vector3::unitX();
Vector3 Z = X.cross(Y).direction();
X = Y.cross(Z);
cframe.rotation.setColumn(0, X);
cframe.rotation.setColumn(1, Y);
cframe.rotation.setColumn(2, Z);
}
Vector3 Capsule::randomInteriorPoint() const {
float h = height();
float r = radius();
// Create a random point in a standard capsule and then rotate to the global frame.
Vector3 p;
float hemiVolume = pi() * (r*r*r) * 4 / 6.0;
float cylVolume = pi() * square(r) * h;
float r1 = uniformRandom(0, 2.0 * hemiVolume + cylVolume);
if (r1 < 2.0 * hemiVolume) {
p = Sphere(Vector3::zero(), r).randomInteriorPoint();
p.y += sign(p.y) * h / 2.0f;
} else {
// Select a point uniformly at random on a disk
float a = uniformRandom(0, (float)twoPi());
float r2 = sqrt(uniformRandom(0, 1)) * r;
p = Vector3(cos(a) * r2,
uniformRandom(-h / 2.0f, h / 2.0f),
sin(a) * r2);
}
// Transform to world space
CoordinateFrame cframe;
getReferenceFrame(cframe);
return cframe.pointToWorldSpace(p);
}
} // namespace
File diff suppressed because it is too large Load Diff
-40
View File
@@ -1,40 +0,0 @@
/**
@file Color1.cpp
Color class.
@author Morgan McGuire, [email protected]
@created 2007-01-30
@edited 2007-01-30
*/
#include "G3D/platform.h"
#include "G3D/Color1.h"
#include "G3D/Color1uint8.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
namespace G3D {
Color1::Color1(BinaryInput& bi) {
deserialize(bi);
}
void Color1::deserialize(BinaryInput& bi) {
value = bi.readFloat32();
}
void Color1::serialize(BinaryOutput& bo) const {
bo.writeFloat32(value);
}
Color1::Color1(const class Color1uint8& other) {
value = other.value / 255.0f;
}
} // namespace G3D
-38
View File
@@ -1,38 +0,0 @@
/**
@file Color1uint8.cpp
@author Morgan McGuire, [email protected]
@created 2007-01-30
@edited 2007-01-30
*/
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
#include "G3D/Color1uint8.h"
#include "G3D/Color1.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
namespace G3D {
Color1uint8::Color1uint8(const class Color1& c) : value(iClamp(iFloor(c.value * 256), 0, 255)) {
}
Color1uint8::Color1uint8(class BinaryInput& bi) {
deserialize(bi);
}
void Color1uint8::serialize(class BinaryOutput& bo) const {
bo.writeUInt8(value);
}
void Color1uint8::deserialize(class BinaryInput& bi) {
value = bi.readUInt8();
}
}
-321
View File
@@ -1,321 +0,0 @@
/**
@file Color3.cpp
Color class.
@author Morgan McGuire, [email protected]
@cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com
@created 2001-06-02
@edited 2006-01-13
*/
#include "G3D/platform.h"
#include <stdlib.h>
#include "G3D/Color3.h"
#include "G3D/Vector3.h"
#include "G3D/format.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/Color3uint8.h"
namespace G3D {
const Color3& Color3::red() {
static Color3 c(1.0f, 0.0f, 0.0f);
return c;
}
const Color3& Color3::green() {
static Color3 c(0.0f, 1.0f, 0.0f);
return c;
}
const Color3& Color3::blue() {
static Color3 c(0.0f, 0.0f, 1.0f);
return c;
}
const Color3& Color3::purple() {
static Color3 c(0.7f, 0.0f, 1.0f);
return c;
}
const Color3& Color3::cyan() {
static Color3 c(0.0f, 0.7f, 1.0f);
return c;
}
const Color3& Color3::yellow() {
static Color3 c(1.0f, 1.0f, 0.0f);
return c;
}
const Color3& Color3::brown() {
static Color3 c(0.5f, 0.5f, 0.0f);
return c;
}
const Color3& Color3::orange() {
static Color3 c(1.0f, 0.5f, 0.0f);
return c;
}
const Color3& Color3::black() {
static Color3 c(0.0f, 0.0f, 0.0f);
return c;
}
const Color3& Color3::zero() {
static Color3 c(0.0f, 0.0f, 0.0f);
return c;
}
const Color3& Color3::one() {
static Color3 c(1.0f, 1.0f, 1.0f);
return c;
}
const Color3& Color3::gray() {
static Color3 c(0.7f, 0.7f, 0.7f);
return c;
}
const Color3& Color3::white() {
static Color3 c(1, 1, 1);
return c;
}
Color3::Color3(BinaryInput& bi) {
deserialize(bi);
}
void Color3::deserialize(BinaryInput& bi) {
r = bi.readFloat32();
g = bi.readFloat32();
b = bi.readFloat32();
}
void Color3::serialize(BinaryOutput& bo) const {
bo.writeFloat32(r);
bo.writeFloat32(g);
bo.writeFloat32(b);
}
const Color3& Color3::wheelRandom() {
static const Color3 colorArray[8] =
{Color3::blue(), Color3::red(), Color3::green(),
Color3::orange(), Color3::yellow(),
Color3::cyan(), Color3::purple(), Color3::brown()};
return colorArray[iRandom(0, 7)];
}
size_t Color3::hashCode() const {
unsigned int rhash = (*(int*)(void*)(&r));
unsigned int ghash = (*(int*)(void*)(&g));
unsigned int bhash = (*(int*)(void*)(&b));
return rhash + (ghash * 37) + (bhash * 101);
}
Color3::Color3(const Vector3& v) {
r = v.x;
g = v.y;
b = v.z;
}
Color3::Color3(const class Color3uint8& other) {
r = other.r / 255.0f;
g = other.g / 255.0f;
b = other.b / 255.0f;
}
Color3 Color3::fromARGB(uint32 x) {
return Color3((float)((x >> 16) & 0xFF), (float)((x >> 8) & 0xFF), (float)(x & 0xFF)) / 255.0f;
}
//----------------------------------------------------------------------------
Color3 Color3::random() {
return Color3(uniformRandom(),
uniformRandom(),
uniformRandom()).direction();
}
//----------------------------------------------------------------------------
Color3 Color3::operator/ (float fScalar) const {
Color3 kQuot;
if (fScalar != 0.0f) {
float fInvScalar = 1.0f / fScalar;
kQuot.r = fInvScalar * r;
kQuot.g = fInvScalar * g;
kQuot.b = fInvScalar * b;
return kQuot;
} else {
return Color3((float)G3D::inf(), (float)G3D::inf(), (float)G3D::inf());
}
}
//----------------------------------------------------------------------------
Color3& Color3::operator/= (float fScalar) {
if (fScalar != 0.0f) {
float fInvScalar = 1.0f / fScalar;
r *= fInvScalar;
g *= fInvScalar;
b *= fInvScalar;
} else {
r = (float)G3D::inf();
g = (float)G3D::inf();
b = (float)G3D::inf();
}
return *this;
}
//----------------------------------------------------------------------------
float Color3::unitize (float fTolerance) {
float fLength = length();
if ( fLength > fTolerance ) {
float fInvLength = 1.0f / fLength;
r *= fInvLength;
g *= fInvLength;
b *= fInvLength;
} else {
fLength = 0.0f;
}
return fLength;
}
//----------------------------------------------------------------------------
Color3 Color3::fromHSV(const Vector3& _hsv) {
debugAssertM((_hsv.x <= 1.0f && _hsv.x >= 0.0f)
&& (_hsv.y <= 1.0f && _hsv.y >= 0.0f)
&& ( _hsv.z <= 1.0f && _hsv.z >= 0.0f), "H,S,V must be between [0,1]");
const int i = G3D::iFloor(6.0*_hsv.x);
const float f = 6.0f * _hsv.x - i;
const float m = _hsv.z * (1.0f - (_hsv.y));
const float n = _hsv.z * (1.0f - (_hsv.y * f));
const float k = _hsv.z * (1.0f - (_hsv.y * (1 - f)));
switch(i) {
case 0:
return Color3(_hsv.z, k, m);
case 1:
return Color3(n, _hsv.z, m);
case 2:
return Color3(m, _hsv.z, k);
case 3:
return Color3(m, n, _hsv.z);
case 4:
return Color3(k, m, _hsv.z);
case 5:
return Color3(_hsv.z, m, n);
default:
debugAssertM(false, "fell through switch..");
}
return Color3::black();
}
Vector3 Color3::toHSV(const Color3& _rgb) {
debugAssertM((_rgb.r <= 1.0f && _rgb.r >= 0.0f)
&& (_rgb.g <= 1.0f && _rgb.g >= 0.0f)
&& (_rgb.b <= 1.0f && _rgb.b >= 0.0f), "R,G,B must be between [0,1]");
Vector3 hsv = Vector3::zero();
hsv.z = G3D::max(G3D::max(_rgb.r, _rgb.g), _rgb.b);
if (G3D::fuzzyEq(hsv.z, 0.0f)) {
return hsv;
}
const float x = G3D::min(G3D::min(_rgb.r, _rgb.g), _rgb.b);
hsv.y = (hsv.z - x) / hsv.z;
if (G3D::fuzzyEq(hsv.y, 0.0f)) {
return hsv;
}
Vector3 rgbN;
rgbN.x = (hsv.z - _rgb.r) / (hsv.z - x);
rgbN.y = (hsv.z - _rgb.g) / (hsv.z - x);
rgbN.z = (hsv.z - _rgb.b) / (hsv.z - x);
if (_rgb.r == hsv.z) { // note from the max we know that it exactly equals one of the three.
hsv.x = (_rgb.g == x)? 5.0f + rgbN.z : 1.0f - rgbN.y;
} else if (_rgb.g == hsv.z) {
hsv.x = (_rgb.b == x)? 1.0f + rgbN.x : 3.0f - rgbN.z;
} else {
hsv.x = (_rgb.r == x)? 3.0f + rgbN.y : 5.0f - rgbN.x;
}
hsv.x /= 6.0f;
return hsv;
}
Color3 Color3::jetColorMap(const float& val) {
debugAssertM(val <= 1.0f && val >= 0.0f , "value should be in [0,1]");
//truncated triangles where sides have slope 4
Color3 jet;
jet.r = G3D::min(4.0f * val - 1.5f,-4.0f * val + 4.5f) ;
jet.g = G3D::min(4.0f * val - 0.5f,-4.0f * val + 3.5f) ;
jet.b = G3D::min(4.0f * val + 0.5f,-4.0f * val + 2.5f) ;
jet.r = G3D::clamp(jet.r, 0.0f, 1.0f);
jet.g = G3D::clamp(jet.g, 0.0f, 1.0f);
jet.b = G3D::clamp(jet.b, 0.0f, 1.0f);
return jet;
}
std::string Color3::toString() const {
return G3D::format("(%g, %g, %g)", r, g, b);
}
//----------------------------------------------------------------------------
Color3 Color3::rainbowColorMap(float hue) {
return fromHSV(Vector3(hue, 1.0f, 1.0f));
}
}; // namespace
-45
View File
@@ -1,45 +0,0 @@
/**
@file Color3uint8.cpp
@author Morgan McGuire, [email protected]
@created 2003-04-07
@edited 2006-01-07
*/
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
#include "G3D/Color3uint8.h"
#include "G3D/Color3.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
namespace G3D {
Color3uint8::Color3uint8(const class Color3& c) {
r = iMin(255, iFloor(c.r * 256));
g = iMin(255, iFloor(c.g * 256));
b = iMin(255, iFloor(c.b * 256));
}
Color3uint8::Color3uint8(class BinaryInput& bi) {
deserialize(bi);
}
void Color3uint8::serialize(class BinaryOutput& bo) const {
bo.writeUInt8(r);
bo.writeUInt8(g);
bo.writeUInt8(b);
}
void Color3uint8::deserialize(class BinaryInput& bi) {
r = bi.readUInt8();
g = bi.readUInt8();
b = bi.readUInt8();
}
}
-140
View File
@@ -1,140 +0,0 @@
/**
@file Color4.cpp
Color class.
@author Morgan McGuire, [email protected]
@cite Portions by Laura Wollstadt, graphics3d.com
@cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com
@created 2002-06-25
@edited 2006-01-10
*/
#include <stdlib.h>
#include "G3D/Color4.h"
#include "G3D/Color4uint8.h"
#include "G3D/Vector4.h"
#include "G3D/format.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
namespace G3D {
const Color4& Color4::zero() {
static Color4 c(0.0f, 0.0f, 0.0f, 0.0f);
return c;
}
const Color4& Color4::inf() {
static Color4 c((float)G3D::inf(), (float)G3D::inf(), (float)G3D::inf(), (float)G3D::inf());
return c;
}
const Color4& Color4::clear() {
return Color4::zero();
}
Color4::Color4(const Vector4& v) {
r = v.x;
g = v.y;
b = v.z;
a = v.w;
}
Color4::Color4(const Color4uint8& c) : r(c.r), g(c.g), b(c.b), a(c.a) {
*this /= 255.0f;
}
size_t Color4::hashCode() const {
unsigned int rhash = (*(int*)(void*)(&r));
unsigned int ghash = (*(int*)(void*)(&g));
unsigned int bhash = (*(int*)(void*)(&b));
unsigned int ahash = (*(int*)(void*)(&a));
return rhash + (ghash * 37) + (bhash * 101) + (ahash * 241);
}
Color4 Color4::fromARGB(uint32 x) {
return Color4(
(float)((x >> 16) & 0xFF),
(float)((x >> 8) & 0xFF),
(float)(x & 0xFF),
(float)((x >> 24) & 0xFF)) / 255.0;
}
Color4::Color4(BinaryInput& bi) {
deserialize(bi);
}
void Color4::deserialize(BinaryInput& bi) {
r = bi.readFloat32();
g = bi.readFloat32();
b = bi.readFloat32();
a = bi.readFloat32();
}
void Color4::serialize(BinaryOutput& bo) const {
bo.writeFloat32(r);
bo.writeFloat32(g);
bo.writeFloat32(b);
bo.writeFloat32(a);
}
//----------------------------------------------------------------------------
Color4 Color4::operator/ (float fScalar) const {
Color4 kQuot;
if (fScalar != 0.0f) {
float fInvScalar = 1.0f / fScalar;
kQuot.r = fInvScalar * r;
kQuot.g = fInvScalar * g;
kQuot.b = fInvScalar * b;
kQuot.a = fInvScalar * a;
return kQuot;
} else {
return Color4::inf();
}
}
//----------------------------------------------------------------------------
Color4& Color4::operator/= (float fScalar) {
if (fScalar != 0.0f) {
float fInvScalar = 1.0f / fScalar;
r *= fInvScalar;
g *= fInvScalar;
b *= fInvScalar;
a *= fInvScalar;
} else {
r = (float)G3D::inf();
g = (float)G3D::inf();
b = (float)G3D::inf();
a = (float)G3D::inf();
}
return *this;
}
//----------------------------------------------------------------------------
std::string Color4::toString() const {
return G3D::format("(%g, %g, %g, %g)", r, g, b, a);
}
//----------------------------------------------------------------------------
}; // namespace
-47
View File
@@ -1,47 +0,0 @@
/**
@file Color4uint8.cpp
@author Morgan McGuire, [email protected]
@created 2003-04-07
@edited 2006-01-07
*/
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
#include "G3D/Color4uint8.h"
#include "G3D/Color4.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
namespace G3D {
Color4uint8::Color4uint8(const class Color4& c) {
r = iMin(255, iFloor(c.r * 256));
g = iMin(255, iFloor(c.g * 256));
b = iMin(255, iFloor(c.b * 256));
a = iMin(255, iFloor(c.a * 256));
}
Color4uint8::Color4uint8(class BinaryInput& bi) {
deserialize(bi);
}
void Color4uint8::serialize(class BinaryOutput& bo) const {
bo.writeUInt8(r);
bo.writeUInt8(g);
bo.writeUInt8(b);
bo.writeUInt8(a);
}
void Color4uint8::deserialize(class BinaryInput& bi) {
r = bi.readUInt8();
g = bi.readUInt8();
b = bi.readUInt8();
a = bi.readUInt8();
}
}
-79
View File
@@ -1,79 +0,0 @@
/**
@file Cone.cpp
Cone class
@maintainer Morgan McGuire, [email protected]
@created 2001-07-09
@edited 2006-01-29
*/
#include "G3D/platform.h"
#include "G3D/Cone.h"
#include "G3D/Line.h"
#include "G3D/Sphere.h"
#include "G3D/Box.h"
namespace G3D {
Cone::Cone(const Vector3 &tip, const Vector3 &direction, float angle) {
this->tip = tip;
this->direction = direction.direction();
this->angle = angle;
debugAssert(angle >= 0);
debugAssert(angle <= pi());
}
/**
Forms the smallest cone that contains the box. Undefined if
the tip is inside or on the box.
*/
Cone::Cone(const Vector3& tip, const Box& box) {
this->tip = tip;
this->direction = (box.center() - tip).direction();
// Find the biggest angle
float smallestDotProduct = direction.dot((box.corner(0) - tip).direction());
for (int i = 1; i < 8; ++i) {
float dp = direction.dot((box.corner(i) - tip).direction());
debugAssert(dp > 0);
if (dp < smallestDotProduct) {
smallestDotProduct = dp;
}
}
angle = acosf(smallestDotProduct);
}
bool Cone::intersects(const Sphere& b) const {
// If the bounding sphere contains the tip, then
// they definitely touch.
if (b.contains(this->tip)) {
return true;
}
// Move the tip backwards, effectively making the cone bigger
// to account for the radius of the sphere.
Vector3 tip = this->tip - direction * b.radius / sinf(angle);
return Cone(tip, direction, angle).contains(b.center);
}
bool Cone::contains(const Vector3& v) const {
Vector3 d = (v - tip).direction();
float x = d.dot(direction);
return (x > 0) && (x >= cosf(angle));
}
}; // namespace
-449
View File
@@ -1,449 +0,0 @@
/**
@file ConvexPolyhedron.cpp
@author Morgan McGuire, [email protected]
@created 2001-11-11
@edited 2006-01-10
Copyright 2000-2006, Morgan McGuire.
All rights reserved.
*/
#include "G3D/platform.h"
#include "G3D/ConvexPolyhedron.h"
#include "G3D/debug.h"
namespace G3D {
ConvexPolygon::ConvexPolygon(const Array<Vector3>& __vertex) : _vertex(__vertex) {
// Intentionally empty
}
bool ConvexPolygon::isEmpty() const {
return (_vertex.length() == 0) || (getArea() <= fuzzyEpsilon);
}
float ConvexPolygon::getArea() const {
if (_vertex.length() < 3) {
return 0;
}
float sum = 0;
int length = _vertex.length();
// Split into triangle fan, compute individual area
for (int v = 2; v < length; v++) {
int i0 = 0;
int i1 = v - 1;
int i2 = v;
sum += (_vertex[i1] - _vertex[i0]).cross(_vertex[i2] - _vertex[i0]).magnitude() / 2;
}
return sum;
}
void ConvexPolygon::cut(const Plane& plane, ConvexPolygon &above, ConvexPolygon &below) {
DirectedEdge edge;
cut(plane, above, below, edge);
}
void ConvexPolygon::cut(const Plane& plane, ConvexPolygon &above, ConvexPolygon &below, DirectedEdge &newEdge) {
above._vertex.resize(0);
below._vertex.resize(0);
if (isEmpty()) {
//debugPrintf("Empty\n");
return;
}
int v = 0;
int length = _vertex.length();
Vector3 polyNormal = normal();
Vector3 planeNormal= plane.normal();
// See if the polygon is *in* the plane.
if (planeNormal.fuzzyEq(polyNormal) || planeNormal.fuzzyEq(-polyNormal)) {
// Polygon is parallel to the plane. It must be either above,
// below, or in the plane.
double a, b, c, d;
Vector3 pt = _vertex[0];
plane.getEquation(a,b,c,d);
float r = (float)(a * pt.x + b * pt.y + c * pt.z + d);
if (fuzzyGe(r, 0)) {
// The polygon is entirely in the plane.
//debugPrintf("Entirely above\n");
above = *this;
return;
} else {
//debugPrintf("Entirely below (1)\n");
below = *this;
return;
}
}
// Number of edges crossing the plane. Used for
// debug assertions.
int count = 0;
// True when the last _vertex we looked at was above the plane
bool lastAbove = plane.halfSpaceContains(_vertex[v]);
if (lastAbove) {
above._vertex.append(_vertex[v]);
} else {
below._vertex.append(_vertex[v]);
}
for (v = 1; v < length; v++) {
bool isAbove = plane.halfSpaceContains(_vertex[v]);
if (lastAbove ^ isAbove) {
// Switched sides.
// Create an interpolated point that lies
// in the plane, between the two points.
Line line = Line::fromTwoPoints(_vertex[v - 1], _vertex[v]);
Vector3 interp = line.intersection(plane);
if (! interp.isFinite()) {
// Since the polygon is not in the plane (we checked above),
// it must be the case that this edge (and only this edge)
// is in the plane. This only happens when the polygon is
// entirely below the plane except for one edge. This edge
// forms a degenerate polygon, so just treat the whole polygon
// as below the plane.
below = *this;
above._vertex.resize(0);
//debugPrintf("Entirely below\n");
return;
}
above._vertex.append(interp);
below._vertex.append(interp);
if (lastAbove) {
newEdge.stop = interp;
} else {
newEdge.start = interp;
}
count++;
}
lastAbove = isAbove;
if (lastAbove) {
above._vertex.append(_vertex[v]);
} else {
below._vertex.append(_vertex[v]);
}
}
// Loop back to the first point, seeing if an interpolated point is
// needed.
bool isAbove = plane.halfSpaceContains(_vertex[0]);
if (lastAbove ^ isAbove) {
Line line = Line::fromTwoPoints(_vertex[length - 1], _vertex[0]);
Vector3 interp = line.intersection(plane);
if (! interp.isFinite()) {
// Since the polygon is not in the plane (we checked above),
// it must be the case that this edge (and only this edge)
// is in the plane. This only happens when the polygon is
// entirely below the plane except for one edge. This edge
// forms a degenerate polygon, so just treat the whole polygon
// as below the plane.
below = *this;
above._vertex.resize(0);
//debugPrintf("Entirely below\n");
return;
}
above._vertex.append(interp);
below._vertex.append(interp);
debugAssertM(count < 2, "Convex polygons may only intersect planes at two edges.");
if (lastAbove) {
newEdge.stop = interp;
} else {
newEdge.start = interp;
}
count++;
}
debugAssertM((count == 2) || (count == 0), "Convex polygons may only intersect planes at two edges.");
}
ConvexPolygon ConvexPolygon::inverse() const {
ConvexPolygon result;
int length = _vertex.length();
result._vertex.resize(length);
for (int v = 0; v < length; v++) {
result._vertex[v] = _vertex[length - v - 1];
}
return result;
}
void ConvexPolygon::removeDuplicateVertices(){
// Any valid polygon should have 3 or more vertices, but why take chances?
if(_vertex.size() >= 2){
// Remove duplicate vertices.
for(int i=0;i<_vertex.size()-1;++i){
if(_vertex[i].fuzzyEq(_vertex[i+1])){
_vertex.remove(i+1);
--i; // Don't move forward.
}
}
// Check the last vertex against the first.
if(_vertex[_vertex.size()-1].fuzzyEq(_vertex[0])){
_vertex.pop();
}
}
}
//////////////////////////////////////////////////////////////////////////////
ConvexPolyhedron::ConvexPolyhedron(const Array<ConvexPolygon>& _face) : face(_face) {
// Intentionally empty
}
float ConvexPolyhedron::getVolume() const {
if (face.length() < 4) {
return 0;
}
// The volume of any pyramid is 1/3 * h * base area.
// Discussion at: http://nrich.maths.org/mathsf/journalf/oct01/art1/
float sum = 0;
// Choose the first _vertex of the first face as the origin.
// This lets us skip one face, too, and avoids negative heights.
Vector3 v0 = face[0]._vertex[0];
for (int f = 1; f < face.length(); f++) {
const ConvexPolygon& poly = face[f];
float height = (poly._vertex[0] - v0).dot(poly.normal());
float base = poly.getArea();
sum += height * base;
}
return sum / 3;
}
bool ConvexPolyhedron::isEmpty() const {
return (face.length() == 0) || (getVolume() <= fuzzyEpsilon);
}
void ConvexPolyhedron::cut(const Plane& plane, ConvexPolyhedron &above, ConvexPolyhedron &below) {
above.face.resize(0);
below.face.resize(0);
Array<DirectedEdge> edge;
int f;
// See if the plane cuts this polyhedron at all. Detect when
// the polyhedron is entirely to one side or the other.
//{
int numAbove = 0, numIn = 0, numBelow = 0;
bool ruledOut = false;
double d;
Vector3 abc;
plane.getEquation(abc, d);
// This number has to be fairly large to prevent precision problems down
// the road.
const float eps = 0.005f;
for (f = face.length() - 1; (f >= 0) && (!ruledOut); f--) {
const ConvexPolygon& poly = face[f];
for (int v = poly._vertex.length() - 1; (v >= 0) && (!ruledOut); v--) {
double r = abc.dot(poly._vertex[v]) + d;
if (r > eps) {
numAbove++;
} else if (r < -eps) {
numBelow++;
} else {
numIn++;
}
ruledOut = (numAbove != 0) && (numBelow !=0);
}
}
if (numBelow == 0) {
above = *this;
return;
} else if (numAbove == 0) {
below = *this;
return;
}
//}
// Clip each polygon, collecting split edges.
for (f = face.length() - 1; f >= 0; f--) {
ConvexPolygon a, b;
DirectedEdge e;
face[f].cut(plane, a, b, e);
bool aEmpty = a.isEmpty();
bool bEmpty = b.isEmpty();
//debugPrintf("\n");
if (! aEmpty) {
//debugPrintf(" Above %f\n", a.getArea());
above.face.append(a);
}
if (! bEmpty) {
//debugPrintf(" Below %f\n", b.getArea());
below.face.append(b);
}
if (! aEmpty && ! bEmpty) {
//debugPrintf(" == Split\n");
edge.append(e);
} else {
// Might be the case that the polygon is entirely on
// one side of the plane yet there is an edge we need
// because it touches the plane.
//
// Extract the non-empty _vertex list and examine it.
// If we find exactly one edge in the plane, add that edge.
const Array<Vector3>& _vertex = (aEmpty ? b._vertex : a._vertex);
int L = _vertex.length();
int count = 0;
for (int v = 0; v < L; v++) {
if (plane.fuzzyContains(_vertex[v]) && plane.fuzzyContains(_vertex[(v + 1) % L])) {
e.start = _vertex[v];
e.stop = _vertex[(v + 1) % L];
count++;
}
}
if (count == 1) {
edge.append(e);
}
}
}
if (above.face.length() == 1) {
// Only one face above means that this entire
// polyhedron is below the plane. Move that face over.
below.face.append(above.face[0]);
above.face.resize(0);
} else if (below.face.length() == 1) {
// This shouldn't happen, but it arises in practice
// from numerical imprecision.
above.face.append(below.face[0]);
below.face.resize(0);
}
if ((above.face.length() > 0) && (below.face.length() > 0)) {
// The polyhedron was actually cut; create a cap polygon
ConvexPolygon cap;
// Collect the final polgyon by sorting the edges
int numVertices = edge.length();
/*debugPrintf("\n");
for (int xx=0; xx < numVertices; xx++) {
std::string s1 = edge[xx].start.toString();
std::string s2 = edge[xx].stop.toString();
debugPrintf("%s -> %s\n", s1.c_str(), s2.c_str());
}
*/
// Need at least three points to make a polygon
debugAssert(numVertices >= 3);
Vector3 last_vertex = edge.last().stop;
cap._vertex.append(last_vertex);
// Search for the next _vertex. Because of accumulating
// numerical error, we have to find the closest match, not
// just the one we expect.
for (int v = numVertices - 1; v >= 0; v--) {
// matching edge index
int index = 0;
int num = edge.length();
double distance = (edge[index].start - last_vertex).squaredMagnitude();
for (int e = 1; e < num; e++) {
double d = (edge[e].start - last_vertex).squaredMagnitude();
if (d < distance) {
// This is the new closest one
index = e;
distance = d;
}
}
// Don't tolerate ridiculous error.
debugAssertM(distance < 0.02, "Edge missing while closing polygon.");
last_vertex = edge[index].stop;
cap._vertex.append(last_vertex);
}
//debugPrintf("\n");
//debugPrintf("Cap (both) %f\n", cap.getArea());
above.face.append(cap);
below.face.append(cap.inverse());
}
// Make sure we put enough faces on each polyhedra
debugAssert((above.face.length() == 0) || (above.face.length() >= 4));
debugAssert((below.face.length() == 0) || (below.face.length() >= 4));
}
///////////////////////////////////////////////
ConvexPolygon2D::ConvexPolygon2D(const Array<Vector2>& pts, bool reverse) : m_vertex(pts) {
if (reverse) {
m_vertex.reverse();
}
}
bool ConvexPolygon2D::contains(const Vector2& p, bool reverse) const {
// Compute the signed area of each polygon from p to an edge.
// If the area is non-negative for all polygons then p is inside
// the polygon. (To adapt this algorithm for a concave polygon,
// the *sum* of the areas must be non-negative).
float r = reverse ? -1 : 1;
for (int i0 = 0; i0 < m_vertex.size(); ++i0) {
int i1 = (i0 + 1) % m_vertex.size();
const Vector2& v0 = m_vertex[i0];
const Vector2& v1 = m_vertex[i1];
Vector2 e0 = v0 - p;
Vector2 e1 = v1 - p;
// Area = (1/2) cross product, negated to be ccw in
// a 2D space; we neglect the 1/2
float area = -(e0.x * e1.y - e0.y * e1.x);
if (area * r < 0) {
return false;
}
}
return true;
}
}
-381
View File
@@ -1,381 +0,0 @@
/**
@file CoordinateFrame.cpp
Coordinate frame class
@maintainer Morgan McGuire, [email protected]
@created 2001-06-02
@edited 2008-07-13
*/
#include "G3D/platform.h"
#include "G3D/CoordinateFrame.h"
#include "G3D/Quat.h"
#include "G3D/Matrix4.h"
#include "G3D/Box.h"
#include "G3D/AABox.h"
#include "G3D/Sphere.h"
#include "G3D/Triangle.h"
#include "G3D/Ray.h"
#include "G3D/Capsule.h"
#include "G3D/Cylinder.h"
#include "G3D/UprightFrame.h"
namespace G3D {
CoordinateFrame::CoordinateFrame(const class UprightFrame& f) {
*this = f.toCoordinateFrame();
}
CoordinateFrame CoordinateFrame::fromXYZYPRRadians(float x, float y, float z, float yaw,
float pitch, float roll) {
Matrix3 rotation = Matrix3::fromAxisAngle(Vector3::unitY(), yaw);
rotation = Matrix3::fromAxisAngle(rotation.column(0), pitch) * rotation;
rotation = Matrix3::fromAxisAngle(rotation.column(2), roll) * rotation;
const Vector3 translation(x, y, z);
return CoordinateFrame(rotation, translation);
}
void CoordinateFrame::getXYZYPRRadians(float& x, float& y, float& z,
float& yaw, float& pitch, float& roll) const {
x = translation.x;
y = translation.y;
z = translation.z;
const Vector3& look = lookVector();
if (abs(look.y) > 0.99f) {
// Looking nearly straight up or down
yaw = G3D::pi() + atan2(look.x, look.z);
pitch = asin(look.y);
roll = 0.0f;
} else {
// Yaw cannot be affected by others, so pull it first
yaw = G3D::pi() + atan2(look.x, look.z);
// Pitch is the elevation of the yaw vector
pitch = asin(look.y);
Vector3 actualRight = rightVector();
Vector3 expectedRight = look.cross(Vector3::unitY());
roll = 0;//acos(actualRight.dot(expectedRight)); TODO
}
}
void CoordinateFrame::getXYZYPRDegrees(float& x, float& y, float& z,
float& yaw, float& pitch, float& roll) const {
getXYZYPRRadians(x, y, z, yaw, pitch, roll);
yaw = toDegrees(yaw);
pitch = toDegrees(pitch);
roll = toDegrees(roll);
}
CoordinateFrame CoordinateFrame::fromXYZYPRDegrees(float x, float y, float z,
float yaw, float pitch, float roll) {
return fromXYZYPRRadians(x, y, z, toRadians(yaw), toRadians(pitch), toRadians(roll));
}
Ray CoordinateFrame::lookRay() const {
return Ray::fromOriginAndDirection(translation, lookVector());
}
bool CoordinateFrame::fuzzyEq(const CoordinateFrame& other) const {
for (int c = 0; c < 3; ++c) {
for (int r = 0; r < 3; ++r) {
if (! G3D::fuzzyEq(other.rotation[r][c], rotation[r][c])) {
return false;
}
}
if (! G3D::fuzzyEq(translation[c], other.translation[c])) {
return false;
}
}
return true;
}
bool CoordinateFrame::fuzzyIsIdentity() const {
const Matrix3& I = Matrix3::identity();
for (int c = 0; c < 3; ++c) {
for (int r = 0; r < 3; ++r) {
if (fuzzyNe(I[r][c], rotation[r][c])) {
return false;
}
}
if (fuzzyNe(translation[c], 0)) {
return false;
}
}
return true;
}
bool CoordinateFrame::isIdentity() const {
return
(translation == Vector3::zero()) &&
(rotation == Matrix3::identity());
}
Matrix4 CoordinateFrame::toMatrix4() const {
return Matrix4(*this);
}
std::string CoordinateFrame::toXML() const {
return G3D::format(
"<COORDINATEFRAME>\n %lf,%lf,%lf,%lf,\n %lf,%lf,%lf,%lf,\n %lf,%lf,%lf,%lf,\n %lf,%lf,%lf,%lf\n</COORDINATEFRAME>\n",
rotation[0][0], rotation[0][1], rotation[0][2], translation.x,
rotation[1][0], rotation[1][1], rotation[1][2], translation.y,
rotation[2][0], rotation[2][1], rotation[2][2], translation.z,
0.0, 0.0, 0.0, 1.0);
}
Plane CoordinateFrame::toObjectSpace(const Plane& p) const {
Vector3 N, P;
double d;
p.getEquation(N, d);
P = N * (float)d;
P = pointToObjectSpace(P);
N = normalToObjectSpace(N);
return Plane(N, P);
}
Plane CoordinateFrame::toWorldSpace(const Plane& p) const {
Vector3 N, P;
double d;
p.getEquation(N, d);
P = N * (float)d;
P = pointToWorldSpace(P);
N = normalToWorldSpace(N);
return Plane(N, P);
}
Triangle CoordinateFrame::toObjectSpace(const Triangle& t) const {
return Triangle(pointToObjectSpace(t.vertex(0)),
pointToObjectSpace(t.vertex(1)),
pointToObjectSpace(t.vertex(2)));
}
Triangle CoordinateFrame::toWorldSpace(const Triangle& t) const {
return Triangle(pointToWorldSpace(t.vertex(0)),
pointToWorldSpace(t.vertex(1)),
pointToWorldSpace(t.vertex(2)));
}
Cylinder CoordinateFrame::toWorldSpace(const Cylinder& c) const {
return Cylinder(
pointToWorldSpace(c.point(0)),
pointToWorldSpace(c.point(1)),
c.radius());
}
Capsule CoordinateFrame::toWorldSpace(const Capsule& c) const {
return Capsule(
pointToWorldSpace(c.point(0)),
pointToWorldSpace(c.point(1)),
c.radius());
}
Box CoordinateFrame::toWorldSpace(const AABox& b) const {
return toWorldSpace(Box(b));
}
Box CoordinateFrame::toWorldSpace(const Box& b) const {
Box out(b);
for (int i = 0; i < 8; ++i) {
out._corner[i] = pointToWorldSpace(out._corner[i]);
debugAssert(! isNaN(out._corner[i].x));
}
for (int i = 0; i < 3; ++i) {
out._axis[i] = vectorToWorldSpace(out._axis[i]);
}
out._center = pointToWorldSpace(out._center);
return out;
}
Box CoordinateFrame::toObjectSpace(const Box &b) const {
return inverse().toWorldSpace(b);
}
Box CoordinateFrame::toObjectSpace(const AABox& b) const {
return toObjectSpace(Box(b));
}
CoordinateFrame::CoordinateFrame(class BinaryInput& b) : rotation(Matrix3::zero()) {
deserialize(b);
}
void CoordinateFrame::deserialize(class BinaryInput& b) {
rotation.deserialize(b);
translation.deserialize(b);
}
void CoordinateFrame::serialize(class BinaryOutput& b) const {
rotation.serialize(b);
translation.serialize(b);
}
Sphere CoordinateFrame::toWorldSpace(const Sphere &b) const {
return Sphere(pointToWorldSpace(b.center), b.radius);
}
Sphere CoordinateFrame::toObjectSpace(const Sphere &b) const {
return Sphere(pointToObjectSpace(b.center), b.radius);
}
Ray CoordinateFrame::toWorldSpace(const Ray& r) const {
return Ray::fromOriginAndDirection(pointToWorldSpace(r.origin), vectorToWorldSpace(r.direction));
}
Ray CoordinateFrame::toObjectSpace(const Ray& r) const {
return Ray::fromOriginAndDirection(pointToObjectSpace(r.origin), vectorToObjectSpace(r.direction));
}
void CoordinateFrame::lookAt(const Vector3 &target) {
lookAt(target, Vector3::unitY());
}
void CoordinateFrame::lookAt(
const Vector3& target,
Vector3 up) {
up = up.direction();
Vector3 look = (target - translation).direction();
if (fabs(look.dot(up)) > .99f) {
up = Vector3::unitX();
if (fabs(look.dot(up)) > .99f) {
up = Vector3::unitY();
}
}
up -= look * look.dot(up);
up.unitize();
Vector3 z = -look;
Vector3 x = -z.cross(up);
x.unitize();
Vector3 y = z.cross(x);
rotation.setColumn(0, x);
rotation.setColumn(1, y);
rotation.setColumn(2, z);
}
CoordinateFrame CoordinateFrame::lerp(
const CoordinateFrame& other,
float alpha) const {
if (alpha == 1.0f) {
return other;
} else if (alpha == 0.0f) {
return *this;
} else {
Quat q1 = Quat(this->rotation);
Quat q2 = Quat(other.rotation);
return CoordinateFrame(
q1.slerp(q2, alpha).toRotationMatrix(),
this->translation * (1 - alpha) + other.translation * alpha);
}
}
void CoordinateFrame::pointToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
vout.resize(v.size());
for (int i = v.size() - 1; i >= 0; --i) {
vout[i] = pointToWorldSpace(v[i]);
}
}
void CoordinateFrame::normalToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
vout.resize(v.size());
for (int i = v.size() - 1; i >= 0; --i) {
vout[i] = normalToWorldSpace(v[i]);
}
}
void CoordinateFrame::vectorToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
vout.resize(v.size());
for (int i = v.size() - 1; i >= 0; --i) {
vout[i] = vectorToWorldSpace(v[i]);
}
}
void CoordinateFrame::pointToObjectSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
vout.resize(v.size());
for (int i = v.size() - 1; i >= 0; --i) {
vout[i] = pointToObjectSpace(v[i]);
}
}
void CoordinateFrame::normalToObjectSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
vout.resize(v.size());
for (int i = v.size() - 1; i >= 0; --i) {
vout[i] = normalToObjectSpace(v[i]);
}
}
void CoordinateFrame::vectorToObjectSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
vout.resize(v.size());
for (int i = v.size() - 1; i >= 0; --i) {
vout[i] = vectorToObjectSpace(v[i]);
}
}
} // namespace
-70
View File
@@ -1,70 +0,0 @@
/**
@file Crypto.cpp
@author Morgan McGuire, [email protected]
@created 2006-03-28
@edited 2006-04-06
*/
#include "G3D/platform.h"
#include "G3D/Crypto.h"
#include "G3D/g3dmath.h"
#include <zlib.h>
namespace G3D {
int Crypto::smallPrime(int n) {
debugAssert(n < numSmallPrimes() && n >= 0);
// From:
// http://primes.utm.edu/lists/small/1000.txt
static const int table[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013,
1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373,
1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657,
1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
1993, 1997, 1999};
return table[n];
}
int Crypto::numSmallPrimes() {
return 303;
}
uint32 Crypto::crc32(const void* byte, size_t numBytes) {
return ::crc32(::crc32(0, Z_NULL, 0), static_cast<const Bytef *>(byte), numBytes);
}
} // G3D
-471
View File
@@ -1,471 +0,0 @@
/**
@file Crypto_md5.cpp
@author Morgan McGuire, [email protected]
Copyright 2006-2007, Morgan McGuire. All rights reserved.
@created 2006-03-28
@edited 2006-04-06
*/
#include "G3D/platform.h"
#include "G3D/Crypto.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include <cstring>
namespace G3D {
MD5Hash::MD5Hash(class BinaryInput& b) {
deserialize(b);
}
void MD5Hash::deserialize(class BinaryInput& b) {
b.readBytes(value, 16);
}
void MD5Hash::serialize(class BinaryOutput& b) const {
b.writeBytes(value, 16);
}
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
#ifdef __cplusplus
extern "C"
{
#endif
/* Initialize the algorithm. */
static void md5_init(md5_state_t *pms);
/* Append a string to the message. */
static void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
/* Finish the message and return the digest. */
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
#ifdef __cplusplus
}
#endif
MD5Hash Crypto::md5(const void* data, size_t n) {
md5_state_t state;
md5_init(&state);
md5_append(&state, (const uint8*)data, (int)n);
MD5Hash h;
md5_finish(&state, &(h[0]));
return h;
}
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
[email protected]
*/
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.c is L. Peter Deutsch
<[email protected]>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
either statically or dynamically; added missing #include <string.h>
in library.
2002-03-11 lpd Corrected argument list for main(), and added int return
type, in test program and T value program.
2002-02-21 lpd Added missing #include <stdio.h> in test program.
2000-07-03 lpd Patched to eliminate warnings about "constant is
unsigned in ANSI C, signed in traditional"; made test program
self-checking.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1999-05-03 lpd Original version.
*/
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
#if defined(G3D_LINUX) || defined(G3D_OSX)
# if defined(G3D_OSX_PPC)
# include <ppc/endian.h>
# elif defined(G3D_OSX_INTEL)
# include <i386/endian.h>
# elif defined(__linux__)
# include <endian.h>
# elif defined(__FreeBSD__)
# include <sys/endian.h>
# endif
#else
# define BYTE_ORDER 0
#endif
#define T_MASK ((md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 0x242070db
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 0x4787c62a
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 0x698098d8
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 0x6b901122
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 0x49b40821
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 0x265e5a51
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 0x02441453
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 0x21e1cde6
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 0x455a14ed
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 0x676f02d9
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 0x6d9d6122
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 0x4bdecfa9
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 0x289b7ec6
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 0x04881d05
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 0x1fa27cf8
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 0x432aff97
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 0x655b59c3
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 0x6fa87e4f
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 0x4e0811a1
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 0x2ad7d2bb
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
static void
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
{
md5_word_t
a = pms->abcd[0], b = pms->abcd[1],
c = pms->abcd[2], d = pms->abcd[3];
md5_word_t t;
#if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
const md5_word_t *X;
#endif
{
#if BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static const int w = 1;
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
#endif
#if BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (const md5_byte_t *)0) & 3)) {
/* data are properly aligned */
X = (const md5_word_t *)data;
} else {
/* not aligned */
memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const md5_byte_t *xp = data;
int i;
# if BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
# else
# define xbuf X /* (static only) */
# endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + F(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + G(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti)\
t = a + H(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + I(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
void
md5_init(md5_state_t *pms)
{
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
void
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
{
const md5_byte_t *p = data;
int left = nbytes;
int offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += nbytes >> 29;
pms->count[0] += nbits;
if (pms->count[0] < nbits)
pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p);
/* Process a final partial block. */
if (left)
memcpy(pms->buf, p, left);
}
void
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
{
static const md5_byte_t pad[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}
}
-176
View File
@@ -1,176 +0,0 @@
/**
@file Cylinder.cpp
@maintainer Morgan McGuire, [email protected]
@created 2003-02-07
@edited 2006-02-18
Copyright 2000-2006, Morgan McGuire.
All rights reserved.
*/
#include "G3D/platform.h"
#include "G3D/Cylinder.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/LineSegment.h"
#include "G3D/CoordinateFrame.h"
#include "G3D/Line.h"
#include "G3D/AABox.h"
namespace G3D {
Cylinder::Cylinder(class BinaryInput& b) {
deserialize(b);
}
Cylinder::Cylinder() {
}
Cylinder::Cylinder(const Vector3& _p1, const Vector3& _p2, float _r)
: p1(_p1), p2(_p2), mRadius(_r) {
}
void Cylinder::serialize(class BinaryOutput& b) const {
p1.serialize(b);
p2.serialize(b);
b.writeFloat64(mRadius);
}
void Cylinder::deserialize(class BinaryInput& b) {
p1.deserialize(b);
p2.deserialize(b);
mRadius = b.readFloat64();
}
Line Cylinder::axis() const {
return Line::fromTwoPoints(p1, p2);
}
float Cylinder::radius() const {
return mRadius;
}
float Cylinder::volume() const {
return
(float)pi() * square(mRadius) * (p1 - p2).magnitude();
}
float Cylinder::area() const {
return
// Sides
(twoPi() * mRadius) * height() +
// Caps
twoPi() * square(mRadius);
}
void Cylinder::getBounds(AABox& out) const {
Vector3 min = p1.min(p2) - (Vector3(1, 1, 1) * mRadius);
Vector3 max = p1.max(p2) + (Vector3(1, 1, 1) * mRadius);
out = AABox(min, max);
}
bool Cylinder::contains(const Vector3& p) const {
return LineSegment::fromTwoPoints(p1, p2).distanceSquared(p) <= square(mRadius);
}
void Cylinder::getReferenceFrame(CoordinateFrame& cframe) const {
cframe.translation = center();
Vector3 Y = (p1 - p2).direction();
Vector3 X = (abs(Y.dot(Vector3::unitX())) > 0.9) ? Vector3::unitY() : Vector3::unitX();
Vector3 Z = X.cross(Y).direction();
X = Y.cross(Z);
cframe.rotation.setColumn(0, X);
cframe.rotation.setColumn(1, Y);
cframe.rotation.setColumn(2, Z);
}
void Cylinder::getRandomSurfacePoint(Vector3& p, Vector3& N) const {
float h = height();
float r = radius();
// Create a random point on a standard cylinder and then rotate to the global frame.
// Relative areas (factor of 2PI already taken out)
float capRelArea = square(r) / 2.0f;
float sideRelArea = r * h;
float r1 = uniformRandom(0, capRelArea * 2 + sideRelArea);
if (r1 < capRelArea * 2) {
// Select a point uniformly at random on a disk
// @cite http://mathworld.wolfram.com/DiskPointPicking.html
float a = uniformRandom(0, (float)twoPi());
float r2 = sqrt(uniformRandom(0, 1)) * r;
p.x = cos(a) * r2;
p.z = sin(a) * r2;
N.x = 0;
N.z = 0;
if (r1 < capRelArea) {
// Top
p.y = h / 2.0f;
N.y = 1;
} else {
// Bottom
p.y = -h / 2.0f;
N.y = -1;
}
} else {
// Side
float a = uniformRandom(0, (float)twoPi());
N.x = cos(a);
N.y = 0;
N.z = sin(a);
p.x = N.x * r;
p.z = N.y * r;
p.y = uniformRandom(-h / 2.0f, h / 2.0f);
}
// Transform to world space
CoordinateFrame cframe;
getReferenceFrame(cframe);
p = cframe.pointToWorldSpace(p);
N = cframe.normalToWorldSpace(N);
}
Vector3 Cylinder::randomInteriorPoint() const {
float h = height();
float r = radius();
// Create a random point in a standard cylinder and then rotate to the global frame.
// Select a point uniformly at random on a disk
// @cite http://mathworld.wolfram.com/DiskPointPicking.html
float a = uniformRandom(0, (float)twoPi());
float r2 = sqrt(uniformRandom(0, 1)) * r;
Vector3 p( cos(a) * r2,
uniformRandom(-h / 2.0f, h / 2.0f),
sin(a) * r2);
// Transform to world space
CoordinateFrame cframe;
getReferenceFrame(cframe);
return cframe.pointToWorldSpace(p);
}
} // namespace
-170
View File
@@ -1,170 +0,0 @@
/**
@file Discovery.cpp
@maintainer Morgan McGuire, [email protected]
@created 2003-06-26
@edited 2005-02-24
*/
#include "G3D/Discovery.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include <cstring>
namespace G3D {
///////////////////////////////////////////////////////////////////////////////////////////
void DiscoveryAdvertisement::serialize(BinaryOutput& b) const {
address.serialize(b);
}
void DiscoveryAdvertisement::deserialize(BinaryInput& b) {
address.deserialize(b);
lastUpdateTime = System::time();
}
///////////////////////////////////////////////////////////////////////////////////////////
void DiscoveryServerAddressMessage::serialize(BinaryOutput& b) const {
b.writeString(G3D_DISCOVERY_PROTOCOL_NAME);
b.writeInt32(G3D_DISCOVERY_PROTOCOL_VERSION);
b.writeString(settings->appProtocolName);
b.writeInt32(settings->appProtocolVersion);
// Send addresses
b.writeInt32(address.size());
for (int i = 0; i < address.size(); ++i) {
address[i].serialize(b);
}
}
void DiscoveryServerAddressMessage::deserialize(BinaryInput& b) {
address.clear();
correctProtocol = false;
serverProtocolVersion[0] = 0;
serverProtocolVersion[1] = 0;
// Verify that we are on the same protocol
if (b.readString(strlen(G3D_DISCOVERY_PROTOCOL_NAME) + 1) != G3D_DISCOVERY_PROTOCOL_NAME) {
return;
}
serverProtocolVersion[0] = b.readInt32();
if (serverProtocolVersion[0] != G3D_DISCOVERY_PROTOCOL_VERSION) {
return;
}
if (b.readString() != settings->appProtocolName) {
return;
}
serverProtocolVersion[1] = b.readInt32();
if (serverProtocolVersion[1] != settings->appProtocolVersion) {
return;
}
correctProtocol = true;
address.resize(b.readInt32());
for (int i = 0; i < address.size(); ++i) {
address[i].deserialize(b);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
void DiscoveryServer::sendAnnouncement() const {
NetAddress broadcast(NetworkDevice::instance()->broadcastAddressArray()[0], settings->serverBroadcastPort);
net->send(broadcast, SERVER_BROADCAST_MESSAGE, addressMessage);
const_cast<DiscoveryServer*>(this)->lastBroadcast = System::time();
}
void DiscoveryServer::sendShutDown() const {
NetAddress broadcast(NetworkDevice::instance()->broadcastAddressArray()[0], settings->serverBroadcastPort);
ShutdownMessage s;
net->send(broadcast, SERVER_SHUTDOWN_MESSAGE, s);
}
bool DiscoveryServer::ok() const {
return listener->ok() && net->ok();
}
void DiscoveryServer::init(
const DiscoverySettings* _settings,
DiscoveryAdvertisement* _advertisement) {
Discovery::init(_settings);
advertisement = _advertisement;
addressMessage.settings = settings;
NetworkDevice::instance()->localHostAddresses(addressMessage.address);
// Set the port number
for (int i = 0; i < addressMessage.address.size(); ++i) {
addressMessage.address[i] =
NetAddress(addressMessage.address[i].ip(),
settings->serverAdvertisementPort);
}
net = LightweightConduit::create(settings->clientBroadcastPort, true, true);
listener = NetListener::create(settings->serverAdvertisementPort);
// Send initial announcement
sendAnnouncement();
}
void DiscoveryServer::doNetwork() {
const RealTime UNSOLICITED_BROADCAST_PERIOD = 60;
// Check for client broadcast requests
if (net->messageWaiting()) {
// Some client broadcast that it is looking for servers.
// Respond by sending out our announcement to everyone
// (avoids having to figure out if the message return address
// is correct).
NetAddress dummy;
net->receive(dummy);
sendAnnouncement();
} else if (System::time() > lastBroadcast + UNSOLICITED_BROADCAST_PERIOD) {
sendAnnouncement();
}
// Handle incoming connections
if (listener->clientWaiting()) {
// Respond to this client
ReliableConduitRef client = listener->waitForConnection();
client->send(SERVER_BROADCAST_MESSAGE, *advertisement);
}
}
void DiscoveryServer::cleanup() {
sendShutDown();
}
//////////////////////////////////////////////////////////////////////////////////
std::string IncompatibleServerDescription::toString() const {
return std::string("Incompatible server at ") + address.toString() +
format(", version %d.%d", protocolVersion[0], protocolVersion[1]);
}
//////////////////////////////////////////////////////////////////////////////////
}
-399
View File
@@ -1,399 +0,0 @@
/**
@file GCamera.cpp
@author Morgan McGuire, [email protected]
@author Jeff Marsceill, [email protected]
@created 2005-07-20
@edited 2007-07-24
*/
#include "G3D/GCamera.h"
#include "G3D/platform.h"
#include "G3D/Rect2D.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/Ray.h"
#include "G3D/Matrix4.h"
namespace G3D {
GCamera::GCamera() {
setNearPlaneZ(-0.1f);
setFarPlaneZ(-(float)inf());
setFieldOfView((float)toRadians(55.0f), VERTICAL);
}
GCamera::~GCamera() {
}
void GCamera::getCoordinateFrame(CoordinateFrame& c) const {
c = m_cframe;
}
void GCamera::setCoordinateFrame(const CoordinateFrame& c) {
m_cframe = c;
}
void GCamera::setFieldOfView(float angle, FOVDirection dir) {
debugAssert((angle < pi()) && (angle > 0));
m_fieldOfView = angle;
m_direction = dir;
}
float GCamera::imagePlaneDepth() const{
return -m_nearPlaneZ;
}
float GCamera::viewportWidth(const Rect2D& viewport) const {
// Compute the side of a square at the near plane based on our field of view
float s = 2.0f * -m_nearPlaneZ * tan(m_fieldOfView * 0.5f);
if (m_direction == VERTICAL) {
s *= viewport.width() / viewport.height();
}
return s;
}
float GCamera::viewportHeight(const Rect2D& viewport) const {
// Compute the side of a square at the near plane based on our field of view
float s = 2.0f * -m_nearPlaneZ * tan(m_fieldOfView * 0.5f);
if (m_direction == HORIZONTAL) {
s *= viewport.height() / viewport.width();
}
return s;
}
Ray GCamera::worldRay(float x, float y, const Rect2D& viewport) const {
int screenWidth = iFloor(viewport.width());
int screenHeight = iFloor(viewport.height());
Ray out;
out.origin = m_cframe.translation;
float cx = screenWidth / 2.0f;
float cy = screenHeight / 2.0f;
out.direction = Vector3( (x - cx) * viewportWidth(viewport) / screenWidth,
-(y - cy) * viewportHeight(viewport) / screenHeight,
(m_nearPlaneZ) );
out.direction = m_cframe.vectorToWorldSpace(out.direction);
// Normalize the direction (we didn't do it before)
out.direction = out.direction.direction();
return out;
}
/**
This is the matrix that a RenderDevice (or OpenGL) uses as the projection matrix.
@sa RenderDevice::setProjectionAndCameraMatrix, RenderDevice::setProjectionMatrix, Matrix4::perspectiveProjection
*/
void GCamera::getProjectUnitMatrix(const Rect2D& viewport, Matrix4& P) const{
float screenWidth = viewport.width();
float screenHeight = viewport.height();
float r, l, t, b, n, f, x, y;
if(m_direction == VERTICAL){
y = -m_nearPlaneZ * tan(m_fieldOfView / 2);
x = y * (screenWidth / screenHeight);
}
else{ //m_direction == HORIZONTAL
x = -m_nearPlaneZ * tan(m_fieldOfView / 2);
y = x * (screenHeight / screenWidth);
}
n = -m_nearPlaneZ;
f = -m_farPlaneZ;
r = x;
l = -x;
t = y;
b = -y;
P = Matrix4::perspectiveProjection(l, r, b, t, n, f);
}
Vector3 GCamera::projectUnit(const Vector3& point, const Rect2D& viewport) const {
Matrix4 M;
getProjectUnitMatrix(viewport, M);
Vector4 cameraSpacePoint(coordinateFrame().pointToObjectSpace(point), 1.0f);
const Vector4& screenSpacePoint = M * cameraSpacePoint;
return Vector3(screenSpacePoint.xyz() / screenSpacePoint.w);
}
Vector3 GCamera::project(const Vector3& point,
const Rect2D& viewport) const {
// Find the point in the homogeneous cube
const Vector3& cube = projectUnit(point, viewport);
return convertFromUnitToNormal(cube, viewport);
}
Vector3 GCamera::unprojectUnit(const Vector3& v, const Rect2D& viewport) const {
const Vector3& projectedPoint = convertFromUnitToNormal(v, viewport);
return unproject(projectedPoint, viewport);
}
Vector3 GCamera::unproject(const Vector3& v, const Rect2D& viewport) const {
const float n = m_nearPlaneZ;
const float f = m_farPlaneZ;
float z;
if (-f >= inf()) {
// Infinite far plane
z = 1.0f / (((-1.0f / n) * v.z) + 1.0f / n);
} else {
z = 1.0f / ((((1.0f / f) - (1.0f / n)) * v.z) + 1.0f / n);
}
const Ray& ray = worldRay(v.x, v.y, viewport);
// Find out where the ray reaches the specified depth.
const Vector3& out = ray.origin + ray.direction * -z / (ray.direction.dot(m_cframe.lookVector()));
return out;
}
float GCamera::worldToScreenSpaceArea(float area, float z, const Rect2D& viewport) const {
if (z >= 0) {
return (float)inf();
}
return area * (float)square(imagePlaneDepth() / z);
}
void GCamera::getClipPlanes(
const Rect2D& viewport,
Array<Plane>& clip) const {
Frustum fr;
frustum(viewport, fr);
clip.resize(fr.faceArray.size(), DONT_SHRINK_UNDERLYING_ARRAY);
for (int f = 0; f < clip.size(); ++f) {
clip[f] = fr.faceArray[f].plane;
}
}
GCamera::Frustum GCamera::frustum(const Rect2D& viewport) const {
Frustum f;
frustum(viewport, f);
return f;
}
void GCamera::frustum(const Rect2D& viewport, Frustum& fr) const {
// The volume is the convex hull of the vertices definining the view
// frustum and the light source point at infinity.
const float x = viewportWidth(viewport) / 2;
const float y = viewportHeight(viewport) / 2;
const float z = m_nearPlaneZ;
const float w = z / -m_farPlaneZ;
float fovx;
fovx = m_fieldOfView;
if (m_direction == VERTICAL) {
fovx *= x / y;
}
// Near face (ccw from UR)
fr.vertexPos.append(
Vector4( x, y, z, 1),
Vector4(-x, y, z, 1),
Vector4(-x, -y, z, 1),
Vector4( x, -y, z, 1));
// Far face (ccw from UR, from origin)
fr.vertexPos.append(
Vector4( x, y, z, w),
Vector4(-x, y, z, w),
Vector4(-x, -y, z, w),
Vector4( x, -y, z, w));
Frustum::Face face;
// Near plane (wind backwards so normal faces into frustum)
// Recall that nearPlane, farPlane are positive numbers, so
// we need to negate them to produce actual z values.
face.plane = Plane(Vector3(0,0,-1), Vector3(0,0,m_nearPlaneZ));
face.vertexIndex[0] = 3;
face.vertexIndex[1] = 2;
face.vertexIndex[2] = 1;
face.vertexIndex[3] = 0;
fr.faceArray.append(face);
// Right plane
face.plane = Plane(Vector3(-cosf(fovx/2), 0, -sinf(fovx/2)), Vector3::zero());
face.vertexIndex[0] = 0;
face.vertexIndex[1] = 4;
face.vertexIndex[2] = 7;
face.vertexIndex[3] = 3;
fr.faceArray.append(face);
// Left plane
face.plane = Plane(Vector3(-fr.faceArray.last().plane.normal().x, 0, fr.faceArray.last().plane.normal().z), Vector3::zero());
face.vertexIndex[0] = 5;
face.vertexIndex[1] = 1;
face.vertexIndex[2] = 2;
face.vertexIndex[3] = 6;
fr.faceArray.append(face);
// Top plane
face.plane = Plane(Vector3(0, -cosf(m_fieldOfView/2.0f), -sinf(m_fieldOfView/2.0f)), Vector3::zero());
face.vertexIndex[0] = 1;
face.vertexIndex[1] = 5;
face.vertexIndex[2] = 4;
face.vertexIndex[3] = 0;
fr.faceArray.append(face);
// Bottom plane
face.plane = Plane(Vector3(0, -fr.faceArray.last().plane.normal().y, fr.faceArray.last().plane.normal().z), Vector3::zero());
face.vertexIndex[0] = 2;
face.vertexIndex[1] = 3;
face.vertexIndex[2] = 7;
face.vertexIndex[3] = 6;
fr.faceArray.append(face);
// Far plane
if (-m_farPlaneZ < inf()) {
face.plane = Plane(Vector3(0, 0, 1), Vector3(0, 0, m_farPlaneZ));
face.vertexIndex[0] = 4;
face.vertexIndex[1] = 5;
face.vertexIndex[2] = 6;
face.vertexIndex[3] = 7;
fr.faceArray.append(face);
}
// Transform vertices to world space
for (int v = 0; v < fr.vertexPos.size(); ++v) {
fr.vertexPos[v] = m_cframe.toWorldSpace(fr.vertexPos[v]);
}
// Transform planes to world space
for (int p = 0; p < fr.faceArray.size(); ++p) {
// Since there is no scale factor, we don't have to
// worry about the inverse transpose of the normal.
Vector3 normal;
float d;
fr.faceArray[p].plane.getEquation(normal, d);
Vector3 newNormal = m_cframe.rotation * normal;
if (isFinite(d)) {
d = (newNormal * -d + m_cframe.translation).dot(newNormal);
fr.faceArray[p].plane = Plane(newNormal, newNormal * d);
} else {
// When d is infinite, we can't multiply 0's by it without
// generating NaNs.
fr.faceArray[p].plane = Plane::fromEquation(newNormal.x, newNormal.y, newNormal.z, d);
}
}
}
void GCamera::getNearViewportCorners(
const Rect2D& viewport,
Vector3& outUR,
Vector3& outUL,
Vector3& outLL,
Vector3& outLR) const {
// Must be kept in sync with getFrustum()
const float w = viewportWidth(viewport) / 2.0f;
const float h = viewportHeight(viewport) / 2.0f;
const float z = nearPlaneZ();
// Compute the points
outUR = Vector3( w, h, z);
outUL = Vector3(-w, h, z);
outLL = Vector3(-w, -h, z);
outLR = Vector3( w, -h, z);
// Take to world space
outUR = m_cframe.pointToWorldSpace(outUR);
outUL = m_cframe.pointToWorldSpace(outUL);
outLR = m_cframe.pointToWorldSpace(outLR);
outLL = m_cframe.pointToWorldSpace(outLL);
}
void GCamera::getFarViewportCorners(
const Rect2D& viewport,
Vector3& outUR,
Vector3& outUL,
Vector3& outLL,
Vector3& outLR) const {
// Must be kept in sync with getFrustum()
const float w = viewportWidth(viewport) * m_farPlaneZ / m_nearPlaneZ;
const float h = viewportHeight(viewport) * m_farPlaneZ / m_nearPlaneZ;
const float z = m_farPlaneZ;
// Compute the points
outUR = Vector3( w, h, z);
outUL = Vector3(-w, h, z);
outLL = Vector3(-w, -h, z);
outLR = Vector3( w, -h, z);
// Take to world space
outUR = m_cframe.pointToWorldSpace(outUR);
outUL = m_cframe.pointToWorldSpace(outUL);
outLR = m_cframe.pointToWorldSpace(outLR);
outLL = m_cframe.pointToWorldSpace(outLL);
}
void GCamera::setPosition(const Vector3& t) {
m_cframe.translation = t;
}
void GCamera::lookAt(const Vector3& position, const Vector3& up) {
m_cframe.lookAt(position, up);
}
void GCamera::serialize(BinaryOutput& bo) const {
bo.writeFloat32(m_fieldOfView);
bo.writeFloat32(imagePlaneDepth());
debugAssert(nearPlaneZ() < 0.0f);
bo.writeFloat32(nearPlaneZ());
debugAssert(farPlaneZ() < 0.0f);
bo.writeFloat32(farPlaneZ());
m_cframe.serialize(bo);
bo.writeInt8(m_direction);
}
void GCamera::deserialize(BinaryInput& bi) {
m_fieldOfView = bi.readFloat32();
m_nearPlaneZ = bi.readFloat32();
debugAssert(m_nearPlaneZ < 0.0f);
m_farPlaneZ = bi.readFloat32();
debugAssert(m_farPlaneZ < 0.0f);
m_cframe.deserialize(bi);
m_direction = (FOVDirection)bi.readInt8();
}
Vector3 GCamera::convertFromUnitToNormal(const Vector3& in, const Rect2D& viewport) const{
return (in + Vector3(1,1,1)) * 0.5 * Vector3(viewport.width(), -viewport.height(), 1) +
Vector3(viewport.x0(), viewport.y1(), 0);
}
} // namespace
File diff suppressed because it is too large Load Diff
-298
View File
@@ -1,298 +0,0 @@
/**
@file GImage_bayer.cpp
@author Morgan McGuire, [email protected]
@created 2002-05-27
@edited 2006-05-10
*/
#include "G3D/platform.h"
#include "G3D/GImage.h"
namespace G3D {
void GImage::BAYER_G8B8_R8G8_to_Quarter_R8G8B8(int width, int height, const uint8* in, uint8* out) {
debugAssert(in != out);
int halfHeight = height / 2;
int halfWidth = width / 2;
int dst_off = 0;
for (int y = 0; y < halfHeight; ++y) {
for (int x = 0; x < halfWidth; ++x) {
// GBRG
int src_off = x*2 + y*2*width;
out[dst_off] = in[src_off+width]; // red
out[dst_off+1] = ((int)in[src_off] + (int)in[src_off+width+1])/2; // green
out[dst_off+2] = in[src_off+1]; // blue
dst_off = dst_off + 3;
}
}
}
void GImage::Quarter_R8G8B8_to_BAYER_G8B8_R8G8(int inWidth, int inHeight, const uint8* in, uint8* out) {
// Undo quarter-size Bayer as best we can. This code isn't very efficient, but it
// also isn't used very frequently.
debugAssert(out != in);
int outWidth = 2 * inWidth;
int outHeight = 2 * inHeight;
for (int y = 0; y < outHeight; ++y) {
for (int x = 0; x < outWidth; ++x) {
const Color3uint8* inp = ((const Color3uint8*)in) + ((x/2) + (y/2)* inWidth);
uint8* outp = out + x + y * outWidth;
if (isEven(y)) {
// GB row
if (isEven(x)) {
// Green
*outp = inp->g;
} else {
// Blue
*outp = inp->b;
}
} else {
// RG row
if (isEven(x)) {
// Red
*outp = inp->r;
} else {
// Green
*outp = inp->g;
}
}
}
}
}
/** Applies a 5x5 filter to monochrome image I (wrapping at the boundaries) */
static uint8 applyFilter(
const uint8* I,
int x,
int y,
int w,
int h,
const float filter[5][5]) {
debugAssert(isEven(w));
debugAssert(isEven(h));
float sum = 0.0f;
float denom = 0.0f;
for (int dy = 0; dy < 5; ++dy) {
int offset = ((y + dy + h - 2) % h) * w;
for (int dx = 0; dx < 5; ++dx) {
float f = filter[dy][dx];
sum += f * I[((x + dx + w - 2) % w) + offset];
denom += f;
}
}
return (uint8)iClamp(iRound(sum / denom), 0, 255);
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Bayer conversions
//
// There are two kinds of rows (GR and BG).
// In each row, there are two kinds of pixels (G/R, B/G).
// We express the four kinds of INPUT pixels as:
// GRG, GRG, BGB, BGG
//
// There are three kinds of OUTPUT pixels: R, G, B.
// Thus there are nominally 12 different I/O combinations,
// but several are impulses because needed output at that
// location *is* the input (e.g., G_GRG and G_BGG).
//
// The following 5x5 row-major filters are named as output_input.
// Green
static const float G_GRR[5][5] =
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
{ -1.0f, 2.0f, 4.0f, 2.0f, -1.0f},
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
static const float G_BGB[5][5] =
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
{ -1.0f, 2.0f, 4.0f, 2.0f, -1.0f},
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
// Red
//(the caption in the paper is wrong for this case:
// "R row B column really means R row G column"
static const float R_GRG[5][5] =
{{ 0.0f, 0.0f, 0.5f, 0.0f, 0.0f},
{ 0.0f, -1.0f, 0.0f, -1.0f, 0.0f},
{ -1.0f, 4.0f, 5.0f, 4.0f, -1.0f},
{ 0.0f, -1.0f, 0.0f, -1.0f, 0.0f},
{ 0.0f, 0.0f, 0.5f, 0.0f, 0.0f}};
static const float R_BGG[5][5] =
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
{ 0.0f, -1.0f, 4.0f, -1.0f, 0.0f},
{ 0.5f, 0.0f, 5.0f, 0.0f, 0.5f},
{ 0.0f, -1.0f, 4.0f, -1.0f, 0.0f},
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
static const float R_BGB[5][5] =
{{ 0.0f, 0.0f, -3.0f/2.0f, 0.0f, 0.0f},
{ 0.0f, 2.0f, 0.0f, 2.0f, 0.0f},
{-3.0f/2.0f, 0.0f, 6.0f, 0.0f, -3.0f/2.0f},
{ 0.0f, 2.0f, 0.0f, 2.0f, 0.0f},
{ 0.0f, 0.0f, -3.0f/2.0f, 0.0f, 0.0f}};
// Blue
//(the caption in the paper is wrong for this case:
// "B row R column really means B row G column")
#define B_BGG R_GRG
#define B_GRG R_BGG
#define B_GRR R_BGB
void GImage::BAYER_R8G8_G8B8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
debugAssert(in != _out);
Color3uint8* out = (Color3uint8*)_out;
for (int y = 0; y < h; ++y) {
// Row beginning in the input array.
int offset = y * w;
// RG row
for (int x = 0; x < w; ++x, ++out) {
// R pixel
{
out->r = in[x + offset];
out->g = applyFilter(in, x, y, w, h, G_GRR);
out->b = applyFilter(in, x, y, w, h, B_GRR);
}
++x; ++out;
// G pixel
{
out->r = applyFilter(in, x, y, w, h, R_GRG);
out->g = in[x + offset];
out->b = applyFilter(in, x, y, w, h, B_GRG);
}
}
++y;
offset += w;
// GB row
for (int x = 0; x < w; ++x, ++out) {
// G pixel
{
out->r = applyFilter(in, x, y, w, h, R_BGG);
out->g = in[x + offset];
out->b = applyFilter(in, x, y, w, h, B_BGG);
}
++x; ++out;
// B pixel
{
out->r = applyFilter(in, x, y, w, h, R_BGB);
out->g = applyFilter(in, x, y, w, h, G_BGB);
out->b = in[x + offset];
}
}
}
}
static void swapRedAndBlue(int N, Color3uint8* out) {
for (int i = N - 1; i >= 0; --i) {
uint8 tmp = out[i].r;
out[i].r = out[i].b;
out[i].b = tmp;
}
}
void GImage::BAYER_G8R8_B8G8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
// Run the equivalent function for red
BAYER_G8B8_R8G8_to_R8G8B8_MHC(w, h, in, _out);
// Now swap red and blue
swapRedAndBlue(w * h, (Color3uint8*)_out);
}
void GImage::BAYER_B8G8_G8R8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
// Run the equivalent function for red
BAYER_R8G8_G8B8_to_R8G8B8_MHC(w, h, in, _out);
// Now swap red and blue
swapRedAndBlue(w * h, (Color3uint8*)_out);
}
void GImage::BAYER_G8B8_R8G8_to_R8G8B8_MHC(int w, int h, const uint8* in, uint8* _out) {
debugAssert(in != _out);
Color3uint8* out = (Color3uint8*)_out;
for (int y = 0; y < h; ++y) {
// Row beginning in the input array.
int offset = y * w;
// GB row
for (int x = 0; x < w; ++x, ++out) {
// G pixel
{
out->r = applyFilter(in, x, y, w, h, R_BGG);
out->g = in[x + offset];
out->b = applyFilter(in, x, y, w, h, B_BGG);
}
++x; ++out;
// B pixel
{
out->r = applyFilter(in, x, y, w, h, R_BGB);
out->g = applyFilter(in, x, y, w, h, G_BGB);
out->b = in[x + offset];
}
}
++y;
offset += w;
// RG row
for (int x = 0; x < w; ++x, ++out) {
// R pixel
{
out->r = in[x + offset];
out->g = applyFilter(in, x, y, w, h, G_GRR);
out->b = applyFilter(in, x, y, w, h, B_GRR);
}
++x; ++out;
// G pixel
{
out->r = applyFilter(in, x, y, w, h, R_GRG);
out->g = in[x + offset];
out->b = applyFilter(in, x, y, w, h, B_GRG);
}
}
}
}
#undef B_BGG
#undef B_GRG
#undef B_GRR
}
-716
View File
@@ -1,716 +0,0 @@
/**
@file GImage_bmp.cpp
@author Morgan McGuire, [email protected]
@created 2002-05-27
@edited 2006-05-10
*/
#include "G3D/platform.h"
#include "G3D/GImage.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/Log.h"
namespace G3D {
#ifndef G3D_WIN32
/**
This is used by the Windows bitmap I/O.
*/
static const int BI_RGB = 0;
#endif
void GImage::encodeBMP(
BinaryOutput& out) const {
debugAssert(channels == 1 || channels == 3);
out.setEndian(G3D_LITTLE_ENDIAN);
uint8 red;
uint8 green;
uint8 blue;
int pixelBufferSize = width * height * 3;
int fileHeaderSize = 14;
int infoHeaderSize = 40;
int BMScanWidth;
int BMPadding;
// First write the BITMAPFILEHEADER
//
// WORD bfType;
// DWORD bfSize;
// WORD bfReserved1;
// WORD bfReserved2;
// DWORD bfOffBits;
// Type
out.writeUInt8('B');
out.writeUInt8('M');
// File size
out.writeUInt32(fileHeaderSize + infoHeaderSize + pixelBufferSize);
// Two reserved fields set to zero
out.writeUInt16(0);
out.writeUInt16(0);
// The offset, in bytes, from the BITMAPFILEHEADER structure
// to the bitmap bits.
out.writeUInt32(infoHeaderSize + fileHeaderSize);
// Now the BITMAPINFOHEADER
//
// DWORD biSize;
// LONG biWidth;
// LONG biHeight;
// WORD biPlanes;
// WORD biBitCount
// DWORD biCompression;
// DWORD biSizeImage;
// LONG biXPelsPerMeter;
// LONG biYPelsPerMeter;
// DWORD biClrUsed;
// DWORD biClrImportant;
// Size of the info header
out.writeUInt32(infoHeaderSize);
// Width and height of the image
out.writeUInt32(width);
out.writeUInt32(height);
// Planes ("must be set to 1")
out.writeUInt16(1);
// BitCount and CompressionType
out.writeUInt16(24);
out.writeUInt32(BI_RGB);
// Image size ("may be zero for BI_RGB bitmaps")
out.writeUInt32(0);
// biXPelsPerMeter
out.writeUInt32(0);
// biYPelsPerMeter
out.writeUInt32(0);
// biClrUsed
out.writeUInt32(0);
// biClrImportant
out.writeUInt32(0);
BMScanWidth = width * 3;
if (BMScanWidth & 3) {
BMPadding = 4 - (BMScanWidth & 3);
} else {
BMPadding = 0;
}
int hStart = height - 1;
int hEnd = -1;
int hDir = -1;
int dest;
// Write the pixel data
for (int h = hStart; h != hEnd; h += hDir) {
dest = channels * h * width;
for (int w = 0; w < width; ++w) {
if (channels == 3) {
red = _byte[dest];
green = _byte[dest + 1];
blue = _byte[dest + 2];
} else {
red = _byte[dest];
green = _byte[dest];
blue = _byte[dest];
}
out.writeUInt8(blue);
out.writeUInt8(green);
out.writeUInt8(red);
dest += channels;
}
if (BMPadding > 0) {
out.skip(BMPadding);
}
}
}
void GImage::decodeBMP(
BinaryInput& input) {
// The BMP decoding uses these flags.
static const uint16 PICTURE_NONE = 0x0000;
static const uint16 PICTURE_BITMAP = 0x1000;
// Compression Flags
static const uint16 PICTURE_UNCOMPRESSED = 0x0100;
static const uint16 PICTURE_MONOCHROME = 0x0001;
static const uint16 PICTURE_4BIT = 0x0002;
static const uint16 PICTURE_8BIT = 0x0004;
static const uint16 PICTURE_16BIT = 0x0008;
static const uint16 PICTURE_24BIT = 0x0010;
static const uint16 PICTURE_32BIT = 0x0020;
(void)PICTURE_16BIT;
(void)PICTURE_32BIT;
// This is a simple BMP loader that can handle uncompressed BMP files.
// Verify this is a BMP file by looking for the BM tag.
input.reset();
std::string tag = input.readString(2);
if (tag != "BM") {
throw Error("Not a BMP file", input.getFilename());
}
channels = 3;
// Skip to the BITMAPINFOHEADER's width and height
input.skip(16);
width = input.readUInt32();
height = input.readUInt32();
// Skip to the bit count and compression type
input.skip(2);
uint16 bitCount = input.readUInt16();
uint32 compressionType = input.readUInt32();
uint8 red;
uint8 green;
uint8 blue;
uint8 blank;
// Only uncompressed bitmaps are supported by this code
if ((int32)compressionType != BI_RGB) {
throw Error("BMP images must be uncompressed", input.getFilename());
}
uint8* palette = NULL;
// Create the palette if needed
if (bitCount <= 8) {
// Skip to the palette color count in the header
input.skip(12);
int numColors = input.readUInt32();
palette = (uint8*)System::malloc(numColors * 3);
debugAssert(palette);
// Skip past the end of the header to the palette info
input.skip(4);
int c;
for(c = 0; c < numColors * 3; c += 3) {
// Palette information in bitmaps is stored in BGR_ format.
// That means it's blue-green-red-blank, for each entry.
blue = input.readUInt8();
green = input.readUInt8();
red = input.readUInt8();
blank = input.readUInt8();
palette[c] = red;
palette[c + 1] = green;
palette[c + 2] = blue;
}
}
int hStart = 0;
int hEnd = 0;
int hDir = 0;
if (height < 0) {
height = -height;
hStart = 0;
hEnd = height;
hDir = 1;
} else {
//height = height;
hStart = height - 1;
hEnd = -1;
hDir = -1;
}
_byte = (uint8*)System::malloc(width * height * 3);
debugAssert(_byte);
int BMScanWidth;
int BMPadding;
uint8 BMGroup;
uint8 BMPixel8;
int currPixel;
int dest;
int flags = PICTURE_NONE;
if (bitCount == 1) {
// Note that this file is not necessarily grayscale, since it's possible
// the palette is blue-and-white, or whatever. But of course most image
// programs only write 1-bit images if they're black-and-white.
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_MONOCHROME;
// For bitmaps, each scanline is dword-aligned.
BMScanWidth = (width + 7) >> 3;
if (BMScanWidth & 3) {
BMScanWidth += 4 - (BMScanWidth & 3);
}
// Powers of 2
int pow2[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
for (int h = hStart; h != hEnd; h += hDir) {
currPixel = 0;
dest = 3 * h * width;
for (int w = 0; w < BMScanWidth; ++w) {
BMGroup = input.readUInt8();
// Now we read the pixels. Usually there are eight pixels per byte,
// since each pixel is represented by one bit, but if the width
// is not a multiple of eight, the last byte will have some bits
// set, with the others just being extra. Plus there's the
// dword-alignment padding. So we keep checking to see if we've
// already read "width" number of pixels.
for (int i = 7; i >= 0; --i) {
if (currPixel < width) {
int src = 3 * ((BMGroup & pow2[i]) >> i);
_byte[dest] = palette[src];
_byte[dest + 1] = palette[src + 1];
_byte[dest + 2] = palette[src + 2];
++currPixel;
dest += 3;
}
}
}
}
} else if (bitCount == 4) {
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_4BIT;
// For bitmaps, each scanline is dword-aligned.
int BMScanWidth = (width+1) >> 1;
if (BMScanWidth & 3) {
BMScanWidth += 4 - (BMScanWidth & 3);
}
for (int h = hStart; h != hEnd; h += hDir) {
currPixel = 0;
dest = 3 * h * width;
for (int w = 0; w < BMScanWidth; w++) {
BMGroup = input.readUInt8();
int src[2];
src[0] = 3 * ((BMGroup & 0xF0) >> 4);
src[1] = 3 * (BMGroup & 0x0F);
// Now we read the pixels. Usually there are two pixels per byte,
// since each pixel is represented by four bits, but if the width
// is not a multiple of two, the last byte will have only four bits
// set, with the others just being extra. Plus there's the
// dword-alignment padding. So we keep checking to see if we've
// already read "Width" number of pixels.
for (int i = 0; i < 2; ++i) {
if (currPixel < width) {
int tsrc = src[i];
_byte[dest] = palette[tsrc];
_byte[dest + 1] = palette[tsrc + 1];
_byte[dest + 2] = palette[tsrc + 2];
++currPixel;
dest += 3;
}
}
}
}
} else if (bitCount == 8) {
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_8BIT;
// For bitmaps, each scanline is dword-aligned.
BMScanWidth = width;
if (BMScanWidth & 3) {
BMScanWidth += 4 - (BMScanWidth & 3);
}
for (int h = hStart; h != hEnd; h += hDir) {
currPixel = 0;
for (int w = 0; w < BMScanWidth; ++w) {
BMPixel8 = input.readUInt8();
if (currPixel < width) {
dest = 3 * ((h * width) + currPixel);
int src = 3 * BMPixel8;
_byte[dest] = palette[src];
_byte[dest + 1] = palette[src + 1];
_byte[dest + 2] = palette[src + 2];
++currPixel;
}
}
}
} else if (bitCount == 16) {
System::free(_byte);
_byte = NULL;
System::free(palette);
palette = NULL;
throw Error("16-bit bitmaps not supported", input.getFilename());
} else if (bitCount == 24) {
input.skip(20);
flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_24BIT;
// For bitmaps, each scanline is dword-aligned.
BMScanWidth = width * 3;
if (BMScanWidth & 3) {
BMPadding = 4 - (BMScanWidth & 3);
} else {
BMPadding = 0;
}
for (int h = hStart; h != hEnd; h += hDir) {
dest = 3 * h * width;
for (int w = 0; w < width; ++w) {
blue = input.readUInt8();
green = input.readUInt8();
red = input.readUInt8();
_byte[dest] = red;
_byte[dest + 1] = green;
_byte[dest + 2] = blue;
dest += 3;
}
if (BMPadding) {
input.skip(2);
}
}
} else if (bitCount == 32) {
System::free(_byte);
_byte = NULL;
System::free(palette);
palette = NULL;
throw Error("32 bit bitmaps not supported", input.getFilename());
} else {
// We support all possible bit depths, so if the
// code gets here, it's not even a real bitmap.
System::free(_byte);
_byte = NULL;
throw Error("Not a bitmap!", input.getFilename());
}
System::free(palette);
palette = NULL;
}
void GImage::decodeICO(
BinaryInput& input) {
// Header
uint16 r = input.readUInt16();
debugAssert(r == 0);
r = input.readUInt16();
debugAssert(r == 1);
// Read the number of icons, although we'll only load the
// first one.
int count = input.readUInt16();
channels = 4;
debugAssert(count > 0);
const uint8* headerBuffer = input.getCArray() + input.getPosition();
int maxWidth = 0, maxHeight = 0;
int maxHeaderNum = 0;
for (int currentHeader = 0; currentHeader < count; ++currentHeader) {
const uint8* curHeaderBuffer = headerBuffer + (currentHeader * 16);
int tmpWidth = curHeaderBuffer[0];
int tmpHeight = curHeaderBuffer[1];
// Just in case there is a non-square icon, checking area
if ((tmpWidth * tmpHeight) > (maxWidth * maxHeight)) {
maxWidth = tmpWidth;
maxHeight = tmpHeight;
maxHeaderNum = currentHeader;
}
}
input.skip(maxHeaderNum * 16);
width = input.readUInt8();
height = input.readUInt8();
int numColors = input.readUInt8();
_byte = (uint8*)System::malloc(width * height * channels);
debugAssert(_byte);
// Bit mask for packed bits
int mask = 0;
int bitsPerPixel = 8;
switch (numColors) {
case 2:
mask = 0x01;
bitsPerPixel = 1;
break;
case 16:
mask = 0x0F;
bitsPerPixel = 4;
break;
case 0:
numColors = 256;
mask = 0xFF;
bitsPerPixel = 8;
break;
default:
throw Error("Unsupported ICO color count.", input.getFilename());
}
input.skip(5);
// Skip 'size' unused
input.skip(4);
int offset = input.readUInt32();
// Skip over any other icon descriptions
input.setPosition(offset);
// Skip over bitmap header; it is redundant
input.skip(40);
Array<Color4uint8> palette;
palette.resize(numColors, true);
for (int c = 0; c < numColors; ++c) {
palette[c].b = input.readUInt8();
palette[c].g = input.readUInt8();
palette[c].r = input.readUInt8();
palette[c].a = input.readUInt8();
}
// The actual image and mask follow
// The XOR Bitmap is stored as 1-bit, 4-bit or 8-bit uncompressed Bitmap
// using the same encoding as BMP files. The AND Bitmap is stored in as
// 1-bit uncompressed Bitmap.
//
// Pixels are stored bottom-up, left-to-right. Pixel lines are padded
// with zeros to end on a 32bit (4byte) boundary. Every line will have the
// same number of bytes. Color indices are zero based, meaning a pixel color
// of 0 represents the first color table entry, a pixel color of 255 (if there
// are that many) represents the 256th entry.
/*
int bitsPerRow = width * bitsPerPixel;
int bytesPerRow = iCeil((double)bitsPerRow / 8);
// Rows are padded to 32-bit boundaries
bytesPerRow += bytesPerRow % 4;
// Read the XOR values into the color channel
for (int y = height - 1; y >= 0; --y) {
int x = 0;
// Read the row
for (int i = 0; i < bytesPerRow; ++i) {
uint8 byte = input.readUInt8();
for (int j = 0; (j < 8) && (x < width); ++x, j += bitsPerPixel) {
int bit = ((byte << j) >> (8 - bitsPerPixel)) & mask;
pixel4(x, y) = colorTable[bit];
}
}
}
*/
int hStart = 0;
int hEnd = 0;
int hDir = 0;
if (height < 0) {
height = -height;
hStart = 0;
hEnd = height;
hDir = 1;
} else {
//height = height;
hStart = height - 1;
hEnd = -1;
hDir = -1;
}
int BMScanWidth;
uint8 BMGroup;
uint8 BMPixel8;
int currPixel;
int dest;
if (bitsPerPixel == 1) {
// Note that this file is not necessarily grayscale, since it's possible
// the palette is blue-and-white, or whatever. But of course most image
// programs only write 1-bit images if they're black-and-white.
// For bitmaps, each scanline is dword-aligned.
BMScanWidth = (width + 7) >> 3;
if (BMScanWidth & 3) {
BMScanWidth += 4 - (BMScanWidth & 3);
}
// Powers of 2
int pow2[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
for (int h = hStart; h != hEnd; h += hDir) {
currPixel = 0;
dest = 3 * h * width;
for (int w = 0; w < BMScanWidth; ++w) {
BMGroup = input.readUInt8();
// Now we read the pixels. Usually there are eight pixels per byte,
// since each pixel is represented by one bit, but if the width
// is not a multiple of eight, the last byte will have some bits
// set, with the others just being extra. Plus there's the
// dword-alignment padding. So we keep checking to see if we've
// already read "width" number of pixels.
for (int i = 7; i >= 0; --i) {
if (currPixel < width) {
int src = ((BMGroup & pow2[i]) >> i);
_byte[dest] = palette[src].r;
_byte[dest + 1] = palette[src].g;
_byte[dest + 2] = palette[src].b;
++currPixel;
dest += 4;
}
}
}
}
} else if (bitsPerPixel == 4) {
// For bitmaps, each scanline is dword-aligned.
int BMScanWidth = (width+1) >> 1;
if (BMScanWidth & 3) {
BMScanWidth += 4 - (BMScanWidth & 3);
}
for (int h = hStart; h != hEnd; h += hDir) {
currPixel = 0;
dest = 4 * h * width;
for (int w = 0; w < BMScanWidth; w++) {
BMGroup = input.readUInt8();
int src[2];
src[0] = ((BMGroup & 0xF0) >> 4);
src[1] = (BMGroup & 0x0F);
// Now we read the pixels. Usually there are two pixels per byte,
// since each pixel is represented by four bits, but if the width
// is not a multiple of two, the last byte will have only four bits
// set, with the others just being extra. Plus there's the
// dword-alignment padding. So we keep checking to see if we've
// already read "Width" number of pixels.
for (int i = 0; i < 2; ++i) {
if (currPixel < width) {
int tsrc = src[i];
_byte[dest] = palette[tsrc].r;
_byte[dest + 1] = palette[tsrc].g;
_byte[dest + 2] = palette[tsrc].b;
++currPixel;
dest += 4;
}
}
}
}
} else if (bitsPerPixel == 8) {
// For bitmaps, each scanline is dword-aligned.
BMScanWidth = width;
if (BMScanWidth & 3) {
BMScanWidth += 4 - (BMScanWidth & 3);
}
for (int h = hStart; h != hEnd; h += hDir) {
currPixel = 0;
for (int w = 0; w < BMScanWidth; ++w) {
BMPixel8 = input.readUInt8();
if (currPixel < width) {
dest = 4 * ((h * width) + currPixel);
int src = BMPixel8;
_byte[dest] = palette[src].r;
_byte[dest + 1] = palette[src].g;
_byte[dest + 2] = palette[src].b;
++currPixel;
}
}
}
}
// Read the mask into the alpha channel
int bitsPerRow = width;
int bytesPerRow = iCeil((double)bitsPerRow / 8);
// For bitmaps, each scanline is dword-aligned.
//BMScanWidth = (width + 1) >> 1;
if (bytesPerRow & 3) {
bytesPerRow += 4 - (bytesPerRow & 3);
}
for (int y = height - 1; y >= 0; --y) {
int x = 0;
// Read the row
for (int i = 0; i < bytesPerRow; ++i) {
uint8 byte = input.readUInt8();
for (int j = 0; (j < 8) && (x < width); ++x, ++j) {
int bit = (byte >> (7 - j)) & 0x01;
pixel4(x, y).a = (1 - bit) * 0xFF;
}
}
}
}
}
-445
View File
@@ -1,445 +0,0 @@
/**
@file GImage_jpeg.cpp
@author Morgan McGuire, [email protected]
@created 2002-05-27
@edited 2006-10-10
*/
#include "G3D/platform.h"
#include "G3D/GImage.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include <cstring>
/**
Pick up libjpeg headers locally on Windows, but from the system on all other platforms.
*/
extern "C" {
#include <jconfig.h>
#include <jpeglib.h>
}
namespace G3D {
const int jpegQuality = 96;
/**
The IJG library needs special setup for compress/decompressing
from memory. These classes provide them.
The format of this class is defined by the IJG library; do not
change it.
*/
class memory_destination_mgr {
public:
struct jpeg_destination_mgr pub;
JOCTET* buffer;
int size;
int count;
};
typedef memory_destination_mgr* mem_dest_ptr;
/**
Signature dictated by IJG.
*/
static void init_destination (
j_compress_ptr cinfo) {
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
dest->pub.next_output_byte = dest->buffer;
dest->pub.free_in_buffer = dest->size;
dest->count=0;
}
/**
Signature dictated by IJG.
*/
static boolean empty_output_buffer (
j_compress_ptr cinfo) {
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
dest->pub.next_output_byte = dest->buffer;
dest->pub.free_in_buffer = dest->size;
return TRUE;
}
/**
Signature dictated by IJG.
*/
static void term_destination (
j_compress_ptr cinfo) {
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
dest->count = dest->size - dest->pub.free_in_buffer;
}
/**
Signature dictated by IJG.
*/
static void jpeg_memory_dest (
j_compress_ptr cinfo,
JOCTET* buffer,
int size) {
mem_dest_ptr dest;
if (cinfo->dest == NULL) {
// First time for this JPEG object; call the
// IJG allocator to get space.
cinfo->dest = (struct jpeg_destination_mgr*)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
JPOOL_PERMANENT,
sizeof(memory_destination_mgr));
}
dest = (mem_dest_ptr) cinfo->dest;
dest->size = size;
dest->buffer = buffer;
dest->pub.init_destination = init_destination;
dest->pub.empty_output_buffer = empty_output_buffer;
dest->pub.term_destination = term_destination;
}
////////////////////////////////////////////////////////////////////////////////////////
#define INPUT_BUF_SIZE 4096
/**
Structure dictated by IJG.
*/
class memory_source_mgr {
public:
struct jpeg_source_mgr pub;
int source_size;
unsigned char* source_data;
boolean start_of_data;
JOCTET* buffer;
};
typedef memory_source_mgr* mem_src_ptr;
/**
Signature dictated by IJG.
*/
static void init_source(
j_decompress_ptr cinfo) {
mem_src_ptr src = (mem_src_ptr) cinfo->src;
src->start_of_data = TRUE;
}
/**
Signature dictated by IJG.
*/
static boolean fill_input_buffer(
j_decompress_ptr cinfo) {
mem_src_ptr src = (mem_src_ptr) cinfo->src;
size_t bytes_read = 0;
if (src->source_size > INPUT_BUF_SIZE)
bytes_read = INPUT_BUF_SIZE;
else
bytes_read = src->source_size;
memcpy (src->buffer, src->source_data, bytes_read);
src->source_data += bytes_read;
src->source_size -= bytes_read;
src->pub.next_input_byte = src->buffer;
src->pub.bytes_in_buffer = bytes_read;
src->start_of_data = FALSE;
return TRUE;
}
/**
Signature dictated by IJG.
*/
static void skip_input_data(
j_decompress_ptr cinfo,
long num_bytes) {
mem_src_ptr src = (mem_src_ptr)cinfo->src;
if (num_bytes > 0) {
while (num_bytes > (long) src->pub.bytes_in_buffer) {
num_bytes -= (long) src->pub.bytes_in_buffer;
boolean s = fill_input_buffer(cinfo);
debugAssert(s); (void)s;
}
src->pub.next_input_byte += (size_t) num_bytes;
src->pub.bytes_in_buffer -= (size_t) num_bytes;
}
}
/**
Signature dictated by IJG.
*/
static void term_source (
j_decompress_ptr cinfo) {
(void)cinfo;
// Intentionally empty
}
/**
Signature dictated by IJG.
*/
static void jpeg_memory_src (
j_decompress_ptr cinfo,
JOCTET* buffer,
int size) {
mem_src_ptr src;
if (cinfo->src == NULL) {
// First time for this JPEG object
cinfo->src = (struct jpeg_source_mgr*)
(*cinfo->mem->alloc_small)(
(j_common_ptr) cinfo,
JPOOL_PERMANENT,
sizeof(memory_source_mgr));
src = (mem_src_ptr)cinfo->src;
src->buffer = (JOCTET*)
(*cinfo->mem->alloc_small)(
(j_common_ptr) cinfo,
JPOOL_PERMANENT,
INPUT_BUF_SIZE * sizeof(JOCTET));
}
src = (mem_src_ptr)cinfo->src;
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_input_buffer;
src->pub.skip_input_data = skip_input_data;
// use default method
src->pub.resync_to_restart = jpeg_resync_to_restart;
src->pub.term_source = term_source;
src->source_data = buffer;
src->source_size = size;
// forces fill_input_buffer on first read
src->pub.bytes_in_buffer = 0;
// until buffer loaded
src->pub.next_input_byte = NULL;
}
void GImage::encodeJPEG(
BinaryOutput& out) const {
if (channels != 3) {
// Convert to three channel
GImage tmp = *this;
tmp.convertToRGB();
tmp.encodeJPEG(out);
return;
}
debugAssert(channels == 3);
out.setEndian(G3D_LITTLE_ENDIAN);
// Allocate and initialize a compression object
jpeg_compress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
// Specify the destination for the compressed data.
// (Overestimate the size)
int buffer_size = width * height * 3 + 200;
JOCTET* compressed_data = (JOCTET*)System::malloc(buffer_size);
jpeg_memory_dest(&cinfo, compressed_data, buffer_size);
cinfo.image_width = width;
cinfo.image_height = height;
// # of color components per pixel
cinfo.input_components = 3;
// colorspace of input image
cinfo.in_color_space = JCS_RGB;
cinfo.input_gamma = 1.0;
// Set parameters for compression, including image size & colorspace
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, jpegQuality, false);
cinfo.smoothing_factor = 0;
cinfo.optimize_coding = TRUE;
// cinfo.dct_method = JDCT_FLOAT;
cinfo.dct_method = JDCT_ISLOW;
cinfo.jpeg_color_space = JCS_YCbCr;
// Initialize the compressor
jpeg_start_compress(&cinfo, TRUE);
// Iterate over all scanlines from top to bottom
// pointer to a single row
JSAMPROW row_pointer[1];
// JSAMPLEs per row in image_buffer
int row_stride = cinfo.image_width * 3;
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = &(_byte[cinfo.next_scanline * row_stride]);
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
// Shut down the compressor
jpeg_finish_compress(&cinfo);
// Figure out how big the result was.
int outLength = ((mem_dest_ptr)cinfo.dest)->count;
// Release the JPEG compression object
jpeg_destroy_compress(&cinfo);
// Copy into an appropriately sized output buffer.
out.writeBytes(compressed_data, outLength);
// Free the conservative buffer.
System::free(compressed_data);
compressed_data = NULL;
}
void GImage::decodeJPEG(
BinaryInput& input) {
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
int loc = 0;
channels = 3;
// We have to set up the error handler, in case initialization fails.
cinfo.err = jpeg_std_error(&jerr);
// Initialize the JPEG decompression object.
jpeg_create_decompress(&cinfo);
// Specify data source (eg, a file, for us, memory)
jpeg_memory_src(&cinfo, const_cast<uint8*>(input.getCArray()), input.size());
// Read the parameters with jpeg_read_header()
jpeg_read_header(&cinfo, TRUE);
// Set parameters for decompression
// (We do nothing here since the defaults are fine)
// Start decompressor
jpeg_start_decompress(&cinfo);
// Get and set the values of interest to this object
this->width = cinfo.output_width;
this->height = cinfo.output_height;
// Prepare the pointer object for the pixel data
_byte = (uint8*)System::malloc(width * height * 3);
// JSAMPLEs per row in output buffer
int bpp = cinfo.output_components;
int row_stride = cinfo.output_width * bpp;
// Make a one-row-high sample array that will go away when done with image
JSAMPARRAY temp = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
// Read data on a scanline by scanline basis
while (cinfo.output_scanline < cinfo.output_height) {
// We may need to adjust the output based on the
// number of channels it has.
switch (bpp) {
case 1:
// Grayscale; decompress to temp.
jpeg_read_scanlines(&cinfo, temp, 1);
// Expand to three channels
{
uint8* scan = &(_byte[loc * 3]);
uint8* endScan = scan + (width * 3);
uint8* t = *temp;
while (scan < endScan) {
uint8 value = t[0];
// Spread the value 3x.
scan[0] = value;
scan[1] = value;
scan[2] = value;
scan += 3;
t += 1;
}
}
break;
case 3:
// Read directly into the array
{
// Need one extra level of indirection.
uint8* scan = _byte + loc;
JSAMPARRAY ptr = &scan;
jpeg_read_scanlines(&cinfo, ptr, 1);
}
break;
case 4:
// RGBA; decompress to temp.
jpeg_read_scanlines(&cinfo, temp, 1);
// Drop the 3rd channel
{
uint8* scan = &(_byte[loc * 3]);
uint8* endScan = scan + width * 3;
uint8* t = *temp;
while (scan < endScan) {
scan[0] = t[0];
scan[1] = t[1];
scan[2] = t[2];
scan += 3;
t += 4;
}
}
break;
default:
throw Error("Unexpected number of channels.", input.getFilename());
}
loc += row_stride;
}
// Finish decompression
jpeg_finish_decompress(&cinfo);
alwaysAssertM(this, "Corrupt GImage");
// Release JPEG decompression object
jpeg_destroy_decompress(&cinfo);
}
}
-245
View File
@@ -1,245 +0,0 @@
/**
@file GImage_png.cpp
@author Morgan McGuire, [email protected]
@created 2002-05-27
@edited 2006-05-10
*/
#include "G3D/platform.h"
#include "G3D/GImage.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/Log.h"
#include <png.h>
namespace G3D {
//libpng required function signature
static void png_read_data(
png_structp png_ptr,
png_bytep data,
png_size_t length) {
debugAssert( png_ptr->io_ptr != NULL );
debugAssert( length >= 0 );
debugAssert( data != NULL );
((BinaryInput*)png_ptr->io_ptr)->readBytes(data, length);
}
//libpng required function signature
static void png_write_data(png_structp png_ptr,
png_bytep data,
png_size_t length) {
debugAssert( png_ptr->io_ptr != NULL );
debugAssert( data != NULL );
((BinaryOutput*)png_ptr->io_ptr)->writeBytes(data, length);
}
//libpng required function signature
static void png_flush_data(
png_structp png_ptr) {
(void)png_ptr;
//Do nothing.
}
//libpng required function signature
static void png_error(
png_structp png_ptr,
png_const_charp error_msg) {
(void)png_ptr;
debugAssert( error_msg != NULL );
throw GImage::Error(error_msg, "PNG");
}
//libpng required function signature
void png_warning(
png_structp png_ptr,
png_const_charp warning_msg) {
(void)png_ptr;
debugAssert( warning_msg != NULL );
Log::common()->println(warning_msg);
}
void GImage::encodePNG(
BinaryOutput& out) const {
debugAssert( channels == 1 || channels == 3 || channels == 4 );
if (this->height > (int)(PNG_UINT_32_MAX/png_sizeof(png_bytep)))
throw GImage::Error("Unsupported PNG height.", out.getFilename());
out.setEndian(G3D_LITTLE_ENDIAN);
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_error, png_warning);
if (!png_ptr)
throw GImage::Error("Unable to initialize PNG encoder.", out.getFilename());
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_write_struct(&png_ptr, &info_ptr);
throw GImage::Error("Unable to initialize PNG encoder.", out.getFilename());
}
//setup libpng write handler so can use BinaryOutput
png_set_write_fn(png_ptr, (void*)&out, png_write_data, png_flush_data);
if (channels == 3) {
png_set_IHDR(png_ptr, info_ptr, this->width, this->height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
else if (channels == 4) {
png_set_IHDR(png_ptr, info_ptr, this->width, this->height, 8, PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
else if (channels == 1) {
png_set_IHDR(png_ptr, info_ptr, this->width, this->height, 8, PNG_COLOR_TYPE_GRAY,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
else {
png_destroy_write_struct(&png_ptr, &info_ptr);
throw GImage::Error("Unsupported number of channels for PNG.", out.getFilename());
}
png_color_8_struct sig_bit;
sig_bit.red = 8;
sig_bit.green = 8;
sig_bit.blue = 8;
if (channels == 4)
sig_bit.alpha = 8;
else
sig_bit.alpha = 0;
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
//write the png header
png_write_info(png_ptr, info_ptr);
png_bytepp row_pointers = new png_bytep[this->height];
for (int i=0; i < this->height; ++i) {
row_pointers[i] = (png_bytep)&this->_byte[(this->width * this->channels * i)];
}
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
delete[] row_pointers;
png_destroy_write_struct(&png_ptr, &info_ptr);
}
void GImage::decodePNG(
BinaryInput& input) {
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error, png_warning);
if (!png_ptr)
throw GImage::Error("Unable to initialize PNG decoder.", input.getFilename());
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
throw GImage::Error("Unable to initialize PNG decoder.", input.getFilename());
}
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info) {
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
throw GImage::Error("Unable to initialize PNG decoder.", input.getFilename());
}
//now that the libpng structures are setup, change the error handlers and read routines
//to use G3D functions so that BinaryInput can be used.
png_set_read_fn(png_ptr, (png_voidp)&input, png_read_data);
//read in sequentially so that three copies of the file are not in memory at once
png_read_info(png_ptr, info_ptr);
png_uint_32 png_width, png_height;
int bit_depth, color_type, interlace_type;
//this will validate the data it extracts from info_ptr
png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &bit_depth, &color_type,
&interlace_type, int_p_NULL, int_p_NULL);
if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
throw GImage::Error("Unsupported PNG color type - PNG_COLOR_TYPE_GRAY_ALPHA.", input.getFilename());
}
this->width = static_cast<uint32>(png_width);
this->height = static_cast<uint32>(png_height);
//swap bytes of 16 bit files to least significant byte first
png_set_swap(png_ptr);
png_set_strip_16(png_ptr);
//Expand paletted colors into true RGB triplets
if (color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png_ptr);
}
//Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
png_set_gray_1_2_4_to_8(png_ptr);
}
//Expand paletted or RGB images with transparency to full alpha channels
//so the data will be available as RGBA quartets.
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png_ptr);
}
// Fix sub-8 bit_depth to 8bit
if (bit_depth < 8) {
png_set_packing(png_ptr);
}
if ((color_type == PNG_COLOR_TYPE_RGBA) ||
((color_type == PNG_COLOR_TYPE_PALETTE) && (png_ptr->num_trans > 0)) ) {
this->channels = 4;
this->_byte = (uint8*)System::malloc(width * height * 4);
} else if ((color_type == PNG_COLOR_TYPE_RGB) ||
(color_type == PNG_COLOR_TYPE_PALETTE)) {
this->channels = 3;
this->_byte = (uint8*)System::malloc(width * height * 3);
} else if (color_type == PNG_COLOR_TYPE_GRAY) {
this->channels = 1;
this->_byte = (uint8*)System::malloc(width * height);
} else {
throw GImage::Error("Unsupported PNG bit-depth or type.", input.getFilename());
}
//since we are reading row by row, required to handle interlacing
uint32 number_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
for (uint32 pass = 0; pass < number_passes; ++pass) {
for (uint32 y = 0; y < (uint32)height; ++y) {
png_bytep rowPointer = &this->_byte[width * this->channels * y];
png_read_rows(png_ptr, &rowPointer, png_bytepp_NULL, 1);
}
}
// png_read_image(png_ptr, &_byte);
png_read_end(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
}
}
-185
View File
@@ -1,185 +0,0 @@
/**
@file GImage_ppm.cpp
@author Morgan McGuire, [email protected]
@created 2002-05-27
@edited 2006-05-10
*/
#include "G3D/platform.h"
#include "G3D/GImage.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/TextInput.h"
#include "G3D/TextOutput.h"
#include "G3D/Log.h"
namespace G3D {
void GImage::encodePPMASCII(
BinaryOutput& out) const {
debugAssert(channels == 3);
TextOutput::Settings ppmOptions;
ppmOptions.convertNewlines = false;
ppmOptions.numColumns = 70;
ppmOptions.wordWrap = TextOutput::Settings::WRAP_WITHOUT_BREAKING;
TextOutput ppm(ppmOptions);
// Always write out a full-color ppm
ppm.printf("P3\n%d %d\n255\n", width, height);
const Color3uint8* c = this->pixel3();
for (uint32 i = 0; i < (uint32)(width * height); ++i) {
ppm.printf("%d %d %d%c", c[i].r, c[i].g, c[i].b,
((i % ((width * 3) - 1)) == 0) ?
'\n' : ' ');
}
out.writeString(ppm.commitString());
}
void GImage::encodePPM(
BinaryOutput& out) const {
// http://netpbm.sourceforge.net/doc/ppm.html
debugAssert(channels == 3);
std::string header = format("P6 %d %d 255 ", width, height);
out.writeBytes(header.c_str(), header.size());
out.writeBytes(this->pixel3(), width * height * 3);
}
void GImage::decodePPMASCII(
BinaryInput& input) {
int ppmWidth;
int ppmHeight;
double maxColor;
// Create a TextInput object to parse ascii format
// Mixed binary/ascii formats will require more
const std::string inputStr = input.readString();
TextInput::Settings ppmOptions;
ppmOptions.cppComments = false;
ppmOptions.otherCommentCharacter = '#';
ppmOptions.signedNumbers = true;
ppmOptions.singleQuotedStrings = false;
TextInput ppmInput(TextInput::FROM_STRING, inputStr, ppmOptions);
//Skip first line in header P#
std::string ppmType = ppmInput.readSymbol();
ppmWidth = (int)ppmInput.readNumber();
ppmHeight = (int)ppmInput.readNumber();
// Everything but a PBM will have a max color value
if (ppmType != "P2") {
maxColor = ppmInput.readNumber();
} else {
maxColor = 255;
}
if ((ppmWidth < 0) ||
(ppmHeight < 0) ||
(maxColor <= 0)) {
throw GImage::Error("Invalid PPM Header.", input.getFilename());
}
// I don't think it's proper to scale values less than 255
if (maxColor <= 255.0) {
maxColor = 255.0;
}
this->width = ppmWidth;
this->height = ppmHeight;
this->channels = 3;
// always scale down to 1 byte per channel
this->_byte = (uint8*)System::malloc(width * height * 3);
// Read in the image data. I am not validating if the values match the maxColor
// requirements. I only scale if needed to fit within the byte available.
for (uint32 i = 0; i < (uint32)(width * height); ++i) {
// read in color and scale to max pixel defined in header
// A max color less than 255 might need to be left alone and not scaled.
Color3uint8& curPixel = *(this->pixel3() + i);
if (ppmType == "P3") {
curPixel.r = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
curPixel.g = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
curPixel.b = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
} else if (ppmType == "P2") {
uint8 pixel = (uint8)(ppmInput.readNumber() * (255.0 / maxColor));
curPixel.r = pixel;
curPixel.g = pixel;
curPixel.b = pixel;
} else if (ppmType == "P1") {
int pixel = (uint8)(ppmInput.readNumber() * maxColor);
curPixel.r = pixel;
curPixel.g = pixel;
curPixel.b = pixel;
}
}
}
/** Consumes whitespace up to and including a number, but not the following character */
static int scanUInt(BinaryInput& input) {
char c = input.readUInt8();
while (isWhiteSpace(c)) {
c = input.readUInt8();
}
std::string s;
s += c;
c = input.readUInt8();
while (!isWhiteSpace(c)) {
s += c;
c = input.readUInt8();
}
// Back up one to avoid consuming the last character
input.setPosition(input.getPosition() - 1);
int x;
sscanf(s.c_str(), "%d", &x);
return x;
}
void GImage::decodePPM(
BinaryInput& input) {
char head[2];
int w, h;
input.readBytes(head, 2);
if (head[0] != 'P' || head[1] != '6') {
throw GImage::Error("Invalid PPM Header.", input.getFilename());
}
w = scanUInt(input);
h = scanUInt(input);
// Skip the max color specifier
scanUInt(input);
if ((w < 0) ||
(h < 0) ||
(w > 100000) ||
(h > 100000)) {
throw GImage::Error("Invalid PPM size in header.", input.getFilename());
}
// Trailing whitespace
input.readUInt8();
resize(w, h, 3);
input.readBytes(_byte, width * height * 3);
}
}
-179
View File
@@ -1,179 +0,0 @@
/**
@file GImage_tga.cpp
@author Morgan McGuire, [email protected]
@created 2002-05-27
@edited 2006-05-10
*/
#include "G3D/platform.h"
#include "G3D/GImage.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/Log.h"
namespace G3D {
void GImage::encodeTGA(
BinaryOutput& out) const {
out.setEndian(G3D_LITTLE_ENDIAN);
// ID length
out.writeUInt8(0);
// Color map Type
out.writeUInt8(0);
// Type
out.writeUInt8(2);
// Color map
out.skip(5);
// x, y offsets
out.writeUInt16(0);
out.writeUInt16(0);
// Width & height
out.writeUInt16(width);
out.writeUInt16(height);
// Color depth
out.writeUInt8(8 * channels);
// Image descriptor
if (channels == 3) {
// 0 alpha bits
out.writeUInt8(0);
}
else {
// 8 alpha bits
out.writeUInt8(8);
}
// Image ID (zero length)
if (channels == 3) {
// Pixels are upside down in BGR format.
for (int y = height - 1; y >= 0; y--) {
for (int x = 0; x < width; x++) {
uint8* p = &(_byte[3 * (y * width + x)]);
out.writeUInt8(p[2]);
out.writeUInt8(p[1]);
out.writeUInt8(p[0]);
}
}
} else {
// Pixels are upside down in BGRA format.
for (int y = height - 1; y >= 0; y--) {
for (int x = 0; x < width; x++) {
uint8* p = &(_byte[4 * (y * width + x)]);
out.writeUInt8(p[2]);
out.writeUInt8(p[1]);
out.writeUInt8(p[0]);
out.writeUInt8(p[3]);
}
}
}
// Write "TRUEVISION-XFILE " 18 bytes from the end
// (with null termination)
out.writeString("TRUEVISION-XFILE ");
}
void GImage::decodeTGA(
BinaryInput& input) {
// This is a simple TGA loader that can handle uncompressed
// truecolor TGA files (TGA type 2).
// Verify this is a TGA file by looking for the TRUEVISION tag.
int pos = input.getPosition();
input.setPosition(input.size() - 18);
std::string tag = input.readString(16);
if (tag != "TRUEVISION-XFILE") {
throw Error("Not a TGA file", input.getFilename());
}
input.setPosition(pos);
int IDLength = input.readUInt8();
int colorMapType = input.readUInt8();
int imageType = input.readUInt8();
(void)colorMapType;
// 2 is the type supported by this routine.
if (imageType != 2) {
throw Error("TGA images must be type 2 (Uncompressed truecolor)", input.getFilename());
}
// Color map specification
input.skip(5);
// Image specification
// Skip x and y offsets
input.skip(4);
width = input.readInt16();
height = input.readInt16();
int colorDepth = input.readUInt8();
if ((colorDepth != 24) && (colorDepth != 32)) {
throw Error("TGA files must be 24 or 32 bit.", input.getFilename());
}
if (colorDepth == 32) {
channels = 4;
} else {
channels = 3;
}
// Image descriptor contains overlay data as well
// as data indicating where the origin is
int imageDescriptor = input.readUInt8();
(void)imageDescriptor;
// Image ID
input.skip(IDLength);
_byte = (uint8*)System::malloc(width * height * channels);
debugAssert(_byte);
// Pixel data
int x;
int y;
if (channels == 3) {
for (y = height - 1; y >= 0; y--) {
for (x = 0; x < width; x++) {
int b = input.readUInt8();
int g = input.readUInt8();
int r = input.readUInt8();
int i = (x + y * width) * 3;
_byte[i + 0] = r;
_byte[i + 1] = g;
_byte[i + 2] = b;
}
}
} else {
for (y = height - 1; y >= 0; y--) {
for (x = 0; x < width; x++) {
int b = input.readUInt8();
int g = input.readUInt8();
int r = input.readUInt8();
int a = input.readUInt8();
int i = (x + y * width) * 4;
_byte[i + 0] = r;
_byte[i + 1] = g;
_byte[i + 2] = b;
_byte[i + 3] = a;
}
}
}
}
}
-143
View File
@@ -1,143 +0,0 @@
/**
@file GLight.cpp
@maintainer Morgan McGuire, [email protected]
@created 2003-11-12
@edited 2007-10-22
*/
#include "G3D/GLight.h"
#include "G3D/Sphere.h"
namespace G3D {
GLight::GLight() {
position = Vector4(0, 0, 0, 0);
color = Color3::white();
spotDirection = Vector3(0, 0, -1);
spotCutoff = 180;
enabled = false;
attenuation[0] = 1.0;
attenuation[1] = 0.0;
attenuation[2] = 0.0;
specular = true;
diffuse = true;
}
GLight GLight::directional(const Vector3& toLight, const Color3& color, bool s, bool d) {
GLight L;
L.position = Vector4(toLight.direction(), 0);
L.color = color;
L.specular = s;
L.diffuse = d;
return L;
}
GLight GLight::point(const Vector3& pos, const Color3& color, float constAtt, float linAtt, float quadAtt, bool s, bool d) {
GLight L;
L.position = Vector4(pos, 1);
L.color = color;
L.attenuation[0] = constAtt;
L.attenuation[1] = linAtt;
L.attenuation[2] = quadAtt;
L.specular = s;
L.diffuse = d;
return L;
}
GLight GLight::spot(const Vector3& pos, const Vector3& pointDirection, float cutOffAngleDegrees, const Color3& color, float constAtt, float linAtt, float quadAtt, bool s, bool d) {
GLight L;
L.position = Vector4(pos, 1.0f);
L.spotDirection = pointDirection.direction();
debugAssert(cutOffAngleDegrees <= 90);
L.spotCutoff = cutOffAngleDegrees;
L.color = color;
L.attenuation[0] = constAtt;
L.attenuation[1] = linAtt;
L.attenuation[2] = quadAtt;
L.specular = s;
L.diffuse = d;
return L;
}
bool GLight::operator==(const GLight& other) const {
return (position == other.position) &&
(spotDirection == other.spotDirection) &&
(spotCutoff == other.spotCutoff) &&
(attenuation[0] == other.attenuation[0]) &&
(attenuation[1] == other.attenuation[1]) &&
(attenuation[2] == other.attenuation[2]) &&
(color == other.color) &&
(enabled == other.enabled) &&
(specular == other.specular) &&
(diffuse == other.diffuse);
}
bool GLight::operator!=(const GLight& other) const {
return !(*this == other);
}
Sphere GLight::effectSphere(float cutoff) const {
if (position.w == 0) {
// Directional light
return Sphere(Vector3::zero(), (float)inf());
} else {
// Avoid divide by zero
cutoff = max(cutoff, 0.0001f);
float maxIntensity = max(color.r, max(color.g, color.b));
float radius = (float)inf();
if (attenuation[2] != 0) {
// Solve I / attenuation.dot(1, r, r^2) < cutoff for r
//
// a[0] + a[1] r + a[2] r^2 > I/cutoff
//
float a = attenuation[2];
float b = attenuation[1];
float c = attenuation[0] - maxIntensity / cutoff;
float discrim = square(b) - 4 * a * c;
if (discrim >= 0) {
discrim = sqrt(discrim);
float r1 = (-b + discrim) / (2 * a);
float r2 = (-b - discrim) / (2 * a);
if (r1 < 0) {
if (r2 > 0) {
radius = r2;
}
} else if (r2 > 0) {
radius = min(r1, r2);
} else {
radius = r1;
}
}
} else if (attenuation[1] != 0) {
// Solve I / attenuation.dot(1, r) < cutoff for r
//
// r * a[1] + a[0] = I / cutoff
// r = (I / cutoff - a[0]) / a[1]
float radius = (maxIntensity / cutoff - attenuation[0]) / attenuation[1];
radius = max(radius, 0.0f);
}
return Sphere(position.xyz(), radius);
}
}
}
-203
View File
@@ -1,203 +0,0 @@
/**
@file GThread.cpp
GThread class.
@created 2005-09-24
@edited 2005-10-22
*/
#include "G3D/GThread.h"
#include "G3D/System.h"
#include "G3D/debugAssert.h"
namespace G3D {
namespace _internal {
class BasicThread: public GThread {
public:
BasicThread(const std::string& name, void (*proc)(void*), void* param):
GThread(name), m_wrapperProc(proc), m_param(param) { }
protected:
virtual void threadMain() {
m_wrapperProc(m_param);
}
private:
void (*m_wrapperProc)(void*);
void* m_param;
};
} // namespace _internal
GThread::GThread(const std::string& name):
m_status(STATUS_CREATED),
m_name(name) {
#ifdef G3D_WIN32
m_event = NULL;
#endif
// system-independent clear of handle
System::memset(&m_handle, 0, sizeof(m_handle));
}
GThread::~GThread() {
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning( disable : 4127 )
#endif
alwaysAssertM(m_status != STATUS_RUNNING, "Deleting thread while running.");
#ifdef _MSC_VER
# pragma warning( pop )
#endif
#ifdef G3D_WIN32
if (m_event) {
::CloseHandle(m_event);
}
#endif
}
GThreadRef GThread::create(const std::string& name, void (*proc)(void*), void* param) {
return new _internal::BasicThread(name, proc, param);
}
bool GThread::started() const {
return m_status != STATUS_CREATED;
}
bool GThread::start() {
debugAssertM(! started(), "Thread has already executed.");
if (started()) {
return false;
}
m_status = STATUS_STARTED;
# ifdef G3D_WIN32
DWORD threadId;
m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
debugAssert(m_event);
m_handle = ::CreateThread(NULL, 0, &internalThreadProc, this, 0, &threadId);
if (m_handle == NULL) {
::CloseHandle(m_event);
m_event = NULL;
}
return (m_handle != NULL);
# else
if (!pthread_create(&m_handle, NULL, &internalThreadProc, this)) {
return true;
} else {
// system-independent clear of handle
System::memset(&m_handle, 0, sizeof(m_handle));
return false;
}
# endif
}
void GThread::terminate() {
if (m_handle) {
# ifdef G3D_WIN32
::TerminateThread(m_handle, 0);
# else
pthread_kill(m_handle, SIGSTOP);
# endif
// system-independent clear of handle
System::memset(&m_handle, 0, sizeof(m_handle));
}
}
bool GThread::running() const{
return (m_status == STATUS_RUNNING);
}
bool GThread::completed() const {
return (m_status == STATUS_COMPLETED);
}
void GThread::waitForCompletion() {
# ifdef G3D_WIN32
debugAssert(m_event);
::WaitForSingleObject(m_event, INFINITE);
# else
debugAssert(m_handle);
pthread_join(m_handle, NULL);
# endif
}
#ifdef G3D_WIN32
DWORD WINAPI GThread::internalThreadProc(LPVOID param) {
GThread* current = reinterpret_cast<GThread*>(param);
debugAssert(current->m_event);
current->m_status = STATUS_RUNNING;
current->threadMain();
current->m_status = STATUS_COMPLETED;
::SetEvent(current->m_event);
return 0;
}
#else
void* GThread::internalThreadProc(void* param) {
GThread* current = reinterpret_cast<GThread*>(param);
current->m_status = STATUS_RUNNING;
current->threadMain();
current->m_status = STATUS_COMPLETED;
return (void*)NULL;
}
#endif
GMutex::GMutex() {
# ifdef G3D_WIN32
::InitializeCriticalSection(&m_handle);
# else
pthread_mutex_init(&m_handle, NULL);
# endif
}
GMutex::~GMutex() {
//TODO: Debug check for locked
# ifdef G3D_WIN32
::DeleteCriticalSection(&m_handle);
# else
pthread_mutex_destroy(&m_handle);
# endif
}
//bool GMutex::tryLock() {
//# ifdef G3D_WIN32
// return ::TryEnterCriticalSection(&m_handle);
//# else
// return pthread_mutex_trylock(&m_handle);
//# endif
//}
void GMutex::lock() {
# ifdef G3D_WIN32
::EnterCriticalSection(&m_handle);
# else
pthread_mutex_lock(&m_handle);
# endif
}
void GMutex::unlock() {
# ifdef G3D_WIN32
::LeaveCriticalSection(&m_handle);
# else
pthread_mutex_unlock(&m_handle);
# endif
}
} // namespace G3D
-78
View File
@@ -1,78 +0,0 @@
/**
@file GUniqueID.cpp
@author Morgan McGuire, [email protected]
*/
#include "G3D/GUniqueID.h"
#include "G3D/BinaryInput.h"
#include "G3D/TextInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/TextOutput.h"
#include "G3D/NetworkDevice.h"
namespace G3D {
void GUniqueID::serialize(BinaryOutput& b) const {
b.writeUInt64(id);
}
void GUniqueID::deserialize(BinaryInput& b) {
id = b.readUInt64();
}
void GUniqueID::serialize(TextOutput& t) const {
t.writeSymbol("(");
t.writeNumber((double)(id >> 32));
t.writeNumber((double)(id & 0xFFFFFFFF));
t.writeSymbol(")");
}
void GUniqueID::deserialize(TextInput& t) {
t.readSymbol("(");
id = (((uint64)t.readNumber()) << 32) + (uint64)t.readNumber();
t.readSymbol(")");
}
GUniqueID GUniqueID::create(uint16 tag) {
static uint64 counter = 0;
static uint64 systemID = 0;
if (systemID == 0) {
// Create a unique ID for this machine/program instance
// TODO: see ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr)
Array<NetAddress> addr;
NetworkDevice::instance()->localHostAddresses(addr);
if (addr.size() > 0) {
systemID |= addr[0].ip();
}
union {
float64 ft;
uint64 ut;
};
ft = System::time();
systemID = ut << 22;
systemID ^= ((uint64)iRandom(0, 32768)) << 8;
systemID &= ~((uint64)1023 << 54);
// Ensure that the systemID is non-zero (vanishingly small probability)
if (systemID == 0) {
systemID = 1;
}
}
// No need for modulo; we'll all be dead before this counter
// overflows 54 bits
++counter;
GUniqueID i;
i.id = (((uint64)(tag & 1023)) << 54) | (counter ^ systemID);
return i;
}
} // G3D
-224
View File
@@ -1,224 +0,0 @@
/**
@file Image1.cpp
@maintainer Morgan McGuire, [email protected]
@created 2007-01-31
@edited 2007-01-31
*/
#include "G3D/Image1.h"
#include "G3D/Image1uint8.h"
#include "G3D/GImage.h"
#include "G3D/Color4.h"
#include "G3D/Color4uint8.h"
#include "G3D/Color1.h"
#include "G3D/Color1uint8.h"
#include "G3D/ImageFormat.h"
namespace G3D {
Image1::Image1(int w, int h, WrapMode wrap) : Map2D<Color1, Color1>(w, h, wrap) {
setAll(Color1(0.0f));
}
Image1::Ref Image1::fromGImage(const GImage& im, WrapMode wrap) {
switch (im.channels) {
case 1:
return fromArray(im.pixel1(), im.width, im.height, wrap);
case 3:
return fromArray(im.pixel3(), im.width, im.height, wrap);
case 4:
return fromArray(im.pixel4(), im.width, im.height, wrap);
default:
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
return NULL;
}
}
Image1::Ref Image1::fromImage1uint8(const ReferenceCountedPointer<Image1uint8>& im) {
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
out->resize(im->width(), im->height());
int N = im->width() * im->height();
const Color1uint8* src = reinterpret_cast<Color1uint8*>(im->getCArray());
for (int i = 0; i < N; ++i) {
out->data[i] = Color1(src[i]);
}
return out;
}
Image1::Ref Image1::createEmpty(int width, int height, WrapMode wrap) {
return new Type(width, height, wrap);
}
Image1::Ref Image1::createEmpty(WrapMode wrap) {
return createEmpty(0, 0, wrap);
}
Image1::Ref Image1::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
Ref out = createEmpty(wrap);
out->load(filename);
return out;
}
void Image1::load(const std::string& filename, GImage::Format fmt) {
copyGImage(GImage(filename, fmt));
setChanged(true);
}
Image1::Ref Image1::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image1::Ref Image1::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image1::Ref Image1::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image1::Ref Image1::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image1::Ref Image1::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image1::Ref Image1::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
void Image1::copyGImage(const GImage& im) {
switch (im.channels) {
case 1:
copyArray(im.pixel1(), im.width, im.height);
break;
case 3:
copyArray(im.pixel3(), im.width, im.height);
break;
case 4:
copyArray(im.pixel4(), im.width, im.height);
break;
}
}
void Image1::copyArray(const Color3uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color1* dst = data.getCArray();
// Convert int8 -> float
for (int i = 0; i < N; ++i) {
dst[i] = Color1(Color3(src[i]).average());
}
}
void Image1::copyArray(const Color4uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color1* dst = data.getCArray();
// Strip alpha and convert
for (int i = 0; i < N; ++i) {
dst[i] = Color1(Color3(src[i].rgb()).average());
}
}
void Image1::copyArray(const Color1* src, int w, int h) {
resize(w, h);
System::memcpy(getCArray(), src, w * h * sizeof(Color1));
}
void Image1::copyArray(const Color4* src, int w, int h) {
resize(w, h);
int N = w * h;
Color1* dst = data.getCArray();
// Strip alpha
for (int i = 0; i < N; ++i) {
dst[i] = Color1(src[i].rgb().average());
}
}
void Image1::copyArray(const Color1uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color1* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i]= Color1(src[i]);
}
}
void Image1::copyArray(const Color3* src, int w, int h) {
resize(w, h);
int N = w * h;
Color1* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i] = Color1(src[i].average());
}
}
/** Saves in any of the formats supported by G3D::GImage. */
void Image1::save(const std::string& filename, GImage::Format fmt) {
GImage im(width(), height(), 1);
int N = im.width * im.height;
Color1uint8* dst = im.pixel1();
for (int i = 0; i < N; ++i) {
dst[i] = Color1uint8(data[i]);
}
im.save(filename, fmt);
}
const ImageFormat* Image1::format() const {
return ImageFormat::L32F();
}
} // G3D
-212
View File
@@ -1,212 +0,0 @@
/**
@file Image1uint8.cpp
@maintainer Morgan McGuire, [email protected]
@created 2007-01-31
@edited 2008-01-13
*/
#include "G3D/Image1uint8.h"
#include "G3D/Image3uint8.h"
#include "G3D/Image1.h"
#include "G3D/GImage.h"
#include "G3D/Color1.h"
#include "G3D/Color1uint8.h"
#include "G3D/Color4.h"
#include "G3D/Color4uint8.h"
#include "G3D/ImageFormat.h"
namespace G3D {
Image1uint8::Image1uint8(int w, int h, WrapMode wrap) : Map2D<Color1uint8, Color1>(w, h, wrap) {
setAll(Color1uint8(0));
}
Image1uint8::Ref Image1uint8::fromImage3uint8(const ReferenceCountedPointer<class Image3uint8>& im) {
return fromArray(im->getCArray(), im->width(), im->height(), im->wrapMode());
}
Image1uint8::Ref Image1uint8::fromGImage(const GImage& im, WrapMode wrap) {
switch (im.channels) {
case 1:
return fromArray(im.pixel1(), im.width, im.height, wrap);
case 3:
return fromArray(im.pixel3(), im.width, im.height, wrap);
case 4:
return fromArray(im.pixel4(), im.width, im.height, wrap);
default:
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
return NULL;
}
}
Image1uint8::Ref Image1uint8::fromImage1(const ReferenceCountedPointer<Image1>& im) {
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
out->copyArray(im->getCArray(), im->width(), im->height());
return out;
}
Image1uint8::Ref Image1uint8::createEmpty(int width, int height, WrapMode wrap) {
return new Type(width, height, wrap);
}
Image1uint8::Ref Image1uint8::createEmpty(WrapMode wrap) {
return createEmpty(0, 0, wrap);
}
Image1uint8::Ref Image1uint8::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
Ref out = createEmpty(wrap);
out->load(filename);
return out;
}
Image1uint8::Ref Image1uint8::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image1uint8::Ref Image1uint8::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image1uint8::Ref Image1uint8::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image1uint8::Ref Image1uint8::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image1uint8::Ref Image1uint8::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image1uint8::Ref Image1uint8::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
void Image1uint8::load(const std::string& filename, GImage::Format fmt) {
copyGImage(GImage(filename, fmt));
setChanged(true);
}
void Image1uint8::copyGImage(const GImage& im) {
switch (im.channels) {
case 1:
copyArray(im.pixel1(), im.width, im.height);
break;
case 3:
copyArray(im.pixel3(), im.width, im.height);
break;
case 4:
copyArray(im.pixel4(), im.width, im.height);
break;
}
}
void Image1uint8::copyArray(const Color3uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color1uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i].value = (src[i].r + src[i].g + src[i].b) / 3;
}
}
void Image1uint8::copyArray(const Color3* src, int w, int h) {
resize(w, h);
int N = w * h;
Color1uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i] = Color1uint8(Color1(src[i].average()));
}
}
void Image1uint8::copyArray(const Color1uint8* ptr, int w, int h) {
resize(w, h);
System::memcpy(getCArray(), ptr, w * h);
}
void Image1uint8::copyArray(const Color1* src, int w, int h) {
resize(w, h);
int N = w * h;
Color1uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i] = Color1uint8(src[i]);
}
}
void Image1uint8::copyArray(const Color4uint8* ptr, int w, int h) {
resize(w, h);
int N = w * h;
Color1uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i].value = (ptr[i].r + ptr[i].g + ptr[i].b) / 3;
}
}
void Image1uint8::copyArray(const Color4* src, int w, int h) {
resize(w, h);
int N = w * h;
Color1uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i] = Color1uint8(Color1(src[i].rgb().average()));
}
}
/** Saves in any of the formats supported by G3D::GImage. */
void Image1uint8::save(const std::string& filename, GImage::Format fmt) {
GImage im(width(), height(), 1);
System::memcpy(im.byte(), getCArray(), width() * height());
im.save(filename, fmt);
}
const ImageFormat* Image1uint8::format() const {
return ImageFormat::L8();
}
} // G3D
-224
View File
@@ -1,224 +0,0 @@
/**
@file Image3.cpp
@maintainer Morgan McGuire, [email protected]
@created 2007-01-31
@edited 2007-01-31
*/
#include "G3D/Image3.h"
#include "G3D/Image3uint8.h"
#include "G3D/GImage.h"
#include "G3D/Color4.h"
#include "G3D/Color4uint8.h"
#include "G3D/Color1.h"
#include "G3D/Color1uint8.h"
#include "G3D/ImageFormat.h"
namespace G3D {
Image3::Image3(int w, int h, WrapMode wrap) : Map2D<Color3, Color3>(w, h, wrap) {
setAll(Color3::black());
}
Image3::Ref Image3::fromGImage(const GImage& im, WrapMode wrap) {
switch (im.channels) {
case 1:
return fromArray(im.pixel1(), im.width, im.height, wrap);
case 3:
return fromArray(im.pixel3(), im.width, im.height, wrap);
case 4:
return fromArray(im.pixel4(), im.width, im.height, wrap);
default:
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
return NULL;
}
}
Image3::Ref Image3::fromImage3uint8(const ReferenceCountedPointer<Image3uint8>& im) {
Ref out = createEmpty(im->wrapMode());
out->resize(im->width(), im->height());
int N = im->width() * im->height();
const Color3uint8* src = reinterpret_cast<Color3uint8*>(im->getCArray());
for (int i = 0; i < N; ++i) {
out->data[i] = Color3(src[i]);
}
return out;
}
Image3::Ref Image3::createEmpty(int width, int height, WrapMode wrap) {
return new Image3(width, height, wrap);
}
Image3::Ref Image3::createEmpty(WrapMode wrap) {
return createEmpty(0, 0, wrap);
}
Image3::Ref Image3::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
Ref out = createEmpty(wrap);
out->load(filename);
return out;
}
void Image3::load(const std::string& filename, GImage::Format fmt) {
copyGImage(GImage(filename, fmt));
setChanged(true);
}
Image3::Ref Image3::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image3::Ref Image3::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image3::Ref Image3::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image3::Ref Image3::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image3::Ref Image3::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image3::Ref Image3::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
void Image3::copyGImage(const GImage& im) {
switch (im.channels) {
case 1:
copyArray(im.pixel1(), im.width, im.height);
break;
case 3:
copyArray(im.pixel3(), im.width, im.height);
break;
case 4:
copyArray(im.pixel4(), im.width, im.height);
break;
}
}
void Image3::copyArray(const Color3uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color3* dst = data.getCArray();
// Convert int8 -> float
for (int i = 0; i < N; ++i) {
dst[i] = Color3(src[i]);
}
}
void Image3::copyArray(const Color4uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color3* dst = data.getCArray();
// Strip alpha and convert
for (int i = 0; i < N; ++i) {
dst[i] = Color3(src[i].rgb());
}
}
void Image3::copyArray(const Color3* src, int w, int h) {
resize(w, h);
System::memcpy(getCArray(), src, w * h * sizeof(Color3));
}
void Image3::copyArray(const Color4* src, int w, int h) {
resize(w, h);
int N = w * h;
Color3* dst = data.getCArray();
// Strip alpha
for (int i = 0; i < N; ++i) {
dst[i] = src[i].rgb();
}
}
void Image3::copyArray(const Color1uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color3* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i].r = dst[i].g = dst[i].b = Color1(src[i]).value;
}
}
void Image3::copyArray(const Color1* src, int w, int h) {
resize(w, h);
int N = w * h;
Color3* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i].r = dst[i].g = dst[i].b = src[i].value;
}
}
/** Saves in any of the formats supported by G3D::GImage. */
void Image3::save(const std::string& filename, GImage::Format fmt) {
GImage im(width(), height(), 3);
int N = im.width * im.height;
Color3uint8* dst = im.pixel3();
for (int i = 0; i < N; ++i) {
dst[i] = Color3uint8(data[i]);
}
im.save(filename, fmt);
}
const ImageFormat* Image3::format() const {
return ImageFormat::RGB32F();
}
} // G3D
-225
View File
@@ -1,225 +0,0 @@
/**
@file Image3uint8.cpp
@maintainer Morgan McGuire, [email protected]
@created 2007-01-31
@edited 2008-01-08
*/
#include "G3D/Image1uint8.h"
#include "G3D/Image3uint8.h"
#include "G3D/Image3.h"
#include "G3D/GImage.h"
#include "G3D/Color1.h"
#include "G3D/Color1uint8.h"
#include "G3D/Color4.h"
#include "G3D/Color4uint8.h"
#include "G3D/ImageFormat.h"
namespace G3D {
Image3uint8::Ref Image3uint8::fromImage1uint8(const ReferenceCountedPointer<class Image1uint8>& im) {
return fromArray(im->getCArray(), im->width(), im->height(), im->wrapMode());
}
Image3uint8::Image3uint8(int w, int h, WrapMode wrap) : Map2D<Color3uint8>(w, h, wrap) {
setAll(Color3::black());
}
Image3uint8::Ref Image3uint8::fromGImage(const GImage& im, WrapMode wrap) {
switch (im.channels) {
case 1:
return fromArray(im.pixel1(), im.width, im.height, wrap);
case 3:
return fromArray(im.pixel3(), im.width, im.height, wrap);
case 4:
return fromArray(im.pixel4(), im.width, im.height, wrap);
default:
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
return NULL;
}
}
Image3uint8::Ref Image3uint8::fromImage3(const ReferenceCountedPointer<Image3>& im) {
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
out->copyArray(im->getCArray(), im->width(), im->height());
return out;
}
Image3uint8::Ref Image3uint8::createEmpty(int width, int height, WrapMode wrap) {
return new Type(width, height, wrap);
}
Image3uint8::Ref Image3uint8::createEmpty(WrapMode wrap) {
return createEmpty(0, 0, wrap);
}
Image3uint8::Ref Image3uint8::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
Ref out = createEmpty(wrap);
out->load(filename);
return out;
}
Image3uint8::Ref Image3uint8::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image3uint8::Ref Image3uint8::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image3uint8::Ref Image3uint8::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image3uint8::Ref Image3uint8::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image3uint8::Ref Image3uint8::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image3uint8::Ref Image3uint8::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
void Image3uint8::load(const std::string& filename, GImage::Format fmt) {
copyGImage(GImage(filename, fmt));
setChanged(true);
}
void Image3uint8::copyGImage(const GImage& im) {
switch (im.channels) {
case 1:
copyArray(im.pixel1(), im.width, im.height);
break;
case 3:
copyArray(im.pixel3(), im.width, im.height);
break;
case 4:
copyArray(im.pixel4(), im.width, im.height);
break;
}
}
void Image3uint8::copyArray(const Color1uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color3uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i].r = dst[i].g = dst[i].b = src[i].value;
}
}
void Image3uint8::copyArray(const Color1* src, int w, int h) {
resize(w, h);
int N = w * h;
Color3uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i].r = dst[i].g = dst[i].b = Color1uint8(src[i]).value;
}
}
void Image3uint8::copyArray(const Color3uint8* ptr, int w, int h) {
resize(w, h);
System::memcpy(getCArray(), ptr, w * h * 3);
}
void Image3uint8::copyArray(const Color3* src, int w, int h) {
resize(w, h);
int N = w * h;
Color3uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i] = Color3uint8(src[i]);
}
}
void Image3uint8::copyArray(const Color4uint8* ptr, int w, int h) {
resize(w, h);
// Copy 3/4 bytes
GImage::RGBAtoRGB((const uint8*)ptr, (uint8*)getCArray(), w * h);
}
void Image3uint8::copyArray(const Color4* src, int w, int h) {
resize(w, h);
int N = w * h;
Color3uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i] = Color3uint8(src[i].rgb());
}
}
/** Saves in any of the formats supported by G3D::GImage. */
void Image3uint8::save(const std::string& filename, GImage::Format fmt) {
GImage im(width(), height(), 3);
System::memcpy(im.byte(), getCArray(), width() * height() * 3);
im.save(filename, fmt);
}
ReferenceCountedPointer<class Image1uint8> Image3uint8::getChannel(int c) const {
debugAssert(c >= 0 && c <= 2);
Image1uint8Ref dst = Image1uint8::createEmpty(width(), height(), wrapMode());
const Color3uint8* srcArray = getCArray();
Color1uint8* dstArray = dst->getCArray();
const int N = width() * height();
for (int i = 0; i < N; ++i) {
dstArray[i] = Color1uint8(srcArray[i][c]);
}
return dst;
}
const ImageFormat* Image3uint8::format() const {
return ImageFormat::RGB8();
}
} // G3D
-226
View File
@@ -1,226 +0,0 @@
/**
@file Image4.cpp
@maintainer Morgan McGuire, [email protected]
@created 2007-01-31
@edited 2008-07-27
*/
#include "G3D/Image4.h"
#include "G3D/Image4uint8.h"
#include "G3D/GImage.h"
#include "G3D/Color3.h"
#include "G3D/Color3uint8.h"
#include "G3D/Color1.h"
#include "G3D/Color1uint8.h"
#include "G3D/ImageFormat.h"
namespace G3D {
Image4::Image4(int w, int h, WrapMode wrap) : Map2D<Color4, Color4>(w, h, wrap) {
setAll(Color4::zero());
}
Image4::Ref Image4::fromGImage(const GImage& im, WrapMode wrap) {
switch (im.channels) {
case 1:
return fromArray(im.pixel1(), im.width, im.height, wrap);
case 3:
return fromArray(im.pixel3(), im.width, im.height, wrap);
case 4:
return fromArray(im.pixel4(), im.width, im.height, wrap);
default:
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
return NULL;
}
}
Image4::Ref Image4::fromImage4uint8(const ReferenceCountedPointer<Image4uint8>& im) {
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
out->resize(im->width(), im->height());
int N = im->width() * im->height();
const Color4uint8* src = reinterpret_cast<Color4uint8*>(im->getCArray());
for (int i = 0; i < N; ++i) {
out->data[i] = Color4(src[i]);
}
return out;
}
Image4::Ref Image4::createEmpty(int width, int height, WrapMode wrap) {
return new Type(width, height, WrapMode::ERROR);
}
Image4::Ref Image4::createEmpty(WrapMode wrap) {
return createEmpty(0, 0, wrap);
}
Image4::Ref Image4::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
Ref out = createEmpty(wrap);
out->load(filename);
return out;
}
void Image4::load(const std::string& filename, GImage::Format fmt) {
copyGImage(GImage(filename, fmt));
setChanged(true);
}
Image4::Ref Image4::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image4::Ref Image4::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image4::Ref Image4::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image4::Ref Image4::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image4::Ref Image4::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image4::Ref Image4::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
void Image4::copyGImage(const GImage& im) {
switch (im.channels) {
case 1:
copyArray(im.pixel1(), im.width, im.height);
break;
case 3:
copyArray(im.pixel3(), im.width, im.height);
break;
case 4:
copyArray(im.pixel4(), im.width, im.height);
break;
}
}
void Image4::copyArray(const Color4uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color4* dst = data.getCArray();
// Convert int8 -> float
for (int i = 0; i < N; ++i) {
dst[i] = Color4(src[i]);
}
}
void Image4::copyArray(const Color3uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color4* dst = data.getCArray();
// Add alpha and convert
for (int i = 0; i < N; ++i) {
dst[i] = Color4(Color3(src[i]), 1.0f);
}
}
void Image4::copyArray(const Color4* src, int w, int h) {
resize(w, h);
System::memcpy(getCArray(), src, w * h * sizeof(Color4));
}
void Image4::copyArray(const Color3* src, int w, int h) {
resize(w, h);
int N = w * h;
Color4* dst = data.getCArray();
// Add alpha
for (int i = 0; i < N; ++i) {
dst[i] = Color4(src[i], 1.0f);
}
}
void Image4::copyArray(const Color1uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color4* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i].r = dst[i].g = dst[i].b = Color1(src[i]).value;
dst[i].a = 1.0f;
}
}
void Image4::copyArray(const Color1* src, int w, int h) {
resize(w, h);
int N = w * h;
Color4* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i].r = dst[i].g = dst[i].b = src[i].value;
dst[i].a = 1.0f;
}
}
/** Saves in any of the formats supported by G3D::GImage. */
void Image4::save(const std::string& filename, GImage::Format fmt) {
GImage im(width(), height(), 4);
int N = im.width * im.height;
Color4uint8* dst = im.pixel4();
for (int i = 0; i < N; ++i) {
dst[i] = Color4uint8(data[i]);
}
im.save(filename, fmt);
}
const ImageFormat* Image4::format() const {
return ImageFormat::RGBA32F();
}
} // G3D
-222
View File
@@ -1,222 +0,0 @@
/**
@file Image4uint8.cpp
@maintainer Morgan McGuire, [email protected]
@created 2007-01-31
@edited 2008-07-31
*/
#include "G3D/Image4uint8.h"
#include "G3D/Image4.h"
#include "G3D/Image3uint8.h"
#include "G3D/Image3.h"
#include "G3D/GImage.h"
#include "G3D/Color1.h"
#include "G3D/Color1uint8.h"
#include "G3D/Color4.h"
#include "G3D/Color4uint8.h"
#include "G3D/ImageFormat.h"
namespace G3D {
Image4uint8::Image4uint8(int w, int h, WrapMode wrap) : Map2D<Color4uint8, Color4>(w, h, wrap) {
setAll(Color4::zero());
}
Image4uint8::Ref Image4uint8::fromGImage(const GImage& im, WrapMode wrap) {
switch (im.channels) {
case 1:
return fromArray(im.pixel1(), im.width, im.height, wrap);
case 3:
return fromArray(im.pixel3(), im.width, im.height, wrap);
case 4:
return fromArray(im.pixel4(), im.width, im.height, wrap);
default:
debugAssertM(false, "Input GImage must have 1, 3, or 4 channels.");
return NULL;
}
}
Image4uint8::Ref Image4uint8::fromImage4(const ReferenceCountedPointer<Image4>& im) {
Ref out = createEmpty(static_cast<WrapMode>(im->wrapMode()));
out->copyArray(im->getCArray(), im->width(), im->height());
return out;
}
Image4uint8::Ref Image4uint8::createEmpty(int width, int height, WrapMode wrap) {
return new Type(width, height, wrap);
}
Image4uint8::Ref Image4uint8::createEmpty(WrapMode wrap) {
return createEmpty(0, 0, wrap);
}
Image4uint8::Ref Image4uint8::fromFile(const std::string& filename, WrapMode wrap, GImage::Format fmt) {
Ref out = createEmpty(wrap);
out->load(filename);
return out;
}
Image4uint8::Ref Image4uint8::fromArray(const class Color3uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image4uint8::Ref Image4uint8::fromArray(const class Color1* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image4uint8::Ref Image4uint8::fromArray(const class Color1uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image4uint8::Ref Image4uint8::fromArray(const class Color3* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image4uint8::Ref Image4uint8::fromArray(const class Color4uint8* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
Image4uint8::Ref Image4uint8::fromArray(const class Color4* ptr, int w, int h, WrapMode wrap) {
Ref out = createEmpty(wrap);
out->copyArray(ptr, w, h);
return out;
}
void Image4uint8::load(const std::string& filename, GImage::Format fmt) {
copyGImage(GImage(filename, fmt));
setChanged(true);
}
void Image4uint8::copyGImage(const GImage& im) {
switch (im.channels) {
case 1:
copyArray(im.pixel1(), im.width, im.height);
break;
case 3:
copyArray(im.pixel3(), im.width, im.height);
break;
case 4:
copyArray(im.pixel4(), im.width, im.height);
break;
}
}
void Image4uint8::copyArray(const Color1uint8* src, int w, int h) {
resize(w, h);
int N = w * h;
Color4uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i].r = dst[i].g = dst[i].b = src[i].value;
dst[i].a = 255;
}
}
void Image4uint8::copyArray(const Color1* src, int w, int h) {
resize(w, h);
int N = w * h;
Color4uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i].r = dst[i].g = dst[i].b = Color1uint8(src[i]).value;
dst[i].a = 255;
}
}
void Image4uint8::copyArray(const Color4uint8* ptr, int w, int h) {
resize(w, h);
System::memcpy(getCArray(), ptr, w * h * 4);
}
void Image4uint8::copyArray(const Color4* src, int w, int h) {
resize(w, h);
int N = w * h;
Color4uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i] = Color4uint8(src[i]);
}
}
void Image4uint8::copyArray(const Color3uint8* ptr, int w, int h) {
resize(w, h);
GImage::RGBtoRGBA((const uint8*)ptr, (uint8*)getCArray(), w * h);
}
void Image4uint8::copyArray(const Color3* src, int w, int h) {
resize(w, h);
int N = w * h;
Color4uint8* dst = getCArray();
for (int i = 0; i < N; ++i) {
dst[i] = Color4uint8(Color4(src[i], 1.0f));
}
}
/** Saves in any of the formats supported by G3D::GImage. */
void Image4uint8::save(const std::string& filename, GImage::Format fmt) {
GImage im(width(), height(), 4);
System::memcpy(im.byte(), getCArray(), width() * height() * 4);
im.save(filename, fmt);
}
ReferenceCountedPointer<class Image1uint8> Image4uint8::getChannel(int c) const {
debugAssert(c >= 0 && c <= 3);
Image1uint8Ref dst = Image1uint8::createEmpty(width(), height(), wrapMode());
const Color4uint8* srcArray = getCArray();
Color1uint8* dstArray = dst->getCArray();
const int N = width() * height();
for (int i = 0; i < N; ++i) {
dstArray[i] = Color1uint8(srcArray[i][c]);
}
return dst;
}
const ImageFormat* Image4uint8::format() const {
return ImageFormat::RGBA8();
}
} // G3D
-440
View File
@@ -1,440 +0,0 @@
/**
@file ImageFormat.cpp
@maintainer Morgan McGuire, [email protected]
@created 2003-05-23
@edited 2006-01-11
*/
#include "../../GLG3D.lib/include/GLG3D/glheaders.h"
#include "../../GLG3D.lib/include/GLG3D/glcalls.h"
#include "G3D/ImageFormat.h"
namespace G3D {
ImageFormat::ImageFormat(
int _numComponents,
bool _compressed,
int _glFormat,
int _glBaseFormat,
int _luminanceBits,
int _alphaBits,
int _redBits,
int _greenBits,
int _blueBits,
int _depthBits,
int _stencilBits,
int _hardwareBitsPerTexel,
int _packedBitsPerTexel,
int glDataFormat,
bool _opaque,
bool _floatingPoint,
Code _code,
ColorSpace _colorSpace,
BayerPattern _bayerPattern) :
numComponents(_numComponents),
compressed(_compressed),
code(_code),
colorSpace(_colorSpace),
bayerPattern(_bayerPattern),
openGLFormat(_glFormat),
openGLBaseFormat(_glBaseFormat),
luminanceBits(_luminanceBits),
alphaBits(_alphaBits),
redBits(_redBits),
greenBits(_greenBits),
blueBits(_blueBits),
stencilBits(_stencilBits),
depthBits(_depthBits),
cpuBitsPerPixel(_packedBitsPerTexel),
packedBitsPerTexel(_packedBitsPerTexel),
openGLBitsPerPixel(_hardwareBitsPerTexel),
hardwareBitsPerTexel(_hardwareBitsPerTexel),
openGLDataFormat(glDataFormat),
opaque(_opaque),
floatingPoint(_floatingPoint) {
debugAssert(_packedBitsPerTexel <= _hardwareBitsPerTexel);
}
const ImageFormat* ImageFormat::depth(int depthBits) {
switch (depthBits) {
case 16:
return DEPTH16();
case 24:
return DEPTH24();
case 32:
return DEPTH32();
default:
debugAssertM(false, "Depth must be 16, 24, or 32.");
return DEPTH32();
}
}
const ImageFormat* ImageFormat::stencil(int bits) {
switch (bits) {
case 1:
return STENCIL1();
case 4:
return STENCIL4();
case 8:
return STENCIL8();
case 16:
return STENCIL16();
default:
debugAssertM(false, "Stencil must be 1, 4, 8 or 16.");
return STENCIL16();
}
}
std::string ImageFormat::name() const {
static const std::string nameArray[] =
{
"L8",
"L16",
"L16F",
"L32F",
"A8",
"A16",
"A16F",
"A32F",
"LA4",
"LA8",
"LA16",
"LA16F",
"LA32F",
"RGB5",
"RGB5A1",
"RGB8",
"RGB10",
"RGB10A2",
"RGB16",
"RGB16F",
"RGB32F",
"ARGB8",
"BGR8",
"RGBA8",
"RGBA16",
"RGBA16F",
"RGBA32F",
"BAYER_RGGB8",
"BAYER_GRBG8",
"BAYER_GBRG8",
"BAYER_BGGR8",
"BAYER_RGGB32F",
"BAYER_GRBG32F",
"BAYER_GBRG32F",
"BAYER_BGGR32F",
"HSV8",
"HSV32F",
"YUV420_PLANAR",
"YUV422",
"YUV444",
"RGB_DXT1",
"RGBA_DXT1",
"RGBA_DXT3",
"RGBA_DXT5",
"DEPTH16",
"DEPTH24",
"DEPTH32",
"DEPTH32F",
"STENCIL1",
"STENCIL4",
"STENCIL8",
"STENCIL16",
"DEPTH24_STENCIL8"
};
debugAssert(code < CODE_NUM);
return nameArray[code];
}
const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
switch (code) {
case ImageFormat::CODE_L8:
return ImageFormat::L8();
break;
case ImageFormat::CODE_L16:
return ImageFormat::L16();
break;
case ImageFormat::CODE_L16F:
return ImageFormat::L16F();
break;
case ImageFormat::CODE_L32F:
return ImageFormat::L32F();
break;
case ImageFormat::CODE_A8:
return ImageFormat::A8();
break;
case ImageFormat::CODE_A16:
return ImageFormat::A16();
break;
case ImageFormat::CODE_A16F:
return ImageFormat::A16F();
break;
case ImageFormat::CODE_A32F:
return ImageFormat::A32F();
break;
case ImageFormat::CODE_LA4:
return ImageFormat::LA4();
break;
case ImageFormat::CODE_LA8:
return ImageFormat::LA8();
break;
case ImageFormat::CODE_LA16:
return ImageFormat::LA16();
break;
case ImageFormat::CODE_LA16F:
return ImageFormat::LA16F();
break;
case ImageFormat::CODE_LA32F:
return ImageFormat::LA32F();
break;
case ImageFormat::CODE_RGB5:
return ImageFormat::RGB5();
break;
case ImageFormat::CODE_RGB5A1:
return ImageFormat::RGB5A1();
break;
case ImageFormat::CODE_RGB8:
return ImageFormat::RGB8();
break;
case ImageFormat::CODE_RGB10:
return ImageFormat::RGB10();
break;
case ImageFormat::CODE_RGB10A2:
return ImageFormat::RGB10A2();
break;
case ImageFormat::CODE_RGB16:
return ImageFormat::RGB16();
break;
case ImageFormat::CODE_RGB16F:
return ImageFormat::RGB16F();
break;
case ImageFormat::CODE_RGB32F:
return ImageFormat::RGB32F();
break;
case ImageFormat::CODE_ARGB8:
return NULL;
case ImageFormat::CODE_BGR8:
return NULL;
case ImageFormat::CODE_RGBA8:
return ImageFormat::RGBA8();
break;
case ImageFormat::CODE_RGBA16:
return ImageFormat::RGBA16();
break;
case ImageFormat::CODE_RGBA16F:
return ImageFormat::RGBA16F();
break;
case ImageFormat::CODE_RGBA32F:
return ImageFormat::RGBA32F();
break;
case ImageFormat::CODE_BAYER_RGGB8:
case ImageFormat::CODE_BAYER_GRBG8:
case ImageFormat::CODE_BAYER_GBRG8:
case ImageFormat::CODE_BAYER_BGGR8:
case ImageFormat::CODE_BAYER_RGGB32F:
case ImageFormat::CODE_BAYER_GRBG32F:
case ImageFormat::CODE_BAYER_GBRG32F:
case ImageFormat::CODE_BAYER_BGGR32F:
case ImageFormat::CODE_HSV8:
case ImageFormat::CODE_HSV32F:
case ImageFormat::CODE_RGB_DXT1:
return ImageFormat::RGB_DXT1();
break;
case ImageFormat::CODE_RGBA_DXT1:
return ImageFormat::RGBA_DXT1();
break;
case ImageFormat::CODE_RGBA_DXT3:
return ImageFormat::RGBA_DXT3();
break;
case ImageFormat::CODE_RGBA_DXT5:
return ImageFormat::RGBA_DXT5();
break;
case ImageFormat::CODE_DEPTH16:
return ImageFormat::DEPTH16();
break;
case ImageFormat::CODE_DEPTH24:
return ImageFormat::DEPTH24();
break;
case ImageFormat::CODE_DEPTH32:
return ImageFormat::DEPTH32();
break;
case ImageFormat::CODE_DEPTH32F:
return ImageFormat::DEPTH32F();
break;
case ImageFormat::CODE_STENCIL1:
return ImageFormat::STENCIL1();
break;
case ImageFormat::CODE_STENCIL4:
return ImageFormat::STENCIL4();
break;
case ImageFormat::CODE_STENCIL8:
return ImageFormat::STENCIL8();
break;
case ImageFormat::CODE_STENCIL16:
return ImageFormat::STENCIL16();
break;
case ImageFormat::CODE_DEPTH24_STENCIL8:
return ImageFormat::DEPTH24_STENCIL8();
break;
case ImageFormat::CODE_YUV420_PLANAR:
return ImageFormat::YUV420_PLANAR();
break;
case ImageFormat::CODE_YUV422:
return ImageFormat::YUV422();
break;
case ImageFormat::CODE_YUV444:
return ImageFormat::YUV444();
break;
default:
return NULL;
}
}
// Helper variables for defining texture formats
// Is floating point format
static const bool FLOAT_FORMAT = true;
static const bool INT_FORMAT = false;
// Is opaque format (no alpha)
static const bool OPAQUE_FORMAT = true;
static const bool CLEAR_FORMAT = false;
// Is compressed format (not raw component data)
static const bool COMP_FORMAT = true;
static const bool UNCOMP_FORMAT = false;
#define DEFINE_TEXTUREFORMAT_METHOD(name, cmpnts, cmprssd, glf, glbf, lb, rb, gb, bb, db, sb, hbpt, pbpt, gldf, opq, fp, code, cs, bp) \
const ImageFormat* ImageFormat::name() { \
static const ImageFormat format(cmpnts, cmprssd, glf, glbf, lb, rb, gb, bb, db, sb, hbpt, pbpt, gldf, opq, fp, code, cs, bp); \
return &format; }
DEFINE_TEXTUREFORMAT_METHOD(L8, 1, UNCOMP_FORMAT, GL_LUMINANCE8, GL_LUMINANCE, 8, 0, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, CODE_L8, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(L16, 1, UNCOMP_FORMAT, GL_LUMINANCE16, GL_LUMINANCE, 16, 0, 0, 0, 0, 0, 0, 16, 16,GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INT_FORMAT, CODE_L16, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(L16F, 1, UNCOMP_FORMAT, GL_LUMINANCE16F_ARB,GL_LUMINANCE, 16, 0, 0, 0, 0, 0, 0, 16, 16, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, CODE_L16F, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(L32F, 1, UNCOMP_FORMAT, GL_LUMINANCE32F_ARB,GL_LUMINANCE, 32, 0, 0, 0, 0, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, CODE_L32F, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(A8, 1, UNCOMP_FORMAT, GL_ALPHA8, GL_ALPHA, 0, 8, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, CODE_A8, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(A16, 1, UNCOMP_FORMAT, GL_ALPHA16, GL_ALPHA, 0, 16, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, CODE_A16, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(A16F, 1, UNCOMP_FORMAT, GL_ALPHA16F_ARB, GL_ALPHA, 0, 16, 0, 0, 0, 0, 0, 16, 16, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, CODE_A16F, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(A32F, 1, UNCOMP_FORMAT, GL_ALPHA32F_ARB, GL_ALPHA, 0, 32, 0, 0, 0, 0, 0, 32, 32, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, CODE_A32F, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(LA4, 2, UNCOMP_FORMAT, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE_ALPHA, 4, 4, 0, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, CODE_LA4, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(LA8, 2, UNCOMP_FORMAT, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, 8, 8, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, CODE_LA8, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(LA16, 2, UNCOMP_FORMAT, GL_LUMINANCE16_ALPHA16, GL_LUMINANCE_ALPHA, 16, 16, 0, 0, 0, 0, 0, 16*2, 16*2, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, CODE_LA16, COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(LA16F, 2, UNCOMP_FORMAT, GL_LUMINANCE_ALPHA16F_ARB, GL_LUMINANCE_ALPHA, 16, 16, 0, 0, 0, 0, 0, 16*2, 16*2, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_LA16F, ImageFormat::COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(LA32F, 2, UNCOMP_FORMAT, GL_LUMINANCE_ALPHA32F_ARB, GL_LUMINANCE_ALPHA, 32, 32, 0, 0, 0, 0, 0, 32*2, 32*2, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_LA32F, ImageFormat::COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(BGR8, 3, UNCOMP_FORMAT, GL_RGB8, GL_BGR, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_BGR8, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGB5, 3, UNCOMP_FORMAT, GL_RGB5, GL_RGBA, 0, 0, 5, 5, 5, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB5, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGB5A1, 4, UNCOMP_FORMAT, GL_RGB5_A1, GL_RGBA, 0, 1, 5, 5, 5, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB5A1, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGB8, 3, UNCOMP_FORMAT, GL_RGB8, GL_RGB, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGB10, 3, UNCOMP_FORMAT, GL_RGB10, GL_RGB, 0, 0, 10, 10, 10, 0, 0, 32, 10*3, GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB10, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGB10A2, 4, UNCOMP_FORMAT, GL_RGB10_A2, GL_RGBA, 0, 2, 10, 10, 10, 0, 0, 32, 32, GL_UNSIGNED_INT_10_10_10_2, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB10A2, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGB16, 3, UNCOMP_FORMAT, GL_RGB16, GL_RGB, 0, 0, 16, 16, 16, 0, 0, 16*3, 16*3, GL_UNSIGNED_SHORT, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB16, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGB16F, 3, UNCOMP_FORMAT, GL_RGB16F_ARB, GL_RGB, 0, 0, 16, 16, 16, 0, 0, 16*3, 16*3, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGB16F, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGB32F, 3, UNCOMP_FORMAT, GL_RGB32F_ARB, GL_RGB, 0, 0, 32, 32, 32, 0, 0, 32*3, 32*3, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGB32F, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGBA8, 4, UNCOMP_FORMAT, GL_RGBA8, GL_RGBA, 0, 8, 8, 8, 8, 0, 0, 32, 32, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA8, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGBA16, 4, UNCOMP_FORMAT, GL_RGBA16, GL_RGBA, 0, 16, 16, 16, 16, 0, 0, 16*4, 16*4, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA16, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGBA16F, 4, UNCOMP_FORMAT, GL_RGBA16F_ARB, GL_RGBA, 0, 16, 16, 16, 16, 0, 0, 16*4, 16*4, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGB16F, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGBA32F, 4, UNCOMP_FORMAT, GL_RGBA32F_ARB, GL_RGBA, 0, 32, 32, 32, 32, 0, 0, 32*4, 32*4, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGBA32F, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGB_DXT1, 3, COMP_FORMAT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB_DXT1, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGBA_DXT1, 4, COMP_FORMAT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA_DXT1, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGBA_DXT3, 4, COMP_FORMAT, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 128, 128, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA_DXT3, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(RGBA_DXT5, 4, COMP_FORMAT, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, 0, 0, 0, 0, 0, 0, 0, 128, 128, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA_DXT5, ImageFormat::COLOR_SPACE_RGB);
DEFINE_TEXTUREFORMAT_METHOD(DEPTH16, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT16_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 0, 16, 16, 16, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH16, ImageFormat::COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(DEPTH24, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT24_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 0, 24, 32, 24, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH24, ImageFormat::COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(DEPTH32, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT32_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 0, 32, 32, 32, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH32, ImageFormat::COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(DEPTH32F, 1, UNCOMP_FORMAT, GL_DEPTH_COMPONENT32_ARB, GL_DEPTH_COMPONENT, 0, 0, 0, 0, 0, 0, 32, 32, 32, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_DEPTH32F, ImageFormat::COLOR_SPACE_NONE);
// These formats are for use with Renderbuffers only!
DEFINE_TEXTUREFORMAT_METHOD(STENCIL1, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX1_EXT, GL_STENCIL_INDEX_EXT, 0, 0, 0, 0, 0, 0, 1, 1, 1, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL1, ImageFormat::COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(STENCIL4, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX4_EXT, GL_STENCIL_INDEX_EXT, 0, 0, 0, 0, 0, 0, 4, 4, 4, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL4, ImageFormat::COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(STENCIL8, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX8_EXT, GL_STENCIL_INDEX_EXT, 0, 0, 0, 0, 0, 0, 8, 8, 8, GL_UNSIGNED_BYTE, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL8, ImageFormat::COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(STENCIL16, 1, UNCOMP_FORMAT, GL_STENCIL_INDEX16_EXT, GL_STENCIL_INDEX_EXT, 0, 0, 0, 0, 0, 0, 16, 16, 16, GL_UNSIGNED_SHORT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_STENCIL16, ImageFormat::COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(DEPTH24_STENCIL8, 2, UNCOMP_FORMAT, GL_DEPTH24_STENCIL8_EXT, GL_DEPTH_STENCIL_EXT,0, 0, 0, 0, 0, 24, 8, 32, 32, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_DEPTH24_STENCIL8, ImageFormat::COLOR_SPACE_NONE);
DEFINE_TEXTUREFORMAT_METHOD(YUV420_PLANAR, 3, UNCOMP_FORMAT, GL_NONE, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 12, 12, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_YUV420_PLANAR, ImageFormat::COLOR_SPACE_YUV);
DEFINE_TEXTUREFORMAT_METHOD(YUV422, 3, UNCOMP_FORMAT, GL_NONE, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_YUV422, ImageFormat::COLOR_SPACE_YUV);
DEFINE_TEXTUREFORMAT_METHOD(YUV444, 3, UNCOMP_FORMAT, GL_NONE, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 24, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_YUV444, ImageFormat::COLOR_SPACE_YUV);
}
File diff suppressed because it is too large Load Diff
-89
View File
@@ -1,89 +0,0 @@
/**
@file Line.cpp
Line class
@maintainer Morgan McGuire, graphics3d.com
@created 2001-06-02
@edited 2006-01-28
*/
#include "G3D/Line.h"
#include "G3D/Plane.h"
namespace G3D {
Vector3 Line::intersection(const Plane& plane) const {
float d;
Vector3 normal = plane.normal();
plane.getEquation(normal, d);
float rate = _direction.dot(normal);
if (rate == 0) {
return Vector3::inf();
} else {
float t = -(d + _point.dot(normal)) / rate;
return _point + _direction * t;
}
}
Line::Line(class BinaryInput& b) {
deserialize(b);
}
void Line::serialize(class BinaryOutput& b) const {
_point.serialize(b);
_direction.serialize(b);
}
void Line::deserialize(class BinaryInput& b) {
_point.deserialize(b);
_direction.deserialize(b);
}
Vector3 Line::closestPoint(const Vector3& pt) const {
float t = _direction.dot(pt - _point);
return _point + _direction * t;
}
Vector3 Line::point() const {
return _point;
}
Vector3 Line::direction() const {
return _direction;
}
Vector3 Line::closestPoint(const Line& B, float& minDist) const {
const Vector3& P1 = _point;
const Vector3& U1 = _direction;
Vector3 P2 = B.point();
Vector3 U2 = B.direction();
const Vector3& P21 = P2 - P1;
const Vector3& M = U2.cross(U1);
float m2 = M.length();
Vector3 R = P21.cross(M) / m2;
float t1 = R.dot(U2);
minDist = abs(P21.dot(M)) / sqrt(m2);
return P1 + t1 * U1;
}
}
-236
View File
@@ -1,236 +0,0 @@
/**
@file LineSegment.cpp
@maintainer Morgan McGuire, [email protected]
@created 2003-02-08
@edited 2008-02-02
*/
#include "G3D/platform.h"
#include "G3D/LineSegment.h"
#include "G3D/Sphere.h"
#include "G3D/debug.h"
namespace G3D {
Vector3 LineSegment::closestPoint(const Vector3& p) const {
// The vector from the end of the capsule to the point in question.
Vector3 v(p - _point);
// Projection of v onto the line segment scaled by
// the length of direction.
float t = direction.dot(v);
// Avoid some square roots. Derivation:
// t/direction.length() <= direction.length()
// t <= direction.squaredLength()
if ((t >= 0) && (t <= direction.squaredMagnitude())) {
// The point falls within the segment. Normalize direction,
// divide t by the length of direction.
return _point + direction * t / direction.squaredMagnitude();
} else {
// The point does not fall within the segment; see which end is closer.
// Distance from 0, squared
float d0Squared = v.squaredMagnitude();
// Distance from 1, squared
float d1Squared = (v - direction).squaredMagnitude();
if (d0Squared < d1Squared) {
// Point 0 is closer
return _point;
} else {
// Point 1 is closer
return _point + direction;
}
}
}
Vector3 LineSegment::point(int i) const {
switch (i) {
case 0:
return _point;
case 1:
return _point + direction;
default:
debugAssertM(i == 0 || i == 1, "Argument to point must be 0 or 1");
return _point;
}
}
bool LineSegment::intersectsSolidSphere(const class Sphere& s) const {
return distanceSquared(s.center) <= square(s.radius);
}
LineSegment::LineSegment(class BinaryInput& b) {
deserialize(b);
}
void LineSegment::serialize(class BinaryOutput& b) const {
_point.serialize(b);
direction.serialize(b);
}
void LineSegment::deserialize(class BinaryInput& b) {
_point.deserialize(b);
direction.deserialize(b);
}
Vector3 LineSegment::randomPoint() const {
return _point + uniformRandom(0, 1) * direction;
}
/////////////////////////////////////////////////////////////////////////////////////
LineSegment2D LineSegment2D::fromTwoPoints(const Vector2& p0, const Vector2& p1) {
LineSegment2D s;
s.m_origin = p0;
s.m_direction = p1 - p0;
s.m_length = s.m_direction.length();
return s;
}
Vector2 LineSegment2D::point(int i) const {
debugAssert(i == 0 || i == 1);
if (i == 0) {
return m_origin;
} else {
return m_direction + m_origin;
}
}
Vector2 LineSegment2D::closestPoint(const Vector2& Q) const {
// Two constants that appear in the result
const Vector2 k1(m_origin - Q);
const Vector2& k2 = m_direction;
if (fuzzyEq(m_length, 0)) {
// This line segment has no length
return m_origin;
}
// Time [0, 1] at which we hit the closest point travelling from p0 to p1.
// Derivation can be obtained by minimizing the expression
// ||P0 + (P1 - P0)t - Q||.
const float t = -k1.dot(k2) / (m_length * m_length);
if (t < 0) {
// Clipped to low end point
return m_origin;
} else if (t > 1) {
// Clipped to high end point
return m_origin + m_direction;
} else {
// Subsitute into the line equation to find
// the point on the segment.
return m_origin + k2 * t;
}
}
float LineSegment2D::distance(const Vector2& p) const {
Vector2 closest = closestPoint(p);
return (closest - p).length();
}
float LineSegment2D::length() const {
return m_length;
}
Vector2 LineSegment2D::intersection(const LineSegment2D& other) const {
if ((m_origin == other.m_origin) ||
(m_origin == other.m_origin + other.m_direction)) {
return m_origin;
}
if (m_origin + m_direction == other.m_origin) {
return other.m_origin;
}
// Note: Now that we've checked the endpoints, all other parallel lines can now be assumed
// to not intersect (within numerical precision)
Vector2 dir1 = m_direction;
Vector2 dir2 = other.m_direction;
Vector2 origin1 = m_origin;
Vector2 origin2 = other.m_origin;
if (dir1.x == 0) {
// Avoid an upcoming divide by zero
dir1 = dir1.yx();
dir2 = dir2.yx();
origin1 = origin1.yx();
origin2 = origin2.yx();
}
// t1 = ((other.m_origin.x - m_origin.x) + other.m_direction.x * t2) / m_direction.x
//
// ((other.m_origin.x - m_origin.x) + other.m_direction.x * t2) * m_direction.y / m_direction.x =
// (other.m_origin.y - m_origin.y) + other.m_direction.y * t2
//
// m = m_direction.y / m_direction.x
// d = other.m_origin - m_origin
//
// (d.x + other.m_direction.x * t2) * m = d.y + other.m_direction.y * t2
//
// d.x * m + other.m_direction.x * m * t2 = d.y + other.m_direction.y * t2
//
// d.x * m - d.y = (other.m_direction.y - other.m_direction.x * m) * t2
//
// (d.x * m - d.y) / (other.m_direction.y - other.m_direction.x * m) = t2
//
Vector2 d = origin2 - origin1;
float m = dir1.y / dir1.x;
float t2 = (d.x * m - d.y) / (dir2.y - dir2.x * m);
if (! isFinite(t2)) {
// Parallel lines: no intersection
return Vector2::inf();
}
if ((t2 < 0.0f) || (t2 > 1.0f)) {
// Intersection occurs past the end of the line segments
return Vector2::inf();
}
float t1 = (d.x + dir2.x * t2) / dir1.x;
if ((t1 < 0.0f) || (t1 > 1.0f)) {
// Intersection occurs past the end of the line segments
return Vector2::inf();
}
// Return the intersection point (computed from non-transposed
// variables even if we flipped above)
return m_origin + m_direction * t1;
}
}
-157
View File
@@ -1,157 +0,0 @@
/**
@file Log.cpp
@maintainer Morgan McGuire, [email protected]
@created 2001-08-04
@edited 2005-07-01
*/
#include "G3D/platform.h"
#include "G3D/Log.h"
#include "G3D/format.h"
#include "G3D/Array.h"
#include "G3D/fileutils.h"
#include <time.h>
#ifdef G3D_WIN32
#include <imagehlp.h>
#else
#include <stdarg.h>
#endif
namespace G3D {
void logPrintf(const char* fmt, ...) {
va_list arg_list;
va_start(arg_list, fmt);
Log::common()->vprintf(fmt, arg_list);
va_end(arg_list);
}
Log* Log::commonLog = NULL;
Log::Log(const std::string& filename, int stripFromStackBottom) :
stripFromStackBottom(stripFromStackBottom) {
this->filename = filename;
logFile = fopen(filename.c_str(), "w");
if (logFile == NULL) {
std::string drive, base, ext;
Array<std::string> path;
parseFilename(filename, drive, path, base, ext);
std::string logName = base + ((ext != "") ? ("." + ext) : "");
// Write time is greater than 1ms. This may be a network drive.... try another file.
#ifdef G3D_WIN32
logName = std::string(std::getenv("TEMP")) + logName;
#else
logName = std::string("/tmp/") + logName;
#endif
logFile = fopen(logName.c_str(), "w");
}
// Turn off buffering.
setvbuf(logFile, NULL, _IONBF, 0);
fprintf(logFile, "Application Log\n");
time_t t;
time(&t);
fprintf(logFile, "Start: %s\n", ctime(&t));
fflush(logFile);
if (commonLog == NULL) {
commonLog = this;
}
}
Log::~Log() {
section("Shutdown");
println("Closing log file");
// Make sure we don't leave a dangling pointer
if (Log::commonLog == this) {
Log::commonLog = NULL;
}
fclose(logFile);
}
FILE* Log::getFile() const {
return logFile;
}
Log* Log::common() {
if (commonLog == NULL) {
commonLog = new Log();
}
return commonLog;
}
std::string Log::getCommonLogFilename() {
return common()->filename;
}
void Log::section(const std::string& s) {
fprintf(logFile, "_____________________________________________________\n");
fprintf(logFile, "\n ### %s ###\n\n", s.c_str());
}
void __cdecl Log::printf(const char* fmt, ...) {
printHeader();
va_list arg_list;
va_start(arg_list, fmt);
print(vformat(fmt, arg_list));
va_end(arg_list);
}
void __cdecl Log::vprintf(const char* fmt, va_list argPtr) {
vfprintf(logFile, fmt, argPtr);
}
void Log::print(const std::string& s) {
printHeader();
fprintf(logFile, "%s", s.c_str());
}
void Log::println(const std::string& s) {
printHeader();
fprintf(logFile, "%s\n", s.c_str());
}
void Log::printHeader() {
time_t t;
if (time(&t) != ((time_t)-1)) {
/*
char buf[32];
strftime(buf, 32, "[%H:%M:%S]", localtime(&t));
Removed because this doesn't work on SDL threads.
#ifdef _DEBUG
std::string bt = getBacktrace(15, 2, stripFromStackBottom);
fprintf(logFile, "\n %s %s\n\n", buf, bt.c_str());
#endif
fprintf(logFile, "\n %s \n", buf);
*/
} else {
println("[Error getting time]");
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-433
View File
@@ -1,433 +0,0 @@
/**
@file Matrix4.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2003-10-02
@edited 2008-07-17
*/
#include "G3D/platform.h"
#include "G3D/Matrix4.h"
#include "G3D/Matrix3.h"
#include "G3D/Vector4.h"
#include "G3D/Vector3.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/CoordinateFrame.h"
#include "G3D/Rect2D.h"
namespace G3D {
const Matrix4& Matrix4::identity() {
static Matrix4 m(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
return m;
}
const Matrix4& Matrix4::zero() {
static Matrix4 m(
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0);
return m;
}
Matrix4::Matrix4(const class CoordinateFrame& cframe) {
for (int r = 0; r < 3; ++r) {
for (int c = 0; c < 3; ++c) {
elt[r][c] = cframe.rotation[r][c];
}
elt[r][3] = cframe.translation[r];
}
elt[3][0] = 0.0f;
elt[3][1] = 0.0f;
elt[3][2] = 0.0f;
elt[3][3] = 1.0f;
}
Matrix4::Matrix4(const Matrix3& upper3x3, const Vector3& lastCol) {
for (int r = 0; r < 3; ++r) {
for (int c = 0; c < 3; ++c) {
elt[r][c] = upper3x3[r][c];
}
elt[r][3] = lastCol[r];
}
elt[3][0] = 0.0f;
elt[3][1] = 0.0f;
elt[3][2] = 0.0f;
elt[3][3] = 1.0f;
}
Matrix3 Matrix4::upper3x3() const {
return Matrix3(elt[0][0], elt[0][1], elt[0][2],
elt[1][0], elt[1][1], elt[1][2],
elt[2][0], elt[2][1], elt[2][2]);
}
Matrix4 Matrix4::orthogonalProjection(
const class Rect2D& rect,
float nearval,
float farval) {
return Matrix4::orthogonalProjection(rect.x0(), rect.x1(), rect.y1(), rect.y0(), nearval, farval);
}
Matrix4 Matrix4::orthogonalProjection(
float left,
float right,
float bottom,
float top,
float nearval,
float farval) {
// Adapted from Mesa. Note that Microsoft (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/glfunc03_8qnj.asp)
// and Linux (http://www.xfree86.org/current/glOrtho.3.html) have different matrices shown in their documentation.
float x, y, z;
float tx, ty, tz;
x = 2.0f / (right-left);
y = 2.0f / (top-bottom);
z = -2.0f / (farval-nearval);
tx = -(right+left) / (right-left);
ty = -(top+bottom) / (top-bottom);
tz = -(farval+nearval) / (farval-nearval);
return
Matrix4( x , 0.0f, 0.0f, tx,
0.0f, y , 0.0f, ty,
0.0f, 0.0f, z , tz,
0.0f, 0.0f, 0.0f, 1.0f);
}
Matrix4 Matrix4::perspectiveProjection(
float left,
float right,
float bottom,
float top,
float nearval,
float farval) {
float x, y, a, b, c, d;
x = (2.0f*nearval) / (right-left);
y = (2.0f*nearval) / (top-bottom);
a = (right+left) / (right-left);
b = (top+bottom) / (top-bottom);
if ((float)farval >= (float)inf()) {
// Infinite view frustum
c = -1.0f;
d = -2.0f * nearval;
} else {
c = -(farval+nearval) / (farval-nearval);
d = -(2.0f*farval*nearval) / (farval-nearval);
}
return Matrix4(
x, 0, a, 0,
0, y, b, 0,
0, 0, c, d,
0, 0, -1, 0);
}
Matrix4::Matrix4(
float r1c1, float r1c2, float r1c3, float r1c4,
float r2c1, float r2c2, float r2c3, float r2c4,
float r3c1, float r3c2, float r3c3, float r3c4,
float r4c1, float r4c2, float r4c3, float r4c4) {
elt[0][0] = r1c1; elt[0][1] = r1c2; elt[0][2] = r1c3; elt[0][3] = r1c4;
elt[1][0] = r2c1; elt[1][1] = r2c2; elt[1][2] = r2c3; elt[1][3] = r2c4;
elt[2][0] = r3c1; elt[2][1] = r3c2; elt[2][2] = r3c3; elt[2][3] = r3c4;
elt[3][0] = r4c1; elt[3][1] = r4c2; elt[3][2] = r4c3; elt[3][3] = r4c4;
}
/**
init should be <B>row major</B>.
*/
Matrix4::Matrix4(const float* init) {
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
elt[r][c] = init[r * 4 + c];
}
}
}
Matrix4::Matrix4(const double* init) {
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
elt[r][c] = (float)init[r * 4 + c];
}
}
}
Matrix4::Matrix4() {
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
elt[r][c] = 0;
}
}
}
void Matrix4::setRow(int r, const Vector4& v) {
for (int c = 0; c < 4; ++c) {
elt[r][c] = v[c];
}
}
void Matrix4::setColumn(int c, const Vector4& v) {
for (int r = 0; r < 4; ++r) {
elt[r][c] = v[r];
}
}
Vector4 Matrix4::getRow(int r) const {
return row(r);
}
const Vector4& Matrix4::row(int r) const {
return reinterpret_cast<const Vector4*>(elt[r])[0];
}
Vector4 Matrix4::getColumn(int c) const {
return column(c);
}
Vector4 Matrix4::column(int c) const {
Vector4 v;
for (int r = 0; r < 4; ++r) {
v[r] = elt[r][c];
}
return v;
}
Matrix4 Matrix4::operator*(const Matrix4& other) const {
Matrix4 result;
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
for (int i = 0; i < 4; ++i) {
result.elt[r][c] += elt[r][i] * other.elt[i][c];
}
}
}
return result;
}
Matrix4 Matrix4::operator*(const float s) const {
Matrix4 result;
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
result.elt[r][c] = elt[r][c] * s;
}
}
return result;
}
Vector3 Matrix4::homoMul(const class Vector3& v, float w) const {
Vector4 r = (*this) * Vector4(v, w);
return r.xyz() * (1.0f / r.w);
}
Vector4 Matrix4::operator*(const Vector4& vector) const {
Vector4 result(0,0,0,0);
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
result[r] += elt[r][c] * vector[c];
}
}
return result;
}
Matrix4 Matrix4::transpose() const {
Matrix4 result;
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
result.elt[c][r] = elt[r][c];
}
}
return result;
}
bool Matrix4::operator!=(const Matrix4& other) const {
return ! (*this == other);
}
bool Matrix4::operator==(const Matrix4& other) const {
// If the bit patterns are identical, they must be
// the same matrix. If not, they *might* still have
// equal elements due to floating point weirdness.
if (memcmp(this, &other, sizeof(Matrix4) == 0)) {
return true;
}
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
if (elt[r][c] != other.elt[r][c]) {
return false;
}
}
}
return true;
}
float Matrix4::determinant() const {
// Determinant is the dot product of the first row and the first row
// of cofactors (i.e. the first col of the adjoint matrix)
return cofactor().getRow(0).dot(getRow(0));
}
Matrix4 Matrix4::adjoint() const {
return cofactor().transpose();
}
Matrix4 Matrix4::inverse() const {
// Inverse = adjoint / determinant
Matrix4 A = adjoint();
// Determinant is the dot product of the first row and the first row
// of cofactors (i.e. the first col of the adjoint matrix)
float det = A.getColumn(0).dot(getRow(0));
return A * (1.0f / det);
}
Matrix4 Matrix4::cofactor() const {
Matrix4 out;
// We'll use i to incrementally compute -1 ^ (r+c)
int i = 1;
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
// Compute the determinant of the 3x3 submatrix
float det = subDeterminant(r, c);
out.elt[r][c] = i * det;
i = -i;
}
i = -i;
}
return out;
}
float Matrix4::subDeterminant(int excludeRow, int excludeCol) const {
// Compute non-excluded row and column indices
int row[3];
int col[3];
for (int i = 0; i < 3; ++i) {
row[i] = i;
col[i] = i;
if (i >= excludeRow) {
++row[i];
}
if (i >= excludeCol) {
++col[i];
}
}
// Compute the first row of cofactors
float cofactor00 =
elt[row[1]][col[1]] * elt[row[2]][col[2]] -
elt[row[1]][col[2]] * elt[row[2]][col[1]];
float cofactor10 =
elt[row[1]][col[2]] * elt[row[2]][col[0]] -
elt[row[1]][col[0]] * elt[row[2]][col[2]];
float cofactor20 =
elt[row[1]][col[0]] * elt[row[2]][col[1]] -
elt[row[1]][col[1]] * elt[row[2]][col[0]];
// Product of the first row and the cofactors along the first row
return
elt[row[0]][col[0]] * cofactor00 +
elt[row[0]][col[1]] * cofactor10 +
elt[row[0]][col[2]] * cofactor20;
}
CoordinateFrame Matrix4::approxCoordinateFrame() const {
CoordinateFrame cframe;
for (int r = 0; r < 3; ++r) {
for (int c = 0; c < 3; ++c) {
cframe.rotation[r][c] = elt[r][c];
}
cframe.translation[r] = elt[r][3];
}
// Ensure that the rotation matrix is orthonormal
cframe.rotation.orthonormalize();
return cframe;
}
void Matrix4::serialize(class BinaryOutput& b) const {
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
b.writeFloat32(elt[r][c]);
}
}
}
void Matrix4::deserialize(class BinaryInput& b) {
for (int r = 0; r < 4; ++r) {
for (int c = 0; c < 4; ++c) {
elt[r][c] = b.readFloat32();
}
}
}
std::string Matrix4::toString() const {
return G3D::format("[%g, %g, %g, %g; %g, %g, %g, %g; %g, %g, %g, %g; %g, %g, %g, %g]",
elt[0][0], elt[0][1], elt[0][2], elt[0][3],
elt[1][0], elt[1][1], elt[1][2], elt[1][3],
elt[2][0], elt[2][1], elt[2][2], elt[2][3],
elt[3][0], elt[3][1], elt[3][2], elt[3][3]);
}
} // namespace
-733
View File
@@ -1,733 +0,0 @@
/**
@file MeshAlg.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2003-09-14
@edited 2008-09-03
Copyright 2000-2008, Morgan McGuire.
All rights reserved.
*/
#include "G3D/MeshAlg.h"
#include "G3D/Table.h"
#include "G3D/Set.h"
#include "G3D/Box.h"
#include "G3D/Sphere.h"
#include "G3D/vectorMath.h"
#include "G3D/AABox.h"
#include <climits>
namespace G3D {
const int MeshAlg::Face::NONE = INT_MIN;
void MeshAlg::generateGrid(
Array<Vector3>& vertex,
Array<Vector2>& texCoord,
Array<int>& index,
int wCells,
int hCells,
const Vector2& textureScale,
bool spaceCentered,
bool twoSided,
const CoordinateFrame& xform) {
vertex.fastClear();
texCoord.fastClear();
index.fastClear();
// Generate vertices
for (int z = 0; z <= hCells; ++z) {
for (int x = 0; x <= wCells; ++x) {
Vector3 v(x / (float)wCells, 0, z / (float)hCells);
Vector2 t = v.xz() * textureScale;
texCoord.append(t);
if (spaceCentered) {
v -= Vector3(0.5f, 0, 0.5f);
}
v = xform.pointToWorldSpace(v);
vertex.append(v);
}
}
// Generate indices
for (int z = 0; z < hCells; ++z) {
for (int x = 0; x < wCells; ++x) {
int A = x + z * (wCells + 1);
int B = A + 1;
int C = A + (wCells + 1);
int D = C + 1;
// A B
// *-----*
// | \ |
// | \ |
// *-----*
// C D
index.append(A, D, B);
index.append(A, C, D);
}
}
if (twoSided) {
// The index array needs to have reversed winding for the bottom
// and offset by the original number of vertices
Array<int> ti = index;
ti.reverse();
for (int i = 0; i < ti.size(); ++i) {
ti[i] += vertex.size();
}
index.append(ti);
// Duplicate the arrays
vertex.append(Array<Vector3>(vertex));
texCoord.append(Array<Vector2>(texCoord));
}
}
MeshAlg::Face::Face() {
for (int i = 0; i < 3; ++i) {
edgeIndex[i] = 0;
vertexIndex[i] = 0;
}
}
MeshAlg::Edge::Edge() {
for (int i = 0; i < 2; ++i) {
vertexIndex[i] = 0;
// Negative face indices are faces that don't exist
faceIndex[i] = -1;
}
}
MeshAlg::Geometry& MeshAlg::Geometry::operator=(const MeshAlg::Geometry& src) {
vertexArray.resize(src.vertexArray.size());
normalArray.resize(src.vertexArray.size());
System::memcpy(vertexArray.getCArray(), src.vertexArray.getCArray(), sizeof(Vector3)*vertexArray.size());
System::memcpy(normalArray.getCArray(), src.normalArray.getCArray(), sizeof(Vector3)*normalArray.size());
return *this;
}
void MeshAlg::computeNormals(
Geometry& geometry,
const Array<int>& indexArray) {
Array<Face> faceArray;
Array<Vertex> vertexArray;
Array<Edge> edgeArray;
Array<Vector3> faceNormalArray;
computeAdjacency(geometry.vertexArray, indexArray, faceArray, edgeArray, vertexArray);
computeNormals(geometry.vertexArray, faceArray, vertexArray,
geometry.normalArray, faceNormalArray);
}
void MeshAlg::computeNormals(
const Array<Vector3>& vertexGeometry,
const Array<Face>& faceArray,
const Array< Array<int> >& adjacentFaceArray,
Array<Vector3>& vertexNormalArray,
Array<Vector3>& faceNormalArray) {
// Construct a fake vertex array for backwards compatibility
Array<Vertex> fakeVertexArray(adjacentFaceArray.size());
for (int v = 0; v < adjacentFaceArray.size(); ++v) {
fakeVertexArray[v].faceIndex = adjacentFaceArray[v];
// We leave out the edges because they aren't used to compute normals
}
computeNormals(vertexGeometry, faceArray, fakeVertexArray,
vertexNormalArray, faceNormalArray);
}
void MeshAlg::computeNormals(
const Array<Vector3>& vertexGeometry,
const Array<Face>& faceArray,
const Array<Vertex>& vertexArray,
Array<Vector3>& vertexNormalArray,
Array<Vector3>& faceNormalArray) {
// Face normals (not unit length)
faceNormalArray.resize(faceArray.size());
for (int f = 0; f < faceArray.size(); ++f) {
const Face& face = faceArray[f];
Vector3 vertex[3];
for (int j = 0; j < 3; ++j) {
vertex[j] = vertexGeometry[face.vertexIndex[j]];
debugAssert(vertex[j].isFinite());
}
faceNormalArray[f] = (vertex[1] - vertex[0]).cross(vertex[2] - vertex[0]);
# ifdef G3D_DEBUG
const Vector3& N = faceNormalArray[f];
debugAssert(N.isFinite());
# endif
}
// Per-vertex normals, computed by averaging
vertexNormalArray.resize(vertexGeometry.size());
for (int v = 0; v < vertexNormalArray.size(); ++v) {
Vector3 sum = Vector3::zero();
for (int k = 0; k < vertexArray[v].faceIndex.size(); ++k) {
const int f = vertexArray[v].faceIndex[k];
sum += faceNormalArray[f];
}
vertexNormalArray[v] = sum.directionOrZero();
# ifdef G3D_DEBUG
const Vector3& N = vertexNormalArray[v];
debugAssert(N.isUnit() || N.isZero());
# endif
}
for (int f = 0; f < faceArray.size(); ++f) {
faceNormalArray[f] = faceNormalArray[f].directionOrZero();
# ifdef G3D_DEBUG
const Vector3& N = faceNormalArray[f];
debugAssert(N.isUnit() || N.isZero());
# endif
}
}
void MeshAlg::computeFaceNormals(
const Array<Vector3>& vertexArray,
const Array<MeshAlg::Face>& faceArray,
Array<Vector3>& faceNormals,
bool normalize) {
faceNormals.resize(faceArray.size());
for (int f = 0; f < faceArray.size(); ++f) {
const MeshAlg::Face& face = faceArray[f];
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
const Vector3& v1 = vertexArray[face.vertexIndex[1]];
const Vector3& v2 = vertexArray[face.vertexIndex[2]];
faceNormals[f] = (v1 - v0).cross(v2 - v0);
}
if (normalize) {
for (int f = 0; f < faceArray.size(); ++f) {
faceNormals[f] = faceNormals[f].direction();
}
}
}
void MeshAlg::identifyBackfaces(
const Array<Vector3>& vertexArray,
const Array<MeshAlg::Face>& faceArray,
const Vector4& HP,
Array<bool>& backface) {
Vector3 P = HP.xyz();
backface.resize(faceArray.size());
if (fuzzyEq(HP.w, 0.0)) {
// Infinite case
for (int f = faceArray.size() - 1; f >= 0; --f) {
const MeshAlg::Face& face = faceArray[f];
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
const Vector3& v1 = vertexArray[face.vertexIndex[1]];
const Vector3& v2 = vertexArray[face.vertexIndex[2]];
const Vector3 N = (v1 - v0).cross(v2 - v0);
backface[f] = N.dot(P) < 0;
}
} else {
// Finite case
for (int f = faceArray.size() - 1; f >= 0; --f) {
const MeshAlg::Face& face = faceArray[f];
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
const Vector3& v1 = vertexArray[face.vertexIndex[1]];
const Vector3& v2 = vertexArray[face.vertexIndex[2]];
const Vector3 N = (v1 - v0).cross(v2 - v0);
backface[f] = N.dot(P - v0) < 0;
}
}
}
void MeshAlg::identifyBackfaces(
const Array<Vector3>& vertexArray,
const Array<MeshAlg::Face>& faceArray,
const Vector4& HP,
Array<bool>& backface,
const Array<Vector3>& faceNormals) {
Vector3 P = HP.xyz();
backface.resize(faceArray.size());
if (fuzzyEq(HP.w, 0.0)) {
// Infinite case
for (int f = faceArray.size() - 1; f >= 0; --f) {
const Vector3& N = faceNormals[f];
backface[f] = N.dot(P) < 0;
}
} else {
// Finite case
for (int f = faceArray.size() - 1; f >= 0; --f) {
const MeshAlg::Face& face = faceArray[f];
const Vector3& v0 = vertexArray[face.vertexIndex[0]];
const Vector3& N = faceNormals[f];
backface[f] = N.dot(P - v0) < 0;
}
}
}
void MeshAlg::createIndexArray(int n, Array<int>& array, int start, int run, int skip) {
debugAssert(skip >= 0);
debugAssert(run >= 0);
array.resize(n);
if (skip == 0) {
for (int i = 0; i < n; ++i) {
array[i] = start + i;
}
} else {
int rcount = 0;
int j = start;
for (int i = 0; i < n; ++i) {
array[i] = j;
++j;
++rcount;
if (rcount == run) {
rcount = 0;
j += skip;
}
}
}
}
void MeshAlg::computeAreaStatistics(
const Array<Vector3>& vertexArray,
const Array<int>& indexArray,
double& minEdgeLength,
double& meanEdgeLength,
double& medianEdgeLength,
double& maxEdgeLength,
double& minFaceArea,
double& meanFaceArea,
double& medianFaceArea,
double& maxFaceArea) {
debugAssert(indexArray.size() % 3 == 0);
Array<double> area(indexArray.size() / 3);
Array<double> magnitude(indexArray.size());
for (int i = 0; i < indexArray.size(); i += 3) {
const Vector3& v0 = vertexArray[indexArray[i]];
const Vector3& v1 = vertexArray[indexArray[i + 1]];
const Vector3& v2 = vertexArray[indexArray[i + 2]];
area[i / 3] = (v1 - v0).cross(v2 - v0).magnitude() / 2.0;
magnitude[i] = (v1 - v0).magnitude();
magnitude[i + 1] = (v2 - v1).magnitude();
magnitude[i + 2] = (v0 - v2).magnitude();
}
area.sort();
magnitude.sort();
minEdgeLength = max(0.0, magnitude[0]);
maxEdgeLength = max(0.0, magnitude.last());
medianEdgeLength = max(0.0, magnitude[magnitude.size() / 2]);
meanEdgeLength = 0;
for (int i = 0; i < magnitude.size(); ++i) {
meanEdgeLength += magnitude[i];
}
meanEdgeLength /= magnitude.size();
minFaceArea = max(0.0, area[0]);
maxFaceArea = max(0.0, area.last());
medianFaceArea = max(0.0, area[area.size() / 2]);
meanFaceArea = 0;
for (int i = 0; i < area.size(); ++i) {
meanFaceArea += area[i];
}
meanFaceArea /= area.size();
// Make sure round-off hasn't pushed values less than zero
meanFaceArea = max(0.0, meanFaceArea);
meanEdgeLength = max(0.0, meanEdgeLength);
}
int MeshAlg::countBoundaryEdges(const Array<MeshAlg::Edge>& edgeArray) {
int b = 0;
for (int i = 0; i < edgeArray.size(); ++i) {
if ((edgeArray[i].faceIndex[0] == MeshAlg::Face::NONE) !=
(edgeArray[i].faceIndex[1] == MeshAlg::Face::NONE)) {
++b;
}
}
return b;
}
void MeshAlg::computeBounds(
const Array<Vector3>& vertexArray,
const Array<int>& indexArray,
Box& box,
Sphere& sphere) {
Array<Vector3> newArray(indexArray.size());
for (int i = 0; i < indexArray.size(); ++i) {
newArray[i] = vertexArray[indexArray[i]];
}
computeBounds(newArray, box, sphere);
}
void MeshAlg::computeBounds(
const Array<Vector3>& vertexArray,
Box& box,
Sphere& sphere) {
Vector3 xmin, xmax, ymin, ymax, zmin, zmax;
// FIRST PASS: find 6 minima/maxima points
xmin.x = ymin.y = zmin.z = inf();
xmax.x = ymax.y = zmax.z = -inf();
for (int v = 0; v < vertexArray.size(); ++v) {
const Vector3& vertex = vertexArray[v];
if (vertex.x < xmin.x) {
xmin = vertex;
}
if (vertex.x > xmax.x) {
xmax = vertex;
}
if (vertex.y < ymin.y) {
ymin = vertex;
}
if (vertex.y > ymax.y) {
ymax = vertex;
}
if (vertex.z < zmin.z) {
zmin = vertex;
}
if (vertex.z > zmax.z) {
zmax = vertex;
}
}
// Set points dia1 & dia2 to the maximally separated pair
Vector3 dia1 = xmin;
Vector3 dia2 = xmax;
{
// Set xspan = distance between the 2 points xmin & xmax (squared)
double xspan = (xmax - xmin).squaredMagnitude();
// Same for y & z spans
double yspan = (ymax - ymin).squaredMagnitude();
double zspan = (zmax - zmin).squaredMagnitude();
double maxspan = xspan;
if (yspan > maxspan) {
maxspan = yspan;
dia1 = ymin;
dia2 = ymax;
}
if (zspan > maxspan) {
maxspan = zspan;
dia1 = zmin;
dia2 = zmax;
}
}
// dia1, dia2 is a diameter of initial sphere
// calc initial center
Vector3 center = (dia1 + dia2) / 2.0;
// calculate initial radius^2 and radius
Vector3 d = dia2 - sphere.center;
double radSq = d.squaredMagnitude();
double rad = sqrt(radSq);
// SECOND PASS: increment current sphere
double old_to_p, old_to_new;
for (int v = 0; v < vertexArray.size(); ++v) {
const Vector3& vertex = vertexArray[v];
d = vertex - center;
double old_to_p_sq = d.squaredMagnitude();
// do r^2 test first
if (old_to_p_sq > radSq) {
// this point is outside of current sphere
old_to_p = sqrt(old_to_p_sq);
// calc radius of new sphere
rad = (rad + old_to_p) / 2.0;
// for next r^2 compare
radSq = rad * rad;
old_to_new = old_to_p - rad;
// calc center of new sphere
center = (rad * center + old_to_new * vertex) / old_to_p;
}
}
const Vector3 min(xmin.x, ymin.y, zmin.z);
const Vector3 max(xmax.x, ymax.y, zmax.z);
box = Box(min, max);
const double boxRadSq = (max - min).squaredMagnitude() * 0.25;
if (boxRadSq >= radSq){
if (isNaN(center.x) || ! isFinite(rad)) {
sphere = Sphere(Vector3::zero(), inf());
} else {
sphere = Sphere(center, rad);
}
}else{
sphere = Sphere((max + min) * 0.5, sqrt(boxRadSq));
}
}
void MeshAlg::computeTangentVectors(
const Vector3& normal,
const Vector3 position[3],
const Vector2 texCoord[3],
Vector3& tangent,
Vector3& binormal) {
Vector3 v[3];
Vector2 t[3];
// TODO: don't need the copy
// Make a copy so that we can sort
for (int i = 0; i < 3; ++i) {
v[i] = position[i];
t[i] = texCoord[i];
}
/////////////////////////////////////////////////
// Begin by computing the tangent
// Bubble sort the vertices by decreasing texture coordinate y.
if (t[0].y < t[1].y) {
std::swap(v[0], v[1]);
std::swap(t[0], t[1]);
}
// t0 >= t1
if (t[0].y < t[2].y) {
std::swap(v[0], v[2]);
std::swap(t[0], t[2]);
}
// t0 >= t2, t0 >= t1
if (t[1].y < t[2].y) {
std::swap(v[1], v[2]);
std::swap(t[1], t[2]);
}
// t0 >= t1 >= t2
float amount;
// Compute the direction of constant y.
if (fuzzyEq(t[2].y, t[0].y)) {
// Degenerate case-- the texture coordinates do not vary across this
// triangle.
amount = 1.0;
} else {
// Solve lerp(t[0].y, t[2].y, amount) = t[1].y for amount:
//
// t0 + (t2 - t0) * a = t1
// a = (t1 - t0) / (t2 - t0)
amount = (t[1].y - t[0].y) / (t[2].y - t[0].y);
}
tangent = lerp(v[0], v[2], amount) - v[1];
// Make sure the tangent points in the right direction and is
// perpendicular to the normal.
if (lerp(t[0].x, t[2].x, amount) < t[1].x) {
tangent = -tangent;
}
// TODO: do we need this? We take this component off
// at the end anyway
tangent -= tangent.dot(normal) * normal;
// Normalize the tangent so it contributes
// equally at the vertex (TODO: do we need this?)
if (fuzzyEq(tangent.magnitude(), 0.0)) {
tangent = Vector3::unitX();
} else {
tangent = tangent.direction();
}
//////////////////////////////////////////////////
// Now compute the binormal (same code, but in x)
// Sort the vertices by texture coordinate x.
if (t[0].x < t[1].x) {
std::swap(v[0], v[1]);
std::swap(t[0], t[1]);
}
if (t[0].x < t[2].x) {
std::swap(v[0], v[2]);
std::swap(t[0], t[2]);
}
if (t[1].x < t[2].x) {
std::swap(v[1], v[2]);
std::swap(t[1], t[2]);
}
// Compute the direction of constant x.
if (fuzzyEq(t[2].x, t[0].x)) {
amount = 1.0;
} else {
amount = (t[1].x - t[0].x) / (t[2].x - t[0].x);
}
binormal = lerp(v[0], v[2], amount) - v[1];
// Make sure the binormal points in the right direction and is
// perpendicular to the normal.
if (lerp(t[0].y, t[2].y, amount) < t[1].y) {
binormal = -binormal;
}
binormal -= binormal.dot(normal) * normal;
// Normalize the binormal so that it contributes
// an equal amount to the per-vertex value (TODO: do we need this?
// Nelson Max showed that we don't for computing per-vertex normals)
if (fuzzyEq(binormal.magnitude(), 0.0)) {
binormal = Vector3::unitZ();
} else {
binormal = binormal.direction();
}
// This computation gives the opposite convention of what we want.
binormal = -binormal;
}
void MeshAlg::computeTangentSpaceBasis(
const Array<Vector3>& vertexArray,
const Array<Vector2>& texCoordArray,
const Array<Vector3>& vertexNormalArray,
const Array<Face>& faceArray,
Array<Vector3>& tangent,
Array<Vector3>& binormal) {
debugAssertM(faceArray.size() != 0, "Unable to calculate valid tangent space without faces.");
// The three vertices and texCoords of each face
Vector3 position[3];
Vector2 texCoord[3];
Vector3 t, b;
tangent.resize(vertexArray.size());
binormal.resize(vertexArray.size());
// Zero the output arrays.
System::memset(tangent.getCArray(), 0, sizeof(Vector3) * tangent.size());
System::memset(binormal.getCArray(), 0, sizeof(Vector3) * binormal.size());
// Iterate over faces, computing the tangent vectors for each
// vertex. Accumulate those into the tangent and binormal arrays
// and then orthonormalize at the end.
for (int f = 0; f < faceArray.size(); ++f) {
const Face& face = faceArray[f];
for (int v = 0; v < 3; ++v) {
int i = face.vertexIndex[v];
position[v] = vertexArray[i];
texCoord[v] = texCoordArray[i];
}
const Vector3 faceNormal((position[1] - position[0]).cross(position[2] - position[0]).direction());
computeTangentVectors(faceNormal, position, texCoord, t, b);
for (int v = 0; v < 3; ++v) {
int i = face.vertexIndex[v];
tangent[i] += t;
binormal[i] += b;
}
}
// Normalize the basis vectors
for (int v = 0; v < vertexArray.size(); ++v) {
// Remove the component parallel to the normal
const Vector3& N = vertexNormalArray[v];
debugAssertM(N.isUnit() || N.isZero(), "Input normals must have unit length");
tangent[v] -= tangent[v].dot(N) * N;
binormal[v] -= binormal[v].dot(N) * N;
// Normalize
tangent[v] = tangent[v].directionOrZero();
binormal[v] = binormal[v].directionOrZero();
// Note that the tangent and binormal might not be perpendicular anymore
}
}
} // G3D namespace
-729
View File
@@ -1,729 +0,0 @@
/**
@file MeshAlgAdjacency.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2003-09-14
@edited 2005-02-24
Copyright 2000-2003, Morgan McGuire.
All rights reserved.
*/
#include "G3D/Table.h"
#include "G3D/MeshAlg.h"
#include "G3D/Set.h"
namespace G3D {
/**
A half [i.e. directed] edge.
*/
class MeshDirectedEdgeKey {
public:
/** vertexIndex[0] <= vertexIndex[1] */
int vertexIndex[2];
MeshDirectedEdgeKey() {}
MeshDirectedEdgeKey(
const int i0,
const int i1) {
if (i0 <= i1) {
vertexIndex[0] = i0;
vertexIndex[1] = i1;
} else {
vertexIndex[0] = i1;
vertexIndex[1] = i0;
}
}
bool operator==(const MeshDirectedEdgeKey& e2) const {
for (int i = 0; i < 2; ++i) {
if (vertexIndex[i] != e2.vertexIndex[i]) {
return false;
}
}
return true;
}
};
}
template<> struct HashTrait<G3D::MeshDirectedEdgeKey> {
static size_t hashCode(const G3D::MeshDirectedEdgeKey& key) {
return key.vertexIndex[0] + (key.vertexIndex[1] << 16);
}
};
namespace G3D {
/**
A hashtable mapping edges to lists of indices for
faces. This is used instead of Table because of the
special logic in insert.
Used only for MeshAlg::computeAdjacency.
In the face lists, index <I>f</I> >= 0 indicates that
<I>f</I> contains the edge as a forward edge. Index <I>f</I> < 0
indicates that ~<I>f</I> contains the edge as a backward edge.
*/
class MeshEdgeTable {
public:
typedef Table<MeshDirectedEdgeKey, Array<int> > ET;
private:
ET table;
public:
/**
Clears the table.
*/
void clear() {
table.clear();
}
/**
Inserts the faceIndex into the edge's face list.
The index may be a negative number indicating a backface.
*/
void insert(const MeshDirectedEdgeKey& edge, int faceIndex) {
// debugAssertM((table.size() > 20) && (table.debugGetLoad() < 0.5 || table.debugGetNumBuckets() < 20),
// "MeshEdgeTable is using a poor hash function.");
if (! table.containsKey(edge)) {
// First time
Array<int> x(1);
x[0] = faceIndex;
table.set(edge, x);
} else {
table[edge].append(faceIndex);
}
}
/**
Returns the face list for a given edge
*/
const Array<int>& get(const MeshDirectedEdgeKey& edge) {
return table[edge];
}
ET::Iterator begin() {
return table.begin();
}
const ET::Iterator end() const {
return table.end();
}
};
/**
edgeTable[edgeKey] is a list of faces containing
Used and cleared by MeshModel::computeAdjacency()
*/
static MeshEdgeTable edgeTable;
/**
Assigns the edge index into the next unassigned edge
index. The edge index may be negative, indicating
a reverse edge.
*/
static void assignEdgeIndex(MeshAlg::Face& face, int e) {
for (int i = 0; i < 3; ++i) {
if (face.edgeIndex[i] == MeshAlg::Face::NONE) {
face.edgeIndex[i] = e;
return;
}
}
debugAssertM(false, "Face has already been assigned 3 edges");
}
void MeshAlg::computeAdjacency(
const Array<Vector3>& vertexGeometry,
const Array<int>& indexArray,
Array<Face>& faceArray,
Array<Edge>& edgeArray,
Array< Array<int> >& adjacentFaceArray) {
Array<Vertex> vertexArray;
computeAdjacency(vertexGeometry, indexArray, faceArray, edgeArray, vertexArray);
// Convert the vertexArray into adjacentFaceArray
adjacentFaceArray.clear();
adjacentFaceArray.resize(vertexArray.size());
for (int v = 0; v < adjacentFaceArray.size(); ++v) {
adjacentFaceArray[v] = vertexArray[v].faceIndex;
}
}
void MeshAlg::computeAdjacency(
const Array<Vector3>& vertexGeometry,
const Array<int>& indexArray,
Array<Face>& faceArray,
Array<Edge>& edgeArray,
Array<Vertex>& vertexArray) {
edgeArray.clear();
vertexArray.clear();
faceArray.clear();
edgeTable.clear();
// Face normals
Array<Vector3> faceNormal;
// This array has the same size as the vertex array
vertexArray.resize(vertexGeometry.size());
// Iterate through the triangle list
for (int q = 0; q < indexArray.size(); q += 3) {
Vector3 vertex[3];
int f = faceArray.size();
MeshAlg::Face& face = faceArray.next();
// Construct the face
for (int j = 0; j < 3; ++j) {
int v = indexArray[q + j];
face.vertexIndex[j] = v;
face.edgeIndex[j] = Face::NONE;
// Store back pointers in the vertices
vertexArray[v].faceIndex.append(f);
// We'll need these vertices to find the face normal
vertex[j] = vertexGeometry[v];
}
// Compute the face normal
Vector3 N = (vertex[1] - vertex[0]).cross(vertex[2] - vertex[0]);
faceNormal.append(N.directionOrZero());
static const int nextIndex[] = {1, 2, 0};
// Add each edge to the edge table.
for (int j = 0; j < 3; ++j) {
const int i0 = indexArray[q + j];
const int i1 = indexArray[q + nextIndex[j]];
const MeshDirectedEdgeKey edge(i0, i1);
if (i0 == edge.vertexIndex[0]) {
// The edge was directed in the same manner as in the face
edgeTable.insert(edge, f);
} else {
// The edge was directed in the opposite manner as in the face
edgeTable.insert(edge, ~f);
}
}
}
// For each edge in the edge table, create an edge in the edge array.
// Collapse every 2 edges from adjacent faces.
MeshEdgeTable::ET::Iterator cur = edgeTable.begin();
MeshEdgeTable::ET::Iterator end = edgeTable.end();
Array<Edge> tempEdgeArray;
while (cur != end) {
MeshDirectedEdgeKey& edgeKey = cur->key;
Array<int>& faceIndexArray = cur->value;
// Process this edge
while (faceIndexArray.size() > 0) {
// Remove the last index
int f0 = faceIndexArray.pop();
// Find the normal to that face
const Vector3& n0 = faceNormal[(f0 >= 0) ? f0 : ~f0];
bool found = false;
// We try to find the matching face with the closest
// normal. This ensures that we don't introduce a lot
// of artificial ridges into flat parts of a mesh.
double ndotn = -2;
int f1 = -1, i1 = -1;
// Try to Find the face with the matching edge
for (int i = faceIndexArray.size() - 1; i >= 0; --i) {
int f = faceIndexArray[i];
if ((f >= 0) != (f0 >= 0)) {
// This face contains the oppositely oriented edge
// and has not been assigned too many edges
const Vector3& n1 = faceNormal[(f >= 0) ? f : ~f];
double d = n1.dot(n0);
if (found) {
// We previously found a good face; see if this
// one is better.
if (d > ndotn) {
// This face is better.
ndotn = d;
f1 = f;
i1 = i;
}
} else {
// This is the first face we've found
found = true;
ndotn = d;
f1 = f;
i1 = i;
}
}
}
// Create the new edge
int e = tempEdgeArray.size();
Edge& edge = tempEdgeArray.next();
edge.vertexIndex[0] = edgeKey.vertexIndex[0];
edge.vertexIndex[1] = edgeKey.vertexIndex[1];
if (f0 >= 0) {
edge.faceIndex[0] = f0;
edge.faceIndex[1] = Face::NONE;
assignEdgeIndex(faceArray[f0], e);
} else {
// The face indices above are two's complemented.
// this code restores them to regular indices.
debugAssert((~f0) >= 0);
edge.faceIndex[1] = ~f0;
edge.faceIndex[0] = Face::NONE;
// The edge index *does* need to be inverted, however.
assignEdgeIndex(faceArray[~f0], ~e);
}
if (found) {
// We found a matching face; remove both
// faces from the active list.
faceIndexArray.fastRemove(i1);
if (f1 >= 0) {
edge.faceIndex[0] = f1;
assignEdgeIndex(faceArray[f1], e);
} else {
edge.faceIndex[1] = ~f1;
assignEdgeIndex(faceArray[~f1], ~e);
}
}
}
++cur;
}
edgeTable.clear();
// Move boundary edges to the end of the list and then
// clean up the face references into them
{
// Map old edge indices to new edge indices
Array<int> newIndex(tempEdgeArray.size());
// Index of the start and end of the edge array
int i = 0;
int j = tempEdgeArray.size() - 1;
edgeArray.resize(tempEdgeArray.size());
for (int e = 0; e < tempEdgeArray.size(); ++e) {
if (tempEdgeArray[e].boundary()) {
newIndex[e] = j;
--j;
} else {
newIndex[e] = i;
++i;
}
edgeArray[newIndex[e]] = tempEdgeArray[e];
}
debugAssertM(i == j + 1, "Counting from front and back of array did not match");
// Fix the faces
for (int f = 0; f < faceArray.size(); ++f) {
Face& face = faceArray[f];
for (int q = 0; q < 3; ++q) {
int e = face.edgeIndex[q];
if (e < 0) {
// Backwards edge; twiddle before and after conversion
face.edgeIndex[q] = ~newIndex[~e];
} else {
// Regular edge; remap the index
face.edgeIndex[q] = newIndex[e];
}
}
}
}
// Now order the edge indices inside the faces correctly.
for (int f = 0; f < faceArray.size(); ++f) {
Face& face = faceArray[f];
int e0 = face.edgeIndex[0];
int e1 = face.edgeIndex[1];
int e2 = face.edgeIndex[2];
// e0 will always remain first. The only
// question is whether e1 and e2 should be swapped.
// See if e1 begins at the vertex where e1 ends.
const int e0End = (e0 < 0) ?
edgeArray[~e0].vertexIndex[0] :
edgeArray[e0].vertexIndex[1];
const int e1Begin = (e1 < 0) ?
edgeArray[~e1].vertexIndex[1] :
edgeArray[e1].vertexIndex[0];
if (e0End != e1Begin) {
// We must swap e1 and e2
face.edgeIndex[1] = e2;
face.edgeIndex[2] = e1;
}
}
// Fill out the edge adjacency information in the vertex array
for (int e = 0; e < edgeArray.size(); ++e) {
const Edge& edge = edgeArray[e];
vertexArray[edge.vertexIndex[0]].edgeIndex.append(e);
vertexArray[edge.vertexIndex[1]].edgeIndex.append(~e);
}
}
void MeshAlg::weldBoundaryEdges(
Array<Face>& faceArray,
Array<Edge>& edgeArray,
Array<Vertex>& vertexArray) {
// Copy over the original edge array
Array<Edge> oldEdgeArray = edgeArray;
// newEdgeIndex[e] is the new index of the old edge with index e
// Note that newEdgeIndex[e] might be negative, indicating that
// the edge switched direction between the arrays.
Array<int> newEdgeIndex(edgeArray.size());
edgeArray.resize(0);
// boundaryEdgeIndices[v_low] is an array of the indices of
// all boundary edges whose lower vertex is v_low.
Table<int, Array<int> > boundaryEdgeIndices;
// Copy over non-boundary edges to the new array
for (int e = 0; e < oldEdgeArray.size(); ++e) {
if (oldEdgeArray[e].boundary()) {
// Add to the boundary table
const int v_low = iMin(oldEdgeArray[e].vertexIndex[0], oldEdgeArray[e].vertexIndex[1]);
if (! boundaryEdgeIndices.containsKey(v_low)) {
boundaryEdgeIndices.set(v_low, Array<int>());
}
boundaryEdgeIndices[v_low].append(e);
// We'll fill out newEdgeIndex[e] later, when we find pairs
} else {
// Copy the edge to the new array
newEdgeIndex[e] = edgeArray.size();
edgeArray.append(oldEdgeArray[e]);
}
}
// Remove all edges from the table that have pairs.
Table<int, Array<int> >::Iterator cur = boundaryEdgeIndices.begin();
Table<int, Array<int> >::Iterator end = boundaryEdgeIndices.end();
while (cur != end) {
Array<int>& boundaryEdge = cur->value;
for (int i = 0; i < boundaryEdge.size(); ++i) {
int ei = boundaryEdge[i];
const Edge& edgei = oldEdgeArray[ei];
for (int j = i + 1; j < boundaryEdge.size(); ++j) {
int ej = boundaryEdge[j];
const Edge& edgej = oldEdgeArray[ej];
// See if edge ei is the reverse (match) of edge ej.
// True if the edges match
bool match = false;
// True if edgej's vertex indices are reversed from
// edgei's (usually true).
bool reversej = false;
int u = edgei.vertexIndex[0];
int v = edgei.vertexIndex[1];
if (edgei.faceIndex[0] != Face::NONE) {
// verts|faces
// edgei = [u v A /]
if (edgej.faceIndex[0] != Face::NONE) {
if ((edgej.vertexIndex[0] == v) && (edgej.vertexIndex[1] == u)) {
// This is the most common of the four cases
// edgej = [v u B /]
match = true;
reversej = true;
}
} else {
if ((edgej.vertexIndex[0] == u) && (edgej.vertexIndex[1] == v)) {
// edgej = [u v / B]
match = true;
}
}
} else {
// edgei = [u v / A]
if (edgej.faceIndex[0] != Face::NONE) {
if ((edgej.vertexIndex[0] == u) && (edgej.vertexIndex[1] == v)) {
// edgej = [u v B /]
match = true;
}
} else {
if ((edgej.vertexIndex[0] == v) && (edgej.vertexIndex[1] == u)) {
// edgej = [v u / B]
match = true;
reversej = true;
}
}
}
if (match) {
// ei and ej can be paired as a single edge
int e = edgeArray.size();
Edge& edge = edgeArray.next();
// Follow the direction of edgei.
edge = edgei;
newEdgeIndex[ei] = e;
// Insert the face index for edgej.
int fj = edgej.faceIndex[0];
if (fj == Face::NONE) {
fj = edgej.faceIndex[1];
}
if (edge.faceIndex[0] == Face::NONE) {
edge.faceIndex[0] = fj;
} else {
edge.faceIndex[1] = fj;
}
if (reversej) {
// The new edge is backwards of the old edge for ej
newEdgeIndex[ej] = ~e;
} else {
newEdgeIndex[ej] = e;
}
// Remove both ei and ej from being candidates for future pairing.
// Remove ej first since it comes later in the list (removing
// ei would decrease the index of ej to j - 1).
boundaryEdge.fastRemove(j);
boundaryEdge.fastRemove(i);
// Re-process element i, which is now a new edge index
--i;
// Jump out of the j for-loop
break;
}
}
}
++cur;
}
// Anything remaining in the table is a real boundary edge; just copy it to
// the end of the array.
cur = boundaryEdgeIndices.begin();
end = boundaryEdgeIndices.end();
while (cur != end) {
Array<int>& boundaryEdge = cur->value;
for (int b = 0; b < boundaryEdge.size(); ++b) {
const int e = boundaryEdge[b];
newEdgeIndex[e] = edgeArray.size();
edgeArray.append(oldEdgeArray[e]);
}
++cur;
}
// Finally, fix up edge indices in the face and vertex arrays
for (int f = 0; f < faceArray.size(); ++f) {
Face& face = faceArray[f];
for (int i = 0; i < 3; ++i) {
int e = face.edgeIndex[i];
if (e < 0) {
face.edgeIndex[i] = ~newEdgeIndex[~e];
} else {
face.edgeIndex[i] = newEdgeIndex[e];
}
}
}
for (int v = 0; v < vertexArray.size(); ++v) {
Vertex& vertex = vertexArray[v];
for (int i = 0; i < vertex.edgeIndex.size(); ++i) {
int e = vertex.edgeIndex[i];
if (e < 0) {
vertex.edgeIndex[i] = ~newEdgeIndex[~e];
} else {
vertex.edgeIndex[i] = newEdgeIndex[e];
}
}
}
}
void MeshAlg::weldAdjacency(
const Array<Vector3>& originalGeometry,
Array<Face>& faceArray,
Array<Edge>& edgeArray,
Array<Vertex>& vertexArray,
double radius) {
// Num vertices
const int n = originalGeometry.size();
// canonical[v] = first occurance of any vertex near oldVertexArray[v]
Array<int> canonical(n);
Array<int> toNew, toOld;
// Throw away the new vertex array
Array<Vector3> dummy;
computeWeld(originalGeometry, dummy, toNew, toOld, radius);
for (int v = 0; v < canonical.size(); ++v) {
// Round-trip through the toNew/toOld process. This will give
// us the original vertex.
canonical[v] = toOld[toNew[v]];
}
// Destroy vertexArray (we reconstruct it below)
vertexArray.clear();
vertexArray.resize(n);
bool hasBoundaryEdges = false;
// Fix edge vertex indices
for (int e = 0; e < edgeArray.size(); ++e) {
Edge& edge = edgeArray[e];
const int v0 = canonical[edge.vertexIndex[0]];
const int v1 = canonical[edge.vertexIndex[1]];
edge.vertexIndex[0] = v0;
edge.vertexIndex[1] = v1;
vertexArray[v0].edgeIndex.append(e);
vertexArray[v1].edgeIndex.append(~e);
hasBoundaryEdges = hasBoundaryEdges || edge.boundary();
}
// Fix face vertex indices
for (int f = 0; f < faceArray.size(); ++f) {
Face& face = faceArray[f];
for (int i = 0; i < 3; ++i) {
const int v = canonical[face.vertexIndex[i]];
face.vertexIndex[i] = v;
// Add the back pointer
vertexArray[v].faceIndex.append(f);
}
}
if (hasBoundaryEdges) {
// As a result of the welding, some of the boundary edges at
// the end of the array may now have mates and no longer be
// boundaries. Try to pair these up.
weldBoundaryEdges(faceArray, edgeArray, vertexArray);
}
}
void MeshAlg::debugCheckConsistency(
const Array<Face>& faceArray,
const Array<Edge>& edgeArray,
const Array<Vertex>& vertexArray) {
#ifdef _DEBUG
for (int v = 0; v < vertexArray.size(); ++v) {
const MeshAlg::Vertex& vertex = vertexArray[v];
for (int i = 0; i < vertex.edgeIndex.size(); ++i) {
const int e = vertex.edgeIndex[i];
debugAssert(edgeArray[(e >= 0) ? e : ~e].containsVertex(v));
}
for (int i = 0; i < vertex.faceIndex.size(); ++i) {
const int f = vertex.faceIndex[i];
debugAssert(faceArray[f].containsVertex(v));
}
}
for (int e = 0; e < edgeArray.size(); ++e) {
const MeshAlg::Edge& edge = edgeArray[e];
for (int i = 0; i < 2; ++i) {
debugAssert((edge.faceIndex[i] == MeshAlg::Face::NONE) ||
faceArray[edge.faceIndex[i]].containsEdge(e));
debugAssert(vertexArray[edge.vertexIndex[i]].inEdge(e));
}
}
// Every face's edge must be on that face
for (int f = 0; f < faceArray.size(); ++f) {
const MeshAlg::Face& face = faceArray[f];
for (int i = 0; i < 3; ++i) {
int e = face.edgeIndex[i];
int ei = (e >= 0) ? e : ~e;
debugAssert(edgeArray[ei].inFace(f));
// Make sure the edge is oriented appropriately
if (e >= 0) {
debugAssert(edgeArray[ei].faceIndex[0] == (int)f);
} else {
debugAssert(edgeArray[ei].faceIndex[1] == (int)f);
}
debugAssert(vertexArray[face.vertexIndex[i]].inFace(f));
}
}
#else
(void)faceArray;
(void)edgeArray;
(void)vertexArray;
#endif // _DEBUG
}
} // G3D namespace
-213
View File
@@ -1,213 +0,0 @@
/**
@file MeshAlgWeld.cpp
The MeshAlg::computeWeld method.
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2003-10-22
@edited 2005-02-24
Copyright 2000-2003, Morgan McGuire.
All rights reserved.
*/
#include "G3D/MeshAlg.h"
#include "G3D/Table.h"
#include "G3D/Set.h"
namespace G3D {
namespace _internal {
class Welder {
private:
// Intentionally illegal
Welder& operator=(const Welder& w);
public:
/** Indices of newVertexArray elements in <B>or near</B> a grid cell. */
typedef Array<int> List;
enum {GRID_RES = 32};
List grid[GRID_RES][GRID_RES][GRID_RES];
const Array<Vector3>& oldVertexArray;
Array<Vector3>& newVertexArray;
Array<int>& toNew;
Array<int>& toOld;
/** Must be less than one grid cell, not checked */
const double radius;
/** (oldVertexArray[i] - offset) * scale is on the range [0, 1] */
Vector3 offset;
Vector3 scale;
Welder(
const Array<Vector3>& _oldVertexArray,
Array<Vector3>& _newVertexArray,
Array<int>& _toNew,
Array<int>& _toOld,
double _radius);
/**
Computes the grid index from an ordinate.
*/
void toGridCoords(Vector3 v, int& x, int& y, int& z) const;
/** Gets the index of a vertex, adding it to
newVertexArray if necessary. */
int getIndex(const Vector3& vertex);
void weld();
};
} // namespace _internal
} // namespace G3D
template<> struct HashTrait<G3D::_internal::Welder::List*> {
static size_t hashCode(const G3D::_internal::Welder::List* key) { return reinterpret_cast<size_t>(key); }
};
namespace G3D {
namespace _internal {
Welder::Welder(
const Array<Vector3>& _oldVertexArray,
Array<Vector3>& _newVertexArray,
Array<int>& _toNew,
Array<int>& _toOld,
double _radius) :
oldVertexArray(_oldVertexArray),
newVertexArray(_newVertexArray),
toNew(_toNew),
toOld(_toOld),
radius(_radius) {
// Compute a scale factor that moves the range
// of all ordinates to [0, 1]
Vector3 minBound = Vector3::inf();
Vector3 maxBound = -minBound;
for (int i = 0; i < oldVertexArray.size(); ++i) {
minBound = minBound.min(oldVertexArray[i]);
maxBound = maxBound.max(oldVertexArray[i]);
}
offset = minBound;
scale = maxBound - minBound;
for (int i = 0; i < 3; ++i) {
// The model might have zero extent along some axis
if (fuzzyEq(scale[i], 0.0)) {
scale[i] = 1.0;
} else {
scale[i] = 1.0 / scale[i];
}
}
}
void Welder::toGridCoords(Vector3 v, int& x, int& y, int& z) const {
v = (v - offset) * scale;
x = iClamp(iFloor(v.x * GRID_RES), 0, GRID_RES - 1);
y = iClamp(iFloor(v.y * GRID_RES), 0, GRID_RES - 1);
z = iClamp(iFloor(v.z * GRID_RES), 0, GRID_RES - 1);
}
int Welder::getIndex(const Vector3& vertex) {
int closestIndex = -1;
double distanceSquared = inf();
int ix, iy, iz;
toGridCoords(vertex, ix, iy, iz);
// Check against all vertices within radius of this grid cube
const List& list = grid[ix][iy][iz];
for (int i = 0; i < list.size(); ++i) {
double d = (newVertexArray[list[i]] - vertex).squaredMagnitude();
if (d < distanceSquared) {
distanceSquared = d;
closestIndex = list[i];
}
}
if (distanceSquared <= radius * radius) {
return closestIndex;
} else {
// This is a new vertex
int newIndex = newVertexArray.size();
newVertexArray.append(vertex);
// Create a new vertex and store its index in the
// neighboring grid cells (usually, only 1 neighbor)
Set<List*> neighbors;
for (float dx = -1; dx <= +1; ++dx) {
for (float dy = -1; dy <= +1; ++dy) {
for (float dz = -1; dz <= +1; ++dz) {
int ix, iy, iz;
toGridCoords(vertex + Vector3(dx, dy, dz) * radius, ix, iy, iz);
neighbors.insert(&(grid[ix][iy][iz]));
}
}
}
Set<List*>::Iterator neighbor(neighbors.begin());
Set<List*>::Iterator none(neighbors.end());
while (neighbor != none) {
(*neighbor)->append(newIndex);
++neighbor;
}
return newIndex;
}
}
void Welder::weld() {
newVertexArray.resize(0);
// Prime the vertex positions
for (int i = 0; i < oldVertexArray.size(); ++i) {
getIndex(oldVertexArray[i]);
}
// Now create the official remapping by snapping to
// nearby vertices.
toNew.resize(oldVertexArray.size());
toOld.resize(newVertexArray.size());
for (int oi = 0; oi < oldVertexArray.size(); ++oi) {
toNew[oi] = getIndex(oldVertexArray[oi]);
toOld[toNew[oi]] = oi;
}
}
} // internal namespace
void MeshAlg::computeWeld(
const Array<Vector3>& oldVertexArray,
Array<Vector3>& newVertexArray,
Array<int>& toNew,
Array<int>& toOld,
double radius) {
_internal::Welder welder(oldVertexArray, newVertexArray, toNew, toOld, radius);
welder.weld();
}
} // G3D namespace
-377
View File
@@ -1,377 +0,0 @@
/**
@file MeshAlgWeld2.cpp
@author Morgan McGuire, Kyle Whitson, Corey Taylor
@created 2008-07-30
@edited 2008-11-10
*/
#include "G3D/platform.h"
#include "G3D/Vector2.h"
#include "G3D/Vector3.h"
#include "G3D/Sphere.h"
#include "G3D/PointHashGrid.h"
#include "G3D/MeshAlg.h"
namespace G3D { namespace _internal{
/** Used by WeldHelper2::smoothNormals. */
class VN {
public:
Vector3 vertex;
Vector3 normal;
VN() {}
VN(const Vector3& v, const Vector3& n) : vertex(v), normal(n) {}
};
/** Used by WeldHelper::getIndex to maintain a list of vertices by location. */
class VNTi {
public:
Vector3 vertex;
Vector3 normal;
Vector2 texCoord;
int index;
VNTi() : index(0) {}
VNTi(const Vector3& v, const Vector3& n, const Vector2& t, int i) :
vertex(v), normal(n), texCoord(t), index(i) {}
};
}} // G3D
template <> struct HashTrait <G3D::_internal::VN> {
static size_t hashCode(const G3D::_internal::VN& k) { return static_cast<size_t>(k.vertex.hashCode()); }
};
template <> struct HashTrait <G3D::_internal::VNTi> {
static size_t hashCode(const G3D::_internal::VNTi& k) { return static_cast<size_t>(k.vertex.hashCode()); }
};
template<> struct EqualsTrait <G3D::_internal::VN> {
static bool equals(const G3D::_internal::VN& a, const G3D::_internal::VN& b) { return a.vertex == b.vertex; }
};
template<> struct EqualsTrait <G3D::_internal::VNTi> {
static bool equals(const G3D::_internal::VNTi& a, const G3D::_internal::VNTi& b) { return a.vertex == b.vertex; }
};
template<> struct PositionTrait<G3D::_internal::VN> {
static void getPosition(const G3D::_internal::VN& v, G3D::Vector3& p) { p = v.vertex; }
};
template<> struct PositionTrait<G3D::_internal::VNTi> {
static void getPosition(const G3D::_internal::VNTi& v, G3D::Vector3& p) { p = v.vertex; }
};
namespace G3D { namespace _internal {
class WeldHelper {
private:
/** Used by getIndex and updateTriLists */
PointHashGrid<VNTi> weldGrid;
Array<Vector3>* outputVertexArray;
Array<Vector3>* outputNormalArray;
Array<Vector2>* outputTexCoordArray;
float vertexWeldRadius;
/** Squared radius allowed for welding similar normals. */
float normalWeldRadius2;
float texCoordWeldRadius2;
float normalSmoothingAngle;
/**
Returns the index of the vertex in
outputVertexArray/outputNormalArray/outputTexCoordArray
that is within the global tolerances of v,n,t. If there
is no such vertex, adds it to the arrays and returns that index.
Called from updateTriLists().
*/
int getIndex(const Vector3& v, const Vector3& n, const Vector2& t) {
PointHashGrid<VNTi>::SphereIterator it =
weldGrid.beginSphereIntersection(Sphere(v, vertexWeldRadius));
if (n.isZero()) {
// Don't bother trying to match the surface normal, since this vertex has no surface normal.
while (it.hasMore()) {
if ((t - it->texCoord).squaredLength() <= texCoordWeldRadius2) {
// This is the vertex
return it->index;
}
++it;
}
} else {
while (it.hasMore()) {
if (((n - it->normal).squaredLength() <= normalWeldRadius2) &&
((t - it->texCoord).squaredLength() <= texCoordWeldRadius2)) {
// This is the vertex
return it->index;
}
++it;
}
}
// Note that a sliver triangle processed before its neighbors may reach here
// with a zero length normal.
// The vertex does not exist. Create it.
const int i = outputVertexArray->size();
outputVertexArray->append(v);
outputNormalArray->append(n);
outputTexCoordArray->append(t);
// Store in the grid so that it will be remembered.
weldGrid.insert(VNTi(v, n, t, i));
return i;
}
/**
Updates each indexArray to refer to vertices in the
outputVertexArray.
Called from process()
*/
void updateTriLists(
Array<Array<int>*>& indexArrayArray,
const Array<Vector3>& vertexArray,
const Array<Vector3>& normalArray,
const Array<Vector2>& texCoordArray) {
// Compute a hash grid so that we can find neighbors quickly.
// It begins empty and is extended as the tri lists are iterated
// through.
weldGrid.clear();
// Process all triLists
int numTriLists = indexArrayArray.size();
int u = 0;
for (int t = 0; t < numTriLists; ++t) {
Array<int>& triList = *(indexArrayArray[t]);
// For all vertices in this list
for (int v = 0; v < triList.size(); ++v) {
// This vertex mapped to u in the flatVertexArray
triList[v] = getIndex(vertexArray[u], normalArray[u], texCoordArray[u]);
/*
# ifdef G3D_DEBUG
{
int i = triList[v];
Vector3 N = normalArray[i];
debugAssertM(N.length() > 0.9f, "Produced non-unit normal");
}
# endif
*/
++u;
}
}
}
/** Expands the indexed triangle lists into a triangle list.
Called from process() */
void unroll(
const Array<Array<int>*>& indexArrayArray,
const Array<Vector3>& vertexArray,
const Array<Vector2>& texCoordArray,
Array<Vector3>& unrolledVertexArray,
Array<Vector2>& unrolledTexCoordArray) {
int numTriLists = indexArrayArray.size();
for (int t = 0; t < numTriLists; ++t) {
const Array<int>& triList = *(indexArrayArray[t]);
for (int v = 0; v < triList.size(); ++v) {
int i = triList[v];
unrolledVertexArray.append(vertexArray[i]);
unrolledTexCoordArray.append(texCoordArray[i]);
}
}
}
/** For every three vertices, compute the face normal and store it three times.
Sliver triangles have a zero surface normal, which we will later take to
match *any* surface normal. */
void computeFaceNormals(
const Array<Vector3>& vertexArray,
Array<Vector3>& faceNormalArray) {
debugAssertM(vertexArray.size() % 3 == 0, "Input is not a triangle soup");
debugAssertM(faceNormalArray.size() == 0, "Output must start empty.");
for (int v = 0; v < vertexArray.size(); v += 3) {
const Vector3& e0 = vertexArray[v + 1] - vertexArray[v];
const Vector3& e1 = vertexArray[v + 2] - vertexArray[v];
// Note that the length may be zero in the case of sliver polygons, e.g.,
// those correcting a T-junction.
const Vector3& n = e0.cross(e1).directionOrZero();
// Append the normal once per vertex.
faceNormalArray.append(n, n, n);
}
}
/**
Computes @a smoothNormalArray, whose elements are those of normalArray averaged
with neighbors within the angular cutoff.
*/
void smoothNormals(
const Array<Vector3>& vertexArray,
const Array<Vector3>& normalArray,
Array<Vector3>& smoothNormalArray) {
const float cosThresholdAngle = (float)cos(normalSmoothingAngle);
debugAssert(vertexArray.size() == normalArray.size());
smoothNormalArray.resize(normalArray.size());
// Compute a hash grid so that we can find neighbors quickly.
PointHashGrid<VN> grid(vertexWeldRadius);
for (int v = 0; v < normalArray.size(); ++v) {
grid.insert(VN(vertexArray[v], normalArray[v]));
}
for (int v = 0; v < normalArray.size(); ++v) {
// Compute the sum of all nearby normals within the cutoff angle.
// Search within the vertexWeldRadius, since those are the vertices
// that will collapse to the same point.
PointHashGrid<VN>::SphereIterator it =
grid.beginSphereIntersection(Sphere(vertexArray[v], vertexWeldRadius));
Vector3 sum;
const Vector3& original = normalArray[v];
while (it.hasMore()) {
const Vector3& N = it->normal;
const float cosAngle = N.dot(original);
if (cosAngle > cosThresholdAngle) {
// This normal is close enough to consider
sum += N;
}
++it;
}
const Vector3& average = sum.directionOrZero();
const bool indeterminate = average.isZero();
// Never "smooth" a normal so far that it points backwards
const bool backFacing = original.dot(average) < 0;
if (indeterminate || backFacing) {
// Revert to the face normal
smoothNormalArray[v] = original;
} else {
// Average available normals
smoothNormalArray[v] = average;
}
}
}
public:
/**
Algorithm:
1. Unroll the indexed triangle list into a triangle list, where
there are duplicated vertices.
2. Compute face normals for all triangles, and expand those into
the triangle vertices.
3. At each vertex, average all normals that are within normalSmoothingAngle.
4. Generate output indexArrayArray. While doing so, merge all vertices where
the distance between position, texCoord, and normal is within the thresholds.
*/
void process(
Array<Vector3>& vertexArray,
Array<Vector2>& texCoordArray,
Array<Vector3>& normalArray,
Array<Array<int>*>& indexArrayArray,
float normAngle,
float texRadius,
float normRadius) {
normalSmoothingAngle = normAngle;
normalWeldRadius2 = square(normRadius);
texCoordWeldRadius2 = square(texRadius);
const bool hasTexCoords = (texCoordArray.size() > 0);
if (hasTexCoords) {
debugAssertM(vertexArray.size() == texCoordArray.size(),
"Input arrays are not parallel.");
}
Array<Vector3> unrolledVertexArray;
Array<Vector3> unrolledFaceNormalArray;
Array<Vector3> unrolledSmoothNormalArray;
Array<Vector2> unrolledTexCoordArray;
if (! hasTexCoords) {
// Generate all zero texture coordinates
texCoordArray.resize(vertexArray.size());
}
// Generate a flat (unrolled) triangle list with texture coordinates.
unroll(indexArrayArray, vertexArray, texCoordArray,
unrolledVertexArray, unrolledTexCoordArray);
// Put the output back into the input slots. Clear immediately to reduce peak
// memory.
outputVertexArray = &vertexArray;
outputNormalArray = &normalArray;
outputTexCoordArray = &texCoordArray;
outputVertexArray->fastClear();
outputNormalArray->fastClear();
outputTexCoordArray->fastClear();
// For every three vertices, generate their face normal and store it at
// each vertex. The output array has the same length as the input.
computeFaceNormals(unrolledVertexArray, unrolledFaceNormalArray);
// Compute smooth normals at vertices.
smoothNormals(unrolledVertexArray, unrolledFaceNormalArray, unrolledSmoothNormalArray);
unrolledFaceNormalArray.clear();
// Regenerate the triangle lists
updateTriLists(indexArrayArray, unrolledVertexArray, unrolledSmoothNormalArray, unrolledTexCoordArray);
if (! hasTexCoords) {
// Throw away the generated texCoords
texCoordArray.resize(0);
}
}
WeldHelper(float vertRadius) :
weldGrid(vertRadius),
vertexWeldRadius(vertRadius) {}
};
} // Internal
void MeshAlg::weld(
Array<Vector3>& vertexArray,
Array<Vector2>& texCoordArray,
Array<Vector3>& normalArray,
Array<Array<int>*>& indexArrayArray,
float normalSmoothingAngle,
float vertexWeldRadius,
float textureWeldRadius,
float normalWeldRadius) {
_internal::WeldHelper(vertexWeldRadius).process(
vertexArray, texCoordArray, normalArray, indexArrayArray,
normalSmoothingAngle, textureWeldRadius, normalWeldRadius);
}
} // G3D
-113
View File
@@ -1,113 +0,0 @@
/**
@file MeshBuilder.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2002-02-27
@edited 2005-02-24
*/
#include "G3D/MeshBuilder.h"
#include "G3D/MeshAlg.h"
namespace G3D {
void MeshBuilder::setName(const std::string& n) {
name = n;
}
void MeshBuilder::commit(std::string& n, Array<int>& indexArray, Array<Vector3>& outvertexArray) {
n = name;
// Make the data fit in a unit cube
centerTriList();
Array<int> toNew, toOld;
if (close == MeshBuilder::AUTO_WELD) {
Array<int> index;
MeshAlg::createIndexArray(triList.size(), index);
double minEdgeLen, maxEdgeLen, meanEdgeLen, medianEdgeLen;
double minFaceArea, maxFaceArea, meanFaceArea, medianFaceArea;
MeshAlg::computeAreaStatistics(triList, index,
minEdgeLen, meanEdgeLen, medianEdgeLen, maxEdgeLen,
minFaceArea, meanFaceArea, medianFaceArea, maxFaceArea);
close = minEdgeLen * 0.1;
}
MeshAlg::computeWeld(triList, outvertexArray, toNew, toOld, close);
// Construct triangles
for (int t = 0; t < triList.size(); t += 3) {
int index[3];
for (int i = 0; i < 3; ++i) {
index[i] = toNew[t + i];
}
// Throw out zero size triangles
if ((index[0] != index[1]) &&
(index[1] != index[2]) &&
(index[2] != index[0])) {
indexArray.append(index[0], index[1], index[2]);
}
}
}
void MeshBuilder::centerTriList() {
// Compute the range of the vertices
Vector3 vmin, vmax;
computeBounds(vmin, vmax);
Vector3 diagonal = vmax - vmin;
double scale = max(max(diagonal.x, diagonal.y), diagonal.z) / 2;
debugAssert(scale > 0);
Vector3 translation = vmin + diagonal / 2;
// Center and scale all vertices in the input list
int v;
//Matrix3 rot90 = Matrix3::fromAxisAngle(Vector3::UNIT_Y, toRadians(180)) * Matrix3::fromAxisAngle(Vector3::UNIT_X, toRadians(90));
for (v = 0; v < triList.size(); ++v) {
triList[v] = (triList[v] - translation) / scale;
//triList[v] = rot90 * triList[v];
}
}
void MeshBuilder::computeBounds(Vector3& min, Vector3& max) {
min = Vector3::inf();
max = -min;
int v;
for (v = 0; v < triList.size(); ++v) {
min = min.min(triList[v]);
max = max.max(triList[v]);
}
}
void MeshBuilder::addTriangle(const Vector3& a, const Vector3& b, const Vector3& c) {
triList.append(a, b, c);
if (_twoSided) {
triList.append(c, b, a);
}
}
void MeshBuilder::addQuad(const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d) {
addTriangle(a, b, c);
addTriangle(a, c, d);
}
void MeshBuilder::addTriangle(const Triangle& t) {
addTriangle(t.vertex(0), t.vertex(1), t.vertex(2));
}
} // namespace
-164
View File
@@ -1,164 +0,0 @@
/**
@file NetMessage.cpp
@maintainer Morgan McGuire, morgan@cs.brown.edu
@created 2005-02-06
@edited 2005-02-06
*/
#include "G3D/platform.h"
#include "G3D/NetAddress.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/Array.h"
#include "G3D/stringutils.h"
#include "G3D/System.h"
#include "G3D/NetworkDevice.h"
#if defined(G3D_LINUX) || defined(G3D_OSX)
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/tcp.h>
#define _alloca alloca
# ifndef SOCKADDR_IN
# define SOCKADDR_IN struct sockaddr_in
# endif
# ifndef SOCKET
# define SOCKET int
# endif
// SOCKADDR_IN is supposed to be defined in NetAddress.h
#ifndef SOCKADDR_IN
# error Network headers included in wrong order
#endif
#endif
namespace G3D {
NetAddress::NetAddress() {
System::memset(&addr, 0, sizeof(addr));
}
void NetAddress::init(uint32 host, uint16 port) {
if ((host != 0) || (port != 0)) {
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (host == 0) {
host = INADDR_ANY;
}
addr.sin_addr.s_addr = htonl(host);
} else {
System::memset(&addr, 0, sizeof(addr));
}
}
NetAddress::NetAddress(
const std::string& hostname,
uint16 port) {
init(hostname, port);
}
void NetAddress::init(
const std::string& hostname,
uint16 port) {
uint32 addr;
if (hostname == "") {
addr = INADDR_NONE;
} else {
addr = inet_addr(hostname.c_str());
}
// The address wasn't in numeric form, resolve it
if (addr == INADDR_NONE) {
// Get the IP address of the server and store it in host
struct hostent* host = gethostbyname(hostname.c_str());
if (host == NULL) {
init(0, 0);
return;
}
System::memcpy(&addr, host->h_addr_list[0], host->h_length);
}
if (addr != INADDR_NONE) {
addr = ntohl(addr);
}
init(addr, port);
}
NetAddress::NetAddress(uint32 hostip, uint16 port) {
init(hostip, port);
}
NetAddress NetAddress::broadcastAddress(uint16 port) {
return NetAddress(NetworkDevice::instance()->broadcastAddressArray()[0], port);
}
NetAddress::NetAddress(const std::string& hostnameAndPort) {
Array<std::string> part = stringSplit(hostnameAndPort, ':');
debugAssert(part.length() == 2);
init(part[0], atoi(part[1].c_str()));
}
NetAddress::NetAddress(const SOCKADDR_IN& a) {
addr = a;
}
NetAddress::NetAddress(const struct in_addr& addr, uint16 port) {
#ifdef G3D_WIN32
init(ntohl(addr.S_un.S_addr), port);
#else
init(htonl(addr.s_addr), port);
#endif
}
void NetAddress::serialize(class BinaryOutput& b) const {
b.writeUInt32(ip());
b.writeUInt16(port());
}
void NetAddress::deserialize(class BinaryInput& b) {
uint32 i;
uint16 p;
i = b.readUInt32();
p = b.readUInt16();
init(i, p);
}
bool NetAddress::ok() const {
return addr.sin_family != 0;
}
std::string NetAddress::ipString() const {
return format("%s", inet_ntoa(*(in_addr*)&(addr.sin_addr)));
}
std::string NetAddress::toString() const {
return ipString() + format(":%d", ntohs(addr.sin_port));
}
}
File diff suppressed because it is too large Load Diff
-77
View File
@@ -1,77 +0,0 @@
/**
@file PhysicsFrame.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2002-07-09
@edited 2006-01-25
*/
#include "G3D/platform.h"
#include "G3D/PhysicsFrame.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
namespace G3D {
PhysicsFrame::PhysicsFrame() {
translation = Vector3::zero();
rotation = Quat();
}
PhysicsFrame::PhysicsFrame(
const CoordinateFrame& coordinateFrame) {
translation = coordinateFrame.translation;
rotation = Quat(coordinateFrame.rotation);
}
PhysicsFrame PhysicsFrame::operator*(const PhysicsFrame& other) const {
PhysicsFrame result;
result.rotation = rotation * other.rotation;
result.translation = translation + rotation.toRotationMatrix() * other.translation;
return result;
}
CoordinateFrame PhysicsFrame::toCoordinateFrame() const {
CoordinateFrame f;
f.translation = translation;
f.rotation = rotation.toRotationMatrix();
return f;
}
PhysicsFrame PhysicsFrame::lerp(
const PhysicsFrame& other,
float alpha) const {
PhysicsFrame result;
result.translation = translation.lerp(other.translation, alpha);
result.rotation = rotation.slerp(other.rotation, alpha);
return result;
}
void PhysicsFrame::deserialize(class BinaryInput& b) {
translation.deserialize(b);
rotation.deserialize(b);
}
void PhysicsFrame::serialize(class BinaryOutput& b) const {
translation.serialize(b);
rotation.serialize(b);
}
}; // namespace
-149
View File
@@ -1,149 +0,0 @@
/**
@file Plane.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2003-02-06
@edited 2006-01-29
*/
#include "G3D/platform.h"
#include "G3D/Plane.h"
#include "G3D/BinaryOutput.h"
#include "G3D/BinaryInput.h"
#include "G3D/stringutils.h"
namespace G3D {
Plane::Plane(class BinaryInput& b) {
deserialize(b);
}
void Plane::serialize(class BinaryOutput& b) const {
_normal.serialize(b);
b.writeFloat64(_distance);
}
void Plane::deserialize(class BinaryInput& b) {
_normal.deserialize(b);
_distance = (float)b.readFloat64();
}
Plane::Plane(
Vector4 point0,
Vector4 point1,
Vector4 point2) {
debugAssertM(
point0.w != 0 ||
point1.w != 0 ||
point2.w != 0,
"At least one point must be finite.");
// Rotate the points around so that the finite points come first.
while ((point0.w == 0) &&
((point1.w == 0) || (point2.w != 0))) {
Vector4 temp = point0;
point0 = point1;
point1 = point2;
point2 = temp;
}
Vector3 dir1;
Vector3 dir2;
if (point1.w == 0) {
// 1 finite, 2 infinite points; the plane must contain
// the direction of the two direcitons
dir1 = point1.xyz();
dir2 = point2.xyz();
} else if (point2.w != 0) {
// 3 finite points, the plane must contain the directions
// betwseen the points.
dir1 = point1.xyz() - point0.xyz();
dir2 = point2.xyz() - point0.xyz();
} else {
// 2 finite, 1 infinite point; the plane must contain
// the direction between the first two points and the
// direction of the third point.
dir1 = point1.xyz() - point0.xyz();
dir2 = point2.xyz();
}
_normal = dir1.cross(dir2).direction();
_distance = _normal.dot(point0.xyz());
}
Plane::Plane(
const Vector3& point0,
const Vector3& point1,
const Vector3& point2) {
_normal = (point1 - point0).cross(point2 - point0).direction();
_distance = _normal.dot(point0);
}
Plane::Plane(
const Vector3& __normal,
const Vector3& point) {
_normal = __normal.direction();
_distance = _normal.dot(point);
}
Plane Plane::fromEquation(float a, float b, float c, float d) {
Vector3 n(a, b, c);
float magnitude = n.magnitude();
d /= magnitude;
n /= magnitude;
return Plane(n, -d);
}
void Plane::flip() {
_normal = -_normal;
_distance = -_distance;
}
void Plane::getEquation(Vector3& n, float& d) const {
double _d;
getEquation(n, _d);
d = (float)_d;
}
void Plane::getEquation(Vector3& n, double& d) const {
n = _normal;
d = -_distance;
}
void Plane::getEquation(float& a, float& b, float& c, float& d) const {
double _a, _b, _c, _d;
getEquation(_a, _b, _c, _d);
a = (float)_a;
b = (float)_b;
c = (float)_c;
d = (float)_d;
}
void Plane::getEquation(double& a, double& b, double& c, double& d) const {
a = _normal.x;
b = _normal.y;
c = _normal.z;
d = -_distance;
}
std::string Plane::toString() const {
return format("Plane(%g, %g, %g, %g)", _normal.x, _normal.y, _normal.z, _distance);
}
}
-583
View File
@@ -1,583 +0,0 @@
/**
@file Quat.cpp
Quaternion implementation based on Watt & Watt page 363
@author Morgan McGuire, graphics3d.com
@created 2002-01-23
@edited 2006-01-31
*/
#include "G3D/Quat.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
namespace G3D {
Quat Quat::fromAxisAngleRotation(
const Vector3& axis,
float angle) {
Quat q;
q.w = cos(angle / 2.0f);
q.imag() = axis.direction() * sin(angle / 2.0f);
return q;
}
Quat::Quat(
const Matrix3& rot) {
static const int plus1mod3[] = {1, 2, 0};
// Find the index of the largest diagonal component
// These ? operations hopefully compile to conditional
// move instructions instead of branches.
int i = (rot[1][1] > rot[0][0]) ? 1 : 0;
i = (rot[2][2] > rot[i][i]) ? 2 : i;
// Find the indices of the other elements
int j = plus1mod3[i];
int k = plus1mod3[j];
// Index the elements of the vector part of the quaternion as a float*
float* v = (float*)(this);
// If we attempted to pre-normalize and trusted the matrix to be
// perfectly orthonormal, the result would be:
//
// double c = sqrt((rot[i][i] - (rot[j][j] + rot[k][k])) + 1.0)
// v[i] = -c * 0.5
// v[j] = -(rot[i][j] + rot[j][i]) * 0.5 / c
// v[k] = -(rot[i][k] + rot[k][i]) * 0.5 / c
// w = (rot[j][k] - rot[k][j]) * 0.5 / c
//
// Since we're going to pay the sqrt anyway, we perform a post normalization, which also
// fixes any poorly normalized input. Multiply all elements by 2*c in the above, giving:
// nc2 = -c^2
double nc2 = ((rot[j][j] + rot[k][k]) - rot[i][i]) - 1.0;
v[i] = nc2;
w = (rot[j][k] - rot[k][j]);
v[j] = -(rot[i][j] + rot[j][i]);
v[k] = -(rot[i][k] + rot[k][i]);
// We now have the correct result with the wrong magnitude, so normalize it:
float s = sqrt(x*x + y*y + z*z + w*w);
if (s > 0.00001f) {
s = 1.0f / s;
x *= s;
y *= s;
z *= s;
w *= s;
} else {
// The quaternion is nearly zero. Make it 0 0 0 1
x = 0.0f;
y = 0.0f;
z = 0.0f;
w = 1.0f;
}
}
void Quat::toAxisAngleRotation(
Vector3& axis,
double& angle) const {
// Decompose the quaternion into an angle and an axis.
axis = Vector3(x, y, z);
angle = 2 * acos(w);
float len = sqrt(1.0f - w * w);
if (fuzzyGt(abs(len), 0.0f)) {
axis /= len;
}
// Reduce the range of the angle.
if (angle < 0) {
angle = -angle;
axis = -axis;
}
while (angle > twoPi()) {
angle -= twoPi();
}
if (abs(angle) > pi()) {
angle -= twoPi();
}
// Make the angle positive.
if (angle < 0.0f) {
angle = -angle;
axis = -axis;
}
}
Matrix3 Quat::toRotationMatrix() const {
Matrix3 out = Matrix3::zero();
toRotationMatrix(out);
return out;
}
void Quat::toRotationMatrix(
Matrix3& rot) const {
rot = Matrix3(*this);
}
Quat Quat::slerp(
const Quat& _quat1,
float alpha,
float threshold) const {
// From: Game Physics -- David Eberly pg 538-540
// Modified to include lerp for small angles, which
// is a common practice.
// See also:
// http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/index.html
const Quat& quat0 = *this;
Quat quat1 = _quat1;
// angle between quaternion rotations
float phi;
float cosphi = quat0.dot(quat1);
if (cosphi < 0) {
// Change the sign and fix the dot product; we need to
// loop the other way to get the shortest path
quat1 = -quat1;
cosphi = -cosphi;
}
// Using G3D::aCos will clamp the angle to 0 and pi
phi = static_cast<float>(G3D::aCos(cosphi));
if (phi >= threshold) {
// For large angles, slerp
float scale0, scale1;
scale0 = sin((1.0f - alpha) * phi);
scale1 = sin(alpha * phi);
return ( (quat0 * scale0) + (quat1 * scale1) ) / sin(phi);
} else {
// For small angles, linear interpolate
return quat0.nlerp(quat1, alpha);
}
}
Quat Quat::nlerp(
const Quat& quat1,
float alpha) const {
Quat result = (*this) * (1.0f - alpha) + quat1 * alpha;
return result / result.magnitude();
}
Quat Quat::operator*(const Quat& other) const {
// Following Watt & Watt, page 360
const Vector3& v1 = imag();
const Vector3& v2 = other.imag();
float s1 = w;
float s2 = other.w;
return Quat(s1*v2 + s2*v1 + v1.cross(v2), s1*s2 - v1.dot(v2));
}
// From "Uniform Random Rotations", Ken Shoemake, Graphics Gems III.
Quat Quat::unitRandom() {
float x0 = uniformRandom();
float r1 = sqrtf(1 - x0),
r2 = sqrtf(x0);
float t1 = (float)G3D::twoPi() * uniformRandom();
float t2 = (float)G3D::twoPi() * uniformRandom();
float c1 = cosf(t1),
s1 = sinf(t1);
float c2 = cosf(t2),
s2 = sinf(t2);
return Quat(s1 * r1, c1 * r1, s2 * r2, c2 * r2);
}
void Quat::deserialize(class BinaryInput& b) {
x = b.readFloat32();
y = b.readFloat32();
z = b.readFloat32();
w = b.readFloat32();
}
void Quat::serialize(class BinaryOutput& b) const {
b.writeFloat32(x);
b.writeFloat32(y);
b.writeFloat32(z);
b.writeFloat32(w);
}
// 2-char swizzles
Vector2 Quat::xx() const { return Vector2 (x, x); }
Vector2 Quat::yx() const { return Vector2 (y, x); }
Vector2 Quat::zx() const { return Vector2 (z, x); }
Vector2 Quat::wx() const { return Vector2 (w, x); }
Vector2 Quat::xy() const { return Vector2 (x, y); }
Vector2 Quat::yy() const { return Vector2 (y, y); }
Vector2 Quat::zy() const { return Vector2 (z, y); }
Vector2 Quat::wy() const { return Vector2 (w, y); }
Vector2 Quat::xz() const { return Vector2 (x, z); }
Vector2 Quat::yz() const { return Vector2 (y, z); }
Vector2 Quat::zz() const { return Vector2 (z, z); }
Vector2 Quat::wz() const { return Vector2 (w, z); }
Vector2 Quat::xw() const { return Vector2 (x, w); }
Vector2 Quat::yw() const { return Vector2 (y, w); }
Vector2 Quat::zw() const { return Vector2 (z, w); }
Vector2 Quat::ww() const { return Vector2 (w, w); }
// 3-char swizzles
Vector3 Quat::xxx() const { return Vector3 (x, x, x); }
Vector3 Quat::yxx() const { return Vector3 (y, x, x); }
Vector3 Quat::zxx() const { return Vector3 (z, x, x); }
Vector3 Quat::wxx() const { return Vector3 (w, x, x); }
Vector3 Quat::xyx() const { return Vector3 (x, y, x); }
Vector3 Quat::yyx() const { return Vector3 (y, y, x); }
Vector3 Quat::zyx() const { return Vector3 (z, y, x); }
Vector3 Quat::wyx() const { return Vector3 (w, y, x); }
Vector3 Quat::xzx() const { return Vector3 (x, z, x); }
Vector3 Quat::yzx() const { return Vector3 (y, z, x); }
Vector3 Quat::zzx() const { return Vector3 (z, z, x); }
Vector3 Quat::wzx() const { return Vector3 (w, z, x); }
Vector3 Quat::xwx() const { return Vector3 (x, w, x); }
Vector3 Quat::ywx() const { return Vector3 (y, w, x); }
Vector3 Quat::zwx() const { return Vector3 (z, w, x); }
Vector3 Quat::wwx() const { return Vector3 (w, w, x); }
Vector3 Quat::xxy() const { return Vector3 (x, x, y); }
Vector3 Quat::yxy() const { return Vector3 (y, x, y); }
Vector3 Quat::zxy() const { return Vector3 (z, x, y); }
Vector3 Quat::wxy() const { return Vector3 (w, x, y); }
Vector3 Quat::xyy() const { return Vector3 (x, y, y); }
Vector3 Quat::yyy() const { return Vector3 (y, y, y); }
Vector3 Quat::zyy() const { return Vector3 (z, y, y); }
Vector3 Quat::wyy() const { return Vector3 (w, y, y); }
Vector3 Quat::xzy() const { return Vector3 (x, z, y); }
Vector3 Quat::yzy() const { return Vector3 (y, z, y); }
Vector3 Quat::zzy() const { return Vector3 (z, z, y); }
Vector3 Quat::wzy() const { return Vector3 (w, z, y); }
Vector3 Quat::xwy() const { return Vector3 (x, w, y); }
Vector3 Quat::ywy() const { return Vector3 (y, w, y); }
Vector3 Quat::zwy() const { return Vector3 (z, w, y); }
Vector3 Quat::wwy() const { return Vector3 (w, w, y); }
Vector3 Quat::xxz() const { return Vector3 (x, x, z); }
Vector3 Quat::yxz() const { return Vector3 (y, x, z); }
Vector3 Quat::zxz() const { return Vector3 (z, x, z); }
Vector3 Quat::wxz() const { return Vector3 (w, x, z); }
Vector3 Quat::xyz() const { return Vector3 (x, y, z); }
Vector3 Quat::yyz() const { return Vector3 (y, y, z); }
Vector3 Quat::zyz() const { return Vector3 (z, y, z); }
Vector3 Quat::wyz() const { return Vector3 (w, y, z); }
Vector3 Quat::xzz() const { return Vector3 (x, z, z); }
Vector3 Quat::yzz() const { return Vector3 (y, z, z); }
Vector3 Quat::zzz() const { return Vector3 (z, z, z); }
Vector3 Quat::wzz() const { return Vector3 (w, z, z); }
Vector3 Quat::xwz() const { return Vector3 (x, w, z); }
Vector3 Quat::ywz() const { return Vector3 (y, w, z); }
Vector3 Quat::zwz() const { return Vector3 (z, w, z); }
Vector3 Quat::wwz() const { return Vector3 (w, w, z); }
Vector3 Quat::xxw() const { return Vector3 (x, x, w); }
Vector3 Quat::yxw() const { return Vector3 (y, x, w); }
Vector3 Quat::zxw() const { return Vector3 (z, x, w); }
Vector3 Quat::wxw() const { return Vector3 (w, x, w); }
Vector3 Quat::xyw() const { return Vector3 (x, y, w); }
Vector3 Quat::yyw() const { return Vector3 (y, y, w); }
Vector3 Quat::zyw() const { return Vector3 (z, y, w); }
Vector3 Quat::wyw() const { return Vector3 (w, y, w); }
Vector3 Quat::xzw() const { return Vector3 (x, z, w); }
Vector3 Quat::yzw() const { return Vector3 (y, z, w); }
Vector3 Quat::zzw() const { return Vector3 (z, z, w); }
Vector3 Quat::wzw() const { return Vector3 (w, z, w); }
Vector3 Quat::xww() const { return Vector3 (x, w, w); }
Vector3 Quat::yww() const { return Vector3 (y, w, w); }
Vector3 Quat::zww() const { return Vector3 (z, w, w); }
Vector3 Quat::www() const { return Vector3 (w, w, w); }
// 4-char swizzles
Vector4 Quat::xxxx() const { return Vector4 (x, x, x, x); }
Vector4 Quat::yxxx() const { return Vector4 (y, x, x, x); }
Vector4 Quat::zxxx() const { return Vector4 (z, x, x, x); }
Vector4 Quat::wxxx() const { return Vector4 (w, x, x, x); }
Vector4 Quat::xyxx() const { return Vector4 (x, y, x, x); }
Vector4 Quat::yyxx() const { return Vector4 (y, y, x, x); }
Vector4 Quat::zyxx() const { return Vector4 (z, y, x, x); }
Vector4 Quat::wyxx() const { return Vector4 (w, y, x, x); }
Vector4 Quat::xzxx() const { return Vector4 (x, z, x, x); }
Vector4 Quat::yzxx() const { return Vector4 (y, z, x, x); }
Vector4 Quat::zzxx() const { return Vector4 (z, z, x, x); }
Vector4 Quat::wzxx() const { return Vector4 (w, z, x, x); }
Vector4 Quat::xwxx() const { return Vector4 (x, w, x, x); }
Vector4 Quat::ywxx() const { return Vector4 (y, w, x, x); }
Vector4 Quat::zwxx() const { return Vector4 (z, w, x, x); }
Vector4 Quat::wwxx() const { return Vector4 (w, w, x, x); }
Vector4 Quat::xxyx() const { return Vector4 (x, x, y, x); }
Vector4 Quat::yxyx() const { return Vector4 (y, x, y, x); }
Vector4 Quat::zxyx() const { return Vector4 (z, x, y, x); }
Vector4 Quat::wxyx() const { return Vector4 (w, x, y, x); }
Vector4 Quat::xyyx() const { return Vector4 (x, y, y, x); }
Vector4 Quat::yyyx() const { return Vector4 (y, y, y, x); }
Vector4 Quat::zyyx() const { return Vector4 (z, y, y, x); }
Vector4 Quat::wyyx() const { return Vector4 (w, y, y, x); }
Vector4 Quat::xzyx() const { return Vector4 (x, z, y, x); }
Vector4 Quat::yzyx() const { return Vector4 (y, z, y, x); }
Vector4 Quat::zzyx() const { return Vector4 (z, z, y, x); }
Vector4 Quat::wzyx() const { return Vector4 (w, z, y, x); }
Vector4 Quat::xwyx() const { return Vector4 (x, w, y, x); }
Vector4 Quat::ywyx() const { return Vector4 (y, w, y, x); }
Vector4 Quat::zwyx() const { return Vector4 (z, w, y, x); }
Vector4 Quat::wwyx() const { return Vector4 (w, w, y, x); }
Vector4 Quat::xxzx() const { return Vector4 (x, x, z, x); }
Vector4 Quat::yxzx() const { return Vector4 (y, x, z, x); }
Vector4 Quat::zxzx() const { return Vector4 (z, x, z, x); }
Vector4 Quat::wxzx() const { return Vector4 (w, x, z, x); }
Vector4 Quat::xyzx() const { return Vector4 (x, y, z, x); }
Vector4 Quat::yyzx() const { return Vector4 (y, y, z, x); }
Vector4 Quat::zyzx() const { return Vector4 (z, y, z, x); }
Vector4 Quat::wyzx() const { return Vector4 (w, y, z, x); }
Vector4 Quat::xzzx() const { return Vector4 (x, z, z, x); }
Vector4 Quat::yzzx() const { return Vector4 (y, z, z, x); }
Vector4 Quat::zzzx() const { return Vector4 (z, z, z, x); }
Vector4 Quat::wzzx() const { return Vector4 (w, z, z, x); }
Vector4 Quat::xwzx() const { return Vector4 (x, w, z, x); }
Vector4 Quat::ywzx() const { return Vector4 (y, w, z, x); }
Vector4 Quat::zwzx() const { return Vector4 (z, w, z, x); }
Vector4 Quat::wwzx() const { return Vector4 (w, w, z, x); }
Vector4 Quat::xxwx() const { return Vector4 (x, x, w, x); }
Vector4 Quat::yxwx() const { return Vector4 (y, x, w, x); }
Vector4 Quat::zxwx() const { return Vector4 (z, x, w, x); }
Vector4 Quat::wxwx() const { return Vector4 (w, x, w, x); }
Vector4 Quat::xywx() const { return Vector4 (x, y, w, x); }
Vector4 Quat::yywx() const { return Vector4 (y, y, w, x); }
Vector4 Quat::zywx() const { return Vector4 (z, y, w, x); }
Vector4 Quat::wywx() const { return Vector4 (w, y, w, x); }
Vector4 Quat::xzwx() const { return Vector4 (x, z, w, x); }
Vector4 Quat::yzwx() const { return Vector4 (y, z, w, x); }
Vector4 Quat::zzwx() const { return Vector4 (z, z, w, x); }
Vector4 Quat::wzwx() const { return Vector4 (w, z, w, x); }
Vector4 Quat::xwwx() const { return Vector4 (x, w, w, x); }
Vector4 Quat::ywwx() const { return Vector4 (y, w, w, x); }
Vector4 Quat::zwwx() const { return Vector4 (z, w, w, x); }
Vector4 Quat::wwwx() const { return Vector4 (w, w, w, x); }
Vector4 Quat::xxxy() const { return Vector4 (x, x, x, y); }
Vector4 Quat::yxxy() const { return Vector4 (y, x, x, y); }
Vector4 Quat::zxxy() const { return Vector4 (z, x, x, y); }
Vector4 Quat::wxxy() const { return Vector4 (w, x, x, y); }
Vector4 Quat::xyxy() const { return Vector4 (x, y, x, y); }
Vector4 Quat::yyxy() const { return Vector4 (y, y, x, y); }
Vector4 Quat::zyxy() const { return Vector4 (z, y, x, y); }
Vector4 Quat::wyxy() const { return Vector4 (w, y, x, y); }
Vector4 Quat::xzxy() const { return Vector4 (x, z, x, y); }
Vector4 Quat::yzxy() const { return Vector4 (y, z, x, y); }
Vector4 Quat::zzxy() const { return Vector4 (z, z, x, y); }
Vector4 Quat::wzxy() const { return Vector4 (w, z, x, y); }
Vector4 Quat::xwxy() const { return Vector4 (x, w, x, y); }
Vector4 Quat::ywxy() const { return Vector4 (y, w, x, y); }
Vector4 Quat::zwxy() const { return Vector4 (z, w, x, y); }
Vector4 Quat::wwxy() const { return Vector4 (w, w, x, y); }
Vector4 Quat::xxyy() const { return Vector4 (x, x, y, y); }
Vector4 Quat::yxyy() const { return Vector4 (y, x, y, y); }
Vector4 Quat::zxyy() const { return Vector4 (z, x, y, y); }
Vector4 Quat::wxyy() const { return Vector4 (w, x, y, y); }
Vector4 Quat::xyyy() const { return Vector4 (x, y, y, y); }
Vector4 Quat::yyyy() const { return Vector4 (y, y, y, y); }
Vector4 Quat::zyyy() const { return Vector4 (z, y, y, y); }
Vector4 Quat::wyyy() const { return Vector4 (w, y, y, y); }
Vector4 Quat::xzyy() const { return Vector4 (x, z, y, y); }
Vector4 Quat::yzyy() const { return Vector4 (y, z, y, y); }
Vector4 Quat::zzyy() const { return Vector4 (z, z, y, y); }
Vector4 Quat::wzyy() const { return Vector4 (w, z, y, y); }
Vector4 Quat::xwyy() const { return Vector4 (x, w, y, y); }
Vector4 Quat::ywyy() const { return Vector4 (y, w, y, y); }
Vector4 Quat::zwyy() const { return Vector4 (z, w, y, y); }
Vector4 Quat::wwyy() const { return Vector4 (w, w, y, y); }
Vector4 Quat::xxzy() const { return Vector4 (x, x, z, y); }
Vector4 Quat::yxzy() const { return Vector4 (y, x, z, y); }
Vector4 Quat::zxzy() const { return Vector4 (z, x, z, y); }
Vector4 Quat::wxzy() const { return Vector4 (w, x, z, y); }
Vector4 Quat::xyzy() const { return Vector4 (x, y, z, y); }
Vector4 Quat::yyzy() const { return Vector4 (y, y, z, y); }
Vector4 Quat::zyzy() const { return Vector4 (z, y, z, y); }
Vector4 Quat::wyzy() const { return Vector4 (w, y, z, y); }
Vector4 Quat::xzzy() const { return Vector4 (x, z, z, y); }
Vector4 Quat::yzzy() const { return Vector4 (y, z, z, y); }
Vector4 Quat::zzzy() const { return Vector4 (z, z, z, y); }
Vector4 Quat::wzzy() const { return Vector4 (w, z, z, y); }
Vector4 Quat::xwzy() const { return Vector4 (x, w, z, y); }
Vector4 Quat::ywzy() const { return Vector4 (y, w, z, y); }
Vector4 Quat::zwzy() const { return Vector4 (z, w, z, y); }
Vector4 Quat::wwzy() const { return Vector4 (w, w, z, y); }
Vector4 Quat::xxwy() const { return Vector4 (x, x, w, y); }
Vector4 Quat::yxwy() const { return Vector4 (y, x, w, y); }
Vector4 Quat::zxwy() const { return Vector4 (z, x, w, y); }
Vector4 Quat::wxwy() const { return Vector4 (w, x, w, y); }
Vector4 Quat::xywy() const { return Vector4 (x, y, w, y); }
Vector4 Quat::yywy() const { return Vector4 (y, y, w, y); }
Vector4 Quat::zywy() const { return Vector4 (z, y, w, y); }
Vector4 Quat::wywy() const { return Vector4 (w, y, w, y); }
Vector4 Quat::xzwy() const { return Vector4 (x, z, w, y); }
Vector4 Quat::yzwy() const { return Vector4 (y, z, w, y); }
Vector4 Quat::zzwy() const { return Vector4 (z, z, w, y); }
Vector4 Quat::wzwy() const { return Vector4 (w, z, w, y); }
Vector4 Quat::xwwy() const { return Vector4 (x, w, w, y); }
Vector4 Quat::ywwy() const { return Vector4 (y, w, w, y); }
Vector4 Quat::zwwy() const { return Vector4 (z, w, w, y); }
Vector4 Quat::wwwy() const { return Vector4 (w, w, w, y); }
Vector4 Quat::xxxz() const { return Vector4 (x, x, x, z); }
Vector4 Quat::yxxz() const { return Vector4 (y, x, x, z); }
Vector4 Quat::zxxz() const { return Vector4 (z, x, x, z); }
Vector4 Quat::wxxz() const { return Vector4 (w, x, x, z); }
Vector4 Quat::xyxz() const { return Vector4 (x, y, x, z); }
Vector4 Quat::yyxz() const { return Vector4 (y, y, x, z); }
Vector4 Quat::zyxz() const { return Vector4 (z, y, x, z); }
Vector4 Quat::wyxz() const { return Vector4 (w, y, x, z); }
Vector4 Quat::xzxz() const { return Vector4 (x, z, x, z); }
Vector4 Quat::yzxz() const { return Vector4 (y, z, x, z); }
Vector4 Quat::zzxz() const { return Vector4 (z, z, x, z); }
Vector4 Quat::wzxz() const { return Vector4 (w, z, x, z); }
Vector4 Quat::xwxz() const { return Vector4 (x, w, x, z); }
Vector4 Quat::ywxz() const { return Vector4 (y, w, x, z); }
Vector4 Quat::zwxz() const { return Vector4 (z, w, x, z); }
Vector4 Quat::wwxz() const { return Vector4 (w, w, x, z); }
Vector4 Quat::xxyz() const { return Vector4 (x, x, y, z); }
Vector4 Quat::yxyz() const { return Vector4 (y, x, y, z); }
Vector4 Quat::zxyz() const { return Vector4 (z, x, y, z); }
Vector4 Quat::wxyz() const { return Vector4 (w, x, y, z); }
Vector4 Quat::xyyz() const { return Vector4 (x, y, y, z); }
Vector4 Quat::yyyz() const { return Vector4 (y, y, y, z); }
Vector4 Quat::zyyz() const { return Vector4 (z, y, y, z); }
Vector4 Quat::wyyz() const { return Vector4 (w, y, y, z); }
Vector4 Quat::xzyz() const { return Vector4 (x, z, y, z); }
Vector4 Quat::yzyz() const { return Vector4 (y, z, y, z); }
Vector4 Quat::zzyz() const { return Vector4 (z, z, y, z); }
Vector4 Quat::wzyz() const { return Vector4 (w, z, y, z); }
Vector4 Quat::xwyz() const { return Vector4 (x, w, y, z); }
Vector4 Quat::ywyz() const { return Vector4 (y, w, y, z); }
Vector4 Quat::zwyz() const { return Vector4 (z, w, y, z); }
Vector4 Quat::wwyz() const { return Vector4 (w, w, y, z); }
Vector4 Quat::xxzz() const { return Vector4 (x, x, z, z); }
Vector4 Quat::yxzz() const { return Vector4 (y, x, z, z); }
Vector4 Quat::zxzz() const { return Vector4 (z, x, z, z); }
Vector4 Quat::wxzz() const { return Vector4 (w, x, z, z); }
Vector4 Quat::xyzz() const { return Vector4 (x, y, z, z); }
Vector4 Quat::yyzz() const { return Vector4 (y, y, z, z); }
Vector4 Quat::zyzz() const { return Vector4 (z, y, z, z); }
Vector4 Quat::wyzz() const { return Vector4 (w, y, z, z); }
Vector4 Quat::xzzz() const { return Vector4 (x, z, z, z); }
Vector4 Quat::yzzz() const { return Vector4 (y, z, z, z); }
Vector4 Quat::zzzz() const { return Vector4 (z, z, z, z); }
Vector4 Quat::wzzz() const { return Vector4 (w, z, z, z); }
Vector4 Quat::xwzz() const { return Vector4 (x, w, z, z); }
Vector4 Quat::ywzz() const { return Vector4 (y, w, z, z); }
Vector4 Quat::zwzz() const { return Vector4 (z, w, z, z); }
Vector4 Quat::wwzz() const { return Vector4 (w, w, z, z); }
Vector4 Quat::xxwz() const { return Vector4 (x, x, w, z); }
Vector4 Quat::yxwz() const { return Vector4 (y, x, w, z); }
Vector4 Quat::zxwz() const { return Vector4 (z, x, w, z); }
Vector4 Quat::wxwz() const { return Vector4 (w, x, w, z); }
Vector4 Quat::xywz() const { return Vector4 (x, y, w, z); }
Vector4 Quat::yywz() const { return Vector4 (y, y, w, z); }
Vector4 Quat::zywz() const { return Vector4 (z, y, w, z); }
Vector4 Quat::wywz() const { return Vector4 (w, y, w, z); }
Vector4 Quat::xzwz() const { return Vector4 (x, z, w, z); }
Vector4 Quat::yzwz() const { return Vector4 (y, z, w, z); }
Vector4 Quat::zzwz() const { return Vector4 (z, z, w, z); }
Vector4 Quat::wzwz() const { return Vector4 (w, z, w, z); }
Vector4 Quat::xwwz() const { return Vector4 (x, w, w, z); }
Vector4 Quat::ywwz() const { return Vector4 (y, w, w, z); }
Vector4 Quat::zwwz() const { return Vector4 (z, w, w, z); }
Vector4 Quat::wwwz() const { return Vector4 (w, w, w, z); }
Vector4 Quat::xxxw() const { return Vector4 (x, x, x, w); }
Vector4 Quat::yxxw() const { return Vector4 (y, x, x, w); }
Vector4 Quat::zxxw() const { return Vector4 (z, x, x, w); }
Vector4 Quat::wxxw() const { return Vector4 (w, x, x, w); }
Vector4 Quat::xyxw() const { return Vector4 (x, y, x, w); }
Vector4 Quat::yyxw() const { return Vector4 (y, y, x, w); }
Vector4 Quat::zyxw() const { return Vector4 (z, y, x, w); }
Vector4 Quat::wyxw() const { return Vector4 (w, y, x, w); }
Vector4 Quat::xzxw() const { return Vector4 (x, z, x, w); }
Vector4 Quat::yzxw() const { return Vector4 (y, z, x, w); }
Vector4 Quat::zzxw() const { return Vector4 (z, z, x, w); }
Vector4 Quat::wzxw() const { return Vector4 (w, z, x, w); }
Vector4 Quat::xwxw() const { return Vector4 (x, w, x, w); }
Vector4 Quat::ywxw() const { return Vector4 (y, w, x, w); }
Vector4 Quat::zwxw() const { return Vector4 (z, w, x, w); }
Vector4 Quat::wwxw() const { return Vector4 (w, w, x, w); }
Vector4 Quat::xxyw() const { return Vector4 (x, x, y, w); }
Vector4 Quat::yxyw() const { return Vector4 (y, x, y, w); }
Vector4 Quat::zxyw() const { return Vector4 (z, x, y, w); }
Vector4 Quat::wxyw() const { return Vector4 (w, x, y, w); }
Vector4 Quat::xyyw() const { return Vector4 (x, y, y, w); }
Vector4 Quat::yyyw() const { return Vector4 (y, y, y, w); }
Vector4 Quat::zyyw() const { return Vector4 (z, y, y, w); }
Vector4 Quat::wyyw() const { return Vector4 (w, y, y, w); }
Vector4 Quat::xzyw() const { return Vector4 (x, z, y, w); }
Vector4 Quat::yzyw() const { return Vector4 (y, z, y, w); }
Vector4 Quat::zzyw() const { return Vector4 (z, z, y, w); }
Vector4 Quat::wzyw() const { return Vector4 (w, z, y, w); }
Vector4 Quat::xwyw() const { return Vector4 (x, w, y, w); }
Vector4 Quat::ywyw() const { return Vector4 (y, w, y, w); }
Vector4 Quat::zwyw() const { return Vector4 (z, w, y, w); }
Vector4 Quat::wwyw() const { return Vector4 (w, w, y, w); }
Vector4 Quat::xxzw() const { return Vector4 (x, x, z, w); }
Vector4 Quat::yxzw() const { return Vector4 (y, x, z, w); }
Vector4 Quat::zxzw() const { return Vector4 (z, x, z, w); }
Vector4 Quat::wxzw() const { return Vector4 (w, x, z, w); }
Vector4 Quat::xyzw() const { return Vector4 (x, y, z, w); }
Vector4 Quat::yyzw() const { return Vector4 (y, y, z, w); }
Vector4 Quat::zyzw() const { return Vector4 (z, y, z, w); }
Vector4 Quat::wyzw() const { return Vector4 (w, y, z, w); }
Vector4 Quat::xzzw() const { return Vector4 (x, z, z, w); }
Vector4 Quat::yzzw() const { return Vector4 (y, z, z, w); }
Vector4 Quat::zzzw() const { return Vector4 (z, z, z, w); }
Vector4 Quat::wzzw() const { return Vector4 (w, z, z, w); }
Vector4 Quat::xwzw() const { return Vector4 (x, w, z, w); }
Vector4 Quat::ywzw() const { return Vector4 (y, w, z, w); }
Vector4 Quat::zwzw() const { return Vector4 (z, w, z, w); }
Vector4 Quat::wwzw() const { return Vector4 (w, w, z, w); }
Vector4 Quat::xxww() const { return Vector4 (x, x, w, w); }
Vector4 Quat::yxww() const { return Vector4 (y, x, w, w); }
Vector4 Quat::zxww() const { return Vector4 (z, x, w, w); }
Vector4 Quat::wxww() const { return Vector4 (w, x, w, w); }
Vector4 Quat::xyww() const { return Vector4 (x, y, w, w); }
Vector4 Quat::yyww() const { return Vector4 (y, y, w, w); }
Vector4 Quat::zyww() const { return Vector4 (z, y, w, w); }
Vector4 Quat::wyww() const { return Vector4 (w, y, w, w); }
Vector4 Quat::xzww() const { return Vector4 (x, z, w, w); }
Vector4 Quat::yzww() const { return Vector4 (y, z, w, w); }
Vector4 Quat::zzww() const { return Vector4 (z, z, w, w); }
Vector4 Quat::wzww() const { return Vector4 (w, z, w, w); }
Vector4 Quat::xwww() const { return Vector4 (x, w, w, w); }
Vector4 Quat::ywww() const { return Vector4 (y, w, w, w); }
Vector4 Quat::zwww() const { return Vector4 (z, w, w, w); }
Vector4 Quat::wwww() const { return Vector4 (w, w, w, w); }
}
-112
View File
@@ -1,112 +0,0 @@
/**
@file Ray.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2002-07-12
@edited 2004-03-19
*/
#include "G3D/platform.h"
#include "G3D/Ray.h"
#include "G3D/Plane.h"
#include "G3D/Sphere.h"
#include "G3D/CollisionDetection.h"
namespace G3D {
Ray::Ray(class BinaryInput& b) {
deserialize(b);
}
void Ray::serialize(class BinaryOutput& b) const {
origin.serialize(b);
direction.serialize(b);
}
void Ray::deserialize(class BinaryInput& b) {
origin.deserialize(b);
direction.deserialize(b);
}
Ray Ray::refract(
const Vector3& newOrigin,
const Vector3& normal,
float iInside,
float iOutside) const {
Vector3 D = direction.refractionDirection(normal, iInside, iOutside);
return Ray::fromOriginAndDirection(
newOrigin + (direction + normal * (float)sign(direction.dot(normal))) * 0.001f, D);
}
Ray Ray::reflect(
const Vector3& newOrigin,
const Vector3& normal) const {
Vector3 D = direction.reflectionDirection(normal);
return Ray::fromOriginAndDirection(newOrigin + (D + normal) * 0.001f, D);
}
Vector3 Ray::intersection(const Plane& plane) const {
float d;
Vector3 normal = plane.normal();
plane.getEquation(normal, d);
float rate = direction.dot(normal);
if (rate >= 0.0f) {
return Vector3::inf();
} else {
float t = -(d + origin.dot(normal)) / rate;
return origin + direction * t;
}
}
float Ray::intersectionTime(const class Sphere& sphere) const {
Vector3 dummy;
return CollisionDetection::collisionTimeForMovingPointFixedSphere(
origin, direction, sphere, dummy);
}
float Ray::intersectionTime(const class Plane& plane) const {
Vector3 dummy;
return CollisionDetection::collisionTimeForMovingPointFixedPlane(
origin, direction, plane, dummy);
}
float Ray::intersectionTime(const class Box& box) const {
Vector3 dummy;
float time = CollisionDetection::collisionTimeForMovingPointFixedBox(
origin, direction, box, dummy);
if ((time == inf()) && (box.contains(origin))) {
return 0.0f;
} else {
return time;
}
}
float Ray::intersectionTime(const class AABox& box) const {
Vector3 dummy;
bool inside;
float time = CollisionDetection::collisionTimeForMovingPointFixedAABox(
origin, direction, box, dummy, inside);
if ((time == inf()) && inside) {
return 0.0f;
} else {
return time;
}
}
}
-290
View File
@@ -1,290 +0,0 @@
/**
@file RegistryUtil.cpp
@created 2006-04-06
@edited 2006-04-24
Copyright 2000-2006, Morgan McGuire.
All rights reserved.
*/
#include "G3D/platform.h"
// This file is only used on Windows
#ifdef G3D_WIN32
#include "G3D/RegistryUtil.h"
#include "G3D/System.h"
namespace G3D {
// static helpers
static HKEY getRootKeyFromString(const char* str, size_t length);
bool RegistryUtil::keyExists(const std::string& key) {
size_t pos = key.find('\\', 0);
if (pos == std::string::npos) {
return false;
}
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
if (hkey == NULL) {
return false;
}
HKEY openKey;
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
if (result == ERROR_SUCCESS) {
RegCloseKey(openKey);
return true;
} else {
return false;
}
}
bool RegistryUtil::valueExists(const std::string& key, const std::string& value) {
size_t pos = key.find('\\', 0);
if (pos == std::string::npos) {
return false;
}
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
if ( hkey == NULL ) {
return false;
}
HKEY openKey;
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
if (result == ERROR_SUCCESS) {
uint32 dataSize = 0;
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, NULL, reinterpret_cast<LPDWORD>(&dataSize));
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
RegCloseKey(openKey);
}
return (result == ERROR_SUCCESS);
}
bool RegistryUtil::readInt32(const std::string& key, const std::string& value, int32& data) {
size_t pos = key.find('\\', 0);
if (pos == std::string::npos) {
return false;
}
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
if ( hkey == NULL ) {
return false;
}
HKEY openKey;
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
if (result == ERROR_SUCCESS) {
uint32 dataSize = sizeof(int32);
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(&data), reinterpret_cast<LPDWORD>(&dataSize));
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
RegCloseKey(openKey);
}
return (result == ERROR_SUCCESS);
}
bool RegistryUtil::readBytes(const std::string& key, const std::string& value, uint8* data, uint32& dataSize) {
size_t pos = key.find('\\', 0);
if (pos == std::string::npos) {
return false;
}
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
if (hkey == NULL) {
return false;
}
HKEY openKey;
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
if (result == ERROR_SUCCESS) {
if (data == NULL) {
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, NULL, reinterpret_cast<LPDWORD>(&dataSize));
} else {
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(&data), reinterpret_cast<LPDWORD>(&dataSize));
}
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
RegCloseKey(openKey);
}
return (result == ERROR_SUCCESS);
}
bool RegistryUtil::readString(const std::string& key, const std::string& value, std::string& data) {
size_t pos = key.find('\\', 0);
if (pos == std::string::npos) {
return false;
}
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
if (hkey == NULL) {
return false;
}
HKEY openKey;
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_READ, &openKey);
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
if (result == ERROR_SUCCESS) {
uint32 dataSize = 0;
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, NULL, reinterpret_cast<LPDWORD>(&dataSize));
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
// increment datasize to allow for non null-terminated strings in registry
dataSize += 1;
if (result == ERROR_SUCCESS) {
char* tmpStr = static_cast<char*>(System::malloc(dataSize));
System::memset(tmpStr, 0, dataSize);
result = RegQueryValueExA(openKey, value.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(tmpStr), reinterpret_cast<LPDWORD>(&dataSize));
debugAssertM(result == ERROR_SUCCESS, "Could not read registry key value.");
if (result == ERROR_SUCCESS) {
data = tmpStr;
}
RegCloseKey(openKey);
System::free(tmpStr);
}
}
return (result == ERROR_SUCCESS);
}
bool RegistryUtil::writeInt32(const std::string& key, const std::string& value, int32 data) {
size_t pos = key.find('\\', 0);
if (pos == std::string::npos) {
return false;
}
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
if (hkey == NULL) {
return false;
}
HKEY openKey;
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_WRITE, &openKey);
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
if (result == ERROR_SUCCESS) {
result = RegSetValueExA(openKey, value.c_str(), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&data), sizeof(int32));
debugAssertM(result == ERROR_SUCCESS, "Could not write registry key value.");
RegCloseKey(openKey);
}
return (result == ERROR_SUCCESS);
}
bool RegistryUtil::writeBytes(const std::string& key, const std::string& value, const uint8* data, uint32 dataSize) {
debugAssert(data);
size_t pos = key.find('\\', 0);
if (pos == std::string::npos) {
return false;
}
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
if (hkey == NULL) {
return false;
}
HKEY openKey;
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_WRITE, &openKey);
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
if (result == ERROR_SUCCESS) {
if (data) {
result = RegSetValueExA(openKey, value.c_str(), 0, REG_BINARY, reinterpret_cast<const BYTE*>(data), dataSize);
}
debugAssertM(result == ERROR_SUCCESS, "Could not write registry key value.");
RegCloseKey(openKey);
}
return (result == ERROR_SUCCESS);
}
bool RegistryUtil::writeString(const std::string& key, const std::string& value, const std::string& data) {
size_t pos = key.find('\\', 0);
if (pos == std::string::npos) {
return false;
}
HKEY hkey = getRootKeyFromString(key.c_str(), pos);
if (hkey == NULL) {
return false;
}
HKEY openKey;
int32 result = RegOpenKeyExA(hkey, (key.c_str() + pos + 1), 0, KEY_WRITE, &openKey);
debugAssert(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
if (result == ERROR_SUCCESS) {
result = RegSetValueExA(openKey, value.c_str(), 0, REG_SZ, reinterpret_cast<const BYTE*>(data.c_str()), (data.size() + 1));
debugAssertM(result == ERROR_SUCCESS, "Could not write registry key value.");
RegCloseKey(openKey);
}
return (result == ERROR_SUCCESS);
}
// static helpers
static HKEY getRootKeyFromString(const char* str, uint32 length) {
debugAssert(str);
if (str) {
if ( strncmp(str, "HKEY_CLASSES_ROOT", length) == 0 ) {
return HKEY_CLASSES_ROOT;
} else if ( strncmp(str, "HKEY_CURRENT_CONFIG", length) == 0 ) {
return HKEY_CURRENT_CONFIG;
} else if ( strncmp(str, "HKEY_CURRENT_USER", length) == 0 ) {
return HKEY_CURRENT_USER;
} else if ( strncmp(str, "HKEY_LOCAL_MACHINE", length) == 0 ) {
return HKEY_LOCAL_MACHINE;
} else if ( strncmp(str, "HKEY_PERFORMANCE_DATA", length) == 0 ) {
return HKEY_PERFORMANCE_DATA;
} else if ( strncmp(str, "HKEY_PERFORMANCE_NLSTEXT", length) == 0 ) {
return HKEY_PERFORMANCE_NLSTEXT;
} else if ( strncmp(str, "HKEY_PERFORMANCE_TEXT", length) == 0 ) {
return HKEY_PERFORMANCE_TEXT;
} else if ( strncmp(str, "HKEY_CLASSES_ROOT", length) == 0 ) {
return HKEY_CLASSES_ROOT;
} else {
return NULL;
}
} else {
return NULL;
}
}
} // namespace G3D
#endif // G3D_WIN32
-196
View File
@@ -1,196 +0,0 @@
/**
@file Sphere.cpp
Sphere class
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2001-04-17
@edited 2006-02-05
*/
#include "G3D/platform.h"
#include "G3D/Sphere.h"
#include "G3D/stringutils.h"
#include "G3D/BinaryOutput.h"
#include "G3D/BinaryInput.h"
#include "G3D/AABox.h"
#include "G3D/Plane.h"
namespace G3D {
int32 Sphere::dummy;
Sphere::Sphere(class BinaryInput& b) {
deserialize(b);
}
void Sphere::serialize(class BinaryOutput& b) const {
center.serialize(b);
b.writeFloat64(radius);
}
void Sphere::deserialize(class BinaryInput& b) {
center.deserialize(b);
radius = (float)b.readFloat64();
}
std::string Sphere::toString() const {
return format("Sphere(<%g, %g, %g>, %g)",
center.x, center.y, center.z, radius);
}
bool Sphere::contains(const Vector3& point) const {
double distance = (center - point).squaredMagnitude();
return distance <= (radius * radius);
}
bool Sphere::intersects(const Sphere& other) const {
return (other.center - center).length() <= (radius + other.radius);
}
bool Sphere::culledBy(
const Array<Plane>& plane,
int& cullingPlaneIndex,
const uint32 inMask,
uint32& outMask) const {
return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask, outMask);
}
bool Sphere::culledBy(
const Array<Plane>& plane,
int& cullingPlaneIndex,
const uint32 inMask) const {
return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask);
}
bool Sphere::culledBy(
const class Plane* plane,
int numPlanes,
int& cullingPlane,
const uint32 _inMask,
uint32& childMask) const {
if (radius == inf()) {
// No plane can cull the infinite box
return false;
}
uint32 inMask = _inMask;
assert(numPlanes < 31);
childMask = 0;
// See if there is one plane for which all of the
// vertices are in the negative half space.
for (int p = 0; p < numPlanes; p++) {
// Only test planes that are not masked
if ((inMask & 1) != 0) {
bool culledLow = ! plane[p].halfSpaceContainsFinite(center + plane[p].normal() * radius);
bool culledHigh = ! plane[p].halfSpaceContainsFinite(center - plane[p].normal() * radius);
if (culledLow) {
// Plane p culled the sphere
cullingPlane = p;
// The caller should not recurse into the children,
// since the parent is culled. If they do recurse,
// make them only test against this one plane, which
// will immediately cull the volume.
childMask = 1 << p;
return true;
} else if (culledHigh) {
// The bounding volume straddled the plane; we have
// to keep testing against this plane
childMask |= (1 << p);
}
}
// Move on to the next bit.
inMask = inMask >> 1;
}
// None of the planes could cull this box
cullingPlane = -1;
return false;
}
bool Sphere::culledBy(
const class Plane* plane,
int numPlanes,
int& cullingPlane,
const uint32 _inMask) const {
uint32 inMask = _inMask;
assert(numPlanes < 31);
// See if there is one plane for which all of the
// vertices are in the negative half space.
for (int p = 0; p < numPlanes; p++) {
// Only test planes that are not masked
if ((inMask & 1) != 0) {
bool culled = ! plane[p].halfSpaceContains(center + plane[p].normal() * radius);
if (culled) {
// Plane p culled the sphere
cullingPlane = p;
return true;
}
}
// Move on to the next bit.
inMask = inMask >> 1;
}
// None of the planes could cull this box
cullingPlane = -1;
return false;
}
Vector3 Sphere::randomSurfacePoint() const {
return Vector3::random() * radius + center;
}
Vector3 Sphere::randomInteriorPoint() const {
Vector3 result;
do {
result = Vector3(uniformRandom(-1, 1),
uniformRandom(-1, 1),
uniformRandom(-1, 1));
} while (result.squaredMagnitude() >= 1.0f);
return result * radius + center;
}
float Sphere::volume() const {
return (float)pi() * (4.0f / 3.0f) * powf((float)radius, 3.0f);
}
float Sphere::area() const {
return (float)pi() * 4.0f * powf((float)radius, 2.0f);
}
void Sphere::getBounds(AABox& out) const {
Vector3 extent(radius, radius, radius);
out = AABox(center - extent, center + extent);
}
} // namespace
-162
View File
@@ -1,162 +0,0 @@
#include "G3D/platform.h"
#include "G3D/Spline.h"
namespace G3D {
float SplineBase::getFinalInterval() const {
if (! cyclic) {
return 0;
} else if (finalInterval <= 0) {
int N = time.size();
if (N >= 2) {
return (time[1] - time[0] + time[N - 1] - time[N - 2]) * 0.5f;
} else {
return 1.0f;
}
} else {
return finalInterval;
}
}
Matrix4 SplineBase::computeBasis() {
// The standard Catmull-Rom spline basis (e.g., Watt & Watt p108)
// is for [u^3 u^2 u^1 u^0] * B * [p[0] p[1] p[2] p[3]]^T.
// We need a basis formed for:
//
// U * C * [2*p'[1] p[1] p[2] 2*p'[2]]^T
//
// U * C * [p2-p0 p1 p2 p3-p1]^T
//
// To make this transformation, compute the differences of columns in C:
// For [p0 p1 p2 p3]
Matrix4 basis =
Matrix4( -1, 3, -3, 1,
2, -5, 4, -1,
-1, 0, 1, 0,
0, 2, 0, 0) * 0.5f;
// For [-p0 p1 p2 p3]^T
basis.setColumn(0, -basis.column(0));
// For [-p0 p1 p2 p3-p1]^T
basis.setColumn(1, basis.column(1) + basis.column(3));
// For [p2-p0 p1 p2 p3-p1]^T
basis.setColumn(2, basis.column(2) - basis.column(0));
return basis;
}
float SplineBase::duration() const {
if (time.size() == 0) {
return 0;
} else {
return time.last() - time[0] + getFinalInterval();
}
}
void SplineBase::computeIndexInBounds(float s, int& i, float& u) const {
int N = time.size();
float t0 = time[0];
float tn = time[N - 1];
i = iFloor((N - 1) * (s - t0) / (tn - t0));
// Inclusive bounds for binary search
int hi = N - 1;
int lo = 0;
while ((time[i] > s) || (time[i + 1] <= s)) {
if (time[i] > s) {
// too big
hi = i - 1;
} else if (time[i + 1] <= s) {
// too small
lo = i + 1;
}
i = (hi + lo) / 2;
}
// Having exited the above loop, i must be correct, so compute u.
u = (s - time[i]) / (time[i + 1] - time[i]);
}
void SplineBase::computeIndex(float s, int& i, float& u) const {
int N = time.size();
debugAssertM(N > 0, "No control points");
float t0 = time[0];
float tn = time[N - 1];
if (N < 2) {
// No control points to work with
i = 0;
u = 0.0;
} else if (cyclic) {
float fi = getFinalInterval();
// Cyclic spline
if ((s < t0) || (s >= tn + fi)) {
// Cyclic, off the bottom or top
// Compute offset and reduce to the in-bounds case
float d = duration();
// Number of times we wrapped around the cyclic array
int wraps = iFloor((s - t0) / d);
debugAssert(s - d * wraps >= t0);
debugAssert(s - d * wraps < tn + getFinalInterval());
computeIndex(s - d * wraps, i, u);
i += wraps * N;
} else if (s >= tn) {
debugAssert(s < tn + fi);
// Cyclic, off the top but before the end of the last interval
i = N - 1;
u = (s - tn) / fi;
} else {
// Cyclic, in bounds
computeIndexInBounds(s, i, u);
}
} else {
// Non-cyclic
if (s < t0) {
// Non-cyclic, off the bottom. Assume points are spaced
// following the first time interval.
float dt = time[1] - t0;
float x = (s - t0) / dt;
i = iFloor(x);
u = x - i;
} else if (s >= tn) {
// Non-cyclic, off the top. Assume points are spaced following
// the last time interval.
float dt = tn - time[N - 2];
float x = N - 1 + (s - tn) / dt;
i = iFloor(x);
u = x - i;
} else {
// In bounds, non-cyclic. Assume a regular
// distribution (which gives O(1) for uniform spacing)
// and then binary search to handle the general case
// efficiently.
computeIndexInBounds(s, i, u);
} // if in bounds
} // if cyclic
}
}
-96
View File
@@ -1,96 +0,0 @@
/**
@file Stopwatch.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2005-10-05
@edited 2005-10-05
Copyright 2000-2003, Morgan McGuire.
All rights reserved.
*/
#include "G3D/Stopwatch.h"
#include "G3D/System.h"
namespace G3D {
Stopwatch::Stopwatch() : inBetween(false), lastTockTime(-1),
lastDuration(0), lastCycleCount(0), m_fps(0), emwaFPS(0),
m_smoothFPS(0), emwaDuration(0) {
computeOverhead();
}
void Stopwatch::computeOverhead() {
cycleOverhead = 0;
tick();
tock();
cycleOverhead = elapsedCycles();
}
void Stopwatch::tick() {
// This is 'alwaysAssert' instead of 'debugAssert'
// since people rarely profile in debug mode.
alwaysAssertM(! inBetween, "Stopwatch::tick() called twice in a row.");
inBetween = true;
// We read RDTSC twice here, but it is more abstract to implement this
// way and at least we're reading the cycle count last.
timeStart = System::time();
System::beginCycleCount(cycleStart);
}
void Stopwatch::tock() {
System::endCycleCount(cycleStart);
RealTime now = System::time();
lastDuration = now - timeStart;
if (abs(emwaDuration - lastDuration) > max(emwaDuration, lastDuration) * 0.50) {
// Off by more than 50%
emwaDuration = lastDuration;
} else {
emwaDuration = lastDuration * 0.05 + emwaDuration * 0.95;
}
lastCycleCount = cycleStart - cycleOverhead;
if (lastCycleCount < 0) {
lastCycleCount = 0;
}
if (lastTockTime != -1.0) {
m_fps = 1.0 / (now - lastTockTime);
// Time smooth the average
emwaFPS = m_fps * 0.01 + emwaFPS * 0.99;
if (abs(emwaFPS - m_fps) > max(emwaFPS, m_fps) * 0.08) {
// The difference between emwa and m_fps is way off
// update emwa directly.
emwaFPS = m_fps;
}
// Update m_smoothFPS only when the value varies significantly
// We round so as to not mislead the user as to the accuracy of
// the number.
if (m_smoothFPS == 0) {
m_smoothFPS = m_fps;
} else if (emwaFPS <= 10) {
if (::fabs(m_smoothFPS - emwaFPS) > .75) {
m_smoothFPS = floor(emwaFPS * 10.0 + 0.5) / 10.0;
}
} else {
if (::fabs(m_smoothFPS - emwaFPS) > 1.25) {
m_smoothFPS = floor(emwaFPS + 0.5);
}
}
}
lastTockTime = now;
alwaysAssertM(inBetween, "Stopwatch::tock() called without matching tick.");
inBetween = false;
}
}
File diff suppressed because it is too large Load Diff
-988
View File
@@ -1,988 +0,0 @@
/**
@file TextInput.cpp
@author Morgan McGuire, graphics3d.com
@cite Based on a lexer written by Aaron Orenstein.
@created 2001-11-27
@edited 2008-07-14
*/
#include "G3D/fileutils.h"
#include "G3D/TextInput.h"
#include "G3D/BinaryInput.h"
#include "G3D/stringutils.h"
#ifdef _MSC_VER
# pragma warning (push)
// conversion from 'int' to 'char', possible loss of data (TODO: fix underlying problems)
# pragma warning (disable: 4244)
#endif
namespace G3D {
double Token::number() const {
if (_type == NUMBER) {
std::string s = toLower(_string);
if (s == "-1.#ind00") {
return nan();
}
if (s == "1.#inf00") {
return inf();
}
if (s == "-1.#inf00") {
return -inf();
}
double n;
if ((_string.length() > 2) &&
(_string[0] == '0') &&
(_string[1] == 'x')) {
// Hex
uint32 i;
sscanf(_string.c_str(), "%x", &i);
n = i;
} else {
sscanf(_string.c_str(), "%lg", &n);
}
return n;
} else {
return 0.0;
}
}
TextInput::Settings::Settings ()
: cComments(true), cppComments(true), escapeSequencesInStrings(true),
otherCommentCharacter('\0'), otherCommentCharacter2('\0'),
signedNumbers(true), singleQuotedStrings(true), sourceFileName(),
startingLineNumberOffset(0), msvcSpecials(true), proofSymbols(false),
caseSensitive(true)
{
trueSymbols.insert("true");
falseSymbols.insert("false");
}
Token TextInput::peek() {
if (stack.size() == 0) {
Token t = nextToken();
push(t);
}
return stack.front();
}
int TextInput::peekLineNumber() {
return peek().line();
}
int TextInput::peekCharacterNumber() {
return peek().character();
}
Token TextInput::read() {
if (stack.size() > 0) {
Token t = stack.front();
stack.pop_front();
return t;
} else {
return nextToken();
}
}
static void toUpper(Set<std::string>& set) {
Array<std::string> symbols;
set.getMembers(symbols);
set.clear();
for (int i = 0; i < symbols.size(); ++i) {
set.insert(toUpper(symbols[i]));
}
}
void TextInput::init() {
currentCharOffset = 0;
charNumber = 1;
lineNumber = 1 + options.startingLineNumberOffset;
if (! options.caseSensitive) {
// Convert true and false symbols to all uppercase for fast comparisons
toUpper(options.trueSymbols);
toUpper(options.falseSymbols);
}
}
void TextInput::push(const Token& t) {
stack.push_front(t);
}
bool TextInput::hasMore() {
return (peek()._type != Token::END);
}
int TextInput::eatInputChar() {
// Don't go off the end
if (currentCharOffset >= (unsigned int)buffer.length()) {
return EOF;
}
unsigned char c = buffer[currentCharOffset];
++currentCharOffset;
// update lineNumber and charNumber to reflect the location of the *next*
// character which will be read.
//
// We update even for CR because the user is allowed to do arbitrarily
// stupid things, like put a bunch of literal CRs inside a quoted string.
//
// We eat all whitespace between tokens, so they should never see a
// lineNumber that points to a CR. However, if they have some kind of
// syntax error in a token that appears *after* a quoted string
// containing CRs, they should get a correct character number.
// TODO: http://sourceforge.net/tracker/index.php?func=detail&aid=1341266&group_id=76879&atid=548565
if (c == '\n') {
++lineNumber;
charNumber = 1;
} else {
++charNumber;
}
return c;
}
int TextInput::peekInputChar(unsigned int distance) {
// Don't go off the end
if ((currentCharOffset + distance) >= (unsigned int)buffer.length()) {
return EOF;
}
unsigned char c = buffer[currentCharOffset + distance];
return c;
}
Token TextInput::nextToken() {
Token t;
t._line = lineNumber;
t._character = charNumber;
t._type = Token::END;
t._extendedType = Token::END_TYPE;
int c = peekInputChar();
if (c == EOF) {
return t;
}
bool whitespaceDone = false;
while (! whitespaceDone) {
whitespaceDone = true;
// Consume whitespace
while (isWhiteSpace(c)) {
c = eatAndPeekInputChar();
}
int c2 = peekInputChar(1);
if ((options.cppComments && c == '/' && c2 == '/')
|| (options.otherCommentCharacter != '\0'
&& c == options.otherCommentCharacter)
|| (options.otherCommentCharacter2 != '\0'
&& c == options.otherCommentCharacter2)) {
// Single line comment, consume to newline or EOF.
do {
c = eatAndPeekInputChar();
} while (! isNewline(c) && c != EOF);
// There is whitespace after the comment (in particular, the
// newline that terminates the comment). There might also be
// whitespace at the start of the next line.
whitespaceDone = false;
} else if (options.cComments && (c == '/') && (c2 == '*')) {
// consume both start-comment chars, can't let the trailing one
// help close the comment.
eatInputChar();
eatInputChar();
// Multi-line comment, consume to end-marker or EOF.
c = peekInputChar();
c2 = peekInputChar(1);
while (! ((c == '*') && (c2 == '/')) && (c != EOF)) {
eatInputChar();
c = c2;
c2 = peekInputChar(1);
}
eatInputChar(); // eat closing '*'
eatInputChar(); // eat closing '/'
c = peekInputChar();
// May be whitespace after comment.
whitespaceDone = false;
}
} // while (! whitespaceDone)
t._line = lineNumber;
t._character = charNumber;
// handle EOF
if (c == EOF) {
return t;
}
// Extended ASCII parses as itself, except for EOF
if (c > 127 && c < 255) {
t._type = Token::SYMBOL;
t._extendedType = Token::SYMBOL_TYPE;
t._string = c;
c = eatAndPeekInputChar();
}
// Perform appropriate setup for a symbol (including setting up the token
// string to start with c), eat the input character, and overwrite
// 'c' with the peeked next input character.
#define SETUP_SYMBOL(c) \
{ \
t._type = Token::SYMBOL; \
t._extendedType = Token::SYMBOL_TYPE; \
t._string = c; \
c = eatAndPeekInputChar(); \
}
switch (c) {
case '@': // Simple symbols -> just themselves.
case '(':
case ')':
case ',':
case ';':
case '{':
case '}':
case '[':
case ']':
case '#':
case '$':
case '?':
case '%':
SETUP_SYMBOL(c);
return t;
case '-': // negative number, -, --, -=, or ->
SETUP_SYMBOL(c);
switch (c) {
case '>': // ->
case '-': // --
case '=': // -=
t._string += c;
eatInputChar();
return t;
}
if (options.signedNumbers
&& (isDigit(c) || (c == '.' && isDigit(peekInputChar(1))))) {
// Negative number. 'c' is still the first digit, and is
// the next input char.
goto numLabel;
}
// plain -
return t;
case '+': // positive number, +, ++, or +=
SETUP_SYMBOL(c);
switch (c) {
case '+': // ++
case '=': // +=
t._string += c;
eatInputChar();
return t;
}
if (options.signedNumbers
&& (isDigit(c) || (c == '.' && isDigit(peekInputChar(1))))) {
// Positive number. 'c' is still the first digit, and is
// the next input char.
goto numLabel;
}
return t;
case ':': // : or :: or ::> or ::= or := or :>
SETUP_SYMBOL(c);
if (c == ':') {
t._string += c;
eatInputChar();
if (options.proofSymbols) {
c = peekInputChar(0);
if ((c == '>') || (c == '=')) {
t._string += c;
eatInputChar();
}
}
}
else if (options.proofSymbols && (c == '=' || c == '>')) {
t._string += c;
eatInputChar();
}
return t;
case '=': // = or == or =>
SETUP_SYMBOL(c);
if (c == '=') {
t._string += c;
eatInputChar();
return t;
} else if (options.proofSymbols && (c == '>')) {
t._string += c;
eatInputChar();
return t;
}
return t;
case '*': // * or *=
case '/': // / or /=
case '!': // ! or !=
case '~': // ~ or ~=
case '^': // ^ or ^=
SETUP_SYMBOL(c);
if (c == '=') {
t._string += c;
eatInputChar();
return t;
}
return t;
case '>': // >, >>,or >=
case '<': // <<, <<, or <= or <- or <:
case '|': // ||, ||, or |= or |-
case '&': // &, &&, or &=
{
int orig_c = c;
SETUP_SYMBOL(c);
if ((c == '=') || (orig_c == c)) {
t._string += c;
eatInputChar();
return t;
} else if (options.proofSymbols) {
if ((orig_c == '<') && (c == '-')) {
t._string += c;
eatInputChar();
} else if ((orig_c == '|') && (c == '-')) {
t._string += c;
eatInputChar();
} else if ((orig_c == '<') && (c == ':')) {
t._string += c;
c = eatAndPeekInputChar();
if (c == ':') {
t._string += c;
eatInputChar();
}
}
}
}
return t;
case '\\': // backslash or escaped comment char.
SETUP_SYMBOL(c);
if ((options.otherCommentCharacter != '\0'
&& c == options.otherCommentCharacter)
|| (options.otherCommentCharacter2 != '\0'
&& c == options.otherCommentCharacter2)) {
// escaped comment character. Return the raw comment
// char (no backslash).
t._string = c;
eatInputChar();
return t;
}
return t;
case '.': // number, ., .., or ...
if (isDigit(peekInputChar(1))) {
// We're parsing a float that began without a leading zero
goto numLabel;
}
SETUP_SYMBOL(c);
if (c == '.') { // .. or ...
t._string += c;
c = eatAndPeekInputChar();
if (c == '.') { // ...
t._string += c;
eatInputChar();
}
return t;
}
return t;
} // switch (c)
#undef SETUP_SYMBOL
numLabel:
if (isDigit(c) || (c == '.')) {
// A number. Note-- single dots have been
// parsed already, so a . indicates a number
// less than 1 in floating point form.
// [0-9]*(\.[0-9]) or [0-9]+ or 0x[0-9,A-F]+
if (t._string != "-") {
// If we picked up a leading "-" sign above, keep it,
// otherwise drop the string parsed thus far
t._string = "";
}
t._type = Token::NUMBER;
if (c == '.') {
t._extendedType = Token::FLOATING_POINT_TYPE;
} else {
t._extendedType = Token::INTEGER_TYPE;
}
if ((c == '0') && (peekInputChar(1) == 'x')) {
// Hex number
t._string += "0x";
// skip the 0x
eatInputChar();
eatInputChar();
c = peekInputChar();
while (isDigit(c) || ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f'))) {
t._string += c;
c = eatAndPeekInputChar();
}
} else {
// Non-hex number
// Read the part before the decimal.
while (isDigit(c)) {
t._string += c;
c = eatAndPeekInputChar();
}
// True if we are reading a floating-point special type
bool isSpecial = false;
// Read the decimal, if one exists
if (c == '.') {
t._extendedType = Token::FLOATING_POINT_TYPE;
// The '.' character was a decimal point, not the start of a
// method or range operator
t._string += c;
c = eatAndPeekInputChar();
// Floating point specials (msvc format only)
if (options.msvcSpecials && (c == '#')) {
isSpecial = true;
// We are reading a floating point special value
// of the form -1.#IND00, -1.#INF00, or 1.#INF00
c = eatAndPeekInputChar();
char test = c;
if (! options.caseSensitive) {
test = toupper(c);
}
if (test != 'I') {
throw BadMSVCSpecial
(
"Incorrect floating-point special (inf or nan) "
"format.",
t.line(), charNumber);
}
c = eatAndPeekInputChar();
test = c;
if (! options.caseSensitive) {
test = toupper(c);
}
if (test != 'N') {
throw BadMSVCSpecial
(
"Incorrect floating-point special (inf or nan) "
"format.",
t.line(), charNumber);
}
t._string += "#IN";
c = eatAndPeekInputChar();
test = c;
if (! options.caseSensitive) {
test = toupper(c);
}
if ((test != 'F') && (test != 'D')) {
throw BadMSVCSpecial
(
"Incorrect floating-point special (inf or nan) "
"format.",
t.line(), charNumber);
}
t._string += c;
for (int j = 0; j < 2; ++j) {
c = eatAndPeekInputChar();
if (c != '0') {
throw BadMSVCSpecial
(
"Incorrect floating-point special (inf or"
"nan) format.",
t.line(), charNumber);
}
t._string += (char)c;
}
} else {
// Read the part after the decimal
while (isDigit((char)c)) {
t._string += (char)c;
c = eatAndPeekInputChar();
}
}
}
if (! isSpecial && ((c == 'e') || (c == 'E'))) {
// Read exponent
t._extendedType = Token::FLOATING_POINT_TYPE;
t._string += c;
c = eatAndPeekInputChar();
if ((c == '-') || (c == '+')) {
t._string += c;
c = eatAndPeekInputChar();
}
while (isDigit(c)) {
t._string += c;
c = eatAndPeekInputChar();
}
}
}
return t;
} else if (isLetter(c) || (c == '_')) {
// Identifier or keyword
// [A-Za-z_][A-Za-z_0-9]*
t._type = Token::SYMBOL;
t._extendedType = Token::SYMBOL_TYPE;
t._string = "";
do {
t._string += c;
c = eatAndPeekInputChar();
} while (isLetter(c) || isDigit(c) || (c == '_'));
// See if this symbol is actually a boolean
if ((options.trueSymbols.size() > 0) || (options.falseSymbols.size() > 0)) {
std::string str = t._string;
if (! options.caseSensitive) {
str = toUpper(str);
}
if (options.trueSymbols.contains(str)) {
t._type = Token::BOOLEAN;
t._extendedType = Token::BOOLEAN_TYPE;
t._bool = true;
} else if (options.falseSymbols.contains(str)) {
t._type = Token::BOOLEAN;
t._extendedType = Token::BOOLEAN_TYPE;
t._bool = false;
}
}
return t;
} else if (c == '\"') {
// Discard the double-quote.
eatInputChar();
// Double quoted string
parseQuotedString('\"', t);
return t;
} else if (c == '\'') {
// Discard the single-quote.
eatInputChar();
if (options.singleQuotedStrings) {
// Single quoted string
parseQuotedString('\'', t);
} else {
t._string = c;
t._type = Token::SYMBOL;
t._extendedType = Token::SYMBOL_TYPE;
}
return t;
} // end of special case tokens
if (c == EOF) {
t._type = Token::END;
t._extendedType = Token::END_TYPE;
t._string = "";
return t;
}
// Some unknown token
debugAssertM(false,
format("Unrecognized token type beginning with character '%c' (ASCII %d)",
c, c));
return t;
}
void TextInput::parseQuotedString(unsigned char delimiter, Token& t) {
t._type = Token::STRING;
if (delimiter == '\'') {
t._extendedType = Token::SINGLE_QUOTED_TYPE;
} else {
t._extendedType = Token::DOUBLE_QUOTED_TYPE;
}
while (true) {
// We're definitely going to consume the next input char, so we get
// it right now. This makes the condition handling below a bit easier.
int c = eatInputChar();
if (c == EOF) {
// END inside a quoted string. (We finish the string.)
break;
}
if (options.escapeSequencesInStrings && (c == '\\')) {
// An escaped character. We're definitely going to consume it,
// so we get it (and consume it) now.
c = eatInputChar();
switch (c) {
case 'r':
t._string += '\r';
break;
case 'n':
t._string += '\n';
break;
case 't':
t._string += '\t';
break;
case '0':
t._string += '\0';
break;
case '\\':
case '\"':
case '\'':
t._string += (char)c;
break;
default:
if (((c == options.otherCommentCharacter) &&
(options.otherCommentCharacter != '\0')) ||
((c == options.otherCommentCharacter2) &&
(options.otherCommentCharacter2 != '\0'))) {
t._string += c;
}
// otherwise, some illegal escape sequence; skip it.
break;
} // switch
} else if (c == delimiter) {
// End of the string. Already consumed the character.
break;
} else {
// All other chars, go on to the string. Already consumed the
// character.
t._string += (char)c;
}
}
}
bool TextInput::readBoolean() {
Token t(read());
if (t._type == Token::BOOLEAN) {
return t.boolean();
}
// Push initial token back, and throw an error. We intentionally
// indicate that the wrong type is the type of the initial token.
// Logically, the number started there.
push(t);
throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
Token::BOOLEAN, t._type);
}
double TextInput::readNumber() {
Token t(read());
if (t._type == Token::NUMBER) {
return t.number();
}
// Even if signedNumbers is disabled, readNumber attempts to
// read a signed number, so we handle that case here.
if (! options.signedNumbers
&& (t._type == Token::SYMBOL)
&& ((t._string == "-")
|| (t._string == "+"))) {
Token t2(read());
if ((t2._type == Token::NUMBER)
&& (t2._character == t._character + 1)) {
if (t._string == "-") {
return -t2.number();
} else {
return t2.number();
}
}
// push back the second token.
push(t2);
}
// Push initial token back, and throw an error. We intentionally
// indicate that the wrong type is the type of the initial token.
// Logically, the number started there.
push(t);
throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
Token::NUMBER, t._type);
}
Token TextInput::readStringToken() {
Token t(read());
if (t._type == Token::STRING) { // fast path
return t;
}
push(t);
throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
Token::STRING, t._type);
}
std::string TextInput::readString() {
return readStringToken()._string;
}
void TextInput::readString(const std::string& s) {
Token t(readStringToken());
if (t._string == s) { // fast path
return;
}
push(t);
throw WrongString(options.sourceFileName, t.line(), t.character(),
s, t._string);
}
Token TextInput::readSymbolToken() {
Token t(read());
if (t._type == Token::SYMBOL) { // fast path
return t;
}
push(t);
throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
Token::SYMBOL, t._type);
}
std::string TextInput::readSymbol() {
return readSymbolToken()._string;
}
void TextInput::readSymbol(const std::string& symbol) {
Token t(readSymbolToken());
if (t._string == symbol) { // fast path
return;
}
push(t);
throw WrongSymbol(options.sourceFileName, t.line(), t.character(),
symbol, t._string);
}
TextInput::TextInput(const std::string& filename, const Settings& opt) : options(opt) {
init();
std::string input = readWholeFile(filename);
if (options.sourceFileName.empty()) {
options.sourceFileName = filename;
}
int n = input.size();
buffer.resize(n);
System::memcpy(buffer.getCArray(), input.c_str(), n);
}
TextInput::TextInput(FS fs, const std::string& str, const Settings& opt) : options(opt) {
(void)fs;
init();
if (options.sourceFileName.empty()) {
if (str.length() < 14) {
options.sourceFileName = std::string("\"") + str + "\"";
} else {
options.sourceFileName = std::string("\"") + str.substr(0, 10) + "...\"";
}
}
buffer.resize(str.length()); // we don't bother copying trailing NUL.
System::memcpy(buffer.getCArray(), str.c_str(), buffer.size());
}
const std::string& TextInput::filename() const {
return options.sourceFileName;
}
///////////////////////////////////////////////////////////////////////////////////
TextInput::TokenException::TokenException(
const std::string& src,
int ln,
int ch) : sourceFile(src), line(ln), character(ch) {
message = format("%s(%d) : ", sourceFile.c_str(), line);
}
///////////////////////////////////////////////////////////////////////////////////
static const char* tokenTypeToString(Token::Type t) {
switch (t) {
case Token::SYMBOL:
return "Token::SYMBOL";
case Token::STRING:
return "Token::STRING";
case Token::NUMBER:
return "Token::NUMBER";
case Token::END:
return "Token::END";
default:
debugAssertM(false, "Fell through switch");
return "?";
}
}
TextInput::WrongTokenType::WrongTokenType(
const std::string& src,
int ln,
int ch,
Token::Type e,
Token::Type a) :
TokenException(src, ln, ch), expected(e), actual(a) {
message += format("Expected token of type %s, found type %s.",
tokenTypeToString(e), tokenTypeToString(a));
}
TextInput::BadMSVCSpecial::BadMSVCSpecial(
const std::string& src,
int ln,
int ch) :
TokenException(src, ln, ch) {
}
TextInput::WrongSymbol::WrongSymbol(
const std::string& src,
int ln,
int ch,
const std::string& e,
const std::string& a) :
TokenException(src, ln, ch), expected(e), actual(a) {
message += format("Expected symbol '%s', found symbol '%s'.",
e.c_str(), a.c_str());
}
TextInput::WrongString::WrongString(
const std::string& src,
int ln,
int ch,
const std::string& e,
const std::string& a) :
TokenException(src, ln, ch), expected(e), actual(a) {
message += format("Expected string '%s', found string '%s'.",
e.c_str(), a.c_str());
}
void deserialize(bool& b, TextInput& ti) {
b = ti.readSymbol() == "true";
}
void deserialize(int& b, TextInput& ti) {
b = iRound(ti.readNumber());
}
void deserialize(uint8& b, TextInput& ti) {
b = (uint8)iRound(ti.readNumber());
}
void deserialize(double& b, TextInput& ti) {
b = ti.readNumber();
}
void deserialize(float& b, TextInput& ti) {
b = (float)ti.readNumber();
}
} // namespace
#ifdef _MSC_VER
# pragma warning (pop)
#endif
-452
View File
@@ -1,452 +0,0 @@
/**
@file TextOutput.cpp
@maintainer Morgan McGuire, morgan@graphics3d.com
@created 2004-06-21
@edited 2006-08-14
Copyright 2000-2006, Morgan McGuire.
All rights reserved.
*/
#include "G3D/TextOutput.h"
#include "G3D/Log.h"
#include "G3D/fileutils.h"
namespace G3D {
TextOutput::TextOutput(const TextOutput::Settings& opt) :
startingNewLine(true),
currentColumn(0),
inDQuote(false),
filename(""),
indentLevel(0)
{
setOptions(opt);
}
TextOutput::TextOutput(const std::string& fil, const TextOutput::Settings& opt) :
startingNewLine(true),
currentColumn(0),
inDQuote(false),
filename(fil),
indentLevel(0)
{
setOptions(opt);
}
void TextOutput::setIndentLevel(int i) {
indentLevel = i;
// If there were more pops than pushes, don't let that take us below 0 indent.
// Don't ever indent more than the number of columns.
indentSpaces =
iClamp(option.spacesPerIndent * indentLevel,
0,
option.numColumns - 1);
}
void TextOutput::setOptions(const Settings& _opt) {
option = _opt;
debugAssert(option.numColumns > 1);
setIndentLevel(indentLevel);
newline = (option.newlineStyle == Settings::NEWLINE_WINDOWS) ? "\r\n" : "\n";
}
void TextOutput::pushIndent() {
setIndentLevel(indentLevel + 1);
}
void TextOutput::popIndent() {
setIndentLevel(indentLevel - 1);
}
static std::string escape(const std::string& string) {
std::string result = "";
for (std::string::size_type i = 0; i < string.length(); ++i) {
char c = string.at(i);
switch (c) {
case '\0':
result += "\\0";
break;
case '\r':
result += "\\r";
break;
case '\n':
result += "\\n";
break;
case '\t':
result += "\\t";
break;
case '\\':
result += "\\\\";
break;
default:
result += c;
}
}
return result;
}
void TextOutput::writeString(const std::string& string) {
// Convert special characters to escape sequences
this->printf("\"%s\"", escape(string).c_str());
}
void TextOutput::writeBoolean(bool b) {
this->printf("%s ", b ? option.trueSymbol.c_str() : option.falseSymbol.c_str());
}
void TextOutput::writeNumber(double n) {
this->printf("%f ", n);
}
void TextOutput::writeNumber(int n) {
this->printf("%d ", n);
}
void TextOutput::writeSymbol(const std::string& string) {
if (string.size() > 0) {
// TODO: check for legal symbols?
this->printf("%s ", string.c_str());
}
}
void TextOutput::writeSymbols(
const std::string& a,
const std::string& b,
const std::string& c,
const std::string& d,
const std::string& e,
const std::string& f) {
writeSymbol(a);
writeSymbol(b);
writeSymbol(c);
writeSymbol(d);
writeSymbol(e);
writeSymbol(f);
}
void TextOutput::printf(const std::string formatString, ...) {
va_list argList;
va_start(argList, formatString);
this->vprintf(formatString.c_str(), argList);
va_end(argList);
}
void TextOutput::printf(const char* formatString, ...) {
va_list argList;
va_start(argList, formatString);
this->vprintf(formatString, argList);
va_end(argList);
}
void TextOutput::convertNewlines(const std::string& in, std::string& out) {
// TODO: can be significantly optimized in cases where
// single characters are copied in order by walking through
// the array and copying substrings as needed.
if (option.convertNewlines) {
out = "";
for (uint32 i = 0; i < in.size(); ++i) {
if (in[i] == '\n') {
// Unix newline
out += newline;
} else if ((in[i] == '\r') && (i + 1 < in.size()) && (in[i + 1] == '\n')) {
// Windows newline
out += newline;
++i;
} else {
out += in[i];
}
}
} else {
out = in;
}
}
void TextOutput::writeNewline() {
for (uint32 i = 0; i < newline.size(); ++i) {
indentAppend(newline[i]);
}
}
void TextOutput::writeNewlines(int numLines) {
for (int i = 0; i < numLines; ++i) {
writeNewline();
}
}
void TextOutput::wordWrapIndentAppend(const std::string& str) {
// TODO: keep track of the last space character we saw so we don't
// have to always search.
if ((option.wordWrap == Settings::WRAP_NONE) ||
(currentColumn + (int)str.size() <= option.numColumns)) {
// No word-wrapping is needed
// Add one character at a time.
// TODO: optimize for strings without newlines to add multiple
// characters.
for (uint32 i = 0; i < str.size(); ++i) {
indentAppend(str[i]);
}
return;
}
// Number of columns to wrap against
int cols = option.numColumns - indentSpaces;
// Copy forward until we exceed the column size,
// and then back up and try to insert newlines as needed.
for (uint32 i = 0; i < str.size(); ++i) {
indentAppend(str[i]);
if ((str[i] == '\r') && (i + 1 < str.size()) && (str[i + 1] == '\n')) {
// \r\n, we need to hit the \n to enter word wrapping.
++i;
indentAppend(str[i]);
}
if (currentColumn >= cols) {
debugAssertM(str[i] != '\n' && str[i] != '\r',
"Should never enter word-wrapping on a newline character");
// True when we're allowed to treat a space as a space.
bool unquotedSpace = option.allowWordWrapInsideDoubleQuotes || ! inDQuote;
// Cases:
//
// 1. Currently in a series of spaces that ends with a newline
// strip all spaces and let the newline
// flow through.
//
// 2. Currently in a series of spaces that does not end with a newline
// strip all spaces and replace them with single newline
//
// 3. Not in a series of spaces
// search backwards for a space, then execute case 2.
// Index of most recent space
uint32 lastSpace = data.size() - 1;
// How far back we had to look for a space
uint32 k = 0;
uint32 maxLookBackward = currentColumn - indentSpaces;
// Search backwards (from current character), looking for a space.
while ((k < maxLookBackward) &&
(lastSpace > 0) &&
(! ((data[lastSpace] == ' ') && unquotedSpace))) {
--lastSpace;
++k;
if ((data[lastSpace] == '\"') && !option.allowWordWrapInsideDoubleQuotes) {
unquotedSpace = ! unquotedSpace;
}
}
if (k == maxLookBackward) {
// We couldn't find a series of spaces
if (option.wordWrap == Settings::WRAP_ALWAYS) {
// Strip the last character we wrote, force a newline,
// and replace the last character;
data.pop();
writeNewline();
indentAppend(str[i]);
} else {
// Must be Settings::WRAP_WITHOUT_BREAKING
//
// Don't write the newline; we'll come back to
// the word wrap code after writing another character
}
} else {
// We found a series of spaces. If they continue
// to the new string, strip spaces off both. Otherwise
// strip spaces from data only and insert a newline.
// Find the start of the spaces. firstSpace is the index of the
// first non-space, looking backwards from lastSpace.
uint32 firstSpace = lastSpace;
while ((k < maxLookBackward) &&
(firstSpace > 0) &&
(data[firstSpace] == ' ')) {
--firstSpace;
++k;
}
if (k == maxLookBackward) {
++firstSpace;
}
if (lastSpace == (uint32)data.size() - 1) {
// Spaces continued up to the new string
data.resize(firstSpace + 1);
writeNewline();
// Delete the spaces from the new string
while ((i < str.size() - 1) && (str[i + 1] == ' ')) {
++i;
}
} else {
// Spaces were somewhere in the middle of the old string.
// replace them with a newline.
// Copy over the characters that should be saved
Array<char> temp;
for (uint32 j = lastSpace + 1; j < (uint32)data.size(); ++j) {
char c = data[j];
if (c == '\"') {
// Undo changes to quoting (they will be re-done
// when we paste these characters back on).
inDQuote = !inDQuote;
}
temp.append(c);
}
// Remove those characters and replace with a newline.
data.resize(firstSpace + 1);
writeNewline();
// Write them back
for (uint32 j = 0; j < (uint32)temp.size(); ++j) {
indentAppend(temp[j]);
}
// We are now free to continue adding from the
// new string, which may or may not begin with spaces.
} // if spaces included new string
} // if hit indent
} // if line exceeded
} // iterate over str
}
void TextOutput::indentAppend(char c) {
if (startingNewLine) {
for (int j = 0; j < indentSpaces; ++j) {
data.push(' ');
}
startingNewLine = false;
currentColumn = indentSpaces;
}
data.push(c);
// Don't increment the column count on return character
// newline is taken care of below.
if (c != '\r') {
++currentColumn;
}
if (c == '\"') {
inDQuote = ! inDQuote;
}
startingNewLine = (c == '\n');
if (startingNewLine) {
currentColumn = 0;
}
}
void TextOutput::vprintf(const char* formatString, va_list argPtr) {
std::string str = vformat(formatString, argPtr);
std::string clean;
convertNewlines(str, clean);
wordWrapIndentAppend(clean);
}
void TextOutput::commit(bool flush) {
std::string p = filenamePath(filename);
if (! fileExists(p, false)) {
createDirectory(p);
}
FILE* f = fopen(filename.c_str(), "wb");
debugAssert(f);
fwrite(data.getCArray(), 1, data.size(), f);
if (flush) {
fflush(f);
}
fclose(f);
}
void TextOutput::commitString(std::string& out) {
// Null terminate
data.push('\0');
out = data.getCArray();
data.pop();
}
std::string TextOutput::commitString() {
std::string str;
commitString(str);
return str;
}
/////////////////////////////////////////////////////////////////////
void serialize(const float& b, TextOutput& to) {
to.writeNumber(b);
}
void serialize(const bool& b, TextOutput& to) {
to.writeSymbol(b ? "true" : "false");
}
void serialize(const int& b, TextOutput& to) {
to.writeNumber(b);
}
void serialize(const uint8& b, TextOutput& to) {
to.writeNumber(b);
}
void serialize(const double& b, TextOutput& to) {
to.writeNumber(b);
}
}
-147
View File
@@ -1,147 +0,0 @@
#include "G3D/ThreadSet.h"
namespace G3D {
int ThreadSet::size() const {
ThreadSet* me = const_cast<ThreadSet*>(this);
me->m_lock.lock();
int s = m_thread.size();
me->m_lock.unlock();
return s;
}
int ThreadSet::numStarted() const {
ThreadSet* me = const_cast<ThreadSet*>(this);
me->m_lock.lock();
int count = 0;
for (int i = 0; i < m_thread.size(); ++i) {
if (m_thread[i]->started()) {
++count;
}
}
me->m_lock.unlock();
return count;
}
void ThreadSet::start() const {
ThreadSet* me = const_cast<ThreadSet*>(this);
me->m_lock.lock();
for (int i = 0; i < m_thread.size(); ++i) {
if (! m_thread[i]->started()) {
m_thread[i]->start();
}
}
me->m_lock.unlock();
}
void ThreadSet::terminate() const {
ThreadSet* me = const_cast<ThreadSet*>(this);
me->m_lock.lock();
for (int i = 0; i < m_thread.size(); ++i) {
if (m_thread[i]->started()) {
m_thread[i]->terminate();
}
}
me->m_lock.unlock();
}
void ThreadSet::waitForCompletion() const {
ThreadSet* me = const_cast<ThreadSet*>(this);
me->m_lock.lock();
for (int i = 0; i < m_thread.size(); ++i) {
if (m_thread[i]->started()) {
m_thread[i]->waitForCompletion();
}
}
me->m_lock.unlock();
}
int ThreadSet::removeCompleted() {
m_lock.lock();
for (int i = 0; i < m_thread.size(); ++i) {
if (m_thread[i]->completed()) {
m_thread.fastRemove(i);
--i;
}
}
int s = m_thread.size();
m_lock.unlock();
return s;
}
void ThreadSet::clear() {
m_lock.lock();
m_thread.clear();
m_lock.unlock();
}
int ThreadSet::insert(const ThreadRef& t) {
m_lock.lock();
bool found = false;
for (int i = 0; i < m_thread.size() && ! found; ++i) {
found = (m_thread[i] == t);
}
if (! found) {
m_thread.append(t);
}
int s = m_thread.size();
m_lock.unlock();
return s;
}
bool ThreadSet::remove(const ThreadRef& t) {
m_lock.lock();
bool found = false;
for (int i = 0; i < m_thread.size() && ! found; ++i) {
found = (m_thread[i] == t);
if (found) {
m_thread.fastRemove(i);
}
}
m_lock.unlock();
return found;
}
bool ThreadSet::contains(const ThreadRef& t) const {
ThreadSet* me = const_cast<ThreadSet*>(this);
me->m_lock.lock();
bool found = false;
for (int i = 0; i < m_thread.size() && ! found; ++i) {
found = (m_thread[i] == t);
}
me->m_lock.unlock();
return found;
}
ThreadSet::Iterator ThreadSet::begin() {
return m_thread.begin();
}
ThreadSet::Iterator ThreadSet::end() {
return m_thread.end();
}
ThreadSet::ConstIterator ThreadSet::begin() const {
return m_thread.begin();
}
ThreadSet::ConstIterator ThreadSet::end() const {
return m_thread.end();
}
} // namespace G3D
-135
View File
@@ -1,135 +0,0 @@
/**
@file Triangle.cpp
@maintainer Morgan McGuire, graphics3d.com
@created 2001-04-06
@edited 2006-01-20
Copyright 2000-2006, Morgan McGuire.
All rights reserved.
*/
#include "G3D/platform.h"
#include "G3D/Triangle.h"
#include "G3D/Plane.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/debugAssert.h"
#include "G3D/AABox.h"
namespace G3D {
void Triangle::init(const Vector3& v0, const Vector3& v1, const Vector3& v2) {
_plane = Plane(v0, v1, v2);
_vertex[0] = v0;
_vertex[1] = v1;
_vertex[2] = v2;
static int next[] = {1,2,0};
for (int i = 0; i < 3; ++i) {
const Vector3& e = _vertex[next[i]] - _vertex[i];
edgeMagnitude[i] = e.magnitude();
if (edgeMagnitude[i] == 0) {
edgeDirection[i] = Vector3::zero();
} else {
edgeDirection[i] = e / (float)edgeMagnitude[i];
}
}
_edge01 = _vertex[1] - _vertex[0];
_edge02 = _vertex[2] - _vertex[0];
_primaryAxis = _plane.normal().primaryAxis();
_area = 0.5f * edgeDirection[0].cross(edgeDirection[2]).magnitude() * (edgeMagnitude[0] * edgeMagnitude[2]);
//0.5f * (_vertex[1] - _vertex[0]).cross(_vertex[2] - _vertex[0]).dot(_plane.normal());
}
Triangle::Triangle() {
init(Vector3::zero(), Vector3::zero(), Vector3::zero());
}
Triangle::Triangle(const Vector3& v0, const Vector3& v1, const Vector3& v2) {
init(v0, v1, v2);
}
Triangle::~Triangle() {
}
Triangle::Triangle(class BinaryInput& b) {
deserialize(b);
}
void Triangle::serialize(class BinaryOutput& b) {
_vertex[0].serialize(b);
_vertex[1].serialize(b);
_vertex[2].serialize(b);
}
void Triangle::deserialize(class BinaryInput& b) {
_vertex[0].deserialize(b);
_vertex[1].deserialize(b);
_vertex[2].deserialize(b);
init(_vertex[0], _vertex[1], _vertex[2]);
}
float Triangle::area() const {
return _area;
}
const Vector3& Triangle::normal() const {
return _plane.normal();
}
const Plane& Triangle::plane() const {
return _plane;
}
Vector3 Triangle::center() const {
return (_vertex[0] + _vertex[1] + _vertex[2]) / 3.0;
}
Vector3 Triangle::randomPoint() const {
// Choose a random point in the parallelogram
float s = uniformRandom();
float t = uniformRandom();
if (t > 1.0f - s) {
// Outside the triangle; reflect about the
// diagonal of the parallelogram
t = 1.0f - t;
s = 1.0f - s;
}
return _edge01 * s + _edge02 * t + _vertex[0];
}
void Triangle::getBounds(AABox& out) const {
Vector3 lo = _vertex[0];
Vector3 hi = lo;
for (int i = 1; i < 3; ++i) {
lo = lo.min(_vertex[i]);
hi = hi.max(_vertex[i]);
}
out = AABox(lo, hi);
}
} // G3D
-132
View File
@@ -1,132 +0,0 @@
/**
@file UprightFrame.cpp
Box class
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2007-05-02
@edited 2007-05-05
*/
#include "G3D/UprightFrame.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
namespace G3D {
UprightFrame::UprightFrame(const CoordinateFrame& cframe) {
Vector3 look = cframe.lookVector();
yaw = G3D::pi() + atan2(look.x, look.z);
pitch = asin(look.y);
translation = cframe.translation;
}
CoordinateFrame UprightFrame::toCoordinateFrame() const {
CoordinateFrame cframe;
Matrix3 P(Matrix3::fromAxisAngle(Vector3::unitX(), pitch));
Matrix3 Y(Matrix3::fromAxisAngle(Vector3::unitY(), yaw));
cframe.rotation = Y * P;
cframe.translation = translation;
return cframe;
}
UprightFrame UprightFrame::operator+(const UprightFrame& other) const {
return UprightFrame(translation + other.translation, pitch + other.pitch, yaw + other.yaw);
}
UprightFrame UprightFrame::operator*(const float k) const {
return UprightFrame(translation * k, pitch * k, yaw * k);
}
void UprightFrame::unwrapYaw(UprightFrame* a, int N) {
// Use the first point to establish the wrapping convention
for (int i = 1; i < N; ++i) {
const float prev = a[i - 1].yaw;
float& cur = a[i].yaw;
// No two angles should be more than pi (i.e., 180-degrees) apart.
if (abs(cur - prev) > G3D::pi()) {
// These angles must have wrapped at zero, causing them
// to be interpolated the long way.
// Find canonical [0, 2pi] versions of these numbers
float p = wrap(prev, twoPi());
float c = wrap(cur, twoPi());
// Find the difference -pi < diff < pi between the current and previous values
float diff = c - p;
if (diff < -G3D::pi()) {
diff += twoPi();
} else if (diff > G3D::pi()) {
diff -= twoPi();
}
// Offset the current from the previous by the difference
// between them.
cur = prev + diff;
}
}
}
void UprightFrame::serialize(class BinaryOutput& b) const {
translation.serialize(b);
b.writeFloat32(pitch);
b.writeFloat32(yaw);
}
void UprightFrame::deserialize(class BinaryInput& b) {
translation.deserialize(b);
pitch = b.readFloat32();
yaw = b.readFloat32();
}
void UprightSpline::serialize(class BinaryOutput& b) const {
b.writeBool8(cyclic);
b.writeInt32(control.size());
for (int i = 0; i < control.size(); ++i) {
control[i].serialize(b);
}
b.writeInt32(time.size());
for (int i = 0; i < time.size(); ++i) {
b.writeFloat32(time[i]);
}
}
void UprightSpline::deserialize(class BinaryInput& b) {
cyclic = b.readBool8();
control.resize(b.readInt32());
for (int i = 0; i < control.size(); ++i) {
control[i].deserialize(b);
}
if (b.hasMore()) {
time.resize(b.readInt32());
for (int i = 0; i < time.size(); ++i) {
time[i] = b.readFloat32();
}
debugAssert(time.size() == control.size());
} else {
// Import legacy path
time.resize(control.size());
for (int i = 0; i < time.size(); ++i) {
time[i] = i;
}
}
}
}
-211
View File
@@ -1,211 +0,0 @@
/**
@file Vector2.cpp
2D vector class, used for texture coordinates primarily.
@maintainer Morgan McGuire, matrix@graphics3d.com
@cite Portions based on Dave Eberly'x Magic Software Library
at http://www.magic-software.com
@created 2001-06-02
@edited 2006-01-16
*/
#include "G3D/platform.h"
#include <stdlib.h>
#include "G3D/Vector2.h"
#include "G3D/g3dmath.h"
#include "G3D/format.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/TextInput.h"
#include "G3D/TextOutput.h"
namespace G3D {
const Vector2& Vector2::zero() {
static Vector2 v(0, 0);
return v;
}
const Vector2& Vector2::unitX() {
static Vector2 v(1, 0);
return v;
}
const Vector2& Vector2::unitY() {
static Vector2 v(0, 1);
return v;
}
const Vector2& Vector2::inf() {
static Vector2 v((float)G3D::inf(), (float)G3D::inf());
return v;
}
const Vector2& Vector2::nan() {
static Vector2 v((float)G3D::nan(), (float)G3D::nan());
return v;
}
const Vector2& Vector2::minFinite() {
static Vector2 v(-FLT_MAX, -FLT_MAX);
return v;
}
const Vector2& Vector2::maxFinite() {
static Vector2 v(FLT_MAX, FLT_MAX);
return v;
}
size_t Vector2::hashCode() const {
unsigned int xhash = (*(int*)(void*)(&x));
unsigned int yhash = (*(int*)(void*)(&y));
return xhash + (yhash * 37);
}
Vector2::Vector2(BinaryInput& b) {
deserialize(b);
}
void Vector2::deserialize(BinaryInput& b) {
x = b.readFloat32();
y = b.readFloat32();
}
void Vector2::serialize(BinaryOutput& b) const {
b.writeFloat32(x);
b.writeFloat32(y);
}
void Vector2::deserialize(TextInput& t) {
t.readSymbol("(");
x = (float)t.readNumber();
t.readSymbol(",");
y = (float)t.readNumber();
t.readSymbol(")");
}
void Vector2::serialize(TextOutput& t) const {
t.writeSymbol("(");
t.writeNumber(x);
t.writeSymbol(",");
t.writeNumber(y);
t.writeSymbol(")");
}
//----------------------------------------------------------------------------
Vector2 Vector2::random() {
Vector2 result;
do {
result = Vector2(uniformRandom(-1, 1), uniformRandom(-1, 1));
} while (result.squaredLength() >= 1.0f);
result.unitize();
return result;
}
//----------------------------------------------------------------------------
Vector2 Vector2::operator/ (float fScalar) const {
Vector2 kQuot;
if ( fScalar != 0.0f ) {
float fInvScalar = 1.0f / fScalar;
kQuot.x = fInvScalar * x;
kQuot.y = fInvScalar * y;
return kQuot;
} else {
return Vector2::inf();
}
}
//----------------------------------------------------------------------------
Vector2& Vector2::operator/= (float fScalar) {
if (fScalar != 0.0f) {
float fInvScalar = 1.0f / fScalar;
x *= fInvScalar;
y *= fInvScalar;
} else {
x = (float)G3D::inf();
y = (float)G3D::inf();
}
return *this;
}
//----------------------------------------------------------------------------
float Vector2::unitize (float fTolerance) {
float fLength = length();
if (fLength > fTolerance) {
float fInvLength = 1.0f / fLength;
x *= fInvLength;
y *= fInvLength;
} else {
fLength = 0.0;
}
return fLength;
}
//----------------------------------------------------------------------------
std::string Vector2::toString() const {
return G3D::format("(%g, %g)", x, y);
}
// 2-char swizzles
Vector2 Vector2::xx() const { return Vector2 (x, x); }
Vector2 Vector2::yx() const { return Vector2 (y, x); }
Vector2 Vector2::xy() const { return Vector2 (x, y); }
Vector2 Vector2::yy() const { return Vector2 (y, y); }
// 3-char swizzles
Vector3 Vector2::xxx() const { return Vector3 (x, x, x); }
Vector3 Vector2::yxx() const { return Vector3 (y, x, x); }
Vector3 Vector2::xyx() const { return Vector3 (x, y, x); }
Vector3 Vector2::yyx() const { return Vector3 (y, y, x); }
Vector3 Vector2::xxy() const { return Vector3 (x, x, y); }
Vector3 Vector2::yxy() const { return Vector3 (y, x, y); }
Vector3 Vector2::xyy() const { return Vector3 (x, y, y); }
Vector3 Vector2::yyy() const { return Vector3 (y, y, y); }
// 4-char swizzles
Vector4 Vector2::xxxx() const { return Vector4 (x, x, x, x); }
Vector4 Vector2::yxxx() const { return Vector4 (y, x, x, x); }
Vector4 Vector2::xyxx() const { return Vector4 (x, y, x, x); }
Vector4 Vector2::yyxx() const { return Vector4 (y, y, x, x); }
Vector4 Vector2::xxyx() const { return Vector4 (x, x, y, x); }
Vector4 Vector2::yxyx() const { return Vector4 (y, x, y, x); }
Vector4 Vector2::xyyx() const { return Vector4 (x, y, y, x); }
Vector4 Vector2::yyyx() const { return Vector4 (y, y, y, x); }
Vector4 Vector2::xxxy() const { return Vector4 (x, x, x, y); }
Vector4 Vector2::yxxy() const { return Vector4 (y, x, x, y); }
Vector4 Vector2::xyxy() const { return Vector4 (x, y, x, y); }
Vector4 Vector2::yyxy() const { return Vector4 (y, y, x, y); }
Vector4 Vector2::xxyy() const { return Vector4 (x, x, y, y); }
Vector4 Vector2::yxyy() const { return Vector4 (y, x, y, y); }
Vector4 Vector2::xyyy() const { return Vector4 (x, y, y, y); }
Vector4 Vector2::yyyy() const { return Vector4 (y, y, y, y); }
} // namespace
-47
View File
@@ -1,47 +0,0 @@
/**
@file Vector2int16.cpp
@author Morgan McGuire, matrix@graphics3d.com
@created 2003-08-09
@edited 2006-01-29
*/
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
#include "G3D/Vector2int16.h"
#include "G3D/Vector2.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
namespace G3D {
Vector2int16::Vector2int16(const class Vector2& v) {
x = (int16)iFloor(v.x + 0.5);
y = (int16)iFloor(v.y + 0.5);
}
Vector2int16::Vector2int16(class BinaryInput& bi) {
deserialize(bi);
}
void Vector2int16::serialize(class BinaryOutput& bo) const {
bo.writeInt16(x);
bo.writeInt16(y);
}
void Vector2int16::deserialize(class BinaryInput& bi) {
x = bi.readInt16();
y = bi.readInt16();
}
Vector2int16 Vector2int16::clamp(const Vector2int16& lo, const Vector2int16& hi) {
return Vector2int16(iClamp(x, lo.x, hi.x), iClamp(y, lo.y, hi.y));
}
}
-493
View File
@@ -1,493 +0,0 @@
/**
@file Vector3.cpp
3D vector class
@maintainer Morgan McGuire, matrix@graphics3d.com
@cite Portions based on Dave Eberly's Magic Software Library at http://www.magic-software.com
@created 2001-06-02
@edited 2006-01-30
*/
#include <limits>
#include <stdlib.h>
#include "G3D/Vector3.h"
#include "G3D/g3dmath.h"
#include "G3D/stringutils.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/TextInput.h"
#include "G3D/TextOutput.h"
#include "G3D/Vector3int16.h"
#include "G3D/Matrix3.h"
#include "G3D/Vector2.h"
#include "G3D/Vector4int8.h"
namespace G3D {
Vector3 Vector3::dummy;
Vector3::Vector3(const Vector4int8& v) : x(v.x / 127.0f), y(v.y / 127.0f), z(v.z / 127.0f) {}
Vector3::Vector3(const class Vector2& v, float _z) : x(v.x), y(v.y), z(_z) {
}
Vector3::Axis Vector3::primaryAxis() const {
Axis a = X_AXIS;
double nx = abs(x);
double ny = abs(y);
double nz = abs(z);
if (nx > ny) {
if (nx > nz) {
a = X_AXIS;
} else {
a = Z_AXIS;
}
} else {
if (ny > nz) {
a = Y_AXIS;
} else {
a = Z_AXIS;
}
}
return a;
}
size_t Vector3::hashCode() const {
unsigned int xhash = (*(int*)(void*)(&x));
unsigned int yhash = (*(int*)(void*)(&y));
unsigned int zhash = (*(int*)(void*)(&z));
return xhash + (yhash * 37) + (zhash * 101);
}
std::ostream& operator<<(std::ostream& os, const Vector3& v) {
return os << v.toString();
}
//----------------------------------------------------------------------------
double frand() {
return rand() / (double) RAND_MAX;
}
Vector3::Vector3(TextInput& t) {
deserialize(t);
}
Vector3::Vector3(BinaryInput& b) {
deserialize(b);
}
Vector3::Vector3(const class Vector3int16& v) {
x = v.x;
y = v.y;
z = v.z;
}
void Vector3::deserialize(BinaryInput& b) {
x = b.readFloat32();
y = b.readFloat32();
z = b.readFloat32();
}
void Vector3::deserialize(TextInput& t) {
t.readSymbol("(");
x = (float)t.readNumber();
t.readSymbol(",");
y = (float)t.readNumber();
t.readSymbol(",");
z = (float)t.readNumber();
t.readSymbol(")");
}
void Vector3::serialize(TextOutput& t) const {
t.writeSymbol("(");
t.writeNumber(x);
t.writeSymbol(",");
t.writeNumber(y);
t.writeSymbol(",");
t.writeNumber(z);
t.writeSymbol(")");
}
void Vector3::serialize(BinaryOutput& b) const {
b.writeFloat32(x);
b.writeFloat32(y);
b.writeFloat32(z);
}
Vector3 Vector3::random() {
Vector3 result;
do {
result = Vector3(uniformRandom(-1.0, 1.0),
uniformRandom(-1.0, 1.0),
uniformRandom(-1.0, 1.0));
} while (result.squaredMagnitude() >= 1.0f);
result.unitize();
return result;
}
//----------------------------------------------------------------------------
Vector3 Vector3::operator/ (float fScalar) const {
Vector3 kQuot;
if ( fScalar != 0.0 ) {
float fInvScalar = 1.0f / fScalar;
kQuot.x = fInvScalar * x;
kQuot.y = fInvScalar * y;
kQuot.z = fInvScalar * z;
return kQuot;
} else {
return Vector3::inf();
}
}
//----------------------------------------------------------------------------
Vector3& Vector3::operator/= (float fScalar) {
if (fScalar != 0.0) {
float fInvScalar = 1.0f / fScalar;
x *= fInvScalar;
y *= fInvScalar;
z *= fInvScalar;
} else {
x = (float)G3D::inf();
y = (float)G3D::inf();
z = (float)G3D::inf();
}
return *this;
}
//----------------------------------------------------------------------------
float Vector3::unitize (float fTolerance) {
float fMagnitude = magnitude();
if (fMagnitude > fTolerance) {
float fInvMagnitude = 1.0f / fMagnitude;
x *= fInvMagnitude;
y *= fInvMagnitude;
z *= fInvMagnitude;
} else {
fMagnitude = 0.0f;
}
return fMagnitude;
}
//----------------------------------------------------------------------------
Vector3 Vector3::reflectAbout(const Vector3& normal) const {
Vector3 out;
Vector3 N = normal.direction();
// 2 * normal.dot(this) * normal - this
return N * 2 * this->dot(N) - *this;
}
//----------------------------------------------------------------------------
Vector3 Vector3::cosRandom(const Vector3& normal) {
double e1 = G3D::uniformRandom(0, 1);
double e2 = G3D::uniformRandom(0, 1);
// Angle from normal
double theta = acos(sqrt(e1));
// Angle about normal
double phi = 2 * pi() * e2;
// Make a coordinate system
Vector3 U = normal.direction();
Vector3 V = Vector3::unitX();
if (abs(U.dot(V)) > .9) {
V = Vector3::unitY();
}
Vector3 W = U.cross(V).direction();
V = W.cross(U);
// Convert to rectangular form
return cos(theta) * U + sin(theta) * (cos(phi) * V + sin(phi) * W);
}
//----------------------------------------------------------------------------
Vector3 Vector3::hemiRandom(const Vector3& normal) {
Vector3 V = Vector3::random();
if (V.dot(normal) < 0) {
return -V;
} else {
return V;
}
}
//----------------------------------------------------------------------------
Vector3 Vector3::reflectionDirection(const Vector3& normal) const {
return -reflectAbout(normal).direction();
}
//----------------------------------------------------------------------------
Vector3 Vector3::refractionDirection(
const Vector3& normal,
float iInside,
float iOutside) const {
// From pg. 24 of Henrik Wann Jensen. Realistic Image Synthesis
// Using Photon Mapping. AK Peters. ISBN: 1568811470. July 2001.
// Invert the directions from Wann Jensen's formulation
// and normalize the vectors.
const Vector3 W = -direction();
Vector3 N = normal.direction();
float h1 = iOutside;
float h2 = iInside;
if (normal.dot(*this) > 0.0f) {
h1 = iInside;
h2 = iOutside;
N = -N;
}
const float hRatio = h1 / h2;
const float WdotN = W.dot(N);
float det = 1.0f - (float)square(hRatio) * (1.0f - (float)square(WdotN));
if (det < 0) {
// Total internal reflection
return Vector3::zero();
} else {
return -hRatio * (W - WdotN * N) - N * sqrt(det);
}
}
//----------------------------------------------------------------------------
void Vector3::orthonormalize (Vector3 akVector[3]) {
// If the input vectors are v0, v1, and v2, then the Gram-Schmidt
// orthonormalization produces vectors u0, u1, and u2 as follows,
//
// u0 = v0/|v0|
// u1 = (v1-(u0*v1)u0)/|v1-(u0*v1)u0|
// u2 = (v2-(u0*v2)u0-(u1*v2)u1)/|v2-(u0*v2)u0-(u1*v2)u1|
//
// where |A| indicates length of vector A and A*B indicates dot
// product of vectors A and B.
// compute u0
akVector[0].unitize();
// compute u1
float fDot0 = akVector[0].dot(akVector[1]);
akVector[1] -= akVector[0] * fDot0;
akVector[1].unitize();
// compute u2
float fDot1 = akVector[1].dot(akVector[2]);
fDot0 = akVector[0].dot(akVector[2]);
akVector[2] -= akVector[0] * fDot0 + akVector[1] * fDot1;
akVector[2].unitize();
}
//----------------------------------------------------------------------------
void Vector3::generateOrthonormalBasis (Vector3& rkU, Vector3& rkV,
Vector3& rkW, bool bUnitLengthW) {
if ( !bUnitLengthW )
rkW.unitize();
if ( G3D::abs(rkW.x) >= G3D::abs(rkW.y)
&& G3D::abs(rkW.x) >= G3D::abs(rkW.z) ) {
rkU.x = -rkW.y;
rkU.y = + rkW.x;
rkU.z = 0.0;
} else {
rkU.x = 0.0;
rkU.y = + rkW.z;
rkU.z = -rkW.y;
}
rkU.unitize();
rkV = rkW.cross(rkU);
}
//----------------------------------------------------------------------------
std::string Vector3::toString() const {
return G3D::format("(%g, %g, %g)", x, y, z);
}
//----------------------------------------------------------------------------
Matrix3 Vector3::cross() const {
return Matrix3( 0, -z, y,
z, 0, -x,
-y, x, 0);
}
void serialize(const Vector3::Axis& a, class BinaryOutput& bo) {
bo.writeUInt8((uint8)a);
}
void deserialize(Vector3::Axis& a, class BinaryInput& bi) {
a = (Vector3::Axis)bi.readUInt8();
}
//----------------------------------------------------------------------------
// 2-char swizzles
Vector2 Vector3::xx() const { return Vector2 (x, x); }
Vector2 Vector3::yx() const { return Vector2 (y, x); }
Vector2 Vector3::zx() const { return Vector2 (z, x); }
Vector2 Vector3::xy() const { return Vector2 (x, y); }
Vector2 Vector3::yy() const { return Vector2 (y, y); }
Vector2 Vector3::zy() const { return Vector2 (z, y); }
Vector2 Vector3::xz() const { return Vector2 (x, z); }
Vector2 Vector3::yz() const { return Vector2 (y, z); }
Vector2 Vector3::zz() const { return Vector2 (z, z); }
// 3-char swizzles
Vector3 Vector3::xxx() const { return Vector3 (x, x, x); }
Vector3 Vector3::yxx() const { return Vector3 (y, x, x); }
Vector3 Vector3::zxx() const { return Vector3 (z, x, x); }
Vector3 Vector3::xyx() const { return Vector3 (x, y, x); }
Vector3 Vector3::yyx() const { return Vector3 (y, y, x); }
Vector3 Vector3::zyx() const { return Vector3 (z, y, x); }
Vector3 Vector3::xzx() const { return Vector3 (x, z, x); }
Vector3 Vector3::yzx() const { return Vector3 (y, z, x); }
Vector3 Vector3::zzx() const { return Vector3 (z, z, x); }
Vector3 Vector3::xxy() const { return Vector3 (x, x, y); }
Vector3 Vector3::yxy() const { return Vector3 (y, x, y); }
Vector3 Vector3::zxy() const { return Vector3 (z, x, y); }
Vector3 Vector3::xyy() const { return Vector3 (x, y, y); }
Vector3 Vector3::yyy() const { return Vector3 (y, y, y); }
Vector3 Vector3::zyy() const { return Vector3 (z, y, y); }
Vector3 Vector3::xzy() const { return Vector3 (x, z, y); }
Vector3 Vector3::yzy() const { return Vector3 (y, z, y); }
Vector3 Vector3::zzy() const { return Vector3 (z, z, y); }
Vector3 Vector3::xxz() const { return Vector3 (x, x, z); }
Vector3 Vector3::yxz() const { return Vector3 (y, x, z); }
Vector3 Vector3::zxz() const { return Vector3 (z, x, z); }
Vector3 Vector3::xyz() const { return Vector3 (x, y, z); }
Vector3 Vector3::yyz() const { return Vector3 (y, y, z); }
Vector3 Vector3::zyz() const { return Vector3 (z, y, z); }
Vector3 Vector3::xzz() const { return Vector3 (x, z, z); }
Vector3 Vector3::yzz() const { return Vector3 (y, z, z); }
Vector3 Vector3::zzz() const { return Vector3 (z, z, z); }
// 4-char swizzles
Vector4 Vector3::xxxx() const { return Vector4 (x, x, x, x); }
Vector4 Vector3::yxxx() const { return Vector4 (y, x, x, x); }
Vector4 Vector3::zxxx() const { return Vector4 (z, x, x, x); }
Vector4 Vector3::xyxx() const { return Vector4 (x, y, x, x); }
Vector4 Vector3::yyxx() const { return Vector4 (y, y, x, x); }
Vector4 Vector3::zyxx() const { return Vector4 (z, y, x, x); }
Vector4 Vector3::xzxx() const { return Vector4 (x, z, x, x); }
Vector4 Vector3::yzxx() const { return Vector4 (y, z, x, x); }
Vector4 Vector3::zzxx() const { return Vector4 (z, z, x, x); }
Vector4 Vector3::xxyx() const { return Vector4 (x, x, y, x); }
Vector4 Vector3::yxyx() const { return Vector4 (y, x, y, x); }
Vector4 Vector3::zxyx() const { return Vector4 (z, x, y, x); }
Vector4 Vector3::xyyx() const { return Vector4 (x, y, y, x); }
Vector4 Vector3::yyyx() const { return Vector4 (y, y, y, x); }
Vector4 Vector3::zyyx() const { return Vector4 (z, y, y, x); }
Vector4 Vector3::xzyx() const { return Vector4 (x, z, y, x); }
Vector4 Vector3::yzyx() const { return Vector4 (y, z, y, x); }
Vector4 Vector3::zzyx() const { return Vector4 (z, z, y, x); }
Vector4 Vector3::xxzx() const { return Vector4 (x, x, z, x); }
Vector4 Vector3::yxzx() const { return Vector4 (y, x, z, x); }
Vector4 Vector3::zxzx() const { return Vector4 (z, x, z, x); }
Vector4 Vector3::xyzx() const { return Vector4 (x, y, z, x); }
Vector4 Vector3::yyzx() const { return Vector4 (y, y, z, x); }
Vector4 Vector3::zyzx() const { return Vector4 (z, y, z, x); }
Vector4 Vector3::xzzx() const { return Vector4 (x, z, z, x); }
Vector4 Vector3::yzzx() const { return Vector4 (y, z, z, x); }
Vector4 Vector3::zzzx() const { return Vector4 (z, z, z, x); }
Vector4 Vector3::xxxy() const { return Vector4 (x, x, x, y); }
Vector4 Vector3::yxxy() const { return Vector4 (y, x, x, y); }
Vector4 Vector3::zxxy() const { return Vector4 (z, x, x, y); }
Vector4 Vector3::xyxy() const { return Vector4 (x, y, x, y); }
Vector4 Vector3::yyxy() const { return Vector4 (y, y, x, y); }
Vector4 Vector3::zyxy() const { return Vector4 (z, y, x, y); }
Vector4 Vector3::xzxy() const { return Vector4 (x, z, x, y); }
Vector4 Vector3::yzxy() const { return Vector4 (y, z, x, y); }
Vector4 Vector3::zzxy() const { return Vector4 (z, z, x, y); }
Vector4 Vector3::xxyy() const { return Vector4 (x, x, y, y); }
Vector4 Vector3::yxyy() const { return Vector4 (y, x, y, y); }
Vector4 Vector3::zxyy() const { return Vector4 (z, x, y, y); }
Vector4 Vector3::xyyy() const { return Vector4 (x, y, y, y); }
Vector4 Vector3::yyyy() const { return Vector4 (y, y, y, y); }
Vector4 Vector3::zyyy() const { return Vector4 (z, y, y, y); }
Vector4 Vector3::xzyy() const { return Vector4 (x, z, y, y); }
Vector4 Vector3::yzyy() const { return Vector4 (y, z, y, y); }
Vector4 Vector3::zzyy() const { return Vector4 (z, z, y, y); }
Vector4 Vector3::xxzy() const { return Vector4 (x, x, z, y); }
Vector4 Vector3::yxzy() const { return Vector4 (y, x, z, y); }
Vector4 Vector3::zxzy() const { return Vector4 (z, x, z, y); }
Vector4 Vector3::xyzy() const { return Vector4 (x, y, z, y); }
Vector4 Vector3::yyzy() const { return Vector4 (y, y, z, y); }
Vector4 Vector3::zyzy() const { return Vector4 (z, y, z, y); }
Vector4 Vector3::xzzy() const { return Vector4 (x, z, z, y); }
Vector4 Vector3::yzzy() const { return Vector4 (y, z, z, y); }
Vector4 Vector3::zzzy() const { return Vector4 (z, z, z, y); }
Vector4 Vector3::xxxz() const { return Vector4 (x, x, x, z); }
Vector4 Vector3::yxxz() const { return Vector4 (y, x, x, z); }
Vector4 Vector3::zxxz() const { return Vector4 (z, x, x, z); }
Vector4 Vector3::xyxz() const { return Vector4 (x, y, x, z); }
Vector4 Vector3::yyxz() const { return Vector4 (y, y, x, z); }
Vector4 Vector3::zyxz() const { return Vector4 (z, y, x, z); }
Vector4 Vector3::xzxz() const { return Vector4 (x, z, x, z); }
Vector4 Vector3::yzxz() const { return Vector4 (y, z, x, z); }
Vector4 Vector3::zzxz() const { return Vector4 (z, z, x, z); }
Vector4 Vector3::xxyz() const { return Vector4 (x, x, y, z); }
Vector4 Vector3::yxyz() const { return Vector4 (y, x, y, z); }
Vector4 Vector3::zxyz() const { return Vector4 (z, x, y, z); }
Vector4 Vector3::xyyz() const { return Vector4 (x, y, y, z); }
Vector4 Vector3::yyyz() const { return Vector4 (y, y, y, z); }
Vector4 Vector3::zyyz() const { return Vector4 (z, y, y, z); }
Vector4 Vector3::xzyz() const { return Vector4 (x, z, y, z); }
Vector4 Vector3::yzyz() const { return Vector4 (y, z, y, z); }
Vector4 Vector3::zzyz() const { return Vector4 (z, z, y, z); }
Vector4 Vector3::xxzz() const { return Vector4 (x, x, z, z); }
Vector4 Vector3::yxzz() const { return Vector4 (y, x, z, z); }
Vector4 Vector3::zxzz() const { return Vector4 (z, x, z, z); }
Vector4 Vector3::xyzz() const { return Vector4 (x, y, z, z); }
Vector4 Vector3::yyzz() const { return Vector4 (y, y, z, z); }
Vector4 Vector3::zyzz() const { return Vector4 (z, y, z, z); }
Vector4 Vector3::xzzz() const { return Vector4 (x, z, z, z); }
Vector4 Vector3::yzzz() const { return Vector4 (y, z, z, z); }
Vector4 Vector3::zzzz() const { return Vector4 (z, z, z, z); }
} // namespace
-49
View File
@@ -1,49 +0,0 @@
/**
@file Vector3int16.cpp
@author Morgan McGuire, matrix@graphics3d.com
@created 2003-04-07
@edited 2006-01-17
*/
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
#include "G3D/Vector3int16.h"
#include "G3D/Vector3.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/format.h"
namespace G3D {
Vector3int16::Vector3int16(const class Vector3& v) {
x = (int16)iFloor(v.x + 0.5);
y = (int16)iFloor(v.y + 0.5);
z = (int16)iFloor(v.z + 0.5);
}
Vector3int16::Vector3int16(class BinaryInput& bi) {
deserialize(bi);
}
void Vector3int16::serialize(class BinaryOutput& bo) const {
bo.writeInt16(x);
bo.writeInt16(y);
bo.writeInt16(z);
}
void Vector3int16::deserialize(class BinaryInput& bi) {
x = bi.readInt16();
y = bi.readInt16();
z = bi.readInt16();
}
std::string Vector3int16::toString() const {
return G3D::format("(%d, %d, %d)", x, y, z);
}
}
-57
View File
@@ -1,57 +0,0 @@
/**
@file Vector3int32.cpp
@author Morgan McGuire, matrix@graphics3d.com
@created 2008-07-01
@edited 2008-07-01
*/
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
#include "G3D/Vector3int32.h"
#include "G3D/Vector3int16.h"
#include "G3D/Vector3.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/format.h"
namespace G3D {
Vector3int32::Vector3int32(const class Vector3& v) {
x = (int32)iFloor(v.x + 0.5);
y = (int32)iFloor(v.y + 0.5);
z = (int32)iFloor(v.z + 0.5);
}
Vector3int32::Vector3int32(const class Vector3int16& v) {
x = v.x;
y = v.y;
z = v.z;
}
Vector3int32::Vector3int32(class BinaryInput& bi) {
deserialize(bi);
}
void Vector3int32::serialize(class BinaryOutput& bo) const {
bo.writeInt32(x);
bo.writeInt32(y);
bo.writeInt32(z);
}
void Vector3int32::deserialize(class BinaryInput& bi) {
x = bi.readInt32();
y = bi.readInt32();
z = bi.readInt32();
}
std::string Vector3int32::toString() const {
return G3D::format("(%d, %d, %d)", x, y, z);
}
}
-475
View File
@@ -1,475 +0,0 @@
/**
@file Vector4.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2001-07-09
@edited 2007-02-29
*/
#include <stdlib.h>
#include <limits>
#include "G3D/Vector4.h"
#include "G3D/Color4.h"
#include "G3D/g3dmath.h"
#include "G3D/stringutils.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/Vector4int8.h"
#include "G3D/Matrix4.h"
namespace G3D {
Vector4::Vector4(const Vector4int8& v) : x(v.x / 127.0f), y(v.y / 127.0f), z(v.z / 127.0f), w(v.w / 127.0f) {
}
size_t Vector4::hashCode() const {
unsigned int xhash = (*(int*)(void*)(&x));
unsigned int yhash = (*(int*)(void*)(&y));
unsigned int zhash = (*(int*)(void*)(&z));
unsigned int whash = (*(int*)(void*)(&w));
return xhash + (yhash * 37) + (zhash * 101) + (whash * 241);
}
Vector4::Vector4(const class Color4& c) {
x = c.r;
y = c.g;
z = c.b;
w = c.a;
}
Vector4::Vector4(const Vector2& v1, const Vector2& v2) {
x = v1.x;
y = v1.y;
z = v2.x;
w = v2.y;
}
Vector4::Vector4(const Vector2& v1, float fz, float fw) {
x = v1.x;
y = v1.y;
z = fz;
w = fw;
}
Vector4::Vector4(BinaryInput& b) {
deserialize(b);
}
void Vector4::deserialize(BinaryInput& b) {
x = b.readFloat32();
y = b.readFloat32();
z = b.readFloat32();
w = b.readFloat32();
}
void Vector4::serialize(BinaryOutput& b) const {
b.writeFloat32(x);
b.writeFloat32(y);
b.writeFloat32(z);
b.writeFloat32(w);
}
//----------------------------------------------------------------------------
Vector4 Vector4::operator*(const Matrix4& M) const {
Vector4 result;
for (int i = 0; i < 4; ++i) {
result[i] = 0.0f;
for (int j = 0; j < 4; ++j) {
result[i] += (*this)[j] * M[j][i];
}
}
return result;
}
Vector4 Vector4::operator/ (float fScalar) const {
Vector4 kQuot;
if ( fScalar != 0.0 ) {
float fInvScalar = 1.0f / fScalar;
kQuot.x = fInvScalar * x;
kQuot.y = fInvScalar * y;
kQuot.z = fInvScalar * z;
kQuot.w = fInvScalar * w;
return kQuot;
} else {
return Vector4::inf();
}
}
//----------------------------------------------------------------------------
Vector4& Vector4::operator/= (float fScalar) {
if (fScalar != 0.0f) {
float fInvScalar = 1.0f / fScalar;
x *= fInvScalar;
y *= fInvScalar;
z *= fInvScalar;
w *= fInvScalar;
} else {
*this = Vector4::inf();
}
return *this;
}
//----------------------------------------------------------------------------
std::string Vector4::toString() const {
return G3D::format("(%g, %g, %g, %g)", x, y, z, w);
}
// 2-char swizzles
Vector2 Vector4::xx() const { return Vector2 (x, x); }
Vector2 Vector4::yx() const { return Vector2 (y, x); }
Vector2 Vector4::zx() const { return Vector2 (z, x); }
Vector2 Vector4::wx() const { return Vector2 (w, x); }
Vector2 Vector4::xy() const { return Vector2 (x, y); }
Vector2 Vector4::yy() const { return Vector2 (y, y); }
Vector2 Vector4::zy() const { return Vector2 (z, y); }
Vector2 Vector4::wy() const { return Vector2 (w, y); }
Vector2 Vector4::xz() const { return Vector2 (x, z); }
Vector2 Vector4::yz() const { return Vector2 (y, z); }
Vector2 Vector4::zz() const { return Vector2 (z, z); }
Vector2 Vector4::wz() const { return Vector2 (w, z); }
Vector2 Vector4::xw() const { return Vector2 (x, w); }
Vector2 Vector4::yw() const { return Vector2 (y, w); }
Vector2 Vector4::zw() const { return Vector2 (z, w); }
Vector2 Vector4::ww() const { return Vector2 (w, w); }
// 3-char swizzles
Vector3 Vector4::xxx() const { return Vector3 (x, x, x); }
Vector3 Vector4::yxx() const { return Vector3 (y, x, x); }
Vector3 Vector4::zxx() const { return Vector3 (z, x, x); }
Vector3 Vector4::wxx() const { return Vector3 (w, x, x); }
Vector3 Vector4::xyx() const { return Vector3 (x, y, x); }
Vector3 Vector4::yyx() const { return Vector3 (y, y, x); }
Vector3 Vector4::zyx() const { return Vector3 (z, y, x); }
Vector3 Vector4::wyx() const { return Vector3 (w, y, x); }
Vector3 Vector4::xzx() const { return Vector3 (x, z, x); }
Vector3 Vector4::yzx() const { return Vector3 (y, z, x); }
Vector3 Vector4::zzx() const { return Vector3 (z, z, x); }
Vector3 Vector4::wzx() const { return Vector3 (w, z, x); }
Vector3 Vector4::xwx() const { return Vector3 (x, w, x); }
Vector3 Vector4::ywx() const { return Vector3 (y, w, x); }
Vector3 Vector4::zwx() const { return Vector3 (z, w, x); }
Vector3 Vector4::wwx() const { return Vector3 (w, w, x); }
Vector3 Vector4::xxy() const { return Vector3 (x, x, y); }
Vector3 Vector4::yxy() const { return Vector3 (y, x, y); }
Vector3 Vector4::zxy() const { return Vector3 (z, x, y); }
Vector3 Vector4::wxy() const { return Vector3 (w, x, y); }
Vector3 Vector4::xyy() const { return Vector3 (x, y, y); }
Vector3 Vector4::yyy() const { return Vector3 (y, y, y); }
Vector3 Vector4::zyy() const { return Vector3 (z, y, y); }
Vector3 Vector4::wyy() const { return Vector3 (w, y, y); }
Vector3 Vector4::xzy() const { return Vector3 (x, z, y); }
Vector3 Vector4::yzy() const { return Vector3 (y, z, y); }
Vector3 Vector4::zzy() const { return Vector3 (z, z, y); }
Vector3 Vector4::wzy() const { return Vector3 (w, z, y); }
Vector3 Vector4::xwy() const { return Vector3 (x, w, y); }
Vector3 Vector4::ywy() const { return Vector3 (y, w, y); }
Vector3 Vector4::zwy() const { return Vector3 (z, w, y); }
Vector3 Vector4::wwy() const { return Vector3 (w, w, y); }
Vector3 Vector4::xxz() const { return Vector3 (x, x, z); }
Vector3 Vector4::yxz() const { return Vector3 (y, x, z); }
Vector3 Vector4::zxz() const { return Vector3 (z, x, z); }
Vector3 Vector4::wxz() const { return Vector3 (w, x, z); }
Vector3 Vector4::xyz() const { return Vector3 (x, y, z); }
Vector3 Vector4::yyz() const { return Vector3 (y, y, z); }
Vector3 Vector4::zyz() const { return Vector3 (z, y, z); }
Vector3 Vector4::wyz() const { return Vector3 (w, y, z); }
Vector3 Vector4::xzz() const { return Vector3 (x, z, z); }
Vector3 Vector4::yzz() const { return Vector3 (y, z, z); }
Vector3 Vector4::zzz() const { return Vector3 (z, z, z); }
Vector3 Vector4::wzz() const { return Vector3 (w, z, z); }
Vector3 Vector4::xwz() const { return Vector3 (x, w, z); }
Vector3 Vector4::ywz() const { return Vector3 (y, w, z); }
Vector3 Vector4::zwz() const { return Vector3 (z, w, z); }
Vector3 Vector4::wwz() const { return Vector3 (w, w, z); }
Vector3 Vector4::xxw() const { return Vector3 (x, x, w); }
Vector3 Vector4::yxw() const { return Vector3 (y, x, w); }
Vector3 Vector4::zxw() const { return Vector3 (z, x, w); }
Vector3 Vector4::wxw() const { return Vector3 (w, x, w); }
Vector3 Vector4::xyw() const { return Vector3 (x, y, w); }
Vector3 Vector4::yyw() const { return Vector3 (y, y, w); }
Vector3 Vector4::zyw() const { return Vector3 (z, y, w); }
Vector3 Vector4::wyw() const { return Vector3 (w, y, w); }
Vector3 Vector4::xzw() const { return Vector3 (x, z, w); }
Vector3 Vector4::yzw() const { return Vector3 (y, z, w); }
Vector3 Vector4::zzw() const { return Vector3 (z, z, w); }
Vector3 Vector4::wzw() const { return Vector3 (w, z, w); }
Vector3 Vector4::xww() const { return Vector3 (x, w, w); }
Vector3 Vector4::yww() const { return Vector3 (y, w, w); }
Vector3 Vector4::zww() const { return Vector3 (z, w, w); }
Vector3 Vector4::www() const { return Vector3 (w, w, w); }
// 4-char swizzles
Vector4 Vector4::xxxx() const { return Vector4 (x, x, x, x); }
Vector4 Vector4::yxxx() const { return Vector4 (y, x, x, x); }
Vector4 Vector4::zxxx() const { return Vector4 (z, x, x, x); }
Vector4 Vector4::wxxx() const { return Vector4 (w, x, x, x); }
Vector4 Vector4::xyxx() const { return Vector4 (x, y, x, x); }
Vector4 Vector4::yyxx() const { return Vector4 (y, y, x, x); }
Vector4 Vector4::zyxx() const { return Vector4 (z, y, x, x); }
Vector4 Vector4::wyxx() const { return Vector4 (w, y, x, x); }
Vector4 Vector4::xzxx() const { return Vector4 (x, z, x, x); }
Vector4 Vector4::yzxx() const { return Vector4 (y, z, x, x); }
Vector4 Vector4::zzxx() const { return Vector4 (z, z, x, x); }
Vector4 Vector4::wzxx() const { return Vector4 (w, z, x, x); }
Vector4 Vector4::xwxx() const { return Vector4 (x, w, x, x); }
Vector4 Vector4::ywxx() const { return Vector4 (y, w, x, x); }
Vector4 Vector4::zwxx() const { return Vector4 (z, w, x, x); }
Vector4 Vector4::wwxx() const { return Vector4 (w, w, x, x); }
Vector4 Vector4::xxyx() const { return Vector4 (x, x, y, x); }
Vector4 Vector4::yxyx() const { return Vector4 (y, x, y, x); }
Vector4 Vector4::zxyx() const { return Vector4 (z, x, y, x); }
Vector4 Vector4::wxyx() const { return Vector4 (w, x, y, x); }
Vector4 Vector4::xyyx() const { return Vector4 (x, y, y, x); }
Vector4 Vector4::yyyx() const { return Vector4 (y, y, y, x); }
Vector4 Vector4::zyyx() const { return Vector4 (z, y, y, x); }
Vector4 Vector4::wyyx() const { return Vector4 (w, y, y, x); }
Vector4 Vector4::xzyx() const { return Vector4 (x, z, y, x); }
Vector4 Vector4::yzyx() const { return Vector4 (y, z, y, x); }
Vector4 Vector4::zzyx() const { return Vector4 (z, z, y, x); }
Vector4 Vector4::wzyx() const { return Vector4 (w, z, y, x); }
Vector4 Vector4::xwyx() const { return Vector4 (x, w, y, x); }
Vector4 Vector4::ywyx() const { return Vector4 (y, w, y, x); }
Vector4 Vector4::zwyx() const { return Vector4 (z, w, y, x); }
Vector4 Vector4::wwyx() const { return Vector4 (w, w, y, x); }
Vector4 Vector4::xxzx() const { return Vector4 (x, x, z, x); }
Vector4 Vector4::yxzx() const { return Vector4 (y, x, z, x); }
Vector4 Vector4::zxzx() const { return Vector4 (z, x, z, x); }
Vector4 Vector4::wxzx() const { return Vector4 (w, x, z, x); }
Vector4 Vector4::xyzx() const { return Vector4 (x, y, z, x); }
Vector4 Vector4::yyzx() const { return Vector4 (y, y, z, x); }
Vector4 Vector4::zyzx() const { return Vector4 (z, y, z, x); }
Vector4 Vector4::wyzx() const { return Vector4 (w, y, z, x); }
Vector4 Vector4::xzzx() const { return Vector4 (x, z, z, x); }
Vector4 Vector4::yzzx() const { return Vector4 (y, z, z, x); }
Vector4 Vector4::zzzx() const { return Vector4 (z, z, z, x); }
Vector4 Vector4::wzzx() const { return Vector4 (w, z, z, x); }
Vector4 Vector4::xwzx() const { return Vector4 (x, w, z, x); }
Vector4 Vector4::ywzx() const { return Vector4 (y, w, z, x); }
Vector4 Vector4::zwzx() const { return Vector4 (z, w, z, x); }
Vector4 Vector4::wwzx() const { return Vector4 (w, w, z, x); }
Vector4 Vector4::xxwx() const { return Vector4 (x, x, w, x); }
Vector4 Vector4::yxwx() const { return Vector4 (y, x, w, x); }
Vector4 Vector4::zxwx() const { return Vector4 (z, x, w, x); }
Vector4 Vector4::wxwx() const { return Vector4 (w, x, w, x); }
Vector4 Vector4::xywx() const { return Vector4 (x, y, w, x); }
Vector4 Vector4::yywx() const { return Vector4 (y, y, w, x); }
Vector4 Vector4::zywx() const { return Vector4 (z, y, w, x); }
Vector4 Vector4::wywx() const { return Vector4 (w, y, w, x); }
Vector4 Vector4::xzwx() const { return Vector4 (x, z, w, x); }
Vector4 Vector4::yzwx() const { return Vector4 (y, z, w, x); }
Vector4 Vector4::zzwx() const { return Vector4 (z, z, w, x); }
Vector4 Vector4::wzwx() const { return Vector4 (w, z, w, x); }
Vector4 Vector4::xwwx() const { return Vector4 (x, w, w, x); }
Vector4 Vector4::ywwx() const { return Vector4 (y, w, w, x); }
Vector4 Vector4::zwwx() const { return Vector4 (z, w, w, x); }
Vector4 Vector4::wwwx() const { return Vector4 (w, w, w, x); }
Vector4 Vector4::xxxy() const { return Vector4 (x, x, x, y); }
Vector4 Vector4::yxxy() const { return Vector4 (y, x, x, y); }
Vector4 Vector4::zxxy() const { return Vector4 (z, x, x, y); }
Vector4 Vector4::wxxy() const { return Vector4 (w, x, x, y); }
Vector4 Vector4::xyxy() const { return Vector4 (x, y, x, y); }
Vector4 Vector4::yyxy() const { return Vector4 (y, y, x, y); }
Vector4 Vector4::zyxy() const { return Vector4 (z, y, x, y); }
Vector4 Vector4::wyxy() const { return Vector4 (w, y, x, y); }
Vector4 Vector4::xzxy() const { return Vector4 (x, z, x, y); }
Vector4 Vector4::yzxy() const { return Vector4 (y, z, x, y); }
Vector4 Vector4::zzxy() const { return Vector4 (z, z, x, y); }
Vector4 Vector4::wzxy() const { return Vector4 (w, z, x, y); }
Vector4 Vector4::xwxy() const { return Vector4 (x, w, x, y); }
Vector4 Vector4::ywxy() const { return Vector4 (y, w, x, y); }
Vector4 Vector4::zwxy() const { return Vector4 (z, w, x, y); }
Vector4 Vector4::wwxy() const { return Vector4 (w, w, x, y); }
Vector4 Vector4::xxyy() const { return Vector4 (x, x, y, y); }
Vector4 Vector4::yxyy() const { return Vector4 (y, x, y, y); }
Vector4 Vector4::zxyy() const { return Vector4 (z, x, y, y); }
Vector4 Vector4::wxyy() const { return Vector4 (w, x, y, y); }
Vector4 Vector4::xyyy() const { return Vector4 (x, y, y, y); }
Vector4 Vector4::yyyy() const { return Vector4 (y, y, y, y); }
Vector4 Vector4::zyyy() const { return Vector4 (z, y, y, y); }
Vector4 Vector4::wyyy() const { return Vector4 (w, y, y, y); }
Vector4 Vector4::xzyy() const { return Vector4 (x, z, y, y); }
Vector4 Vector4::yzyy() const { return Vector4 (y, z, y, y); }
Vector4 Vector4::zzyy() const { return Vector4 (z, z, y, y); }
Vector4 Vector4::wzyy() const { return Vector4 (w, z, y, y); }
Vector4 Vector4::xwyy() const { return Vector4 (x, w, y, y); }
Vector4 Vector4::ywyy() const { return Vector4 (y, w, y, y); }
Vector4 Vector4::zwyy() const { return Vector4 (z, w, y, y); }
Vector4 Vector4::wwyy() const { return Vector4 (w, w, y, y); }
Vector4 Vector4::xxzy() const { return Vector4 (x, x, z, y); }
Vector4 Vector4::yxzy() const { return Vector4 (y, x, z, y); }
Vector4 Vector4::zxzy() const { return Vector4 (z, x, z, y); }
Vector4 Vector4::wxzy() const { return Vector4 (w, x, z, y); }
Vector4 Vector4::xyzy() const { return Vector4 (x, y, z, y); }
Vector4 Vector4::yyzy() const { return Vector4 (y, y, z, y); }
Vector4 Vector4::zyzy() const { return Vector4 (z, y, z, y); }
Vector4 Vector4::wyzy() const { return Vector4 (w, y, z, y); }
Vector4 Vector4::xzzy() const { return Vector4 (x, z, z, y); }
Vector4 Vector4::yzzy() const { return Vector4 (y, z, z, y); }
Vector4 Vector4::zzzy() const { return Vector4 (z, z, z, y); }
Vector4 Vector4::wzzy() const { return Vector4 (w, z, z, y); }
Vector4 Vector4::xwzy() const { return Vector4 (x, w, z, y); }
Vector4 Vector4::ywzy() const { return Vector4 (y, w, z, y); }
Vector4 Vector4::zwzy() const { return Vector4 (z, w, z, y); }
Vector4 Vector4::wwzy() const { return Vector4 (w, w, z, y); }
Vector4 Vector4::xxwy() const { return Vector4 (x, x, w, y); }
Vector4 Vector4::yxwy() const { return Vector4 (y, x, w, y); }
Vector4 Vector4::zxwy() const { return Vector4 (z, x, w, y); }
Vector4 Vector4::wxwy() const { return Vector4 (w, x, w, y); }
Vector4 Vector4::xywy() const { return Vector4 (x, y, w, y); }
Vector4 Vector4::yywy() const { return Vector4 (y, y, w, y); }
Vector4 Vector4::zywy() const { return Vector4 (z, y, w, y); }
Vector4 Vector4::wywy() const { return Vector4 (w, y, w, y); }
Vector4 Vector4::xzwy() const { return Vector4 (x, z, w, y); }
Vector4 Vector4::yzwy() const { return Vector4 (y, z, w, y); }
Vector4 Vector4::zzwy() const { return Vector4 (z, z, w, y); }
Vector4 Vector4::wzwy() const { return Vector4 (w, z, w, y); }
Vector4 Vector4::xwwy() const { return Vector4 (x, w, w, y); }
Vector4 Vector4::ywwy() const { return Vector4 (y, w, w, y); }
Vector4 Vector4::zwwy() const { return Vector4 (z, w, w, y); }
Vector4 Vector4::wwwy() const { return Vector4 (w, w, w, y); }
Vector4 Vector4::xxxz() const { return Vector4 (x, x, x, z); }
Vector4 Vector4::yxxz() const { return Vector4 (y, x, x, z); }
Vector4 Vector4::zxxz() const { return Vector4 (z, x, x, z); }
Vector4 Vector4::wxxz() const { return Vector4 (w, x, x, z); }
Vector4 Vector4::xyxz() const { return Vector4 (x, y, x, z); }
Vector4 Vector4::yyxz() const { return Vector4 (y, y, x, z); }
Vector4 Vector4::zyxz() const { return Vector4 (z, y, x, z); }
Vector4 Vector4::wyxz() const { return Vector4 (w, y, x, z); }
Vector4 Vector4::xzxz() const { return Vector4 (x, z, x, z); }
Vector4 Vector4::yzxz() const { return Vector4 (y, z, x, z); }
Vector4 Vector4::zzxz() const { return Vector4 (z, z, x, z); }
Vector4 Vector4::wzxz() const { return Vector4 (w, z, x, z); }
Vector4 Vector4::xwxz() const { return Vector4 (x, w, x, z); }
Vector4 Vector4::ywxz() const { return Vector4 (y, w, x, z); }
Vector4 Vector4::zwxz() const { return Vector4 (z, w, x, z); }
Vector4 Vector4::wwxz() const { return Vector4 (w, w, x, z); }
Vector4 Vector4::xxyz() const { return Vector4 (x, x, y, z); }
Vector4 Vector4::yxyz() const { return Vector4 (y, x, y, z); }
Vector4 Vector4::zxyz() const { return Vector4 (z, x, y, z); }
Vector4 Vector4::wxyz() const { return Vector4 (w, x, y, z); }
Vector4 Vector4::xyyz() const { return Vector4 (x, y, y, z); }
Vector4 Vector4::yyyz() const { return Vector4 (y, y, y, z); }
Vector4 Vector4::zyyz() const { return Vector4 (z, y, y, z); }
Vector4 Vector4::wyyz() const { return Vector4 (w, y, y, z); }
Vector4 Vector4::xzyz() const { return Vector4 (x, z, y, z); }
Vector4 Vector4::yzyz() const { return Vector4 (y, z, y, z); }
Vector4 Vector4::zzyz() const { return Vector4 (z, z, y, z); }
Vector4 Vector4::wzyz() const { return Vector4 (w, z, y, z); }
Vector4 Vector4::xwyz() const { return Vector4 (x, w, y, z); }
Vector4 Vector4::ywyz() const { return Vector4 (y, w, y, z); }
Vector4 Vector4::zwyz() const { return Vector4 (z, w, y, z); }
Vector4 Vector4::wwyz() const { return Vector4 (w, w, y, z); }
Vector4 Vector4::xxzz() const { return Vector4 (x, x, z, z); }
Vector4 Vector4::yxzz() const { return Vector4 (y, x, z, z); }
Vector4 Vector4::zxzz() const { return Vector4 (z, x, z, z); }
Vector4 Vector4::wxzz() const { return Vector4 (w, x, z, z); }
Vector4 Vector4::xyzz() const { return Vector4 (x, y, z, z); }
Vector4 Vector4::yyzz() const { return Vector4 (y, y, z, z); }
Vector4 Vector4::zyzz() const { return Vector4 (z, y, z, z); }
Vector4 Vector4::wyzz() const { return Vector4 (w, y, z, z); }
Vector4 Vector4::xzzz() const { return Vector4 (x, z, z, z); }
Vector4 Vector4::yzzz() const { return Vector4 (y, z, z, z); }
Vector4 Vector4::zzzz() const { return Vector4 (z, z, z, z); }
Vector4 Vector4::wzzz() const { return Vector4 (w, z, z, z); }
Vector4 Vector4::xwzz() const { return Vector4 (x, w, z, z); }
Vector4 Vector4::ywzz() const { return Vector4 (y, w, z, z); }
Vector4 Vector4::zwzz() const { return Vector4 (z, w, z, z); }
Vector4 Vector4::wwzz() const { return Vector4 (w, w, z, z); }
Vector4 Vector4::xxwz() const { return Vector4 (x, x, w, z); }
Vector4 Vector4::yxwz() const { return Vector4 (y, x, w, z); }
Vector4 Vector4::zxwz() const { return Vector4 (z, x, w, z); }
Vector4 Vector4::wxwz() const { return Vector4 (w, x, w, z); }
Vector4 Vector4::xywz() const { return Vector4 (x, y, w, z); }
Vector4 Vector4::yywz() const { return Vector4 (y, y, w, z); }
Vector4 Vector4::zywz() const { return Vector4 (z, y, w, z); }
Vector4 Vector4::wywz() const { return Vector4 (w, y, w, z); }
Vector4 Vector4::xzwz() const { return Vector4 (x, z, w, z); }
Vector4 Vector4::yzwz() const { return Vector4 (y, z, w, z); }
Vector4 Vector4::zzwz() const { return Vector4 (z, z, w, z); }
Vector4 Vector4::wzwz() const { return Vector4 (w, z, w, z); }
Vector4 Vector4::xwwz() const { return Vector4 (x, w, w, z); }
Vector4 Vector4::ywwz() const { return Vector4 (y, w, w, z); }
Vector4 Vector4::zwwz() const { return Vector4 (z, w, w, z); }
Vector4 Vector4::wwwz() const { return Vector4 (w, w, w, z); }
Vector4 Vector4::xxxw() const { return Vector4 (x, x, x, w); }
Vector4 Vector4::yxxw() const { return Vector4 (y, x, x, w); }
Vector4 Vector4::zxxw() const { return Vector4 (z, x, x, w); }
Vector4 Vector4::wxxw() const { return Vector4 (w, x, x, w); }
Vector4 Vector4::xyxw() const { return Vector4 (x, y, x, w); }
Vector4 Vector4::yyxw() const { return Vector4 (y, y, x, w); }
Vector4 Vector4::zyxw() const { return Vector4 (z, y, x, w); }
Vector4 Vector4::wyxw() const { return Vector4 (w, y, x, w); }
Vector4 Vector4::xzxw() const { return Vector4 (x, z, x, w); }
Vector4 Vector4::yzxw() const { return Vector4 (y, z, x, w); }
Vector4 Vector4::zzxw() const { return Vector4 (z, z, x, w); }
Vector4 Vector4::wzxw() const { return Vector4 (w, z, x, w); }
Vector4 Vector4::xwxw() const { return Vector4 (x, w, x, w); }
Vector4 Vector4::ywxw() const { return Vector4 (y, w, x, w); }
Vector4 Vector4::zwxw() const { return Vector4 (z, w, x, w); }
Vector4 Vector4::wwxw() const { return Vector4 (w, w, x, w); }
Vector4 Vector4::xxyw() const { return Vector4 (x, x, y, w); }
Vector4 Vector4::yxyw() const { return Vector4 (y, x, y, w); }
Vector4 Vector4::zxyw() const { return Vector4 (z, x, y, w); }
Vector4 Vector4::wxyw() const { return Vector4 (w, x, y, w); }
Vector4 Vector4::xyyw() const { return Vector4 (x, y, y, w); }
Vector4 Vector4::yyyw() const { return Vector4 (y, y, y, w); }
Vector4 Vector4::zyyw() const { return Vector4 (z, y, y, w); }
Vector4 Vector4::wyyw() const { return Vector4 (w, y, y, w); }
Vector4 Vector4::xzyw() const { return Vector4 (x, z, y, w); }
Vector4 Vector4::yzyw() const { return Vector4 (y, z, y, w); }
Vector4 Vector4::zzyw() const { return Vector4 (z, z, y, w); }
Vector4 Vector4::wzyw() const { return Vector4 (w, z, y, w); }
Vector4 Vector4::xwyw() const { return Vector4 (x, w, y, w); }
Vector4 Vector4::ywyw() const { return Vector4 (y, w, y, w); }
Vector4 Vector4::zwyw() const { return Vector4 (z, w, y, w); }
Vector4 Vector4::wwyw() const { return Vector4 (w, w, y, w); }
Vector4 Vector4::xxzw() const { return Vector4 (x, x, z, w); }
Vector4 Vector4::yxzw() const { return Vector4 (y, x, z, w); }
Vector4 Vector4::zxzw() const { return Vector4 (z, x, z, w); }
Vector4 Vector4::wxzw() const { return Vector4 (w, x, z, w); }
Vector4 Vector4::xyzw() const { return Vector4 (x, y, z, w); }
Vector4 Vector4::yyzw() const { return Vector4 (y, y, z, w); }
Vector4 Vector4::zyzw() const { return Vector4 (z, y, z, w); }
Vector4 Vector4::wyzw() const { return Vector4 (w, y, z, w); }
Vector4 Vector4::xzzw() const { return Vector4 (x, z, z, w); }
Vector4 Vector4::yzzw() const { return Vector4 (y, z, z, w); }
Vector4 Vector4::zzzw() const { return Vector4 (z, z, z, w); }
Vector4 Vector4::wzzw() const { return Vector4 (w, z, z, w); }
Vector4 Vector4::xwzw() const { return Vector4 (x, w, z, w); }
Vector4 Vector4::ywzw() const { return Vector4 (y, w, z, w); }
Vector4 Vector4::zwzw() const { return Vector4 (z, w, z, w); }
Vector4 Vector4::wwzw() const { return Vector4 (w, w, z, w); }
Vector4 Vector4::xxww() const { return Vector4 (x, x, w, w); }
Vector4 Vector4::yxww() const { return Vector4 (y, x, w, w); }
Vector4 Vector4::zxww() const { return Vector4 (z, x, w, w); }
Vector4 Vector4::wxww() const { return Vector4 (w, x, w, w); }
Vector4 Vector4::xyww() const { return Vector4 (x, y, w, w); }
Vector4 Vector4::yyww() const { return Vector4 (y, y, w, w); }
Vector4 Vector4::zyww() const { return Vector4 (z, y, w, w); }
Vector4 Vector4::wyww() const { return Vector4 (w, y, w, w); }
Vector4 Vector4::xzww() const { return Vector4 (x, z, w, w); }
Vector4 Vector4::yzww() const { return Vector4 (y, z, w, w); }
Vector4 Vector4::zzww() const { return Vector4 (z, z, w, w); }
Vector4 Vector4::wzww() const { return Vector4 (w, z, w, w); }
Vector4 Vector4::xwww() const { return Vector4 (x, w, w, w); }
Vector4 Vector4::ywww() const { return Vector4 (y, w, w, w); }
Vector4 Vector4::zwww() const { return Vector4 (z, w, w, w); }
Vector4 Vector4::wwww() const { return Vector4 (w, w, w, w); }
}; // namespace
-58
View File
@@ -1,58 +0,0 @@
/**
@file Vector4int8.cpp
Homogeneous vector class.
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2007-02-09
@edited 2007-02-09
Copyright 2000-2007, Morgan McGuire.
All rights reserved.
*/
#include "G3D/platform.h"
#include "G3D/Vector4int8.h"
#include "G3D/Vector3.h"
#include "G3D/Vector4.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include <string>
namespace G3D {
Vector4int8::Vector4int8(const Vector4& source) {
x = iClamp(iRound(source.x), -128, 127);
y = iClamp(iRound(source.y), -128, 127);
z = iClamp(iRound(source.z), -128, 127);
w = iClamp(iRound(source.w), -128, 127);
}
Vector4int8::Vector4int8(const Vector3& source, int8 w) : w(w) {
x = iClamp(iRound(source.x), -128, 127);
y = iClamp(iRound(source.y), -128, 127);
z = iClamp(iRound(source.z), -128, 127);
}
Vector4int8::Vector4int8(class BinaryInput& b) {
deserialize(b);
}
void Vector4int8::serialize(class BinaryOutput& b) const {
// Intentionally write individual bytes to avoid endian issues
b.writeInt8(x);
b.writeInt8(y);
b.writeInt8(z);
b.writeInt8(w);
}
void Vector4int8::deserialize(class BinaryInput& b) {
x = b.readInt8();
y = b.readInt8();
z = b.readInt8();
w = b.readInt8();
}
} // namespace G3D
-155
View File
@@ -1,155 +0,0 @@
/*
Dervied from SDL_main.c, which was placed in the public domain by Sam Lantinga 4/13/98
The WinMain function -- calls your program's main() function
*/
#include "G3D/platform.h"
#ifdef G3D_WIN32
#include <stdio.h>
#include <stdlib.h>
#include <cctype>
#ifdef main
# ifndef _WIN32_WCE_EMULATION
# undef main
# endif /* _WIN32_WCE_EMULATION */
#endif /* main */
#if defined(_WIN32_WCE) && _WIN32_WCE < 300
/* seems to be undefined in Win CE although in online help */
#define isspace(a) (((CHAR)a == ' ') || ((CHAR)a == '\t'))
#endif /* _WIN32_WCE < 300 */
// Turn off the G3D for loop scoping for C++
#ifdef for
# undef for
#endif
extern int main(int argc, const char** argv);
/* Parse a command line buffer into arguments */
static int ParseCommandLine(char *cmdline, char **argv) {
char *bufp;
int argc;
argc = 0;
for (bufp = cmdline; *bufp;) {
/* Skip leading whitespace */
while (isspace(*bufp)) {
++bufp;
}
/* Skip over argument */
if (*bufp == '"') {
++bufp;
if (*bufp) {
if (argv) {
argv[argc] = bufp;
}
++argc;
}
/* Skip over word */
while (*bufp && (*bufp != '"')) {
++bufp;
}
} else {
if (*bufp) {
if (argv) {
argv[argc] = bufp;
}
++argc;
}
/* Skip over word */
while (*bufp && !isspace(*bufp)) {
++bufp;
}
}
if (*bufp) {
if (argv) {
*bufp = '\0';
}
++bufp;
}
}
if (argv) {
argv[argc] = NULL;
}
return (argc);
}
/* Show an error message */
static void ShowError(const char *title, const char *message) {
/* If USE_MESSAGEBOX is defined, you need to link with user32.lib */
#ifdef USE_MESSAGEBOX
MessageBox(NULL, message, title, MB_ICONEXCLAMATION | MB_OK);
#else
fprintf(stderr, "%s: %s\n", title, message);
#endif
}
/* Pop up an out of memory message, returns to Windows */
static BOOL OutOfMemory(void) {
ShowError("Fatal Error", "Out of memory - aborting");
return FALSE;
}
int WINAPI G3D_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {
char **argv;
int argc;
int status;
char *cmdline;
# ifdef _WIN32_WCE
wchar_t *bufp;
int nLen;
# else
char *bufp;
size_t nLen;
# endif
#ifdef _WIN32_WCE
#error WinCE not supported
/*
nLen = wcslen(szCmdLine) + 128 + 1;
bufp = SDL_stack_alloc(wchar_t, nLen * 2);
wcscpy(bufp, TEXT("\""));
GetModuleFileName(NULL, bufp + 1, 128 - 3);
wcscpy(bufp + wcslen(bufp), TEXT("\" "));
wcsncpy(bufp + wcslen(bufp), szCmdLine, nLen - wcslen(bufp));
nLen = wcslen(bufp) + 1;
cmdline = SDL_stack_alloc(char, nLen);
if (cmdline == NULL) {
return OutOfMemory();
}
WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL);
*/
#else
/* Grab the command line */
bufp = GetCommandLineA();
nLen = strlen(bufp) + 1;
cmdline = (char*)malloc(sizeof(char) * nLen);
if (cmdline == NULL) {
return OutOfMemory();
}
strncpy(cmdline, bufp, nLen);
#endif
/* Parse it into argv and argc */
argc = ParseCommandLine(cmdline, NULL);
argv = (char**)malloc(sizeof(char*) * (argc + 1));
if (argv == NULL) {
return OutOfMemory();
}
ParseCommandLine(cmdline, argv);
/* Run the main program */
status = main(argc, (const char**)argv);
free(argv);
free(cmdline);
return status;
}
#endif // if Win32
-392
View File
@@ -1,392 +0,0 @@
/**
@file debugAssert.cpp
Windows implementation of assertion routines.
@maintainer Morgan McGuire, graphics3d.com
@created 2001-08-26
@edited 2006-02-02
*/
#include "G3D/debugAssert.h"
#include "G3D/platform.h"
#ifdef G3D_WIN32
#include <tchar.h>
#endif
#include "G3D/format.h"
#include "G3D/prompt.h"
#include <string>
#include "G3D/debugPrintf.h"
#include "G3D/Log.h"
#include <cstdlib>
#ifdef _MSC_VER
// disable: "C++ exception handler used"
# pragma warning (push)
# pragma warning (disable : 4530)
#endif
using namespace std;
namespace G3D { namespace _internal {
ConsolePrintHook _consolePrintHook;
AssertionHook _debugHook = _handleDebugAssert_;
AssertionHook _failureHook = _handleErrorCheck_;
#ifdef G3D_LINUX
Display* x11Display = NULL;
Window x11Window = 0;
#endif
#ifdef G3D_WIN32
static void postToClipboard(const char *text) {
if (OpenClipboard(NULL)) {
HGLOBAL hMem = GlobalAlloc(GHND | GMEM_DDESHARE, strlen(text) + 1);
if (hMem) {
char *pMem = (char*)GlobalLock(hMem);
strcpy(pMem, text);
GlobalUnlock(hMem);
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
}
CloseClipboard();
GlobalFree(hMem);
}
}
#endif
/**
outTitle should be set before the call
*/
static void createErrorMessage(
const char* expression,
const std::string& message,
const char* filename,
int lineNumber,
std::string& outTitle,
std::string& outMessage) {
std::string le = "";
const char* newline = "\n";
#ifdef G3D_WIN32
newline = "\r\n";
// The last error value. (Which is preserved across the call).
DWORD lastErr = GetLastError();
// The decoded message from FormatMessage
LPTSTR formatMsg = NULL;
if (NULL == formatMsg) {
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
lastErr,
0,
(LPTSTR)&formatMsg,
0,
NULL);
}
// Make sure the message got translated into something.
LPTSTR realLastErr;
if (NULL != formatMsg) {
realLastErr = formatMsg;
} else {
realLastErr = _T("Last error code does not exist.");
}
if (lastErr != 0) {
le = G3D::format("Last Error (0x%08X): %s\r\n\r\n", lastErr, (LPCSTR)realLastErr);
}
// Get rid of the allocated memory from FormatMessage.
if (NULL != formatMsg) {
LocalFree((LPVOID)formatMsg);
}
char modulePath[MAX_PATH];
GetModuleFileNameA(NULL, modulePath, MAX_PATH);
const char* moduleName = strrchr(modulePath, '\\');
outTitle = outTitle + string(" - ") + string(moduleName ? (moduleName + 1) : modulePath);
#endif
// Build the message.
outMessage =
G3D::format("%s%s%sExpression: %s%s%s:%d%s%s%s",
message.c_str(), newline, newline, expression, newline,
filename, lineNumber, newline, newline, le.c_str());
}
bool _handleDebugAssert_(
const char* expression,
const std::string& message,
const char* filename,
int lineNumber,
bool& ignoreAlways,
bool useGuiPrompt) {
std::string dialogTitle = "Assertion Failure";
std::string dialogText = "";
createErrorMessage(expression, message, filename, lineNumber, dialogTitle, dialogText);
#ifdef G3D_WIN32
DWORD lastErr = GetLastError();
postToClipboard(dialogText.c_str());
debugPrintf("\n%s\n", dialogText.c_str());
#endif
const int cBreak = 0;
const int cIgnore = 1;
const int cIgnoreAlways = 2;
const int cAbort = 3;
static const char* choices[] = {"Debug", "Ignore", "Ignore Always", "Exit"};
// Log the error
Log::common()->print(std::string("\n**************************\n\n") + dialogTitle + "\n" + dialogText);
int result = G3D::prompt(dialogTitle.c_str(), dialogText.c_str(), (const char**)choices, 4, useGuiPrompt);
# ifdef G3D_WIN32
// Put the incoming last error back.
SetLastError(lastErr);
# endif
switch (result) {
// -1 shouldn't actually occur because it means
// that we're in release mode.
case -1:
case cBreak:
return true;
break;
case cIgnore:
return false;
break;
case cIgnoreAlways:
ignoreAlways = true;
return false;
break;
case cAbort:
exit(-1);
break;
}
// Should never get here
return false;
}
bool _handleErrorCheck_(
const char* expression,
const std::string& message,
const char* filename,
int lineNumber,
bool& ignoreAlways,
bool useGuiPrompt) {
(void)ignoreAlways;
std::string dialogTitle = "Critical Error";
std::string dialogText = "";
createErrorMessage(expression, message, filename, lineNumber, dialogTitle, dialogText);
// Log the error
Log::common()->print(std::string("\n**************************\n\n") + dialogTitle + "\n" + dialogText);
#ifdef G3D_WIN32
DWORD lastErr = GetLastError();
postToClipboard(dialogText.c_str());
debugPrintf("\n%s\n", dialogText.c_str());
#endif
static const char* choices[] = {"Ok"};
std::string m =
std::string("An internal error has occured in your program and it will now close. Details about the error have been reported in \"") +
Log::getCommonLogFilename() + "\".";
int result = G3D::prompt("Error", m.c_str(), (const char**)choices, 1, useGuiPrompt);
(void)result;
return true;
}
#ifdef G3D_WIN32
static HCURSOR oldCursor;
static RECT oldCursorRect;
static POINT oldCursorPos;
static int oldShowCursorCount;
#endif
void _releaseInputGrab_() {
#ifdef G3D_WIN32
GetCursorPos(&oldCursorPos);
// Stop hiding the cursor if the application hid it.
oldShowCursorCount = ShowCursor(true) - 1;
if (oldShowCursorCount < -1) {
for (int c = oldShowCursorCount; c < -1; ++c) {
ShowCursor(true);
}
}
// Set the default cursor in case the application
// set the cursor to NULL.
oldCursor = GetCursor();
SetCursor(LoadCursor(NULL, IDC_ARROW));
// Allow the cursor full access to the screen
GetClipCursor(&oldCursorRect);
ClipCursor(NULL);
#elif defined(G3D_LINUX)
if (x11Display != NULL) {
XUngrabPointer(x11Display, CurrentTime);
XUngrabKeyboard(x11Display, CurrentTime);
if (x11Window != 0) {
//XUndefineCursor(x11Display, x11Window);
// TODO: Note that we leak this cursor; it should be
// freed in the restore code.
Cursor c = XCreateFontCursor(x11Display, 68);
XDefineCursor(x11Display, x11Window, c);
}
XSync(x11Display, false);
XAllowEvents(x11Display, AsyncPointer, CurrentTime);
XFlush(x11Display);
}
#elif defined(G3D_OSX)
// TODO: OS X
#endif
}
void _restoreInputGrab_() {
#ifdef G3D_WIN32
// Restore the old clipping region
ClipCursor(&oldCursorRect);
SetCursorPos(oldCursorPos.x, oldCursorPos.y);
// Restore the old cursor
SetCursor(oldCursor);
// Restore old visibility count
if (oldShowCursorCount < 0) {
for (int c = 0; c > oldShowCursorCount; --c) {
ShowCursor(false);
}
}
#elif defined(G3D_LINUX)
// TODO: Linux
#elif defined(G3D_OSX)
// TODO: OS X
#endif
}
}; // internal namespace
void setAssertionHook(AssertionHook hook) {
G3D::_internal::_debugHook = hook;
}
AssertionHook assertionHook() {
return G3D::_internal::_debugHook;
}
void setFailureHook(AssertionHook hook) {
G3D::_internal::_failureHook = hook;
}
AssertionHook failureHook() {
return G3D::_internal::_failureHook;
}
void setConsolePrintHook(ConsolePrintHook h) {
G3D::_internal::_consolePrintHook = h;
}
ConsolePrintHook consolePrintHook() {
return G3D::_internal::_consolePrintHook;
}
std::string __cdecl debugPrint(const std::string& s) {
# ifdef G3D_WIN32
const int MAX_STRING_LEN = 1024;
// Windows can't handle really long strings sent to
// the console, so we break the string.
if (s.size() < MAX_STRING_LEN) {
OutputDebugStringA(s.c_str());
} else {
for (unsigned int i = 0; i < s.size(); i += MAX_STRING_LEN) {
std::string sub = s.substr(i, MAX_STRING_LEN);
OutputDebugStringA(sub.c_str());
}
}
# else
fprintf(stderr, "%s", s.c_str());
fflush(stderr);
# endif
return s;
}
std::string __cdecl debugPrintf(const char* fmt ...) {
va_list argList;
va_start(argList, fmt);
std::string s = G3D::vformat(fmt, argList);
va_end(argList);
return debugPrint(consolePrint(s));
}
std::string consolePrint(const std::string& s) {
FILE* L = Log::common()->getFile();
fprintf(L, "%s", s.c_str());
if (consolePrintHook()) {
consolePrintHook()(s);
}
fflush(L);
return s;
}
std::string __cdecl consolePrintf(const char* fmt ...) {
va_list argList;
va_start(argList, fmt);
std::string s = G3D::vformat(fmt, argList);
va_end(argList);
return consolePrint(s);
}
} // namespace
#ifdef _MSC_VER
# pragma warning (pop)
#endif
File diff suppressed because it is too large Load Diff
-32
View File
@@ -1,32 +0,0 @@
/**
@file filter.cpp
@author Morgan McGuire, matrix@graphics3d.com
@created 2007-03-01
@edited 2007-03-01
Copyright 2000-2007, Morgan McGuire.
All rights reserved.
*/
#include "G3D/filter.h"
namespace G3D {
void gaussian1D(Array<float>& coeff, int N, float std) {
coeff.resize(N);
float sum = 0.0f;
for (int i = 0; i < N; ++i) {
float x = i - (N - 1) / 2.0f;
float p = -square(x / std) / 2.0f;
float y = exp(p);
coeff[i] = y;
sum += y;
}
for (int i = 0; i < N; ++i) {
coeff[i] /= sum;
}
}
} // namespace
-164
View File
@@ -1,164 +0,0 @@
/**
@file format.cpp
@author Morgan McGuire, graphics3d.com
@created 2000-09-09
@edited 2006-08-14
*/
#include "G3D/format.h"
#include "G3D/platform.h"
#include "G3D/System.h"
#ifdef _MSC_VER
// disable: "C++ exception handler used"
# pragma warning (push)
# pragma warning (disable : 4530)
#endif // _MSC_VER
// If your platform does not have vsnprintf, you can find a
// implementation at http://www.ijs.si/software/snprintf/
namespace G3D {
std::string __cdecl format(const char* fmt,...) {
va_list argList;
va_start(argList,fmt);
std::string result = vformat(fmt, argList);
va_end(argList);
return result;
}
#if defined(_MSC_VER) && (_MSC_VER >= 1300)
// Both MSVC seems to use the non-standard vsnprintf
// so we are using vscprintf to determine buffer size, however
// only MSVC7 and up headers include vscprintf for some reason.
std::string vformat(const char *fmt, va_list argPtr) {
// We draw the line at a 1MB string.
const int maxSize = 1000000;
// If the string is less than 161 characters,
// allocate it on the stack because this saves
// the malloc/free time.
const int bufSize = 161;
char stackBuffer[bufSize];
// MSVC does not support va_copy
int actualSize = _vscprintf(fmt, argPtr) + 1;
if (actualSize > bufSize) {
// Now use the heap.
char* heapBuffer = NULL;
if (actualSize < maxSize) {
heapBuffer = (char*)System::malloc(maxSize + 1);
_vsnprintf(heapBuffer, maxSize, fmt, argPtr);
heapBuffer[maxSize] = '\0';
} else {
heapBuffer = (char*)System::malloc(actualSize);
vsprintf(heapBuffer, fmt, argPtr);
}
std::string formattedString(heapBuffer);
System::free(heapBuffer);
return formattedString;
} else {
vsprintf(stackBuffer, fmt, argPtr);
return std::string(stackBuffer);
}
}
#elif defined(_MSC_VER) && (_MSC_VER < 1300)
std::string vformat(const char *fmt, va_list argPtr) {
// We draw the line at a 1MB string.
const int maxSize = 1000000;
// If the string is less than 161 characters,
// allocate it on the stack because this saves
// the malloc/free time.
const int bufSize = 161;
char stackBuffer[bufSize];
// MSVC6 doesn't support va_copy, however it also seems to compile
// correctly if we just pass our argument list along. Note that
// this whole code block is only compiled if we're on MSVC6 anyway
int actualWritten = _vsnprintf(stackBuffer, bufSize, fmt, argPtr);
// Not a big enough buffer, bufSize characters written
if (actualWritten == -1) {
int heapSize = 512;
double powSize = 1.0;
char* heapBuffer = (char*)System::malloc(heapSize);
while ((_vsnprintf(heapBuffer, heapSize, fmt, argPtr) == -1) &&
(heapSize < maxSize)) {
heapSize = iCeil(heapSize * ::pow((double)2.0, powSize++));
heapBuffer = (char*)System::realloc(heapBuffer, heapSize);
}
heapBuffer[heapSize-1] = '\0';
std::string heapString(heapBuffer);
System::free(heapBuffer);
return heapString;
} else {
return std::string(stackBuffer);
}
}
#else
// glibc 2.1 has been updated to the C99 standard
std::string vformat(const char* fmt, va_list argPtr) {
// If the string is less than 161 characters,
// allocate it on the stack because this saves
// the malloc/free time. The number 161 is chosen
// to support two lines of text on an 80 character
// console (plus the null terminator).
const int bufSize = 161;
char stackBuffer[bufSize];
va_list argPtrCopy;
va_copy(argPtrCopy, argPtr);
int numChars = vsnprintf(stackBuffer, bufSize, fmt, argPtrCopy);
va_end(argPtrCopy);
if (numChars >= bufSize) {
// We didn't allocate a big enough string.
char* heapBuffer = (char*)System::malloc((numChars + 1) * sizeof(char));
debugAssert(heapBuffer);
int numChars2 = vsnprintf(heapBuffer, numChars + 1, fmt, argPtr);
debugAssert(numChars2 == numChars);
(void)numChars2;
std::string result(heapBuffer);
System::free(heapBuffer);
return result;
} else {
return std::string(stackBuffer);
}
}
#endif
} // namespace
#ifdef _MSC_VER
# pragma warning (pop)
#endif
-70
View File
@@ -1,70 +0,0 @@
/**
@file g3dmath.cpp
@author Morgan McGuire, graphics3d.com
@created 2001-06-02
@edited 2004-02-24
*/
#include "G3D/g3dmath.h"
#include <stdlib.h>
namespace G3D {
float gaussRandom(float mean, float stdev) {
// Using Box-Mueller method from http://www.taygeta.com/random/gaussian.html
// Modified to specify standard deviation and mean of distribution
float w, x1, x2;
// Loop until w is less than 1 so that log(w) is negative
do {
x1 = uniformRandom(-1.0, 1.0);
x2 = uniformRandom(-1.0, 1.0);
w = float(square(x1) + square(x2));
} while (w > 1.0f);
// Transform to gassian distribution
// Multiply by sigma (stdev ^ 2) and add mean.
return x2 * (float)square(stdev) * sqrtf((-2.0f * logf(w) ) / w) + mean;
}
int highestBit(uint32 x) {
// Binary search.
int base = 0;
if (x & 0xffff0000) {
base = 16;
x >>= 16;
}
if (x & 0x0000ff00) {
base += 8;
x >>= 8;
}
if (x & 0x000000f0) {
base += 4;
x >>= 4;
}
static const int lut[] = {-1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3};
return base + lut[x];
}
int iRandom(int low, int high) {
int r = iFloor(low + (high - low + 1) * (double)rand() / RAND_MAX);
// There is a *very small* chance of generating
// a number larger than high.
if (r > high) {
return high;
} else {
return r;
}
}
}
-70
View File
@@ -1,70 +0,0 @@
/**
@file license.cpp
@author Morgan McGuire, graphics3d.com
@created 2004-04-15
@edited 2004-04-15
*/
#include "G3D/format.h"
#include <string>
namespace G3D {
std::string license() {
return format(
"This software is based in part on the PNG Reference Library which is\n"
"Copyright (c) 2004 Glenn Randers-Pehrson\n\n"
"This software is based in part on the work of the Independent JPEG Group.\n\n"
"This software is based on part on the FFmpeg libavformat and libavcodec libraries\n"
"(\"FFmpeg\", http://ffmpeg.mplayerhq.hu), which are included under the terms of the\n"
"GNU Lesser General Public License (LGPL), (http://www.gnu.org/copyleft/lesser.html).\n\n"
"%s"
"This program uses the G3D Library (http://g3d-cpp.sf.net), which\n"
"is licensed under the \"BSD\" Open Source license. The Graphics3D library\n"
"source code is Copyright © 2000-2008, Morgan McGuire, All rights reserved.\n"
"The BSD license requires the following statement regarding G3D:\n"
"\n"
"Redistribution and use in source and binary forms, with or without\n"
"modification, are permitted provided that the following conditions\n"
"are met:\n"
"\n"
"Redistributions of source code must retain the above copyright\n"
"notice, this list of conditions and the following disclaimer.\n"
"\n"
"Redistributions in binary form must reproduce the above copyright\n"
"notice, this list of conditions and the following disclaimer in the\n"
"documentation and/or other materials provided with the distribution.\n"
"\n"
"Neither the name of Morgan McGuire, Brown University, Williams College, nor the names\n"
"of the G3D contributors may be used to endorse or promote products derived\n"
"from this software without specific prior written permission.\n"
"\n"
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n\n"
"G3D VERSION %d\n",
#ifdef G3D_WIN32
"" // Win32 doesn't use SDL
#else
"This software uses the Simple DirectMedia Layer library (\"SDL\",\n"
"http://www.libsdl.org), which is included under the terms of the\n"
"GNU Lesser General Public License, (http://www.gnu.org/copyleft/lesser.html).\n\n"
#endif
,
G3D_VER);
}
}
-716
View File
@@ -1,716 +0,0 @@
/**
@file prompt.cpp
@author Morgan McGuire, morgan@graphics3d.com
@cite Windows dialog interface by Max McGuire, mmcguire@ironlore.com
@cite Font setting code by Kurt Miller, kurt@flipcode.com
@created 2000-08-26
@edited 2005-01-14
*/
#include "G3D/prompt.h"
#include "G3D/platform.h"
#include <stdio.h>
#ifdef G3D_WIN32
# include <sstream>
# include <conio.h>
#else
# define _getch getchar
#endif
#ifdef G3D_OSX
# include <Carbon/Carbon.h>
#endif
namespace G3D {
#ifdef G3D_WIN32
namespace _internal {
/**
Generic Win32 dialog facility.
@author Max McGuire
*/
class DialogTemplate {
public:
DialogTemplate(LPCSTR caption, DWORD style,
int x, int y, int w, int h,
LPCSTR font = NULL, WORD fontSize = 8) {
usedBufferLength = sizeof(DLGTEMPLATE);
totalBufferLength = usedBufferLength;
dialogTemplate = (DLGTEMPLATE*)malloc(totalBufferLength);
dialogTemplate->style = style;
if (font != NULL) {
dialogTemplate->style |= DS_SETFONT;
}
dialogTemplate->x = (short)x;
dialogTemplate->y = (short)y;
dialogTemplate->cx = (short)w;
dialogTemplate->cy = (short)h;
dialogTemplate->cdit = 0;
dialogTemplate->dwExtendedStyle = 0;
// The dialog box doesn't have a menu or a special class
AppendData("\0", 2);
AppendData("\0", 2);
// Add the dialog's caption to the template
AppendString(caption);
if (font != NULL) {
AppendData(&fontSize, sizeof(WORD));
AppendString(font);
}
}
void AddComponent(LPCSTR type, LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
DLGITEMTEMPLATE item;
item.style = style;
item.x = (short)x;
item.y = (short)y;
item.cx = (short)w;
item.cy = (short)h;
item.id = id;
item.dwExtendedStyle = exStyle;
AppendData(&item, sizeof(DLGITEMTEMPLATE));
AppendString(type);
AppendString(caption);
WORD creationDataLength = 0;
AppendData(&creationDataLength, sizeof(WORD));
// Increment the component count
dialogTemplate->cdit++;
}
void AddButton(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
AddStandardComponent(0x0080, caption, style, exStyle, x, y, w, h, id);
WORD creationDataLength = 0;
AppendData(&creationDataLength, sizeof(WORD));
}
void AddEditBox(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
AddStandardComponent(0x0081, caption, style, exStyle, x, y, w, h, id);
WORD creationDataLength = 0;
AppendData(&creationDataLength, sizeof(WORD));
}
void AddStatic(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
AddStandardComponent(0x0082, caption, style, exStyle, x, y, w, h, id);
WORD creationDataLength = 0;
AppendData(&creationDataLength, sizeof(WORD));
}
void AddListBox(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
AddStandardComponent(0x0083, caption, style, exStyle, x, y, w, h, id);
WORD creationDataLength = sizeof(WORD) + 5 * sizeof(WCHAR);
AppendData(&creationDataLength, sizeof(WORD));
AppendString("TEST");
}
void AddScrollBar(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
AddStandardComponent(0x0084, caption, style, exStyle, x, y, w, h, id);
WORD creationDataLength = 0;
AppendData(&creationDataLength, sizeof(WORD));
}
void AddComboBox(LPCSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, WORD id) {
AddStandardComponent(0x0085, caption, style, exStyle, x, y, w, h, id);
WORD creationDataLength = 0;
AppendData(&creationDataLength, sizeof(WORD));
}
/**
*
* Returns a pointer to the Win32 dialog template which the object
* represents. This pointer may become invalid if additional components
* are added to the template.
*
*/
operator const DLGTEMPLATE*() const {
return dialogTemplate;
}
virtual ~DialogTemplate() {
free(dialogTemplate);
}
protected:
void AddStandardComponent(WORD type, LPCSTR caption, DWORD style, DWORD exStyle,
int x, int y, int w, int h, WORD id, LPSTR font = NULL, WORD fontSize = 8) {
DLGITEMTEMPLATE item;
// DWORD align the beginning of the component data
AlignData(sizeof(DWORD));
item.style = style;
if (font != NULL) {
item.style |= DS_SETFONT;
}
item.x = (short)x;
item.y = (short)y;
item.cx = (short)w;
item.cy = (short)h;
item.id = id;
item.dwExtendedStyle = exStyle;
AppendData(&item, sizeof(DLGITEMTEMPLATE));
WORD preType = 0xFFFF;
AppendData(&preType, sizeof(WORD));
AppendData(&type, sizeof(WORD));
AppendString(caption);
if (font != NULL) {
AppendData(&fontSize, sizeof(WORD));
AppendString(font);
}
// Increment the component count
dialogTemplate->cdit++;
}
void AlignData(int size) {
int paddingSize = usedBufferLength % size;
if (paddingSize != 0) {
EnsureSpace(paddingSize);
usedBufferLength += paddingSize;
}
}
void AppendString(LPCSTR string) {
int length = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0);
WCHAR* wideString = (WCHAR*)malloc(sizeof(WCHAR) * length);
MultiByteToWideChar(CP_ACP, 0, string, -1, wideString, length);
AppendData(wideString, length * sizeof(WCHAR));
free(wideString);
}
void AppendData(const void* data, int dataLength) {
EnsureSpace(dataLength);
memcpy((char*)dialogTemplate + usedBufferLength, data, dataLength);
usedBufferLength += dataLength;
}
void EnsureSpace(int length) {
if (length + usedBufferLength > totalBufferLength) {
totalBufferLength += length * 2;
void* newBuffer = malloc(totalBufferLength);
memcpy(newBuffer, dialogTemplate, usedBufferLength);
free(dialogTemplate);
dialogTemplate = (DLGTEMPLATE*)newBuffer;
}
}
private:
DLGTEMPLATE* dialogTemplate;
int totalBufferLength;
int usedBufferLength;
};
struct PromptParams {
const char* message;
const char* title;
};
/**
* Constants for controls.
*/
#define IDC_MESSAGE 1000
#define IDC_BUTTON0 2000
INT_PTR CALLBACK PromptDlgProc(HWND hDlg, UINT msg,
WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_INITDIALOG:
{
PromptParams *params = (PromptParams*)lParam;
::SetWindowTextA(::GetDlgItem(hDlg, IDC_MESSAGE), params->message);
::SetFocus(::GetDlgItem(hDlg, IDC_BUTTON0));
SetWindowTextA(hDlg, params->title);
HFONT hfont =
CreateFontA(16, 0, 0, 0, FW_NORMAL,
FALSE, FALSE, FALSE,
ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
PROOF_QUALITY, FIXED_PITCH | FF_MODERN, "Courier New");
SendDlgItemMessage(hDlg, IDC_MESSAGE, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE,0));
break;
}
case WM_COMMAND:
{
int choiceNumber = LOWORD(wParam) - IDC_BUTTON0;
if ((choiceNumber >= 0) && (choiceNumber < 10)) {
EndDialog(hDlg, choiceNumber);
return TRUE;
}
}
break;
case WM_NCDESTROY:
// Under SDL 1.2.6 we get a NCDESTROY message for no reason and the
// window is immediately closed. This is here to debug the problem.
(void)0;
break;
}
return FALSE;
}
}; // namespace _internal
using namespace _internal;
/**
* Show a dialog prompt.
*/
static int guiPrompt(
const char* windowTitle,
const char* prompt,
const char** choice,
int numChoices) {
int width = 280;
int height = 128;
const int buttonSpacing = 2;
const int buttonWidth =
(width - buttonSpacing * 2 -
buttonSpacing * (numChoices - 1)) / numChoices;
const int buttonHeight = 13;
DialogTemplate dialogTemplate(
windowTitle,
WS_CAPTION | DS_CENTER | WS_SYSMENU,
10, 10, width, height,
"Tahoma");
dialogTemplate.AddEditBox(
"Edit", WS_VISIBLE | ES_READONLY | ES_OEMCONVERT | ES_MULTILINE | WS_TABSTOP, WS_EX_STATICEDGE,
2, 2, width - 4, height - buttonHeight - 7, IDC_MESSAGE);
int i;
for (i = 0; i < numChoices; i++) {
int x = buttonSpacing + i * (buttonWidth + buttonSpacing);
int y = height - buttonHeight - buttonSpacing;
dialogTemplate.AddButton(choice[i], WS_VISIBLE | WS_TABSTOP, 0,
x, y, buttonWidth, buttonHeight, IDC_BUTTON0 + (WORD)i);
}
// Convert all single \n characters to \r\n for proper printing
int strLen = 0;
const char* pStr = prompt;
while (*pStr != '\0') {
if ((*pStr == '\n') && (pStr != prompt)) {
if (*(pStr - 1) != '\r') {
++strLen;
}
}
++strLen;
++pStr;
}
char* newStr = (char*)malloc(strLen + 1);
const char* pStr2 = prompt;
char* pNew = newStr;
while (*pStr2 != '\0') {
if ((*pStr2 == '\n') && (pStr2 != prompt)) {
if (*(pStr2 - 1) != '\r') {
*pNew = '\r';
++pNew;
}
}
*pNew = *pStr2;
++pNew;
++pStr2;
}
*pNew = '\0';
PromptParams params;
params.message = newStr;;
params.title = windowTitle;
HMODULE module = GetModuleHandle(0);
int ret = DialogBoxIndirectParam(module, dialogTemplate, NULL, (DLGPROC) PromptDlgProc, (DWORD)&params);
free(newStr);
/*
For debugging when DialogBoxIndirectParam fails:
// The last error value. (Which is preserved across the call).
DWORD lastErr = GetLastError();
// The decoded message from FormatMessage
LPTSTR formatMsg = NULL;
if (NULL == formatMsg) {
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
lastErr,
0,
(LPTSTR)&formatMsg,
0,
NULL);
}
// Make sure the message got translated into something.
LPTSTR realLastErr;
if (NULL != formatMsg) {
realLastErr = formatMsg;
} else {
realLastErr = "Last error code does not exist.";
}
// Get rid of the allocated memory from FormatMessage.
if (NULL != formatMsg) {
LocalFree((LPVOID)formatMsg);
}
*/
return ret;
}
#endif
/**
* Show a prompt on stdout
*/
static int textPrompt(
const char* windowTitle,
const char* prompt,
const char** choice,
int numChoices) {
printf("\n___________________________________________________\n");
printf("%s\n", windowTitle);
printf("%s", prompt);
if (numChoices > 10) {
numChoices = 10;
}
int c = -1;
if (numChoices > 1) {
printf("\n");
printf("Choose an option by number:");
while ((c < 0) || (c >= numChoices)) {
printf("\n");
for (int i = 0; i < numChoices; i++) {
if (numChoices <= 3) {
printf(" (%d) %s ", i, choice[i]);
} else {
printf(" (%d) %s\n", i, choice[i]);
}
}
printf("\n> ");
c = _getch() - '0';
if ((c < 0) || (c >= numChoices)) {
printf("'%d' is not a valid choice.", c);
} else {
printf("%d", c);
}
}
} else if (numChoices == 1) {
printf("\nPress any key for '%s'...", choice[0]);
_getch();
c = 0;
} else {
printf("\nPress any key...");
_getch();
c = 0;
}
printf("\n___________________________________________________\n");
return c;
}
#ifdef G3D_OSX
// See http://developer.apple.com/documentation/Carbon/Reference/Carbon_Event_Manager_Ref/index.html
#define CARBON_COMMANDID_START 128
#define CARBON_BUTTON_SPACING 12
#define CARBON_BUTTON_HEIGHT 20
#define CARBON_BUTTON_MINWIDTH 69
#define CARBON_WINDOW_PADDING 20
struct CallbackData {
WindowRef refWindow;
/** Index of this particular button */
int myIndex;
/** Buttons store their index into here when pressed. */
int* whichButton;
};
/**
Assumes that userData is a pointer to a carbon_evt_data_t.
*/
static pascal OSStatus DoCommandEvent(EventHandlerCallRef handlerRef, EventRef event, void* userData) {
// See http://developer.apple.com/documentation/Carbon/Conceptual/HandlingWindowsControls/index.html
CallbackData& callbackData = *(CallbackData*)userData;
# pragma unused(handlerRef)
callbackData.whichButton[0] = callbackData.myIndex;
// If we get here we can close the window
QuitAppModalLoopForWindow(callbackData.refWindow);
// Return noErr to indicate that we handled the event
return noErr;
}
static int guiPrompt
(const char* windowTitle,
const char* prompt,
const char** choice,
int numChoices) {
WindowRef window;
int iNumButtonRows = 0;
int iButtonWidth = -1;
OSStatus err = noErr;
// Determine number of rows of buttons
while (iButtonWidth < CARBON_BUTTON_MINWIDTH) {
++iNumButtonRows;
iButtonWidth =
(550 - (CARBON_WINDOW_PADDING*2 +
(CARBON_BUTTON_SPACING*numChoices))) /
(numChoices/iNumButtonRows);
}
// Window Variables
Rect rectWin = {0, 0, 200 + ((iNumButtonRows-1) * (CARBON_BUTTON_HEIGHT+CARBON_BUTTON_SPACING)), 550}; // top, left, bottom, right
CFStringRef szWindowTitle = CFStringCreateWithCString(kCFAllocatorDefault, windowTitle, kCFStringEncodingUTF8);
window = NULL;
err = CreateNewWindow(kMovableAlertWindowClass, kWindowStandardHandlerAttribute|kWindowCompositingAttribute, &rectWin, &window);
err = SetWindowTitleWithCFString(window, szWindowTitle);
err = SetThemeWindowBackground(window, kThemeBrushAlertBackgroundActive, false);
assert(err == noErr);
// Event Handler Variables
EventTypeSpec buttonSpec[] = {{ kEventClassControl, kEventControlHit }, { kEventClassCommand, kEventCommandProcess }};
EventHandlerUPP buttonHandler = NewEventHandlerUPP(DoCommandEvent);
// Static Text Variables
Rect rectStatic = {20, 20, 152, 530};
CFStringRef szStaticText = CFStringCreateWithCString(kCFAllocatorDefault, prompt, kCFStringEncodingUTF8);
ControlRef refStaticText = NULL;
err = CreateStaticTextControl(window, &rectStatic, szStaticText, NULL, &refStaticText);
// Button Variables
Rect bounds[numChoices];
CFStringRef caption[numChoices];
ControlRef button[numChoices];
int whichButton=-1;
CallbackData callbackData[numChoices];
// Create the Buttons and assign event handlers
for (int i = 0; i < numChoices; ++i) {
bounds[i].top = 160 + ((CARBON_BUTTON_HEIGHT+CARBON_BUTTON_SPACING)*(i%iNumButtonRows));
bounds[i].right = 530 - ((iButtonWidth+CARBON_BUTTON_SPACING)*(i/iNumButtonRows));
bounds[i].left = bounds[i].right - iButtonWidth;
bounds[i].bottom = bounds[i].top + CARBON_BUTTON_HEIGHT;
// Convert the button captions to Apple strings
caption[i] = CFStringCreateWithCString(kCFAllocatorDefault, choice[i], kCFStringEncodingUTF8);
err = CreatePushButtonControl(window, &bounds[i], caption[i], &button[i]);
assert(err == noErr);
err = SetControlCommandID(button[i], CARBON_COMMANDID_START + i);
assert(err == noErr);
callbackData[i].refWindow = window;
callbackData[i].myIndex = i;
callbackData[i].whichButton = &whichButton;
err = InstallControlEventHandler(button[i], buttonHandler,
GetEventTypeCount(buttonSpec), buttonSpec,
&callbackData[i], NULL);
assert(err == noErr);
}
// Show Dialog
err = RepositionWindow(window, NULL, kWindowCenterOnMainScreen);
ShowWindow(window);
BringToFront(window);
err = ActivateWindow(window, true);
// Hack to get our window/process to the front...
ProcessSerialNumber psn = { 0, kCurrentProcess};
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
SetFrontProcess (&psn);
// Run in Modal State
err = RunAppModalLoopForWindow(window);
// Dispose of Button Related Data
for (int i = 0; i < numChoices; ++i) {
// Dispose of controls
DisposeControl(button[i]);
// Release CFStrings
CFRelease(caption[i]);
}
// Dispose of Other Controls
DisposeControl(refStaticText);
// Dispose of Event Handlers
DisposeEventHandlerUPP(buttonHandler);
// Dispose of Window
DisposeWindow(window);
// Release CFStrings
CFRelease(szWindowTitle);
CFRelease(szStaticText);
// Return Selection
return whichButton;
}
#endif
int prompt(
const char* windowTitle,
const char* prompt,
const char** choice,
int numChoices,
bool useGui) {
#ifdef G3D_WIN32
if (useGui) {
// Build the message box
return guiPrompt(windowTitle, prompt, choice, numChoices);
}
#endif
#ifdef G3D_OSX
if (useGui){
//Will default to text prompt if numChoices > 4
return guiPrompt(windowTitle, prompt, choice, numChoices);
}
#endif
return textPrompt(windowTitle, prompt, choice, numChoices);
}
void msgBox(
const std::string& message,
const std::string& title) {
const char *choice[] = {"Ok"};
prompt(title.c_str(), message.c_str(), choice, 1, true);
}
#ifndef G3D_WIN32
#undef _getch
#endif
};// namespace
-231
View File
@@ -1,231 +0,0 @@
/**
@file stringutils.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2000-09-09
@edited 2008-01-10
*/
#include "G3D/platform.h"
#include "G3D/stringutils.h"
#include "G3D/BinaryInput.h"
#include <algorithm>
namespace G3D {
#ifdef _MSC_VER
// disable: "C++ exception handler used"
# pragma warning (push)
# pragma warning (disable : 4530)
#endif
#ifdef G3D_WIN32
const char* NEWLINE = "\r\n";
#else
const char* NEWLINE = "\n";
static bool iswspace(int ch) { return (ch==' ' || ch=='\t' || ch=='\n'); }
#endif
bool beginsWith(
const std::string& test,
const std::string& pattern) {
if (test.size() >= pattern.size()) {
for (int i = 0; i < (int)pattern.size(); ++i) {
if (pattern[i] != test[i]) {
return false;
}
}
return true;
} else {
return false;
}
}
bool endsWith(
const std::string& test,
const std::string& pattern) {
if (test.size() >= pattern.size()) {
int te = test.size() - 1;
int pe = pattern.size() - 1;
for (int i = pattern.size() - 1; i >= 0; --i) {
if (pattern[pe - i] != test[te - i]) {
return false;
}
}
return true;
} else {
return false;
}
}
std::string wordWrap(
const std::string& input,
int numCols) {
std::string output;
size_t c = 0;
int len;
// Don't make lines less than this length
int minLength = numCols / 4;
size_t inLen = input.size();
bool first = true;
while (c < inLen) {
if (first) {
first = false;
} else {
output += NEWLINE;
}
if ((int)inLen - (int)c - 1 < numCols) {
// The end
output += input.substr(c, inLen - c);
break;
}
len = numCols;
// Look at character c + numCols, see if it is a space.
while ((len > minLength) &&
(input[c + len] != ' ')) {
len--;
}
if (len == minLength) {
// Just crop
len = numCols;
}
output += input.substr(c, len);
c += len;
if (c < input.size()) {
// Collapse multiple spaces.
while ((input[c] == ' ') && (c < input.size())) {
c++;
}
}
}
return output;
}
int stringCompare(
const std::string& s1,
const std::string& s2) {
return stringPtrCompare(&s1, &s2);
}
int stringPtrCompare(
const std::string* s1,
const std::string* s2) {
return s1->compare(*s2);
}
std::string toUpper(const std::string& x) {
std::string result = x;
std::transform(result.begin(), result.end(), result.begin(), toupper);
return result;
}
std::string toLower(const std::string& x) {
std::string result = x;
std::transform(result.begin(), result.end(), result.begin(), tolower);
return result;
}
Array<std::string> stringSplit(
const std::string& x,
char splitChar) {
Array<std::string> out;
// Pointers to the beginning and end of the substring
const char* start = x.c_str();
const char* stop = start;
while ((stop = strchr(start, splitChar))) {
out.append(std::string(start, stop - start));
start = stop + 1;
}
// Append the last one
out.append(std::string(start));
return out;
}
std::string stringJoin(
const Array<std::string>& a,
char joinChar) {
std::string out;
for (int i = 0; i < (int)a.size() - 1; ++i) {
out += a[i] + joinChar;
}
if (a.size() > 0) {
return out + a.last();
} else {
return out;
}
}
std::string stringJoin(
const Array<std::string>& a,
const std::string& joinStr) {
std::string out;
for (int i = 0; i < (int)a.size() - 1; ++i) {
out += a[i] + joinStr;
}
if (a.size() > 0) {
return out + a.last();
} else {
return out;
}
}
std::string trimWhitespace(
const std::string& s) {
size_t left = 0;
// Trim from left
while ((left < s.length()) && iswspace(s[left])) {
++left;
}
int right = s.length() - 1;
// Trim from right
while ((right > (int)left) && iswspace(s[right])) {
--right;
}
return s.substr(left, right - left + 1);
}
}; // namespace
#undef NEWLINE
#ifdef _MSC_VER
# pragma warning (pop)
#endif
-155
View File
@@ -1,155 +0,0 @@
/**
@file uint128.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@author Kyle Whitson
@created 2008-07-17
@edited 2008-07-17
*/
#include "G3D/uint128.h"
namespace G3D {
/** Adds two 64-bit integers, placing the result and the overflow into 64-bit integers.*/
static void addAndCarry(const uint64& _a, const uint64& _b, uint64& carry, uint64& result) {
// Break each number into 4 32-bit chunks. Since we are using uints, right-shifting will fill with zeros.
// This eliminates the need to and with 0xFFFFFFFF.
uint32 a [2] = {_a & 0xFFFFFFFF, _a >> 32};
uint32 b [2] = {_b & 0xFFFFFFFF, _b >> 32};
uint64 tmp = uint64(a[0]) + b[0];
result = tmp & 0xFFFFFFFF;
uint32 c = tmp >> 32;
tmp = uint64(c) + a[1] + b[1];
result += tmp << 32;
carry = (tmp >> 32);
}
/** Multiplies two unsigned 64-bit integers, placing the result into one 64-bit int and the overflow into another.*/
void multiplyAndCarry(const uint64& _a, const uint64& _b, uint64& carry, uint64& result) {
// Break each number into 4 32-bit chunks. Since we are using uints, right-shifting will fill with zeros.
// This eliminates the need to and with 0xFFFFFFFF.
uint32 a [2] = {_a & 0xFFFFFFFF, _a >> 32};
uint32 b [2] = {_b & 0xFFFFFFFF, _b >> 32};
uint64 prod [2][2];
for(int i = 0; i < 2; ++i) {
for(int j = 0; j < 2; ++j) {
prod[i][j] = uint64(a[i]) * b[j];
}
}
// The product of the low bits of a and b will always fit into the result
result = prod[0][0];
// The product of the high bits of a and b will never fit into the result
carry = prod[1][1];
// The high 32 bits of prod[0][1] and prod[1][0] will never fit into the result
carry += prod[0][1] >> 32;
carry += prod[1][0] >> 32;
uint64 tmp;
addAndCarry(result, (prod[0][1] << 32), tmp, result);
carry += tmp;
addAndCarry(result, (prod[1][0] << 32), tmp, result);
carry += tmp;
}
uint128::uint128(const uint64& hi, const uint64& lo) : hi(hi), lo(lo) {
}
uint128::uint128(const uint64& lo) : hi(0), lo(lo) {
}
uint128& uint128::operator+=(const uint128& x) {
G3D::uint64 carry;
addAndCarry(lo, x.lo, carry, lo);
// Adding the carry will change hi. Save the old hi bits in case this == x.
const uint64 xHi = x.hi;
hi += carry;
hi += xHi;
return *this;
}
uint128& uint128::operator*=(const uint128& x) {
// The low bits will get overwritten when doing the multiply, so back up both (in case &x == this)
const uint64 oldLo = lo;
const uint64 oldXLo = x.lo;
G3D::uint64 carry;
multiplyAndCarry(oldLo, oldXLo, carry, lo);
// Overflow doesn't matter here because the result is going into hi - any overflow will exceed the capacity of a 128-bit number
// Note: hi * x.hi will always overflow, since (x * 2^64) * (y * 2^64) = x*y*(2^128). The largest number expressable in 128 bits is
// 2^128 - 1.
hi = carry + (oldLo * x.hi) + (hi * oldXLo);
return *this;
}
uint128& uint128::operator^=(const uint128& x) {
hi ^= x.hi;
lo ^= x.lo;
return *this;
}
uint128& uint128::operator&=(const uint128& x) {
hi &= x.hi;
lo &= x.lo;
return *this;
}
uint128& uint128::operator|=(const uint128& x) {
hi |= x.hi;
lo |= x.lo;
return *this;
}
bool uint128::operator==(const uint128& x) {
return (hi == x.hi) && (lo == x.lo);
}
uint128& uint128::operator>>=(const int x) {
//Before shifting, mask out the bits that will be shifted out of hi.
//Put a 1 in the first bit that will not be lost in the shift, then subtract 1 to get the mask.
uint64 mask = ((uint64)1L << x) - 1;
uint64 tmp = hi & mask;
hi >>= x;
//Shift lo and add the bits shifted down from hi
lo = (lo >> x) + (tmp << (64 - x));
return *this;
}
uint128& uint128::operator<<=(const int x) {
//Before shifting, mask out the bits that will be shifted out of lo.
//Put a 1 in the last bit that will be lost in the shift, then subtract 1 to get the logical inverse of the mask.
//A bitwise NOT will then produce the correct mask.
uint64 mask = ~((((uint64)1L) << (64 - x)) - 1);
uint64 tmp = lo & mask;
lo <<= x;
//Shift hi and add the bits shifted up from lo
hi = (hi << x) + (tmp >> (64 - x));
return *this;
}
uint128 uint128::operator&(const uint128& x) {
return uint128(hi & x.hi, lo & x.lo);
}
}
@@ -3,12 +3,12 @@
Axis-aligned box class
@maintainer Morgan McGuire, matrix@graphics3d.com
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2004-01-10
@edited 2006-02-10
@edited 2009-02-10
Copyright 2000-2006, Morgan McGuire.
Copyright 2000-2009, Morgan McGuire.
All rights reserved.
*/
@@ -28,6 +28,7 @@ namespace G3D {
*/
class AABox {
private:
friend class Intersect;
/** Optional argument placeholder */
static int dummy;
@@ -83,6 +84,10 @@ public:
void deserialize(class BinaryInput& b);
inline bool isFinite() const {
return lo.isFinite() && hi.isFinite();
}
inline const Vector3& low() const {
return lo;
}
@@ -94,29 +99,15 @@ public:
/**
The largest possible finite box.
*/
static inline const AABox& maxFinite() {
static const AABox b = AABox(Vector3::minFinite(),
Vector3::maxFinite());
return b;
}
static const AABox& maxFinite();
/** A large finite box. This is smaller than FLT_MAX
because it leaves room to add boxes together. */
static inline const AABox& large() {
static const AABox b = AABox(Vector3::minFinite() * 0.5f,
Vector3::maxFinite() * 0.5f);
return b;
}
static const AABox& large();
static inline const AABox& inf() {
static const AABox b = AABox(-Vector3::inf(), Vector3::inf());
return b;
}
static const AABox& inf();
static inline const AABox& zero() {
static const AABox b = AABox(Vector3::zero(), Vector3::zero());
return b;
}
static const AABox& zero();
/**
Returns the centroid of the box.
+570
View File
@@ -0,0 +1,570 @@
/**
@file Any.h
@author Morgan McGuire, Shawn Yarbrough, and Corey Taylor
@maintainer Morgan McGuire
@created 2006-06-11
@edited 2009-12-16
Copyright 2000-2010, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_Any_h
#define G3D_Any_h
#include "G3D/platform.h"
#include "G3D/Table.h"
#include "G3D/Array.h"
#include "G3D/AtomicInt32.h"
#include <string>
// needed for Token
#include "G3D/TextInput.h"
#ifdef verify
#undef verify
#endif
namespace G3D {
class TextOutput;
/**
\brief Easy loading and saving of human-readable configuration files.
Encodes typed, structured data and can serialize it to a human
readable format that is very similar to the Python language's data
syntax. 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 class is designed so that copying Anys generally is fast, even if
it is a large array or table. This is because data is shared between
copies until it is mutated, at which point an actual copy occurs.
\section Example
Sample File:
<pre>
{
shape = "round",
# in meters
radius = 3.7,
position = Vector3(1.0, -1.0, 0.0),
texture = { format = "RGB8", size = (320, 200)}
}
</pre>
Sample code using:
<pre>
Any x;
x.load("ball.txt");
if (x["shape"].string() == "round") {
x["density"] = 3;
}
x.save("ball.txt");
</pre>
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.
G3D::Any assumes that structures do not contain cycles; it is an
error to create a structure like:
<pre>
Any x(Any::ARRAY);
x.array().append(x); // don't do this!
</pre>
although no exception will be thrown at runtime during that append.
\section Parsing
The primary use of Any is to create your own text file formats.
The Vector3 constructor is a good example of how to use the Any::verify
methods to provide good error checking while parsing such formats:
<pre>
Vector3::Vector3(const Any& any) {
any.verifyName("Vector3");
any.verifyType(Any::TABLE, Any::ARRAY);
any.verifySize(3);
if (any.type() == Any::ARRAY) {
x = any[0];
y = any[1];
z = any[2];
} else {
// Table
x = any["x"];
y = any["y"];
z = any["z"];
}
}
</pre>
\section BNF
Serialized format BNF:
<pre>
identifier ::= (letter | "_") (letter | digit | "_")*
identifier-op ::= "::" | "->" | "."
identifier-exp ::= [identifier-op] identifier (identifier-op identifier)*
comment ::= "#" <any characters> "\n"
separator ::= "," | ";"
number ::= <legal C printf number format>
string ::= <legal C double-quoted string; backslashes must be escaped>
boolean ::= "True" | "False"
none ::= "None"
array ::= "(" [value ("," value)*] ")"
pair ::= (identifier | string) "=" value
table ::= "{" [pair (separator pair)*] "}"
named-array ::= identifier-exp tuple
named-table ::= identifier-exp dict
value ::= [comment] (none | number | boolean | string | array | table | named-array | named-table)
</pre>
Except for single-line comments, whitespace is not significant.
All parsing is case-insensitive.
The deserializer allows the substitution of [] for () when writing
tuples and ";" for ",".
The serializer indents four spaces for each level of nesting.
Tables are written with the keys in alphabetic order.
*/
class Any {
public:
enum Type {NONE, BOOLEAN, NUMBER, STRING, ARRAY, TABLE};
static std::string toString(Type t);
/** Where an Any came from in a file. Useful for throwing parsing errors */
class Source {
public:
std::string filename;
int line;
int character;
Source() : line(0), character(0) {}
void set(const TextInput& ti, const Token& t) {
filename = ti.filename();
line = t.line();
character = t.character();
}
};
typedef Array<Any> AnyArray;
typedef Table<std::string, Any> AnyTable;
private:
/** Called from deserialize() */
static void deserializeComment(TextInput& ti, Token& token, std::string& comment);
/** NONE, BOOLEAN, and NUMBER are stored directly in the Any */
union SimpleValue {
bool b;
double n;
inline SimpleValue() : n(0.0) {}
inline SimpleValue(bool x) : b(x) {}
inline SimpleValue(double x) : n(x) {}
};
class Data {
public:
/** ARRAY, TABLE, or STRING value only. NULL otherwise. */
union Value {
std::string* s;
Array<Any>* a;
AnyTable* t;
inline Value() : s(NULL) {}
};
// Needed so that the destructor knows what is in Value
// and can call its destructor.
Type type;
/** Always points to memory that is allocated with the Data, so
the destructor does not delete this. */
Value value;
std::string comment;
std::string name;
/** 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
the value. This is not used for other types.
*/
AtomicInt32 referenceCount;
Source source;
private:
/** Called by create() */
inline Data(Type t) : type(t), referenceCount(1) {}
/** Called by destroy */
~Data();
public:
/** Clones the argument */
static Data* create(const Data* d);
static Data* create(Type t);
/** 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
and perhaps was not intended to exist. The name is needed to
format the error message if it is read from before it is
written to.
The source of a placeholder object is that of the parent
object until it is written.
*/
std::string m_placeholderName;
Type m_type;
SimpleValue m_simpleValue;
mutable Data* m_data;
/** Called before every read operation to ensure that this object
is not a placeholder. */
void beforeRead() const;
/** Called before every write operation to wipe the placeholder
status. */
void beforeWrite();
/** Decrements the reference count (if there is one). If the
reference count is zero after decrement, calls delete on @a m_data
and sets it to NULL.
*/
void dropReference();
/** Allocate the Data object if it does not exist */
void ensureData();
/** If m_data is not NULL, ensure that it has a unique reference
and contains a valid m_data. This has a race condition if two
threads are both trying to modify the same Any
simultaneously.*/
void ensureMutable();
/** Read an unnamed a TABLE or ARRAY. Token should be the open
paren token; it is the next token after the close on
return. Called from deserialize().*/
void deserializeBody(TextInput& ti, Token& token);
void deserialize(TextInput& ti, Token& token);
/** 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
return that token. Considers the passed in token to be the first
value read. */
static void readUntilCommaOrClose(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 {
return ! m_placeholderName.empty();
}
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;
};
/** Thrown by operator[] when an array index is not present. */
class IndexOutOfBounds : public Exception {
public:
int index;
int size;
inline IndexOutOfBounds() : index(0), size(0) {}
inline IndexOutOfBounds(int i, int s) : index(i), size(s) {}
};
/** NONE constructor */
Any();
/** Deserialize */
explicit Any(TextInput& t);
Any(const Any& x);
/** NUMBER constructor */
Any(double x);
#ifdef G3D_32BIT
/** NUMBER constructor */
Any(int64 x);
#endif // G3D_32BIT
#if 0
/** NUMBER constructor */
Any(int32 x);
#endif // 0
/** NUMBER constructor */
Any(long x);
/** NUMBER constructor */
Any(int x);
/** NUMBER constructor */
Any(short x);
/** BOOLEAN constructor */
Any(bool x);
/** STRING constructor */
Any(const std::string& x);
/** STRING constructor */
Any(const char* x);
/** \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 */
Any& operator=(Type t);
Type type() const;
/** Same as deserialize or load, but operates on a string instead
of a stream or file.
\sa deserialize, load
*/
void parse(const std::string& src);
std::string unparse() 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;
/** Throws a ParseError exception if this is not a number */
double number() const;
const std::string& string() const;
bool boolean() const;
/** If this is named ARRAY or TABLE, returns the name. */
const std::string& name() const;
/** \brief Set the name used when serializing an ARRAY or TABLE.
Only legal for ARRAY or TABLE. The \a name must begin with a letter
and contain only letters, numbers, underscores and scope operators.
<pre>
a2z
hello
Foo::bar
color.red
this->that
__x
</pre>
The scope operators "::", "->", and
".", may have spaces around them. The name may not
contain parentheses.
*/
void setName(const std::string& name);
/** Number of elements if this is an ARRAY or TABLE */
int size() const;
int length() const;
/** For an array, returns the ith element */
const Any& operator[](int i) const;
Any& operator[](int i);
/** 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.*/
const Table<std::string, Any>& table() const;
/** For a table, returns the element for \a key. Throws KeyNotFound
exception if the element does not exist.
*/
const Any& operator[](const std::string& key) const;
// Needed to prevent the operator[](int) overload from catching
// string literals
inline const Any& operator[](const char* key) const {
return operator[](std::string(key));
}
/**
Fetch an element from a table. This can be used as:
<pre>
a["key"] = value; (create the key if it did not exist)
</pre>
or
<pre>
value = a["key"]; (throw an error if the key did not exist)
</pre>
<b>Note:</b>
In order to cause elements to be correctly created in the
first case while still providing "key not found" errors in the
second case, the Any returned is a special object that delays
the actual fetch until the following assignment or method
call. This means that in the event of an error, the exception
may be thrown from a line other than the actual fetch. Use
the Any::get() or the const Any::operator[]() methods to avoid
this behavior and ensure error-checking at fetch time.
*/
Any& operator[](const std::string& key);
/** \copydoc Any::operator[](const std::string&) */
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;
/** 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);
/** for an ARRAY, resizes and returns the last element */
Any& next();
/** True if the Anys are exactly equal, ignoring comments. Applies deeply on arrays and tables. */
bool operator==(const Any& x) const;
bool operator!=(const Any& x) const;
operator int() const;
operator float() const;
operator double() const;
operator bool() const;
operator std::string() const;
/** 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);
/**
Clears all entries.
This must be a TABLE or ARRAY */
void clear();
/** Parse from a file.
\sa deserialize, parse */
void load(const std::string& filename);
/** Uses the serialize method. */
void save(const std::string& filename) const;
void serialize(TextOutput& to) const;
/** Parse from a stream.
\sa load, parse */
void deserialize(TextInput& ti);
const Source& source() const;
/** Throws a ParseError if \a value is false. Useful for quickly
creating parse rules in classes that deserialize from Any.
*/
void verify(bool value, const std::string& message = "") const;
/** Verifies that the name begins with identifier \a n. It may contain
identifier operators after this */
void verifyName(const std::string& n) const;
/** Verifies that the type is \a t. */
void verifyType(Type t) const;
/** Throws an exception if the type is not \a t0 or \a t1. */
void verifyType(Type t0, Type t1) const;
/** Verifies that the size is between \a low and \a high, inclusive */
void verifySize(int low, int high) const;
/** Verifies that the size is exactly \a s */
void verifySize(int s) const;
private:
void deserializeTable(TextInput& ti);
void deserializeArray(TextInput& ti,const std::string& term);
}; // class Any
} // namespace G3D
#endif
@@ -34,6 +34,10 @@ class Rect2D;
class AABox;
/**
\deprecated
<b>Use the G3D::Any class instead. This is only provided for
backwards compatibility to G3D 7.xx.</b>
A generic value, useful for defining property trees that can
be loaded from and saved to disk. The values are intentionally
restricted to a small set.
@@ -172,6 +176,8 @@ Table<boost::any> tree;
...
}
</pre>
\deprecated
*/
class AnyVal {
public:
+93
View File
@@ -0,0 +1,93 @@
/**
@file AreaMemoryManager.h
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2009-01-20
@edited 2009-05-29
Copyright 2000-2009, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_AreaMemoryManager_h
#define G3D_AreaMemoryManager_h
#include "G3D/platform.h"
#include "G3D/g3dmath.h"
#include "G3D/Array.h"
#include "G3D/MemoryManager.h"
namespace G3D {
/**
\brief Allocates memory in large blocks and then frees it as an area.
Useful for ensuring cache coherence and for reducing the time cost of
multiple allocations and deallocations.
<b>Not threadsafe</b>
*/
class AreaMemoryManager : public MemoryManager {
private:
class Buffer {
private:
uint8* m_first;
size_t m_size;
size_t m_used;
public:
Buffer(size_t size);
~Buffer();
/** Returns NULL if out of space */
void* alloc(size_t s);
};
size_t m_sizeHint;
/** The underlying array is stored in regular MemoryManager heap memory */
Array<Buffer*> m_bufferArray;
AreaMemoryManager(size_t sizeHint);
public:
typedef ReferenceCountedPointer<AreaMemoryManager> Ref;
/**
\param sizeHint Total amount of memory expected to be allocated.
The allocator will allocate memory from the system in increments
of this size.
*/
static AreaMemoryManager::Ref create(size_t sizeHint = 10 * 1024 * 1024);
/** Invokes deallocateAll. */
~AreaMemoryManager();
size_t bytesAllocated() const;
/** Allocates memory out of the buffer pool.
@param s must be no larger than sizeHint */
virtual void* alloc(size_t s);
/** Ignored. */
virtual void free(void* x);
virtual bool isThreadsafe() const;
/** Deletes all previously allocated memory. Because delete is not
invoked on objects in this memory, it is not safe to simply
free memory containing C++ objects that expect their destructors
to be called. */
void deallocateAll();
};
typedef AreaMemoryManager CoherentAllocator;
}
#endif
@@ -5,18 +5,19 @@
@cite Portions written by Aaron Orenstein, a@orenstein.name
@created 2001-03-11
@edited 2008-07-09
@edited 2009-05-29
Copyright 2000-2008, Morgan McGuire, morgan@cs.williams.edu
Copyright 2000-2009, Morgan McGuire, http://graphics.cs.williams.edu
All rights reserved.
*/
#ifndef G3D_ARRAY_H
#define G3D_ARRAY_H
#ifndef G3D_Array_h
#define G3D_Array_h
#include "G3D/platform.h"
#include "G3D/debug.h"
#include "G3D/System.h"
#include "G3D/MemoryManager.h"
#ifdef G3D_DEBUG
// For formatting error messages
# include "G3D/format.h"
@@ -47,7 +48,7 @@ const int SORT_INCREASING = 1;
const int SORT_DECREASING = -1;
/**
Dynamic 1D array.
\brief Dynamic 1D array tuned for performance.
Objects must have a default constructor (constructor that
takes no arguments) in order to be used with this template.
@@ -57,20 +58,15 @@ const int SORT_DECREASING = -1;
Do not use with objects that overload placement <code>operator new</code>,
since the speed of Array is partly due to pooled allocation.
If SSE is defined Arrays allocate the first element aligned to
16 bytes.
Array is highly optimized compared to std::vector.
Array operations are less expensive than on std::vector and for large
amounts of data, Array consumes only 1.5x the total size of the
data, while std::vector consumes 2.0x. The default
array takes up zero heap space. The first resize (or append)
operation grows it to a reasonable internal size so it is efficient
to append to small arrays. Memory is allocated using
System::alignedMalloc, which produces pointers aligned to 16-byte
boundaries for use with SSE instructions and uses pooled storage for
fast allocation. When Array needs to copy
to append to small arrays.
Then Array needs to copy
data internally on a resize operation it correctly invokes copy
constructors of the elements (the MSVC6 implementation of
std::vector uses realloc, which can create memory leaks for classes
@@ -90,6 +86,8 @@ const int SORT_DECREASING = -1;
is empty.
Do not subclass an Array.
\sa G3D::SmallArray
*/
template <class T, int MIN_ELEMENTS = 10, size_t MIN_BYTES = 32>
class Array {
@@ -100,13 +98,17 @@ private:
int num;
int numAllocated;
void init(int n, int a) {
debugAssert(n <= a);
MemoryManager::Ref m_memoryManager;
/** \param n Number of elements
*/
void init(int n, const MemoryManager::Ref& m) {
m_memoryManager = m;
debugAssert(n >= 0);
this->num = 0;
this->numAllocated = 0;
data = NULL;
if (a > 0) {
if (n > 0) {
resize(n);
} else {
data = NULL;
@@ -114,7 +116,7 @@ private:
}
void _copy(const Array &other) {
init(other.num, other.num);
init(other.num, MemoryManager::create());
for (int i = 0; i < num; i++) {
data[i] = other.data[i];
}
@@ -148,7 +150,8 @@ private:
// elements are actually revealed to the application. They
// will be constructed in the resize() method.
data = (T*)System::alignedMalloc(sizeof(T) * numAllocated, 16);
data = (T*)m_memoryManager->alloc(sizeof(T) * numAllocated);
alwaysAssertM(data, "Memory manager returned NULL: out of memory?");
// Call the copy constructors
{const int N = G3D::min(oldNum, numAllocated);
@@ -171,8 +174,7 @@ private:
ptr->~T();
}}
System::alignedFree(oldData);
m_memoryManager->free(oldData);
}
public:
@@ -237,22 +239,59 @@ public:
}
/** Creates a zero length array (no heap allocation occurs until resize). */
Array() {
init(0, 0);
Array() : num(0) {
init(0, MemoryManager::create());
debugAssert(num >= 0);
}
/**
Creates an array of size.
*/
Array(int size) {
init(size, size);
/** Creates an array containing v0. */
Array(const T& v0) {
init(1, MemoryManager::create());
(*this)[0] = v0;
}
/** Creates an array containing v0 and v1. */
Array(const T& v0, const T& v1) {
init(2, MemoryManager::create());
(*this)[0] = v0;
(*this)[1] = v1;
}
/** Creates an array containing v0...v2. */
Array(const T& v0, const T& v1, const T& v2) {
init(3, MemoryManager::create());
(*this)[0] = v0;
(*this)[1] = v1;
(*this)[2] = v2;
}
/** Creates an array containing v0...v3. */
Array(const T& v0, const T& v1, const T& v2, const T& v3) {
init(4, MemoryManager::create());
(*this)[0] = v0;
(*this)[1] = v1;
(*this)[2] = v2;
(*this)[3] = v3;
}
/** Creates an array containing v0...v4. */
Array(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) {
init(5, MemoryManager::create());
(*this)[0] = v0;
(*this)[1] = v1;
(*this)[2] = v2;
(*this)[3] = v3;
(*this)[4] = v4;
}
/**
Copy constructor
*/
Array(const Array& other) {
Array(const Array& other) : num(0) {
_copy(other);
debugAssert(num >= 0);
}
/**
@@ -268,14 +307,13 @@ public:
(data + i)->~T();
}
System::alignedFree(data);
m_memoryManager->free(data);
// Set to 0 in case this Array is global and gets referenced during app exit
data = NULL;
num = 0;
numAllocated = 0;
}
/**
Removes all elements. Use resize(0, false) or fastClear if you want to
remove all elements without deallocating the underlying array
@@ -285,6 +323,12 @@ public:
resize(0, shrink);
}
void clearAndSetMemoryManager(const MemoryManager::Ref& m) {
clear();
debugAssert(data == NULL);
m_memoryManager = m;
}
/** resize(0, false)
@deprecated*/
void fastClear() {
@@ -295,10 +339,11 @@ public:
Assignment operator.
*/
Array& operator=(const Array& other) {
resize(other.num);
for (int i = 0; i < num; ++i) {
debugAssert(num >= 0);
resize(other.num); for (int i = 0; i < num; ++i) {
data[i] = other[i];
}
debugAssert(num >= 0);
return *this;
}
@@ -310,6 +355,10 @@ public:
return *this;
}
inline MemoryManager::Ref memoryManager() const {
return m_memoryManager;
}
/**
Number of elements in the array.
*/
@@ -336,12 +385,6 @@ public:
resize(size() - 1, shrinkIfNecessary);
}
/** Resizes without shrinking the underlying array. Same as resize(n, false).
@deprecated*/
void fastResize(int n) {
resize(n, false);
}
/**
Inserts at the specified index and shifts all other elements up by one.
@@ -358,8 +401,14 @@ public:
/** @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.
*/
void resize(int n, bool shrinkIfNecessary = true) {
debugAssert(n >= 0);
if (num == n) {
return;
}
int oldNum = num;
num = n;
@@ -369,12 +418,12 @@ public:
}
// Once allocated, always maintain MIN_ELEMENTS elements or 32 bytes, whichever is higher.
static const int minSize = G3D::max(MIN_ELEMENTS, (int)(MIN_BYTES / sizeof(T)));
const int minSize = std::max(MIN_ELEMENTS, (int)(MIN_BYTES / sizeof(T)));
if ((MIN_ELEMENTS == 0) && (MIN_BYTES == 0) && (n == 0) && shrinkIfNecessary) {
// Deallocate the array completely
numAllocated = 0;
System::alignedFree(data);
m_memoryManager->free(data);
data = NULL;
return;
}
@@ -403,7 +452,7 @@ public:
float growFactor = 3.0;
size_t oldSizeBytes = numAllocated * sizeof(T);
int oldSizeBytes = numAllocated * sizeof(T);
if (oldSizeBytes > 400000) {
// Avoid bloat
growFactor = 1.5;
@@ -621,6 +670,24 @@ public:
return (*this)[0];
}
/**
"The member function returns a reference to the last element of the controlled sequence,
which must be non-empty."
For compatibility with std::vector.
*/
T& back() {
return (*this)[size()-1];
}
/**
"The member function returns a reference to the last element of the controlled sequence,
which must be non-empty."
For compatibility with std::vector.
*/
const T& back() const {
return (*this)[size()-1];
}
/**
Removes the last element and returns it. By default, shrinks the underlying array.
*/
@@ -761,6 +828,19 @@ public:
resize(0);
}
/**
Returns the index of (the first occurance of) an index or -1 if
not found. Searches from the right.
*/
int rfindIndex(const T& value) const {
for (int i = num -1 ; i >= 0; --i) {
if (data[i] == value) {
return i;
}
}
return -1;
}
/**
Returns the index of (the first occurance of) an index or -1 if
not found.
@@ -851,12 +931,26 @@ public:
return elem1->x < elem2->x;
}
</PRE>
or a functor, e.g.,
<pre>
bool
less_than_functor::operator()( const double& lhs, const double& rhs ) const
{
return( lhs < rhs? true : false );
}
</pre>
*/
void sort(bool (__cdecl *lessThan)(const T& elem1, const T& elem2)) {
// void sort(bool (__cdecl *lessThan)(const T& elem1, const T& elem2)) {
// std::sort(data, data + num, lessThan);
//}
template<class LessThan>
void sort(const LessThan& lessThan) {
// Using std::sort, which according to http://www.open-std.org/JTC1/SC22/WG21/docs/D_4.cpp
// was 2x faster than qsort for arrays around size 2000 on intel core2 with gcc
std::sort(data, data + num, lessThan);
}
/**
Sorts the array in increasing order using the > or < operator. To
invoke this method on Array<T>, T must override those operator.
@@ -1,7 +1,7 @@
/**
@file AtomicInt32.h
@maintainer Morgan McGuire, matrix@graphics3d.com
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2005-09-01
@edited 2006-06-21
@@ -138,24 +138,22 @@ public:
Otherwise, no operation is performed.
Under VC6 the sign bit may be lost.
*/
int32 compareAndSet(const int32 comperand, const int32 exchange) {
# if defined(G3D_WIN32)
return InterlockedCompareExchange(&m_value, exchange, comperand);
# elif defined(G3D_LINUX) || defined(G3D_FREEBSD)
# 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;
# elif defined(G3D_OSX)
int32 old = m_value;
OSAtomicCompareAndSwap32(comperand, exchange, &m_value);
return old;
// Note that OSAtomicCompareAndSwap32 does not return a useful value for us
// so it can't satisfy the cmpxchgl contract.
# endif
}
@@ -1,6 +1,6 @@
/**
@file BinaryFormat.h
@maintainer Morgan McGuire, matrix@graphics3d.com
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@author 2005-06-03
@edited 2005-06-03
@@ -6,12 +6,12 @@
@created 2001-08-09
@edited 2006-07-19
Copyright 2000-2007, Morgan McGuire.
Copyright 2000-2009, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_BINARYINPUT_H
#define G3D_BINARYINPUT_H
#ifndef G3D_BinaryInput_h
#define G3D_BinaryInput_h
#ifdef _MSC_VER
// Disable conditional expression is constant, which occurs incorrectly on inlined functions
@@ -1,10 +1,10 @@
/**
@file BoundsTrait.h
@maintainer Morgan McGuire, morgan@cs.williams.edu
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2008-10-01
@edited 2008-10-01
Copyright 2000-2008, Morgan McGuire.
Copyright 2000-2009, Morgan McGuire.
All rights reserved.
*/
@@ -3,7 +3,7 @@
Box class
@maintainer Morgan McGuire, matrix@graphics3d.com
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@cite Portions based on Dave Eberly's Magic Software Library at <A HREF="http://www.magic-software.com">http://www.magic-software.com</A>
@created 2001-06-02
@@ -153,7 +153,8 @@ public:
/**
See AABox::culledBy
*/
bool culledBy(
bool culledBy
(
const Array<Plane>& plane,
int32& cullingPlaneIndex,
const uint32 testMask,
@@ -162,7 +163,8 @@ public:
/**
Conservative culling test that does not produce a mask for children.
*/
bool culledBy(
bool culledBy
(
const Array<Plane>& plane,
int32& cullingPlaneIndex = dummy,
const uint32 testMask = -1) const;
@@ -174,7 +176,7 @@ public:
float volume() const;
void getRandomSurfacePoint(Vector3& P, Vector3& N = Vector3::dummy) const;
void getRandomSurfacePoint(Vector3& P, Vector3& N = Vector3::ignore()) const;
/**
Uniformly distributed on the interior (includes surface)
+121
View File
@@ -0,0 +1,121 @@
/**
@file Box2D.h
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2001-06-02
@edited 2008-12-27
Copyright 2000-2009, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_Box2D_h
#define G3D_Box2D_h
#include "G3D/platform.h"
#include "G3D/Vector2.h"
namespace G3D {
class CoordinateFrame;
typedef class CoordinateFrame CFrame;
class Rect2D;
typedef class Rect2D AABox2D;
/**
2D oriented box
@cite http://www.flipcode.com/archives/2D_OBB_Intersection.shtml
*/
class Box2D {
private:
/** Corners of the box, where 0 is the lower left. */
Vector2 m_corner[4];
/** Two edges of the box extended away from corner[0], with length
= 1 / extentSquared */
Vector2 m_axisin[2];
/** Two edges of the box extended away from corner[0], with unit length */
Vector2 m_axis[2];
/** Centroid of the box */
Vector2 m_center;
/** origin[a] = m_corner[0].dot(m_axisin[a]); */
float origin[2];
/** Surface area */
float m_area;
Vector2 m_extent;
/** Returns true if other overlaps one dimension of this. */
bool overlaps1Way(const Box2D& other) const;
/** Updates the axes after the m_corners move. Assumes the
m_corners actually form a rectangle. */
void computeAxes();
public:
/**
@param center World-space center
@param w Width along object-space x-axis
@param h Height along object-space y-axis
@param angle Counter-clockwise angle from object-space x-axis in radians
*/
Box2D(const Vector2& center = Vector2(0, 0), float w = 0, float h = 0, float angle = 0);
Box2D(const AABox2D& b);
Box2D(const Vector2& min, const Vector2& max);
/** Transform @a b by @a frame, discarding the Z components, and
compute the new box.*/
Box2D(const CFrame& frame, Box2D& b);
inline bool contains(const Vector2& v) const {
// Take to object space:
const Vector2& p = v - m_center;
float x = p.dot(m_axisin[0]);
float y = p.dot(m_axisin[1]);
// Must be within extent/2 on both axes in object space
return (abs(x) <= 0.5f) && (abs(y) <= 0.5f);
}
/** @brief Distance from corner(0) to the next corner along the box's local axis a. */
inline const Vector2& extent() const {
return m_extent;
}
/** @brief Unit length vector along axis @a a */
inline const Vector2& axis(int a) const {
debugAssert(a == 0 || a == 1);
return m_axis[a];
}
/** @brief Surface area */
inline float area() const {
return m_area;
}
inline const Vector2& corner(int i) const {
debugAssert(i >=0 && i <= 3);
return m_corner[i];
}
inline const Vector2& center() const {
return m_center;
}
/** Returns true if the intersection of the boxes is non-empty. */
inline bool overlaps(const Box2D& other) const {
return overlaps1Way(other) && other.overlaps1Way(*this);
}
};
} // G3D
#endif
+61
View File
@@ -0,0 +1,61 @@
/**
\file BumpMapPreprocess.h
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
\created 2010-01-28
\edited 2010-01-28
Copyright 2000-2010, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_BumpMapPreprocess_h
#define G3D_BumpMapPreprocess_h
#include "G3D/platform.h"
namespace G3D {
class Any;
/**
Not in the BumpMap class to avoid a circular dependency between Texture and BumpMap.
G3D::GImage::computeNormalMap().
*/
class BumpMapPreprocess {
public:
/** If true, the elevations are box filtered after computing normals
and before uploading, which produces better results for parallax offset mapping
Defaults to false. */
bool lowPassFilter;
/** Height of the maximum ("white") value, in pixels, for the purpose of computing normals.
A value of 255 means that a 255 x 255 bump image with a full black-to-white gradient
will produce a 45-degree ramp (this also results in "cubic" voxels).
A negative value means to set zExtentPixels to -zExtentPixels * max(width, height).
The default is -0.02.
*/
float zExtentPixels;
/** After computing normals, scale the height by |N.z|, a trick that reduces texture swim in steep areas for parallax offset
mapping. Defaults to false.*/
bool scaleZByNz;
BumpMapPreprocess() : lowPassFilter(false), zExtentPixels(-0.02f), scaleZByNz(false) {}
BumpMapPreprocess(const Any& any);
operator Any() const;
bool operator==(const BumpMapPreprocess& other) const {
return
(lowPassFilter == other.lowPassFilter) &&
(zExtentPixels == other.zExtentPixels) &&
(scaleZByNz == other.scaleZByNz);
}
};
}
#endif
@@ -1,7 +1,7 @@
/**
@file Capsule.h
@maintainer Morgan McGuire, matrix@graphics3d.com
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2003-02-07
@edited 2005-08-20

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