Initial commit

This commit is contained in:
Eagle517
2025-02-17 23:17:30 -06:00
commit 7cad314c94
4726 changed files with 1145203 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,237 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef NV_TRISTRIP_OBJECTS_H
#define NV_TRISTRIP_OBJECTS_H
//#include <assert.h>
//#include <windows.h>
//#include <vector>
//#include <list>
#ifndef _NVVERTEXCACHE_H_
#include "max2dtsExporter/NvVertexCache.h"
#endif
#ifndef _TVECTOR_H_
#include "Core/tVector.h"
#endif
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
//#define int S32
#define UINT U32
//#define float F32
#define WORD U16
/////////////////////////////////////////////////////////////////////////////////
//
// Types defined for stripification
//
/////////////////////////////////////////////////////////////////////////////////
struct MyVertex {
float x, y, z;
float nx, ny, nz;
};
typedef MyVertex MyVector;
struct MyFace {
int v1, v2, v3;
float nx, ny, nz;
};
class NvFaceInfo {
public:
// vertex indices
NvFaceInfo(int v0, int v1, int v2){
m_v0 = v0; m_v1 = v1; m_v2 = v2;
m_stripId = -1;
m_testStripId = -1;
m_experimentId = -1;
}
// data members are left public
int m_v0, m_v1, m_v2;
int m_stripId; // real strip Id
int m_testStripId; // strip Id in an experiment
int 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 (int v0, int 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;
int 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 Vector<NvFaceInfo*> NvFaceInfoVec;
typedef Vector<NvFaceInfo*> NvFaceInfoList;
typedef Vector<NvFaceInfoVec*> NvStripList;
typedef Vector<NvEdgeInfo*> NvEdgeInfoVec;
typedef Vector<WORD> WordVec;
typedef Vector<MyVertex> MyVertexVec;
typedef Vector<MyFace> MyFaceVec;
// 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, int stripId, int experimentId = -1) :
m_startInfo(startInfo)
{
m_stripId = stripId;
m_experimentId = experimentId;
visited = false;
}
// 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;
int m_stripId;
int m_experimentId;
bool visited;
};
typedef 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 int in_cacheSize, const int in_minStripLength,
NvStripInfoVec &allStrips, NvFaceInfoVec &allFaces);
static int GetUniqueVertexInB(NvFaceInfo *faceA, NvFaceInfo *faceB);
static int GetSharedVertex(NvFaceInfo *faceA, NvFaceInfo *faceB);
protected:
WordVec indices;
int cacheSize;
int minStripLength;
float meshJump;
bool bFirstTimeResetPoint;
/////////////////////////////////////////////////////////////////////////////////
//
// Big mess of functions called during stripification
//
/////////////////////////////////////////////////////////////////////////////////
static int GetNextIndex(const WordVec &indices, NvFaceInfo *face);
static NvEdgeInfo *FindEdgeInfo(NvEdgeInfoVec &edgeInfos, int v0, int v1);
static NvFaceInfo *FindOtherFace(NvEdgeInfoVec &edgeInfos, int v0, int v1, NvFaceInfo *faceInfo);
NvFaceInfo *FindGoodResetPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
void FindAllStrips(NvStripInfoVec &allStrips, NvFaceInfoVec &allFaceInfos, NvEdgeInfoVec &allEdgeInfos, int 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);
int CountRemainingTris(Vector<NvStripInfo*>::iterator iter, Vector<NvStripInfo*>::iterator end);
void CommitStrips(NvStripInfoVec &allStrips, const NvStripInfoVec &strips);
float AvgStripSize(const NvStripInfoVec &strips);
int FindStartPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
void UpdateCacheStrip(VertexCache* vcache, NvStripInfo* strip);
void UpdateCacheFace(VertexCache* vcache, NvFaceInfo* face);
float CalcNumHitsStrip(VertexCache* vcache, NvStripInfo* strip);
int CalcNumHitsFace(VertexCache* vcache, NvFaceInfo* face);
int NumNeighbors(NvFaceInfo* face, NvEdgeInfoVec& edgeInfoVec);
void BuildStripifyInfo(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
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 NvStripInfo;
};
#endif

View File

@ -0,0 +1,57 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "max2dtsExporter/NvVertexCache.h"
VertexCache::VertexCache()
{
VertexCache(16);
}
VertexCache::VertexCache(int size)
{
numEntries = size;
entries = new int[numEntries];
for(int i = 0; i < numEntries; i++)
entries[i] = -1;
}
VertexCache::~VertexCache()
{
delete[] entries;
}
int VertexCache::At(int index)
{
return entries[index];
}
void VertexCache::Set(int index, int value)
{
entries[index] = value;
}
void VertexCache::Clear()
{
for(int i = 0; i < numEntries; i++)
entries[i] = -1;
}
void VertexCache::Copy(VertexCache* inVcache)
{
for(int i = 0; i < numEntries; i++)
{
inVcache->Set(i, entries[i]);
}
}

View File

@ -0,0 +1,71 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#if !defined(VERTEX_CACHE_H)
#define VERTEX_CACHE_H
class VertexCache
{
public:
VertexCache(int size);
VertexCache();
~VertexCache();
bool InCache(int entry);
int AddEntry(int entry);
void Clear();
void Copy(VertexCache* inVcache);
int At(int index);
void Set(int index, int value);
private:
int *entries;
int numEntries;
};
inline bool VertexCache::InCache(int entry)
{
bool returnVal = false;
for(int i = 0; i < numEntries; i++)
{
if(entries[i] == entry)
{
returnVal = true;
break;
}
}
return returnVal;
}
inline int VertexCache::AddEntry(int entry)
{
int removed;
removed = entries[numEntries - 1];
//push everything right one
for(int i = numEntries - 2; i >= 0; i--)
{
entries[i + 1] = entries[i];
}
entries[0] = entry;
return removed;
}
#endif

1007
tools/max2dtsExporter/SceneEnum.cc Executable file

File diff suppressed because it is too large Load Diff

126
tools/max2dtsExporter/SceneEnum.h Executable file
View File

@ -0,0 +1,126 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef SCENEENUM_H_
#define SCENEENUM_H_
#pragma pack(push,8)
#include <max.h>
#pragma pack(pop)
#include "max2dtsExporter/shapeMimic.h"
#include "ts/tsShape.h"
#include "platform/platform.h"
#include "core/tvector.h"
#include "core/filestream.h"
class SceneEnumProc : public ITreeEnumProc
{
static FileStream file;
Vector<INode*> meshNodes;
Vector<INode*> skinNodes;
Vector<INode*> subTrees;
Vector<INode*> sequences;
INode *boundsNode;
INode *viconNode;
ShapeMimic shapeMimic;
TSShape * pShape;
bool exportError;
char * exportErrorStr;
S32 getSequence( INode *pNode );
static void clearExportConfig();
void getPolyCount(S32 & polyCount, F32 & minVolPerPoly, F32 & maxVolPerPoly);
void getPolyCountSubtree(INode *, S32 &, F32 & minVolPerPoly, F32 & maxVolPerPoly);
public:
SceneEnumProc();
~SceneEnumProc();
static Vector<char *> alwaysExport;
static Vector<char *> neverExport;
static Vector<char *> neverAnimate;
static char exportType;
static const char * readConfigFile(const char * filename);
static void writeConfigFile(const char * filename);
static void setInitialDefaults();
static bool dumpShape(const char * filename);
void exportTextFile(Stream * file);
static bool isDummy(INode *pNode);
static bool isBounds(INode *pNode);
static bool isVICON(INode *pNode);
static bool isCamera(INode *pNode);
static bool isSubtree(INode *pNode);
static bool isBillboard(INode * pNode);
static bool isBillboardZAxis(INode * pNode);
static bool isSortedObject(INode * pNode);
static bool isDecal(INode * pNode);
static void tweakName(const char ** nodeName); // can only take from front at this point...
static void printDump(U32 mask, const char *);
void startDump(const TCHAR * filename, const TCHAR * maxFile);
void setExportError(const char * errStr) { dFree(exportErrorStr); exportErrorStr = dStrdup(errStr); exportError = true; }
void clearExportError() { exportError = false; dFree(exportErrorStr); exportErrorStr = NULL; }
bool isExportError() { return exportError; }
const char * getExportError() { return exportErrorStr; }
TSShape * getShape() { return pShape; }
TSShape * regenShape(); // for testing purposes only...
bool isEmpty();
S32 callback( INode *node );
void processScene();
void enumScene(IScene *);
};
// 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
};
// parameters of export...
extern U32 dumpMask;
extern U32 allowEmptySubtrees;
extern U32 allowCrossedDetails;
extern U32 allowUnusedMeshes;
extern U32 transformCollapse;
extern U32 viconNeeded;
extern U32 enableSequences;
extern U32 allowOldSequences;
extern U32 enableTwoSidedMaterials;
extern F32 animationDelta;
extern F32 maxFrameRate;
extern S32 weightsPerVertex;
extern F32 weightThreshhold;
extern char baseTexturePath[256];
extern S32 t2AutoDetail;
extern void setBaseTexturePath(const char *);
//--------------------------------------------------------------
#endif

192
tools/max2dtsExporter/Sequence.h Executable file
View File

@ -0,0 +1,192 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _SEQUENCE_H_
#define _SEQUENCE_H_
#pragma pack(push,8)
#include <MAX.H>
#include <dummy.h>
#include <iparamm.h>
#pragma pack(pop)
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#define SEQUENCE_CLASS_ID Class_ID(0x63a64197, 0xfd72a55)
#define PB_SEQ_BEGIN_END 0
#define PB_SEQ_CYCLIC 1
#define PB_SEQ_BLEND 2
#define PB_SEQ_LAST_FIRST_FRAME_SAME 3 // only valid if cyclic
#define PB_SEQ_USE_FRAME_RATE 4 // if this
#define PB_SEQ_FRAME_RATE 5 // then this
#define PB_SEQ_NUM_FRAMES 6 // else this
#define PB_SEQ_IGNORE_GROUND_TRANSFORM 7
#define PB_SEQ_USE_GROUND_FRAME_RATE 8 // if this
#define PB_SEQ_GROUND_FRAME_RATE 9 // then use this
#define PB_SEQ_NUM_GROUND_FRAMES 10// else use this
#define PB_SEQ_ENABLE_MORPH_ANIMATION 11
#define PB_SEQ_ENABLE_VIS_ANIMATION 12
#define PB_SEQ_ENABLE_TRANSFORM_ANIMATION 13
#define PB_SEQ_FORCE_MORPH_ANIMATION 14
#define PB_SEQ_FORCE_VIS_ANIMATION 15
#define PB_SEQ_FORCE_TRANSFORM_ANIMATION 16
#define PB_SEQ_DEFAULT_PRIORITY 17
#define PB_SEQ_BLEND_REFERENCE_TIME 18
#define PB_SEQ_ENABLE_TEXTURE_ANIMATION 19
#define PB_SEQ_ENABLE_IFL_ANIMATION 20
#define PB_SEQ_FORCE_TEXTURE_ANIMATION 21
#define PB_SEQ_TRIGGERS 22
#define PB_SEQ_ENABLE_DECAL_ANIMATION 23
#define PB_SEQ_ENABLE_DECAL_FRAME_ANIMATION 24
#define PB_SEQ_FORCE_DECAL_ANIMATION 25
#define PB_SEQ_OVERRIDE_DURATION 26
#define PB_SEQ_DURATION 27
#define PB_SEQ_ENABLE_UNIFORM_SCALE_ANIMATION 28
#define PB_SEQ_ENABLE_ARBITRARY_SCALE_ANIMATION 29
#define PB_SEQ_FORCE_SCALE_ANIMATION 30
// Class ID for old sequence class -- id for exporter used
// in starsiege, tribes 1, and other games around that time
// You know, games from the previous millenium.
#define OLD_SEQUENCE_CLASS_ID Class_ID(0x09923023,0)
// param block constants for old sequence class
#define PB_OLD_SEQ_ONESHOT 3
#define PB_OLD_SEQ_FORCEVIS 4
#define PB_OLD_SEQ_VISONLY 5
#define PB_OLD_SEQ_NOCOLLAPSE 6
#define PB_OLD_SEQ_USECELRATE 7
extern ClassDesc * GetSequenceDesc();
extern bool getBoolSequenceDefault(S32 index);
extern F32 getFloatSequenceDefault(S32 index);
extern S32 getIntSequenceDefault(S32 index);
extern void resetSequenceDefaults();
class SequenceObject: public DummyObject
{
public:
static U32 defaultCyclic;
static U32 defaultBlend;
static U32 defaultFirstLastFrameSame;
static U32 defaultUseFrameRate;
static F32 defaultFrameRate;
static S32 defaultNumFrames;
static U32 defaultIgnoreGroundTransform;
static U32 defaultUseGroundFrameRate;
static F32 defaultGroundFrameRate;
static S32 defaultNumGroundFrames;
static U32 defaultEnableMorphAnimation;
static U32 defaultEnableVisAnimation;
static U32 defaultEnableTransformAnimation;
static U32 defaultForceMorphAnimation;
static U32 defaultForceVisAnimation;
static U32 defaultForceTransformAnimation;
static S32 defaultDefaultSequencePriority;
static S32 defaultBlendReferenceTime;
static U32 defaultEnableTextureAnimation;
static U32 defaultEnableIflAnimation;
static U32 defaultForceTextureAnimation;
static U32 defaultEnableDecalAnimation;
static U32 defaultEnableDecalFrameAnimation;
static U32 defaultForceDecalAnimation;
static U32 defaultOverrideDuration;
static F32 defaultDuration;
static U32 defaultEnableUniformScaleAnimation;
static U32 defaultEnableArbitraryScaleAnimation;
static U32 defaultForceScaleAnimation;
// Class vars
IParamBlock *pblock;
Interval ivalid;
//
static IParamMap *pmapParam1;
static IParamMap *pmapParam2;
static IParamMap *pmapParam3;
static SequenceObject *editOb;
SequenceObject();
~SequenceObject();
// inherited virtual methods for Reference-management
RefResult NotifyRefChanged( Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message );
// From BaseObject
void BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev);
void EndEditParams( IObjParam *ip, ULONG flags,Animatable *next);
RefTargetHandle Clone(RemapDir& remap = NoRemap());
// From Object
virtual TCHAR *GetObjectName() { return _T("Sequence II"); }
void InitNodeName(TSTR& s);
Interval ObjectValidity(TimeValue t);
// unimplemented methods from Object class:
// ObjectState Eval(TimeValue time);
// ObjectHandle ApplyTransform(Matrix3& matrix) {return this;}
// Interval ObjectValidity(TimeValue t) {return FOREVER;}
// S32 CanConvertToType(Class_ID obtype) {return FALSE;}
// Object* ConvertToType(TimeValue t, Class_ID obtype) {assert(0);return NULL;}
// void GetWorldBoundBox(TimeValue t, INode *mat, ViewExp *vpt, Box3& box );
// void GetLocalBoundBox(TimeValue t, INode *mat, ViewExp *vpt, Box3& box );
// S32 DoOwnSelectHilite() { return 1; }
// Animatable methods
void FreeCaches();
S32 NumSubs() { return 1; }
Animatable* SubAnim(S32 i) { return pblock; }
TSTR SubAnimName(S32 i);
void DeleteThis() { delete this; }
Class_ID ClassID() { return SEQUENCE_CLASS_ID; }
void GetClassName(TSTR& s);
// S32 IsKeyable(){ return 0;}
// From ref
S32 NumRefs() {return 1;}
RefTargetHandle GetReference(S32 i) {return pblock;}
void SetReference(S32 i, RefTargetHandle rtarg) {pblock=(IParamBlock*)rtarg;}
IOResult Load(ILoad *iload);
//IOResult Save(ISave *isave);
//RefTargetHandle Clone(RemapDir& remap = NoRemap());
// where do these come from?
virtual void InvalidateUI();
IParamArray *GetParamBlock();
S32 GetParamBlockIndex(S32 id);
virtual ParamDimension *GetParameterDim(S32 pbIndex);
virtual TSTR GetParameterName(S32 pbIndex);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,461 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef SHAPEMIMIC_H_
#define SHAPEMIMIC_H_
#pragma pack(push,8)
#include <max.h>
#include <stdmat.h>
#include <decomp.h>
#pragma pack(pop)
#ifndef _TSSHAPE_H_
#include "ts/tsShape.h"
#endif
#ifndef _TVECTOR_H_
#include "core/tVector.h"
#endif
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
struct ExporterSequenceData;
struct SkinMimic
{
typedef Vector<F32> WeightList;
INode * skinNode;
TSSkinMesh * skinMesh;
S32 detailSize;
S32 skinNum;
S32 meshNum;
F32 multiResPercent;
Vector<TSDrawPrimitive> faces;
Vector<Point3> verts;
Vector<Point3F> normals;
Vector<Point3> tverts;
Vector<U16> indices;
Vector<U16> mergeIndices;
Vector<U32> smoothingGroups;
Vector<U32> vertId;
Vector<INode *> bones;
Vector<WeightList*> weights;
~SkinMimic() { for (S32 i=0;i<weights.size(); i++) delete weights[i]; }
};
struct IflMimic
{
char * fileName;
char * fullFileName;
S32 materialSlot;
~IflMimic() { dFree(fileName); dFree(fullFileName); }
};
struct MeshMimic
{
INode * pNode;
TSMesh * tsMesh;
SkinMimic * skinMimic;
bool billboard; // i.e., face camera
bool sortedObject;
S32 numVerts; // number of unique vertices
S32 meshNum;
Vector<U32> smoothingGroups;
Vector<U32> remap;
Vector<U32> vertId;
Matrix3 objectOffset; // NOTE: not valid till late in the game
F32 multiResPercent;
MeshMimic(INode * meshNode) { pNode = meshNode; skinMimic = NULL; tsMesh = NULL; }
};
struct MultiResMimic
{
INode * pNode;
INode * multiResNode;
S32 totalVerts;
// record off order of vertex merging (we'll figure out tverts later)
Vector<Point3F> mergeFrom;
Vector<Point3F> mergeTo;
MultiResMimic(INode * pn, INode * mrn) { pNode = pn; multiResNode = mrn; }
};
struct ObjectMimic
{
enum { MaxDetails=20 };
struct Detail
{
S32 size;
MeshMimic * mesh;
};
// my object has a name...I'm Jimmy.
const char * name;
const 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
Vector<S32> * pValidDetails;
INode * inTreeNode; // this is the node 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;
// all verts in the meshes get multiplied by this matrix
// before being added to ts shape
Matrix3 objectOffset;
// The max node this object hangs on (i.e., the one in the shape not
// the loose objects that make up the detail levels).
INode * maxParent;
// Similar to above: the max node that corresponds to tsNode that will
// be our parent. Starts out the same as maxParent, but is revised
// as we prune unwanted nodes from the tree structure.
INode * maxTSParent;
// ts node index we hang off
S32 tsNodeIndex;
S32 tsObjectIndex;
// This is the eventual payoff
TSObject * tsObject;
//
bool isBone;
bool isSkin;
~ObjectMimic()
{
dFree((char*)name);
dFree((char*)fullName);
for (S32 i=0;i<numDetails;i++)
delete details[i].mesh;
}
};
struct DecalMeshMimic
{
MeshMimic * targetMesh;
TSDecalMesh * tsMesh;
DecalMeshMimic(MeshMimic * target) { targetMesh = target; tsMesh = NULL; }
};
struct DecalObjectMimic
{
enum { MaxDetails=20 };
struct Detail
{
DecalMeshMimic * decalMesh;
};
// each object has several meshes attached
S32 numDetails;
Detail details[MaxDetails];
// The next two items are used for sorting decal objects.
// See ObjectMimic for more info.
S32 subtreeNum;
U32 priority;
// The object used to map the decal onto the object
INode * decalNode;
// This is the object we decal
ObjectMimic * targetObject;
// This is the eventual payoff
TSDecal * tsDecal;
~DecalObjectMimic()
{
for (S32 i=0;i<numDetails;i++)
delete details[i].decalMesh;
}
};
struct NodeMimic
{
// our twin in the max world:
INode * maxNode;
// 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
Vector<ObjectMimic*> objects;
};
struct CropInfo
{
bool hasTVerts;
Matrix3 uvTransform;
bool uWrap;
bool vWrap;
bool crop;
bool place;
F32 uOffset;
F32 vOffset;
F32 uWidth;
F32 vHeight;
// only valid if crop==true
bool cropLeft;
bool cropRight;
bool cropTop;
bool cropBottom;
bool twoSided;
};
class ShapeMimic
{
friend class SceneEnumProc;
struct Subtree
{
Vector<S32> validDetails;
Vector<const char*> detailNames;
Vector<INode*> detailNodes;
NodeMimic start;
};
Vector<Subtree*> subtrees;
Vector<ObjectMimic*> objectList;
Vector<DecalObjectMimic*> decalObjectList;
Vector<SkinMimic*> skins;
Vector<MultiResMimic*> multiResList;
Vector<IflMimic*> iflList;
Vector<INode*> sequences;
Vector<char*> materials;
Vector<U32> materialFlags;
Vector<U32> materialReflectionMaps;
Vector<U32> materialBumpMaps;
Vector<U32> materialDetailMaps;
Vector<F32> materialDetailScales;
Vector<F32> materialEmapAmounts;
INode * 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
Vector<NodeMimic*> nodes;
// error control
char * errorStr;
void setExportError(const char * str);
// called by generateShape
void generateBounds(TSShape * pShape);
void generateDetails(TSShape * pShape);
void generateSubtrees(TSShape * pShape);
void generateObjects(TSShape * pShape);
void generateDecals(TSShape * pShape);
void generateDefaultStates(TSShape * pShape);
void generateIflMaterials(TSShape * pShape);
void generateSequences(TSShape * pShape);
void generateMaterialList(TSShape * pShape);
void generateSkins(TSShape * pShape);
void optimizeMeshes(TSShape * pShape);
void convertSortObjects(TSShape * pShape);
void generateObjectState(ObjectMimic*,S32 time,TSShape *, bool addFrame, bool addMatFrame);
void generateDecalState(DecalObjectMimic*,S32 time,TSShape *, bool multipleFrames);
void generateFrame(ObjectMimic*,S32 time, bool addFrame, bool addMatFrame);
void generateFaces(INode * meshNode, Mesh & maxMesh, Matrix3 & objectOffset,
Vector<TSDrawPrimitive> & faces, Vector<Point3F> & normals,
Vector<Point3> & verts, Vector<Point3> & tverts, Vector<U16> & indices,
Vector<U32> & smooth, Vector<U32> * vertId = NULL);
S32 getMultiResVerts(INode * meshNode, F32 multiResPercent);
void generateNodeTransform(NodeMimic*,S32 time,TSShape *, bool blend, S32 blendReferenceTime, Quat16 & rot, Point3F & trans, Quat16 & srot, Point3F & scale);
void addNodeRotation(NodeMimic*,S32 time,TSShape *, bool blend, Quat16 & rot, bool defaultVal=false);
void addNodeTranslation(NodeMimic*,S32 time,TSShape *, bool blend, Point3F & trans, bool defaultVal=false);
void addNodeUniformScale(NodeMimic*,S32 time,TSShape *, bool blend, F32 scale);
void addNodeAlignedScale(NodeMimic*,S32 time,TSShape *, bool blend, Point3F & scale);
void addNodeArbitraryScale(NodeMimic*,S32 time,TSShape *, bool blend, Quat16 & srot, Point3F & scale);
void computeNormals(Vector<TSDrawPrimitive> &, Vector<U16> & indices, Vector<Point3F> & verts, Vector<Point3F> & norms, Vector<U32> & smooth, S32 vertsPerFrame, S32 numFrames, Vector<U16> * mergeIndices);
void computeNormals(Vector<TSDrawPrimitive> &, Vector<U16> & indices, Vector<Point3> & verts, Vector<Point3F> & norms, Vector<U32> & smooth, S32 vertsPerFrame, S32 numFrames);
void generateNodeAnimation(TSShape * pShape, Interval & range, ExporterSequenceData &);
void generateObjectAnimation(TSShape * pShape, Interval & range, ExporterSequenceData &);
void generateDecalAnimation(TSShape * pShape, Interval & range, ExporterSequenceData &);
void generateGroundAnimation(TSShape * pShape, Interval & range, ExporterSequenceData &);
void generateFrameTriggers(TSShape *, Interval &, ExporterSequenceData &, IParamBlock *);
void addTriggersInOrder(IKeyControl *, F32 duration, TSShape *, U32 & offTriggers);
void setNodeMembership(TSShape *, Interval & range, ExporterSequenceData &, S32 &, S32 &, S32 &, S32 &, S32 &);
S32 setObjectMembership(TSShape::Sequence &, Interval & range, ExporterSequenceData &);
S32 setDecalMembership(TSShape::Sequence &, Interval & range, ExporterSequenceData &);
S32 setIflMembership(TSShape::Sequence &, Interval & range, ExporterSequenceData &);
S32 setRotationMembership(TSShape *, TSSequence &, ExporterSequenceData &, S32 numFrames);
S32 setTranslationMembership(TSShape *, TSSequence &, ExporterSequenceData &, S32 numFrames);
S32 setUniformScaleMembership(TSShape *, TSSequence &, ExporterSequenceData &, S32 numFrames);
S32 setAlignedScaleMembership(TSShape *, TSSequence &, ExporterSequenceData &, S32 numFrames);
S32 setArbitraryScaleMembership(TSShape *, TSSequence &, ExporterSequenceData &, S32 numFrames);
bool animatesAlignedScale(ExporterSequenceData &, S32 numFrames);
bool animatesArbitraryScale(ExporterSequenceData &, S32 numFrames);
void setObjectPriorities(Vector<ObjectMimic*> &);
void setDecalObjectPriorities(Vector<DecalObjectMimic*> &);
bool testCutNodes(Interval & range, ExporterSequenceData &);
// methods used to optimize meshes
void collapseVertices(TSMesh*, Vector<U32> & smooth, Vector<U32> & remap, Vector<U32> * vertId = NULL);
void shareVerts(ObjectMimic *, S32 dl, TSShape *);
void shareVerts(SkinMimic *, Vector<U32> & originalRemap, TSShape *);
void shareBones(SkinMimic *, TSShape *);
bool vertexSame(Point3F &, Point3F &, Point2F &, Point2F &, U32 smooth1, U32 smooth2, U32 idx1, U32 idx2, Vector<U32> * vertId);
void stripify(Vector<TSDrawPrimitive> &, Vector<U16> & indices);
// add a name to the shape and return the index
S32 addName(const char *, TSShape *);
// adds a mesh node to the mesh list and returns the mesh it hangs off
ObjectMimic * getObject(INode *, char * name, S32 size, S32 * detailNum, F32 multiResPercent = -1.0f, bool matchFullName = true, bool isBone=false, bool isSkin=false);
ObjectMimic * addObject(INode *, Vector<S32> *pValidDetails);
ObjectMimic * addObject(INode *, Vector<S32> *pValidDetails, bool multiRes, S32 multiResSize = -1, F32 multiResPercent = -1.0f);
ObjectMimic * addBoneObject(INode * bone, S32 subtreeNum);
MeshMimic * addSkinObject(SkinMimic * skinMimic);
void addDecalObject(INode *, ObjectMimic *);
// functions for adding decals
bool decalOn(DecalObjectMimic*,S32 time);
void interpolateTVert(Point3F v0, Point3F v1, Point3F v2, Point3F planeNormal, Point3F & p, Point3 tv0, Point3 tv1, Point3 tv2, Point3 & tv);
S32 generateDecalFrame(DecalObjectMimic*,S32 time);
void findDecalTexGen(MatrixF &, Point4F &, Point4F &);
S32 findLastDecalFrameNumber(DecalObjectMimic*);
bool prepareDecal(INode * decalNode, S32 time);
void generateDecalFrame(DecalObjectMimic*, S32 time, S32 dl);
bool getDecalTVert(U32 decalType, Point3 vert, Point3F normal, Point3 & tv);
bool getPlaneDecalTVSpecial(Point3 & vert, const Point3F & normal, Point3 & tv);
void findNonOrthogonalComponents(const Point3F & v1, const Point3F & v2, const Point3F & p, F32 & t1, F32 & t2);
bool getDecalProjPoint(U32 decalType, Point3 vert, Point3F & normal, U32 decalFaceIdx, Point3F & p);
bool checkDecalFilter(Point3 v0, Point3 v1, Point3 v2);
bool checkDecalFace(Point3 tv0, Point3 tv1, Point3 tv2);
// utility function for traversing tree in depth first order
// returns NULL when we get back to the top
NodeMimic * findNextNode(NodeMimic * cur);
// utility function called by collapseTransform removes
// the node from the mimic tree structure, taking care
// to otherwise maintain the integrity of the shape tree
void snip(NodeMimic *);
// should we cut this node?
bool cut(NodeMimic *);
// is this node on the never animate list?
bool neverAnimateNode(NodeMimic *);
void splitFaceX(TSDrawPrimitive & face, TSDrawPrimitive & faceA, TSDrawPrimitive & faceB,
Vector<Point3> & verts, Vector<Point3> & tverts, Vector<U16> & indices,
Vector<bool> & flipX, Vector<bool> & flipY,
F32 splitAt,
Vector<U32> & smooth, Vector<U32> * vertId);
void splitFaceY(TSDrawPrimitive & face, TSDrawPrimitive & faceA, TSDrawPrimitive & faceB,
Vector<Point3> & verts, Vector<Point3> & tverts, Vector<U16> & indices,
Vector<bool> & flipX, Vector<bool> & flipY,
F32 splitAt,
Vector<U32> & smooth, Vector<U32> * vertId);
void handleCropAndPlace(Point3 &, CropInfo &);
public:
ShapeMimic();
~ShapeMimic();
// check for errors
bool isError();
const char * getError();
//
void setGlobals(INode * pNode, S32 polyCount, F32 minVolPerPoly, F32 maxVolPerPoly);
void recordMergeOrder(IParamBlock *, MultiResMimic *);
void collapseEdge(Vector<Face> & faces, S32 fromA, S32 toB);
void getMultiResData(INode * pNode, Vector<S32> & multiResSize, Vector<F32> & multiResPercent);
void addMultiRes(INode * pNode, INode * multiResNode);
MultiResMimic * getMultiRes(INode * pNode);
void remapWeights(Vector<SkinMimic::WeightList*> &, INode * skinNode, INode * multiResNode);
void copyWeightsToVerts(SkinMimic *);
void fixupT2AutoDetail();
void applyAutoDetail(Vector<S32> &, Vector<const char*> &, Vector<INode*> &);
// find which vertices merge with which vertices
void findMergeIndices(MeshMimic *, Matrix3 & objectOffset, const Vector<TSDrawPrimitive> &,
Vector<Point3F> &, Vector<Point3F> &, Vector<Point2F> &,
const Vector<U16> & indices, Vector<U16> & mergeIndices,
Vector<U32> & smooth, Vector<U32> & vertId, S32 numChildVerts);
// very specialized function used by above
void addMergeTargetAndMerge(Vector<TSDrawPrimitive> & faces, S32 & faceNum, S32 & v,
Vector<U16> & indices, Vector<U16> & mergeIndices,
Vector<Point3F> & verts, Vector<Point2F> & tverts, Vector<Point3F> & norms,
Vector<U32> & smooth, Vector<U32> & vertId,
Vector<S32> & mergeOrder, Vector<S32> & mergeID, Vector<Point3F> & mergeTarget);
// called in optimizeMeshes
void fixupMergeIndices(TSShape *);
// called after adding first frame to non-skin objects
void generateMergeIndices(ObjectMimic*);
void testMerge(TSShape *, ObjectMimic *, S32 dl, S32 numChildVerts);
// parts added to mimic using these methods...order unimportant
void addBounds(INode * pNode);
void addSubtree(INode * pNode);
void addNode(NodeMimic *,INode *, Vector<S32> &,bool);
void addMesh(INode * pNode) { addObject(pNode,NULL); }
void addSkin(INode * pNode);
void addSkin(INode * pNode, S32 multiResSize, F32 multiResPercent);
void addSequence(INode * pNode);
S32 addMaterial(INode * pNode, S32 materialIndex, CropInfo *);
S32 findMaterial(const char * name, const char * fullName, U32 flags, S32,S32,S32,F32 dscale = 1.0f,F32 emapAmount=1.0f); // finds, and adds if not there
void appendMaterialList(const char * name, U32 flags, S32,S32,S32,F32 dscale = 1.0f,F32 emapAmount=1.0f); // adds to the end
const char * getBaseTextureName(const char *);
// can optionally get rid of nodes with no mesh
void collapseTransforms();
void clearCollapseTransforms();
F32 findMaxDistance(TSMesh * loMesh, TSMesh * hiMesh, F32 & total, S32 & count);
// the payoff...call after adding all of the above
TSShape * generateShape();
void initShape(TSShape*);
void destroyShape(TSShape*);
};
#endif

View File

@ -0,0 +1,657 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#pragma pack(push,8)
#include <MAX.H>
#include <istdplug.h>
#include <utilapi.h>
#pragma pack(pop)
#include "max2dtsExporter/SceneEnum.h"
#include "max2dtsExporter/maxUtil.h"
#include "Platform/platform.h"
#include "Platform/platformAssert.h"
#include "max2dtsExporter/exportUtil.h"
#include "max2dtsExporter/exporter.h"
extern HINSTANCE hInstance;
extern TCHAR *GetString(S32);
extern const char * GetVersionString();
#define EditBoxesToo 0x80000000
class ExportUtil : public UtilityObj
{
public:
IUtil *iu;
Interface *ip;
HWND hPanel1;
HWND hPanel1b;
HWND hPanel2;
HWND hPanel3;
HWND hPanel4;
HWND hPanel5;
//Constructor/Destructor
ExportUtil();
~ExportUtil();
void BeginEditParams(Interface *ip, IUtil *iu);
void EndEditParams(Interface *ip, IUtil *iu);
void DeleteThis() {}
void Init(HWND hWnd);
void Destroy(HWND hWnd);
void initializePanels(S32 mask = -1);
};
static ExportUtil exportUtil;
// This is the Class Descriptor for the U plug-in
class ExportUtilClassDesc:public ClassDesc
{
public:
S32 IsPublic() {return 1;}
void * Create(BOOL loading = FALSE) { loading; return &exportUtil;}
const TCHAR * ClassName() {return "DTS Exporter Utility";}
SClass_ID SuperClassID() {return UTILITY_CLASS_ID;}
Class_ID ClassID() {return ExportUtil_CLASS_ID;}
const TCHAR* Category() {return "Exporter Utility";}
void ResetClassParams (BOOL fileReset);
};
static ExportUtilClassDesc exportUtilDesc;
ClassDesc * GetExportUtilDesc() {return &exportUtilDesc;}
Interface * GetMaxInterface() { return exportUtil.ip; }
//TODO: Should implement this method to reset the plugin params when Max is reset
void ExportUtilClassDesc::ResetClassParams (BOOL fileReset)
{
}
#define MAX_FILENAME_LEN 128
char filenameBuffer[MAX_FILENAME_LEN];
void findFiles(const char * filePattern, Vector<char *> & matches)
{
WIN32_FIND_DATA findData;
HANDLE searchHandle = FindFirstFile(filePattern,&findData);
if (searchHandle != INVALID_HANDLE_VALUE)
{
matches.push_back(dStrdup(findData.cFileName));
while (FindNextFile(searchHandle,&findData))
matches.push_back(dStrdup(findData.cFileName));
}
}
void clearFindFiles(Vector<char*> & matches)
{
for (S32 i=0; i<matches.size(); i++)
dFree(matches[i]);
matches.clear();
}
void initOFN(OPENFILENAME & ofn, char * filter, char * ext, char * title, const char * dir)
{
memset(filenameBuffer,0,MAX_FILENAME_LEN);
memset(&ofn,0,sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = NULL;
ofn.hInstance = hInstance;
ofn.lpstrFilter = filter;
ofn.lpstrCustomFilter = NULL;
ofn.nFilterIndex = 1;
ofn.lpstrFile = filenameBuffer;
ofn.nMaxFile = MAX_FILENAME_LEN;
filenameBuffer[0] = '\0';
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = dir;
ofn.lpstrTitle = title;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_EXPLORER;
ofn.lpstrDefExt = ext;
}
static BOOL CALLBACK ExportUtilDlgProc1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
exportUtil.Init(hWnd);
break;
case WM_DESTROY:
exportUtil.Destroy(hWnd);
break;
case WM_COMMAND:
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
exportUtil.ip->RollupMouseMessage(hWnd,msg,wParam,lParam);
break;
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK RenumberDlgFunc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
break;
case WM_DESTROY:
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hWnd,-99);
break;
case IDOK:
char buffer[128];
if (GetDlgItemText(hWnd,IDC_EDIT,buffer,128)>0)
{
int newSize = dAtoi(buffer);
EndDialog(hWnd,newSize);
}
else
EndDialog(hWnd,-99);
break;
}
break;
}
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
break;
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK ExportUtilDlgProc1b(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
exportUtil.Init(hWnd);
break;
case WM_DESTROY:
exportUtil.Destroy(hWnd);
break;
case WM_COMMAND:
{
OPENFILENAME ofn;
switch(LOWORD(wParam))
{
case IDC_EXPORT_WHOLE :
initOFN(ofn,"Torque 3Space Shape File (*.dts)\0*.dts\0","dts","Export DTS",exportUtil.ip->GetDir(APP_EXPORT_DIR));
if (GetSaveFileName(&ofn))
exportUtil.ip->ExportToFile(ofn.lpstrFile);
break;
case IDC_EXPORT_SEQUENCES :
initOFN(ofn,"Torque 3Space Sequence File (*.dsq)\0*.dsq\0","dsq","Export DSQ",exportUtil.ip->GetDir(APP_EXPORT_DIR));
if (GetSaveFileName(&ofn))
exportUtil.ip->ExportToFile(ofn.lpstrFile);
break;
case IDC_EXPORT_TEXT:
initOFN(ofn,"Torque 3Space Scene Text Export (*.txt)\0*.txt\0","txt","Scene Text Export",exportUtil.ip->GetDir(APP_EXPORT_DIR));
if (GetSaveFileName(&ofn))
exportUtil.ip->ExportToFile(ofn.lpstrFile);
break;
case IDC_RENUMBER:
{
S32 newNumber = DialogBox(hInstance,MAKEINTRESOURCE(IDD_RENUMBER),hWnd,RenumberDlgFunc);
if (newNumber >=0 && exportUtil.ip)
renumberNodes(exportUtil.ip,newNumber);
break;
}
case IDC_REGISTER_DETAILS:
registerDetails(exportUtil.ip);
break;
case IDC_EMBED:
embedSubtree(exportUtil.ip);
break;
}
break;
}
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
exportUtil.ip->RollupMouseMessage(hWnd,msg,wParam,lParam);
break;
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK ExportUtilDlgProc2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
exportUtil.Init(hWnd);
break;
case WM_DESTROY:
exportUtil.Destroy(hWnd);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_COLLAPSE : transformCollapse = !transformCollapse; break;
case IDC_ENABLE_SEQUENCES : enableSequences = !enableSequences; break;
case IDC_ENABLE_TWO_SIDED : enableTwoSidedMaterials = !enableTwoSidedMaterials; break;
case IDC_ANIMATION_DELTA:
if (HIWORD(wParam)==EN_CHANGE)
{
ICustEdit * edit = GetICustEdit( GetDlgItem(exportUtil.hPanel2,IDC_ANIMATION_DELTA) );
if (!edit->GotReturn())
return TRUE;
F32 tmp = edit->GetFloat();
if (tmp > 10E-12f)
animationDelta = tmp;
ReleaseICustEdit(edit);
exportUtil.initializePanels(2 + EditBoxesToo);
}
break;
case IDC_BASE_TEXTURE_PATH:
if (HIWORD(wParam)==EN_CHANGE)
{
ICustEdit * edit = GetICustEdit( GetDlgItem(exportUtil.hPanel2,IDC_BASE_TEXTURE_PATH) );
if (!edit->GotReturn())
return TRUE;
char buffer[256];
edit->GetText(buffer,sizeof(buffer));
setBaseTexturePath(buffer);
ReleaseICustEdit(edit);
exportUtil.initializePanels(2 + EditBoxesToo);
}
break;
default : break;
}
exportUtil.initializePanels(2);
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
exportUtil.ip->RollupMouseMessage(hWnd,msg,wParam,lParam);
break;
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK ExportUtilDlgProc3(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
exportUtil.Init(hWnd);
break;
case WM_DESTROY:
exportUtil.Destroy(hWnd);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_ALLOW_EMPTY : allowEmptySubtrees = !allowEmptySubtrees; break;
case IDC_ALLOW_CROSSED : allowCrossedDetails = !allowCrossedDetails; break;
case IDC_ALLOW_UNUSED : allowUnusedMeshes = !allowUnusedMeshes; break;
case IDC_ALLOW_OLD : allowOldSequences = !allowOldSequences; break;
case IDC_REQUIRE_VICON : viconNeeded = !viconNeeded; break;
}
exportUtil.initializePanels(4);
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
exportUtil.ip->RollupMouseMessage(hWnd,msg,wParam,lParam);
break;
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK ExportUtilDlgProc4(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
exportUtil.Init(hWnd);
break;
case WM_DESTROY:
exportUtil.Destroy(hWnd);
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDC_PASS1 : dumpMask ^= PDPass1; break;
case IDC_PASS2 : dumpMask ^= PDPass2; break;
case IDC_PASS3 : dumpMask ^= PDPass3; break;
case IDC_NODE_STATES : dumpMask ^= PDNodeStates; break;
case IDC_OBJECT_STATES : dumpMask ^= PDObjectStates; break;
case IDC_NODE_STATE_DETAILS : dumpMask ^= PDNodeStateDetails; break;
case IDC_OBJECT_STATE_DETAILS : dumpMask ^= PDObjectStateDetails; break;
case IDC_OBJECT_OFFSETS : dumpMask ^= PDObjectOffsets; break;
case IDC_SEQUENCE_DETAILS : dumpMask ^= PDSequences; break;
case IDC_SHAPE_HIERARCHY : dumpMask ^= PDShapeHierarchy; break;
}
exportUtil.initializePanels(8);
break;
}
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
exportUtil.ip->RollupMouseMessage(hWnd,msg,wParam,lParam);
break;
default:
return FALSE;
}
return TRUE;
}
// ok,ok, so this should probably be in a header somewhere...so sue me
extern char globalConfig[270];
static BOOL CALLBACK ExportUtilDlgProc5(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
exportUtil.Init(hWnd);
break;
case WM_DESTROY:
exportUtil.Destroy(hWnd);
break;
case WM_COMMAND:
{
OPENFILENAME ofn;
switch(LOWORD(wParam))
{
case IDC_CONFIG_LOAD_DEFAULT :
SceneEnumProc::readConfigFile(globalConfig);
break;
case IDC_CONFIG_SAVE_DEFAULT :
SceneEnumProc::writeConfigFile(globalConfig);
break;
case IDC_CONFIG_LOAD :
initOFN(ofn,"Exporter Configuration File (*.cfg)\0*.cfg\0","cfg","Load Configuration File",NULL);
if (GetOpenFileName(&ofn))
SceneEnumProc::readConfigFile(ofn.lpstrFile);
break;
case IDC_CONFIG_SAVE :
initOFN(ofn,"Exporter Configuration File (*.cfg)\0*.cfg\0","dsq","Save Configuration File",NULL);
if (GetSaveFileName(&ofn))
SceneEnumProc::writeConfigFile(ofn.lpstrFile);
break;
}
exportUtil.initializePanels();
break;
}
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
exportUtil.ip->RollupMouseMessage(hWnd,msg,wParam,lParam);
break;
default:
return FALSE;
}
return TRUE;
}
ExportUtil::ExportUtil()
{
iu = NULL;
ip = NULL;
hPanel1 = NULL;
hPanel1b = NULL;
hPanel2 = NULL;
hPanel3 = NULL;
hPanel4 = NULL;
hPanel5 = NULL;
}
ExportUtil::~ExportUtil()
{
}
void ExportUtil::BeginEditParams(Interface *ip, IUtil *iu)
{
this->iu = iu;
this->ip = ip;
hPanel1 = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_UTIL_PANEL1),
ExportUtilDlgProc1,
"About",
0,
APPENDROLL_CLOSED);
hPanel1b = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_UTIL_PANEL1B),
ExportUtilDlgProc1b,
"Utilities",
0);
hPanel2 = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_UTIL_PANEL2),
ExportUtilDlgProc2,
"Parameters",
0,
APPENDROLL_CLOSED);
hPanel3 = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_UTIL_PANEL3),
ExportUtilDlgProc3,
"Error Control",
0,
APPENDROLL_CLOSED);
hPanel4 = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_UTIL_PANEL4),
ExportUtilDlgProc4,
"Dump File Control",
0,
APPENDROLL_CLOSED);
hPanel5 = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_UTIL_PANEL5),
ExportUtilDlgProc5,
"Configuration Control",
0,
APPENDROLL_CLOSED);
initializePanels();
}
void ExportUtil::EndEditParams(Interface *ip, IUtil *iu)
{
this->iu = NULL;
this->ip = NULL;
ip->DeleteRollupPage(hPanel1);
hPanel1 = NULL;
ip->DeleteRollupPage(hPanel1b);
hPanel1b = NULL;
ip->DeleteRollupPage(hPanel2);
hPanel2 = NULL;
ip->DeleteRollupPage(hPanel3);
hPanel3 = NULL;
ip->DeleteRollupPage(hPanel4);
hPanel4 = NULL;
ip->DeleteRollupPage(hPanel5);
hPanel5 = NULL;
}
void ExportUtil::Init(HWND hWnd)
{
}
void ExportUtil::Destroy(HWND hWnd)
{
}
void ExportUtil::initializePanels(S32 mask)
{
ICustButton * button;
ICustEdit * edit;
char buffer[255];
// Panel 1 -- about panel
if (mask & 1)
{
// add text to about panel
dStrcpy(buffer,avar("Torque DTS Exporter\n%s\nCompiled %s\n%s",GetVersionString(),__DATE__,__TIME__));
SetDlgItemText(hPanel1,IDC_STATIC_ABOUT,buffer);
}
// Panel 2 -- Parameters
if (mask&2)
{
CheckDlgButton(hPanel2,IDC_COLLAPSE,transformCollapse);
CheckDlgButton(hPanel2,IDC_ENABLE_SEQUENCES,enableSequences);
CheckDlgButton(hPanel2,IDC_ENABLE_TWO_SIDED,enableTwoSidedMaterials);
if (mask & EditBoxesToo)
{
edit = GetICustEdit(GetDlgItem(hPanel2,IDC_ANIMATION_DELTA));
dStrcpy(buffer,avar("%f",animationDelta));
if (edit) // may already be locked
{
edit->SetText( buffer );
edit->WantReturn(true);
ReleaseICustEdit(edit);
}
edit = GetICustEdit(GetDlgItem(hPanel2,IDC_BASE_TEXTURE_PATH));
dStrcpy(buffer,baseTexturePath);
if (edit)
{
edit->SetText( buffer );
edit->WantReturn(true);
ReleaseICustEdit(edit);
}
}
}
// Panel 3 -- Error Control
if (mask & 4)
{
CheckDlgButton(hPanel3,IDC_ALLOW_EMPTY,allowEmptySubtrees);
CheckDlgButton(hPanel3,IDC_ALLOW_CROSSED,allowCrossedDetails);
CheckDlgButton(hPanel3,IDC_ALLOW_UNUSED,allowUnusedMeshes);
CheckDlgButton(hPanel3,IDC_ALLOW_OLD,allowOldSequences);
CheckDlgButton(hPanel3,IDC_REQUIRE_VICON,viconNeeded);
}
// Panel 4 -- Dump file control
if (mask & 8)
{
CheckDlgButton(hPanel4,IDC_PASS1,dumpMask & PDPass1);
CheckDlgButton(hPanel4,IDC_PASS2,dumpMask & PDPass2);
CheckDlgButton(hPanel4,IDC_PASS3,dumpMask & PDPass3);
CheckDlgButton(hPanel4,IDC_NODE_STATES,dumpMask & PDNodeStates);
CheckDlgButton(hPanel4,IDC_OBJECT_STATES,dumpMask & PDObjectStates);
CheckDlgButton(hPanel4,IDC_NODE_STATE_DETAILS,dumpMask & PDNodeStateDetails);
CheckDlgButton(hPanel4,IDC_OBJECT_STATE_DETAILS,dumpMask & PDObjectStateDetails);
CheckDlgButton(hPanel4,IDC_OBJECT_OFFSETS,dumpMask & PDObjectOffsets);
CheckDlgButton(hPanel4,IDC_SEQUENCE_DETAILS,dumpMask & PDSequences);
CheckDlgButton(hPanel4,IDC_SHAPE_HIERARCHY,dumpMask & PDShapeHierarchy);
}
// Panel 5 -- Configuration control
if (mask & 16)
{
// make buttons push buttons rather than check buttons...
button = GetICustButton(GetDlgItem(hPanel5,IDC_CONFIG_LOAD_DEFAULT));
button->SetType(CBT_PUSH);
ReleaseICustButton(button);
button = GetICustButton(GetDlgItem(hPanel5,IDC_CONFIG_SAVE_DEFAULT));
button->SetType(CBT_PUSH);
ReleaseICustButton(button);
button = GetICustButton(GetDlgItem(hPanel5,IDC_CONFIG_LOAD));
button->SetType(CBT_PUSH);
ReleaseICustButton(button);
button = GetICustButton(GetDlgItem(hPanel5,IDC_CONFIG_SAVE));
button->SetType(CBT_PUSH);
ReleaseICustButton(button);
}
// Panel 1b -- Utility panel
if (mask & 32)
{
// make buttons push buttons rather than check buttons...
button = GetICustButton(GetDlgItem(hPanel1b,IDC_EXPORT_WHOLE));
button->SetType(CBT_PUSH);
ReleaseICustButton(button);
button = GetICustButton(GetDlgItem(hPanel1b,IDC_EXPORT_SEQUENCES));
button->SetType(CBT_PUSH);
ReleaseICustButton(button);
button = GetICustButton(GetDlgItem(hPanel1b,IDC_EXPORT_TEXT));
button->SetType(CBT_PUSH);
ReleaseICustButton(button);
button = GetICustButton(GetDlgItem(hPanel1b,IDC_RENUMBER));
button->SetType(CBT_PUSH);
ReleaseICustButton(button);
button = GetICustButton(GetDlgItem(hPanel1b,IDC_EMBED));
button->SetType(CBT_PUSH);
ReleaseICustButton(button);
button = GetICustButton(GetDlgItem(hPanel1b,IDC_REGISTER_DETAILS));
button->SetType(CBT_PUSH);
ReleaseICustButton(button);
}
}

View File

@ -0,0 +1,17 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _EXPORT_UTIL_H_
#define _EXPORT_UTIL_H_
#pragma pack(push,8)
#include <MAX.H>
#pragma pack(pop)
#define ExportUtil_CLASS_ID Class_ID(0x5959933e, 0x7673c15a)
extern ClassDesc * GetExportUtilDesc();
extern Interface * GetMaxInterface();
#endif // _EXPORT_UTIL_H_

View File

@ -0,0 +1,7 @@
EXPORTS
LibDescription @1
LibNumberClasses @2
LibClassDesc @3
LibVersion @4
SECTIONS
.data READ WRITE

114
tools/max2dtsExporter/exporter.h Executable file
View File

@ -0,0 +1,114 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#define IDD_DTSEXP_UI 101
#define IDD_SEQUENCE_PARAMS 102
#define IDD_SEQUENCE_PARAMS2 103
#define IDD_SEQUENCE_PARAMS3 105
#define IDD_UTIL_PANEL1 106
#define IDD_UTIL_PANEL2 107
#define IDB_BITMAP1 107
#define IDD_UTIL_PANEL3 108
#define IDD_UTIL_PANEL4 109
#define IDD_UTIL_PANEL5 110
#define IDD_UTIL_PANEL1B 111
#define IDD_RENUMBER 112
#define IDD_SKINHELP_PANEL 113
#define IDC_SEQ_CYCLIC 1001
#define IDC_SEQ_BLEND 1002
#define IDC_SEQ_LAST_FIRST_FRAME_SAME 1003
#define IDC_SEQ_USE_FRAME_RATE 1004
#define IDC_SEQ_FRAME_RATE 1005
#define IDC_SEQ_NUM_FRAMES 1006
#define IDC_SEQ_IGNORE_GROUND_TRANSFORM 1007
#define IDC_SEQ_USE_N_FRAMES 1007
#define IDC_SEQ_USE_GROUND_FRAME_RATE 1008
#define IDC_SEQ_PRIORITY 1008
#define IDC_SEQ_GROUND_FRAME_RATE 1009
#define IDC_SEQ_DURATION_OVERRIDE 1009
#define IDC_SEQ_GROUND_FRAME_RATE_SPINNER 1010
#define IDC_SEQ_DURATION 1010
#define IDC_SEQ_NUM_GROUND_FRAMES 1011
#define IDC_SEQ_NUM_GROUND_FRAMES_SPINNER 1012
#define IDC_SEQ_FRAME_RATE_SPINNER 1013
#define IDC_SEQ_NUM_FRAMES_SPINNER 1014
#define IDC_SEQ_PRIORITY_SPINNER 1015
#define IDC_SEQ_DURATION_SPINNER 1016
#define IDC_SEQ_ENABLE_MORPH_ANIMATION 1017
#define IDC_SEQ_ENABLE_VIS_ANIMATION 1018
#define IDC_SEQ_ENABLE_TRANSFORM_ANIMATION 1019
#define IDC_SEQ_USE_N_GROUND_FRAMES 1020
#define IDC_SEQ_ENABLE_TEXTURE_ANIMATION 1020
#define IDC_SEQ_ENABLE_IFL_ANIMATION 1021
#define IDC_SEQ_ENABLE_DECAL_ANIMATION 1022
#define IDC_SEQ_FORCE_MORPH_ANIMATION 1023
#define IDC_SEQ_FORCE_VIS_ANIMATION 1024
#define IDC_SEQ_FORCE_TRANSFORM_ANIMATION 1025
#define IDC_STATIC_ABOUT 1025
#define IDC_EXPORT_WHOLE 1026
#define IDC_SEQ_FORCE_TEXTURE_ANIMATION 1026
#define IDC_EXPORT_SEQUENCES 1027
#define IDC_CONFIG_SAVE_DEFAULT 1027
#define IDC_SEQ_ENABLE_DECAL_FRAME_ANIMATION 1027
#define IDC_EXPORT_TEXT 1028
#define IDC_ANIMATION_DELTA 1028
#define IDC_CONFIG_LOAD 1028
#define IDC_SEQ_FORCE_DECAL_ANIMATION 1028
#define IDC_ALLOW_EMPTY 1029
#define IDC_CONFIG_SAVE 1029
#define IDC_RENUMBER 1029
#define IDC_BASE_TEXTURE_PATH 1029
#define IDC_SEQ_ENABLE_UNIFORM_SCALE_ANIMATION 1029
#define IDC_ALLOW_CROSSED 1030
#define IDC_COLLAPSE 1030
#define IDC_EMBED 1030
#define IDC_SEQ_ENABLE_ARBITRARY_SCALE_ANIMATION 1030
#define IDC_ALLOW_UNUSED 1031
#define IDC_ENABLE_SEQUENCES 1031
#define IDC_REGISTER_DETAILS 1031
#define IDC_SEQ_FORCE_SCALE_ANIMATION 1031
#define IDC_ALLOW_OLD 1032
#define IDC_REQUIRE_VICON 1033
#define IDC_NODE_STATE_DETAILS 1034
#define IDC_ENABLE_TWO_SIDED 1034
#define IDC_OBJECT_STATE_DETAILS 1035
#define IDC_OBJECT_OFFSETS 1036
#define IDC_SEQUENCE_DETAILS 1037
#define IDC_SHAPE_HIERARCHY 1038
#define IDC_PASS1 1039
#define IDC_PASS2 1040
#define IDC_PASS3 1041
#define IDC_NODE_STATES 1042
#define IDC_OBJECT_STATES 1043
#define IDC_CONFIG_LOAD_DEFAULT 1044
#define IDC_EDIT 1045
#define IDC_SPIN 1496
#define IDS_TH_3SPACE 40216
#define IDS_TH_DTSFILE_LONG 40220
#define IDS_TH_DTSFILE_SHORT 40221
#define IDS_TH_COPYRIGHT_COMPANY 40223
#define IDS_TH_DTSEXP 40229
#define IDS_TH_SHAPEEXPORT 40231
#define IDS_TH_DTSEXPORTDLL 40232
#define IDS_TH_NODATATOEXPORT 40233
#define IDS_TH_CANTCREATE 40234
#define IDS_TH_WRITEERROR 40235
#define IDS_OBJ_TOO_LARGE 40236
#define IDS_EXPORT_ERROR 40237
#define IDS_TH_AUTHOR 40238
#define IDS_DB_SEQUENCE 40239
#define IDS_DB_GENERAL 40240
#define IDS_SKINHELP_PARAMS 40241
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 114
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1046
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

394
tools/max2dtsExporter/exporter.rc Executable file
View File

@ -0,0 +1,394 @@
//Microsoft Developer Studio generated resource script.
//
#include "exporter.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"exporter.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_SEQUENCE_PARAMS DIALOG DISCARDABLE 0, 0, 108, 185
STYLE WS_CHILD | WS_VISIBLE
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "",IDC_SEQ_CYCLIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
61,12,16,8
LTEXT "Cyclic sequence:",IDC_STATIC,3,12,55,8
LTEXT "Blend Sequence:",IDC_STATIC,3,45,56,8
CONTROL "",IDC_SEQ_BLEND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
61,46,11,8
LTEXT "Complete cycle:",IDC_STATIC,22,25,51,8
CONTROL "",IDC_SEQ_LAST_FIRST_FRAME_SAME,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,80,26,12,8
LTEXT "Use frame rate:",IDC_STATIC,3,67,49,8
CONTROL "",IDC_SEQ_FRAME_RATE,"CustEdit",WS_TABSTOP,28,80,27,10
CONTROL "",IDC_SEQ_NUM_FRAMES,"CustEdit",WS_TABSTOP,28,103,27,10
CONTROL "",IDC_SEQ_FRAME_RATE_SPINNER,"SpinnerControl",0x0,63,79,
6,11
CONTROL "",IDC_SEQ_NUM_FRAMES_SPINNER,"SpinnerControl",0x0,63,
102,6,11
CONTROL "",IDC_SEQ_USE_FRAME_RATE,"Button",BS_AUTORADIOBUTTON,61,
67,10,10
CONTROL "",IDC_SEQ_USE_N_FRAMES,"Button",BS_AUTORADIOBUTTON,61,
92,10,10
LTEXT "Use N frames:",IDC_STATIC,3,92,46,8
LTEXT "N=",IDC_STATIC,15,104,10,8
LTEXT "or,",IDC_STATIC,74,80,12,11
CONTROL "",IDC_SEQ_PRIORITY,"CustEdit",WS_TABSTOP,27,167,27,10
CONTROL "",IDC_SEQ_PRIORITY_SPINNER,"SpinnerControl",0x0,63,166,
6,11
LTEXT "Sequence priority:",IDC_STATIC,3,156,58,8
LTEXT "Override duration:",IDC_STATIC,4,123,57,8
CONTROL "",IDC_SEQ_DURATION_OVERRIDE,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,62,124,11,8
CONTROL "",IDC_SEQ_DURATION,"CustEdit",WS_TABSTOP,29,138,27,10
CONTROL "",IDC_SEQ_DURATION_SPINNER,"SpinnerControl",0x0,63,137,
6,11
END
IDD_SEQUENCE_PARAMS2 DIALOG DISCARDABLE 0, 0, 108, 103
STYLE WS_CHILD | WS_VISIBLE
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Ignore ground transform:",IDC_STATIC,3,13,78,8
CONTROL "",IDC_SEQ_IGNORE_GROUND_TRANSFORM,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,88,13,12,8
LTEXT "Use frame rate:",IDC_STATIC,3,37,49,8
CONTROL "",IDC_SEQ_GROUND_FRAME_RATE,"CustEdit",WS_TABSTOP,34,51,
22,10
CONTROL "",IDC_SEQ_NUM_GROUND_FRAMES,"CustEdit",WS_TABSTOP,36,77,
20,10
CONTROL "",IDC_SEQ_GROUND_FRAME_RATE_SPINNER,"SpinnerControl",
0x0,59,51,10,10
CONTROL "",IDC_SEQ_NUM_GROUND_FRAMES_SPINNER,"SpinnerControl",
0x0,60,77,8,10
CONTROL "",IDC_SEQ_USE_GROUND_FRAME_RATE,"Button",
BS_AUTORADIOBUTTON,58,38,16,8
CONTROL "",IDC_SEQ_USE_N_GROUND_FRAMES,"Button",
BS_AUTORADIOBUTTON,57,67,16,8
LTEXT "Use N frames:",IDC_STATIC,3,66,46,8
LTEXT "or,",IDC_STATIC,75,51,17,12
LTEXT "N=",IDC_STATIC,20,79,10,8
END
IDD_SEQUENCE_PARAMS3 DIALOG DISCARDABLE 0, 0, 109, 200
STYLE WS_CHILD | WS_VISIBLE
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "",IDC_SEQ_ENABLE_MORPH_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,18,16,8
CONTROL "",IDC_SEQ_ENABLE_VIS_ANIMATION,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,87,29,16,8
CONTROL "",IDC_SEQ_ENABLE_TRANSFORM_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,40,16,8
LTEXT "Enable:",IDC_STATIC,4,6,25,8
LTEXT "Morph animation:",IDC_STATIC,12,18,55,8
LTEXT "Visibility animation:",IDC_STATIC,12,29,59,8
LTEXT "Transform animation:",IDC_STATIC,12,40,66,8
CONTROL "",IDC_SEQ_FORCE_MORPH_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,130,16,8
CONTROL "",IDC_SEQ_FORCE_VIS_ANIMATION,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,87,141,16,8
CONTROL "",IDC_SEQ_FORCE_TRANSFORM_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,152,16,8
LTEXT "Force:",IDC_STATIC,4,119,21,8
LTEXT "Morph animation:",IDC_STATIC,12,130,55,8
LTEXT "Visibility animation:",IDC_STATIC,12,141,59,8
LTEXT "Transform animation:",IDC_STATIC,12,152,66,8
CONTROL "",IDC_SEQ_FORCE_TEXTURE_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,174,16,8
LTEXT "Texture animation:",IDC_STATIC,12,174,59,8
CONTROL "",IDC_SEQ_ENABLE_TEXTURE_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,73,16,8
LTEXT "Texture animation:",IDC_STATIC,12,73,59,8
CONTROL "",IDC_SEQ_ENABLE_IFL_ANIMATION,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,87,84,16,8
LTEXT "IFL animation:",IDC_STATIC,12,84,45,8
CONTROL "",IDC_SEQ_ENABLE_DECAL_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,95,16,8
LTEXT "Decal animation:",IDC_STATIC,12,95,54,8
CONTROL "",IDC_SEQ_ENABLE_DECAL_FRAME_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,106,16,8
LTEXT "Decal-frame animation:",IDC_STATIC,12,106,73,8
CONTROL "",IDC_SEQ_FORCE_DECAL_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,185,16,8
LTEXT "Decal animation:",IDC_STATIC,12,185,54,8
CONTROL "",IDC_SEQ_ENABLE_UNIFORM_SCALE_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,51,16,8
LTEXT "Uniform scale anim:",IDC_STATIC,12,51,62,8
CONTROL "",IDC_SEQ_ENABLE_ARBITRARY_SCALE_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,62,16,8
LTEXT "Arbitrary scale anim:",IDC_STATIC,12,62,64,8
CONTROL "",IDC_SEQ_FORCE_SCALE_ANIMATION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,87,163,16,8
LTEXT "Scale animation:",IDC_STATIC,12,163,53,8
END
IDD_UTIL_PANEL1 DIALOG DISCARDABLE 0, 0, 108, 51
STYLE WS_CHILD
FONT 8, "MS Sans Serif"
BEGIN
CTEXT "About text...",IDC_STATIC_ABOUT,11,2,88,40
END
IDD_UTIL_PANEL2 DIALOG DISCARDABLE 0, 0, 108, 91
STYLE WS_CHILD
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "",IDC_ANIMATION_DELTA,"CustEdit",WS_TABSTOP,57,50,48,9
LTEXT "Animation Delta:",IDC_STATIC,2,50,52,8
LTEXT "Collapse Transforms",IDC_STATIC,19,7,84,11
CONTROL "",IDC_COLLAPSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,
7,8,10
LTEXT "Enable Sequence Export",IDC_STATIC,19,21,84,11
CONTROL "",IDC_ENABLE_SEQUENCES,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,6,21,8,10
CONTROL "",IDC_ENABLE_TWO_SIDED,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,6,35,8,9
LTEXT "Enable 2-sided materials",IDC_STATIC,19,35,81,12
CONTROL "",IDC_BASE_TEXTURE_PATH,"CustEdit",WS_TABSTOP,9,77,91,9
LTEXT "Base Texture Path:",IDC_STATIC,2,66,62,8
END
IDD_UTIL_PANEL3 DIALOG DISCARDABLE 0, 0, 108, 96
STYLE WS_CHILD
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "",IDC_ALLOW_EMPTY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
5,11,8,9
LTEXT "Allow Empty Subtrees",IDC_STATIC,16,11,71,11
CONTROL "",IDC_ALLOW_CROSSED,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,5,29,8,9
LTEXT "Allow Crossed Details",IDC_STATIC,16,29,71,11
CONTROL "",IDC_ALLOW_UNUSED,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,5,46,8,9
LTEXT "Allow Unused Meshes",IDC_STATIC,16,46,71,11
CONTROL "",IDC_ALLOW_OLD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,
64,8,9
LTEXT "Allow Old Style Sequences",IDC_STATIC,16,64,85,12
CONTROL "",IDC_REQUIRE_VICON,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,5,80,8,9
LTEXT "Require VICON/BIP",IDC_STATIC,16,80,74,12
END
IDD_UTIL_PANEL4 DIALOG DISCARDABLE 0, 0, 108, 178
STYLE WS_CHILD
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "",IDC_PASS1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,11,
8,9
LTEXT "Initial Node Collection",IDC_STATIC,16,11,71,11
CONTROL "",IDC_PASS2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,27,
8,9
LTEXT "Initial Shape Construction",IDC_STATIC,16,27,85,11
CONTROL "",IDC_PASS3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,44,
8,9
LTEXT "Node Culling",IDC_STATIC,16,44,71,11
CONTROL "",IDC_NODE_STATES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
5,62,8,9
LTEXT "Node States",IDC_STATIC,16,62,85,12
CONTROL "",IDC_OBJECT_STATES,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,5,78,8,9
LTEXT "Object States",IDC_STATIC,16,78,74,12
CONTROL "",IDC_NODE_STATE_DETAILS,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,5,93,8,9
LTEXT "Node State Details",IDC_STATIC,16,93,71,11
CONTROL "",IDC_OBJECT_STATE_DETAILS,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,5,109,8,9
LTEXT "Object State Details",IDC_STATIC,16,109,85,11
CONTROL "",IDC_OBJECT_OFFSETS,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,5,126,8,9
LTEXT "Object Offsets",IDC_STATIC,16,126,71,11
CONTROL "",IDC_SEQUENCE_DETAILS,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,5,143,8,9
LTEXT "Sequences",IDC_STATIC,16,143,85,12
CONTROL "",IDC_SHAPE_HIERARCHY,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,5,159,8,9
LTEXT "Shape Hierarchy",IDC_STATIC,16,159,74,12
END
IDD_UTIL_PANEL5 DIALOG DISCARDABLE 0, 0, 107, 85
STYLE WS_CHILD
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "Load Default Config",IDC_CONFIG_LOAD_DEFAULT,"CustButton",
WS_TABSTOP,7,8,94,13
CONTROL "Save As Default Config",IDC_CONFIG_SAVE_DEFAULT,
"CustButton",WS_TABSTOP,7,27,94,13
CONTROL "Load Config...",IDC_CONFIG_LOAD,"CustButton",WS_TABSTOP,
7,46,94,13
CONTROL "Save Config...",IDC_CONFIG_SAVE,"CustButton",WS_TABSTOP,
7,65,94,13
END
IDD_UTIL_PANEL1B DIALOG DISCARDABLE 0, 0, 108, 123
STYLE WS_CHILD
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "Whole Shape",IDC_EXPORT_WHOLE,"CustButton",WS_TABSTOP,
14,16,80,11
CONTROL "Sequences",IDC_EXPORT_SEQUENCES,"CustButton",WS_TABSTOP,
14,31,80,11
CONTROL "Text Description",IDC_EXPORT_TEXT,"CustButton",
WS_TABSTOP,14,46,80,11
CONTROL " Export:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP |
WS_GROUP,4,4,28,11
LTEXT " General:",IDC_STATIC,4,63,30,10
CONTROL "Renumber selection...",IDC_RENUMBER,"CustButton",
WS_TABSTOP,14,75,80,11
CONTROL "Embed Shape",IDC_EMBED,"CustButton",WS_TABSTOP,14,91,80,
11
CONTROL "Register Details",IDC_REGISTER_DETAILS,"CustButton",
WS_TABSTOP,14,107,80,11
END
IDD_RENUMBER DIALOG DISCARDABLE 0, 0, 187, 55
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Renumber"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,130,7,50,14
PUSHBUTTON "Cancel",IDCANCEL,130,24,50,14
LTEXT "New number:",IDC_STATIC,7,14,53,12
EDITTEXT IDC_EDIT,56,13,67,14,ES_AUTOHSCROLL
END
IDD_SKINHELP_PANEL DIALOG DISCARDABLE 0, 0, 108, 156
STYLE WS_CHILD | WS_VISIBLE
FONT 8, "MS Sans Serif"
BEGIN
CTEXT "Generated by Plugin AppWizard\nCode && design by\nRavi Karra - Kinetix",
IDC_STATIC,7,7,94,36
CONTROL "",1490,"CustEdit",WS_TABSTOP,29,114,35,10
CONTROL "",IDC_SPIN,"SpinnerControl",0x0,65,114,7,10
LTEXT "Spinner Cust Control:",IDC_STATIC,20,102,67,8
CTEXT "TODO: Place panel controls here.",IDC_STATIC,15,63,78,
19
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_UTIL_PANEL2, DIALOG
BEGIN
RIGHTMARGIN, 107
END
IDD_RENUMBER, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 180
TOPMARGIN, 7
BOTTOMMARGIN, 48
END
IDD_SKINHELP_PANEL, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 101
TOPMARGIN, 7
BOTTOMMARGIN, 149
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDS_TH_3SPACE "3Space"
IDS_TH_DTSFILE_LONG "V12 3Space (DTS) File"
IDS_TH_DTSFILE_SHORT "V12 DTS File"
IDS_TH_COPYRIGHT_COMPANY "Copyright 2001 GarageGames.com"
END
STRINGTABLE DISCARDABLE
BEGIN
IDS_TH_DTSEXP "max2dtsExporter"
IDS_TH_SHAPEEXPORT "Shape Export"
IDS_TH_DTSEXPORTDLL "GarageGames V12 3Space DTS File Export DLL"
IDS_TH_NODATATOEXPORT "No data to export"
IDS_TH_CANTCREATE "Can't create output file"
IDS_TH_WRITEERROR "Write error on file"
IDS_OBJ_TOO_LARGE "Object %s is too large to export"
IDS_EXPORT_ERROR "Export Error"
IDS_TH_AUTHOR "Created by Clark Fagot"
IDS_DB_SEQUENCE "Sequence"
END
STRINGTABLE DISCARDABLE
BEGIN
IDS_DB_GENERAL "General DTS Objects"
IDS_SKINHELP_PARAMS "skin help params"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

648
tools/max2dtsExporter/main.cc Executable file
View File

@ -0,0 +1,648 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#pragma pack(push,8)
#include <MAX.H>
#pragma pack(pop)
// NOTE:
// if you have problems linking this exporter it is likely you are encountering a
// bug in Microsofts include\basetsd.h header.
//
// The problem is that Visual C++ defines INT_PTR to 'long' when it is
// supposed to be defined as an 'int' (on ia32 platforms). You can either
// use a supported build environment by updating to the platform SDK, or
// you can use the unsupported environment by manually fixing the problem
// in the header "On or around line 123 of include\basetsd.h change:
//
// typedef long INT_PTR, *PINT_PTR;
// typedef unsigned long UINT_PTR, *PUINT_PTR;
// TO
// typedef int INT_PTR, *PINT_PTR;
// typedef unsigned int UINT_PTR, *PUINT_PTR;
#include "max2dtsExporter/exporter.h"
#include "max2dtsExporter/sceneEnum.h"
#include "core/filestream.h"
#include "ts/tsShapeInstance.h"
#include "max2dtsExporter/sequence.h"
#include "max2dtsExporter/exportUtil.h"
#include "max2dtsExporter/skinHelper.h"
#define DLLEXPORT __declspec(dllexport)
#if defined(TORQUE_DEBUG)
const char * const gProgramVersion = "0.900d-beta";
#else
const char * const gProgramVersion = "0.900r-beta";
#endif
HINSTANCE hInstance;
S32 gSupressUI = 0;
TCHAR maxFile[1024];
S32 controlsInit = FALSE;
char dllPath[256];
char globalConfig[270];
TCHAR *GetString(S32 id)
{
static TCHAR buf[256];
if (hInstance)
{
return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : NULL;
}
return NULL;
}
const char * days[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
const char * months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
static S32 Alert(const char * s1, const char * s2, S32 option = MB_OK)
{
if (gSupressUI)
{
FileStream fs;
fs.open(avar("%smax2difExport.error.log",dllPath),FileStream::ReadWrite);
if (fs.getStatus() != Stream::Ok)
{
fs.close();
return -1;
}
fs.setPosition(fs.getStreamSize());
// what's the time and date?
Platform::LocalTime localTime;
Platform::getLocalTime(localTime);
char timeBuffer[256];
dStrcpy(timeBuffer,avar("%i:%i on %s %s %i",localTime.hour,localTime.min,days[localTime.weekday],months[localTime.month],localTime.monthday));
// write the error to the log file
char buffer[1024];
dStrcpy(buffer,avar("Error exporting file \"%s\" at %s:\r\n --> %s\r\n\r\n",maxFile,timeBuffer,s1));
fs.writeLine((unsigned char*) buffer);
fs.close();
return -1;
}
else
{
TSTR str1(s1);
TSTR str2(s2);
return MessageBox(GetActiveWindow(), str1, str2, option);
}
}
static S32 Alert(S32 s1, S32 s2 = IDS_TH_DTSEXP, S32 option = MB_OK)
{
return Alert(GetString(s1),GetString(s2),option);
}
static S32 Alert(const char * s1, S32 s2 = IDS_TH_DTSEXP, S32 option = MB_OK)
{
return Alert(s1,GetString(s2),option);
}
const char * GetVersionString()
{
static char versionString[128];
dStrcpy(versionString,avar("Version %s (dts v%i.%.2i)",gProgramVersion, DTS_EXPORTER_CURRENT_VERSION/100, DTS_EXPORTER_CURRENT_VERSION%100));
return versionString;
}
//------------------------------------------------------
// Our main plugin class:
class _Exporter : public SceneExport
{
char extension[10]; // 'DTS' or 'DSQ'
public:
_Exporter(const char *);
~_Exporter();
S32 ExtCount(); // Number of extensions supported
const TCHAR *Ext(S32); // Extension #n
const TCHAR *LongDesc(); // Long ASCII description
const TCHAR *ShortDesc(); // Short ASCII description
const TCHAR *AuthorName(); // ASCII Author name
const TCHAR *CopyrightMessage(); // ASCII Copyright message
const TCHAR *OtherMessage1(); // Other message #1
const TCHAR *OtherMessage2(); // Other message #2
U32 Version(); // Version number * 100
void ShowAbout(HWND); // Show DLL's "About..." box
S32 DoExport(const TCHAR *, ExpInterface *, Interface *, int, DWORD);
};
//------------------------------------------------------
// Jaguar interface code
extern void mInstallLibrary_C();
namespace Memory
{
extern bool gAlwaysLogLeaks;
};
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
{
hInstance = hinstDLL;
if (!controlsInit)
{
controlsInit = TRUE;
// 3DS custom controls
InitCustomControls(hInstance);
// Initialize common Windows controls
InitCommonControls();
// install math library (set up function pointers)
mInstallLibrary_C();
// set "factory" default parameter values
SceneEnumProc::setInitialDefaults();
// always log memory leaks -- some of them aren't really leaks,
// but we want to see them and we don't want the annoying box asking us
// about it...
Memory::gAlwaysLogLeaks = true;
// get DLL path
GetModuleFileName(hInstance,dllPath,sizeof(dllPath));
char * p = dStrrchr(dllPath,'\\');
char * p2 = dStrrchr(dllPath,':');
if (p && *p=='\\')
*(p+1) = '\0';
else if(p2 && *p2==':')
*(p2+1) = '\0';
else
dllPath[0] = '\0';
// load the global config file if we can find it
dStrcpy(globalConfig,dllPath);
dStrcpy(globalConfig+dStrlen(globalConfig),"dtsGlobal.cfg");
SceneEnumProc::readConfigFile(globalConfig);
}
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return(TRUE);
}
// defines for setting exporter type and description
#define _EXPORTER_CLASS_NAME "Torque Shape Exporter"
#define _DTS_EXPORTER_CLASS_ID Class_ID(0x296a4787, 0x2ec557fc)
#define _DSQ_EXPORTER_CLASS_ID Class_ID(0x65d74e76, 0x10da4a97)
#define _TXT_EXPORTER_CLASS_ID Class_ID(0x6bfb02d7, 0x13860666)
#define _EXPORTER_CLASS_SDESC "Torque Shape Exporter"
// more code for interfacing with max
class _DTSClassDesc : public ClassDesc
{
public:
S32 IsPublic() { return 1; }
void *Create(BOOL loading = FALSE) { return new _Exporter("DTS"); }
const TCHAR *ClassName() { return _EXPORTER_CLASS_NAME; }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID() { return _DTS_EXPORTER_CLASS_ID; }
const TCHAR *Category() { return GetString(IDS_TH_SHAPEEXPORT); }
};
// more code for interfacing with max
class _DSQClassDesc : public ClassDesc
{
public:
S32 IsPublic() { return 1; }
void *Create(BOOL loading = FALSE) { return new _Exporter("DSQ"); }
const TCHAR *ClassName() { return _EXPORTER_CLASS_NAME; }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID() { return _DSQ_EXPORTER_CLASS_ID; }
const TCHAR *Category() { return GetString(IDS_TH_SHAPEEXPORT); }
};
// more code for interfacing with max
class _TXTClassDesc : public ClassDesc
{
public:
S32 IsPublic() { return 1; }
void *Create(BOOL loading = FALSE) { return new _Exporter("TXT"); }
const TCHAR *ClassName() { return _EXPORTER_CLASS_NAME; }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID() { return _TXT_EXPORTER_CLASS_ID; }
const TCHAR *Category() { return GetString(IDS_TH_SHAPEEXPORT); }
};
static _DTSClassDesc _DTSDesc;
static _DSQClassDesc _DSQDesc;
static _TXTClassDesc _TXTDesc;
DLLEXPORT const TCHAR *LibDescription()
{
return GetString(IDS_TH_DTSEXPORTDLL);
}
DLLEXPORT S32 LibNumberClasses()
{
return 6;
}
DLLEXPORT ClassDesc *LibClassDesc(S32 i)
{
switch(i)
{
case 0:
return &_DTSDesc;
case 1:
return &_DSQDesc;
case 2:
return &_TXTDesc;
case 3:
return GetSequenceDesc();
case 4:
return GetExportUtilDesc();
case 5:
return GetSkinHelperDesc();
default:
return NULL;
}
}
// Return version so can detect obsolete DLLs
DLLEXPORT ULONG LibVersion()
{
return VERSION_3DSMAX;
}
//
// ._DTS export module functions follow:
//
_Exporter::_Exporter(const char * _extension)
{
dStrcpy(extension,_extension);
}
_Exporter::~_Exporter()
{
}
S32 _Exporter::ExtCount()
{
return 1;
}
// Extensions supported for import/export modules
const TCHAR *_Exporter::Ext(S32 n)
{
switch(n)
{
case 0:
return _T(extension);
default:
return _T("");
}
}
// Long ASCII description (e.g., "Targa 2.0 Image File")
const TCHAR *_Exporter::LongDesc()
{
return GetString(IDS_TH_DTSFILE_LONG);
}
// Short ASCII description (e.g., "Targa")
const TCHAR *_Exporter::ShortDesc()
{
return _EXPORTER_CLASS_SDESC;
}
// ASCII Author name
const TCHAR *_Exporter::AuthorName()
{
return GetString(IDS_TH_AUTHOR);
}
// ASCII Copyright message
const TCHAR *_Exporter::CopyrightMessage()
{
return GetString(IDS_TH_COPYRIGHT_COMPANY);
}
// Other message #1
const TCHAR *_Exporter::OtherMessage1()
{
return _T("");
}
// Other message #2
const TCHAR *_Exporter::OtherMessage2()
{
return _T("");
}
// Version number * 100 (i.e. v3.01 = 301)
U32 _Exporter::Version()
{
return DTS_EXPORTER_CURRENT_VERSION;
}
// Optional
void _Exporter::ShowAbout(HWND hWnd)
{
}
//------------------------------------------------------
// be more thourough about this later...
U32 saveDumpMask;
bool saveEnableSequences;
bool saveCollapse;
bool saveAllowEmptySubtrees;
bool saveAllowCrossedDetails;
bool saveAllowUnusedMeshes;
bool saveViconNeeded;
bool saveAllowOldSequences;
F32 saveAnimationDelta;
F32 saveMaxFrameRate;
S32 saveT2AutoDetail;
void saveConfig()
{
saveDumpMask = dumpMask;
saveEnableSequences = enableSequences;
saveCollapse = transformCollapse;
saveAllowEmptySubtrees = allowEmptySubtrees;
saveAllowCrossedDetails = allowCrossedDetails;
saveAllowUnusedMeshes = allowUnusedMeshes;
saveViconNeeded = viconNeeded;
saveAllowOldSequences = allowOldSequences;
saveAnimationDelta = animationDelta;
saveMaxFrameRate = maxFrameRate;
saveT2AutoDetail = t2AutoDetail;
}
void restoreConfig()
{
dumpMask = saveDumpMask;
enableSequences = saveEnableSequences;
transformCollapse = saveCollapse;
allowEmptySubtrees = saveAllowEmptySubtrees;
allowCrossedDetails = saveAllowCrossedDetails;
allowUnusedMeshes = saveAllowUnusedMeshes;
viconNeeded = saveViconNeeded;
allowOldSequences = saveAllowOldSequences;
animationDelta = saveAnimationDelta;
maxFrameRate = saveMaxFrameRate;
t2AutoDetail = saveT2AutoDetail;
}
S32 cheapSemaphore = 0;
S32 _dts_save(const TCHAR *fname, ExpInterface *ei, Interface *gi)
{
if (cheapSemaphore)
{
Alert("One export at a time: Export code not re-entrant.");
return 1;
}
cheapSemaphore = 1;
char filename[1024];
dStrcpy(filename,fname);
char * ch = filename;
while (*ch!='\0')
{
*ch = tolower(*ch);
ch++;
}
SceneEnumProc myScene;
dStrcpy(maxFile,gi->GetCurFilePath());
//-----------------------------------------------
// read in the config file...
char configFilename[256];
dStrcpy(configFilename,maxFile);
char * p = dStrrchr(configFilename,'\\');
char * p2 = dStrrchr(configFilename,':');
if (p && *p=='\\')
dStrcpy(p+1,"*.cfg");
else if (p2 && *p2==':')
dStrcpy(p2+1,"*.cfg");
else
dStrcpy(configFilename,"*.cfg");
const char * error = myScene.readConfigFile(configFilename);
if (error)
myScene.setExportError(error);
//-----------------------------------------------
// Error?
if (myScene.isExportError())
{
Alert(myScene.getExportError());
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// create dump file...
myScene.startDump(filename,maxFile);
//-----------------------------------------------
// read config file again so we have a record of it...
myScene.readConfigFile(configFilename);
//-----------------------------------------------
// Error?
if (myScene.isExportError())
{
Alert(myScene.getExportError());
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// tweak some parameters depending on export type...
if (dStrstr((const char*)filename,".dsq"))
{
// we're exporting sequences, so turn this on
if (!enableSequences)
{
enableSequences = true;
SceneEnumProc::printDump(PDAlways,"\r\nEnabling \"Param::SequenceExport\" (doing *.dsq export).\r\n");
}
SceneEnumProc::exportType = 's'; // sequence
}
if (dStrstr((const char*)filename,".txt"))
{
// doing a text file dump -- export everything
if (!enableSequences)
{
enableSequences = true;
SceneEnumProc::printDump(PDAlways,"\r\nEnabling \"Param::SequenceExport\" (doing *.txt export).\r\n");
}
if (transformCollapse)
{
transformCollapse = false;
SceneEnumProc::printDump(PDAlways,"\r\nDisabling \"Param::CollapseTransforms\" (doing *.txt export).\r\n");
}
SceneEnumProc::exportType = 't'; // text
}
if (dStrstr((const char*)filename,".dts"))
SceneEnumProc::exportType = 'w'; // whole shape
//-----------------------------------------------
// Error?
if (myScene.isExportError())
{
Alert(myScene.getExportError());
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// Get the nodes we're interested in!
// We also do some checking to make sure everything
// we need is present ... if something is missing,
// an error will be returned.
myScene.enumScene(ei->theScene);
//-----------------------------------------------
// Error?
if (myScene.isExportError())
{
Alert(myScene.getExportError());
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// Any useful nodes?
if (myScene.isEmpty())
{
Alert("No data to export");
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// make sure we get rid of target file before opening it
// otherwise, it'll never shrink
File zap;
zap.open(filename,File::Write);
zap.close();
//-----------------------------------------------
// open a file to save the exported shape to:
FileStream file;
file.open(filename,FileStream::Write);
if( file.getStatus() != Stream::Ok )
{
Alert(IDS_TH_CANTCREATE);
cheapSemaphore = 0;
return(0);
}
//-----------------------------------------------
// actually do the export:
myScene.processScene();
//-----------------------------------------------
// Error?
if (myScene.isExportError())
{
Alert(myScene.getExportError());
file.close();
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// now save the shape
TSShape * pShape = myScene.getShape();
if (dStrstr((const char*)filename,".dts"))
pShape->write(&file);
else if (dStrstr((const char*)filename,".dsq"))
pShape->exportSequences(&file);
else if (dStrstr((const char*)filename,".txt"))
myScene.exportTextFile(&file);
//-----------------------------------------------
// close the file and report any problems:
if( file.getStatus() != Stream::Ok )
{
Alert(IDS_TH_WRITEERROR);
file.close();
remove(filename);
cheapSemaphore = 0;
return(0);
}
else
file.close();
//-----------------------------------------------
// write the shape out to dump file
if (PDShapeHierarchy & dumpMask && dStrstr((const char*)filename,".dts"))
{
// write out the structure of the newly created shape
// but read it from the file first...
if (!SceneEnumProc::dumpShape(filename))
{
Alert(avar("Error opening created file \"%s\".",filename));
file.close();
cheapSemaphore = 0;
return 1;
}
}
cheapSemaphore = 0;
return 1;
}
S32 _Exporter::DoExport(const TCHAR *filename,ExpInterface *ei,Interface *gi, S32 supressUI, DWORD)
{
gSupressUI = supressUI;
// so we can go back to defaults when we're done
saveConfig();
S32 status;
status = _dts_save(filename, ei, gi);
restoreConfig();
if(status == 0)
return 1; // Dialog cancelled
if(status < 0)
return 0; // Real, honest-to-goodness error
return status;
}

748
tools/max2dtsExporter/maxUtil.cc Executable file
View 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;
}
*/

67
tools/max2dtsExporter/maxUtil.h Executable file
View File

@ -0,0 +1,67 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _DYN_MAX_UTIL_H
#define _DYN_MAX_UTIL_H
#pragma pack(push,8)
#include <max.h>
#include <iparamb2.h>
#include <ISkin.h>
#include <decomp.h>
#pragma pack(pop)
#include "math/mMath.h"
#include "ts/tsTransform.h"
#define DEFAULT_TIME 0
extern Point3F & Point3ToPoint3F(Point3 & p3, Point3F & p3f);
extern MatrixF & convertToMatrixF(Matrix3 & mat3,MatrixF & matf);
extern void zapScale(Matrix3 & mat);
extern TriObject * getTriObject( INode *pNode, S32 time, S32 multiResVerts, bool & deleteIt);
extern void getLocalNodeTransform(INode *pNode, INode *parent, AffineParts & child0, AffineParts & parent0, S32 time, Quat16 & rot, Point3F & trans, Quat16 & srot, Point3F & scale);
extern void getBlendNodeTransform(INode *pNode, INode *parent, AffineParts & child0, AffineParts & parent0, S32 time, S32 referenceTime, Quat16 & rot, Point3F & trans, Quat16 & srot, Point3F & scale);
extern Matrix3 & getLocalNodeMatrix(INode *pNode, INode *parent, S32 time, Matrix3 & matrix, AffineParts & child0, AffineParts & parent0);
extern void computeObjectOffset(INode * pNode, Matrix3 & mat);
extern F32 findVolume(INode * pNode, S32 & polyCount);
extern void getDeltaTransform(INode * pNode, S32 time1, S32 time2, Quat16 & rot, Point3F & trans, Quat16 & srot, Point3F & scale);
extern bool isVis(INode * pNode, S32 time);
extern F32 getVisValue(INode * pNode, S32 time);
extern bool animatesVis(INode * pNode, const Interval & range, bool & error);
extern bool animatesFrame(INode * pNode, const Interval & range, bool & error);
extern bool animatesMatFrame(INode * pNode, const Interval & range, bool & error);
extern void embedSubtree(Interface *);
extern void renumberNodes(Interface *, S32 newSize);
extern void registerDetails(Interface * ip);
extern char * chopTrailingNumber(const char *, S32 & size);
extern bool hasMesh(INode *pNode);
extern void findSkinData(INode * pNode, ISkin **skin, ISkinContextData ** skinData);
extern bool hasSkin(INode * pNode);
extern bool pointInPoly(const Point3F & point, const Point3F & normal, const Point3F * verts, U32 n);
#endif // _DYN_MAX_UTIL_H

BIN
tools/max2dtsExporter/readme.doc Executable file

Binary file not shown.

993
tools/max2dtsExporter/sequence.cc Executable file
View File

@ -0,0 +1,993 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "max2dtsExporter/Sequence.h"
#include "max2dtsExporter/exporter.h"
#include "Platform/platformAssert.h"
#pragma pack(push,8)
#include <MAX.H>
#include <dummy.h>
#include <iparamm.h>
#pragma pack(pop)
// conversion from 1.x to 2.x 3ds Max?
//#define TYPE_BOOL TYPE_BOOLEAN
extern HINSTANCE hInstance;
extern TCHAR *GetString(S32);
//------------------------------------------------------
// max data structures used to map between max
// user-interface and max parameter blocks...
//------------------------------------------------------
S32 useFrameRateControls1[] = { IDC_SEQ_USE_FRAME_RATE, IDC_SEQ_USE_N_FRAMES };
S32 useFrameRateControls2[] = { IDC_SEQ_USE_GROUND_FRAME_RATE, IDC_SEQ_USE_N_GROUND_FRAMES };
S32 tfArray[] = { true, false };
static ParamUIDesc descParam1[] =
{
ParamUIDesc(
PB_SEQ_CYCLIC,
TYPE_SINGLECHEKBOX,
IDC_SEQ_CYCLIC ),
ParamUIDesc(
PB_SEQ_BLEND,
TYPE_SINGLECHEKBOX,
IDC_SEQ_BLEND ),
ParamUIDesc(
PB_SEQ_LAST_FIRST_FRAME_SAME,
TYPE_SINGLECHEKBOX,
IDC_SEQ_LAST_FIRST_FRAME_SAME ),
ParamUIDesc(
PB_SEQ_USE_FRAME_RATE,
TYPE_RADIO,
useFrameRateControls1,
2,
tfArray),
ParamUIDesc(
PB_SEQ_FRAME_RATE,
EDITTYPE_FLOAT,
IDC_SEQ_FRAME_RATE,IDC_SEQ_FRAME_RATE_SPINNER,
0.0001f,100.0f,1.0f),
ParamUIDesc(
PB_SEQ_NUM_FRAMES,
EDITTYPE_INT,
IDC_SEQ_NUM_FRAMES,IDC_SEQ_NUM_FRAMES_SPINNER,
2.0f,100.0f,1.0f),
ParamUIDesc(
PB_SEQ_OVERRIDE_DURATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_DURATION_OVERRIDE ),
ParamUIDesc(
PB_SEQ_DURATION,
EDITTYPE_FLOAT,
IDC_SEQ_DURATION,IDC_SEQ_DURATION_SPINNER,
0.0001f,1000.0f,1.0f),
ParamUIDesc(
PB_SEQ_DEFAULT_PRIORITY,
EDITTYPE_INT,
IDC_SEQ_PRIORITY,IDC_SEQ_PRIORITY_SPINNER,
0.0f, 1000.0f, 1.0f)
};
static ParamUIDesc descParam2[] =
{
ParamUIDesc(
PB_SEQ_IGNORE_GROUND_TRANSFORM,
TYPE_SINGLECHEKBOX,
IDC_SEQ_IGNORE_GROUND_TRANSFORM ),
ParamUIDesc(
PB_SEQ_USE_GROUND_FRAME_RATE,
TYPE_RADIO,
useFrameRateControls2,
2,
tfArray),
ParamUIDesc(
PB_SEQ_GROUND_FRAME_RATE,
EDITTYPE_FLOAT,
IDC_SEQ_GROUND_FRAME_RATE,
IDC_SEQ_GROUND_FRAME_RATE_SPINNER,
0.0001f,100.0f,1.0f),
ParamUIDesc(
PB_SEQ_NUM_GROUND_FRAMES,
EDITTYPE_INT,
IDC_SEQ_NUM_GROUND_FRAMES,
IDC_SEQ_NUM_GROUND_FRAMES_SPINNER,
2.0f,100.0f,1.0f),
};
static ParamUIDesc descParam3[] =
{
ParamUIDesc(
PB_SEQ_ENABLE_MORPH_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_ENABLE_MORPH_ANIMATION ),
ParamUIDesc(
PB_SEQ_ENABLE_VIS_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_ENABLE_VIS_ANIMATION ),
ParamUIDesc(
PB_SEQ_ENABLE_TRANSFORM_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_ENABLE_TRANSFORM_ANIMATION ),
ParamUIDesc(
PB_SEQ_ENABLE_UNIFORM_SCALE_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_ENABLE_UNIFORM_SCALE_ANIMATION ),
ParamUIDesc(
PB_SEQ_ENABLE_ARBITRARY_SCALE_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_ENABLE_ARBITRARY_SCALE_ANIMATION ),
ParamUIDesc(
PB_SEQ_ENABLE_TEXTURE_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_ENABLE_TEXTURE_ANIMATION ),
ParamUIDesc(
PB_SEQ_ENABLE_IFL_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_ENABLE_IFL_ANIMATION ),
ParamUIDesc(
PB_SEQ_ENABLE_DECAL_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_ENABLE_DECAL_ANIMATION ),
ParamUIDesc(
PB_SEQ_ENABLE_DECAL_FRAME_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_ENABLE_DECAL_FRAME_ANIMATION ),
ParamUIDesc(
PB_SEQ_FORCE_MORPH_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_FORCE_MORPH_ANIMATION ),
ParamUIDesc(
PB_SEQ_FORCE_VIS_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_FORCE_VIS_ANIMATION ),
ParamUIDesc(
PB_SEQ_FORCE_TRANSFORM_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_FORCE_TRANSFORM_ANIMATION ),
ParamUIDesc(
PB_SEQ_FORCE_SCALE_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_FORCE_SCALE_ANIMATION ),
ParamUIDesc(
PB_SEQ_FORCE_TEXTURE_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_FORCE_TEXTURE_ANIMATION ),
ParamUIDesc(
PB_SEQ_FORCE_DECAL_ANIMATION,
TYPE_SINGLECHEKBOX,
IDC_SEQ_FORCE_DECAL_ANIMATION )
};
#define PARAMDESC1_LENGTH (sizeof( descParam1 ) / sizeof( ParamUIDesc ))
#define PARAMDESC2_LENGTH (sizeof( descParam2 ) / sizeof( ParamUIDesc ))
#define PARAMDESC3_LENGTH (sizeof( descParam3 ) / sizeof( ParamUIDesc ))
// This is the current version.
static ParamBlockDescID curVer[] =
{
{ TYPE_BOOL, NULL, TRUE , 0 }, // begin/end
{ TYPE_BOOL, NULL, FALSE, 1 }, // cyclic
{ TYPE_BOOL, NULL, FALSE, 2 }, // blend
{ TYPE_BOOL, NULL, FALSE, 3 }, // first and last frame same (cyclic seq only)
{ TYPE_BOOL, NULL, FALSE, 4 }, // use frame rate?
{ TYPE_FLOAT, NULL, FALSE, 5 }, // Frame Rate
{ TYPE_INT, NULL, FALSE, 6 }, // number of frames
{ TYPE_BOOL, NULL, FALSE, 7 }, // ignore ground transform altogether?
{ TYPE_BOOL, NULL, FALSE, 8 }, // use ground frame rate?
{ TYPE_FLOAT, NULL, FALSE, 9 }, // ground frame Rate
{ TYPE_INT, NULL, FALSE, 10 }, // number of ground frames
{ TYPE_BOOL, NULL, FALSE, 11 }, // enable morph animation
{ TYPE_BOOL, NULL, FALSE, 12 }, // enable vis animation
{ TYPE_BOOL, NULL, FALSE, 13 }, // enable transform animation
{ TYPE_BOOL, NULL, FALSE, 14 }, // force morph animation
{ TYPE_BOOL, NULL, FALSE, 15 }, // force vis animation
{ TYPE_BOOL, NULL, FALSE, 16 }, // force transform animation
{ TYPE_INT, NULL, FALSE, 17 }, // sequence default priority
{ TYPE_FLOAT, NULL, TRUE, 18 }, // blend sequence reference time (keyframe time determines it, not param value)
{ TYPE_BOOL, NULL, FALSE, 19 }, // enable texture animation
{ TYPE_BOOL, NULL, FALSE, 20 }, // enable ifl animation
{ TYPE_BOOL, NULL, FALSE, 21 }, // force texture animation
{ TYPE_FLOAT, NULL, TRUE, 22 }, // triggers...keyframes are read to determine trigger times and values
{ TYPE_BOOL, NULL, FALSE, 23 }, // enable decal animation
{ TYPE_BOOL, NULL, FALSE, 24 }, // enable decal frame animation
{ TYPE_BOOL, NULL, FALSE, 25 }, // force decal animation
{ TYPE_BOOL, NULL, FALSE, 26 }, // override sequence duration
{ TYPE_FLOAT, NULL, FALSE, 27 }, // sequence duration (if override true)
{ TYPE_BOOL, NULL, FALSE, 28 }, // enable uniform scale animation
{ TYPE_BOOL, NULL, FALSE, 29 }, // enable arbitrary scale animation
{ TYPE_BOOL, NULL, FALSE, 30 }, // force scale animation
};
static ParamBlockDescID oldVer6[] =
{
{ TYPE_BOOL, NULL, TRUE , 0 }, // begin/end
{ TYPE_BOOL, NULL, FALSE, 1 }, // cyclic
{ TYPE_BOOL, NULL, FALSE, 2 }, // blend
{ TYPE_BOOL, NULL, FALSE, 3 }, // first and last frame same (cyclic seq only)
{ TYPE_BOOL, NULL, FALSE, 4 }, // use frame rate?
{ TYPE_FLOAT, NULL, FALSE, 5 }, // Frame Rate
{ TYPE_INT, NULL, FALSE, 6 }, // number of frames
{ TYPE_BOOL, NULL, FALSE, 7 }, // ignore ground transform altogether?
{ TYPE_BOOL, NULL, FALSE, 8 }, // use ground frame rate?
{ TYPE_FLOAT, NULL, FALSE, 9 }, // ground frame Rate
{ TYPE_INT, NULL, FALSE, 10 }, // number of ground frames
{ TYPE_BOOL, NULL, FALSE, 11 }, // enable morph animation
{ TYPE_BOOL, NULL, FALSE, 12 }, // enable vis animation
{ TYPE_BOOL, NULL, FALSE, 13 }, // enable transform animation
{ TYPE_BOOL, NULL, FALSE, 14 }, // force morph animation
{ TYPE_BOOL, NULL, FALSE, 15 }, // force vis animation
{ TYPE_BOOL, NULL, FALSE, 16 }, // force transform animation
{ TYPE_INT, NULL, FALSE, 17 }, // sequence default priority
{ TYPE_FLOAT, NULL, TRUE, 18 }, // blend sequence reference time (keyframe time determines it, not param value)
{ TYPE_BOOL, NULL, FALSE, 19 }, // enable texture animation
{ TYPE_BOOL, NULL, FALSE, 20 }, // enable ifl animation
{ TYPE_BOOL, NULL, FALSE, 21 }, // force texture animation
{ TYPE_FLOAT, NULL, TRUE, 22 }, // triggers...keyframes are read to determine trigger times and values
{ TYPE_BOOL, NULL, FALSE, 23 }, // enable decal animation
{ TYPE_BOOL, NULL, FALSE, 24 }, // enable decal frame animation
{ TYPE_BOOL, NULL, FALSE, 25 }, // force decal animation
{ TYPE_BOOL, NULL, FALSE, 26 }, // override sequence duration
{ TYPE_FLOAT, NULL, FALSE, 27 }, // sequence duration (if override true)
};
static ParamBlockDescID oldVer5[] =
{
{ TYPE_BOOL, NULL, TRUE , 0 }, // begin/end
{ TYPE_BOOL, NULL, FALSE, 1 }, // cyclic
{ TYPE_BOOL, NULL, FALSE, 2 }, // blend
{ TYPE_BOOL, NULL, FALSE, 3 }, // first and last frame same (cyclic seq only)
{ TYPE_BOOL, NULL, FALSE, 4 }, // use frame rate?
{ TYPE_FLOAT, NULL, FALSE, 5 }, // Frame Rate
{ TYPE_INT, NULL, FALSE, 6 }, // number of frames
{ TYPE_BOOL, NULL, FALSE, 7 }, // ignore ground transform altogether?
{ TYPE_BOOL, NULL, FALSE, 8 }, // use ground frame rate?
{ TYPE_FLOAT, NULL, FALSE, 9 }, // ground frame Rate
{ TYPE_INT, NULL, FALSE, 10 }, // number of ground frames
{ TYPE_BOOL, NULL, FALSE, 11 }, // enable morph animation
{ TYPE_BOOL, NULL, FALSE, 12 }, // enable vis animation
{ TYPE_BOOL, NULL, FALSE, 13 }, // enable transform animation
{ TYPE_BOOL, NULL, FALSE, 14 }, // force morph animation
{ TYPE_BOOL, NULL, FALSE, 15 }, // force vis animation
{ TYPE_BOOL, NULL, FALSE, 16 }, // force transform animation
{ TYPE_INT, NULL, FALSE, 17 }, // sequence default priority
{ TYPE_FLOAT, NULL, TRUE, 18 }, // blend sequence reference time (keyframe time determines it, not param value)
{ TYPE_BOOL, NULL, FALSE, 19 }, // enable texture animation
{ TYPE_BOOL, NULL, FALSE, 20 }, // enable ifl animation
{ TYPE_BOOL, NULL, FALSE, 21 }, // force texture animation
{ TYPE_FLOAT, NULL, TRUE, 22 }, // triggers...keyframes are read to determine trigger times and values
{ TYPE_BOOL, NULL, FALSE, 23 }, // enable decal animation
{ TYPE_BOOL, NULL, FALSE, 24 }, // enable decal frame animation
{ TYPE_BOOL, NULL, FALSE, 25 } // force decal animation
};
static ParamBlockDescID oldVer4[] =
{
{ TYPE_BOOL, NULL, TRUE , 0 }, // begin/end
{ TYPE_BOOL, NULL, FALSE, 1 }, // cyclic
{ TYPE_BOOL, NULL, FALSE, 2 }, // blend
{ TYPE_BOOL, NULL, FALSE, 3 }, // first and last frame same (cyclic seq only)
{ TYPE_BOOL, NULL, FALSE, 4 }, // use frame rate?
{ TYPE_FLOAT, NULL, FALSE, 5 }, // Frame Rate
{ TYPE_INT, NULL, FALSE, 6 }, // number of frames
{ TYPE_BOOL, NULL, FALSE, 7 }, // ignore ground transform altogether?
{ TYPE_BOOL, NULL, FALSE, 8 }, // use ground frame rate?
{ TYPE_FLOAT, NULL, FALSE, 9 }, // ground frame Rate
{ TYPE_INT, NULL, FALSE, 10 }, // number of ground frames
{ TYPE_BOOL, NULL, FALSE, 11 }, // enable morph animation
{ TYPE_BOOL, NULL, FALSE, 12 }, // enable vis animation
{ TYPE_BOOL, NULL, FALSE, 13 }, // enable transform animation
{ TYPE_BOOL, NULL, FALSE, 14 }, // force morph animation
{ TYPE_BOOL, NULL, FALSE, 15 }, // force vis animation
{ TYPE_BOOL, NULL, FALSE, 16 }, // force transform animation
{ TYPE_INT, NULL, FALSE, 17 }, // sequence default priority
{ TYPE_FLOAT, NULL, TRUE, 18 }, // blend sequence reference time (keyframe time determines it, not param value)
{ TYPE_BOOL, NULL, FALSE, 19 }, // enable texture animation
{ TYPE_BOOL, NULL, FALSE, 20 }, // enable ifl animation
{ TYPE_BOOL, NULL, FALSE, 21 }, // force texture animation
{ TYPE_FLOAT, NULL, TRUE, 22 }, // triggers...keyframes are read to determine trigger times and values
};
// old param block versions
static ParamBlockDescID oldVer3[] =
{
{ TYPE_BOOL, NULL, TRUE , 0 }, // begin/end
{ TYPE_BOOL, NULL, FALSE, 1 }, // cyclic
{ TYPE_BOOL, NULL, FALSE, 2 }, // blend
{ TYPE_BOOL, NULL, FALSE, 3 }, // first and last frame same (cyclic seq only)
{ TYPE_BOOL, NULL, FALSE, 4 }, // use frame rate?
{ TYPE_FLOAT, NULL, FALSE, 5 }, // Frame Rate
{ TYPE_INT, NULL, FALSE, 6 }, // number of frames
{ TYPE_BOOL, NULL, FALSE, 7 }, // ignore ground transform altogether?
{ TYPE_BOOL, NULL, FALSE, 8 }, // use ground frame rate?
{ TYPE_FLOAT, NULL, FALSE, 9 }, // ground frame Rate
{ TYPE_INT, NULL, FALSE, 10 }, // number of ground frames
{ TYPE_BOOL, NULL, FALSE, 11 }, // enable morph animation
{ TYPE_BOOL, NULL, FALSE, 12 }, // enable vis animation
{ TYPE_BOOL, NULL, FALSE, 13 }, // enable transform animation
{ TYPE_BOOL, NULL, FALSE, 14 }, // force morph animation
{ TYPE_BOOL, NULL, FALSE, 15 }, // force vis animation
{ TYPE_BOOL, NULL, FALSE, 16 }, // force transform animation
{ TYPE_INT, NULL, FALSE, 17 }, // sequence default priority
{ TYPE_FLOAT, NULL, TRUE, 18 }, // blend sequence reference time (keyframe time determines it, not param value)
{ TYPE_BOOL, NULL, FALSE, 19 }, // enable texture animation
{ TYPE_BOOL, NULL, FALSE, 20 }, // enable ifl animation
{ TYPE_BOOL, NULL, FALSE, 21 } // force texture animation
};
static ParamBlockDescID oldVer2[] =
{
{ TYPE_BOOL, NULL, TRUE , 0 }, // begin/end
{ TYPE_BOOL, NULL, FALSE, 1 }, // cyclic
{ TYPE_BOOL, NULL, FALSE, 2 }, // blend
{ TYPE_BOOL, NULL, FALSE, 3 }, // first and last frame same (cyclic seq only)
{ TYPE_BOOL, NULL, FALSE, 4 }, // use frame rate?
{ TYPE_FLOAT, NULL, FALSE, 5 }, // Frame Rate
{ TYPE_INT, NULL, FALSE, 6 }, // number of frames
{ TYPE_BOOL, NULL, FALSE, 7 }, // ignore ground transform altogether?
{ TYPE_BOOL, NULL, FALSE, 8 }, // use ground frame rate?
{ TYPE_FLOAT, NULL, FALSE, 9 }, // ground frame Rate
{ TYPE_INT, NULL, FALSE, 10 }, // number of ground frames
{ TYPE_BOOL, NULL, FALSE, 11 }, // enable morph animation
{ TYPE_BOOL, NULL, FALSE, 12 }, // enable vis animation
{ TYPE_BOOL, NULL, FALSE, 13 }, // enable transform animation
{ TYPE_BOOL, NULL, FALSE, 14 }, // force morph animation
{ TYPE_BOOL, NULL, FALSE, 15 }, // force vis animation
{ TYPE_BOOL, NULL, FALSE, 16 }, // force transform animation
{ TYPE_INT, NULL, FALSE, 17 }, // sequence default priority
{ TYPE_FLOAT, NULL, TRUE, 18 } // blend sequence reference time (keyframe time determines it, not param value)
};
static ParamBlockDescID oldVer1[] =
{
{ TYPE_BOOL, NULL, TRUE , 0 }, // begin/end
{ TYPE_BOOL, NULL, FALSE, 1 }, // cyclic
{ TYPE_BOOL, NULL, FALSE, 2 }, // blend
{ TYPE_BOOL, NULL, FALSE, 3 }, // first and last frame same (cyclic seq only)
{ TYPE_BOOL, NULL, FALSE, 4 }, // use frame rate?
{ TYPE_FLOAT, NULL, FALSE, 5 }, // Frame Rate
{ TYPE_INT, NULL, FALSE, 6 }, // number of frames
{ TYPE_BOOL, NULL, FALSE, 7 }, // ignore ground transform altogether?
{ TYPE_BOOL, NULL, FALSE, 8 }, // use ground frame rate?
{ TYPE_FLOAT, NULL, FALSE, 9 }, // ground frame Rate
{ TYPE_INT, NULL, FALSE, 10 }, // number of ground frames
{ TYPE_BOOL, NULL, FALSE, 11 }, // enable morph animation
{ TYPE_BOOL, NULL, FALSE, 12 }, // enable vis animation
{ TYPE_BOOL, NULL, FALSE, 13 }, // enable transform animation
{ TYPE_BOOL, NULL, FALSE, 14 }, // force morph animation
{ TYPE_BOOL, NULL, FALSE, 15 }, // force vis animation
{ TYPE_BOOL, NULL, FALSE, 16 }, // force transform animation
{ TYPE_INT, NULL, FALSE, 17 } // sequence default priority
};
// Array of old versions
static ParamVersionDesc versions[] =
{
ParamVersionDesc( oldVer1, sizeof(oldVer1)/sizeof(ParamBlockDescID), 0),
ParamVersionDesc( oldVer2, sizeof(oldVer2)/sizeof(ParamBlockDescID), 1),
ParamVersionDesc( oldVer3, sizeof(oldVer3)/sizeof(ParamBlockDescID), 2),
ParamVersionDesc( oldVer4, sizeof(oldVer4)/sizeof(ParamBlockDescID), 3),
ParamVersionDesc( oldVer5, sizeof(oldVer5)/sizeof(ParamBlockDescID), 4),
ParamVersionDesc( oldVer6, sizeof(oldVer6)/sizeof(ParamBlockDescID), 5)
};
#define NUM_OLDVERSIONS (sizeof(versions) / sizeof(ParamVersionDesc))
#define CURRENT_VERSION NUM_OLDVERSIONS
// Current version
#define PBLOCK_LENGTH (sizeof(curVer) / sizeof(ParamBlockDescID))
static ParamVersionDesc curVersion( curVer, PBLOCK_LENGTH, CURRENT_VERSION );
//------------------------------------------------------
// sequence class defaults:
//------------------------------------------------------
U32 SequenceObject::defaultCyclic = true;
U32 SequenceObject::defaultBlend = false;
U32 SequenceObject::defaultFirstLastFrameSame = false;
U32 SequenceObject::defaultUseFrameRate = true;
F32 SequenceObject::defaultFrameRate = 15.0f;
S32 SequenceObject::defaultNumFrames = 2;
U32 SequenceObject::defaultIgnoreGroundTransform = false;
U32 SequenceObject::defaultUseGroundFrameRate = false;
F32 SequenceObject::defaultGroundFrameRate = 15.0f;
S32 SequenceObject::defaultNumGroundFrames = 2;
U32 SequenceObject::defaultEnableMorphAnimation = false;
U32 SequenceObject::defaultEnableVisAnimation = false;
U32 SequenceObject::defaultEnableTransformAnimation = true;
U32 SequenceObject::defaultEnableTextureAnimation = false;
U32 SequenceObject::defaultEnableIflAnimation = false;
U32 SequenceObject::defaultEnableDecalAnimation = false;
U32 SequenceObject::defaultEnableDecalFrameAnimation = false;
U32 SequenceObject::defaultForceMorphAnimation = false;
U32 SequenceObject::defaultForceVisAnimation = false;
U32 SequenceObject::defaultForceTransformAnimation = false;
U32 SequenceObject::defaultForceTextureAnimation = false;
U32 SequenceObject::defaultForceDecalAnimation = false;
S32 SequenceObject::defaultDefaultSequencePriority = 0;
S32 SequenceObject::defaultBlendReferenceTime = 0; // value not important
U32 SequenceObject::defaultOverrideDuration = false;
F32 SequenceObject::defaultDuration = 1.0f;
U32 SequenceObject::defaultEnableUniformScaleAnimation = false;
U32 SequenceObject::defaultEnableArbitraryScaleAnimation = false;
U32 SequenceObject::defaultForceScaleAnimation = false;
//------------------------------------------------------
// Some more statics:
//------------------------------------------------------
SequenceObject * SequenceObject::editOb = NULL;
IParamMap * SequenceObject::pmapParam1 = NULL;
IParamMap * SequenceObject::pmapParam2 = NULL;
IParamMap * SequenceObject::pmapParam3 = NULL;
//------------------------------------------------------
// Sequence object methods...
//------------------------------------------------------
void SequenceObject::InitNodeName(TSTR& s)
{
s = GetString(IDS_DB_SEQUENCE);
}
void SequenceObject::GetClassName(TSTR& s)
{
s = TSTR(GetString(IDS_DB_SEQUENCE));
}
void resetSequenceDefaults()
{
SequenceObject::defaultCyclic = true;
SequenceObject::defaultBlend = false;
SequenceObject::defaultFirstLastFrameSame = false;
SequenceObject::defaultUseFrameRate = true;
SequenceObject::defaultFrameRate = 15.0f;
SequenceObject::defaultNumFrames = 2;
SequenceObject::defaultIgnoreGroundTransform = false;
SequenceObject::defaultUseGroundFrameRate = false;
SequenceObject::defaultGroundFrameRate = 15.0f;
SequenceObject::defaultNumGroundFrames = 2;
SequenceObject::defaultEnableMorphAnimation = false;
SequenceObject::defaultEnableVisAnimation = false;
SequenceObject::defaultEnableTransformAnimation = true;
SequenceObject::defaultEnableTextureAnimation = false;
SequenceObject::defaultEnableIflAnimation = false;
SequenceObject::defaultEnableDecalAnimation = false;
SequenceObject::defaultEnableDecalFrameAnimation = false;
SequenceObject::defaultForceMorphAnimation = false;
SequenceObject::defaultForceVisAnimation = false;
SequenceObject::defaultForceTransformAnimation = false;
SequenceObject::defaultForceTextureAnimation = false;
SequenceObject::defaultForceDecalAnimation = false;
SequenceObject::defaultDefaultSequencePriority = 0;
SequenceObject::defaultBlendReferenceTime = 0; // value not important
SequenceObject::defaultOverrideDuration = false;
SequenceObject::defaultDuration = 1.0f;
SequenceObject::defaultEnableUniformScaleAnimation = false;
SequenceObject::defaultEnableArbitraryScaleAnimation = false;
SequenceObject::defaultForceScaleAnimation = false;
}
bool getBoolSequenceDefault(S32 index)
{
switch (index)
{
case PB_SEQ_CYCLIC: return SequenceObject::defaultCyclic;
case PB_SEQ_BLEND: return SequenceObject::defaultBlend;
case PB_SEQ_LAST_FIRST_FRAME_SAME: return SequenceObject::defaultFirstLastFrameSame;
case PB_SEQ_USE_FRAME_RATE: return SequenceObject::defaultUseFrameRate;
case PB_SEQ_IGNORE_GROUND_TRANSFORM: return SequenceObject::defaultIgnoreGroundTransform;
case PB_SEQ_USE_GROUND_FRAME_RATE: return SequenceObject::defaultUseGroundFrameRate;
case PB_SEQ_ENABLE_MORPH_ANIMATION: return SequenceObject::defaultEnableMorphAnimation;
case PB_SEQ_ENABLE_VIS_ANIMATION: return SequenceObject::defaultEnableVisAnimation;
case PB_SEQ_ENABLE_TRANSFORM_ANIMATION: return SequenceObject::defaultEnableTransformAnimation;
case PB_SEQ_ENABLE_TEXTURE_ANIMATION: return SequenceObject::defaultEnableTextureAnimation;
case PB_SEQ_ENABLE_IFL_ANIMATION: return SequenceObject::defaultEnableIflAnimation;
case PB_SEQ_ENABLE_DECAL_ANIMATION: return SequenceObject::defaultEnableDecalAnimation;
case PB_SEQ_ENABLE_DECAL_FRAME_ANIMATION: return SequenceObject::defaultEnableDecalFrameAnimation;
case PB_SEQ_FORCE_MORPH_ANIMATION: return SequenceObject::defaultForceMorphAnimation;
case PB_SEQ_FORCE_VIS_ANIMATION: return SequenceObject::defaultForceVisAnimation;
case PB_SEQ_FORCE_TRANSFORM_ANIMATION: return SequenceObject::defaultForceTransformAnimation;
case PB_SEQ_FORCE_TEXTURE_ANIMATION: return SequenceObject::defaultForceTextureAnimation;
case PB_SEQ_FORCE_DECAL_ANIMATION: return SequenceObject::defaultForceDecalAnimation;
case PB_SEQ_OVERRIDE_DURATION: return SequenceObject::defaultOverrideDuration;
case PB_SEQ_ENABLE_UNIFORM_SCALE_ANIMATION: return SequenceObject::defaultEnableUniformScaleAnimation;
case PB_SEQ_ENABLE_ARBITRARY_SCALE_ANIMATION: return SequenceObject::defaultEnableArbitraryScaleAnimation;
case PB_SEQ_FORCE_SCALE_ANIMATION: return SequenceObject::defaultForceScaleAnimation;
// default : AssertFatal(0,"Invalid default when getting sequence default value");
// return false;
}
return false;
}
F32 getFloatSequenceDefault(S32 index)
{
switch (index)
{
case PB_SEQ_FRAME_RATE: return SequenceObject::defaultFrameRate;
case PB_SEQ_GROUND_FRAME_RATE: return SequenceObject::defaultGroundFrameRate;
case PB_SEQ_DURATION: return SequenceObject::defaultDuration;
// default : AssertFatal(0,"Invalid default when getting sequence default value");
// return 0.0f;
}
return 0.0f;
}
S32 getIntSequenceDefault(S32 index)
{
switch (index)
{
case PB_SEQ_NUM_FRAMES: return SequenceObject::defaultNumFrames;
case PB_SEQ_NUM_GROUND_FRAMES: return SequenceObject::defaultNumGroundFrames;
case PB_SEQ_DEFAULT_PRIORITY: return SequenceObject::defaultDefaultSequencePriority;
// default : AssertFatal(0,"Invalid default when getting sequence default value");
// return 0;
}
return 0;
}
//------------------------------------------------------
// Sequence object implementation -- not much here
//------------------------------------------------------
IParamArray *SequenceObject::GetParamBlock()
{
return pblock;
}
S32 SequenceObject::GetParamBlockIndex(S32 id)
{
if (pblock && id>=0 && id<pblock->NumParams())
return id;
return -1;
}
void SequenceObject::FreeCaches()
{
ivalid.SetEmpty();
}
RefResult SequenceObject::NotifyRefChanged( Interval changeInt,
RefTargetHandle hTarget,
PartID& partID,
RefMessage message )
{
switch (message)
{
case REFMSG_CHANGE:
{
if (editOb==this)
InvalidateUI();
break;
}
case REFMSG_GET_PARAM_DIM:
{
GetParamDim *gpd = (GetParamDim*)partID;
gpd->dim = GetParameterDim(gpd->index);
return REF_STOP;
}
case REFMSG_GET_PARAM_NAME:
{
GetParamName *gpn = (GetParamName*)partID;
gpn->name = GetParameterName(gpn->index);
return REF_STOP;
}
}
return(REF_SUCCEED);
}
Interval SequenceObject::ObjectValidity(TimeValue time)
{
return ivalid;
}
TSTR SequenceObject::SubAnimName(S32 i)
{
return _T("Parameters");
}
void SequenceObject::BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev)
{
// Save the current sequence object
editOb = this;
// we have mutliple parameter maps...make sure one of each is created:
if (pmapParam1)
{
// Left over from last sequence ceated
pmapParam1->SetParamBlock(pblock);
}
else
{
pmapParam1 = CreateCPParamMap(
descParam1,
PARAMDESC1_LENGTH,
pblock,
ip,
hInstance,
MAKEINTRESOURCE(IDD_SEQUENCE_PARAMS),
_T("General"),
0);
}
if (pmapParam2)
{
// Left over from last sequence ceated
pmapParam2->SetParamBlock(pblock);
}
else
{
pmapParam2 = CreateCPParamMap(
descParam2,
PARAMDESC2_LENGTH,
pblock,
ip,
hInstance,
MAKEINTRESOURCE(IDD_SEQUENCE_PARAMS2),
_T("Ground Transform"),
APPENDROLL_CLOSED);
}
if (pmapParam3)
{
// Left over from last sequence ceated
pmapParam3->SetParamBlock(pblock);
}
else
{
pmapParam3 = CreateCPParamMap(
descParam3,
PARAMDESC3_LENGTH,
pblock,
ip,
hInstance,
MAKEINTRESOURCE(IDD_SEQUENCE_PARAMS3),
_T("Export Control"),
APPENDROLL_CLOSED);
}
}
void SequenceObject::EndEditParams(IObjParam *ip, ULONG flags,Animatable *next)
{
editOb = NULL;
ClearAFlag(A_OBJ_CREATING);
if ( (flags&END_EDIT_REMOVEUI) && pmapParam1 )
{
// Remove the rollup pages from the command panel.
DestroyCPParamMap(pmapParam1);
pmapParam1 = NULL;
}
if ( (flags&END_EDIT_REMOVEUI) && pmapParam2 )
{
// Remove the rollup pages from the command panel.
DestroyCPParamMap(pmapParam2);
pmapParam2 = NULL;
}
if ( (flags&END_EDIT_REMOVEUI) && pmapParam3 )
{
// Remove the rollup pages from the command panel.
DestroyCPParamMap(pmapParam3);
pmapParam3 = NULL;
}
}
// This method is called when the user interface controls need to be
// updated to reflect new values because of the user moving the time
// slider. Here we simply call a method of the parameter map to
// handle this for us.
void SequenceObject::InvalidateUI()
{
if (pmapParam1)
pmapParam1->Invalidate();
if (pmapParam2)
pmapParam2->Invalidate();
if (pmapParam3)
pmapParam3->Invalidate();
}
// This method returns the dimension of the parameter requested.
// This dimension describes the type and magnitude of the value
// stored by the parameter.
ParamDimension *SequenceObject::GetParameterDim(S32)
{
return defaultDim; // just store the parameter...ask no questions
}
// This method returns the name of the parameter requested.
TSTR SequenceObject::GetParameterName(S32 pbIndex)
{
switch (pbIndex)
{
case PB_SEQ_BEGIN_END:
return TSTR(_T("Sequence Begin/End"));
case PB_SEQ_CYCLIC:
return TSTR(_T("Cyclic sequence"));
case PB_SEQ_BLEND:
return TSTR(_T("Blend sequence"));
case PB_SEQ_LAST_FIRST_FRAME_SAME:
return TSTR(_T("Last frame matches first frame"));
case PB_SEQ_USE_FRAME_RATE:
return TSTR(_T("Use frame rate"));
case PB_SEQ_FRAME_RATE:
return TSTR(_T("Frame rate"));
case PB_SEQ_NUM_FRAMES:
return TSTR(_T("Number of frames"));
case PB_SEQ_IGNORE_GROUND_TRANSFORM:
return TSTR(_T("Ignore ground transform"));
case PB_SEQ_USE_GROUND_FRAME_RATE:
return TSTR(_T("Use ground transform frame rate"));
case PB_SEQ_GROUND_FRAME_RATE:
return TSTR(_T("Ground transform frame rate"));
case PB_SEQ_NUM_GROUND_FRAMES:
return TSTR(_T("Number of ground transform frames"));
case PB_SEQ_ENABLE_MORPH_ANIMATION:
return TSTR(_T("Enable morph animation"));
case PB_SEQ_ENABLE_VIS_ANIMATION:
return TSTR(_T("Enable visibility animation"));
case PB_SEQ_ENABLE_TRANSFORM_ANIMATION:
return TSTR(_T("Enable transform animation"));
case PB_SEQ_ENABLE_TEXTURE_ANIMATION:
return TSTR(_T("Enable texture animation"));
case PB_SEQ_ENABLE_IFL_ANIMATION:
return TSTR(_T("Enable IFL animation"));
case PB_SEQ_ENABLE_DECAL_ANIMATION:
return TSTR(_T("Enable decal animation"));
case PB_SEQ_ENABLE_DECAL_FRAME_ANIMATION:
return TSTR(_T("Enable decal frame animation"));
case PB_SEQ_FORCE_MORPH_ANIMATION:
return TSTR(_T("Force morph animation"));
case PB_SEQ_FORCE_VIS_ANIMATION:
return TSTR(_T("Force visibility animation"));
case PB_SEQ_FORCE_TRANSFORM_ANIMATION:
return TSTR(_T("Force transform animation"));
case PB_SEQ_FORCE_TEXTURE_ANIMATION:
return TSTR(_T("Force texture animation"));
case PB_SEQ_FORCE_DECAL_ANIMATION:
return TSTR(_T("Force decal animation"));
case PB_SEQ_DEFAULT_PRIORITY:
return TSTR(_T("Default sequence priority"));
case PB_SEQ_BLEND_REFERENCE_TIME:
return TSTR(_T("Blend Reference Time"));
case PB_SEQ_TRIGGERS:
return TSTR(_T("Triggers"));
case PB_SEQ_OVERRIDE_DURATION:
return TSTR(_T("Override sequence duration"));
case PB_SEQ_DURATION:
return TSTR(_T("Sequence duration"));
case PB_SEQ_ENABLE_UNIFORM_SCALE_ANIMATION:
return TSTR(_T("Enable uniform scale animation"));
case PB_SEQ_ENABLE_ARBITRARY_SCALE_ANIMATION:
return TSTR(_T("Enable arbitrary scale animation"));
case PB_SEQ_FORCE_SCALE_ANIMATION:
return TSTR(_T("Force scale animation"));
default:
return TSTR(_T(""));
}
}
RefTargetHandle SequenceObject::Clone(RemapDir& remap)
{
SequenceObject* newob = new SequenceObject();
newob->ReplaceReference(0,pblock->Clone(remap));
newob->ivalid.SetEmpty();
return newob;
}
SequenceObject::SequenceObject()
{
ivalid.SetEmpty();
pblock = NULL;
SetAFlag(A_OBJ_CREATING);
// Create the parameter block and make a reference to it.
MakeRefByID(FOREVER, 0,
CreateParameterBlock( curVersion.desc, PBLOCK_LENGTH, CURRENT_VERSION));
// assert(pblock);
// if (!pblock)
// // need a way to signal an error
// return;
// Initialize the default values.
pblock->SetValue(PB_SEQ_BEGIN_END, 0, false);
pblock->SetValue(PB_SEQ_CYCLIC, 0, (bool)defaultCyclic);
pblock->SetValue(PB_SEQ_BLEND, 0, (bool)defaultBlend);
pblock->SetValue(PB_SEQ_LAST_FIRST_FRAME_SAME, 0, (bool)defaultFirstLastFrameSame);
pblock->SetValue(PB_SEQ_USE_FRAME_RATE, 0, (bool)defaultUseFrameRate);
pblock->SetValue(PB_SEQ_FRAME_RATE, 0, defaultFrameRate);
pblock->SetValue(PB_SEQ_NUM_FRAMES, 0, defaultNumFrames);
pblock->SetValue(PB_SEQ_IGNORE_GROUND_TRANSFORM, 0, (bool)defaultIgnoreGroundTransform);
pblock->SetValue(PB_SEQ_USE_GROUND_FRAME_RATE, 0, (bool)defaultUseGroundFrameRate);
pblock->SetValue(PB_SEQ_GROUND_FRAME_RATE, 0, defaultGroundFrameRate);
pblock->SetValue(PB_SEQ_NUM_GROUND_FRAMES, 0, defaultNumGroundFrames);
pblock->SetValue(PB_SEQ_ENABLE_MORPH_ANIMATION, 0, (bool)defaultEnableMorphAnimation);
pblock->SetValue(PB_SEQ_ENABLE_VIS_ANIMATION, 0, (bool)defaultEnableVisAnimation);
pblock->SetValue(PB_SEQ_ENABLE_TRANSFORM_ANIMATION, 0, (bool)defaultEnableTransformAnimation);
pblock->SetValue(PB_SEQ_ENABLE_TEXTURE_ANIMATION, 0, (bool)defaultEnableTextureAnimation);
pblock->SetValue(PB_SEQ_ENABLE_IFL_ANIMATION, 0, (bool)defaultEnableIflAnimation);
pblock->SetValue(PB_SEQ_ENABLE_DECAL_ANIMATION, 0, (bool)defaultEnableDecalAnimation);
pblock->SetValue(PB_SEQ_ENABLE_DECAL_FRAME_ANIMATION, 0, (bool)defaultEnableDecalFrameAnimation);
pblock->SetValue(PB_SEQ_FORCE_MORPH_ANIMATION, 0, (bool)defaultForceMorphAnimation);
pblock->SetValue(PB_SEQ_FORCE_VIS_ANIMATION, 0, (bool)defaultForceVisAnimation);
pblock->SetValue(PB_SEQ_FORCE_TRANSFORM_ANIMATION, 0, (bool)defaultForceTransformAnimation);
pblock->SetValue(PB_SEQ_FORCE_TEXTURE_ANIMATION, 0, (bool)defaultForceTextureAnimation);
pblock->SetValue(PB_SEQ_FORCE_DECAL_ANIMATION, 0, (bool)defaultForceDecalAnimation);
pblock->SetValue(PB_SEQ_DEFAULT_PRIORITY, 0, defaultDefaultSequencePriority);
pblock->SetValue(PB_SEQ_BLEND_REFERENCE_TIME, 0, defaultBlendReferenceTime);
pblock->SetValue(PB_SEQ_OVERRIDE_DURATION, 0, (bool)defaultOverrideDuration);
pblock->SetValue(PB_SEQ_DURATION, 0, defaultDuration);
pblock->SetValue(PB_SEQ_ENABLE_UNIFORM_SCALE_ANIMATION, 0, (bool)defaultEnableUniformScaleAnimation);
pblock->SetValue(PB_SEQ_ENABLE_ARBITRARY_SCALE_ANIMATION, 0, (bool)defaultEnableArbitraryScaleAnimation);
pblock->SetValue(PB_SEQ_FORCE_SCALE_ANIMATION, 0, (bool)defaultForceScaleAnimation);
}
SequenceObject::~SequenceObject()
{
DeleteAllRefsFromMe();
}
//
// Reference Managment:
//
IOResult SequenceObject::Load(ILoad *iload)
{
// This is the callback that corrects for any older versions
// of the parameter block structure found in the MAX file
// being loaded.
iload->RegisterPostLoadCallback(new ParamBlockPLCB(versions,NUM_OLDVERSIONS,&curVersion,this,0));
return IO_OK;
}
//------------------------------------------------------
// Sequence object descriptor declaration & implementation
//------------------------------------------------------
class SequenceObjClassDesc:public ClassDesc
{
public:
S32 IsPublic() { return 1; }
void * Create(BOOL loading = FALSE) { return new SequenceObject; }
const TCHAR * ClassName() { return GetString(IDS_DB_SEQUENCE); }
SClass_ID SuperClassID() { return HELPER_CLASS_ID; }
Class_ID ClassID() { return SEQUENCE_CLASS_ID; }
const TCHAR * Category() { return GetString(IDS_DB_GENERAL); }
// following functions allow setting of parameter defaults...
// worthless unless all 3 are implemented
// void ResetClassParams(BOOL fileReset)
// {
// if(fileReset)
// resetSequenceDefaults();
// }
// HasClassParams?
// EditClassParams?
};
static SequenceObjClassDesc sequenceObjDesc;
ClassDesc * GetSequenceDesc() { return &sequenceObjDesc; }

View File

@ -0,0 +1,289 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "max2dtsExporter/skinHelper.h"
#include "max2dtsExporter/sceneEnum.h"
#include "max2dtsExporter/exportUtil.h"
#include "max2dtsExporter/exporter.h"
#include "core/tvector.h"
#pragma pack(push,8)
#include <Max.h>
#include <decomp.h>
#include <dummy.h>
#include <ISkin.h>
#include <modstack.h>
#pragma pack(pop)
#define printDump SceneEnumProc::printDump
class SkinHelperClassDesc:public ClassDesc {
public:
int IsPublic() {return 1;}
void * Create(BOOL loading = FALSE) {return new SkinHelper();}
const TCHAR * ClassName() {return "Skin Helper";}
SClass_ID SuperClassID() {return WSM_CLASS_ID;}
Class_ID ClassID() {return SKINHELPER_CLASS_ID;}
const TCHAR* Category() {return "General";}
void ResetClassParams(BOOL) {}
};
static SkinHelperClassDesc SkinHelperDesc;
ClassDesc* GetSkinHelperDesc() {return &SkinHelperDesc;}
static BOOL CALLBACK SkinHelperDlgProc(
HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
SkinHelper *ins = (SkinHelper*)GetWindowLong(hWnd,GWL_USERDATA);
if (!ins && msg!=WM_INITDIALOG) return FALSE;
switch (msg) {
case WM_INITDIALOG:
ins = (SkinHelper*)lParam;
SetWindowLong(hWnd,GWL_USERDATA,lParam);
ins->hParams = hWnd;
break;
case WM_DESTROY:
break;
case WM_COMMAND:
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
ins->ip->RollupMouseMessage(hWnd,msg,wParam,lParam);
break;
default:
return FALSE;
}
return TRUE;
}
IObjParam *SkinHelper::ip = NULL;
HWND SkinHelper::hParams = NULL;
//--- SkinHelper -------------------------------------------------------
SkinHelper::SkinHelper()
{
}
SkinHelper::~SkinHelper()
{
}
S32 gDamnit=0;
void SkinHelper::SetReference(S32 i, RefTargetHandle rtarg)
{
gDamnit++;
}
Interval SkinHelper::LocalValidity(TimeValue t)
{
// if being edited, return NEVER forces a cache to be built
// after previous modifier.
if (TestAFlag(A_MOD_BEING_EDITED))
return NEVER;
//TODO: Return the validity interval of the modifier
return NEVER;
}
RefTargetHandle SkinHelper::Clone(RemapDir& remap)
{
SkinHelper* newmod = new SkinHelper();
//TODO: Add the cloning code here
return(newmod);
}
void SkinHelper::ModifyObject(TimeValue t, ModContext &mc, ObjectState * os, INode *pNode)
{
ISkin * skin;
ISkinContextData * skinData;
if (!pNode)
return;
findSkinData(pNode,&skin,&skinData);
if (!skin || !skinData)
return;
TriObject * triObj = (TriObject*)os->obj->ConvertToType(0,Class_ID(TRIOBJ_CLASS_ID,0));
if (triObj!=os->obj)
delete triObj;
else
modifyTriObject(triObj,skin,skinData);
PatchObject * patchObj = (PatchObject*)os->obj->ConvertToType(0,Class_ID(PATCHOBJ_CLASS_ID,0));
if (patchObj!=os->obj)
delete patchObj;
else
modifyPatchObject(patchObj,skin,skinData);
}
void SkinHelper::modifyTriObject(TriObject * triObj, ISkin * skin, ISkinContextData * skinData)
{
S32 numBones = skin->GetNumBones();
Mesh & maxMesh = triObj->mesh;
S32 numVerts = maxMesh.getNumVerts();
S32 numTVerts = maxMesh.getNumMapVerts(1);
if (numVerts!=skinData->GetNumPoints())
return;
S32 numChannels = 2+((numBones+1)>>1);
UVVert tv(0,0,0);
for (S32 i=2; i<numChannels; i++)
{
maxMesh.setMapSupport(i,true);
maxMesh.setNumMapVerts(i,numVerts);
for (S32 j=0; j<numVerts; j++)
maxMesh.setMapVert(i,j,tv);
maxMesh.setNumMapFaces(i,maxMesh.getNumFaces());
// copy map faces from the first channel
for (S32 j=0; j<maxMesh.getNumFaces(); j++)
{
Face & face = maxMesh.faces[j];
TVFace & tvFace = maxMesh.mapFaces(i)[j];
tvFace.t[0] = face.v[0];
tvFace.t[1] = face.v[1];
tvFace.t[2] = face.v[2];
}
}
for (S32 v=0; v<numVerts; v++)
{
for (S32 i=0; i<skinData->GetNumAssignedBones(v); i++)
{
S32 bone = skinData->GetAssignedBone(v,i);
F32 w = skinData->GetBoneWeight(v,i);
UVVert tv = maxMesh.mapVerts(2+(bone>>1))[v];
if (bone&1)
tv.y = w;
else
tv.x = w;
maxMesh.setMapVert(2+(bone>>1),v,tv);
}
}
}
void SkinHelper::modifyPatchObject(PatchObject * patchObj, ISkin * skin, ISkinContextData * skinData)
{
S32 numBones = skin->GetNumBones();
S32 numPoints = skinData->GetNumPoints();
S32 i;
PatchMesh & maxMesh = patchObj->patch;
S32 numVerts = maxMesh.getNumVerts();
if (numVerts>numPoints)
// points should be more than verts...first set of points are the verts, the rest are control verts
// we don't do anything with those weights...it limits the surface deformations that can take
// place, but it's all we can do...
return;
if (!numBones)
return;
S32 numChannels = 2+((numBones+1)>>1);
S32 numTVerts = maxMesh.getNumMapVerts(1);
UVVert tv(0,0,0);
maxMesh.setNumMaps(numChannels);
for (i=2; i<numChannels; i++)
{
// prepare each channel...
S32 j;
maxMesh.setNumMapVerts(i,numVerts);
for (j=0; j<numVerts; j++)
maxMesh.getMapVert(i,j) = tv;
// set up tv patch faces
maxMesh.setNumMapPatches(i,maxMesh.getNumPatches());
for (j=0; j<maxMesh.getNumPatches(); j++)
{
Patch & patch = maxMesh.patches[j];
TVPatch & tvPatch = maxMesh.getMapPatch(i,j);
tvPatch.tv[0] = patch.v[0];
tvPatch.tv[1] = patch.v[1];
tvPatch.tv[2] = patch.v[2];
tvPatch.tv[3] = patch.v[3];
}
}
for (S32 v=0; v<numVerts; v++)
{
for (i=0; i<skinData->GetNumAssignedBones(v); i++)
{
S32 bone = skinData->GetAssignedBone(v,i);
F32 w = skinData->GetBoneWeight(v,i);
S32 channel = 2 + (bone>>1);
UVVert & tv = maxMesh.getMapVert(channel,v);
if (bone&1)
tv.y = w;
else
tv.x = w;
}
}
}
void SkinHelper::BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev )
{
this->ip = ip;
if (!hParams) {
hParams = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_SKINHELP_PANEL),
SkinHelperDlgProc,
GetString(IDS_SKINHELP_PARAMS),
(LPARAM)this);
ip->RegisterDlgWnd(hParams);
} else {
SetWindowLong(hParams,GWL_USERDATA,(LONG)this);
}
}
void SkinHelper::EndEditParams( IObjParam *ip, ULONG flags,Animatable *next)
{
ip->UnRegisterDlgWnd(hParams);
ip->DeleteRollupPage(hParams);
hParams = NULL;
this->ip = NULL;
}
//From ReferenceMaker
RefResult SkinHelper::NotifyRefChanged(
Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message)
{
//TODO: Add code to handle the various reference changed messages
return REF_SUCCEED;
}
//From Object
BOOL SkinHelper::HasUVW()
{
//TODO: Return whether the object has UVW coordinates or not
return TRUE;
}
void SkinHelper::SetGenUVW(BOOL sw)
{
if (sw==HasUVW()) return;
//TODO: Set the plugin internal value to sw
}
IOResult SkinHelper::Load(ILoad *iload)
{
//TODO: Add code to allow plugin to load its data
return IO_OK;
}
IOResult SkinHelper::Save(ISave *isave)
{
//TODO: Add code to allow plugin to save its data
return IO_OK;
}

View File

@ -0,0 +1,85 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef __SKINHELPER__H
#define __SKINHELPER__H
#pragma pack(push,8)
#include <Max.h>
#include <istdplug.h>
#include <iparamb2.h>
#include <iparamm2.h>
#pragma pack(pop)
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _MAXUTIL_H_
#include "max2dtsExporter/maxUtil.h"
#endif
#define SKINHELPER_CLASS_ID Class_ID(0x20dfdba0, 0x60646cb4)
extern ClassDesc* GetSkinHelperDesc();
extern TCHAR *GetString(S32);
class SkinHelper : public WSModifier
{
public:
static HWND hParams;
static IObjParam *ip; //Access to the interface
// From Animatable
TCHAR *GetObjectName() { return "SkinHelper"; }
//From Modifier
ChannelMask ChannelsUsed() { return TEXMAP_CHANNEL; }
ChannelMask ChannelsChanged() { return TEXMAP_CHANNEL; }
void ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node);
void modifyTriObject(TriObject *, ISkin *, ISkinContextData *);
void modifyPatchObject(PatchObject *, ISkin *, ISkinContextData *);
Class_ID InputType() {return defObjectClassID;}
Interval LocalValidity(TimeValue t);
// From BaseObject
BOOL ChangeTopology() {return FALSE;}
CreateMouseCallBack* GetCreateMouseCallBack() {return NULL;}
void BeginEditParams(IObjParam *ip, ULONG flags,Animatable *prev);
void EndEditParams(IObjParam *ip, ULONG flags,Animatable *next);
Interval GetValidity(TimeValue t);
// Automatic texture support
BOOL HasUVW();
void SetGenUVW(BOOL sw);
// Loading/Saving
IOResult Load(ILoad *iload);
IOResult Save(ISave *isave);
//From Animatable
Class_ID ClassID() {return SKINHELPER_CLASS_ID;}
SClass_ID SuperClassID() { return WSM_CLASS_ID; }
void GetClassName(TSTR& s) {s = "SkinHelper"; }
RefTargetHandle Clone( RemapDir &remap );
RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message);
int NumSubs() { return 0; }
TSTR SubAnimName(int i) { return _T(""); }
Animatable* SubAnim(int i) { return NULL; }
int NumRefs() { return 0; }
RefTargetHandle GetReference(int i) { return NULL; }
void SetReference(int i, RefTargetHandle rtarg);
void DeleteThis() { delete this; }
//Constructor/Destructor
SkinHelper();
~SkinHelper();
};
#endif // __SKINHELPER__H

907
tools/max2dtsExporter/stripper.cc Executable file
View File

@ -0,0 +1,907 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "max2dtsExporter/stripper.h"
F32 Stripper::adjacencyWeight = 5;
F32 Stripper::noswapWeight = 3;
F32 Stripper::alreadyCachedWeight = 1;
U32 Stripper::cacheSize = 16;
U32 Stripper::simK = 5;
Stripper::Stripper(Vector<TSDrawPrimitive> & _faces, Vector<U16> & _faceIndices)
: faces(_faces), faceIndices(_faceIndices), adjacent(_faces.size(),_faces.size())
{
// keep track of whether face used in a strip yet
used.setSize(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;
errorStr = NULL;
}
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);
errorStr = NULL;
}
Stripper::~Stripper()
{
dFree(errorStr);
}
void Stripper::testCache(S32 addedFace)
{
S32 * cache = &vertexCache.last();
// make sure last 3 verts on strip list are last 3 verts in cache
U16 * indices = &stripIndices.last();
if (*indices!=*cache || *(indices-1)!=*(cache-1) || *(indices-2)!=*(cache-2))
{
setExportError("Assertion failed when stripping (11)");
return;
}
if (addedFace>=0)
{
// make sure current face is still last 3 items in the cache
TSDrawPrimitive & face = faces[addedFace];
U32 idx0 = faceIndices[face.start+0];
U32 idx1 = faceIndices[face.start+1];
U32 idx2 = faceIndices[face.start+2];
if ( idx0!=*(cache) && idx0!=*(cache-1) && idx0!=*(cache-2))
{
setExportError("Assertion failed when stripping (8)");
return;
}
if ( idx1!=*(cache) && idx1!=*(cache-1) && idx1!=*(cache-2))
{
setExportError("Assertion failed when stripping (9)");
return;
}
if ( idx2!=*(cache) && idx2!=*(cache-1) && idx2!=*(cache-2))
{
setExportError("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 (isError()) return;
// main strip loop...
U32 start, end, i, sz;
Vector<TSDrawPrimitive> someFaces;
Vector<U16> someIndices;
for (start = 0; start<faces.size(); start=end)
{
for (end=start; end<faces.size() && faces[start].matIndex==faces[end].matIndex; 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.last().start = someIndices.size();
someIndices.push_back(faceIndices[faces[i].start + 0]);
someIndices.push_back(faceIndices[faces[i].start + 1]);
someIndices.push_back(faceIndices[faces[i].start + 2]);
}
// strip these...
Stripper someStrips(someFaces,someIndices);
someStrips.copyParams(this);
someStrips.makeStripsB();
if (isError()) return;
// copy these strips into our arrays
sz = strips.size();
strips.setSize(sz+someStrips.strips.size());
for (i=0; i<someStrips.strips.size(); i++)
{
strips[i+sz] = someStrips.strips[i];
strips[i+sz].start += stripIndices.size();
}
sz = stripIndices.size();
stripIndices.setSize(sz+someStrips.stripIndices.size());
dMemcpy(&stripIndices[sz],someStrips.stripIndices.address(),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 (isError()) return;
// set adjacency info
setAdjacency(0,faces.size());
while (1)
{
strips.increment();
TSDrawPrimitive & strip = strips.last();
strip.start = stripIndices.size();
strip.numElements = 0;
if (faces[0].matIndex & TSDrawPrimitive::NoMaterial)
strip.matIndex = TSDrawPrimitive::NoMaterial;
else
strip.matIndex = faces[0].matIndex & TSDrawPrimitive::MaterialMask;
strip.matIndex |= TSDrawPrimitive::Strip | TSDrawPrimitive::Indexed;
if (!startStrip(strip,0,faces.size()))
{
strips.decrement();
break;
}
while (addStrip(strip,0,faces.size()));
// if already encountered an error, then
// we'll just go through the motions
if (isError()) return;
}
// let's make sure everything is legit up till here
U32 i;
for (i=0; i<faces.size(); i++)
{
if (!used[i])
{
setExportError("Assertion failed when stripping (1)");
return;
}
}
for (i=0; i<numAdjacent.size(); i++)
{
if (numAdjacent[i])
{
setExportError("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])
{
setExportError("Assertion failed when stripping (3)");
return;
}
}
}
/*
void Stripper::makeStrips()
{
// if already encountered an error, then
// we'll just go through the motions
if (isError()) return;
// main strip loop...
U32 start, end, i;
for (start = 0; start<faces.size(); start=end)
{
for (end=start; end<faces.size() && faces[start].matIndex==faces[end].matIndex; end++)
;
// set adjacency info
setAdjacency(start,end);
while (1)
{
strips.increment();
TSDrawPrimitive & strip = strips.last();
strip.start = stripIndices.size();
strip.numElements = 0;
if (faces[start].matIndex & TSDrawPrimitive::NoMaterial)
strip.matIndex = TSDrawPrimitive::NoMaterial;
else
strip.matIndex = faces[start].matIndex & TSDrawPrimitive::MaterialMask;
strip.matIndex |= TSDrawPrimitive::Strip | TSDrawPrimitive::Indexed;
if (!startStrip(strip,start,end))
{
strips.decrement();
break;
}
while (addStrip(strip,start,end));
// if already encountered an error, then
// we'll just go through the motions
if (isError()) return;
}
// let's make sure everything is legit up till here
for (i=start; i<end; i++)
{
if (!used[i])
{
setExportError("Assertion failed when stripping (1)");
return;
}
}
for (i=0; i<numAdjacent.size(); i++)
{
if (numAdjacent[i])
{
setExportError("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])
{
setExportError("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 (isError()) return 0;
TSDrawPrimitive & strip = strips.last();
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.increment();
TSDrawPrimitive & strip = strips.last();
strip.start = stripIndices.size();
strip.numElements = 0;
if (faces[startFace].matIndex & TSDrawPrimitive::NoMaterial)
strip.matIndex = TSDrawPrimitive::NoMaterial;
else
strip.matIndex = faces[startFace].matIndex & TSDrawPrimitive::MaterialMask;
strip.matIndex |= TSDrawPrimitive::Strip | TSDrawPrimitive::Indexed;
if (!startStrip(strip,startFace,endFace))
{
strips.decrement();
break;
}
len--;
while (len && addStrip(strip,startFace,endFace))
len--;
// if already encountered an error, then
// we'll just go through the motions
if (isError()) 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 (isError()) return;
// two faces adjacent only if wound the same way (so shared edge must appear in opp. order)
S32 i,j;
numAdjacent.setSize(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].start + 0];
U32 idx1 = faceIndices[faces[i].start + 1];
U32 idx2 = faceIndices[faces[i].start + 2];
for (j=i+1; j<endFace; j++)
{
// the j-indices...
U32 jdx0 = faceIndices[faces[j].start + 0];
U32 jdx1 = faceIndices[faces[j].start + 1];
U32 jdx2 = faceIndices[faces[j].start + 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))
{
setExportError("wtf (1)");
return;
}
adjacent.setBit(i,j);
adjacent.setBit(j,i);
if (!adjacent.isSet(i,j) || !adjacent.isSet(j,i))
{
setExportError("wtf (2)");
return;
}
numAdjacent[i]++;
numAdjacent[j]++;
}
}
}
}
void Stripper::clearCache()
{
vertexCache.setSize(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++;
vertexCache.erase((U32)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...
vertexCache.erase((U32)0);
vertexCache.insert(vertexCache.size()-posFromBack);
vertexCache[vertexCache.size()-1-posFromBack] = vertexIndex;
}
bool Stripper::startStrip(TSDrawPrimitive & strip, S32 startFace, S32 endFace)
{
// if already encountered an error, then
// we'll just go through the motions
if (isError()) 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].start + 0];
U32 idx1 = faceIndices[faces[i].start + 1];
U32 idx2 = faceIndices[faces[i].start + 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].start + 0]);
addToCache(stripIndices.last());
stripIndices.push_back(faceIndices[faces[bestFace].start + 1]);
addToCache(stripIndices.last());
stripIndices.push_back(faceIndices[faces[bestFace].start + 2]);
addToCache(stripIndices.last());
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)
{
setExportError("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 (isError()) return;
Vector<S32> prev;
addVert = -1;
TSDrawPrimitive & addFace = faces[face];
U32 idx0 = faceIndices[addFace.start+0];
U32 idx1 = faceIndices[addFace.start+1];
U32 idx2 = faceIndices[addFace.start+2];
S32 * cache = &vertexCache.last();
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)
{
setExportError("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, 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.last();
tmp = *(cache-2);
*(cache-2) = *(cache-1);
*(cache-1) = *cache;
*cache = tmp;
testCache(currentFace);
}
bool Stripper::swapNeeded(S32 oldVert0, S32 oldVert1)
{
S32 * cache = &vertexCache.last();
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].start;
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 (isError()) 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].start + 0];
U32 idx1 = faceIndices[faces[face].start + 1];
U32 idx2 = faceIndices[faces[face].start + 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
{
setExportError("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 (isError()) 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].start + 0];
U32 idx1 = faceIndices[faces[face].start + 1];
U32 idx2 = faceIndices[faces[face].start + 2];
U32 last = stripIndices.last();
if (last==idx0 || last==idx1 || last==idx2)
return true;
return false;
}
bool Stripper::addStrip(TSDrawPrimitive & strip, S32 startFace, S32 endFace)
{
// if already encountered an error, then
// we'll just go through the motions
if (isError()) 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.start,stripIndices);
if (++doh==3)
{
setExportError("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];
stripIndices.insert(sz-1);
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)
{
setExportError("Assertion failed when stripping (7)");
return false;
}
}
}
// mark face as used
used[bestFace] = true;
numAdjacent[bestFace] = 0;
currentFace = bestFace;
return true;
}

View File

@ -0,0 +1,87 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _TSSHAPE_H_
#include "ts/tsShape.h"
#endif
#ifndef _TVECTOR_H_
#include "core/tVector.h"
#endif
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _BITMATRIX_H_
#include "core/bitMatrix.h"
#endif
class Stripper
{
Vector<S32> numAdjacent;
Vector<bool> used;
BitMatrix adjacent;
Vector<S32> vertexCache;
Vector<S32> recentFaces;
S32 currentFace;
bool limitStripLength;
S32 bestLength;
U32 cacheMisses;
Vector<TSDrawPrimitive> strips;
Vector<U16> stripIndices;
Vector<TSDrawPrimitive> & faces;
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, 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(TSDrawPrimitive & strip, S32 startFace, S32 endFace);
bool addStrip(TSDrawPrimitive & 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);
char * errorStr;
void setExportError(const char * str) { errorStr = errorStr ? errorStr : dStrdup(str); }
public:
Stripper(Vector<TSDrawPrimitive> & faces, Vector<U16> & indices);
Stripper(Stripper &);
~Stripper();
void makeStrips();
S32 continueStrip(S32 startFace, S32 endFace, S32 len, S32 restart); // used for simulation...
void getStrips(Vector<TSDrawPrimitive> & s, Vector<U16> & si) { s=strips; si=stripIndices; }
void setLimitStripLength(bool lim) { limitStripLength = lim; }
void resetCacheMisses() { cacheMisses = 0; }
U32 getCacheMisses() { return cacheMisses; }
const char * getError() { return errorStr; }
bool isError() { return errorStr!=NULL; }
// adjust strip building strategy
static F32 adjacencyWeight;
static F32 noswapWeight;
static F32 alreadyCachedWeight;
static U32 cacheSize;
static U32 simK;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _TRANS_SORT
#define _TRANS_SORT
#ifndef _MMATH_H_
#include "math/mMath.h"
#endif
#ifndef _TSINTEGERSET_H_
#include "ts/tsIntegerSet.h"
#endif
#ifndef _TSSORTEDMESH_H_
#include "ts/tsSortedMesh.h"
#endif
struct TSDrawPrimitive;
class TSIntegerSet;
class TranslucentSort
{
Vector<TSIntegerSet*> frontClusters;
Vector<TSIntegerSet*> backClusters;
Vector<S32> middleCluster;
Point3F 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;
Point3F normal;
F32 k;
TSIntegerSet isInFrontOfMe;
TSIntegerSet isBehindMe;
TSIntegerSet isCutByMe;
TSIntegerSet isCoplanarWithMe;
};
Vector<FaceInfo*> faceInfoList;
Vector<FaceInfo*> saveFaceInfoList;
Vector<TSDrawPrimitive> & mFaces;
Vector<U16> & mIndices;
Vector<Point3F> & mVerts;
Vector<Point3F> & mNorms;
Vector<Point2F> & mTVerts;
void initFaces();
void initFaceInfo(TSDrawPrimitive & face, FaceInfo & faceInfo, bool setPriority = true);
void setFaceInfo(TSDrawPrimitive & face, FaceInfo & faceInfo);
void clearFaces(TSIntegerSet &);
void saveFaceInfo();
void restoreFaceInfo();
void addFaces(TSIntegerSet *, Vector<TSDrawPrimitive> & faces, Vector<U16> & indices, bool continueLast = false);
void addFaces(Vector<TSIntegerSet *> &, Vector<TSDrawPrimitive> & faces, Vector<U16> & indices, bool continueLast = false);
void addOrderedFaces(Vector<S32> &, Vector<TSDrawPrimitive> &, Vector<U16> & indices, bool continueLast = false);
void splitFace(S32 faceIndex, Point3F normal, F32 k);
void splitFace2(S32 faceIndex, Point3F normal, F32 k);
void sort();
// routines for sorting faces when there is no perfect solution for all cases
void copeSort(Vector<S32> &);
void layerSort(Vector<S32> &, bool upFirst);
// these are for debugging
bool anyInFrontOfPlane(Point3F normal, F32 k);
bool anyBehindPlane(Point3F normal, F32 k);
//
void generateClusters(Vector<TSSortedMesh::Cluster> & clusters, Vector<TSDrawPrimitive> & faces, Vector<U16> & indices, S32 retIndex = -1);
TranslucentSort(TranslucentSort *);
TranslucentSort(Vector<TSDrawPrimitive> & faces,
Vector<U16> & indices,
Vector<Point3F> & verts,
Vector<Point3F> & norms,
Vector<Point2F> & tverts,
S32 numBigFaces, S32 maxDepth, bool zLayerUp, bool zLayerDown);
~TranslucentSort();
public:
static void generateSortedMesh(TSSortedMesh * mesh, S32 numBigFaces, S32 maxDepth, bool zLayerUp, bool zLayerDown);
};
#endif // _TRANS_SORT