Initial commit
This commit is contained in:
748
Torque/SDK/tools/max2dtsExporter/maxUtil.cc
Normal file
748
Torque/SDK/tools/max2dtsExporter/maxUtil.cc
Normal file
@@ -0,0 +1,748 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "max2dtsExporter/maxUtil.h"
|
||||
|
||||
#pragma pack(push,8)
|
||||
#include <decomp.h>
|
||||
#include <dummy.h>
|
||||
#include <ISkin.h>
|
||||
#include <modstack.h>
|
||||
#pragma pack(pop)
|
||||
|
||||
#include "Core/tVector.h"
|
||||
|
||||
// Special for biped stuff -- class id in no header, so we just def it here
|
||||
// NOTE/WARNING: This could change with Character Studio updates
|
||||
#define BipedObjectClassID Class_ID(37157,0)
|
||||
|
||||
Point3F & Point3ToPoint3F(Point3 & p3, Point3F & p3f)
|
||||
{
|
||||
p3f.x = p3.x;
|
||||
p3f.y = p3.y;
|
||||
p3f.z = p3.z;
|
||||
return p3f;
|
||||
}
|
||||
|
||||
void convertToTransform(Matrix3 & mat, Quat16 & rot, Point3F & trans, Quat16 & srot, Point3F & scale)
|
||||
{
|
||||
AffineParts parts;
|
||||
decomp_affine(mat,&parts);
|
||||
Point3ToPoint3F(parts.t,trans);
|
||||
rot.set(QuatF(parts.q[0],parts.q[1],parts.q[2],parts.q[3]));
|
||||
srot.set(QuatF(parts.u[0],parts.u[1],parts.u[2],parts.u[3]));
|
||||
Point3ToPoint3F(parts.k,scale);
|
||||
}
|
||||
|
||||
MatrixF & convertToMatrixF(Matrix3 & mat3,MatrixF &matf)
|
||||
{
|
||||
matf.identity();
|
||||
Point3F x,y,z,p;
|
||||
Point3 x3 = mat3 * Point3(1.0f,0.0f,0.0f);
|
||||
Point3 y3 = mat3 * Point3(0.0f,1.0f,0.0f);
|
||||
Point3 z3 = mat3 * Point3(0.0f,0.0f,1.0f);
|
||||
Point3 p3 = mat3 * Point3(0.0f,0.0f,0.0f);
|
||||
x = Point3ToPoint3F(x3,x);
|
||||
y = Point3ToPoint3F(y3,y);
|
||||
z = Point3ToPoint3F(z3,z);
|
||||
p = Point3ToPoint3F(p3,p);
|
||||
x -= p;
|
||||
y -= p;
|
||||
z -= p;
|
||||
matf.setColumn(0,x);
|
||||
matf.setColumn(1,y);
|
||||
matf.setColumn(2,z);
|
||||
matf.setColumn(3,p);
|
||||
return matf;
|
||||
}
|
||||
|
||||
void getNodeTransform(INode *pNode, S32 time, Quat16 & rot, Point3F & trans, Quat16 & srot, Point3F & scale)
|
||||
{
|
||||
Matrix3 nodeMat = pNode->GetNodeTM( time );
|
||||
convertToTransform(nodeMat,rot,trans,srot,scale);
|
||||
}
|
||||
|
||||
TriObject * getTriObject( INode *pNode, S32 time, S32 multiResVerts, bool & deleteIt)
|
||||
{
|
||||
TriObject * tri = NULL;
|
||||
IParamBlock * paramBlock = NULL;
|
||||
|
||||
// if we're a multiRes object, dial us down
|
||||
if (multiResVerts>0)
|
||||
{
|
||||
Animatable * obj = (Animatable*)pNode->GetObjectRef();
|
||||
|
||||
for (S32 i=0; i<obj->NumSubs(); i++)
|
||||
{
|
||||
if (!dStrcmp(obj->SubAnimName(i),"MultiRes"))
|
||||
{
|
||||
paramBlock = (IParamBlock*)obj->SubAnim(i)->SubAnim(0);
|
||||
|
||||
Interval range = pNode->GetTimeRange(TIMERANGE_ALL|TIMERANGE_CHILDNODES|TIMERANGE_CHILDANIMS);
|
||||
paramBlock->SetValue(0,time,multiResVerts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the object can't convert to a tri-mesh, eval world state to
|
||||
// get an object that can:
|
||||
const ObjectState &os = pNode->EvalWorldState(time);
|
||||
|
||||
if ( os.obj->CanConvertToType(triObjectClassID) )
|
||||
tri = (TriObject *)os.obj->ConvertToType( time, triObjectClassID );
|
||||
|
||||
deleteIt = (tri && (tri != os.obj));
|
||||
|
||||
return tri;
|
||||
}
|
||||
|
||||
F32 findVolume(INode * pNode, S32 & polyCount)
|
||||
{
|
||||
bool deleteTri;
|
||||
TriObject * tri = getTriObject(pNode,DEFAULT_TIME,-1,deleteTri);
|
||||
if (!tri)
|
||||
{
|
||||
polyCount=0;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
Mesh & mesh = tri->mesh;
|
||||
polyCount = mesh.getNumFaces();
|
||||
Box3F bounds;
|
||||
bounds.min.set( 10E30f, 10E30f, 10E30f);
|
||||
bounds.max.set(-10E30f,-10E30f,-10E30f);
|
||||
for (S32 i=0; i<mesh.numVerts; i++)
|
||||
{
|
||||
Point3F v = Point3ToPoint3F(mesh.verts[i],v);
|
||||
bounds.min.setMin(v);
|
||||
bounds.max.setMax(v);
|
||||
}
|
||||
if (deleteTri)
|
||||
delete tri;
|
||||
return (bounds.max.x-bounds.min.x)*(bounds.max.y-bounds.min.y)*(bounds.max.z-bounds.min.z);
|
||||
}
|
||||
|
||||
void findSkinData(INode * pNode, ISkin **skin, ISkinContextData ** skinData)
|
||||
{
|
||||
// till proven otherwise...
|
||||
*skin = NULL;
|
||||
*skinData = NULL;
|
||||
|
||||
// Get object from node. Abort if no object.
|
||||
Object* obj = pNode->GetObjectRef();
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
Modifier * mod = NULL;
|
||||
|
||||
// Is derived object ?
|
||||
S32 i;
|
||||
while (obj->SuperClassID() == GEN_DERIVOB_CLASS_ID)
|
||||
{
|
||||
IDerivedObject* dobj = (IDerivedObject*) obj;
|
||||
// Iterate over all entries of the modifier stack.
|
||||
for (i=0;i<dobj->NumModifiers();i++)
|
||||
if (dobj->GetModifier(i)->ClassID() == SKIN_CLASSID)
|
||||
break;
|
||||
|
||||
if (i!=dobj->NumModifiers())
|
||||
{
|
||||
mod = dobj->GetModifier(i);
|
||||
break;
|
||||
}
|
||||
obj = dobj->GetObjRef();
|
||||
}
|
||||
if (!mod)
|
||||
return;
|
||||
*skin = (ISkin*) mod->GetInterface(I_SKIN);
|
||||
if (!*skin)
|
||||
return;
|
||||
*skinData = (*skin)->GetContextInterface(pNode);
|
||||
if (!*skinData)
|
||||
*skin=NULL; // return both or neither
|
||||
}
|
||||
|
||||
bool hasSkin(INode * pNode)
|
||||
{
|
||||
ISkin * skin;
|
||||
ISkinContextData * skinData;
|
||||
findSkinData(pNode,&skin,&skinData);
|
||||
return skin != NULL;
|
||||
}
|
||||
|
||||
bool hasMesh(INode * pNode)
|
||||
{
|
||||
ObjectState os = pNode->EvalWorldState(0);
|
||||
return( os.obj->CanConvertToType(triObjectClassID) && !(os.obj->ClassID() == BipedObjectClassID) );
|
||||
}
|
||||
|
||||
void zapScale(Matrix3 & mat)
|
||||
{
|
||||
AffineParts parts;
|
||||
decomp_affine(mat,&parts);
|
||||
|
||||
// now put the matrix back together again without the scale:
|
||||
// mat = mat.rot * mat.pos
|
||||
mat.IdentityMatrix();
|
||||
mat.PreTranslate(parts.t);
|
||||
PreRotateMatrix(mat,parts.q);
|
||||
}
|
||||
|
||||
Matrix3 & getLocalNodeMatrix(INode *pNode, INode *parent, S32 time, Matrix3 & 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) = inverse(Tscale(0)) * T(time)
|
||||
// Note: above formula is max style. Torque style would have the order reveresed. :(
|
||||
|
||||
// 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...
|
||||
Matrix3 m1 = pNode->GetNodeTM(time);
|
||||
Matrix3 m2 = parent ? parent->GetNodeTM(time) : Matrix3(true);
|
||||
if (time==DEFAULT_TIME)
|
||||
{
|
||||
decomp_affine(m1,&a10);
|
||||
decomp_affine(m2,&a20);
|
||||
}
|
||||
|
||||
// build the inverse scale matrices
|
||||
Matrix3 stretchRot10,stretchRot20;
|
||||
Point3 sfactor10, sfactor20;
|
||||
Matrix3 invScale10, invScale20;
|
||||
a10.u.MakeMatrix(stretchRot10);
|
||||
a20.u.MakeMatrix(stretchRot20);
|
||||
sfactor10 = Point3(a10.f/a10.k.x,a10.f/a10.k.y,a10.f/a10.k.z);
|
||||
sfactor20 = Point3(a20.f/a20.k.x,a20.f/a20.k.y,a20.f/a20.k.z);
|
||||
invScale10 = Inverse(stretchRot10) * ScaleMatrix(sfactor10) * stretchRot10;
|
||||
invScale20 = Inverse(stretchRot20) * ScaleMatrix(sfactor20) * stretchRot20;
|
||||
|
||||
// build world transforms
|
||||
m1 = invScale10 * m1;
|
||||
m2 = invScale20 * m2;
|
||||
|
||||
// build local transform
|
||||
matrix = m1 * Inverse(m2);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void getLocalNodeTransform(INode *pNode, INode *parent, AffineParts & child0, AffineParts & parent0, S32 time, Quat16 & rot, Point3F & trans, Quat16 & srot, Point3F & scale)
|
||||
{
|
||||
Matrix3 local;
|
||||
getLocalNodeMatrix(pNode,parent,time,local,parent0,child0);
|
||||
convertToTransform(local,rot,trans,srot,scale);
|
||||
}
|
||||
|
||||
void getBlendNodeTransform(INode *pNode, INode *parent, AffineParts & child0, AffineParts & parent0, S32 time, S32 referenceTime, Quat16 & rot, Point3F & trans, Quat16 & srot, Point3F & scale)
|
||||
{
|
||||
Matrix3 m1;
|
||||
Matrix3 m2;
|
||||
|
||||
getLocalNodeMatrix(pNode, parent, referenceTime, m1, child0, parent0);
|
||||
getLocalNodeMatrix(pNode, parent, time, m2, child0, parent0);
|
||||
m1 = Inverse(m1);
|
||||
m2 *= m1;
|
||||
convertToTransform(m2, rot,trans,srot,scale);
|
||||
}
|
||||
|
||||
void computeObjectOffset(INode * pNode, Matrix3 & mat)
|
||||
{
|
||||
// compute the object offset transform...
|
||||
// this will be applied to all the verts of the meshes...
|
||||
// we grab this straight from the node, but we also
|
||||
// multiply in any scaling on the node transform because
|
||||
// the scaling will be stripped out when making a tsshape
|
||||
|
||||
Matrix3 nodeMat = pNode->GetNodeTM(DEFAULT_TIME);
|
||||
zapScale(nodeMat);
|
||||
nodeMat = Inverse(nodeMat);
|
||||
|
||||
mat = pNode->GetObjTMAfterWSM(DEFAULT_TIME);
|
||||
mat *= nodeMat;
|
||||
}
|
||||
|
||||
void getDeltaTransform(INode * pNode, S32 time1, S32 time2, Quat16 & rot, Point3F & trans, Quat16 & srot, Point3F & scale)
|
||||
{
|
||||
Matrix3 m1 = pNode->GetNodeTM(time2);
|
||||
Matrix3 m2 = pNode->GetNodeTM(time1);
|
||||
m2 = Inverse(m2);
|
||||
m1 *= m2;
|
||||
convertToTransform(m1,rot,trans,srot,scale);
|
||||
}
|
||||
|
||||
bool isVis(INode * pNode, S32 time)
|
||||
{
|
||||
return pNode->GetVisibility(time) > 0.0000001f;
|
||||
}
|
||||
|
||||
F32 getVisValue(INode * pNode, S32 time)
|
||||
{
|
||||
return pNode->GetVisibility(time);
|
||||
}
|
||||
|
||||
bool animatesVis(INode * pNode, const Interval & range, bool & error)
|
||||
{
|
||||
// running error...exit if already encountered an error
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
F32 startVis = getVisValue(pNode,range.Start());
|
||||
for (S32 i=range.Start()+1; i<=range.End(); i++)
|
||||
if (mFabs(startVis-getVisValue(pNode,i))>0.01f)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool animatesFrame(INode * pNode, const Interval & range, bool & error)
|
||||
{
|
||||
// running error...exit if already encountered an error
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
bool deleteIt;
|
||||
TriObject * tri = getTriObject(pNode,range.Start(),-1,deleteIt);
|
||||
if (!tri)
|
||||
{
|
||||
error = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Interval ivalid;
|
||||
ivalid = tri->ChannelValidity(range.Start(), GEOM_CHAN_NUM);
|
||||
|
||||
if (deleteIt)
|
||||
tri->DeleteMe();
|
||||
|
||||
return (ivalid.Start() > range.Start() || ivalid.End() < range.End());
|
||||
}
|
||||
|
||||
bool animatesMatFrame(INode * pNode, const Interval & range, bool & error)
|
||||
{
|
||||
// running error...exit if already encountered an error
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
|
||||
bool deleteIt;
|
||||
TriObject * tri = getTriObject(pNode,range.Start(),-1,deleteIt);
|
||||
if (!tri)
|
||||
{
|
||||
error = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Interval ivalid;
|
||||
ivalid = tri->ChannelValidity(range.Start(), TEXMAP_CHAN_NUM);
|
||||
|
||||
if (deleteIt)
|
||||
tri->DeleteMe();
|
||||
|
||||
return (ivalid.Start() > range.Start() || ivalid.End() < range.End());
|
||||
}
|
||||
|
||||
bool isdigit(char ch)
|
||||
{
|
||||
return (ch>='0' && ch<='9');
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// If 's' ends in a number, chopNum returns
|
||||
// a pointer to first digit in this number.
|
||||
// If not, then returns pointer to '\0'
|
||||
// at end of name or first of any trailing
|
||||
// spaces.
|
||||
char * chopNum(char * s)
|
||||
{
|
||||
if (s==NULL)
|
||||
return NULL;
|
||||
|
||||
char * p = s + dStrlen(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
|
||||
if (*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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// separates nodes names into base name
|
||||
// and detail number
|
||||
char * chopTrailingNumber(const char * fullName, S32 & size)
|
||||
{
|
||||
if (!fullName)
|
||||
{
|
||||
size = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char * buffer = dStrdup(fullName);
|
||||
char * p = chopNum(buffer);
|
||||
if (*p=='\0')
|
||||
{
|
||||
size = -1;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
size = dAtoi(p);
|
||||
*p='\0'; // terminate string
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// returns a list of detail levels of this shape...grabs meshes off shape
|
||||
// and finds meshes on root level with same name but different trailing
|
||||
// detail number (i.e., head32 on shape, head16 at root, leads to detail
|
||||
// levels 32 and 16).
|
||||
void findDetails(INode * base, INode * root, Vector<S32> & details)
|
||||
{
|
||||
S32 i,j,k;
|
||||
|
||||
// run through all the descendents of this node
|
||||
// and look for numbers indicating detail levels
|
||||
Vector<INode*> nodeStack;
|
||||
nodeStack.push_back(base);
|
||||
while (!nodeStack.empty())
|
||||
{
|
||||
INode * node = nodeStack.last();
|
||||
nodeStack.pop_back();
|
||||
if (hasMesh(node))
|
||||
{
|
||||
// have a mesh...a little obscure below:
|
||||
// add # of this mesh + any mesh w/ same
|
||||
// name on the root level to details vector
|
||||
S32 detailSize;
|
||||
char * baseName = chopTrailingNumber(node->GetName(),detailSize);
|
||||
INode * meshNode = node;
|
||||
for (j=-1;j<root->NumberOfChildren();j++)
|
||||
{
|
||||
if (j>=0)
|
||||
meshNode = root->GetChildNode(j);
|
||||
if (!hasMesh(meshNode))
|
||||
continue;
|
||||
char * meshName = chopTrailingNumber(meshNode->GetName(),detailSize);
|
||||
if (!dStricmp(baseName,meshName))
|
||||
{
|
||||
for (k=0; k<details.size(); k++)
|
||||
if (detailSize==details[k])
|
||||
break;
|
||||
if (k==details.size())
|
||||
details.push_back(detailSize);
|
||||
}
|
||||
dFree(meshName);
|
||||
}
|
||||
dFree(baseName);
|
||||
}
|
||||
for (j=0; j<node->NumberOfChildren();j++)
|
||||
nodeStack.push_back(node->GetChildNode(j));
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// find selected subtrees (nodes on root level only) and embed in subtree of
|
||||
// the style the exporter looks for:
|
||||
// Root
|
||||
// |
|
||||
// |-base
|
||||
// |-start
|
||||
// | |
|
||||
// | |-<selected node 1>
|
||||
// | | .
|
||||
// | | .
|
||||
// | |-<selected node N>
|
||||
// |
|
||||
// |-detail 1
|
||||
// | .
|
||||
// | .
|
||||
// |-detail N
|
||||
void embedSubtree(Interface * ip)
|
||||
{
|
||||
S32 i,j,k;
|
||||
|
||||
// make dummy node named baseName
|
||||
TSTR baseName("base");
|
||||
ip->MakeNameUnique(baseName);
|
||||
INode * base = ip->CreateObjectNode(new DummyObject);
|
||||
base->SetName(baseName);
|
||||
|
||||
// make dummy node named startName
|
||||
TSTR startName("start");
|
||||
ip->MakeNameUnique(startName);
|
||||
INode * start = ip->CreateObjectNode(new DummyObject);
|
||||
start->SetName(startName);
|
||||
|
||||
// link later to former
|
||||
base->AttachChild(start);
|
||||
|
||||
Vector<S32> details;
|
||||
|
||||
// loop through selection set, link to start (only if child of root)
|
||||
S32 count = ip->GetSelNodeCount();
|
||||
INode * root = ip->GetRootNode();
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
INode * node = ip->GetSelNode(i);
|
||||
if (!node->GetParentNode()->IsRootNode())
|
||||
continue;
|
||||
start->AttachChild(node);
|
||||
|
||||
findDetails(node,root,details);
|
||||
}
|
||||
|
||||
// now create detail markers
|
||||
for (i=0; i<details.size();i++)
|
||||
{
|
||||
char detailName[20];
|
||||
INode * detailNode = ip->CreateObjectNode(new DummyObject);
|
||||
dSprintf(detailName,20,"detail%i",details[i]);
|
||||
detailNode->SetName(detailName);
|
||||
base->AttachChild(detailNode);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void registerDetails(Interface * ip)
|
||||
{
|
||||
S32 i,j,k;
|
||||
|
||||
// loop through selection set, only care about nodes off root
|
||||
S32 count = ip->GetSelNodeCount();
|
||||
INode * root = ip->GetRootNode();
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
INode * node = ip->GetSelNode(i);
|
||||
if (!node->GetParentNode()->IsRootNode())
|
||||
continue;
|
||||
|
||||
Vector<S32> details;
|
||||
|
||||
// search branches of tree for meshes and find their details
|
||||
for (j=0; j<node->NumberOfChildren(); j++)
|
||||
{
|
||||
INode * child = node->GetChildNode(j);
|
||||
if (child->NumberOfChildren()>0)
|
||||
findDetails(child,root,details);
|
||||
}
|
||||
|
||||
// go through children of base node and cull detail numbers
|
||||
// that don't need to be added (because detail marker already
|
||||
// present)
|
||||
for (j=0; j<node->NumberOfChildren(); j++)
|
||||
{
|
||||
INode * child = node->GetChildNode(j);
|
||||
if (child->NumberOfChildren()==0)
|
||||
{
|
||||
// look for #
|
||||
S32 detailSize;
|
||||
char * baseName = chopTrailingNumber(child->GetName(),detailSize);
|
||||
dFree(baseName);
|
||||
for (k=0;k<details.size();k++)
|
||||
{
|
||||
if (details[k]==detailSize)
|
||||
{
|
||||
// found it
|
||||
details.erase(k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// items left in details list are unique -- add markers
|
||||
for (j=0;j<details.size();j++)
|
||||
{
|
||||
char detailName[20];
|
||||
INode * detailNode = ip->CreateObjectNode(new DummyObject);
|
||||
dSprintf(detailName,20,"detail%i",details[j]);
|
||||
detailNode->SetName(detailName);
|
||||
node->AttachChild(detailNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void renumberNodes(Interface * ip, S32 newSize)
|
||||
{
|
||||
S32 i, count = ip->GetSelNodeCount();
|
||||
char newName[128];
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
INode * node = ip->GetSelNode(i);
|
||||
S32 oldSize;
|
||||
char * baseName = chopTrailingNumber(node->GetName(),oldSize);
|
||||
dSprintf(newName,128,"%s%i",baseName,newSize);
|
||||
node->SetName(newName);
|
||||
dFree(baseName);
|
||||
}
|
||||
}
|
||||
|
||||
// this version of doDot used by m_pointInPoly
|
||||
inline float doDot(F32 v1x, F32 v1y, F32 v2x, F32 v2y, F32 px, F32 py)
|
||||
{
|
||||
return (v1x-px) * (v1y-v2y) +
|
||||
(v1y-py) * (v2x-v1x);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// pointInPoly returns true if point is inside poly defined by verts on plane w/
|
||||
// normal "normal" -- based on m_pointInTriangle.
|
||||
//------------------------------------------------------------------------------------
|
||||
bool pointInPoly(const Point3F & point,
|
||||
const Point3F & normal,
|
||||
const Point3F * verts,
|
||||
U32 n)
|
||||
{
|
||||
F32 thisDot, lastDot=0;
|
||||
U32 i;
|
||||
|
||||
// we can ignore one of the dimensions because all points are on the same plane...
|
||||
if (mFabs(normal.y)>mFabs(normal.x)&&mFabs(normal.y)>mFabs(normal.z))
|
||||
{
|
||||
// drop y coord
|
||||
thisDot = doDot(verts[n-1].x,verts[n-1].z,verts[0].x,verts[0].z,point.x,point.z);
|
||||
if (thisDot*lastDot<0)
|
||||
return false;
|
||||
lastDot = thisDot;
|
||||
|
||||
for (i=0;i<n-1;i++)
|
||||
{
|
||||
thisDot = doDot(verts[i].x,verts[i].z,verts[i+1].x,verts[i+1].z,point.x,point.z);
|
||||
if (thisDot*lastDot<0)
|
||||
return false; // different sign, point outside one of the edges
|
||||
lastDot = thisDot;
|
||||
}
|
||||
}
|
||||
else if (mFabs(normal.x)>mFabs(normal.y)&&mFabs(normal.x)>mFabs(normal.z))
|
||||
{
|
||||
// drop x coord
|
||||
thisDot = doDot(verts[n-1].y,verts[n-1].z,verts[0].y,verts[0].z,point.y,point.z);
|
||||
if (thisDot*lastDot<0)
|
||||
return false;
|
||||
lastDot = thisDot;
|
||||
|
||||
for (i=0;i<n-1;i++)
|
||||
{
|
||||
thisDot = doDot(verts[i].y,verts[i].z,verts[i+1].y,verts[i+1].z,point.y,point.z);
|
||||
if (thisDot*lastDot<0)
|
||||
return false; // different sign, point outside one of the edges
|
||||
lastDot = thisDot;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// drop z coord
|
||||
thisDot = doDot(verts[n-1].x,verts[n-1].y,verts[0].x,verts[0].y,point.x,point.y);
|
||||
if (thisDot*lastDot<0)
|
||||
return false;
|
||||
lastDot = thisDot;
|
||||
|
||||
for (i=0;i<n-1;i++)
|
||||
{
|
||||
thisDot = doDot(verts[i].x,verts[i].y,verts[i+1].x,verts[i+1].y,point.x,point.y);
|
||||
if (thisDot*lastDot<0)
|
||||
return false; // different sign, point outside one of the edges
|
||||
lastDot = thisDot;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// deal with some unresolved externals...
|
||||
#include "platform/event.h"
|
||||
#include "core/bitStream.h"
|
||||
void GamePostEvent(struct Event const &) {}
|
||||
void GameHandleInfoPacket(struct NetAddress const *, BitStream *){}
|
||||
void GameHandleDataPacket(S32, BitStream *){}
|
||||
void GameConnectionAccepted(S32, BitStream *){}
|
||||
void GameConnectionRejected(S32, BitStream *){}
|
||||
void GameConnectionDisconnected(S32, BitStream *){}
|
||||
void GameConnectionRequested(struct NetAddress const *, BitStream *){}
|
||||
void GameConnectionEstablished(S32){}
|
||||
void GameHandleNotify(S32,bool){}
|
||||
void GameConnectionTimedOut(S32){}
|
||||
void GameDeactivate(bool) {}
|
||||
void GameReactivate() {}
|
||||
S32 GameMain(S32,char const * *){ return 0; }
|
||||
U32 getTickCount() { return 0; }
|
||||
void (*terrMipBlit)(U16 *dest, U32 destStride, U32 squareSize, const U8 *sourcePtr, U32 sourceStep, U32 sourceRowAdd);
|
||||
bool gEditingMission;
|
||||
|
||||
class SimGroup;
|
||||
SimGroup * gDataBlockGroup;
|
||||
SimGroup * gActionMapGroup;
|
||||
SimGroup * gClientGroup;
|
||||
SimGroup * gGuiGroup;
|
||||
SimGroup * gGuiDataGroup;
|
||||
SimGroup * gTCPGroup;
|
||||
class SimSet;
|
||||
SimSet * gActiveActionMapSet;
|
||||
SimSet * gGhostAlwaysSet;
|
||||
SimSet * gLightSet;
|
||||
|
||||
//------------------------------------------------------
|
||||
// These routines aren't currently used, but could prove
|
||||
// useful at a later time...
|
||||
//------------------------------------------------------
|
||||
/*
|
||||
|
||||
MatrixF & getNodeMatrix(INode *pNode, S32 time, MatrixF & matrix)
|
||||
{
|
||||
Matrix3 nodeMat = pNode->GetNodeTM( time );
|
||||
convertToMatrixF(nodeMat,matrix);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
MatrixF & getLocalNodeMatrix(INode *pNode, INode *parent, S32 time, MatrixF & matrix)
|
||||
{
|
||||
if (!parent)
|
||||
return getNodeMatrix(pNode,time,matrix);
|
||||
|
||||
MatrixF m1,m2;
|
||||
getNodeMatrix(pNode,time,m1);
|
||||
getNodeMatrix(parent,time ,m2);
|
||||
m2.inverse();
|
||||
matrix.mul(m1,m2);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
*/
|
||||
Reference in New Issue
Block a user