* 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:
Vendored
+1
-1
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
-1381
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
-2152
File diff suppressed because it is too large
Load Diff
-40
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
-1065
File diff suppressed because it is too large
Load Diff
-298
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-1801
File diff suppressed because it is too large
Load Diff
-1725
File diff suppressed because it is too large
Load Diff
-433
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
-1362
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-1864
File diff suppressed because it is too large
Load Diff
-988
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
-1092
File diff suppressed because it is too large
Load Diff
-32
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)¶ms);
|
||||
|
||||
free(newStr);
|
||||
|
||||
/*
|
||||
For debugging when DialogBoxIndirectParam fails:
|
||||
|
||||
// The last error value. (Which is preserved across the call).
|
||||
DWORD lastErr = GetLastError();
|
||||
|
||||
// The decoded message from FormatMessage
|
||||
LPTSTR formatMsg = NULL;
|
||||
|
||||
if (NULL == formatMsg) {
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
lastErr,
|
||||
0,
|
||||
(LPTSTR)&formatMsg,
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
// Make sure the message got translated into something.
|
||||
LPTSTR realLastErr;
|
||||
if (NULL != formatMsg) {
|
||||
realLastErr = formatMsg;
|
||||
} else {
|
||||
realLastErr = "Last error code does not exist.";
|
||||
}
|
||||
|
||||
// Get rid of the allocated memory from FormatMessage.
|
||||
if (NULL != formatMsg) {
|
||||
LocalFree((LPVOID)formatMsg);
|
||||
}
|
||||
*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Show a prompt on stdout
|
||||
*/
|
||||
static int textPrompt(
|
||||
const char* windowTitle,
|
||||
const char* prompt,
|
||||
const char** choice,
|
||||
int numChoices) {
|
||||
|
||||
printf("\n___________________________________________________\n");
|
||||
printf("%s\n", windowTitle);
|
||||
printf("%s", prompt);
|
||||
|
||||
if (numChoices > 10) {
|
||||
numChoices = 10;
|
||||
}
|
||||
|
||||
int c = -1;
|
||||
if (numChoices > 1) {
|
||||
printf("\n");
|
||||
printf("Choose an option by number:");
|
||||
|
||||
while ((c < 0) || (c >= numChoices)) {
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < numChoices; i++) {
|
||||
if (numChoices <= 3) {
|
||||
printf(" (%d) %s ", i, choice[i]);
|
||||
} else {
|
||||
printf(" (%d) %s\n", i, choice[i]);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n> ");
|
||||
c = _getch() - '0';
|
||||
|
||||
if ((c < 0) || (c >= numChoices)) {
|
||||
printf("'%d' is not a valid choice.", c);
|
||||
} else {
|
||||
printf("%d", c);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (numChoices == 1) {
|
||||
|
||||
printf("\nPress any key for '%s'...", choice[0]);
|
||||
_getch();
|
||||
c = 0;
|
||||
|
||||
} else {
|
||||
|
||||
printf("\nPress any key...");
|
||||
_getch();
|
||||
c = 0;
|
||||
}
|
||||
|
||||
printf("\n___________________________________________________\n");
|
||||
return c;
|
||||
}
|
||||
|
||||
#ifdef G3D_OSX
|
||||
|
||||
// See http://developer.apple.com/documentation/Carbon/Reference/Carbon_Event_Manager_Ref/index.html
|
||||
|
||||
#define CARBON_COMMANDID_START 128
|
||||
#define CARBON_BUTTON_SPACING 12
|
||||
#define CARBON_BUTTON_HEIGHT 20
|
||||
#define CARBON_BUTTON_MINWIDTH 69
|
||||
#define CARBON_WINDOW_PADDING 20
|
||||
|
||||
struct CallbackData {
|
||||
WindowRef refWindow;
|
||||
|
||||
/** Index of this particular button */
|
||||
int myIndex;
|
||||
|
||||
/** Buttons store their index into here when pressed. */
|
||||
int* whichButton;
|
||||
};
|
||||
|
||||
/**
|
||||
Assumes that userData is a pointer to a carbon_evt_data_t.
|
||||
|
||||
*/
|
||||
static pascal OSStatus DoCommandEvent(EventHandlerCallRef handlerRef, EventRef event, void* userData) {
|
||||
// See http://developer.apple.com/documentation/Carbon/Conceptual/HandlingWindowsControls/index.html
|
||||
|
||||
CallbackData& callbackData = *(CallbackData*)userData;
|
||||
|
||||
# pragma unused(handlerRef)
|
||||
|
||||
callbackData.whichButton[0] = callbackData.myIndex;
|
||||
|
||||
// If we get here we can close the window
|
||||
QuitAppModalLoopForWindow(callbackData.refWindow);
|
||||
|
||||
// Return noErr to indicate that we handled the event
|
||||
return noErr;
|
||||
}
|
||||
|
||||
static int guiPrompt
|
||||
(const char* windowTitle,
|
||||
const char* prompt,
|
||||
const char** choice,
|
||||
int numChoices) {
|
||||
|
||||
WindowRef window;
|
||||
|
||||
int iNumButtonRows = 0;
|
||||
int iButtonWidth = -1;
|
||||
OSStatus err = noErr;
|
||||
|
||||
// Determine number of rows of buttons
|
||||
while (iButtonWidth < CARBON_BUTTON_MINWIDTH) {
|
||||
++iNumButtonRows;
|
||||
iButtonWidth =
|
||||
(550 - (CARBON_WINDOW_PADDING*2 +
|
||||
(CARBON_BUTTON_SPACING*numChoices))) /
|
||||
(numChoices/iNumButtonRows);
|
||||
}
|
||||
|
||||
// Window Variables
|
||||
Rect rectWin = {0, 0, 200 + ((iNumButtonRows-1) * (CARBON_BUTTON_HEIGHT+CARBON_BUTTON_SPACING)), 550}; // top, left, bottom, right
|
||||
CFStringRef szWindowTitle = CFStringCreateWithCString(kCFAllocatorDefault, windowTitle, kCFStringEncodingUTF8);
|
||||
|
||||
window = NULL;
|
||||
|
||||
err = CreateNewWindow(kMovableAlertWindowClass, kWindowStandardHandlerAttribute|kWindowCompositingAttribute, &rectWin, &window);
|
||||
err = SetWindowTitleWithCFString(window, szWindowTitle);
|
||||
err = SetThemeWindowBackground(window, kThemeBrushAlertBackgroundActive, false);
|
||||
assert(err == noErr);
|
||||
|
||||
// Event Handler Variables
|
||||
EventTypeSpec buttonSpec[] = {{ kEventClassControl, kEventControlHit }, { kEventClassCommand, kEventCommandProcess }};
|
||||
EventHandlerUPP buttonHandler = NewEventHandlerUPP(DoCommandEvent);
|
||||
|
||||
// Static Text Variables
|
||||
Rect rectStatic = {20, 20, 152, 530};
|
||||
CFStringRef szStaticText = CFStringCreateWithCString(kCFAllocatorDefault, prompt, kCFStringEncodingUTF8);
|
||||
ControlRef refStaticText = NULL;
|
||||
err = CreateStaticTextControl(window, &rectStatic, szStaticText, NULL, &refStaticText);
|
||||
|
||||
// Button Variables
|
||||
Rect bounds[numChoices];
|
||||
CFStringRef caption[numChoices];
|
||||
ControlRef button[numChoices];
|
||||
|
||||
int whichButton=-1;
|
||||
CallbackData callbackData[numChoices];
|
||||
|
||||
// Create the Buttons and assign event handlers
|
||||
for (int i = 0; i < numChoices; ++i) {
|
||||
bounds[i].top = 160 + ((CARBON_BUTTON_HEIGHT+CARBON_BUTTON_SPACING)*(i%iNumButtonRows));
|
||||
bounds[i].right = 530 - ((iButtonWidth+CARBON_BUTTON_SPACING)*(i/iNumButtonRows));
|
||||
bounds[i].left = bounds[i].right - iButtonWidth;
|
||||
bounds[i].bottom = bounds[i].top + CARBON_BUTTON_HEIGHT;
|
||||
|
||||
// Convert the button captions to Apple strings
|
||||
caption[i] = CFStringCreateWithCString(kCFAllocatorDefault, choice[i], kCFStringEncodingUTF8);
|
||||
|
||||
err = CreatePushButtonControl(window, &bounds[i], caption[i], &button[i]);
|
||||
assert(err == noErr);
|
||||
|
||||
err = SetControlCommandID(button[i], CARBON_COMMANDID_START + i);
|
||||
assert(err == noErr);
|
||||
|
||||
callbackData[i].refWindow = window;
|
||||
callbackData[i].myIndex = i;
|
||||
callbackData[i].whichButton = &whichButton;
|
||||
|
||||
err = InstallControlEventHandler(button[i], buttonHandler,
|
||||
GetEventTypeCount(buttonSpec), buttonSpec,
|
||||
&callbackData[i], NULL);
|
||||
assert(err == noErr);
|
||||
}
|
||||
|
||||
// Show Dialog
|
||||
err = RepositionWindow(window, NULL, kWindowCenterOnMainScreen);
|
||||
ShowWindow(window);
|
||||
BringToFront(window);
|
||||
err = ActivateWindow(window, true);
|
||||
|
||||
// Hack to get our window/process to the front...
|
||||
ProcessSerialNumber psn = { 0, kCurrentProcess};
|
||||
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
||||
SetFrontProcess (&psn);
|
||||
|
||||
// Run in Modal State
|
||||
err = RunAppModalLoopForWindow(window);
|
||||
|
||||
// Dispose of Button Related Data
|
||||
for (int i = 0; i < numChoices; ++i) {
|
||||
// Dispose of controls
|
||||
DisposeControl(button[i]);
|
||||
|
||||
// Release CFStrings
|
||||
CFRelease(caption[i]);
|
||||
}
|
||||
|
||||
// Dispose of Other Controls
|
||||
DisposeControl(refStaticText);
|
||||
|
||||
// Dispose of Event Handlers
|
||||
DisposeEventHandlerUPP(buttonHandler);
|
||||
|
||||
// Dispose of Window
|
||||
DisposeWindow(window);
|
||||
|
||||
// Release CFStrings
|
||||
CFRelease(szWindowTitle);
|
||||
CFRelease(szStaticText);
|
||||
|
||||
// Return Selection
|
||||
return whichButton;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int prompt(
|
||||
const char* windowTitle,
|
||||
const char* prompt,
|
||||
const char** choice,
|
||||
int numChoices,
|
||||
bool useGui) {
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
if (useGui) {
|
||||
// Build the message box
|
||||
return guiPrompt(windowTitle, prompt, choice, numChoices);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef G3D_OSX
|
||||
if (useGui){
|
||||
//Will default to text prompt if numChoices > 4
|
||||
return guiPrompt(windowTitle, prompt, choice, numChoices);
|
||||
}
|
||||
#endif
|
||||
return textPrompt(windowTitle, prompt, choice, numChoices);
|
||||
}
|
||||
|
||||
|
||||
void msgBox(
|
||||
const std::string& message,
|
||||
const std::string& title) {
|
||||
|
||||
const char *choice[] = {"Ok"};
|
||||
prompt(title.c_str(), message.c_str(), choice, 1, true);
|
||||
}
|
||||
|
||||
#ifndef G3D_WIN32
|
||||
#undef _getch
|
||||
#endif
|
||||
|
||||
};// namespace
|
||||
|
||||
-231
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
+12
-21
@@ -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.
|
||||
Vendored
+570
@@ -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
|
||||
+6
@@ -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
@@ -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
|
||||
+138
-44
@@ -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.
|
||||
+6
-8
@@ -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
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
+3
-3
@@ -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
|
||||
Vendored
+2
-2
@@ -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)
|
||||
Vendored
+121
@@ -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
@@ -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
-1
@@ -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
Reference in New Issue
Block a user