added everything

This commit is contained in:
Metario
2017-04-17 06:17:10 -06:00
commit 9c6ff74f19
6121 changed files with 1625704 additions and 0 deletions

363
lib/dtsSDKPlus/DTSDecimator.cpp Executable file
View File

@ -0,0 +1,363 @@
//-----------------------------------------------------------------------------
// Decimator
// based on "A Simple, Fast, and Effective Polygon Reduction Algorithm"
// by Stan Melax from Game Developer Magazine, November 1998
//-----------------------------------------------------------------------------
#pragma warning ( disable: 4786 4018 )
#include "DTSUtil.h"
#include "DTSDecimator.h"
namespace DTS
{
static std::vector<DecimatorVertex *> vertices;
static std::vector<DecimatorTriangle *> triangles;
DecimatorTriangle::DecimatorTriangle(DecimatorVertex *v0,DecimatorVertex *v1,DecimatorVertex *v2, S32 _type){
assert(v0!=v1 && v1!=v2 && v2!=v0);
vertex[0]=v0;
vertex[1]=v1;
vertex[2]=v2;
ComputeNormal();
triangles.push_back(this);
for(S32 i=0;i<3;i++) {
vertex[i]->face.push_back(this);
for(S32 j=0;j<3;j++) if(i!=j) {
addUniqueElement(vertex[i]->neighbor, vertex[j]);
}
}
type = _type;
}
DecimatorTriangle::~DecimatorTriangle(){
S32 i;
delElement( triangles, this );
for(i=0;i<3;i++) {
if(vertex[i]) delElement(vertex[i]->face,this);
}
for(i=0;i<3;i++) {
S32 i2 = (i+1)%3;
if(!vertex[i] || !vertex[i2]) continue;
vertex[i ]->RemoveIfNonNeighbor(vertex[i2]);
vertex[i2]->RemoveIfNonNeighbor(vertex[i ]);
}
}
S32 DecimatorTriangle::HasVertex(DecimatorVertex *v) {
return (v==vertex[0] ||v==vertex[1] || v==vertex[2]);
}
void DecimatorTriangle::ComputeNormal(){
Point v0=vertex[0]->position;
Point v1=vertex[1]->position;
Point v2=vertex[2]->position;
Point e1 = v1 - v0;
Point e2 = v2 - v1;
crossProduct( e1, e2, &normal );
normal.normalize();
}
void DecimatorTriangle::ReplaceVertex(DecimatorVertex *vold,DecimatorVertex *vnew) {
assert(vold && vnew);
assert(vold==vertex[0] || vold==vertex[1] || vold==vertex[2]);
assert(vnew!=vertex[0] && vnew!=vertex[1] && vnew!=vertex[2]);
if(vold==vertex[0]){
vertex[0]=vnew;
}
else if(vold==vertex[1]){
vertex[1]=vnew;
}
else {
assert(vold==vertex[2]);
vertex[2]=vnew;
}
S32 i;
delElement(vold->face,this);
assert(!containsElement(vnew->face,this));
vnew->face.push_back(this);
for(i=0;i<3;i++) {
vold->RemoveIfNonNeighbor(vertex[i]);
vertex[i]->RemoveIfNonNeighbor(vold);
}
for(i=0;i<3;i++) {
assert(containsElement(vertex[i]->face,this)==1);
for(S32 j=0;j<3;j++) if(i!=j) {
addUniqueElement( vertex[i]->neighbor, vertex[j]);
}
}
ComputeNormal();
}
DecimatorVertex::DecimatorVertex(Point v,S32 _id) {
position =v;
id=_id;
vertices.push_back(this);
}
DecimatorVertex::~DecimatorVertex(){
assert(face.size()==0);
while(neighbor.size()) {
delElement(neighbor[0]->neighbor,this);
delElement(neighbor,neighbor[0]);
}
delElement(vertices,this);
}
void DecimatorVertex::RemoveIfNonNeighbor(DecimatorVertex *n) {
// removes n from neighbor list if n isn't a neighbor.
if(!containsElement(neighbor,n)) return;
for(S32 i=0;i<face.size();i++) {
if(face[i]->HasVertex(n)) return;
}
delElement(neighbor,n);
}
S32 DecimatorVertex::IsBorder()
{
S32 i,j;
for(i=0;i<neighbor.size();i++)
{
S32 count=0;
for(j=0;j<face.size();j++)
{
if(face[j]->HasVertex(neighbor[i]))
{
count++;
}
}
assert(count>0);
if(count==1)
{
return 1;
}
}
return 0;
}
F32 Decimator::ComputeEdgeCollapseCost(DecimatorVertex *src,DecimatorVertex *dest) {
// if we collapse edge src/dest by moving src to dest then how
// much different will the model change, i.e. how much "error".
// Texture, vertex normal, and border vertex code was removed
// to keep this demo as simple as possible.
// The method of determining cost was designed in order
// to exploit small and coplanar regions for
// effective polygon reduction.
// Is is possible to add some checks here to see if "folds"
// would be generated. i.e. normal of a remaining face gets
// flipped. I never seemed to run into this problem and
// therefore never added code to detect this case.
S32 i;
Point p = dest->position - src->position;
F32 edgelength = p.length();
F32 curvature = 0;
// find the "sides" triangles that are on the edge uv
std::vector<DecimatorTriangle *> sides;
for( i = 0; i < src->face.size(); i++ )
{
if( src->face[i]->HasVertex( dest ) )
{
sides.push_back( src->face[i] );
}
}
if(src->IsBorder() )
{
if( sides.size() > 1 )
{
curvature = 1;
}
else
{
curvature = 1;
}
}
else
{
// use the triangle facing most away from the sides
// to determine our curvature term
for( i = 0; i < src->face.size(); i++ )
{
F32 mincurv = 1; // curve for face i and closer side to it
for( S32 j = 0; j < sides.size(); j++ )
{
// use dot product of face normals. '^' defined in Point
F32 dotprod = dotProduct( src->face[i]->normal, sides[j]->normal );
mincurv = getmin( mincurv, ( 1.0f - dotprod ) * 0.5f );
}
curvature = getmax( curvature, mincurv );
}
}
/*
// check for texture seam ripping
S32 nomatch=0;
for(i=0;i<src->face.num;i++) {
for(S32 j=0;j<sides.num;j++) {
// perhaps we should actually compare the positions in uv space
if(src->face[i]->texat(src) == sides[j]->texat(src)) break;
}
if(j==sides.num)
{
// we didn't find a triangle with edge uv that shares texture coordinates
// with face i at vertex src
nomatch++;
}
}
if(nomatch) {
curvature=1;
}
*/
return edgelength * curvature;
}
void Decimator::ComputeEdgeCostAtVertex(DecimatorVertex *v) {
// compute the edge collapse cost for all edges that start
// from vertex v. Since we are only interested in reducing
// the object by selecting the min cost edge at each step, we
// only cache the cost of the least cost edge at this vertex
// (in member variable collapse) as well as the value of the
// cost (in member variable objdist).
if(v->neighbor.size()==0) {
// v doesn't have neighbors so it costs nothing to collapse
v->collapse=NULL;
v->objdist=-0.01f;
return;
}
v->objdist = 1000000;
v->collapse=NULL;
// search all neighboring edges for "least cost" edge
for(S32 i=0;i<v->neighbor.size();i++) {
F32 dist;
dist = ComputeEdgeCollapseCost(v,v->neighbor[i]);
if(dist<v->objdist) {
v->collapse=v->neighbor[i]; // candidate for edge collapse
v->objdist=dist; // cost of the collapse
}
}
}
void Decimator::ComputeAllEdgeCollapseCosts() {
// For all the edges, compute the difference it would make
// to the model if it was collapsed. The least of these
// per vertex is cached in each vertex object.
for(S32 i=0;i<vertices.size();i++) {
ComputeEdgeCostAtVertex(vertices[i]);
}
}
void Decimator::Collapse(DecimatorVertex *u,DecimatorVertex *v){
// Collapse the edge uv by moving vertex u onto v
// Actually remove tris on uv, then update tris that
// have u to have v, and then remove u.
if(!v) {
// u is a vertex all by itself so just delete it
delete u;
return;
}
S32 i;
std::vector<DecimatorVertex *>tmp;
// make tmp a list of all the neighbors of u
for(i=0;i<u->neighbor.size();i++) {
tmp.push_back(u->neighbor[i]);
}
// delete triangles on edge uv:
for(i=u->face.size()-1;i>=0;i--) {
if(u->face[i]->HasVertex(v)) {
delete(u->face[i]);
}
}
// update remaining triangles to have v instead of u
for(i=u->face.size()-1;i>=0;i--) {
u->face[i]->ReplaceVertex(u,v);
}
delete u;
// recompute the edge collapse costs for neighboring vertices
for(i=0;i<tmp.size();i++) {
ComputeEdgeCostAtVertex(tmp[i]);
}
}
DecimatorVertex *Decimator::MinimumCostEdge(){
// Find the edge that when collapsed will affect model the least.
// This function actually returns a Vertex, the second vertex
// of the edge (collapse candidate) is stored in the vertex data.
// Serious optimization opportunity here: this function currently
// does a sequential search through an unsorted list :-(
// Our algorithm could be O(n*lg(n)) instead of O(n*n)
DecimatorVertex *mn=vertices[0];
for(S32 i=0;i<vertices.size();i++) {
if(vertices[i]->objdist < mn->objdist) {
mn = vertices[i];
}
}
return mn;
}
// Public interface
Decimator::Decimator(std::vector<Primitive>& faces, std::vector<U16>& indices, std::vector<Point>& verts)
{
// Add the vertices
for( S32 i = 0; i < verts.size(); i++ )
{
DecimatorVertex *v = new DecimatorVertex( verts[i], i );
}
// Add the faces
for( S32 i = 0; i < faces.size(); i++ )
{
DecimatorTriangle *t=new DecimatorTriangle(
vertices[indices[faces[i].firstElement]],
vertices[indices[faces[i].firstElement+1]],
vertices[indices[faces[i].firstElement+2]],
faces[i].type );
}
ComputeAllEdgeCollapseCosts(); // cache all edge collapse costs
}
Decimator::~Decimator()
{
for( S32 i = triangles.size() - 1; i >= 0; i-- )
{
DecimatorTriangle *tmp = triangles[i];
//triangles.Remove(tmp);
delete tmp;
}
for( S32 i = vertices.size() - 1; i >= 0; i-- )
{
DecimatorVertex *tmp = vertices[i];
//vertices.Remove(tmp);
delete tmp;
}
}
void Decimator::ReduceMesh( S32 faceCount )
{
// reduce the object
while(triangles.size() > faceCount)
{
// get the next vertex to collapse
DecimatorVertex *mn = MinimumCostEdge();
// Collapse this edge
Collapse(mn,mn->collapse);
}
primitives.empty();
indices.empty();
// Build our new primitive and index list
for( S32 i = 0; i < triangles.size(); i++ )
{
if( triangles[i]->vertex[0] != NULL && triangles[i]->vertex[1] != NULL && triangles[i]->vertex[2] != NULL )
{
Primitive p;
p.firstElement = indices.size();
p.numElements = 3;
p.type = triangles[i]->type;
primitives.push_back( p );
indices.push_back( triangles[i]->vertex[0]->id );
indices.push_back( triangles[i]->vertex[1]->id );
indices.push_back( triangles[i]->vertex[2]->id );
}
}
}
}

81
lib/dtsSDKPlus/DTSDecimator.h Executable file
View File

@ -0,0 +1,81 @@
//-----------------------------------------------------------------------------
// Decimator
// based on "A Simple, Fast, and Effective Polygon Reduction Algorithm"
// by Stan Melax from Game Developer Magazine, November 1998
//-----------------------------------------------------------------------------
#ifndef __DTS_DECIMATOR_H
#define __DTS_DECIMATOR_H
#include "DTSMesh.h"
#include "DTSPoint.h"
namespace DTS
{
/*
* For the polygon reduction algorithm we use data structures
* that contain a little bit more information than the usual
* indexed face set type of data structure.
* From a vertex we wish to be able to quickly get the
* neighboring faces and vertices.
*/
class DecimatorTriangle;
class DecimatorVertex;
class DecimatorVector;
class DecimatorTriangle
{
public:
DecimatorVertex* vertex[3]; // the 3 points that make this tri
Point normal; // unit vector othogonal to this face
S32 type;
DecimatorTriangle(DecimatorVertex *v0,DecimatorVertex *v1,DecimatorVertex *v2, S32 _type);
~DecimatorTriangle();
void ComputeNormal();
void ReplaceVertex(DecimatorVertex *vold,DecimatorVertex *vnew);
S32 HasVertex(DecimatorVertex *v);
};
class DecimatorVertex
{
public:
Point position; // location of point in euclidean space
S32 id; // place of vertex in original list
std::vector<DecimatorVertex *> neighbor; // adjacent vertices
std::vector<DecimatorTriangle *> face; // adjacent triangles
F32 objdist; // cached cost of collapsing edge
DecimatorVertex* collapse; // candidate vertex for collapse
DecimatorVertex(Point v,S32 _id);
~DecimatorVertex();
S32 IsBorder();
void RemoveIfNonNeighbor(DecimatorVertex *n);
};
class Decimator
{
private:
F32 ComputeEdgeCollapseCost(DecimatorVertex *u,DecimatorVertex *v);
void ComputeEdgeCostAtVertex(DecimatorVertex *v);
void ComputeAllEdgeCollapseCosts();
void Collapse(DecimatorVertex *u,DecimatorVertex *v);
DecimatorVertex *MinimumCostEdge();
std::vector<Primitive> primitives;
std::vector<U16> indices;
public:
Decimator(std::vector<Primitive>& faces, std::vector<U16>& indices, std::vector<Point>& verts);
~Decimator();
void ReduceMesh( S32 numFaces );
void GetMesh(std::vector<Primitive>& p, std::vector<U16>& i) { p=primitives; i=indices; }
};
}
#endif

49
lib/dtsSDKPlus/DTSPlusTypes.h Executable file
View File

@ -0,0 +1,49 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef DTSPLUSTYPES_H_
#define DTSPLUSTYPES_H_
typedef signed char S8; // Compiler independent Signed Char
typedef unsigned char U8; // Compiler independent Unsigned Char
typedef signed short S16; // Compiler independent Signed 16-bit short
typedef unsigned short U16; // Compiler independent Unsigned 16-bit short
typedef signed int S32; // Compiler independent Signed 32-bit integer
typedef unsigned int U32; // Compiler independent Unsigned 32-bit integer
typedef float F32; // Compiler independent 32-bit F32
typedef double F64; // Compiler independent 64-bit F32
// Simple template used to make sure some operation
// gets executed before going out of scope
template <class Type> class OnDestroy
{
protected:
Type * mObj;
void transfer(OnDestroy<Type> * des)
{
doit();
if (des)
{
mObj = des->mObj;
des->mObj=NULL;
}
}
virtual void doit() = 0;
public:
OnDestroy(Type * obj=NULL) { mObj=obj; }
OnDestroy(OnDestroy<Type> & des) { transfer(&des); }
virtual ~OnDestroy() {}
void operator=(OnDestroy<Type> & des) { transfer(&des); }
};
#endif // DTSPLUSTYPES_H_

394
lib/dtsSDKPlus/DTSUtil.cpp Executable file
View File

@ -0,0 +1,394 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786 4018)
#endif
#include "DTSUtil.h"
#include "appConfig.h"
#include "decomp/Decompose.h"
#include <stdarg.h>
#define TEST_DTS_MATH
namespace DTS
{
const char* avar(const char *message, ...)
{
static char buffer[4096];
va_list args;
va_start(args, message);
vsprintf(buffer, message, args);
return( buffer );
}
bool isEqualQ16(const Quaternion & a, const Quaternion &b)
{
U16 MAX_VAL = 0x7fff;
// convert components to 16 bit, then test for equality
S16 x, y, z, w;
x = ((S16)(a.x() * F32(MAX_VAL))) - ((S16)(b.x() * F32(MAX_VAL)));
y = ((S16)(a.y() * F32(MAX_VAL))) - ((S16)(b.y() * F32(MAX_VAL)));
z = ((S16)(a.z() * F32(MAX_VAL))) - ((S16)(b.z() * F32(MAX_VAL)));
w = ((S16)(a.w() * F32(MAX_VAL))) - ((S16)(b.w() * F32(MAX_VAL)));
return (x==0) && (y==0) && (z==0) && (w==0);
}
void crossProduct(const Point3D & a, const Point3D & b, Point3D * c)
{
c->x(a.y() * b.z() - a.z() * b.y());
c->y(a.z() * b.x() - a.x() * b.z());
c->z(a.x() * b.y() - a.y() * b.x());
}
void convertToTransform(Matrix<4,4,F32> & mat, Quaternion & rot, Point3D & trans, Quaternion & srot, Point3D & scale)
{
AffineParts parts;
decomp_affine(mat,&parts);
trans = parts.trans;
rot = parts.rot;
srot = parts.scaleRot;
scale = parts.scale;
}
void decomp_affine(const Matrix<4,4,F32> & mat, AffineParts * parts)
{
GraphicGems::HMatrix ggMat;
GraphicGems::AffineParts ggParts;
for (S32 i=0; i<4; i++)
{
for (S32 j=0; j<4; j++)
ggMat[i][j] = mat[i][j];
}
GraphicGems::decomp_affine(ggMat,&ggParts);
parts->rot = Quaternion(F32(ggParts.q.x),F32(ggParts.q.y),F32(ggParts.q.z),F32(ggParts.q.w));
parts->scale = Point3D(F32(ggParts.k.x),F32(ggParts.k.y),F32(ggParts.k.z));
parts->scaleRot = Quaternion(F32(ggParts.u.x),F32(ggParts.u.y),F32(ggParts.u.z),F32(ggParts.u.w));
parts->trans = Point3D(F32(ggParts.t.x),F32(ggParts.t.y),F32(ggParts.t.z));
parts->sign = F32(ggParts.f);
#ifdef TEST_DTS_MATH
// Test math (but only in the unscaled case
if (isEqual(parts->scale.x(),1.0f,0.01f) && isEqual(parts->scale.y(),1.0f,0.01f) && isEqual(parts->scale.z(),1.0f,0.01f))
{
Matrix<4,4,F32> mat2 = parts->rot.toMatrix();
Vector<F32,4> col;
col[0] = parts->trans.x();
col[1] = parts->trans.y();
col[2] = parts->trans.z();
col[3] = 1;
mat2.setCol(3,col);
for (S32 i=0; i<4; i++)
{
for (S32 ii=0; ii<4; ii++)
{
if (!isEqual(mat[i][ii],mat2[i][ii],0.01f))
AppConfig::PrintDump(-1,"Doh!");
}
}
}
#endif
}
void zapScale(Matrix<4,4,F32> & mat)
{
AffineParts parts;
decomp_affine(mat,&parts);
// now put the matrix back together again without the scale:
// mat = mat.rot * mat.pos
Vector<F32,4> trans;
trans[0] = parts.trans.x();
trans[1] = parts.trans.y();
trans[2] = parts.trans.z();
trans[3] = 1;
mat = parts.rot.toMatrix();
mat.setCol(3,trans);
#ifdef TEST_DTS_MATH
{
// A test...will get rid of once we know it works...
Matrix<4,4,F32> mat2;
decomp_affine(mat,&parts);
trans[0] = parts.trans.x();
trans[1] = parts.trans.y();
trans[2] = parts.trans.z();
trans[3] = 1;
mat2 = parts.rot.toMatrix();
mat2.setCol(3,trans);
for (S32 i=0; i<4; i++)
{
for (S32 j=0; j<4; j++)
{
assert(isZero(mat[i][j]-mat2[i][j],0.01f));
}
}
}
#endif
}
Matrix<4,4,F32> & getLocalNodeMatrix(AppNode * node, AppNode * parent, const AppTime & time, Matrix<4,4,F32> & matrix, AffineParts & a10, AffineParts & a20)
{
// Here's the story: the default transforms have no scale. In order to account for scale, the
// scale at the default time is folded into the object offset (which is multiplied into the points
// before exporting). Because of this, the local transform at a given time must take into account
// the scale of the parent and child node at time 0 in addition to the current time. In particular,
// the world transform at a given time is WT(time) = T(time) * inverse(Tscale(0))
// in order to avoid recomputing matrix at default time over and over, we assume that the first request
// for the matrix will be at the default time, and thereafter, we will pass that matrix in and reuse it...
Matrix<4,4,F32> m1 = node->getNodeTransform(time);
Matrix<4,4,F32> m2;
if (parent)
m2 = parent->getNodeTransform(time);
else
m2 = Matrix<4,4,F32>::identity();
if (time == AppTime::DefaultTime())
{
decomp_affine(m1,&a10);
decomp_affine(m2,&a20);
}
// build the inverse scale matrices
Matrix<4,4,F32> stretchRot10,stretchRot20;
Matrix<4,4,F32> scaleMat10,scaleMat20;
Matrix<4,4,F32> invScale10, invScale20;
Point3D sfactor10, sfactor20;
stretchRot10 = a10.scaleRot.toMatrix();
stretchRot20 = a20.scaleRot.toMatrix();
sfactor10 = Point3D(a10.sign/a10.scale.x(),a10.sign/a10.scale.y(),a10.sign/a10.scale.z());
sfactor20 = Point3D(a20.sign/a20.scale.x(),a20.sign/a20.scale.y(),a20.sign/a20.scale.z());
scaleMat10 = Matrix<4,4,F32>::identity();
scaleMat10[0][0] = sfactor10.x();
scaleMat10[1][1] = sfactor10.y();
scaleMat10[2][2] = sfactor10.z();
scaleMat20 = Matrix<4,4,F32>::identity();
scaleMat20[0][0] = sfactor20.x();
scaleMat20[1][1] = sfactor20.y();
scaleMat20[2][2] = sfactor20.z();
invScale10 = stretchRot10 * scaleMat10 * stretchRot10.inverse();
invScale20 = stretchRot20 * scaleMat20 * stretchRot20.inverse();
// build world transforms
m1 = m1 * invScale10;
m2 = m2 * invScale20;
// build local transform
matrix = m2.inverse() * m1;
#ifdef TEST_DTS_MATH
{
Matrix<4,4,F32> testMat;
Matrix<4,4,F32> m2inv = m2.inverse();
testMat = m2inv * m2;
{
for (S32 i=0; i<4; i++)
for (S32 j=0; j<4; j++)
{
F32 val = i==j ? 1.0f : 0.0f;
assert(isEqual(testMat[i][j],val,0.01f) && "assertion failed");
}
}
testMat = m2 * m2inv;
{
for (S32 i=0; i<4; i++)
for (S32 j=0; j<4; j++)
{
F32 val = i==j ? 1.0f : 0.0f;
assert(isEqual(testMat[i][j],val,0.01f) && "assertion failed");
}
}
}
#endif
return matrix;
}
void getLocalNodeTransform(AppNode * node, AppNode * parent, AffineParts & child0, AffineParts & parent0, const AppTime & time, Quaternion & rot, Point3D & trans, Quaternion & srot, Point3D & scale)
{
Matrix<4,4,F32> localMat;
getLocalNodeMatrix(node,parent,time,localMat,child0,parent0);
convertToTransform(localMat,rot,trans,srot,scale);
}
void getBlendNodeTransform(AppNode * node, AppNode * parent, AffineParts & child0, AffineParts & parent0, const AppTime & time, const AppTime & referenceTime, Quaternion & rot, Point3D & trans, Quaternion & srot, Point3D & scale)
{
Matrix<4,4,F32> m1, invm1, m2, retMat;
getLocalNodeMatrix(node, parent, referenceTime, m1, child0, parent0);
getLocalNodeMatrix(node, parent, time, m2, child0, parent0);
invm1 = m1.inverse();
retMat = invm1 * m2;
convertToTransform(retMat, rot,trans,srot,scale);
}
void getDeltaTransform(AppNode * node, const AppTime & time1, const AppTime & time2, Quaternion & rot, Point3D & trans, Quaternion & srot, Point3D & scale)
{
Matrix<4,4,F32> m1 = node->getNodeTransform(time1);
Matrix<4,4,F32> m2 = node->getNodeTransform(time2);
zapScale(m1);
zapScale(m2);
convertToTransform(m1.inverse() * m2,rot,trans,srot,scale);
}
bool neverAnimateNode(AppNode*)
{
return false;
}
char * chopNum(char * s)
{
if (s==NULL)
return NULL;
char * p = s + strlen(s);
if (p==s)
return s;
p--;
// trim spaces from the end
while (p!=s && *p==' ')
p--;
// back up until we reach a non-digit
// gotta be better way than this...
if (isdigit(*p))
do
{
if (p--==s)
return p+1;
} while (isdigit(*p));
// allow negative numbers, treat _ as - for Maya
if (*p=='-' || *p=='_')
p--;
// trim spaces separating name and number
while (*p==' ')
{
p--;
if (p==s)
return p;
}
// return first space if there was one,
// o.w. return first digit
return p+1;
}
char * chopTrailingNumber(const char * fullName, S32 & size)
{
if (!fullName)
{
size = -1;
return NULL;
}
char * buffer = strnew(fullName);
char * p = chopNum(buffer);
if (*p=='\0')
{
size = -1;
return buffer;
}
size = 1;
if (*p=='_')
size = -atoi(p+1);
else
size = atoi(p);
*p='\0'; // terminate string
return buffer;
}
S32 getTrailingNumber(const char * fullName)
{
S32 size;
delete [] chopTrailingNumber(fullName,size);
return size;
}
void tweakName(const char ** name)
{
char * pre[] = { "BB::", "BBZ::", "SORT::", "SEQUENCE::",
"BB_" , "BBZ_" , "SORT_" , "SEQUENCE_" , "" };
for (S32 i=0; strlen(pre[i]) != 0; i++)
{
if (!_strnicmp(*name,pre[i],strlen(pre[i])))
{
// found prefix...now skip the prefix and return
*name += strlen(pre[i]);
break;
}
}
}
const char * getFileBase(const char * str)
{
const char * ret = strrchr(str,'/');
if (!ret)
ret = strrchr(str,'\\');
if (!ret)
ret = strrchr(str,':');
if (!ret)
ret = str;
else
++ret;
return ret;
}
char * getFileBase(char * str)
{
return (char*)getFileBase((const char*)str);
}
char * getFilePath(const char * str, S32 pad)
{
const char * slash = getFileBase(str);
S32 len = slash-str;
char * ret = new char[len+1+pad];
strncpy(ret,str,len);
ret[len]='\0';
return ret;
}
// perform string compare with wildcards (in s2 only) and case insensitivity
bool stringEqual(const char * s1, const char * s2)
{
if (*s1=='\0' && *s2=='\0')
return true;
if (*s2=='*')
{
if (stringEqual(s1,s2+1))
return true;
if (*s1=='\0')
return false;
return stringEqual(s1+1,s2);
}
if (toupper(*s1)==toupper(*s2))
return stringEqual(s1+1,s2+1);
return false;
}
char * removeExt(char * str)
{
char * tmp = _strdup(str);
char * ext = strrchr(tmp,'.');
if (ext)
*ext = 0;
return tmp;
}
};

176
lib/dtsSDKPlus/DTSUtil.h Executable file
View File

@ -0,0 +1,176 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef DTSUTIL_H_
#define DTSUTIL_H_
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSPlusTypes.h"
#include "appNode.h"
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#endif
namespace DTS
{
#ifndef M_PI
const F64 M_PI = 3.14159265358979323846;
#endif
const S8 PATH_DELIM_CHAR = '\\';
const S8 PATH_DELIM_STR[] = "\\";
template <class T> inline const T & getmax(const T & t1, const T & t2) { return t1>t2 ? t1 : t2; }
template <class T> inline const T & getmin(const T & t1, const T & t2) { return t1<t2 ? t1 : t2; }
// don't like std:vector insert/erase...
template <class T> inline void delElementAtIndex(std::vector<T> & vec, S32 idx)
{
vec.erase(vec.begin() + idx);
}
template <class T> inline void insElementAtIndex(std::vector<T> & vec, S32 idx, const T & el)
{
vec.insert(vec.begin() + idx,el);
}
template <class T> inline void delElement(std::vector<T> & vec, const T & el)
{
for(S32 i=0;i<vec.size();i++) {
if(vec[i] == el)
{
vec.erase(vec.begin() + i);
return;
}
}
}
template <class T> inline bool containsElement(std::vector<T> & vec, const T & el )
{
S32 count = 0;
for(S32 i=0;i<vec.size();i++)
{
if(vec[i] == el)
count++;
}
if (count > 0)
return true;
else
return false;
}
template <class T> inline void addUniqueElement(std::vector<T> & vec, const T & el )
{
if( !containsElement(vec, el) )
vec.push_back(el);
}
// add a method that Torque vectors has but std::vectors don't
template <class T>
inline void appendVector(std::vector<T> & m1, const std::vector<T> & m2) { m1.insert(m1.end(),m2.begin(),m2.end()); }
inline bool isZero(F32 f, F32 tol) { return fabs(f)<tol; }
inline bool isZero(const Point2D & a, F32 tol) { return isZero(a.x(),tol) && isZero(a.y(),tol); }
inline bool isZero(const Point3D & a, F32 tol) { return isZero(a.x(),tol) && isZero(a.y(),tol) && isZero(a.z(),tol); }
inline bool isZero(const Quaternion & a, F32 tol) { isZero(a.x(),tol) && isZero(a.y(),tol) && isZero(a.z(),tol) && isZero(a.w(),tol); }
inline bool isEqual(F32 a, F32 b, F32 tol) { return isZero(a-b,tol); }
inline bool isEqual(const Point2D & a, const Point2D & b, F32 tol) { return isZero(a-b,tol); }
inline bool isEqual(const Point3D & a, const Point3D & b, F32 tol) { return isZero(a-b,tol); }
inline bool isEqual(const Quaternion & a, const Quaternion & b, F32 tol) { return isZero(a-b,tol); }
extern bool isEqualQ16(const Quaternion & a, const Quaternion &b);
inline F32 dotProduct(const Point3D & a, const Point3D & b) { return a.x() * b.x() + a.y() * b.y() + a.z() * b.z(); }
extern void crossProduct(const Point3D & a, const Point3D & b, Point3D * c);
template <class T>
inline T* constructInPlace(T* p)
{
return new(p) T;
}
template <class T>
inline void destructInPlace(T* p)
{
p->~T();
}
struct AffineParts
{
Point3D trans; // Translation components
Quaternion rot; // Essential rotation
Quaternion scaleRot; // Stretch rotation
Point3D scale; // Stretch factors
F32 sign; // Sign of determinant
};
extern void decomp_affine(const Matrix<4,4,F32> &, AffineParts *);
extern void zapScale(Matrix<4,4,F32> &);
extern void getLocalNodeTransform(AppNode * node, AppNode * parent, AffineParts & child0, AffineParts & parent0, const AppTime & time, Quaternion & rot, Point3D & trans, Quaternion & srot, Point3D & scale);
extern void getBlendNodeTransform(AppNode * node, AppNode * parent, AffineParts & child0, AffineParts & parent0, const AppTime & time, const AppTime & referenceTime, Quaternion & rot, Point3D & trans, Quaternion & srot, Point3D & scale);
extern void getDeltaTransform(AppNode * node, const AppTime & time1, const AppTime & time2, Quaternion & rot, Point3D & trans, Quaternion & srot, Point3D & scale);
inline void setMembershipArray(std::vector<bool> & m, bool setTo, S32 a, S32 b)
{
if (m.size() < U32(b))
m.resize(b);
for (S32 i=a; i<b; i++)
m[i]=setTo;
}
inline void setMembershipArray(std::vector<bool> & m, bool setTo, S32 a)
{
m[a]=setTo;
}
inline bool allSet(std::vector<bool> & m)
{
for (U32 i=0; i<m.size(); i++)
{
if (m[i]) return true;
}
return false;
}
inline void overlapSet(std::vector<bool> & m1, const std::vector<bool> & m2)
{
assert(m1.size()==m2.size());
for (U32 i=0; i<m2.size(); i++)
{
if (m2[i])
m1[i]=true;
}
}
inline void subtractSet(std::vector<bool> & m1, const std::vector<bool> & m2)
{
assert(m1.size()==m2.size());
for (U32 i=0; i<m2.size(); i++)
{
if (m2[i])
m1[i]=false;
}
}
extern S32 getTrailingNumber(const char * fullName);
extern char * chopTrailingNumber(const char * fullName, S32 & size);
extern void tweakName(const char ** name);
extern const char* avar(const char *in_msg, ...);
extern bool stringEqual(const char * s1, const char * s2);
inline char * strnew(const char * str) { char * ret = new char[strlen(str)+1]; strcpy(ret,str); return ret; }
extern char * getFileBase(char * str);
extern const char * getFileBase(const char * str);
extern char * getFilePath(const char * str, S32 pad=0);
inline char * strnew(std::string str) { return strnew(str.c_str()); }
extern char * removeExt(char * str);
};
#endif // DTSUTIL_H_

3960
lib/dtsSDKPlus/ShapeMimic.cpp Executable file

File diff suppressed because it is too large Load Diff

301
lib/dtsSDKPlus/ShapeMimic.h Executable file
View File

@ -0,0 +1,301 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
// The ShapeMimic tries to hold court in both the App world and
// the Torque three-space world. It holds a shape tree isomorphic
// to what the shape will look like when exported, but maintains
// links to App objects and delays computing certain things
// until the tsshape is finally created in generateShape().
#ifndef SHAPEMIMIC_H_
#define SHAPEMIMIC_H_
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSPlusTypes.h"
#include "DTSUtil.h"
#include "appNode.h"
#include "appMesh.h"
#include "appSequence.h"
#include "appIfl.h"
#include "appConfig.h"
namespace DTS
{
struct IflMimic
{
AppIfl * appIfl;
S32 materialSlot;
};
struct SkinMimic
{
typedef std::vector<F32> WeightList;
AppMesh * appMesh;
Mesh * skinMesh;
S32 detailSize;
S32 skinNum;
S32 meshNum;
F32 multiResPercent;
std::vector<Primitive> faces;
std::vector<Point3D> verts;
std::vector<Point3D> normals;
std::vector<Point2D> tverts;
std::vector<U16> indices;
std::vector<U32> smoothingGroups;
std::vector<U32> vertId;
std::vector<AppNode *> bones;
std::vector<WeightList*> weights;
~SkinMimic() { for (U32 i=0;i<weights.size(); i++) delete weights[i]; multiResPercent = 1.0f; }
};
struct MeshMimic
{
AppMesh * appMesh;
Mesh * tsMesh;
SkinMimic * skinMimic;
bool billboard; // i.e., face camera
bool sortedObject;
S32 numVerts; // number of unique vertices
S32 meshNum;
std::vector<U32> smoothingGroups;
std::vector<U32> remap;
std::vector<U32> vertId;
F32 multiResPercent;
Matrix<4,4,F32> objectOffset; // NOTE: not valid till late in the game
MeshMimic(AppMesh * mesh) { appMesh = mesh; skinMimic = NULL; tsMesh = NULL; multiResPercent = 1.0f; }
};
struct ObjectMimic
{
enum { MaxDetails=20 };
struct Detail
{
S32 size;
F32 multiResPercent;
MeshMimic * mesh;
};
// object name
char * name;
char * fullName; // name of object in tree
// each object has several meshes attached
S32 numDetails;
Detail details[MaxDetails];
// we'll check the object against this list in the end
std::vector<S32> * validDetails;
AppNode * inTreeNode; // this is the node that sits in the shape's node hierrarchy
AppMesh * inTreeMesh; // this is the mesh that sits in the shape's node hierrarchy
// The next two items are used for sorting objects
// objects are sorted by subTreeNum first, and then
// priority (smallest to highest in both cases).
S32 subtreeNum;
U32 priority;
// The node in the 3D app this object hangs on (i.e., the one in the shape not
// the loose objects that make up the detail levels).
AppNode * appParent;
// Similar to above: the app node that corresponds to tsNode that will
// be our parent. Starts out the same as appParent, but is revised
// as we prune unwanted nodes from the tree structure.
AppNode * appTSParent;
// ts node index we hang off
S32 tsNodeIndex;
S32 tsObjectIndex;
// This is the eventual payoff
DTS::Object * tsObject;
//
bool isBone;
bool isSkin;
AppMesh * getSkin()
{
for (S32 dl=0; dl<numDetails; dl++)
if (details[dl].mesh)
return details[dl].mesh->skinMimic ? details[dl].mesh->skinMimic->appMesh : NULL;
return NULL;
}
~ObjectMimic()
{
delete [] name;
delete [] fullName;
for (S32 i=0;i<numDetails;i++)
delete details[i].mesh;
}
};
struct NodeMimic
{
// our twin in the max world:
AppNode * appNode;
// our neighbors in the mimic world:
NodeMimic * parent;
NodeMimic * child;
NodeMimic * sibling;
// transforms at default time
AffineParts child0;
AffineParts parent0;
// index of our ts version
S32 number;
// our mimic object
std::vector<ObjectMimic*> objects;
};
class ShapeMimic
{
struct Subtree
{
std::vector<S32> validDetails;
std::vector<const char*> detailNames;
std::vector<AppNode*> detailNodes;
NodeMimic start;
};
std::vector<Subtree*> subtrees;
std::vector<ObjectMimic*> objectList;
std::vector<SkinMimic*> skins;
std::vector<IflMimic*> iflList;
std::vector<AppSequence*> sequences;
std::vector<Material> materials;
AppNode * boundsNode;
// this gets filled in late in the game
// it holds the nodes that actually go into the shape
// in the order they appear in the shape
std::vector<NodeMimic*> nodes;
static std::vector<Quaternion*> nodeRotCache;
static std::vector<Point3D*> nodeTransCache;
static std::vector<Quaternion*> nodeScaleRotCache;
static std::vector<Point3D*> nodeScaleCache;
static std::vector<AppNode*> cutNodes;
static std::vector<AppNode*> cutNodesParents;
// error control
//void setExportError(const char * errStr) { AppConfig::SetExportError(errStr); }
//const char * getError() { return AppConfig::GetExportError(); }
//bool isError() { return AppConfig::IsExportError(); }
// called by generateShape
void generateBounds(Shape * shape);
void generateDetails(Shape * shape);
void generateSubtrees(Shape * shape);
void generateObjects(Shape * shape);
void generateDefaultStates(Shape * shape);
void generateIflMaterials(Shape * shape);
void generateSequences(Shape * shape);
void generateMaterialList(Shape * shape);
void generateSkins(Shape * shape);
void optimizeMeshes(Shape * shape);
void convertSortObjects(Shape * shape);
void initShape(Shape*);
// deeper generate methods...
void generateBillboardDetail(AppNode * detailNode, DetailLevel & detail);
void sortTSDetails(std::vector<DTS::DetailLevel> & details);
void setObjectPriorities(std::vector<ObjectMimic*> & objects);
void sortObjectList(std::vector<ObjectMimic*> & objects);
void generateNodeTransform(NodeMimic *, const AppTime & time, bool blend, const AppTime & blendReferenceTime, Quaternion & rot, Point3D & trans, Quaternion & qrot, Point3D & scale);
void generateObjectState(ObjectMimic *, const AppTime & time, Shape *, bool addFrame, bool addMatFrame);
// generate animation data
void generateFrame(ObjectMimic *, const AppTime & time, bool addFrame, bool addMatFrame);
void generateGroundAnimation(Shape *, Sequence &, AppSequenceData &);
void generateObjectAnimation(Shape *, Sequence &, AppSequenceData &);
void generateFrameTriggers(Shape *, Sequence &, AppSequenceData &, AppSequence *);
void generateNodeAnimation(Shape *, Sequence &, AppSequenceData &);
// add transform data
void addNodeRotation(NodeMimic *, const AppTime & time, Shape *, bool blend, Quaternion & rot, bool defaultVal);
void addNodeTranslation(NodeMimic *, const AppTime & time, Shape *, bool blend, Point3D & trans, bool defaultVal);
void addNodeUniformScale(NodeMimic *, const AppTime & time, Shape *, bool blend, F32 scale);
void addNodeAlignedScale(NodeMimic *, const AppTime & time, Shape *, bool blend, Point3D & scale);
void addNodeArbitraryScale(NodeMimic *, const AppTime & time, Shape *, bool blend, Quaternion & qrot, Point3D & scale);
// membership tests for animation
void setIflMembership(Shape *, Sequence &, AppSequenceData &, S32 & iflCount);
S32 setObjectMembership(Shape *, Sequence &, AppSequenceData &, S32 & objectCount);
void setNodeMembership(Shape *, Sequence &, AppSequenceData &,
S32 & rotCount, S32 & transCount,
S32 & uniformScaleCount, S32 & alignedScaleCount, S32 & arbitraryScaleCount);
void setRotationMembership(Shape *, Sequence &, AppSequenceData &, S32 & rotCount);
void setTranslationMembership(Shape *, Sequence &, AppSequenceData &, S32 & transCount);
void setScaleMembership(Sequence &, AppSequenceData &, S32 & arbitraryScale, S32 & alignedScale, S32 & uniformScale);
bool animatesAlignedScale(AppSequenceData &);
bool animatesArbitraryScale(AppSequenceData &);
S32 setUniformScaleMembership(Sequence &, AppSequenceData &);
S32 setAlignedScaleMembership(Sequence &, AppSequenceData &);
S32 setArbitraryScaleMembership(Sequence &, AppSequenceData &);
// add material from mesh
S32 addFaceMaterial(AppMesh *,S32 faceNum);
S32 addMaterial(Material mat);
// utility methods
void fillNodeTransformCache(std::vector<NodeMimic*> &, Sequence &, AppSequenceData &);
ObjectMimic * addObject(AppNode *, AppMesh *, std::vector<S32> * validDetails);
ObjectMimic * addObject(AppNode * node, AppMesh * mesh, std::vector<S32> * validDetails, bool multiRes, S32 multiResSize=-1, F32 multiResPercent=1.0f);
ObjectMimic * getObject(AppNode *, AppMesh *, char * name, S32 size, S32 * detailNum, F32 multiResPercent, bool matchFullName = true, bool isBone=false, bool isSkin=false);
ObjectMimic * addBoneObject(AppNode * node, S32 subtreeNum);
MeshMimic * addSkinObject(SkinMimic * skinMimic);
S32 addName(const char *, Shape * shape);
void computeNormals(std::vector<Primitive> &, std::vector<U16> & indices, std::vector<Point3D> & verts, std::vector<Point3D> & norms, std::vector<U32> & smooth, S32 vertsPerFrame, S32 numFrames);
void copyWeightsToVerts(SkinMimic * skinMimic);
void collapseVertices(Mesh *, std::vector<U32> & smooth, std::vector<U32> & remap, std::vector<U32> * vertId);
bool vertexSame(Point3D & v1, Point3D & v2, Point2D & tv1, Point2D & tv2, U32 smooth1, U32 smooth2, Point3D & norm1, Point3D & norm2, U32 idx1, U32 idx2, std::vector<U32> * vertId);
void stripify(std::vector<Primitive> &, std::vector<U16> & indices);
void decimate(Mesh * mesh, F32 percentage);
void collapseTransforms();
bool cut(NodeMimic * mimicNode);
void snip(NodeMimic * nodeMimic);
bool testCutNodes(AppSequenceData & seqData);
NodeMimic * findNextNode(NodeMimic *);
void dumpShapeNode(Shape * shape, S32 level, S32 nodeIndex, std::vector<S32> & detailSizes);
void dumpShape(Shape * shape);
void getMultiResData(AppNode * node, std::vector<S32> & multiResSize, std::vector<F32> & multiResPercent);
void getMultiResData(AppMesh * node, std::vector<S32> & multiResSize, std::vector<F32> & multiResPercent);
public:
ShapeMimic();
~ShapeMimic();
// add shape items as we walk the scene
void addBounds(AppNode * appNode) { boundsNode=appNode; }
void addSubtree(AppNode * appNode);
void addNode(NodeMimic *,AppNode *, std::vector<S32> &,bool);
void addMesh(AppNode * node, AppMesh * mesh) { addObject(node,mesh,NULL); }
void addSkin(AppMesh * mesh);
void addSkin(AppMesh * mesh, bool multiRes, S32 multiResSize=-1, F32 multiResPercent=1.0f);
void addSequence(AppSequence * sequence) { sequences.push_back(sequence); }
// the payoff...call after adding all of the above
Shape * generateShape();
};
}; // namespace DTS
#endif

571
lib/dtsSDKPlus/appConfig.cpp Executable file
View File

@ -0,0 +1,571 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786 4018)
#endif
#include "appConfig.h"
#include "appNode.h"
namespace DTS {
class AppMessage
{
char* mMessageId;
char* mMessage;
public:
AppMessage( const char * messageId, const char * message );
~AppMessage();
char* MessageId() { return mMessageId; };
char* Message() { return mMessage; };
};
AppMessage::AppMessage( const char * messageId, const char* message )
{
mMessageId = _strdup( messageId );
mMessage = _strdup( message );
}
AppMessage::~AppMessage()
{
if( mMessageId )
free( mMessageId );
if( mMessage )
free( mMessage );
}
static AppConfig gAppConfig;
AppConfig * AppConfig::smConfig = &gAppConfig;
AppConfig::AppConfig()
{
setInitialDefaults();
setupConfigParams();
mDumpFile = NULL;
}
AppConfig::~AppConfig()
{
clearConfigLists();
clearConfigParams();
if( mDumpFile )
{
mDumpFile->close();
delete mDumpFile;
}
if (smConfig==this)
smConfig=&gAppConfig;
}
void AppConfig::setInitialDefaults()
{
mEnableSequences = true;
mExportOptimized = true;
mAllowUnusedMeshes = true;
mAllowCollapseTransform = true;
mNoMipMap = false;
mNoMipMapTranslucent = false;
mZapBorder = true;
mAnimationDelta = 0.0001f;
mSameVertTOL = 0.00005f;
mSameNormTOL = 0.005f;
mSameVertTOL = 0.00005f;
mWeightThreshhold = 0.001f;
mWeightsPerVertex = 10;
mCyclicSequencePadding = 1.0f / 30.0f;
mAppFramesPerSec = 30.0f;
mDumpConfig = 0xFFFFFFFF;
mErrorString = NULL;
mProgressCallback = NULL;
mIgnoreSmoothingGroupOnSkinMesh = true;
mIgnoreSmoothingGroupDuringCollapse = false;
clearConfigLists();
}
void AppConfig::clearConfigLists()
{
S32 i;
for (i=0; i<mAlwaysExport.size(); i++)
delete [] mAlwaysExport[i];
mAlwaysExport.clear();
for (i=0; i<mNeverExport.size(); i++)
delete [] mNeverExport[i];
mNeverExport.clear();
for (i=0; i<mNeverAnimate.size(); i++)
delete [] mNeverAnimate[i];
mNeverAnimate.clear();
for (i=0; i<mErrorMessages.size(); i++)
delete mErrorMessages[i];
mErrorMessages.clear();
for (i=0; i<mWarningMessages.size(); i++)
delete mWarningMessages[i];
mWarningMessages.clear();
}
void AppConfig::setConfig(AppConfig * config)
{
assert(config != NULL);
if (smConfig!=&gAppConfig)
delete smConfig;
smConfig = config;
}
bool AppConfig::setDumpFile(const char * path, const char * name)
{
// open dump file in path specified, with optional name (use dump.dmp by default)
// path can include full file name...can also include \,/, or : as path delimitors
assert(path && "No path set on dump file");
if (name==NULL)
name = "dump.html";
char * fullpath = getFilePath(path,strlen(name)+1);
strcat(fullpath,name);
mDumpFile = new std::ofstream();
mDumpFile->open(fullpath,std::ofstream::binary);
if( !mDumpFile->fail() )
{
*mDumpFile << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n";
*mDumpFile << "<html>\r\n<head>\r\n<title>DTS Exporter Report</title>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\r\n";
*mDumpFile << "<style type=\"text/css\">\r\n<!--\r\n";
*mDumpFile << "body {\r\nfont-family: Verdana, Arial, Helvetica, sans-serif;\r\nfont-size: 14px;\r\nfont-weight: normal;\r\ncolor: #000000;\r\n}\r\n";
*mDumpFile << ".monoText {\r\nfont-size: 12px;\r\nline-height: normal;\r\nfont-family: \"Courier New\", Courier, mono;\r\n}\r\n";
*mDumpFile << ".errors {\r\nbackground-color: #FF9999;\r\nborder-width: 5;\r\nborder-style: solid;\r\nborder-color: #FF0000;\r\npadding: 4;\r\n}\r\n";
*mDumpFile << ".warnings {\r\nbackground-color: #FFF8AA;\r\nborder-width: 5;\r\nborder-style: solid;\r\nborder-color: #FFCC00;\r\npadding: 4;\r\n}\r\n";
*mDumpFile << ".header {\r\nfont-size: 16px;\r\nline-height: 24px;\r\nfont-family:Verdana, Arial, Helvetica, sans-serif;\r\nfont-weight: bold;\r\npadding-left: 0px;\r\n}\r\n";
*mDumpFile << "-->\r\n</style>\r\n</head>\r\n<body>\r\n<div class=\"header\">Exporter Report</div>\r\n<pre class=\"monoText\">\r\n";
mDumpFile->flush();
}
return !mDumpFile->fail();
}
bool AppConfig::closeDumpFile()
{
S32 i;
*mDumpFile << "</pre>";
*mDumpFile << "<div class=\"warnings\">\r\n<div class=\"header\">Warnings:</div>\r\n";
if( mWarningMessages.size() == 0 )
*mDumpFile << "<div>No warnings.</div>";
else
for (i=0; i<mWarningMessages.size(); i++)
*mDumpFile << "<div><a href=\"http://artist.garagegames.com/dts/warnings/" << mWarningMessages[i]->MessageId() << "\">Warning #" << mWarningMessages[i]->MessageId() << "</a>:" << mWarningMessages[i]->Message() << "</div>";
*mDumpFile << "</div>\r\n<br>\r\n";
*mDumpFile << "<div class=\"errors\">\r\n<div class=\"header\">Errors:</div>\r\n";
if( mErrorMessages.size() == 0 )
*mDumpFile << "<div>No errors.</div>";
else
for (i=0; i<mErrorMessages.size(); i++)
*mDumpFile << "<div><a href=\"http://artist.garagegames.com/dts/errors/" << mErrorMessages[i]->MessageId() << "\">Error #" << mErrorMessages[i]->MessageId() << "</a>:" << mErrorMessages[i]->Message() << "</div>";
*mDumpFile << "</div>\r\n";
*mDumpFile << "</body>\r\n</html>\r\n";
mDumpFile->flush();
mDumpFile->close();
delete mDumpFile;
mDumpFile = NULL;
return true;
}
void AppConfig::printDump(U32 mask, const char * str)
{
if (mask && AppConfig::GetDumpMask())
{
*mDumpFile << str;
mDumpFile->flush();
}
}
void AppConfig::printWarning( U32 mask, const char * warningId, const char* warningMessage )
{
if (mask && AppConfig::GetDumpMask())
{
mWarningMessages.push_back( new AppMessage( warningId, warningMessage ) );
printDump( mask, warningMessage );
}
}
void AppConfig::printError( U32 mask, const char * errorId, const char* errorMessage )
{
if (mask && AppConfig::GetDumpMask())
{
mErrorMessages.push_back( new AppMessage( errorId, errorMessage ) );
printDump( mask, errorMessage );
}
}
bool AppConfig::alwaysExport(AppNode * node)
{
const char * name = node->getName();
for (S32 i=0; i<mAlwaysExport.size(); i++)
if (stringEqual(name,mAlwaysExport[i]))
return true;
return false;
}
bool AppConfig::neverExport(AppNode * node)
{
const char * name = node->getName();
for (S32 i=0; i<mNeverExport.size(); i++)
if (stringEqual(name,mNeverExport[i]))
return true;
return false;
}
bool AppConfig::neverAnimate(AppNode * node)
{
const char * name = node->getName();
for (S32 i=0; i<mNeverAnimate.size(); i++)
if (stringEqual(name,mNeverAnimate[i]))
return true;
return false;
}
S32 AppConfig::getParamEntry(const char * name, std::vector<char *> & nameTable)
{
for (S32 i=0; i<nameTable.size(); i++)
{
if (!strcmp(name,nameTable[i]))
return i;
}
return -1;
}
bool AppConfig::searchConfigFile(const char * filename)
{
const char * ext = strrchr(filename,'.');
if (!ext)
ext = ""; // just use filename as base
const char * defaultName = "dtsScene.cfg";
const char * pos = filename+strlen(filename)-strlen(ext);
char * newname = new char[strlen(filename)+strlen(defaultName)+1];
strcpy(newname,filename);
// try using base filename with .cfg suffix
strcpy(newname+(pos-filename),".cfg");
if (readConfigFile(newname))
{
delete [] newname;
return true;
}
// try using base filename except no number with .cfg suffix
do
pos--;
while (pos>=filename && *pos<='9' && *pos>='0');
pos++;
strcpy(newname+(pos-filename),".cfg");
if (readConfigFile(newname))
{
delete [] newname;
return true;
}
// try using dtsScene.cfg
do
pos--;
while (pos>=filename && *pos!='\\' && *pos!='/' && *pos!=':');
pos++;
strcpy(newname+(pos-filename),defaultName);
if (readConfigFile(newname))
{
delete [] newname;
return true;
}
// no config file
delete [] newname;
return false;
}
bool AppConfig::readConfigFile(const char * filename)
{
clearConfigLists();
std::ifstream is;
is.open(filename);
if (!is.is_open())
{
printWarning(PDAlways,"101",avar("\r\nConfig file \"%s\" not found.\r\n",filename));
return false;
}
printDump(PDAlways,avar("\r\nBegin reading config file \"%s\".\r\n",filename));
S32 mode = 0; // 0=AlwaysExport:, 1=NeverExport:, 2=NeverAnimate:
char buffer[256];
do
{
is.getline(buffer,sizeof(buffer));
if (stringEqual(buffer,"AlwaysExport:*"))
mode = 0;
else if (stringEqual(buffer,"NeverExport:*"))
mode = 1;
else if (stringEqual(buffer,"NeverAnimate:*"))
mode = 2;
else if (buffer[0]=='+' || buffer[0]=='-')
{
bool newVal = buffer[0]=='+';
S32 idx = getParamEntry(buffer+1,mBoolParamNames);
if (idx>=0)
{
if (mBoolParamBit[idx])
{
if (newVal)
*mBoolParams[idx] |= mBoolParamBit[idx];
else
*mBoolParams[idx] &= ~mBoolParamBit[idx];
}
else
*mBoolParams[idx] = newVal;
printDump(PDAlways,avar("%s %s.\r\n",mBoolParamNames[idx],newVal ? "enabled" : "disabled"));
}
else
printDump(PDAlways,avar("Unknown bool parameter \"%s\"\r\n",buffer+1));
}
else if (buffer[0]=='=')
{
char * endName = strchr(buffer+1,' ');
if (endName)
{
*endName = '\0';
S32 idx1 = getParamEntry(buffer+1,mFloatParamNames);
S32 idx2 = getParamEntry(buffer+1,mStringParamNames);
S32 idx3 = getParamEntry(buffer+1,mIntParamNames);
if (idx1>=0)
{
// Float
*mFloatParams[idx1] = F32(atof(endName+1));
printDump(PDAlways,avar("%s = %f\r\n",mFloatParamNames[idx1],*mFloatParams[idx1]));
}
if (idx2>=0)
{
// string
S32 maxLen = mStringParamMaxLen[idx2];
strncpy(mStringParams[idx2],endName+1,maxLen-1);
mStringParams[idx2][maxLen]='\0';
printDump(PDAlways,avar("%s = \"%s\"\r\n",mStringParamNames[idx2],mStringParams[idx2]));
}
if (idx3>=0)
{
// S32
*mIntParams[idx3] = atoi(endName+1);
printDump(PDAlways,avar("%s = %i\r\n",mIntParamNames[idx3],*mIntParams[idx3]));
}
if (idx1<0 && idx2<0 && idx3<0)
printDump(PDAlways,avar("Unknown parameter \"%s\"\r\n",buffer+1));
}
}
else if (buffer[0]!='\\' && buffer[0]!='/' && buffer[0]!=';')
{
char * name = buffer;
while (*name==' ')
name++;
if (strlen(name))
{
if (mode == 0)
{
mAlwaysExport.push_back(strnew(buffer));
printDump(PDAlways,avar("Always export node: \"%s\"\r\n",buffer));
}
else if (mode == 1)
{
mNeverExport.push_back(strnew(buffer));
printDump(PDAlways,avar("Never export node: \"%s\"\r\n",buffer));
}
else if (mode == 2)
{
mNeverAnimate.push_back(strnew(buffer));
printDump(PDAlways,avar("Never animate transform on node: \"%s\"\r\n",buffer));
}
}
}
} while (is.good());
printDump(PDAlways,"End reading config file.\r\n");
return true;
}
void AppConfig::writeConfigFile(const char * filename)
{
S32 i;
std::ofstream os;
os.open(filename);
os << "AlwaysExport:" << std::endl;
for (i=0; i<mAlwaysExport.size(); i++)
os << mAlwaysExport[i] << std::endl;
os << "NeverExport:" << std::endl;
for (i=0; i<mNeverExport.size(); i++)
os << mNeverExport[i] << std::endl;
os << "NeverAnimate:" << std::endl;
for (i=0; i<mNeverAnimate.size(); i++)
os << mNeverAnimate[i] << std::endl;
for (i=0; i<mBoolParamNames.size(); i++)
{
bool enabled = mBoolParamBit[i] ? (mBoolParamBit[i] & *mBoolParams[i]) != 0 : *mBoolParams[i]!=0;
os << (enabled ? "+" : "-") << mBoolParamNames[i] << std::endl;
}
for (i=0; i<mFloatParamNames.size(); i++)
os << mFloatParamNames[i] << "= " << *mFloatParams[i] << std::endl;
for (i=0; i<mIntParamNames.size(); i++)
os << mIntParamNames[i] << "= " << *mIntParams[i] << std::endl;
for (i=0; i<mStringParamNames.size(); i++)
os << mStringParamNames[i] << "= " << mStringParams[i] << std::endl;
os.close();
}
void AppConfig::setupConfigParams()
{
// add bool config parameters
mBoolParamNames.push_back(strnew("Dump::NodeCollection"));
mBoolParams.push_back(&mDumpConfig);
mBoolParamBit.push_back(PDPass1);
mBoolParamNames.push_back(strnew("Dump::ShapeConstruction"));
mBoolParams.push_back(&mDumpConfig);
mBoolParamBit.push_back(PDPass2);
mBoolParamNames.push_back(strnew("Dump::NodeCulling"));
mBoolParams.push_back(&mDumpConfig);
mBoolParamBit.push_back(PDPass3);
mBoolParamNames.push_back(strnew("Dump::NodeStates"));
mBoolParams.push_back(&mDumpConfig);
mBoolParamBit.push_back(PDNodeStates);
mBoolParamNames.push_back(strnew("Dump::NodeStateDetails"));
mBoolParams.push_back(&mDumpConfig);
mBoolParamBit.push_back(PDNodeStateDetails);
mBoolParamNames.push_back(strnew("Dump::ObjectStates"));
mBoolParams.push_back(&mDumpConfig);
mBoolParamBit.push_back(PDObjectStates);
mBoolParamNames.push_back(strnew("Dump::ObjectStateDetails"));
mBoolParams.push_back(&mDumpConfig);
mBoolParamBit.push_back(PDObjectStateDetails);
mBoolParamNames.push_back(strnew("Dump::ObjectOffsets"));
mBoolParams.push_back(&mDumpConfig);
mBoolParamBit.push_back(PDObjectOffsets);
mBoolParamNames.push_back(strnew("Dump::SequenceDetails"));
mBoolParams.push_back(&mDumpConfig);
mBoolParamBit.push_back(PDSequences);
mBoolParamNames.push_back(strnew("Dump::ShapeHierarchy"));
mBoolParams.push_back(&mDumpConfig);
mBoolParamBit.push_back(PDShapeHierarchy);
mBoolParamNames.push_back(strnew("Error::AllowUnusedMeshes"));
mBoolParams.push_back((U32*)&mAllowUnusedMeshes);
mBoolParamBit.push_back(0);
mBoolParamNames.push_back(strnew("Param::CollapseTransforms"));
mBoolParams.push_back((U32*)&mAllowCollapseTransform);
mBoolParamBit.push_back(0);
mBoolParamNames.push_back(strnew("Param::SequenceExport"));
mBoolParams.push_back((U32*)&mEnableSequences);
mBoolParamBit.push_back(0);
mBoolParamNames.push_back(strnew("Materials::NoMipMap"));
mBoolParams.push_back((U32*)&mNoMipMap);
mBoolParamBit.push_back(0);
mBoolParamNames.push_back(strnew("Materials::NoMipMapTranslucent"));
mBoolParams.push_back((U32*)&mNoMipMapTranslucent);
mBoolParamBit.push_back(0);
mBoolParamNames.push_back(strnew("Materials::ZapBorder"));
mBoolParams.push_back((U32*)&mZapBorder);
mBoolParamBit.push_back(0);
mBoolParamNames.push_back(strnew("SmoothingGroup::IgnoreOnSkinMesh"));
mBoolParams.push_back((U32*)&mIgnoreSmoothingGroupOnSkinMesh);
mBoolParamBit.push_back(0);
mBoolParamNames.push_back(strnew("SmoothingGroup::IgnoreDuringCollapse"));
mBoolParams.push_back((U32*)&mIgnoreSmoothingGroupDuringCollapse);
mBoolParamBit.push_back(1);
// add F32 config parameters
mFloatParamNames.push_back(strnew("Params::AnimationDelta"));
mFloatParams.push_back(&mAnimationDelta);
mFloatParamNames.push_back(strnew("Params::SkinWeightThreshhold"));
mFloatParams.push_back(&mWeightThreshhold);
mFloatParamNames.push_back(strnew("Params::SameVertTOL"));
mFloatParams.push_back(&mSameVertTOL);
mFloatParamNames.push_back(strnew("Params::SameTVertTOL"));
mFloatParams.push_back(&mSameTVertTOL);
// add S32 config parameters
mIntParamNames.push_back(strnew("Params::weightsPerVertex"));
mIntParams.push_back(&mWeightsPerVertex);
}
void AppConfig::clearConfigParams()
{
S32 i;
for (i=0; i<mBoolParamNames.size(); i++)
delete [] mBoolParamNames[i];
for (i=0; i<mFloatParamNames.size(); i++)
delete [] mFloatParamNames[i];
for (i=0; i<mIntParamNames.size(); i++)
delete [] mIntParamNames[i];
for (i=0; i<mStringParamNames.size(); i++)
delete [] mStringParamNames[i];
mBoolParamNames.clear();
mBoolParams.clear();
mBoolParamBit.clear();
mFloatParamNames.clear();
mFloatParams.clear();
mIntParamNames.clear();
mIntParams.clear();
mStringParamNames.clear();
mStringParams.clear();
mStringParamMaxLen.clear();
}
// progress handling
void AppConfig::setProgressCallback(progressfnptr callback)
{
mProgressCallback = callback;
}
void AppConfig::setProgress(F32 minor, F32 major, const char* message)
{
if (mProgressCallback)
{
mProgressCallback(minor, major, message);
}
}
}; // namespace DTS

174
lib/dtsSDKPlus/appConfig.h Executable file
View File

@ -0,0 +1,174 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef DTSAPPCONFIG_H_
#define DTSAPPCONFIG_H_
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSPlusTypes.h"
#include "DTSUtil.h"
#include <fstream>
namespace DTS
{
typedef void (*progressfnptr)(F32,F32,const char*);
// enum for printDump
enum
{
PDPass1 = 1 << 0, // collect useful nodes
PDPass2 = 1 << 1, // put together shape structure
PDPass3 = 1 << 2, // cull un-needed nodes
PDObjectOffsets = 1 << 3, // display object offset transform during 2nd pass
PDNodeStates = 1 << 4, // display as added
PDObjectStates = 1 << 5, // ""
PDNodeStateDetails = 1 << 6, // details of above
PDObjectStateDetails = 1 << 7, // ""
PDSequences = 1 << 8,
PDShapeHierarchy = 1 << 9,
PDAlways = 0xFFFFFFFF
};
class AppNode;
class AppMessage;
class AppConfig
{
static AppConfig * smConfig;
F32 mAnimationDelta;
F32 mSameVertTOL;
F32 mSameTVertTOL;
F32 mSameNormTOL;
F32 mWeightThreshhold;
S32 mWeightsPerVertex;
F32 mCyclicSequencePadding;
F32 mAppFramesPerSec;
bool mEnableSequences;
bool mExportOptimized;
bool mAllowUnusedMeshes;
bool mAllowCollapseTransform;
bool mNoMipMap;
bool mNoMipMapTranslucent;
bool mZapBorder;
bool mIgnoreSmoothingGroupDuringCollapse;
bool mIgnoreSmoothingGroupOnSkinMesh;
U32 mDumpConfig;
char * mErrorString;
std::ofstream *mDumpFile;
progressfnptr mProgressCallback;
std::vector<char *> mBoolParamNames;
std::vector<U32 *> mBoolParams;
std::vector<U32> mBoolParamBit;
std::vector<char *> mFloatParamNames;
std::vector<F32 *> mFloatParams;
std::vector<char *> mIntParamNames;
std::vector<S32 *> mIntParams;
std::vector<char *> mStringParamNames;
std::vector<char *> mStringParams;
std::vector<S32> mStringParamMaxLen;
std::vector<char *> mAlwaysExport;
std::vector<char *> mNeverExport;
std::vector<char *> mNeverAnimate;
std::vector<AppMessage *>mWarningMessages;
std::vector<AppMessage *>mErrorMessages;
virtual void printDump(U32 mask, const char * str);
virtual void printWarning(U32 mask, const char * warningId, const char * warningMessage);
virtual void printError(U32 mask, const char * errorId, const char * errorMessage);
virtual bool setDumpFile(const char * path, const char * name = NULL);
virtual bool closeDumpFile();
virtual bool alwaysExport(AppNode *);
virtual bool neverExport(AppNode *);
virtual bool neverAnimate(AppNode *);
bool searchConfigFile(const char * filename);
bool readConfigFile(const char * filename);
void writeConfigFile(const char * filename);
void setInitialDefaults();
S32 getParamEntry(const char * name, std::vector<char *> & nameTable);
void setupConfigParams();
void clearConfigParams();
void clearConfigLists();
void setAppFramesPerSec(F32 fps) { mAppFramesPerSec = fps; };
// progress handling
void setProgressCallback(progressfnptr callback);
virtual void setProgress(F32 minor, F32 major, const char* message);
// error handling
void setExportError(const char * errorId, const char * str) { printError( PDAlways, errorId, str ); }
bool isExportError() { return mErrorMessages.size() > 0; }
const char * getExportError() { return "Errors during export, please check dump file."; }
public:
AppConfig();
virtual ~AppConfig();
void setConfig(AppConfig * config);
// access configuration parameters statically...
static bool SetDumpFile(const char * path, const char * name = NULL) { return smConfig->setDumpFile(path,name); }
static bool CloseDumpFile() { return smConfig->closeDumpFile(); }
static void PrintDump(U32 mask, const char * str) { smConfig->printDump(mask,str); }
static void PrintWarning( U32 mask, const char * warningId, const char* warningMessage ) { smConfig->printWarning( mask, warningId, warningMessage ); }
static void PrintError( U32 mask, const char * errorId, const char* errorMessage ) { smConfig->printError( mask, errorId, errorMessage ); }
static U32 GetDumpMask() { return smConfig->mDumpConfig; }
static bool AlwaysExport(AppNode * node) { return smConfig->alwaysExport(node); }
static bool NeverExport(AppNode * node) { return smConfig->neverExport(node); }
static bool NeverAnimate(AppNode * node) { return smConfig->neverAnimate(node); }
static void SetExportError(const char * errorId, const char * str) { smConfig->setExportError(errorId, str); }
static bool IsExportError() { return smConfig->isExportError(); }
static const char * GetExportError() { return smConfig->getExportError(); }
static bool GetEnableSequences() { return smConfig->mEnableSequences; }
static bool GetExportOptimized() { return smConfig->mExportOptimized; }
static bool GetAllowUnusedMeshes() { return smConfig->mAllowUnusedMeshes; }
static bool GetAllowCollapse() { return smConfig->mAllowCollapseTransform; }
static bool GetNoMipMap() { return smConfig->mNoMipMap; }
static bool GetNoMipMapTranslucent() { return smConfig->mNoMipMapTranslucent; }
static bool GetZapBorder() { return smConfig->mZapBorder; }
static bool IgnoreSmoothingGroupDuringCollapse() { return smConfig->mIgnoreSmoothingGroupDuringCollapse; }
static bool IgnoreSmoothingGroupOnSkinMesh() { return smConfig->mIgnoreSmoothingGroupOnSkinMesh; }
static F32 AnimationDelta() { return smConfig->mAnimationDelta; }
static F32 SameVertTOL() { return smConfig->mSameVertTOL; }
static F32 SameNormTOL() { return smConfig->mSameNormTOL; }
static F32 SameTVertTOL() { return smConfig->mSameVertTOL; }
static F32 WeightThreshhold() { return smConfig->mWeightThreshhold; }
static S32 WeightsPerVertex() { return smConfig->mWeightsPerVertex; }
static F32 CyclicSequencePadding() { return smConfig->mCyclicSequencePadding; }
static F32 AppFramesPerSec() { return smConfig->mAppFramesPerSec; }
static void SetAppFramesPerSec(F32 fps) { smConfig->setAppFramesPerSec(fps); }
static void SetExportOptimized(bool opt) { smConfig->mExportOptimized = opt; }
static void SetDefaults() { smConfig->setInitialDefaults(); }
static bool SearchConfigFile(const char * filename) { return smConfig->searchConfigFile(filename); }
static bool ReadConfigFile(const char * filename) { return smConfig->readConfigFile(filename); }
static void WriteConfigFile(const char * filename) { smConfig->writeConfigFile(filename); }
// progress handling
static void SetProgressCallback(progressfnptr callback) { smConfig->setProgressCallback(callback); }
static void SetProgress(F32 minor, F32 major, const char* message) { smConfig->setProgress(minor, major, message); }
};
};
#endif // DTSAPPMATERIAL_H_

57
lib/dtsSDKPlus/appIfl.cpp Executable file
View File

@ -0,0 +1,57 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786 4018)
#endif
#include "appIfl.h"
#include "DTSUtil.h"
#include <fstream>
namespace DTS
{
AppIfl::AppIfl(const char * fullPath)
{
mIflFile = strnew(fullPath);
// load in duration and names
std::ifstream is;
is.open(fullPath);
char buffer[256];
char name[256];
S32 duration;
while (is.good() && !is.eof())
{
is.getline(buffer,sizeof(buffer));
S32 num = sscanf(buffer,"%s %i",name,&duration);
if (num==1)
{
mNames.push_back(strnew(name));
mDurations.push_back(AppTime(1.0f/30.0f,0));
}
else if (num==2)
{
mNames.push_back(strnew(name));
mDurations.push_back(AppTime(F32(duration)/30.0f,0));
}
}
}
AppTime AppIfl::getStartTime() { return AppTime(0,0); }
AppIfl::~AppIfl()
{
delete [] mIflFile;
for (S32 i=0; i<mNames.size(); i++)
delete [] mNames[i];
}
}; // namespace DTS

38
lib/dtsSDKPlus/appIfl.h Executable file
View File

@ -0,0 +1,38 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef DTSAPPIFL_H_
#define DTSAPPIFL_H_
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSPlusTypes.h"
#include "appMesh.h"
namespace DTS
{
class AppIfl
{
char * mIflFile;
std::vector<AppTime> mDurations;
std::vector<char *> mNames;
public:
// Standard AppIfl just needs a path name to the ifl
// Can derive from this class, though, in order to support
// Ifls in a more application dependent manner, if desired.
AppIfl(const char * fullPath);
virtual ~AppIfl();
const char * getFilename() { return mIflFile; }
const std::vector<AppTime> & getDurations() { return mDurations; }
const std::vector<char*> & getNames() { return mNames; }
virtual AppTime getStartTime();
};
};
#endif // DTSAPPIFL_H_

238
lib/dtsSDKPlus/appMesh.cpp Executable file
View File

@ -0,0 +1,238 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786 4018)
#endif
#include "appMesh.h"
#include "appTime.h"
#include "dtsUtil.h"
#include "appIfl.h"
#include "appConfig.h"
namespace DTS
{
AppMesh::AppMesh()
{
mLocked = false;
mSkinDataFetched = false;
}
AppMesh::~AppMesh()
{
assert(!mLocked && "Mesh is locked");
S32 i;
for (i=0; i<mBones.size(); i++)
delete mBones[i];
for (i=0; i<mWeights.size(); i++)
delete mWeights[i];
for (i=0; i<mIfls.size(); i++)
delete mIfls[i];
}
S32 __cdecl compareFaces( void const *e1, void const *e2 )
{
const Primitive * face1 = (const Primitive*)e1;
const Primitive * face2 = (const Primitive*)e2;
if (face1->type < face2->type)
return -1;
else if (face2->type < face1->type)
return 1;
else return 0;
}
void AppMesh::sortFaceList()
{
if (mFaces.size() != 0)
qsort(&mFaces[0],mFaces.size(),sizeof(Primitive),compareFaces);
}
Box AppMesh::getBounds(const Matrix<4,4,F32> & objectOffset)
{
assert(!mLocked && "Mesh is locked");
AppMeshLock lock = lockMesh(AppTime::DefaultTime(),objectOffset);
Box bounds(Point3D( 10E30f, 10E30f, 10E30f),Point3D(-10E30f,-10E30f,-10E30f));
const Point3D * verts = getVerts();
for (S32 i=0; i<getNumVerts(); i++)
{
if (bounds.min.x() > verts[i].x())
bounds.min.x(verts[i].x());
if (bounds.min.y() > verts[i].y())
bounds.min.y(verts[i].y());
if (bounds.min.z() > verts[i].z())
bounds.min.z(verts[i].z());
if (bounds.max.x() < verts[i].x())
bounds.max.x(verts[i].x());
if (bounds.max.y() < verts[i].y())
bounds.max.y(verts[i].y());
if (bounds.max.z() < verts[i].z())
bounds.max.z(verts[i].z());
}
return bounds;
}
F32 AppMesh::getRadius(const Matrix<4,4,F32> & objectOffset)
{
Box bounds = getBounds(objectOffset);
Point3D diameter = bounds.max-bounds.min;
return diameter.length() * 0.5f;
}
F32 AppMesh::getTubeRadius(const Matrix<4,4,F32> & objectOffset)
{
Box bounds = getBounds(objectOffset);
Point2D diameter(bounds.max.x()-bounds.min.x(),bounds.max.y()-bounds.min.y());
return diameter.length() * 0.5f;
}
bool AppMesh::isBillboard()
{
return !_strnicmp(getName(),"BB::",4) || !_strnicmp(getName(),"BB_",3) || !_strnicmp(getName(),"BBZ::",5) || !_strnicmp(getName(),"BBZ_",4);
}
bool AppMesh::isBillboardZAxis()
{
return !_strnicmp(getName(),"BBZ::",5) || !_strnicmp(getName(),"BBZ_",4);
}
bool AppMesh::isSorted()
{
return !_strnicmp(getName(),"SORT::",6) || !_strnicmp(getName(),"SORT_",5);
}
bool AppMesh::isDummy()
{
return !_strnicmp(getName(), "dummy", 5);
}
bool AppMesh::animatesVis(const AppSequenceData & seqData)
{
F32 defaultVis = getVisValue(AppTime::DefaultTime());
AppTime time = seqData.startTime;
for (S32 frame=0; frame<seqData.numFrames; frame++, time += seqData.delta)
if (!isEqual(defaultVis,getVisValue(time),0.01f))
return true;
return false;
}
bool AppMesh::animatesMatFrame(const AppSequenceData & seqData)
{
// don't necessarily want to support this type of animation anymore
return false;
}
bool AppMesh::animatesFrame(const AppSequenceData & seqData)
{
// don't necessarily want to support this type of animation anymore
return false;
}
U16 AppMesh::addVertex(const Point3D & vert, const Point3D & norm, Point2D & tvert, U32 vertId)
{
assert(mVerts.size() == mTVerts.size() && "Verts and TVerts unbalanced");
assert(mVerts.size() == mNormals.size() && "Verts and Normals unbalanced");
assert(mVerts.size() == mVertId.size() && "Verts and vertIds unbalanced");
for (S32 i=0; i<mVerts.size(); i++)
{
if (vertId != mVertId[i])
continue;
if (!isEqual(vert,mVerts[i],AppConfig::SameVertTOL()))
continue;
if (!isEqual(tvert,mTVerts[i],AppConfig::SameTVertTOL()))
continue;
if (!isEqual(norm,mNormals[i],AppConfig::SameNormTOL()))
continue;
return i;
}
mVerts.push_back(vert);
mTVerts.push_back(tvert);
mNormals.push_back(norm);
mVertId.push_back(vertId);
return mVerts.size()-1;
}
U16 AppMesh::addVertex(const Point3D & vert, Point2D & tvert, U32 vertId, U32 smooth)
{
assert(mVerts.size() == mTVerts.size() && "Verts and TVerts unbalanced");
assert(mVerts.size() == mSmooth.size() && "Verts and smooth unbalanced");
assert(mVerts.size() == mVertId.size() && "Verts and vertIds unbalanced");
for (S32 i=0; i<mVerts.size(); i++)
{
if (vertId != mVertId[i])
continue;
if (smooth != mSmooth[i])
continue;
if (!isEqual(vert,mVerts[i],AppConfig::SameVertTOL()))
continue;
if (!isEqual(tvert,mTVerts[i],AppConfig::SameTVertTOL()))
continue;
return i;
}
mVerts.push_back(vert);
mTVerts.push_back(tvert);
mSmooth.push_back(smooth);
mVertId.push_back(vertId);
return mVerts.size()-1;
}
void AppMesh::generateFaces(std::vector<Primitive> & faces,
std::vector<Point3D> & verts,
std::vector<Point2D> & tverts,
std::vector<U16> & indices,
std::vector<U32> & smooth,
std::vector<Point3D> & normals,
std::vector<U32> * vertId)
{
assert(mLocked && "Mesh isn't locked");
faces = mFaces;
verts = mVerts;
tverts = mTVerts;
indices = mIndices;
normals = mNormals;
smooth = mSmooth;
if (vertId)
*vertId = mVertId;
}
AppMeshLock AppMesh::lockMesh(const AppTime & time, const Matrix<4,4,F32> & objectOffset)
{
assert(!mLocked && "Mesh is already locked");
time,objectOffset;
// if more than one mat type, make mats consecutive
sortFaceList();
mLocked = true;
return AppMeshLock(this);
}
void AppMesh::unlockMesh()
{
assert(mLocked && "Mesh isn't locked");
mFaces.clear();
mVerts.clear();
mTVerts.clear();
mIndices.clear();
mNormals.clear();
mSmooth.clear();
mVertId.clear();
mLocked = false;
}
void AppMeshLock::doit() { if (mObj) mObj->unlockMesh(); }
}; // namespace DTS

239
lib/dtsSDKPlus/appMesh.h Executable file
View File

@ -0,0 +1,239 @@
//-----------------------------/------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef DTSAPPMESH_H_
#define DTSAPPMESH_H_
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSPlusTypes.h"
#include "appSequence.h"
namespace DTS
{
class AppIfl;
class AppMeshLock;
class AppNode;
class AppMesh
{
protected:
std::vector<Primitive> mFaces;
std::vector<Point3D> mVerts;
std::vector<Point2D> mTVerts;
std::vector<U16> mIndices;
std::vector<U32> mVertId;
// One can supply either the normals directly or
// 3dsMax style smoothing groups and normals will
// be computed for you. Note that one or the other
// should be supplied -- if both or neither are
// supplied the behavior is not predictable.
// In 3dsMax, normals are not trustworthy, so it is
// necessary to use smoothing groups instead.
std::vector<Point3D> mNormals;
std::vector<U32> mSmooth;
// For skinned meshes, we want bones and weights
// Weights stored by (*mWeights[vertIdx])[boneIdx]
std::vector<AppNode*> mBones;
std::vector<std::vector<F32>*> mWeights;
// For ifls
std::vector<AppIfl*> mIfls;
// These needs to be maintained by lock/unlock methods
bool mLocked;
bool mSkinDataFetched;
void sortFaceList();
void lookupSkinData();
virtual void getSkinData() = 0;
public:
AppMesh();
~AppMesh();
// Not necessary to use these (don't need to keep verts unique) but can be used for
// keeping vert list smaller. Add each vert using one or the other method.
U16 addVertex(const Point3D & vert, const Point3D & norm, Point2D & tvert, U32 vertId);
U16 addVertex(const Point3D & vert, Point2D & tvert, U32 vertId, U32 smooth);
virtual const char * getName() = 0;
virtual Matrix<4,4,F32> getMeshTransform(const AppTime & time) = 0;
virtual F32 getVisValue(const AppTime & time) = 0;
virtual bool getFloat(const char * propName, F32 & defaultVal) = 0;
virtual bool getInt(const char * propName, S32 & defaultVal) = 0;
virtual bool getBool(const char * propName, bool & defaultVal) = 0;
virtual bool getMaterial(S32 matIdx, Material &) = 0;
AppIfl * getIfl(S32 matIdx);
S32 getNumBones();
AppNode * getBone(S32 idx);
F32 getWeight(S32 boneIdx, S32 vertIdx);
virtual bool animatesVis(const AppSequenceData & seqData);
virtual bool animatesMatFrame(const AppSequenceData & seqData);
virtual bool animatesFrame(const AppSequenceData & seqData);
virtual Box getBounds(const Matrix<4,4,F32> & objectOffset);
virtual F32 getRadius(const Matrix<4,4,F32> & objectOffset);
virtual F32 getTubeRadius(const Matrix<4,4,F32> & objectOffset);
virtual bool isBillboard();
virtual bool isBillboardZAxis();
virtual bool isSorted();
virtual bool isDummy();
bool isSkin() { return getNumBones() != 0; }
virtual AppMeshLock lockMesh(const AppTime & time, const Matrix<4,4,F32> & objectOffset);
virtual void unlockMesh();
// before and after accessing following methods,
// one should always call lock/unlock mesh
S32 getNumFaces();
const Primitive * getFaces();
S32 getFaceMaterial(S32 faceIdx);
S32 getNumIndices();
const U16 * getIndices();
S32 getNumTVerts();
const Point2D * getTVerts();
S32 getNumVerts();
const Point3D * getVerts();
S32 getNumNormals();
const Point3D * getNormals();
void generateFaces(std::vector<Primitive> & faces,
std::vector<Point3D> & verts,
std::vector<Point2D> & tverts,
std::vector<U16> & indices,
std::vector<U32> & smooth,
std::vector<Point3D> & normals,
std::vector<U32> * vertId);
};
class AppMeshLock : public OnDestroy<AppMesh>
{
protected:
void doit();
public:
AppMeshLock(AppMesh * mesh) : OnDestroy<AppMesh>(mesh) {}
~AppMeshLock() { transfer(NULL); }
};
inline S32 AppMesh::getNumFaces()
{
assert(mLocked && "Mesh isn't locked");
return mFaces.size();
}
inline const Primitive * AppMesh::getFaces()
{
assert(mLocked && "Mesh isn't locked");
return getNumFaces() ? &mFaces[0] : NULL;
}
inline S32 AppMesh::getFaceMaterial(S32 faceIdx)
{
assert(mLocked && "Mesh isn't locked");
assert(faceIdx>=0 && U32(faceIdx) < mFaces.size() && "Face index out of range");
if (mFaces[faceIdx].type & Primitive::NoMaterial)
return -1;
return mFaces[faceIdx].type & Primitive::MaterialMask;
}
inline S32 AppMesh::getNumIndices()
{
assert(mLocked && "Mesh isn't locked");
return mIndices.size();
}
inline const U16 * AppMesh::getIndices()
{
assert(mLocked && "Mesh isn't locked");
return getNumIndices() ? &mIndices[0] : NULL;
}
inline S32 AppMesh::getNumTVerts()
{
assert(mLocked && "Mesh isn't locked");
return mTVerts.size();
}
inline const Point2D * AppMesh::getTVerts()
{
assert(mLocked && "Mesh isn't locked");
return getNumTVerts() ? &mTVerts[0] : NULL;
}
inline S32 AppMesh::getNumVerts()
{
assert(mLocked && "Mesh isn't locked");
return mVerts.size();
}
inline const Point3D * AppMesh::getVerts()
{
assert(mLocked && "Mesh isn't locked");
return getNumVerts() ? &mVerts[0] : NULL;
}
inline S32 AppMesh::getNumNormals()
{
assert(mLocked && "Mesh isn't locked");
return mNormals.size();
}
inline const Point3D * AppMesh::getNormals()
{
assert(mLocked && "Mesh isn't locked");
return getNumNormals() ? &mNormals[0] : NULL;
}
inline S32 AppMesh::getNumBones()
{
lookupSkinData();
return mBones.size();
}
inline AppNode * AppMesh::getBone(S32 idx)
{
lookupSkinData();
assert(idx>=0 && U32(idx) < mBones.size() && "Bone index out of range");
return mBones[idx];
}
inline F32 AppMesh::getWeight(S32 boneIdx, S32 vertIdx)
{
assert(mLocked && "Mesh isn't locked");
lookupSkinData();
assert(boneIdx>=0 && U32(boneIdx) < mBones.size() && "Bone index out of range");
assert(vertIdx>=0 && U32(vertIdx) < mVertId.size() && "Vertex index out of range");
assert(mVertId[vertIdx]<mWeights[boneIdx]->size() && "Vertex id out of range");
return (*mWeights[boneIdx])[mVertId[vertIdx]];
}
inline AppIfl * AppMesh::getIfl(S32 matIdx)
{
assert(matIdx>=0 && U32(matIdx) < mIfls.size() && "Mat index out of ifl range");
return mIfls[matIdx];
}
inline void AppMesh::lookupSkinData()
{
if (mSkinDataFetched)
return;
getSkinData();
mSkinDataFetched = true;
}
};
#endif // DTSAPPMESH_H_

102
lib/dtsSDKPlus/appNode.cpp Executable file
View File

@ -0,0 +1,102 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786 4018)
#endif
#include "appNode.h"
#include "DTSUtil.h"
namespace DTS
{
AppNode::AppNode()
{
mName = NULL;
mParentName = NULL;
}
AppNode::~AppNode()
{
S32 i;
for (i=0; i<mMeshes.size(); i++)
delete mMeshes[i];
for (i=0; i<mChildNodes.size(); i++)
delete mChildNodes[i];
mMeshes.clear();
mChildNodes.clear();
delete [] mName;
delete [] mParentName;
}
S32 AppNode::getNumMesh()
{
if (mMeshes.size() == 0)
buildMeshList();
return mMeshes.size();
}
AppMesh * AppNode::getMesh(S32 idx)
{
if (mMeshes.size() == 0)
buildMeshList();
if (idx<mMeshes.size() && idx>=0)
return mMeshes[idx];
return NULL;
}
S32 AppNode::getNumChildNodes()
{
if (mChildNodes.size() == 0)
buildChildList();
return mChildNodes.size();
}
AppNode * AppNode::getChildNode(S32 idx)
{
if (mChildNodes.size() == 0)
buildChildList();
if (idx<mChildNodes.size() && idx>=0)
return mChildNodes[idx];
return NULL;
}
bool AppNode::isBillboard()
{
return !_strnicmp(getName(),"BB::",4) || !_strnicmp(getName(),"BB_",3) || !_strnicmp(getName(),"BBZ::",5) || !_strnicmp(getName(),"BBZ_",4);
}
bool AppNode::isBillboardZAxis()
{
return !_strnicmp(getName(),"BBZ::",5) || !_strnicmp(getName(),"BBZ_",4);
}
bool AppNode::isDummy()
{
// naming convention should work well enough...
// ...but can override this method if one wants more
return !_strnicmp(getName(), "dummy", 5);
}
bool AppNode::isBounds()
{
// naming convention should work well enough...
// ...but can override this method if one wants more
return !_stricmp(getName(), "bounds");
}
bool AppNode::isRoot()
{
// we assume root node isn't added, so this is never true
// but allow for possibility (by overriding this method)
// so that isParentRoot still works.
return false;
}
}; // namespace DTS

68
lib/dtsSDKPlus/appNode.h Executable file
View File

@ -0,0 +1,68 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef DTSAPPNODE_H_
#define DTSAPPNODE_H_
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSPlusTypes.h"
#include "appMesh.h"
namespace DTS
{
class AppNode
{
// add attached meshes and child nodes to app node
// the reason these are tracked by AppNode is that
// AppNode is responsible for deleting all it's children
// and attached meshes.
virtual void buildMeshList() = 0;
virtual void buildChildList() = 0;
protected:
std::vector<AppMesh*> mMeshes;
std::vector<AppNode*> mChildNodes;
char * mName;
char * mParentName;
public:
AppNode();
virtual ~AppNode();
S32 getNumMesh();
AppMesh * getMesh(S32 idx);
S32 getNumChildNodes();
AppNode * getChildNode(S32 idx);
virtual Matrix<4,4,F32> getNodeTransform(const AppTime & time) = 0;
virtual bool isEqual(AppNode *) = 0;
virtual bool animatesTransform(const AppSequenceData & seqData) = 0;
virtual const char * getName() = 0;
virtual const char * getParentName() = 0;
virtual bool getFloat(const char * propName, F32 & defaultVal) = 0;
virtual bool getInt(const char * propName, S32 & defaultVal) = 0;
virtual bool getBool(const char * propName, bool & defaultVal) = 0;
virtual bool isBillboard();
virtual bool isBillboardZAxis();
virtual bool isParentRoot() = 0;
virtual bool isDummy();
virtual bool isBounds();
virtual bool isRoot();
};
};
#endif // DTSAPPNODE_H_

177
lib/dtsSDKPlus/appSceneEnum.cpp Executable file
View File

@ -0,0 +1,177 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786 4018)
#endif
#include "appSceneEnum.h"
#include "appSequence.h"
namespace DTS
{
AppSequence * AppSceneEnum::getSequence(AppNode * node)
{
const char * prefix = "Sequence::";
const char * name = node->getName();
if (!_strnicmp(name,prefix,strlen(prefix)))
return new AppSequenceNode(node);
prefix = "Sequence_";
if (!_strnicmp(name,prefix,strlen(prefix)))
return new AppSequenceNode(node);
return NULL;
}
bool AppSceneEnum::processNode(AppNode * node)
{
// Helper method to help rot nodes that we find in the scene.
// At this stage we do not need to collect all the nodes
// because the tree structure will still be there when we
// build the shape. What we need to do right now is grab
// the top of all the subtrees, any meshes hanging on the
// root level (these will be lower detail levels, we don't
// need to grab meshes on the sub-trees because they will
// be found when we recurse into the sub-tree), the bounds
// node, and any sequences.
const char * name = node->getName();
const char * pname = node->getParentName();
AppConfig::PrintDump(PDPass1,avar("Processing Node %s with parent %s\r\n", name, pname));
AppSequence * seq = getSequence(node);
if (seq)
{
sequences.push_back(seq);
return true;
}
if (node->isDummy())
return false;
if (isSubtree(node))
{
// Add this node to the subtree list...
AppConfig::PrintDump(PDPass1,avar("Found subtree starting at Node \"%s\"\r\n",name));
subtrees.push_back(node);
return true;
}
// See if it is a bounding box. If so, save it as THE bounding
// box for the scene
if (node->isBounds())
{
if (boundsNode)
{
AppConfig::SetExportError("4", "More than one bounds node found.");
AppConfig::PrintDump(PDPass1,"More than one bounds node found.\r\n");
}
else
AppConfig::PrintDump(PDPass1,"Bounding box found\r\n");
boundsNode = node;
return true;
}
// if we use this node, then be sure to return true so the caller doesn't delete it
bool used = false;
if (node->getNumMesh()!=0)
{
for (S32 i=0; i<node->getNumMesh(); i++)
{
AppMesh * mesh = node->getMesh(i);
if (mesh->isSkin())
{
AppConfig::PrintDump(PDPass1,avar("Skin \"%s\" with parent \"%s\" added to entry list\r\n",mesh->getName(),pname));
skins.push_back(mesh);
used = true;
}
else
{
if (node->isParentRoot())
{
AppConfig::PrintDump(PDPass1,avar("Mesh \"%s\" with parent \"%s\" added to entry list\r\n",mesh->getName(),pname));
meshNodes.push_back(node);
meshes.push_back(mesh);
used = true;
}
}
}
if (used)
usedNodes.push_back(node);
}
return used;
}
bool AppSceneEnum::isSubtree(AppNode * node)
{
return node->isParentRoot() && node->getNumMesh() == 0;
}
AppSceneEnum::AppSceneEnum()
{
boundsNode = NULL;
}
AppSceneEnum::~AppSceneEnum()
{
S32 i;
for (i=0; i<usedNodes.size(); i++)
delete usedNodes[i];
for (i=0; i<subtrees.size(); i++)
delete subtrees[i];
for (i=0; i<sequences.size(); i++)
delete sequences[i];
delete boundsNode;
}
void AppSceneEnum::updateStatus( const char *stageName, S32 stageNumber, S32 stageProgress, S32 stageProgressMax )
{
}
Shape * AppSceneEnum::processScene()
{
//setExportError(NULL);
AppConfig::PrintDump(PDPass1,"First pass: enumerate scene...\r\n\r\n");
enumScene();
if (!boundsNode)
AppConfig::SetExportError(0,"No bounds found");
if (AppConfig::IsExportError())
return NULL;
AppConfig::PrintDump(PDPass2,"\r\nSecond pass: put shape structure together...\r\n\r\n");
// set up bounds node
shapeMimic.addBounds(boundsNode);
// add other subtrees
S32 i;
for (i=0; i<subtrees.size(); i++)
shapeMimic.addSubtree(subtrees[i]);
// add meshes
for (i=0; i<meshes.size(); i++)
shapeMimic.addMesh(meshNodes[i],meshes[i]);
// add skin
for (i=0; i<skins.size(); i++)
shapeMimic.addSkin(skins[i]);
// add sequences
for (i=0; i<sequences.size(); i++)
shapeMimic.addSequence(sequences[i]);
// generate the shape
return shapeMimic.generateShape();
}
}; // namespace DTS

58
lib/dtsSDKPlus/appSceneEnum.h Executable file
View File

@ -0,0 +1,58 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef DTSAPPSCENEENUM_H_
#define DTSAPPSCENEENUM_H_
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSPlusTypes.h"
#include "ShapeMimic.h"
#include "appMesh.h"
#include "appNode.h"
#include "appSequence.h"
#include "appConfig.h"
namespace DTS
{
class AppSceneEnum
{
protected:
std::vector<AppNode*> usedNodes; // store nodes that need
// to be deleted later but
// not tracked in other lists
std::vector<AppMesh*> meshes; // don't delete these...children of nodes in usedNodes
std::vector<AppMesh*> skins; // ditto
std::vector<AppNode*> meshNodes; // don't delete these...might contain dups
std::vector<AppNode*> subtrees;
std::vector<AppSequence*> sequences;
AppNode * boundsNode;
ShapeMimic shapeMimic;
//void setExportError(const char * errStr) { AppConfig::SetExportError(errStr); }
//const char * getError() { return AppConfig::GetExportError(); }
//bool isError() { return AppConfig::IsExportError(); }
virtual bool isSubtree(AppNode * node);
virtual AppSequence * getSequence(AppNode *);
bool processNode(AppNode *);
public:
AppSceneEnum();
~AppSceneEnum();
virtual void enumScene() = 0;
Shape * processScene();
virtual void updateStatus( const char *stageName, S32 stageNumber, S32 stageProgress, S32 stageProgressMax );
};
}; // namespace DTS
#endif // #define DTSAPPSCENEENUM_H_

196
lib/dtsSDKPlus/appSequence.cpp Executable file
View File

@ -0,0 +1,196 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786 4018)
#endif
#include "appSequence.h"
#include "appNode.h"
#include "appConfig.h"
#include "DTSShape.h"
namespace DTS
{
const char * AppSequenceNode::getName()
{
const char * prefix = "Sequence::";
const char * name = mAppNode->getName();
if (!_strnicmp(name,prefix,strlen(prefix)))
name += strlen(prefix);
return name;
}
void AppSequenceNode::getSequenceData(AppSequenceData * seqData)
{
seqData->cyclic = true;
seqData->blend = false;
seqData->ignoreGround = false;
seqData->enableMorph = false;
seqData->enableTVert = false;
seqData->enableVis = true;
seqData->enableTransform = true;
seqData->enableScale = true;
seqData->enableUniformScale = true;
seqData->enableAlignedScale = true;
seqData->enableArbitraryScale = true;
seqData->enableIFL = true;
seqData->forceMorph = false;
seqData->forceTVert = false;
seqData->forceVis = false;
seqData->forceTransform = false;
seqData->forceScale = false;
seqData->frameRate = 30;
seqData->groundFrameRate = 10;
seqData->numFrames = 0;
seqData->groundNumFrames = 0;
seqData->overrideDuration = -1.0f;
seqData->priority = 5.0f;
S32 startFrame = 0;
S32 endFrame = 0;
S32 blendReferenceFrame = 0;
mAppNode->getBool("cyclic",seqData->cyclic);
mAppNode->getBool("blend",seqData->blend);
mAppNode->getBool("ignoreGround",seqData->ignoreGround);
mAppNode->getBool("enableMorph",seqData->enableMorph);
mAppNode->getBool("enableTVert",seqData->enableTVert);
mAppNode->getBool("enableVis",seqData->enableVis);
mAppNode->getBool("enableTransform",seqData->enableTransform);
mAppNode->getBool("enableScale",seqData->enableScale);
mAppNode->getBool("enableUniformScale",seqData->enableUniformScale);
mAppNode->getBool("enableAlignedScale",seqData->enableAlignedScale);
mAppNode->getBool("enableArbitraryScale",seqData->enableArbitraryScale);
mAppNode->getBool("enableIFL",seqData->enableIFL);
mAppNode->getBool("forceMorph",seqData->forceMorph);
mAppNode->getBool("forceTVert",seqData->forceTVert);
mAppNode->getBool("forceVis",seqData->forceVis);
mAppNode->getBool("forceTransform",seqData->forceTransform);
mAppNode->getBool("forceScale",seqData->forceScale);
mAppNode->getFloat("priority",seqData->priority);
mAppNode->getInt("startFrame",startFrame);
mAppNode->getInt("endFrame",endFrame);
mAppNode->getInt("blendReferenceFrame",blendReferenceFrame);
mAppNode->getFloat("overrideDuration",seqData->overrideDuration);
mAppNode->getFloat("frameRate",seqData->frameRate);
if (seqData->frameRate<0.000001f)
seqData->frameRate = 1.0f/30.0f;
mAppNode->getFloat("groundFrameRate",seqData->groundFrameRate);
if (seqData->groundFrameRate<0.000001f)
seqData->groundFrameRate = 1.0f/10.0f;
// convert from frames to times
F32 appFPS = AppConfig::AppFramesPerSec(); // not necessarily same as exported fps
F32 startTime = F32(startFrame) / appFPS;
F32 endTime = F32(endFrame) / appFPS;
F32 blendReferenceTime = F32(blendReferenceFrame) / appFPS;
seqData->startTime.set(startTime,0);
seqData->endTime.set(endTime,0);
seqData->blendReferenceTime.set(blendReferenceTime,0);
F32 duration = seqData->endTime.getF32() - seqData->startTime.getF32();
if (seqData->cyclic)
// This is required to match up with what is displayed by 3dsMax when
// playing animation cyclically. Set to zero for apps that don't need it.
duration += AppConfig::CyclicSequencePadding();
F32 delta = 0.0f;
F32 groundDelta = 0.0f;
// Get sequence timing information
if (mAppNode->getInt("numFrames",seqData->numFrames) && seqData->numFrames>0)
seqData->numFrames--;
else
seqData->numFrames = (S32) ((duration + 0.25f/seqData->frameRate) * seqData->frameRate);
delta = seqData->numFrames ? duration / F32(seqData->numFrames) : duration;
if (!seqData->cyclic)
seqData->numFrames++;
// Get sequence ground timing information
if (mAppNode->getInt("groundNumFrames",seqData->groundNumFrames) && seqData->groundNumFrames>1)
{
groundDelta = duration / (F32)(seqData->groundNumFrames-1);
}
else
{
seqData->groundNumFrames = (S32)((duration + 0.25f/seqData->groundFrameRate) * seqData->groundFrameRate);
groundDelta = seqData->groundNumFrames ? duration / (F32) seqData->groundNumFrames : duration;
seqData->groundNumFrames++;
}
seqData->duration.set(duration,0);
seqData->delta.set(delta,0);
seqData->groundDelta.set(groundDelta,0);
}
S32 AppSequenceNode::getNumTriggers()
{
S32 num = 0;
mAppNode->getInt("numTriggers",num);
return num;
}
Trigger AppSequenceNode::getTrigger(S32 idx)
{
char buffer[256];
sprintf(buffer,"triggerFrame%i",idx);
S32 frame = 0;
mAppNode->getInt(buffer,frame);
sprintf(buffer,"triggerState%i",idx);
S32 state = 0;
mAppNode->getInt(buffer,state);
AppSequenceData seqData;
getSequenceData(&seqData);
F32 appFPS = AppConfig::AppFramesPerSec(); // not necessarily same as exported fps
Trigger ret;
if (state<0)
ret.state = 1<<(-state-1);
else
ret.state = (1<<(state-1)) | TriggerState::StateOn;
if (seqData.duration.getF32()<0.001f)
ret.pos=0;
else
ret.pos = F32(frame/appFPS-seqData.startTime.getF32())/seqData.duration.getF32();
return ret;
}
void AppSequence::setTSSequence(Sequence * seq)
{
AppSequenceData seqData;
getSequenceData(&seqData);
// fill in some sequence data
seq->flags = 0;
if (seqData.cyclic)
seq->flags |= Sequence::Cyclic;
if (seqData.blend)
seq->flags |= Sequence::Blend;
seq->priority = S32(seqData.priority);
seq->numKeyFrames = seqData.numFrames;
seq->duration = seqData.overrideDuration>0 ? seqData.overrideDuration : seqData.duration.getF32();
seq->toolBegin = seqData.startTime.getF32();
seq->numTriggers = 0;
seq->firstTrigger = 0;
}
}; // namespace DTS

102
lib/dtsSDKPlus/appSequence.h Executable file
View File

@ -0,0 +1,102 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef DTSAPPSEQUENCE_H_
#define DTSAPPSEQUENCE_H_
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSPlusTypes.h"
#include "appTime.h"
namespace DTS
{
// Enum for Triggers...
namespace TriggerState
{
enum { StateOn = 1 << 31, InvertOnReverse = 1 << 30, StateMask = 0x1f };
};
class AppSequence;
class AppNode;
struct AppSequenceData
{
bool cyclic;
bool blend;
bool ignoreGround;
bool enableMorph;
bool enableTVert;
bool enableVis;
bool enableTransform;
bool enableScale;
bool enableUniformScale;
bool enableAlignedScale;
bool enableArbitraryScale;
bool enableIFL;
bool forceMorph;
bool forceTVert;
bool forceVis;
bool forceTransform;
bool forceScale;
AppTime duration;
AppTime delta;
AppTime startTime;
AppTime endTime;
AppTime blendReferenceTime;
AppTime groundDelta;
S32 numFrames;
S32 groundNumFrames;
F32 frameRate;
F32 groundFrameRate;
F32 overrideDuration;
F32 priority;
};
class AppSequence
{
public:
virtual const char * getName() = 0;
virtual void getSequenceData(AppSequenceData *) = 0;
virtual S32 getNumTriggers() = 0;
virtual Trigger getTrigger(S32 idx) = 0;
virtual void setTSSequence(Sequence *);
};
// Create a sequence from an appropriately outfitted node
// Uses property values to figure everything out.
// This system is adequate for all dts features and will
// work in any 3d package which supports naming nodes and adding
// property values to nodes. Specific 3d apps can add support
// guis to manipulate these sequence objects.
class AppSequenceNode : public AppSequence
{
AppNode * mAppNode;
public:
AppSequenceNode(AppNode * node) { mAppNode=node; }
const char * getName();
void getSequenceData(AppSequenceData *);
S32 getNumTriggers();
Trigger getTrigger(S32 idx);
};
};
#endif // DTSAPPSEQUENCE_H_

42
lib/dtsSDKPlus/appTime.cpp Executable file
View File

@ -0,0 +1,42 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786 4018)
#endif
#include "appTime.h"
#include <string>
namespace DTS
{
// Default time...base pose
AppTime AppTime::smDefaultTime(0,0);
// equality tolerance for f64 component
F64 AppTime::smTOL = 0.0001;
// when converting to string, display S32? display F32?
bool AppTime::smPrintInt = false;
bool AppTime::smPrintFloat = true;
const char * AppTime::getStr() const
{
if (!mBuffer)
const_cast<char*>(mBuffer) = new char[64];
if (smPrintInt && smPrintFloat)
sprintf(mBuffer,"%f:%i",F32(f64),u32);
else if (smPrintInt)
sprintf(mBuffer,"%i",u32);
else if (smPrintFloat)
sprintf(mBuffer,"%f",F32(f64));
else
return "";
return mBuffer;
}
}; // namespace DTS

93
lib/dtsSDKPlus/appTime.h Executable file
View File

@ -0,0 +1,93 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef DTSAPPTIME_H_
#define DTSAPPTIME_H_
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSPlusTypes.h"
namespace DTS
{
class AppTime
{
static AppTime smDefaultTime;
static F64 smTOL;
static bool smPrintInt;
static bool smPrintFloat;
F64 f64;
U32 u32;
char * mBuffer;
public:
void set(F64 f, U32 i) { u32=i;f64=f; }
// app can use however desired
F32 getF32() const { return (F32)f64; }
F64 getF64() const { return f64; }
U32 getU32() const { return u32; }
S32 getS32() const { return S32(u32); }
const char * getStr() const;
static const AppTime & DefaultTime() { return smDefaultTime; }
static void SetDefaultTime(const AppTime & def) { smDefaultTime = def; }
static F64 TOL() { return smTOL; }
static void SetTOL(F64 tol) { smTOL = tol; }
static void SetPrintInt(bool i) { smPrintInt=i; }
static void SetPrintFloat(bool f) { smPrintFloat=f; }
// operators...
AppTime & operator+=(const AppTime & r)
{
f64 += r.f64;
u32 += r.u32;
return *this;
}
AppTime & operator-=(const AppTime & r)
{
f64 -= r.f64;
u32 -= r.u32;
return *this;
}
friend AppTime operator+(const AppTime & a, const AppTime & b)
{
return AppTime(a.f64+b.f64,a.u32+b.u32);
}
friend bool operator<(const AppTime & a, const AppTime & b)
{
return (a.f64 < b.f64 && a.u32 <= b.u32);
}
friend bool operator>(const AppTime & a, const AppTime & b)
{
return b<a;
}
friend bool operator<=(const AppTime & a, const AppTime & b)
{
return (a.f64 <= b.f64 && a.u32 <= b.u32);
}
friend bool operator>=(const AppTime & a, const AppTime & b)
{
return b<=a;
}
friend bool operator==(const AppTime & a, const AppTime & b)
{
return ((fabs(a.f64 - b.f64) < AppTime::TOL()) && (a.u32 == b.u32));
}
friend bool operator!=(const AppTime & a, const AppTime & b)
{
return !(a==b);
}
AppTime(F64 f, U32 i) { set(f,i); mBuffer=NULL; }
AppTime() { set(0,0); mBuffer=NULL; }
~AppTime() { delete [] mBuffer; }
};
};
#endif // DTSAPPTIME_H_

View File

@ -0,0 +1,533 @@
/**** Decompose.c ****/
/* Ken Shoemake, 1993 */
#include <math.h>
#include "Decompose.h"
namespace GraphicGems
{
/******* Matrix Preliminaries *******/
/** Fill out 3x3 matrix to 4x4 **/
#define mat_pad(A) (A[W][X]=A[X][W]=A[W][Y]=A[Y][W]=A[W][Z]=A[Z][W]=0,A[W][W]=1)
/** Copy nxn matrix A to C using "gets" for assignment **/
#define mat_copy(C,gets,A,n) {S32 i,j; for(i=0;i<n;i++) for(j=0;j<n;j++)\
C[i][j] gets (A[i][j]);}
/** Copy transpose of nxn matrix A to C using "gets" for assignment **/
#define mat_tpose(AT,gets,A,n) {S32 i,j; for(i=0;i<n;i++) for(j=0;j<n;j++)\
AT[i][j] gets (A[j][i]);}
/** Assign nxn matrix C the element-wise combination of A and B using "op" **/
#define mat_binop(C,gets,A,op,B,n) {S32 i,j; for(i=0;i<n;i++) for(j=0;j<n;j++)\
C[i][j] gets (A[i][j]) op (B[i][j]);}
/** Multiply the upper left 3x3 parts of A and B to get AB **/
void mat_mult(HMatrix A, HMatrix B, HMatrix AB)
{
S32 i, j;
for (i=0; i<3; i++) for (j=0; j<3; j++)
AB[i][j] = A[i][0]*B[0][j] + A[i][1]*B[1][j] + A[i][2]*B[2][j];
}
/** Return dot product of length 3 vectors va and vb **/
F64 vdot(F64 *va, F64 *vb)
{
return (va[0]*vb[0] + va[1]*vb[1] + va[2]*vb[2]);
}
/** Set v to cross product of length 3 vectors va and vb **/
void vcross(F64 *va, F64 *vb, F64 *v)
{
v[0] = va[1]*vb[2] - va[2]*vb[1];
v[1] = va[2]*vb[0] - va[0]*vb[2];
v[2] = va[0]*vb[1] - va[1]*vb[0];
}
/** Set MadjT to transpose of inverse of M times determinant of M **/
void adjoint_transpose(HMatrix M, HMatrix MadjT)
{
vcross(M[1], M[2], MadjT[0]);
vcross(M[2], M[0], MadjT[1]);
vcross(M[0], M[1], MadjT[2]);
}
/******* Quaternion Preliminaries *******/
/* Construct a (possibly non-unit) quaternion from real components. */
Quat Qt_(F64 x, F64 y, F64 z, F64 w)
{
Quat qq;
qq.x = x;
qq.y = y;
qq.z = z;
qq.w = w;
return (qq);
}
/* Return conjugate of quaternion. */
Quat Qt_Conj(Quat q)
{
Quat qq;
qq.x = -q.x;
qq.y = -q.y;
qq.z = -q.z;
qq.w = q.w;
return (qq);
}
/* Return quaternion product qL * qR. Note: order is important!
* To combine rotations, use the product Mul(qSecond, qFirst),
* which gives the effect of rotating by qFirst then qSecond. */
Quat Qt_Mul(Quat qL, Quat qR)
{
Quat qq;
qq.w = qL.w*qR.w - qL.x*qR.x - qL.y*qR.y - qL.z*qR.z;
qq.x = qL.w*qR.x + qL.x*qR.w + qL.y*qR.z - qL.z*qR.y;
qq.y = qL.w*qR.y + qL.y*qR.w + qL.z*qR.x - qL.x*qR.z;
qq.z = qL.w*qR.z + qL.z*qR.w + qL.x*qR.y - qL.y*qR.x;
return (qq);
}
/* Return product of quaternion q by scalar w. */
Quat Qt_Scale(Quat q, F64 w)
{
Quat qq;
qq.w = q.w*w;
qq.x = q.x*w;
qq.y = q.y*w;
qq.z = q.z*w;
return (qq);
}
/* Construct a unit quaternion from rotation matrix. Assumes matrix is
* used to multiply column vector on the left: vnew = mat vold. Works
* correctly for right-handed coordinate system and right-handed rotations.
* Translation and perspective components ignored. */
Quat Qt_FromMatrix(HMatrix mat)
{
/* This algorithm avoids near-zero divides by looking for a large component
* - first w, then x, y, or z. When the trace is greater than zero,
* |w| is greater than 1/2, which is as small as a largest component can be.
* Otherwise, the largest diagonal entry corresponds to the largest of |x|,
* |y|, or |z|, one of which must be larger than |w|, and at least 1/2. */
Quat qu;
register F64 tr, s;
tr = mat[X][X] + mat[Y][Y]+ mat[Z][Z];
if (tr >= 0.0) {
s = sqrt(tr + mat[W][W]);
qu.w = s*0.5;
s = 0.5 / s;
qu.x = (mat[Z][Y] - mat[Y][Z]) * s;
qu.y = (mat[X][Z] - mat[Z][X]) * s;
qu.z = (mat[Y][X] - mat[X][Y]) * s;
} else {
S32 h = X;
if (mat[Y][Y] > mat[X][X]) h = Y;
if (mat[Z][Z] > mat[h][h]) h = Z;
switch (h) {
#define caseMacro(i,j,k,I,J,K) \
case I:\
s = sqrt( (mat[I][I] - (mat[J][J]+mat[K][K])) + mat[W][W] );\
qu.i = s*0.5;\
s = 0.5 / s;\
qu.j = (mat[I][J] + mat[J][I]) * s;\
qu.k = (mat[K][I] + mat[I][K]) * s;\
qu.w = (mat[K][J] - mat[J][K]) * s;\
break
caseMacro(x,y,z,X,Y,Z);
caseMacro(y,z,x,Y,Z,X);
caseMacro(z,x,y,Z,X,Y);
}
}
if (mat[W][W] != 1.0) qu = Qt_Scale(qu, 1/sqrt(mat[W][W]));
return (qu);
}
/******* Decomp Auxiliaries *******/
static HMatrix mat_id = {
{1,0,0,0},
{0,1,0,0},
{0,0,1,0},
{0,0,0,1}
};
/** Compute either the 1 or infinity norm of M, depending on tpose **/
F64 mat_norm(HMatrix M, S32 tpose)
{
S32 i;
F64 sum, max;
max = 0.0;
for (i=0; i<3; i++)
{
if (tpose)
sum = fabs(M[0][i])+fabs(M[1][i])+fabs(M[2][i]);
else
sum = fabs(M[i][0])+fabs(M[i][1])+fabs(M[i][2]);
if (max<sum)
max = sum;
}
return max;
}
F64 norm_inf(HMatrix M) {
return mat_norm(M, 0);
}
F64 norm_one(HMatrix M) {
return mat_norm(M, 1);
}
/** Return index of column of M containing maximum abs entry, or -1 if M=0 **/
S32 find_max_col(HMatrix M)
{
F64 abs, max;
S32 i, j, col;
max = 0.0; col = -1;
for (i=0; i<3; i++) for (j=0; j<3; j++) {
abs = M[i][j]; if (abs<0.0) abs = -abs;
if (abs>max) {max = abs; col = j;}
}
return col;
}
/** Setup u for Household reflection to zero all v components but first **/
void make_reflector(F64 *v, F64 *u)
{
F64 s = sqrt(vdot(v, v));
u[0] = v[0]; u[1] = v[1];
u[2] = v[2] + ((v[2]<0.0) ? -s : s);
s = sqrt(2.0/vdot(u, u));
u[0] = u[0]*s; u[1] = u[1]*s; u[2] = u[2]*s;
}
/** Apply Householder reflection represented by u to column vectors of M **/
void reflect_cols(HMatrix M, F64 *u)
{
S32 i, j;
for (i=0; i<3; i++) {
F64 s = u[0]*M[0][i] + u[1]*M[1][i] + u[2]*M[2][i];
for (j=0; j<3; j++) M[j][i] -= u[j]*s;
}
}
/** Apply Householder reflection represented by u to row vectors of M **/
void reflect_rows(HMatrix M, F64 *u)
{
S32 i, j;
for (i=0; i<3; i++) {
F64 s = vdot(u, M[i]);
for (j=0; j<3; j++) M[i][j] -= u[j]*s;
}
}
/** Find orthogonal factor Q of rank 1 (or less) M **/
void do_rank1(HMatrix M, HMatrix Q)
{
F64 v1[3], v2[3], s;
S32 col;
mat_copy(Q,=,mat_id,4);
/* If rank(M) is 1, we should find a non-zero column in M */
col = find_max_col(M);
if (col<0) return; /* Rank is 0 */
v1[0] = M[0][col]; v1[1] = M[1][col]; v1[2] = M[2][col];
make_reflector(v1, v1); reflect_cols(M, v1);
v2[0] = M[2][0]; v2[1] = M[2][1]; v2[2] = M[2][2];
make_reflector(v2, v2); reflect_rows(M, v2);
s = M[2][2];
if (s<0.0) Q[2][2] = -1.0;
reflect_cols(Q, v1); reflect_rows(Q, v2);
}
/** Find orthogonal factor Q of rank 2 (or less) M using adjoint transpose **/
void do_rank2(HMatrix M, HMatrix MadjT, HMatrix Q)
{
F64 v1[3], v2[3];
F64 w, x, y, z, c, s, d;
S32 col;
/* If rank(M) is 2, we should find a non-zero column in MadjT */
col = find_max_col(MadjT);
if (col<0) {do_rank1(M, Q); return;} /* Rank<2 */
v1[0] = MadjT[0][col]; v1[1] = MadjT[1][col]; v1[2] = MadjT[2][col];
make_reflector(v1, v1); reflect_cols(M, v1);
vcross(M[0], M[1], v2);
make_reflector(v2, v2); reflect_rows(M, v2);
w = M[0][0]; x = M[0][1]; y = M[1][0]; z = M[1][1];
if (w*z>x*y) {
c = z+w; s = y-x; d = sqrt(c*c+s*s); c = c/d; s = s/d;
Q[0][0] = Q[1][1] = c; Q[0][1] = -(Q[1][0] = s);
} else {
c = z-w; s = y+x; d = sqrt(c*c+s*s); c = c/d; s = s/d;
Q[0][0] = -(Q[1][1] = c); Q[0][1] = Q[1][0] = s;
}
Q[0][2] = Q[2][0] = Q[1][2] = Q[2][1] = 0.0; Q[2][2] = 1.0;
reflect_cols(Q, v1); reflect_rows(Q, v2);
}
/******* Polar Decomposition *******/
/* Polar Decomposition of 3x3 matrix in 4x4,
* M = QS. See Nicholas Higham and Robert S. Schreiber,
* Fast Polar Decomposition of An Arbitrary Matrix,
* Technical Report 88-942, October 1988,
* Department of Computer Science, Cornell University.
*/
F64 polar_decomp(HMatrix M, HMatrix Q, HMatrix S)
{
#define TOL 1.0e-6
HMatrix Mk, MadjTk, Ek;
F64 det, M_one, M_inf, MadjT_one, MadjT_inf, E_one, gamma, g1, g2;
S32 i, j;
mat_tpose(Mk,=,M,3);
M_one = norm_one(Mk); M_inf = norm_inf(Mk);
do {
adjoint_transpose(Mk, MadjTk);
det = vdot(Mk[0], MadjTk[0]);
if (det==0.0) {do_rank2(Mk, MadjTk, Mk); break;}
MadjT_one = norm_one(MadjTk); MadjT_inf = norm_inf(MadjTk);
gamma = sqrt(sqrt((MadjT_one*MadjT_inf)/(M_one*M_inf))/fabs(det));
g1 = gamma*0.5;
g2 = 0.5/(gamma*det);
mat_copy(Ek,=,Mk,3);
mat_binop(Mk,=,g1*Mk,+,g2*MadjTk,3);
mat_copy(Ek,-=,Mk,3);
E_one = norm_one(Ek);
M_one = norm_one(Mk); M_inf = norm_inf(Mk);
} while (E_one>(M_one*TOL));
mat_tpose(Q,=,Mk,3); mat_pad(Q);
mat_mult(Mk, M, S); mat_pad(S);
for (i=0; i<3; i++) for (j=i; j<3; j++)
S[i][j] = S[j][i] = 0.5*(S[i][j]+S[j][i]);
return (det);
}
/******* Spectral Decomposition *******/
/* Compute the spectral decomposition of symmetric positive semi-definite S.
* Returns rotation in U and scale factors in result, so that if K is a diagonal
* matrix of the scale factors, then S = U K (U transpose). Uses Jacobi method.
* See Gene H. Golub and Charles F. Van Loan. Matrix Computations. Hopkins 1983.
*/
HVect spect_decomp(HMatrix S, HMatrix U)
{
HVect kv;
F64 Diag[3],OffD[3]; /* OffD is off-diag (by omitted index) */
F64 g,h,fabsh,fabsOffDi,t,theta,c,s,tau,ta,OffDq,a,b;
static S8 nxt[] = {Y,Z,X};
S32 sweep, i, j;
mat_copy(U,=,mat_id,4);
Diag[X] = S[X][X]; Diag[Y] = S[Y][Y]; Diag[Z] = S[Z][Z];
OffD[X] = S[Y][Z]; OffD[Y] = S[Z][X]; OffD[Z] = S[X][Y];
for (sweep=20; sweep>0; sweep--) {
F64 sm = fabs(OffD[X])+fabs(OffD[Y])+fabs(OffD[Z]);
if (sm==0.0) break;
for (i=Z; i>=X; i--) {
S32 p = nxt[i]; S32 q = nxt[p];
fabsOffDi = fabs(OffD[i]);
g = 100.0*fabsOffDi;
if (fabsOffDi>0.0) {
h = Diag[q] - Diag[p];
fabsh = fabs(h);
if (fabsh+g==fabsh) {
t = OffD[i]/h;
} else {
theta = 0.5*h/OffD[i];
t = 1.0/(fabs(theta)+sqrt(theta*theta+1.0));
if (theta<0.0) t = -t;
}
c = 1.0/sqrt(t*t+1.0); s = t*c;
tau = s/(c+1.0);
ta = t*OffD[i]; OffD[i] = 0.0;
Diag[p] -= ta; Diag[q] += ta;
OffDq = OffD[q];
OffD[q] -= s*(OffD[p] + tau*OffD[q]);
OffD[p] += s*(OffDq - tau*OffD[p]);
for (j=Z; j>=X; j--) {
a = U[j][p]; b = U[j][q];
U[j][p] -= s*(b + tau*a);
U[j][q] += s*(a - tau*b);
}
}
}
}
kv.x = Diag[X]; kv.y = Diag[Y]; kv.z = Diag[Z]; kv.w = 1.0;
return (kv);
}
/******* Spectral Axis Adjustment *******/
/* Given a unit quaternion, q, and a scale vector, k, find a unit quaternion, p,
* which permutes the axes and turns freely in the plane of duplicate scale
* factors, such that q p has the largest possible w component, i.e. the
* smallest possible angle. Permutes k's components to go with q p instead of q.
* See Ken Shoemake and Tom Duff. Matrix Animation and Polar Decomposition.
* Proceedings of Graphics Interface 1992. Details on p. 262-263.
*/
Quat snuggle(Quat q, HVect *k)
{
#define SQRTHALF (0.7071067811865475244)
#define sgn(n,v) ((n)?-(v):(v))
#define swap(a,i,j) {a[3]=a[i]; a[i]=a[j]; a[j]=a[3];}
#define cycle(a,p) if (p) {a[3]=a[0]; a[0]=a[1]; a[1]=a[2]; a[2]=a[3];}\
else {a[3]=a[2]; a[2]=a[1]; a[1]=a[0]; a[0]=a[3];}
Quat p;
F64 ka[4];
S32 i, turn = -1;
ka[X] = k->x; ka[Y] = k->y; ka[Z] = k->z;
if (ka[X]==ka[Y]) {if (ka[X]==ka[Z]) turn = W; else turn = Z;}
else {if (ka[X]==ka[Z]) turn = Y; else if (ka[Y]==ka[Z]) turn = X;}
if (turn>=0) {
Quat qtoz, qp;
unsigned neg[3], win;
F64 mag[3], t;
static Quat qxtoz = {0,SQRTHALF,0,SQRTHALF};
static Quat qytoz = {SQRTHALF,0,0,SQRTHALF};
static Quat qppmm = { 0.5, 0.5,-0.5,-0.5};
static Quat qpppp = { 0.5, 0.5, 0.5, 0.5};
static Quat qmpmm = {-0.5, 0.5,-0.5,-0.5};
static Quat qpppm = { 0.5, 0.5, 0.5,-0.5};
static Quat q0001 = { 0.0, 0.0, 0.0, 1.0};
static Quat q1000 = { 1.0, 0.0, 0.0, 0.0};
switch (turn) {
default: return (Qt_Conj(q));
case X: q = Qt_Mul(q, qtoz = qxtoz); swap(ka,X,Z) break;
case Y: q = Qt_Mul(q, qtoz = qytoz); swap(ka,Y,Z) break;
case Z: qtoz = q0001; break;
}
q = Qt_Conj(q);
mag[0] = (F64)q.z*q.z+(F64)q.w*q.w-0.5;
mag[1] = (F64)q.x*q.z-(F64)q.y*q.w;
mag[2] = (F64)q.y*q.z+(F64)q.x*q.w;
for (i=0; i<3; i++) if (neg[i] = (mag[i]<0.0)) mag[i] = -mag[i];
if (mag[0]>mag[1]) {if (mag[0]>mag[2]) win = 0; else win = 2;}
else {if (mag[1]>mag[2]) win = 1; else win = 2;}
switch (win) {
case 0: if (neg[0]) p = q1000; else p = q0001; break;
case 1: if (neg[1]) p = qppmm; else p = qpppp; cycle(ka,0) break;
case 2: if (neg[2]) p = qmpmm; else p = qpppm; cycle(ka,1) break;
}
qp = Qt_Mul(q, p);
t = sqrt(mag[win]+0.5);
p = Qt_Mul(p, Qt_(0.0,0.0,-qp.z/t,qp.w/t));
p = Qt_Mul(qtoz, Qt_Conj(p));
} else {
F64 qa[4], pa[4];
unsigned lo, hi, neg[4], par = 0;
F64 all, big, two;
qa[0] = q.x; qa[1] = q.y; qa[2] = q.z; qa[3] = q.w;
for (i=0; i<4; i++) {
pa[i] = 0.0;
if (neg[i] = (qa[i]<0.0)) qa[i] = -qa[i];
par ^= neg[i];
}
/* Find two largest components, indices in hi and lo */
if (qa[0]>qa[1]) lo = 0; else lo = 1;
if (qa[2]>qa[3]) hi = 2; else hi = 3;
if (qa[lo]>qa[hi]) {
if (qa[lo^1]>qa[hi]) {hi = lo; lo ^= 1;}
else {hi ^= lo; lo ^= hi; hi ^= lo;}
} else {if (qa[hi^1]>qa[lo]) lo = hi^1;}
all = (qa[0]+qa[1]+qa[2]+qa[3])*0.5;
two = (qa[hi]+qa[lo])*SQRTHALF;
big = qa[hi];
if (all>two) {
if (all>big) {/*all*/
{S32 i; for (i=0; i<4; i++) pa[i] = sgn(neg[i], 0.5);}
cycle(ka,par)
} else {/*big*/ pa[hi] = sgn(neg[hi],1.0);}
} else {
if (two>big) {/*two*/
pa[hi] = sgn(neg[hi],SQRTHALF); pa[lo] = sgn(neg[lo], SQRTHALF);
if (lo>hi) {hi ^= lo; lo ^= hi; hi ^= lo;}
if (hi==W) {hi = "\001\002\000"[lo]; lo = 3-hi-lo;}
swap(ka,hi,lo)
} else {/*big*/ pa[hi] = sgn(neg[hi],1.0);}
}
p.x = -pa[0]; p.y = -pa[1]; p.z = -pa[2]; p.w = pa[3];
}
k->x = ka[X]; k->y = ka[Y]; k->z = ka[Z];
return (p);
}
/******* Decompose Affine Matrix *******/
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
/* Decompose 4x4 affine matrix A as TFRUK(U transpose), where t contains the
* translation components, q contains the rotation R, u contains U, k contains
* scale factors, and f contains the sign of the determinant.
* Assumes A transforms column vectors in right-handed coordinates.
* See Ken Shoemake and Tom Duff. Matrix Animation and Polar Decomposition.
* Proceedings of Graphics Interface 1992.
*/
void decomp_affine(HMatrix A, AffineParts *parts)
{
HMatrix Q, S, U;
Quat p;
F64 det;
parts->t = Qt_(A[X][W], A[Y][W], A[Z][W], 0);
det = polar_decomp(A, Q, S);
if (det<0.0) {
mat_copy(Q,=,-Q,3);
parts->f = -1;
} else parts->f = 1;
parts->q = Qt_FromMatrix(Q);
parts->k = spect_decomp(S, U);
parts->u = Qt_FromMatrix(U);
p = snuggle(parts->u, &parts->k);
parts->u = Qt_Mul(parts->u, p);
}
/******* Invert Affine Decomposition *******/
/* Compute inverse of affine decomposition.
*/
void invert_affine(AffineParts *parts, AffineParts *inverse)
{
Quat t, p;
inverse->f = parts->f;
inverse->q = Qt_Conj(parts->q);
inverse->u = Qt_Mul(parts->q, parts->u);
inverse->k.x = (parts->k.x==0.0) ? 0.0 : 1.0/parts->k.x;
inverse->k.y = (parts->k.y==0.0) ? 0.0 : 1.0/parts->k.y;
inverse->k.z = (parts->k.z==0.0) ? 0.0 : 1.0/parts->k.z;
inverse->k.w = parts->k.w;
t = Qt_(-parts->t.x, -parts->t.y, -parts->t.z, 0);
t = Qt_Mul(Qt_Conj(inverse->u), Qt_Mul(t, inverse->u));
t = Qt_(inverse->k.x*t.x, inverse->k.y*t.y, inverse->k.z*t.z, 0);
p = Qt_Mul(inverse->q, inverse->u);
t = Qt_Mul(p, Qt_Mul(t, Qt_Conj(p)));
inverse->t = (inverse->f>0.0) ? t : Qt_(-t.x, -t.y, -t.z, 0);
}
}; // namespace GraphicGems

View File

@ -0,0 +1,34 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
/**** Decompose.h - Basic declarations ****/
#ifndef _H_Decompose
#define _H_Decompose
#include "../DTSPlusTypes.h"
namespace GraphicGems
{
typedef struct {F64 x, y, z, w;} Quat; /* Quaternion */
enum QuatPart {X, Y, Z, W};
typedef Quat HVect; /* Homogeneous 3D vector */
typedef F64 HMatrix[4][4]; /* Right-handed, for column vectors */
typedef struct {
HVect t; /* Translation components */
Quat q; /* Essential rotation */
Quat u; /* Stretch rotation */
HVect k; /* Stretch factors */
F64 f; /* Sign of determinant */
} AffineParts;
F64 polar_decomp(HMatrix M, HMatrix Q, HMatrix S);
HVect spect_decomp(HMatrix S, HMatrix U);
Quat snuggle(Quat q, HVect *k);
void decomp_affine(HMatrix A, AffineParts *parts);
void invert_affine(AffineParts *parts, AffineParts *inverse);
}; // namespace GraphicGems
#endif

318
lib/dtsSDKPlus/dtsBitMatrix.h Executable file
View File

@ -0,0 +1,318 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSMesh.h"
#include "DTSPlusTypes.h"
#include "DTSUtil.h"
// This is rather painful. BitVector and BitMatrix copied from engine repository
// in order to work with triangle stripper. Would rather use NVidia stripper, but
// there is a bug in it whereby we sometimes get flipped faces. So we are stuck
// with the old quick/dirty/ugly (but supremely reliable) original implementation.
namespace DTS
{
#define AssertFatal(a,b) assert(a && b)
class BitVector
{
U8* mBits;
U32 mByteSize;
U32 mSize;
static U32 calcByteSize(const U32 numBits);
public:
BitVector();
BitVector(const U32 _size);
~BitVector();
/// @name Size Management
/// @{
void setSize(const U32 _size);
U32 getSize() const;
U32 getByteSize() const;
U32 getAllocatedByteSize() const { return mByteSize; }
const U8* getBits() const { return mBits; }
U8* getNCBits() { return mBits; }
/// @}
bool copy(const BitVector& from);
/// @name Mutators
/// Note that bits are specified by index, unlike BitSet32.
/// @{
/// Clear all the bits.
void clear();
/// Set all the bits.
void set();
/// Set the specified bit.
void set(U32 bit);
/// Clear the specified bit.
void clear(U32 bit);
/// Test that the specified bit is set.
bool test(U32 bit) const;
/// @}
};
inline BitVector::BitVector()
{
mBits = NULL;
mByteSize = 0;
mSize = 0;
}
inline BitVector::BitVector(const U32 _size)
{
mBits = NULL;
mByteSize = 0;
mSize = 0;
setSize(_size);
}
inline BitVector::~BitVector()
{
delete [] mBits;
mBits = NULL;
mByteSize = 0;
mSize = 0;
}
inline U32 BitVector::calcByteSize(const U32 numBits)
{
// Make sure that we are 32 bit aligned
//
return (((numBits + 0x7) >> 3) + 0x3) & ~0x3;
}
inline void BitVector::setSize(const U32 _size)
{
if (_size != 0) {
U32 newSize = calcByteSize(_size);
if (mByteSize < newSize) {
delete [] mBits;
mBits = new U8[newSize];
mByteSize = newSize;
}
} else {
delete [] mBits;
mBits = NULL;
mByteSize = 0;
}
mSize = _size;
}
inline U32 BitVector::getSize() const
{
return mSize;
}
inline U32 BitVector::getByteSize() const
{
return calcByteSize(mSize);
}
inline void BitVector::clear()
{
if (mSize != 0)
memset(mBits, 0x00, calcByteSize(mSize));
}
inline bool BitVector::copy(const BitVector& from)
{
U32 sourceSize = from.getSize();
if (sourceSize) {
setSize(sourceSize);
memcpy(mBits, from.getBits(), getByteSize());
return true;
}
return false;
}
inline void BitVector::set()
{
if (mSize != 0)
memset(mBits, 0xFF, calcByteSize(mSize));
}
inline void BitVector::set(U32 bit)
{
AssertFatal(bit < mSize, "Error, out of range bit");
mBits[bit >> 3] |= U8(1 << (bit & 0x7));
}
inline void BitVector::clear(U32 bit)
{
AssertFatal(bit < mSize, "Error, out of range bit");
mBits[bit >> 3] &= U8(~(1 << (bit & 0x7)));
}
inline bool BitVector::test(U32 bit) const
{
AssertFatal(bit < mSize, "Error, out of range bit");
return (mBits[bit >> 3] & U8(1 << (bit & 0x7))) != 0;
}
class BitMatrix
{
U32 mWidth;
U32 mHeight;
U32 mRowByteWidth;
U8* mBits;
U32 mSize;
BitVector mColFlags;
BitVector mRowFlags;
public:
/// Create a new bit matrix.
///
/// @param width Width of matrix in bits.
/// @param height Height of matrix in bits.
BitMatrix(const U32 width, const U32 height);
~BitMatrix();
/// @name Setters
/// @{
/// Set all the bits in the matrix to false.
void clearAllBits();
/// Set all the bits in the matrix to true.
void setAllBits();
/// Set a bit at a given location in the matrix.
void setBit(const U32 x, const U32 y);
/// Clear a bit at a given location in the matrix.
void clearBit(const U32 x, const U32 y);
/// @}
/// @name Queries
/// @{
/// Is the specified bit set?
bool isSet(const U32 x, const U32 y) const;
/// Is any bit in the given column set?
bool isAnySetCol(const U32 x);
/// Is any bit in the given row set?
bool isAnySetRow(const U32 y);
/// @}
};
inline BitMatrix::BitMatrix(const U32 width, const U32 height)
: mColFlags(width),
mRowFlags(height)
{
AssertFatal(width != 0 && height != 0, "Error, w/h must be non-zero");
mWidth = width;
mHeight = height;
mRowByteWidth = (width + 7) >> 3;
mSize = mRowByteWidth * mHeight;
mBits = new U8[mSize];
}
inline BitMatrix::~BitMatrix()
{
mWidth = 0;
mHeight = 0;
mRowByteWidth = 0;
mSize = 0;
delete [] mBits;
mBits = NULL;
}
inline void BitMatrix::clearAllBits()
{
AssertFatal(mBits != NULL, "Error, clearing after deletion");
memset(mBits, 0x00, mSize);
mColFlags.clear();
mRowFlags.clear();
}
inline void BitMatrix::setAllBits()
{
AssertFatal(mBits != NULL, "Error, setting after deletion");
memset(mBits, 0xFF, mSize);
mColFlags.set();
mRowFlags.set();
}
inline void BitMatrix::setBit(const U32 x, const U32 y)
{
AssertFatal(x < mWidth && y < mHeight, "Error, out of bounds bit!");
U8* pRow = &mBits[y * mRowByteWidth];
U8* pByte = &pRow[x >> 3];
*pByte |= 1 << (x & 0x7);
mColFlags.set(x);
mRowFlags.set(y);
}
inline void BitMatrix::clearBit(const U32 x, const U32 y)
{
AssertFatal(x < mWidth && y < mHeight, "Error, out of bounds bit!");
U8* pRow = &mBits[y * mRowByteWidth];
U8* pByte = &pRow[x >> 3];
*pByte &= ~(1 << (x & 0x7));
}
inline bool BitMatrix::isSet(const U32 x, const U32 y) const
{
AssertFatal(x < mWidth && y < mHeight, "Error, out of bounds bit!");
U8* pRow = &mBits[y * mRowByteWidth];
U8* pByte = &pRow[x >> 3];
return (*pByte & (1 << (x & 0x7))) != 0;
}
inline bool BitMatrix::isAnySetCol(const U32 x)
{
AssertFatal(x < mWidth, "Error, out of bounds column!");
return mColFlags.test(x);
}
inline bool BitMatrix::isAnySetRow(const U32 y)
{
AssertFatal(y < mHeight, "Error, out of bounds row!");
return mRowFlags.test(y);
}
} // namespace DTS

109
lib/dtsSDKPlus/nvStripWrap.cpp Executable file
View File

@ -0,0 +1,109 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786 4018)
#endif
#include "nvStripWrap.h"
#include "nvtristrip/NvTriStrip.h"
#include "nvtristrip/NvTriStripObjects.h"
namespace DTS
{
void nvMakeStrips(std::vector<Primitive> & primitives, std::vector<U16> & indices, S32 cacheSize, U32 matIndex)
{
// incoming indices may have some "holes" in them...e.g., may have index 1,2,3,6,7 only
// map to 0..N-1
std::vector<S16> map;
std::vector<S16> remap;
U16 next=0;
S32 i;
for (i=0; i<indices.size(); i++)
{
while (indices[i]>=map.size())
map.push_back(-1);
if (map[indices[i]]<0)
{
map[indices[i]]=next++;
remap.push_back(indices[i]);
}
indices[i] = map[indices[i]];
}
PrimitiveGroup * primGroups;
U16 numGroups;
GenerateStrips(&indices[0],indices.size(),&primGroups,&numGroups);
for (i=0; i<numGroups; i++)
{
assert(primGroups[i].type == PT_STRIP);
Primitive strip;
strip.type = matIndex;
strip.firstElement = indices.size();
strip.numElements = primGroups[i].numIndices;
primitives.push_back(strip);
for (S32 j=0; j<primGroups[i].numIndices; j++)
indices.push_back(primGroups[i].indices[j]);
}
delete [] primGroups;
// remap indices...
for (i=0; i<indices.size(); i++)
indices[i] = remap[indices[i]];
}
void nvStripWrap(std::vector<Primitive> & faces, std::vector<U16> & indices, S32 cacheSize)
{
// set stripper parameters...we'll just set some default ones
SetCacheSize(cacheSize);
SetStitchStrips(true); // engine can handle this, so let it
SetListsOnly(false); // engine can handle this, so let it
SetMinStripSize(0); // engine can handle this, so let it
// main strip loop...
U32 start, end, i;
std::vector<Primitive> someStrips;
std::vector<Primitive> retStrips;
std::vector<U16> someIndices;
std::vector<U16> retIndices;
for (start = 0; start<faces.size(); start=end)
{
for (end=start; end<faces.size() && faces[start].type==faces[end].type; end++)
;
// copy start to end faces into new list -- this is so we end up doing less copying
// down the road (when we are doing the look ahead simulation)
someStrips.clear();
someIndices.clear();
for (i=start;i<end;i++)
{
someIndices.push_back(indices[faces[i].firstElement + 0]);
someIndices.push_back(indices[faces[i].firstElement + 1]);
someIndices.push_back(indices[faces[i].firstElement + 2]);
}
U32 matIndex = faces[start].type ^ (Primitive::Triangles|Primitive::Strip);
nvMakeStrips(someStrips,someIndices,cacheSize,matIndex);
// now move strips and indices into larger list
S32 startStrips = retStrips.size();
retStrips.resize(startStrips+someStrips.size());
S32 startIndices = retIndices.size();
retIndices.resize(startIndices+someIndices.size());
memcpy(&retStrips[startStrips],&someStrips[0],someStrips.size()*sizeof(Primitive));
memcpy(&retIndices[startIndices],&someIndices[0],someIndices.size()*sizeof(U16));
// now adjust start of new strips
for (i=startStrips; i<retStrips.size(); i++)
retStrips[i].firstElement += startIndices;
}
indices = retIndices;
faces = retStrips;
}
}; // namespace DTS

18
lib/dtsSDKPlus/nvStripWrap.h Executable file
View File

@ -0,0 +1,18 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSMesh.h"
#include "DTSPlusTypes.h"
#include "DTSUtil.h"
namespace DTS
{
extern void nvStripWrap(std::vector<Primitive> &, std::vector<U16> & indices, S32 cahceSize);
};

View File

@ -0,0 +1,310 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
// Copied from NVidia Triangle Strip SDK, available from NVidia website
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786)
#endif
#include "NvTriStripObjects.h"
#include "NvTriStrip.h"
////////////////////////////////////////////////////////////////////////////////////////
//private data
static U32 cacheSize = CACHESIZE_GEFORCE1_2;
static bool bStitchStrips = true;
static U32 minStripSize = 0;
static bool bListsOnly = false;
////////////////////////////////////////////////////////////////////////////////////////
// SetListsOnly()
//
// If set to true, will return an optimized list, with no strips at all.
//
// Default value: false
//
void SetListsOnly(const bool _bListsOnly)
{
bListsOnly = _bListsOnly;
}
////////////////////////////////////////////////////////////////////////////////////////
// SetCacheSize()
//
// Sets the cache size which the stripfier uses to optimize the data.
// Controls the length of the generated individual strips.
// This is the "actual" cache size, so 24 for GeForce3 and 16 for GeForce1/2
// You may want to play around with this number to tweak performance.
//
// Default value: 16
//
void SetCacheSize(const U32 _cacheSize)
{
cacheSize = _cacheSize;
}
////////////////////////////////////////////////////////////////////////////////////////
// SetStitchStrips()
//
// bool to indicate whether to stitch together strips into one huge strip or not.
// If set to true, you'll get back one huge strip stitched together using degenerate
// triangles.
// If set to false, you'll get back a large number of separate strips.
//
// Default value: true
//
void SetStitchStrips(const bool _bStitchStrips)
{
bStitchStrips = _bStitchStrips;
}
////////////////////////////////////////////////////////////////////////////////////////
// SetMinStripSize()
//
// Sets the minimum acceptable size for a strip, in triangles.
// All strips generated which are shorter than this will be thrown into one big, separate list.
//
// Default value: 0
//
void SetMinStripSize(const U32 _minStripSize)
{
minStripSize = _minStripSize;
}
////////////////////////////////////////////////////////////////////////////////////////
// GenerateStrips()
//
// in_indices: input index list, the indices you would use to render
// in_numIndices: number of entries in in_indices
// primGroups: array of optimized/stripified PrimitiveGroups
// numGroups: number of groups returned
//
// Be sure to call delete[] on the returned primGroups to avoid leaking mem
//
void GenerateStrips(const U16* in_indices, const U32 in_numIndices,
PrimitiveGroup** primGroups, U16* numGroups)
{
//put data in format that the stripifier likes
WordVec tempIndices;
tempIndices.resize(in_numIndices);
U16 maxIndex = 0;
U32 i;
for(i = 0; i < in_numIndices; i++)
{
tempIndices[i] = in_indices[i];
if(in_indices[i] > maxIndex)
maxIndex = in_indices[i];
}
NvStripInfoVec tempStrips;
NvFaceInfoVec tempFaces;
NvStripifier stripifier;
//do actual stripification
stripifier.Stripify(tempIndices, cacheSize, minStripSize, maxIndex, tempStrips, tempFaces);
//stitch strips together
IntVec stripIndices;
U32 numSeparateStrips = 0;
if(bListsOnly)
{
//if we're outputting only lists, we're done
*numGroups = 1;
(*primGroups) = new PrimitiveGroup[*numGroups];
PrimitiveGroup* primGroupArray = *primGroups;
//count the total number of indices
U32 numIndices = 0;
U32 i;
for(i = 0; i < tempStrips.size(); i++)
{
numIndices += tempStrips[i]->m_faces.size() * 3;
}
//add in the list
numIndices += tempFaces.size() * 3;
primGroupArray[0].type = PT_LIST;
primGroupArray[0].numIndices = numIndices;
primGroupArray[0].indices = new U16[numIndices];
//do strips
U32 indexCtr = 0;
for(U32 k = 0; k < tempStrips.size(); k++)
{
for(U32 j = 0; j < tempStrips[i]->m_faces.size(); j++)
{
//degenerates are of no use with lists
if(!NvStripifier::IsDegenerate(tempStrips[i]->m_faces[j]))
{
primGroupArray[0].indices[indexCtr++] = tempStrips[k]->m_faces[j]->m_v0;
primGroupArray[0].indices[indexCtr++] = tempStrips[k]->m_faces[j]->m_v1;
primGroupArray[0].indices[indexCtr++] = tempStrips[k]->m_faces[j]->m_v2;
}
else
{
//we've removed a tri, reduce the number of indices
primGroupArray[0].numIndices -= 3;
}
}
}
//do lists
for(i = 0; i < tempFaces.size(); i++)
{
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v0;
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v1;
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v2;
}
}
else
{
stripifier.CreateStrips(tempStrips, stripIndices, bStitchStrips, numSeparateStrips);
//if we're stitching strips together, we better get back only one strip from CreateStrips()
assert( (bStitchStrips && (numSeparateStrips == 1)) || !bStitchStrips);
//convert to output format
*numGroups = numSeparateStrips; //for the strips
if(tempFaces.size() != 0)
(*numGroups)++; //we've got a list as well, increment
(*primGroups) = new PrimitiveGroup[*numGroups];
PrimitiveGroup* primGroupArray = *primGroups;
//first, the strips
S32 startingLoc = 0;
for(U32 stripCtr = 0; stripCtr < numSeparateStrips; stripCtr++)
{
S32 stripLength = 0;
if(!bStitchStrips)
{
//if we've got multiple strips, we need to figure out the correct length
U32 i;
for(i = startingLoc; i < stripIndices.size(); i++)
{
if(stripIndices[i] == -1)
break;
}
stripLength = i - startingLoc;
}
else
stripLength = stripIndices.size();
primGroupArray[stripCtr].type = PT_STRIP;
primGroupArray[stripCtr].indices = new U16[stripLength];
primGroupArray[stripCtr].numIndices = stripLength;
S32 indexCtr = 0;
for(S32 i = startingLoc; i < stripLength + startingLoc; i++)
primGroupArray[stripCtr].indices[indexCtr++] = stripIndices[i];
//we add 1 to account for the -1 separating strips
//this doesn't break the stitched case since we'll exit the loop
startingLoc += stripLength + 1;
}
//next, the list
if(tempFaces.size() != 0)
{
S32 faceGroupLoc = (*numGroups) - 1; //the face group is the last one
primGroupArray[faceGroupLoc].type = PT_LIST;
primGroupArray[faceGroupLoc].indices = new U16[tempFaces.size() * 3];
primGroupArray[faceGroupLoc].numIndices = tempFaces.size() * 3;
S32 indexCtr = 0;
for(U32 i = 0; i < tempFaces.size(); i++)
{
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v0;
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v1;
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v2;
}
}
}
//clean up everything
//delete strips
for(i = 0; i < tempStrips.size(); i++)
{
for(U32 j = 0; j < tempStrips[i]->m_faces.size(); j++)
{
delete tempStrips[i]->m_faces[j];
tempStrips[i]->m_faces[j] = NULL;
}
delete tempStrips[i];
tempStrips[i] = NULL;
}
//delete faces
for(i = 0; i < tempFaces.size(); i++)
{
delete tempFaces[i];
tempFaces[i] = NULL;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// RemapIndices()
//
// Function to remap your indices to improve spatial locality in your vertex buffer.
//
// in_primGroups: array of PrimitiveGroups you want remapped
// numGroups: number of entries in in_primGroups
// numVerts: number of vertices in your vertex buffer, also can be thought of as the range
// of acceptable values for indices in your primitive groups.
// remappedGroups: array of remapped PrimitiveGroups
//
// Note that, according to the remapping handed back to you, you must reorder your
// vertex buffer.
//
void RemapIndices(const PrimitiveGroup* in_primGroups, const U16 numGroups,
const U16 numVerts, PrimitiveGroup** remappedGroups)
{
(*remappedGroups) = new PrimitiveGroup[numGroups];
//caches oldIndex --> newIndex conversion
S32 *indexCache;
indexCache = new S32[numVerts];
memset(indexCache, -1, sizeof(S32)*numVerts);
//loop over primitive groups
U32 indexCtr = 0;
for(S32 i = 0; i < numGroups; i++)
{
U32 numIndices = in_primGroups[i].numIndices;
//init remapped group
(*remappedGroups)[i].type = in_primGroups[i].type;
(*remappedGroups)[i].numIndices = numIndices;
(*remappedGroups)[i].indices = new U16[numIndices];
for(U32 j = 0; j < numIndices; j++)
{
S32 cachedIndex = indexCache[in_primGroups[i].indices[j]];
if(cachedIndex == -1) //we haven't seen this index before
{
//point to "last" vertex in VB
(*remappedGroups)[i].indices[j] = indexCtr;
//add to index cache, increment
indexCache[in_primGroups[i].indices[j]] = indexCtr++;
}
else
{
//we've seen this index before
(*remappedGroups)[i].indices[j] = cachedIndex;
}
}
}
delete[] indexCache;
}

View File

@ -0,0 +1,135 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
// Copied from NVidia Triangle Strip SDK, available from NVidia website
//-----------------------------------------------------------------------------
#ifndef NVTRISTRIP_H
#define NVTRISTRIP_H
#ifndef NULL
#define NULL 0
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Mod for Torque, 1/3/04
// Compile directly in Torque
//#pragma comment(lib, "nvtristrip")
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// Public interface for stripifier
////////////////////////////////////////////////////////////////////////////////////////
//GeForce1 and 2 cache size
#define CACHESIZE_GEFORCE1_2 16
//GeForce3 cache size
#define CACHESIZE_GEFORCE3 24
enum PrimType
{
PT_LIST,
PT_STRIP,
PT_FAN
};
struct PrimitiveGroup
{
PrimType type;
U32 numIndices;
U16* indices;
////////////////////////////////////////////////////////////////////////////////////////
PrimitiveGroup() : type(PT_STRIP), numIndices(0), indices(NULL) {}
~PrimitiveGroup()
{
if(indices)
delete[] indices;
indices = NULL;
}
};
////////////////////////////////////////////////////////////////////////////////////////
// SetCacheSize()
//
// Sets the cache size which the stripfier uses to optimize the data.
// Controls the length of the generated individual strips.
// This is the "actual" cache size, so 24 for GeForce3 and 16 for GeForce1/2
// You may want to play around with this number to tweak performance.
//
// Default value: 16
//
void SetCacheSize(const U32 cacheSize);
////////////////////////////////////////////////////////////////////////////////////////
// SetStitchStrips()
//
// bool to indicate whether to stitch together strips into one huge strip or not.
// If set to true, you'll get back one huge strip stitched together using degenerate
// triangles.
// If set to false, you'll get back a large number of separate strips.
//
// Default value: true
//
void SetStitchStrips(const bool bStitchStrips);
////////////////////////////////////////////////////////////////////////////////////////
// SetMinStripSize()
//
// Sets the minimum acceptable size for a strip, in triangles.
// All strips generated which are shorter than this will be thrown into one big, separate list.
//
// Default value: 0
//
void SetMinStripSize(const U32 minSize);
////////////////////////////////////////////////////////////////////////////////////////
// SetListsOnly()
//
// If set to true, will return an optimized list, with no strips at all.
//
// Default value: false
//
void SetListsOnly(const bool bListsOnly);
////////////////////////////////////////////////////////////////////////////////////////
// GenerateStrips()
//
// in_indices: input index list, the indices you would use to render
// in_numIndices: number of entries in in_indices
// primGroups: array of optimized/stripified PrimitiveGroups
// numGroups: number of groups returned
//
// Be sure to call delete[] on the returned primGroups to avoid leaking mem
//
void GenerateStrips(const U16* in_indices, const U32 in_numIndices,
PrimitiveGroup** primGroups, U16* numGroups);
////////////////////////////////////////////////////////////////////////////////////////
// RemapIndices()
//
// Function to remap your indices to improve spatial locality in your vertex buffer.
//
// in_primGroups: array of PrimitiveGroups you want remapped
// numGroups: number of entries in in_primGroups
// numVerts: number of vertices in your vertex buffer, also can be thought of as the range
// of acceptable values for indices in your primitive groups.
// remappedGroups: array of remapped PrimitiveGroups
//
// Note that, according to the remapping handed back to you, you must reorder your
// vertex buffer.
//
// Credit goes to the MS Xbox crew for the idea for this interface.
//
void RemapIndices(const PrimitiveGroup* in_primGroups, const U16 numGroups,
const U16 numVerts, PrimitiveGroup** remappedGroups);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,255 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
// Copied from NVidia Triangle Strip SDK, available from NVidia website
//-----------------------------------------------------------------------------
#ifndef NV_TRISTRIP_OBJECTS_H
#define NV_TRISTRIP_OBJECTS_H
#include <assert.h>
#ifdef _WIN32
#include <windows.h>
#else
typedef U32 UINT;
typedef short WORD;
#endif
#include <vector>
#include <list>
#include "VertexCache.h"
#include "../DTSPlusTypes.h"
/////////////////////////////////////////////////////////////////////////////////
//
// Types defined for stripification
//
/////////////////////////////////////////////////////////////////////////////////
struct MyVertex {
F32 x, y, z;
F32 nx, ny, nz;
};
typedef MyVertex MyVector;
struct MyFace {
S32 v1, v2, v3;
F32 nx, ny, nz;
};
class NvFaceInfo {
public:
// vertex indices
NvFaceInfo(S32 v0, S32 v1, S32 v2){
m_v0 = v0; m_v1 = v1; m_v2 = v2;
m_stripId = -1;
m_testStripId = -1;
m_experimentId = -1;
}
// data members are left public
S32 m_v0, m_v1, m_v2;
S32 m_stripId; // real strip Id
S32 m_testStripId; // strip Id in an experiment
S32 m_experimentId; // in what experiment was it given an experiment Id?
};
// nice and dumb edge class that points knows its
// indices, the two faces, and the next edge using
// the lesser of the indices
class NvEdgeInfo {
public:
// constructor puts 1 ref on us
NvEdgeInfo (S32 v0, S32 v1){
m_v0 = v0;
m_v1 = v1;
m_face0 = NULL;
m_face1 = NULL;
m_nextV0 = NULL;
m_nextV1 = NULL;
// we will appear in 2 lists. this is a good
// way to make sure we delete it the second time
// we hit it in the edge infos
m_refCount = 2;
}
// ref and unref
void Unref () { if (--m_refCount == 0) delete this; }
// data members are left public
UINT m_refCount;
NvFaceInfo *m_face0, *m_face1;
S32 m_v0, m_v1;
NvEdgeInfo *m_nextV0, *m_nextV1;
};
// This class is a quick summary of parameters used
// to begin a triangle strip. Some operations may
// want to create lists of such items, so they were
// pulled out into a class
class NvStripStartInfo {
public:
NvStripStartInfo(NvFaceInfo *startFace, NvEdgeInfo *startEdge, bool toV1){
m_startFace = startFace;
m_startEdge = startEdge;
m_toV1 = toV1;
}
NvFaceInfo *m_startFace;
NvEdgeInfo *m_startEdge;
bool m_toV1;
};
typedef std::vector<NvFaceInfo*> NvFaceInfoVec;
typedef std::list <NvFaceInfo*> NvFaceInfoList;
typedef std::list <NvFaceInfoVec*> NvStripList;
typedef std::vector<NvEdgeInfo*> NvEdgeInfoVec;
typedef std::vector<WORD> WordVec;
typedef std::vector<S32> IntVec;
typedef std::vector<MyVertex> MyVertexVec;
typedef std::vector<MyFace> MyFaceVec;
template<class T>
inline void SWAP(T& first, T& second)
{
T temp = first;
first = second;
second = temp;
}
// This is a summary of a strip that has been built
class NvStripInfo {
public:
// A little information about the creation of the triangle strips
NvStripInfo(const NvStripStartInfo &startInfo, S32 stripId, S32 experimentId = -1) :
m_startInfo(startInfo)
{
m_stripId = stripId;
m_experimentId = experimentId;
visited = false;
m_numDegenerates = 0;
}
// This is an experiment if the experiment id is >= 0
inline bool IsExperiment () const { return m_experimentId >= 0; }
inline bool IsInStrip (const NvFaceInfo *faceInfo) const
{
if(faceInfo == NULL)
return false;
return (m_experimentId >= 0 ? faceInfo->m_testStripId == m_stripId : faceInfo->m_stripId == m_stripId);
}
bool SharesEdge(const NvFaceInfo* faceInfo, NvEdgeInfoVec &edgeInfos);
// take the given forward and backward strips and combine them together
void Combine(const NvFaceInfoVec &forward, const NvFaceInfoVec &backward);
//returns true if the face is "unique", i.e. has a vertex which doesn't exist in the faceVec
bool Unique(NvFaceInfoVec& faceVec, NvFaceInfo* face);
// mark the triangle as taken by this strip
bool IsMarked (NvFaceInfo *faceInfo);
void MarkTriangle(NvFaceInfo *faceInfo);
// build the strip
void Build(NvEdgeInfoVec &edgeInfos, NvFaceInfoVec &faceInfos);
// public data members
NvStripStartInfo m_startInfo;
NvFaceInfoVec m_faces;
S32 m_stripId;
S32 m_experimentId;
bool visited;
S32 m_numDegenerates;
};
typedef std::vector<NvStripInfo*> NvStripInfoVec;
//The actual stripifier
class NvStripifier {
public:
// Constructor
NvStripifier();
~NvStripifier();
//the target vertex cache size, the structure to place the strips in, and the input indices
void Stripify(const WordVec &in_indices, const S32 in_cacheSize, const S32 in_minStripLength,
const U16 maxIndex, NvStripInfoVec &allStrips, NvFaceInfoVec &allFaces);
void CreateStrips(const NvStripInfoVec& allStrips, IntVec& stripIndices, const bool bStitchStrips, U32& numSeparateStrips);
static S32 GetUniqueVertexInB(NvFaceInfo *faceA, NvFaceInfo *faceB);
//static S32 GetSharedVertex(NvFaceInfo *faceA, NvFaceInfo *faceB);
static void GetSharedVertices(NvFaceInfo *faceA, NvFaceInfo *faceB, S32* vertex0, S32* vertex1);
static bool IsDegenerate(const NvFaceInfo* face);
protected:
WordVec indices;
S32 cacheSize;
S32 minStripLength;
F32 meshJump;
bool bFirstTimeResetPoint;
/////////////////////////////////////////////////////////////////////////////////
//
// Big mess of functions called during stripification
//
/////////////////////////////////////////////////////////////////////////////////
//********************
bool IsMoneyFace(const NvFaceInfo& face);
bool FaceContainsIndex(const NvFaceInfo& face, const U32 index);
bool IsCW(NvFaceInfo *faceInfo, S32 v0, S32 v1);
bool NextIsCW(const S32 numIndices);
bool IsDegenerate(const U16 v0, const U16 v1, const U16 v2);
static S32 GetNextIndex(const WordVec &indices, NvFaceInfo *face);
static NvEdgeInfo *FindEdgeInfo(NvEdgeInfoVec &edgeInfos, S32 v0, S32 v1);
static NvFaceInfo *FindOtherFace(NvEdgeInfoVec &edgeInfos, S32 v0, S32 v1, NvFaceInfo *faceInfo);
NvFaceInfo *FindGoodResetPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
void FindAllStrips(NvStripInfoVec &allStrips, NvFaceInfoVec &allFaceInfos, NvEdgeInfoVec &allEdgeInfos, S32 numSamples);
void SplitUpStripsAndOptimize(NvStripInfoVec &allStrips, NvStripInfoVec &outStrips, NvEdgeInfoVec& edgeInfos, NvFaceInfoVec& outFaceList);
void RemoveSmallStrips(NvStripInfoVec& allStrips, NvStripInfoVec& allBigStrips, NvFaceInfoVec& faceList);
bool FindTraversal(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, NvStripInfo *strip, NvStripStartInfo &startInfo);
S32 CountRemainingTris(std::list<NvStripInfo*>::iterator iter, std::list<NvStripInfo*>::iterator end);
void CommitStrips(NvStripInfoVec &allStrips, const NvStripInfoVec &strips);
F32 AvgStripSize(const NvStripInfoVec &strips);
S32 FindStartPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
void UpdateCacheStrip(VertexCache* vcache, NvStripInfo* strip);
void UpdateCacheFace(VertexCache* vcache, NvFaceInfo* face);
F32 CalcNumHitsStrip(VertexCache* vcache, NvStripInfo* strip);
S32 CalcNumHitsFace(VertexCache* vcache, NvFaceInfo* face);
S32 NumNeighbors(NvFaceInfo* face, NvEdgeInfoVec& edgeInfoVec);
void BuildStripifyInfo(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, const U16 maxIndex);
bool AlreadyExists(NvFaceInfo* faceInfo, NvFaceInfoVec& faceInfos);
// let our strip info classes and the other classes get
// to these protected stripificaton methods if they want
friend class NvStripInfo;
};
#endif

View File

@ -0,0 +1,32 @@
README for NvTriStrip, library version
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To use:
-#include "NvTriStrip.h"
-put nvtristrip.lib in your library path (the pragma in nvtristrip.h will automatically look for the library).
Check out NvTriStrip.h for the interface.
See the StripTest source code (in function LoadXFileStripped) for an example of using the library.
Features:
-generates strips from arbitrary geometry.
-flexibly optimizes for post TnL vertex caches (16 on GeForce1/2, 24 on GeForce3).
-can stitch together strips using degenerate triangles, or not.
-can output lists instead of strips.
-can optionally throw excessively small strips into a list instead.
-can remap indices to improve spatial locality in your vertex buffers.
On cache sizes:
Note that it's better to UNDERESTIMATE the cache size instead of OVERESTIMATING.
So, if you're targetting GeForce1, 2, and 3, be conservative and use the GeForce1_2 cache
size, NOT the GeForce3 cache size.
This will make sure you don't "blow" the cache of the GeForce1 and 2.
Also note that the cache size you specify is the "actual" cache size, not the "effective"
cache size you may have heard about. This is 16 for GeForce1 and 2, and 24 for GeForce3.
Credit goes to Curtis Beeson and Joe Demers for the basis for this stripifier and to Jason Regier and
Jon Stone at Blizzard for providing a much cleaner version of CreateStrips().
Questions/comments email cem@nvidia.com

View File

@ -0,0 +1,86 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
// Copied from NVidia Triangle Strip SDK, available from NVidia website
//-----------------------------------------------------------------------------
#ifndef VERTEX_CACHE_H
#define VERTEX_CACHE_H
#include "../DTSPlusTypes.h"
class VertexCache
{
public:
VertexCache(S32 size)
{
numEntries = size;
entries = new S32[numEntries];
for(S32 i = 0; i < numEntries; i++)
entries[i] = -1;
}
VertexCache() { VertexCache(16); }
~VertexCache() { delete[] entries; entries = 0; }
bool InCache(S32 entry)
{
bool returnVal = false;
for(S32 i = 0; i < numEntries; i++)
{
if(entries[i] == entry)
{
returnVal = true;
break;
}
}
return returnVal;
}
S32 AddEntry(S32 entry)
{
S32 removed;
removed = entries[numEntries - 1];
//push everything right one
for(S32 i = numEntries - 2; i >= 0; i--)
{
entries[i + 1] = entries[i];
}
entries[0] = entry;
return removed;
}
void Clear()
{
memset(entries, -1, sizeof(S32) * numEntries);
}
void Copy(VertexCache* inVcache)
{
for(S32 i = 0; i < numEntries; i++)
{
inVcache->Set(i, entries[i]);
}
}
S32 At(S32 index) { return entries[index]; }
void Set(S32 index, S32 value) { entries[index] = value; }
private:
S32 *entries;
S32 numEntries;
};
#endif

39
lib/dtsSDKPlus/sceneEnum.h Executable file
View File

@ -0,0 +1,39 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef APP_SCENEENUM_H_
#define APP_SCENEENUM_H_
namespace DTS
{
class AppSceneEnum
{
protected:
std::vector<AppMesh*> meshes;
std::vector<AppMesh*> skins;
std::vector<AppNode*> subTrees;
std::vector<AppSequence*> sequences;
AppNode * boundsNode;
ShapeMimic shapeMimic;
void setExportError(const char * errStr) { AppConfig::SetExportError(errStr); }
const char * getError() { return AppConfig::GetExportError(); }
bool isError() { return AppConfig::IsExportError(); }
void processNode(AppNode *);
public:
AppSceneEnum();
~AppSceneEnum();
virtual void enumScene() = 0;
Shape * processScene();
};
}; // namespace DTS
#endif // #define APP_SCENEENUM_H_

836
lib/dtsSDKPlus/stripper.cpp Executable file
View File

@ -0,0 +1,836 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(disable : 4786 4018)
#endif
#include "stripper.h"
#include "appConfig.h"
namespace DTS
{
F32 Stripper::adjacencyWeight = 5;
F32 Stripper::noswapWeight = 3;
F32 Stripper::alreadyCachedWeight = 1;
U32 Stripper::cacheSize = 16;
U32 Stripper::simK = 5;
Stripper::Stripper(std::vector<Primitive> & _faces, std::vector<U16> & _faceIndices)
: faces(_faces), faceIndices(_faceIndices), adjacent(_faces.size(),_faces.size())
{
// keep track of whether face used in a strip yet
used.resize(faces.size());
for (S32 i=0; i<faces.size(); i++)
used[i]=false;
clearCache();
cacheMisses = 0; // definitely don't want to clear this every time we clear the cache!
bestLength = -1;
}
Stripper::Stripper(Stripper & stripper)
: faces(stripper.faces), faceIndices(stripper.faceIndices), adjacent(stripper.faces.size(),stripper.faces.size()),
numAdjacent(stripper.numAdjacent), used(stripper.used), vertexCache(stripper.vertexCache),
recentFaces(stripper.recentFaces), strips(stripper.strips), stripIndices(stripper.stripIndices)
{
currentFace = stripper.currentFace;
limitStripLength = stripper.limitStripLength;
bestLength = stripper.bestLength;
cacheMisses = stripper.cacheMisses;
adjacent.clearAllBits();
for (S32 i=0; i<faces.size(); i++)
for (S32 j=0; j<faces.size(); j++)
if (stripper.adjacent.isSet(i,j))
adjacent.setBit(i,j);
}
Stripper::~Stripper()
{
}
void Stripper::testCache(S32 addedFace)
{
S32 * cache = &vertexCache.back();
// make sure last 3 verts on strip list are last 3 verts in cache
U16 * indices = &stripIndices.back();
if (*indices!=*cache || *(indices-1)!=*(cache-1) || *(indices-2)!=*(cache-2))
{
AppConfig::SetExportError("14", "Assertion failed when stripping (11)");
return;
}
if (addedFace>=0)
{
// make sure current face is still last 3 items in the cache
Primitive & face = faces[addedFace];
U32 idx0 = faceIndices[face.firstElement+0];
U32 idx1 = faceIndices[face.firstElement+1];
U32 idx2 = faceIndices[face.firstElement+2];
if ( idx0!=*(cache) && idx0!=*(cache-1) && idx0!=*(cache-2))
{
AppConfig::SetExportError("14", "Assertion failed when stripping (8)");
return;
}
if ( idx1!=*(cache) && idx1!=*(cache-1) && idx1!=*(cache-2))
{
AppConfig::SetExportError("14", "Assertion failed when stripping (9)");
return;
}
if ( idx2!=*(cache) && idx2!=*(cache-1) && idx2!=*(cache-2))
{
AppConfig::SetExportError("14", "Assertion failed when stripping (10)");
return;
}
}
}
void Stripper::copyParams(Stripper * from)
{
limitStripLength = from->limitStripLength;
}
void Stripper::makeStrips()
{
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return;
// main strip loop...
U32 start, end, i, sz;
std::vector<Primitive> someFaces;
std::vector<U16> someIndices;
for (start = 0; start<faces.size(); start=end)
{
for (end=start; end<faces.size() && faces[start].type==faces[end].type; end++)
;
if (start==0 && end==faces.size())
{
// all same material, no need to copy anything
makeStripsB();
return;
}
// copy start to end faces into new list -- this is so we end up doing less copying
// down the road (when we are doing the look ahead simulation)
someFaces.clear();
someIndices.clear();
for (i=start;i<end;i++)
{
someFaces.push_back(faces[i]);
someFaces.back().firstElement = someIndices.size();
someIndices.push_back(faceIndices[faces[i].firstElement + 0]);
someIndices.push_back(faceIndices[faces[i].firstElement + 1]);
someIndices.push_back(faceIndices[faces[i].firstElement + 2]);
}
// strip these...
Stripper someStrips(someFaces,someIndices);
someStrips.copyParams(this);
someStrips.makeStripsB();
if (AppConfig::IsExportError()) return;
// copy these strips into our arrays
sz = strips.size();
strips.resize(sz+someStrips.strips.size());
for (i=0; i<someStrips.strips.size(); i++)
{
strips[i+sz] = someStrips.strips[i];
strips[i+sz].firstElement += stripIndices.size();
}
sz = stripIndices.size();
stripIndices.resize(sz+someStrips.stripIndices.size());
memcpy(&stripIndices[sz],&someStrips.stripIndices[0],someStrips.stripIndices.size()*sizeof(U16));
// update cache misses
cacheMisses += someStrips.getCacheMisses();
}
}
void Stripper::makeStripsB()
{
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return;
// set adjacency info
setAdjacency(0,faces.size());
while (1)
{
strips.push_back(Primitive());
Primitive & strip = strips.back();
strip.firstElement = stripIndices.size();
strip.numElements = 0;
if (faces[0].type & Primitive::NoMaterial)
strip.type = Primitive::NoMaterial;
else
strip.type = faces[0].type & Primitive::MaterialMask;
strip.type |= Primitive::Strip | Primitive::Indexed;
if (!startStrip(strip,0,faces.size()))
{
strips.pop_back();
break;
}
while (addStrip(strip,0,faces.size()));
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return;
}
// let's make sure everything is legit up till here
U32 i;
for (i=0; i<faces.size(); i++)
{
if (!used[i])
{
AppConfig::SetExportError("14", "Assertion failed when stripping (1)");
return;
}
}
for (i=0; i<numAdjacent.size(); i++)
{
if (numAdjacent[i])
{
AppConfig::SetExportError("14", "Assertion failed when stripping (2)");
return;
}
}
// make sure all faces were used, o.w. it's an error
for (i=0; i<used.size(); i++)
{
if (!used[i])
{
AppConfig::SetExportError("14", "Assertion failed when stripping (3)");
return;
}
}
}
// used for simulating addition of "len" more faces with a forced strip restart after "restart" faces
S32 Stripper::continueStrip(S32 startFace, S32 endFace, S32 len, S32 restart)
{
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return 0;
Primitive & strip = strips.back();
while (restart && addStrip(strip,startFace,endFace))
restart--,len--;
// either restarted when we were forced to or restarted on our own
// either way, continue adding faces till len==0
while (len)
{
strips.push_back(Primitive());
Primitive & strip = strips.back();
strip.firstElement = stripIndices.size();
strip.numElements = 0;
if (faces[startFace].type & Primitive::NoMaterial)
strip.type = Primitive::NoMaterial;
else
strip.type = faces[startFace].type & Primitive::MaterialMask;
strip.type |= Primitive::Strip | Primitive::Indexed;
if (!startStrip(strip,startFace,endFace))
{
strips.pop_back();
break;
}
len--;
while (len && addStrip(strip,startFace,endFace))
len--;
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return 0;
}
return restart;
}
void Stripper::setAdjacency(S32 startFace, S32 endFace)
{
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return;
// two faces adjacent only if wound the same way (so shared edge must appear in opp. order)
S32 i,j;
numAdjacent.resize(faces.size());
for (i=0; i<numAdjacent.size(); i++)
numAdjacent[i] = 0;
adjacent.clearAllBits();
for (i=startFace; i<endFace-1; i++)
{
// the i-indices...
U32 idx0 = faceIndices[faces[i].firstElement + 0];
U32 idx1 = faceIndices[faces[i].firstElement + 1];
U32 idx2 = faceIndices[faces[i].firstElement + 2];
for (j=i+1; j<endFace; j++)
{
// the j-indices...
U32 jdx0 = faceIndices[faces[j].firstElement + 0];
U32 jdx1 = faceIndices[faces[j].firstElement + 1];
U32 jdx2 = faceIndices[faces[j].firstElement + 2];
// we don't want to be adjacent if we share all our vertices...
if ( ( idx0==jdx0 || idx0==jdx1 || idx0==jdx2) &&
( idx1==jdx0 || idx1==jdx1 || idx1==jdx2) &&
( idx2==jdx0 || idx2==jdx1 || idx2==jdx2) )
continue;
// test adjacency...
if ( ((idx0==jdx1) && (idx1==jdx0)) || ((idx0==jdx2) && (idx1==jdx1)) || ((idx0==jdx0) && (idx1==jdx2)) ||
((idx1==jdx1) && (idx2==jdx0)) || ((idx1==jdx2) && (idx2==jdx1)) || ((idx1==jdx0) && (idx2==jdx2)) ||
((idx2==jdx1) && (idx0==jdx0)) || ((idx2==jdx2) && (idx0==jdx1)) || ((idx2==jdx0) && (idx0==jdx2)) )
{
// i,j are adjacent
if (adjacent.isSet(i,j) || adjacent.isSet(j,i))
{
AppConfig::SetExportError("15", "wtf (1)");
return;
}
adjacent.setBit(i,j);
adjacent.setBit(j,i);
if (!adjacent.isSet(i,j) || !adjacent.isSet(j,i))
{
AppConfig::SetExportError("15", "wtf (2)");
return;
}
numAdjacent[i]++;
numAdjacent[j]++;
}
}
}
}
void Stripper::clearCache()
{
vertexCache.resize(cacheSize);
for (S32 i=0; i<vertexCache.size(); i++)
vertexCache[i] = -1;
}
void Stripper::addToCache(S32 vertexIndex)
{
S32 i;
for (i=0; i<vertexCache.size(); i++)
if (vertexCache[i]==vertexIndex)
break;
if (i==vertexCache.size())
cacheMisses++;
delElementAtIndex(vertexCache,0);
vertexCache.push_back(vertexIndex);
}
void Stripper::addToCache(S32 vertexIndex, U32 posFromBack)
{
// theoretically this could result in a cache miss, but never used that way so
// we won't check...
delElementAtIndex(vertexCache,0);
insElementAtIndex(vertexCache,vertexCache.size()-posFromBack,vertexIndex);
}
bool Stripper::startStrip(Primitive & strip, S32 startFace, S32 endFace)
{
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return false;
S32 i,j;
S32 bestFace = -1;
// first search the list of faces with neighbors that were recently visited
for (i=0;i<recentFaces.size();i++)
{
if (!used[recentFaces[i]])
{
bestFace = recentFaces[i];
break;
}
}
recentFaces.clear();
// if we didn't find one above, search for a good face
if (bestFace<0)
{
S32 bestScore = -1;
for (i=startFace; i<endFace; i++)
{
if (used[i])
continue;
// how many of the verts are in the cache?
// Question: should we favor verts that occur early/late in the cache?
U32 inCache = 0;
U32 idx0 = faceIndices[faces[i].firstElement + 0];
U32 idx1 = faceIndices[faces[i].firstElement + 1];
U32 idx2 = faceIndices[faces[i].firstElement + 2];
for (j=0; j<vertexCache.size(); j++)
if (vertexCache[j] == idx0)
{
inCache++;
break;
}
for (j=0; j<vertexCache.size(); j++)
if (vertexCache[j] == idx1)
{
inCache++;
break;
}
for (j=0; j<vertexCache.size(); j++)
if (vertexCache[j] == idx2)
{
inCache++;
break;
}
S32 currentScore = (inCache<<4) + numAdjacent[i];
if (currentScore>bestScore)
{
bestFace = i;
bestScore = currentScore;
}
}
}
// if no face...
if (bestFace<0)
return false;
// start the strip -- add in standard order...may be changed later
strip.numElements += 3;
stripIndices.push_back(faceIndices[faces[bestFace].firstElement + 0]);
addToCache(stripIndices.back());
stripIndices.push_back(faceIndices[faces[bestFace].firstElement + 1]);
addToCache(stripIndices.back());
stripIndices.push_back(faceIndices[faces[bestFace].firstElement + 2]);
addToCache(stripIndices.back());
testCache(bestFace);
// adjust adjacency information
for (j=startFace; j<endFace; j++)
{
if (j==bestFace || used[j])
continue;
if (adjacent.isSet(bestFace,j))
{
numAdjacent[j]--;
if (numAdjacent[j]<0)
{
AppConfig::SetExportError("14", "Assertion failed when stripping (4)");
return false;
}
}
}
// mark face as used
used[bestFace] = true;
numAdjacent[bestFace] = 0;
currentFace = bestFace;
return true;
}
void Stripper::getVerts(S32 face, S32 & oldVert0, S32 & oldVert1, S32 & addVert)
{
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return;
std::vector<S32> prev;
addVert = -1;
Primitive & addFace = faces[face];
U32 idx0 = faceIndices[addFace.firstElement+0];
U32 idx1 = faceIndices[addFace.firstElement+1];
U32 idx2 = faceIndices[addFace.firstElement+2];
S32 * cache = &vertexCache.back();
if (idx0==*cache || idx0==*(cache-1) || idx0==*(cache-2))
prev.push_back(idx0);
else
addVert = idx0;
if (idx1==*cache || idx1==*(cache-1) || idx1==*(cache-2))
prev.push_back(idx1);
else
addVert = idx1;
if (idx2==*cache || idx2==*(cache-1) || idx2==*(cache-2))
prev.push_back(idx2);
else
addVert = idx2;
if (addVert<0 || prev.size()!=2)
{
AppConfig::SetExportError("14", "Assertion failed when stripping (5)");
return;
}
if (idx1==addVert)
{
// swap order of oldVerts
oldVert0 = prev[1];
oldVert1 = prev[0];
}
else
{
// keep order
oldVert0 = prev[0];
oldVert1 = prev[1];
}
}
// assumes start + 0,1,2 is a triangle or first 3 indices of a strip
void Stripper::rotateFace(S32 start, std::vector<U16> & indices)
{
U32 tmp = indices[start];
indices[start] = indices[start+1];
indices[start+1] = indices[start+2];
indices[start+2] = tmp;
S32 * cache = &vertexCache.back();
tmp = *(cache-2);
*(cache-2) = *(cache-1);
*(cache-1) = *cache;
*cache = tmp;
testCache(currentFace);
}
bool Stripper::swapNeeded(S32 oldVert0, S32 oldVert1)
{
S32 * cache = &vertexCache.back();
return (*cache!=oldVert0 || *(cache-1)!=oldVert1) && (*cache!=oldVert1 || *(cache-1)!=oldVert0);
// Long form:
// if ( (*cache==oldVert0 && *(cache-1)==oldVert1) || (*cache==oldVert1 && *(cache-1)==oldVert0) )
// return false;
// else
// return true;
}
F32 Stripper::getScore(S32 face, bool ignoreOrder)
{
// score face depending on following criteria:
// -- select face with fewest adjacencies?
// -- select face that continues strip without swap?
// -- select face with new vertex already in cache?
// weighting of each criteria controlled by adjacencyWeight, noswapWeight, and alreadyCachedWeight
// if ignoreOrder is true, don't worry about swaps
if (face<0)
return -100000.0f;
// get the 2 verts from the last face and the 1 new vert
S32 oldVert0, oldVert1, addVert;
getVerts(face, oldVert0, oldVert1, addVert);
F32 score = 0.0f;
// fewer adjacent faces the better...
score -= numAdjacent[face] * adjacencyWeight;
// reward if no swap needed...don't worry about order (only same facing faces get here)
if (!ignoreOrder && !swapNeeded(oldVert0,oldVert1))
score += noswapWeight;
// if new vertex in the cache, add the already in cache bonus...
for (S32 i=0;i<vertexCache.size();i++)
if (vertexCache[i]==addVert)
{
score += alreadyCachedWeight;
break;
}
return score;
}
bool Stripper::faceHasEdge(S32 face, U32 idx0, U32 idx1)
{
// return true if face has edge idx0, idx1 (in that order)
S32 start = faces[face].firstElement;
U32 vi0 = faceIndices[start+0];
U32 vi1 = faceIndices[start+1];
U32 vi2 = faceIndices[start+2];
if ( (vi0==idx0 && vi1==idx1) || (vi1==idx0 && vi2==idx1) || (vi2==idx0 && vi0==idx1) )
return true;
return false;
}
void Stripper::getAdjacentFaces(S32 startFace, S32 endFace, S32 face, S32 & face0, S32 & face1, S32 & face2)
{
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return;
// we return one face per edge...ties go to face with fewest adjacencies
S32 adj0=-1,adj1=-1,adj2=-1;
face0=face1=face2=-1;
U32 idx0 = faceIndices[faces[face].firstElement + 0];
U32 idx1 = faceIndices[faces[face].firstElement + 1];
U32 idx2 = faceIndices[faces[face].firstElement + 2];
for (S32 i=startFace; i<endFace; i++)
{
if (i==face || used[i])
continue;
if (!adjacent.isSet(face,i))
continue;
// which edge is this face on
if (faceHasEdge(i,idx1,idx0))
{
if (adj0<0 || numAdjacent[i]<adj0)
{
face0 = i;
adj0 = numAdjacent[i];
}
}
else if (faceHasEdge(i,idx2,idx1))
{
if (adj1<0 || numAdjacent[i]<adj1)
{
face1 = i;
adj1 = numAdjacent[i];
}
}
else if (faceHasEdge(i,idx0,idx2))
{
if (adj2<0 || numAdjacent[i]<adj2)
{
face2 = i;
adj2 = numAdjacent[i];
}
}
else
{
AppConfig::SetExportError("14", "Assertion failed when stripping (6)");
return;
}
}
}
bool Stripper::stripLongEnough(S32 startFace, S32 endFace)
{
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return false;
if (!limitStripLength)
return false;
// simulate stopping the strip here and continuing for cacheSize+simK more rounds
Stripper strip0(*this);
strip0.setLimitStripLength(false);
strip0.resetCacheMisses();
strip0.continueStrip(startFace,endFace,cacheSize+simK,0);
U32 stop0 = strip0.getCacheMisses();
// re-simulate previous best length (-1)
U32 bestMisses;
if (--bestLength<2)
bestLength = 1;
Stripper stripper(*this);
stripper.setLimitStripLength(false);
stripper.resetCacheMisses();
stripper.continueStrip(startFace,endFace,cacheSize+simK,bestLength);
bestMisses = stripper.getCacheMisses();
if (bestMisses<=stop0)
return false;
for (S32 i=1; i<cacheSize+simK; i++)
{
if (i==bestLength)
continue;
Stripper stripper(*this);
stripper.setLimitStripLength(false);
stripper.resetCacheMisses();
S32 underShoot = stripper.continueStrip(startFace,endFace,cacheSize+simK,i);
U32 misses = stripper.getCacheMisses();
if (misses<bestMisses)
{
bestMisses = misses;
bestLength = i - underShoot;
}
if (misses<=stop0)
return false;
// undershoot is how much we missed our restart target by...i.e., if we wanted
// to restart after 5 faces and underShoot is 1, then we restarted after 4.
// If undershoot is positive, then we're going to end up restarting at the same
// place on future iterations, so break out of the loop now to save time
if (underShoot>0)
break;
}
// survived the gauntlet...
return true;
}
bool Stripper::canGo(S32 face)
{
if (face<0)
return false;
U32 idx0 = faceIndices[faces[face].firstElement + 0];
U32 idx1 = faceIndices[faces[face].firstElement + 1];
U32 idx2 = faceIndices[faces[face].firstElement + 2];
U32 last = stripIndices.back();
if (last==idx0 || last==idx1 || last==idx2)
return true;
return false;
}
bool Stripper::addStrip(Primitive & strip, S32 startFace, S32 endFace)
{
// if already encountered an error, then
// we'll just go through the motions
if (AppConfig::IsExportError()) return false;
if (strip.numElements>3 && stripLongEnough(startFace,endFace))
return false;
testCache(currentFace);
// get unused faces adjacent to current face (choose only faces pointing same way)
// if more than one face adjacent on an edge (unusual case) chooses one with lowest adjacency count
S32 face0, face1, face2;
getAdjacentFaces(startFace,endFace,currentFace,face0,face1,face2);
// one more check -- make sure most recent vert is in face
// this can happen in exceptional case where we "back up"
// using common edge between previous two faces, but not the
// previous face (a v-junction?)
bool bad0,bad1,bad2;
bad0=bad1=bad2=false;
if (strip.numElements!=3 && !canGo(face0))
face0=-1;
if (strip.numElements!=3 && !canGo(face1))
face1=-1;
if (strip.numElements!=3 && !canGo(face2))
face2=-1;
if (face0<0 && face1<0 && face2<0)
return false;
testCache(currentFace);
// score faces, choose highest score
F32 score0 = getScore(face0,strip.numElements==3);
F32 score1 = getScore(face1,strip.numElements==3);
F32 score2 = getScore(face2,strip.numElements==3);
S32 bestFace = -1;
if (score0>=score1 && score0>=score2)
bestFace = face0;
else if (score1>=score0 && score1>=score2)
bestFace = face1;
else if (score2>=score1 && score2>=score0)
bestFace = face2;
testCache(currentFace);
// add new element
S32 oldVert0, oldVert1, addVert;
getVerts(bestFace,oldVert0,oldVert1,addVert);
testCache(currentFace);
if (strip.numElements==3)
{
testCache(currentFace);
// special case...rotate previous element until we can add this face
U32 doh=0;
while (swapNeeded(oldVert0,oldVert1))
{
rotateFace(strip.firstElement,stripIndices);
if (++doh==3)
{
AppConfig::SetExportError("14", "Assertion error while stripping: infinite loop");
return false;
}
}
stripIndices.push_back(addVert);
addToCache(addVert);
strip.numElements++;
testCache(bestFace);
}
else
{
testCache(currentFace);
if (swapNeeded(oldVert0,oldVert1))
{
U32 sz = stripIndices.size();
U32 dup = stripIndices[sz-3];
insElementAtIndex(stripIndices,sz-1,U16(dup));
stripIndices[sz-1] = dup;
addToCache(dup,1);
strip.numElements++;
testCache(-1);
}
stripIndices.push_back(addVert);
strip.numElements++;
addToCache(addVert);
testCache(bestFace);
}
// add other faces to recentFaces list
if (face0>=0 && face0!=bestFace)
recentFaces.push_back(face0);
if (face1>=0 && face1!=bestFace)
recentFaces.push_back(face1);
if (face2>=0 && face2!=bestFace)
recentFaces.push_back(face2);
// adjust adjacency information
for (S32 j=startFace; j<endFace; j++)
{
if (j==bestFace || used[j])
continue;
if (adjacent.isSet(bestFace,j))
{
numAdjacent[j]--;
if (numAdjacent[j]<0)
{
AppConfig::SetExportError("14", "Assertion failed when stripping (7)");
return false;
}
}
}
// mark face as used
used[bestFace] = true;
numAdjacent[bestFace] = 0;
currentFace = bestFace;
return true;
}
} // namespace DTS

77
lib/dtsSDKPlus/stripper.h Executable file
View File

@ -0,0 +1,77 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSMesh.h"
#include "DTSPlusTypes.h"
#include "DTSUtil.h"
#include "dtsBitMatrix.h" // see comment in dtsMatrix.h
namespace DTS
{
class Stripper
{
std::vector<S32> numAdjacent;
std::vector<bool> used;
BitMatrix adjacent;
std::vector<S32> vertexCache;
std::vector<S32> recentFaces;
S32 currentFace;
bool limitStripLength;
S32 bestLength;
U32 cacheMisses;
std::vector<Primitive> strips;
std::vector<U16> stripIndices;
std::vector<Primitive> & faces;
std::vector<U16> & faceIndices;
void clearCache();
void addToCache(S32 vertexIndex);
void addToCache(S32 vertexIndex, U32 posFromBack);
void getVerts(S32 face, S32 & oldVert0, S32 & oldVert1, S32 & addVert);
void rotateFace(S32 start, std::vector<U16> & indices);
bool swapNeeded(S32 oldVert0, S32 oldVert1);
F32 getScore(S32 face, bool ignoreOrder);
bool faceHasEdge(S32 face, U32 idx0, U32 idx1);
void getAdjacentFaces(S32 startFace, S32 endFace, S32 face, S32 & face0, S32 & face1, S32 & face2);
void setAdjacency(S32 startFace, S32 endFace);
bool startStrip(Primitive & strip, S32 startFace, S32 endFace);
bool addStrip(Primitive & strip, S32 startFace, S32 endFace);
bool stripLongEnough(S32 startFace, S32 endFace);
void testCache(S32 addedFace);
bool canGo(S32 face);
void makeStripsB(); // makeStrips() from faces...assumes all faces have same material index
void copyParams(Stripper *from);
public:
Stripper(std::vector<Primitive> & faces, std::vector<U16> & indices);
Stripper(Stripper &);
~Stripper();
void makeStrips();
S32 continueStrip(S32 startFace, S32 endFace, S32 len, S32 restart); // used for simulation...
void getStrips(std::vector<Primitive> & s, std::vector<U16> & si) { s=strips; si=stripIndices; }
void setLimitStripLength(bool lim) { limitStripLength = lim; }
void resetCacheMisses() { cacheMisses = 0; }
U32 getCacheMisses() { return cacheMisses; }
// adjust strip building strategy
static F32 adjacencyWeight;
static F32 noswapWeight;
static F32 alreadyCachedWeight;
static U32 cacheSize;
static U32 simK;
};
}

1224
lib/dtsSDKPlus/translucentSort.cpp Executable file

File diff suppressed because it is too large Load Diff

104
lib/dtsSDKPlus/translucentSort.h Executable file
View File

@ -0,0 +1,104 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _TRANS_SORT
#define _TRANS_SORT
#include "DTSTypes.h"
#include "DTSShape.h"
#include "DTSPlusTypes.h"
#include "DTSUtil.h"
namespace DTS
{
typedef std::vector<bool> IntegerSet;
class TranslucentSort
{
std::vector<IntegerSet*> frontClusters;
std::vector<IntegerSet*> backClusters;
std::vector<S32> middleCluster;
Point3D splitNormal;
F32 splitK;
S32 mNumBigFaces;
S32 mMaxDepth;
bool mZLayerUp;
bool mZLayerDown;
S32 currentDepth;
TranslucentSort * frontSort;
TranslucentSort * backSort;
struct FaceInfo
{
bool used;
S32 priority;
S32 parentFace;
S32 childFace1;
S32 childFace2;
S32 childFace3;
Point3D normal;
F32 k;
IntegerSet isInFrontOfMe;
IntegerSet isBehindMe;
IntegerSet isCutByMe;
IntegerSet isCoplanarWithMe;
};
std::vector<FaceInfo*> faceInfoList;
std::vector<FaceInfo*> saveFaceInfoList;
std::vector<Primitive> & mFaces;
std::vector<U16> & mIndices;
std::vector<Point3D> & mVerts;
std::vector<Point3D> & mNorms;
std::vector<Point2D> & mTVerts;
void initFaces();
void initFaceInfo(Primitive & face, FaceInfo & faceInfo, bool setPriority = true);
void setFaceInfo(Primitive & face, FaceInfo & faceInfo);
void clearFaces(IntegerSet &);
void saveFaceInfo();
void restoreFaceInfo();
void addFaces(IntegerSet *, std::vector<Primitive> & faces, std::vector<U16> & indices, bool continueLast = false);
void addFaces(std::vector<IntegerSet *> &, std::vector<Primitive> & faces, std::vector<U16> & indices, bool continueLast = false);
void addOrderedFaces(std::vector<S32> &, std::vector<Primitive> &, std::vector<U16> & indices, bool continueLast = false);
void splitFace(S32 faceIndex, Point3D normal, F32 k);
void splitFace2(S32 faceIndex, Point3D normal, F32 k);
void sort();
// routines for sorting faces when there is no perfect solution for all cases
void copeSort(std::vector<S32> &);
void layerSort(std::vector<S32> &, bool upFirst);
// these are for debugging
bool anyInFrontOfPlane(Point3D normal, F32 k);
bool anyBehindPlane(Point3D normal, F32 k);
//
void generateClusters(std::vector<Cluster> & clusters, std::vector<Primitive> & faces, std::vector<U16> & indices, S32 retIndex = -1);
TranslucentSort(TranslucentSort *);
TranslucentSort(std::vector<Primitive> & faces,
std::vector<U16> & indices,
std::vector<Point3D> & verts,
std::vector<Point3D> & norms,
std::vector<Point2D> & tverts,
S32 numBigFaces, S32 maxDepth, bool zLayerUp, bool zLayerDown);
~TranslucentSort();
public:
static void generateSortedMesh(Mesh * mesh, S32 numBigFaces, S32 maxDepth, bool zLayerUp, bool zLayerDown);
};
};
#endif // _TRANS_SORT