tge/lib/dtsSDK/DTSShape.cpp
2025-02-17 23:17:30 -06:00

776 lines
23 KiB
C++
Executable File

#pragma warning ( disable: 4786 )
#include "DTSShape.h"
#include "DTSBrushMesh.h"
#include "DTSOutputStream.h"
#include "DTSInputStream.h"
#include "DTSEndian.h"
#include "DTSTypes.h"
#include <map>
#ifdef _WIN32
#include <windows.h>
#endif
// Helper macro -- assumes output stream "out"
#define writeEndian(a,sz) out.write((char*) &FIX_ENDIAN(a),sz)
namespace DTS
{
// -----------------------------------------------------------------------
// Constructor (create an empty shape)
// -----------------------------------------------------------------------
Shape::Shape()
{
}
Sequence::Sequence()
{
baseDecalState = 0 ;
baseObjectState = 0 ;
baseRotation = 0 ;
baseScale = 0 ;
baseTranslation = 0 ;
duration = 1.0f ;
firstGroundFrame = 0 ;
flags = 0 ;
nameIndex = 0 ;
numGroundFrames = 0 ;
numKeyFrames = 0 ;
priority = 1 ;
toolBegin = 0.0f ;
}
// -----------------------------------------------------------------------
// Loads a DTS file
// -----------------------------------------------------------------------
void Shape::read (std::istream &in)
{
InputStream stream(in) ;
int version = stream.version() ;
if (version < 19)
{
#ifdef _WIN32
MessageBox (NULL, "The DTS file is of a older, unsupported version", "Error",
MB_ICONHAND | MB_OK) ;
#else
assert(0 && "The DTS file is of a older, unsupported version");
#endif
return ;
}
// Header
int numNodes ;
int numObjects ;
int numDecals ;
int numSubshapes ;
int numIFLmaterials ;
int numNodeRotations ;
int numNodeTranslations ;
int numNodeScalesUniform ;
int numNodeScalesAligned ;
int numNodeScalesArbitrary ;
int numGroundFrames ;
int numObjectStates ;
int numDecalStates ;
int numTriggers ;
int numDetailLevels ;
int numMeshes ;
int numSkins ;
int numNames ;
stream >> numNodes >> numObjects >> numDecals >> numSubshapes >> numIFLmaterials ;
if (version < 22)
{
stream >> numNodeRotations ;
numNodeRotations -= numNodes ;
numNodeTranslations = numNodeRotations ;
numNodeScalesUniform = 0 ;
numNodeScalesAligned = 0 ;
numNodeScalesArbitrary = 0 ;
numGroundFrames = 0 ;
}
else
{
stream >> numNodeRotations ;
stream >> numNodeTranslations ;
stream >> numNodeScalesUniform ;
stream >> numNodeScalesAligned ;
stream >> numNodeScalesArbitrary ;
if (version > 23)
stream >> numGroundFrames ;
}
stream >> numObjectStates ;
stream >> numDecalStates ;
stream >> numTriggers ;
stream >> numDetailLevels ;
stream >> numMeshes ;
if (version < 23)
stream >> numSkins ;
else
numSkins = 0 ;
stream >> numNames ;
int smallestSizeInt ;
stream >> smallestSizeInt ;
stream >> smallestDetailLevel ;
smallestSize = (float)smallestSizeInt ;
stream.readCheck(0) ;
// Bounds
stream >> radius ;
stream >> tubeRadius ;
stream >> center ;
stream >> bounds ;
stream.readCheck(1) ;
// Nodes
nodes.resize(numNodes) ;
stream >> nodes ;
stream.readCheck(2) ;
// Objects
objects.resize(numObjects) ;
stream >> objects ;
stream.readCheck(3) ;
// Decals
decals.resize(numDecals) ;
stream >> decals ;
stream.readCheck(4) ;
// IFL Materials
IFLmaterials.resize(numIFLmaterials) ;
stream >> IFLmaterials ;
stream.readCheck(5) ;
// Subshapes
subshapes.resize(numSubshapes) ;
std::vector<Subshape>::iterator shape ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream >> shape->firstNode ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream >> shape->firstObject ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream >> shape->firstDecal ;
stream.readCheck(6) ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream >> shape->numNodes ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream >> shape->numObjects ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream >> shape->numDecals ;
stream.readCheck(7) ;
// MeshIndexList (obsolete data)
if (version < 16)
{
int size, temp ;
stream >> size ;
while (size--) stream >> temp ;
}
// Default translations and rotations
nodeDefRotations.resize(numNodes) ;
nodeDefTranslations.resize(numNodes) ;
for (int n = 0 ; n < nodes.size() ; n++)
{
stream >> nodeDefRotations[n] ;
stream >> nodeDefTranslations[n] ;
}
// Animation translations and rotations
nodeTranslations.resize(numNodeTranslations) ;
nodeRotations.resize(numNodeRotations) ;
stream >> nodeTranslations ;
stream >> nodeRotations ;
stream.readCheck(8) ;
// Default scales
nodeScalesUniform.resize (numNodeScalesUniform) ;
nodeScalesAligned.resize (numNodeScalesAligned) ;
nodeScalesArbitrary.resize (numNodeScalesArbitrary) ;
if (version > 21)
{
stream >> numNodeScalesUniform ;
stream >> numNodeScalesAligned ;
stream >> numNodeScalesArbitrary ;
stream.readCheck(9) ;
}
// Ground transformations
groundTranslations.resize (numGroundFrames) ;
groundRotations.resize (numGroundFrames) ;
if (version > 23)
{
stream >> groundTranslations ;
stream >> groundRotations ;
stream.readCheck() ;
}
// Object states
objectStates.resize (numObjectStates) ;
stream >> objectStates ;
stream.readCheck() ;
// Decal states
decalStates.resize (numDecalStates) ;
stream >> decalStates ;
stream.readCheck() ;
// Triggers
triggers.resize (numTriggers) ;
stream >> triggers ;
stream.readCheck() ;
// Detail Levels
detailLevels.resize (numDetailLevels) ;
stream >> detailLevels ;
stream.readCheck() ;
// Meshes
meshes.resize (numMeshes) ;
stream >> meshes ;
stream.readCheck() ;
}
// -----------------------------------------------------------------------
// Saves a DTS file
// -----------------------------------------------------------------------
void Shape::save (std::ostream & out) const
{
OutputStream stream (out, 24) ;
// Header
stream << (int) nodes.size() ;
stream << (int) objects.size() ;
stream << (int) decals.size() ;
stream << (int) subshapes.size() ;
stream << (int) IFLmaterials.size() ;
stream << (int) nodeRotations.size() ;
stream << (int) nodeTranslations.size() ;
stream << (int) nodeScalesUniform.size() ;
stream << (int) nodeScalesAligned.size() ;
stream << (int) nodeScalesArbitrary.size() ;
stream << (int) groundTranslations.size() ;
stream << (int) objectStates.size() ;
stream << (int) decalStates.size() ;
stream << (int) triggers.size() ;
stream << (int) detailLevels.size() ;
stream << (int) meshes.size() ;
stream << (int) names.size() ;
stream << (int) smallestSize ;
stream << smallestDetailLevel ;
stream.storeCheck(0) ;
// Bounds
stream << radius ;
stream << tubeRadius ;
stream << center ;
stream << bounds ;
stream.storeCheck(1) ;
// Nodes
stream << nodes ;
stream.storeCheck(2) ;
// Objects
stream << objects ;
stream.storeCheck(3) ;
// Decals
stream << decals ;
stream.storeCheck(4) ;
// IFL Materials
stream << IFLmaterials ;
stream.storeCheck(5) ;
// Subshapes
std::vector<Subshape>::const_iterator shape ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream << shape->firstNode ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream << shape->firstObject ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream << shape->firstDecal ;
stream.storeCheck(6) ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream << shape->numNodes ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream << shape->numObjects ;
for (shape = subshapes.begin() ; shape != subshapes.end() ; shape++)
stream << shape->numDecals ;
stream.storeCheck(7) ;
// Default translations and rotations
assert (nodeDefRotations.size() == nodes.size()) ;
assert (nodeDefTranslations.size() == nodes.size()) ;
for (int n = 0 ; n < nodes.size() ; n++)
{
stream << nodeDefRotations[n] ;
stream << nodeDefTranslations[n] ;
}
// Animation translations and rotations
stream << nodeTranslations ; // As current position, we store the same values
stream << nodeRotations ;
stream.storeCheck(8) ;
// Default scales
stream << nodeScalesUniform ;
stream << nodeScalesAligned ;
stream << nodeScalesArbitrary ;
stream << nodeScaleRotsArbitrary ;
stream.storeCheck(9) ;
// Ground transformations
stream << groundTranslations ;
stream << groundRotations ;
stream.storeCheck(10) ;
// Object states
stream << objectStates ;
stream.storeCheck(11) ;
// Decal states
stream << decalStates ;
stream.storeCheck(12) ;
// Triggers
stream << triggers ;
stream.storeCheck(13) ;
// Detail levels
stream << detailLevels ;
stream.storeCheck(14) ;
// Meshes
stream << meshes ;
stream.storeCheck() ; // Many checks stored within the meshes
// Names
stream << names ;
stream.storeCheck() ;
// Finished with the 3-buffer stuff
stream.flush() ;
// Sequences
int numSequences = sequences.size() ;
out.write ((char *)&FIX_ENDIAN(numSequences), 4) ;
for (int seq = 0 ; seq < sequences.size() ; seq++)
{
const Sequence &p = sequences[seq] ;
out.write ((char *) &FIX_ENDIAN(p.nameIndex), 4) ;
out.write ((char *) &FIX_ENDIAN(p.flags), 4) ;
out.write ((char *) &FIX_ENDIAN(p.numKeyFrames), 4) ;
out.write ((char *) &FIX_ENDIAN(p.duration), 4) ;
out.write ((char *) &FIX_ENDIAN(p.priority), 4) ;
out.write ((char *) &FIX_ENDIAN(p.firstGroundFrame), 4) ;
out.write ((char *) &FIX_ENDIAN(p.numGroundFrames), 4) ;
out.write ((char *) &FIX_ENDIAN(p.baseRotation), 4) ;
out.write ((char *) &FIX_ENDIAN(p.baseTranslation), 4) ;
out.write ((char *) &FIX_ENDIAN(p.baseScale), 4) ;
out.write ((char *) &FIX_ENDIAN(p.baseObjectState), 4) ;
out.write ((char *) &FIX_ENDIAN(p.baseDecalState), 4) ;
out.write ((char *) &FIX_ENDIAN(p.firstTrigger), 4) ;
out.write ((char *) &FIX_ENDIAN(p.numTriggers), 4) ;
out.write ((char *) &FIX_ENDIAN(p.toolBegin), 4) ;
write(out,&p.matters.rotation);
write(out,&p.matters.translation);
write(out,&p.matters.scale);
write(out,&p.matters.decal);
write(out,&p.matters.ifl);
write(out,&p.matters.vis);
write(out,&p.matters.frame);
write(out,&p.matters.matframe);
}
// Materials
char materialListVersion = 1 ;
out.write (&materialListVersion, 1) ;
int count = materials.size() ;
out.write ((char *) &FIX_ENDIAN(count), 4) ;
std::vector<Material>::const_iterator mat ;
for (mat = materials.begin() ; mat != materials.end() ; mat++)
{
char length = mat->name.size() ;
out.write (&length, 1) ;
std::string::const_iterator pos = mat->name.begin() ;
while (pos != mat->name.end())
out.write (&*(pos++), 1) ;
}
for (mat = materials.begin() ; mat != materials.end() ; mat++)
out.write ((char *) &FIX_ENDIAN(mat->flags), 4) ;
for (mat = materials.begin() ; mat != materials.end() ; mat++)
out.write ((char *) &FIX_ENDIAN(mat->reflectance), 4) ;
for (mat = materials.begin() ; mat != materials.end() ; mat++)
out.write ((char *) &FIX_ENDIAN(mat->bump), 4) ;
for (mat = materials.begin() ; mat != materials.end() ; mat++)
out.write ((char *) &FIX_ENDIAN(mat->detail), 4) ;
for (mat = materials.begin() ; mat != materials.end() ; mat++)
out.write ((char *) &FIX_ENDIAN(mat->detailScale), 4) ;
for (mat = materials.begin() ; mat != materials.end() ; mat++)
out.write ((char *) &FIX_ENDIAN(mat->reflection), 4) ;
// Done!
}
void Shape::saveSequences(std::ostream & out) const
{
int i;
// write version info
writeEndian((int)24,4);
// write node names
// -- this is how we will map imported sequence nodes to shape nodes
writeEndian(nodes.size(),4);
for (i=0; i<nodes.size(); i++)
{
const char * name = names[nodes[i].name].c_str();
writeEndian(strlen(name),4);
out.write(name,strlen(name));
}
// legacy write -- write zero objects, don't pretend to support object export anymore
writeEndian((int)0,4);
// on import, we will need to adjust keyframe data based on number of
// nodes/objects in this shape...number of nodes can be inferred from
// above, but number of objects cannot be. Write that quantity here:
writeEndian(objects.size(),4);
writeEndian(nodeRotations.size(),4);
for (i=0; i<nodeRotations.size(); i++)
{
writeEndian((short)(nodeRotations[i].x() * 32767.0f),2);
writeEndian((short)(nodeRotations[i].y() * 32767.0f),2);
writeEndian((short)(nodeRotations[i].z() * 32767.0f),2);
writeEndian((short)(nodeRotations[i].w() * 32767.0f),2);
}
writeEndian(nodeTranslations.size(),4);
for (i=0; i<nodeTranslations.size(); i++)
{
writeEndian(nodeTranslations[i].x(),4);
writeEndian(nodeTranslations[i].y(),4);
writeEndian(nodeTranslations[i].z(),4);
}
writeEndian(nodeScalesUniform.size(),4);
for (i=0; i<nodeScalesUniform.size(); i++)
{
writeEndian(nodeScalesUniform[i],4);
}
writeEndian(nodeScalesAligned.size(),4);
for (i=0; i<nodeScalesAligned.size(); i++)
{
writeEndian(nodeScalesAligned[i].x(),4);
writeEndian(nodeScalesAligned[i].y(),4);
writeEndian(nodeScalesAligned[i].z(),4);
}
writeEndian(nodeScaleRotsArbitrary.size(),4);
for (i=0; i<nodeScaleRotsArbitrary.size(); i++)
{
writeEndian((short)(nodeScaleRotsArbitrary[i].x() * 32767.0f),2);
writeEndian((short)(nodeScaleRotsArbitrary[i].y() * 32767.0f),2);
writeEndian((short)(nodeScaleRotsArbitrary[i].z() * 32767.0f),2);
writeEndian((short)(nodeScaleRotsArbitrary[i].w() * 32767.0f),2);
}
// same number as above...
for (i=0; i<nodeScalesArbitrary.size(); i++)
{
writeEndian(nodeScalesArbitrary[i].x(),4);
writeEndian(nodeScalesArbitrary[i].y(),4);
writeEndian(nodeScalesArbitrary[i].z(),4);
}
writeEndian(groundTranslations.size(),4);
for (i=0; i<groundTranslations.size(); i++)
{
writeEndian(groundTranslations[i].x(),4);
writeEndian(groundTranslations[i].y(),4);
writeEndian(groundTranslations[i].z(),4);
}
// same number as above
for (i=0; i<groundRotations.size(); i++)
{
writeEndian((short)(groundRotations[i].x() * 32767.0f),2);
writeEndian((short)(groundRotations[i].y() * 32767.0f),2);
writeEndian((short)(groundRotations[i].z() * 32767.0f),2);
writeEndian((short)(groundRotations[i].w() * 32767.0f),2);
}
// legacy write -- write zero objects, don't pretend to support object export anymore
writeEndian((int)0,4);
// Sequences
int numSequences = sequences.size() ;
writeEndian(numSequences,4);
for (int seq = 0 ; seq < sequences.size() ; seq++)
{
const Sequence &p = sequences[seq] ;
// write sequence name
const char * seqname = names[p.nameIndex].c_str();
writeEndian(strlen(seqname),4);
out.write((char*)seqname,strlen(seqname));
// skip name index...
writeEndian(p.flags,4);
writeEndian(p.numKeyFrames,4);
writeEndian(p.duration,4);
writeEndian(p.priority,4);
writeEndian(p.firstGroundFrame,4);
writeEndian(p.numGroundFrames,4);
writeEndian(p.baseRotation,4);
writeEndian(p.baseTranslation,4);
writeEndian(p.baseScale,4);
writeEndian(p.baseObjectState,4);
writeEndian(p.baseDecalState,4);
writeEndian(p.firstTrigger,4);
writeEndian(p.numTriggers,4);
writeEndian(p.toolBegin,4);
write(out,&p.matters.rotation);
write(out,&p.matters.translation);
write(out,&p.matters.scale);
write(out,&p.matters.decal);
write(out,&p.matters.ifl);
write(out,&p.matters.vis);
write(out,&p.matters.frame);
write(out,&p.matters.matframe);
}
writeEndian(triggers.size(),4);
for (i=0; i<triggers.size(); i++)
{
writeEndian(triggers[i].state,4);
writeEndian(triggers[i].pos,4);
}
}
void Shape::write (std::ostream & out,const std::vector<bool> * ptr) const
{
// Save out the bool array as an array of bits, in 32bit chunks.
int words[32], use = ptr->size() / 32 ;
if (use * 32 < ptr->size()) use++ ;
memset(words, 0, sizeof(words));
for (int i = 0 ; i < ptr->size() ; i++)
if ((*ptr)[i])
words[i >> 5] |= 1 << (i & 31);
for (int j = 0; j < sizeof(words)/sizeof(int); j++)
words[j] = FIX_ENDIAN(words[j]);
out.write ((char *)&FIX_ENDIAN(use), 4) ;
out.write ((char *)&FIX_ENDIAN(use), 4) ;
if (use > 0)
out.write ((char *)&words, 4*use) ;
}
// -----------------------------------------------------------------------
// Utility methods
// -----------------------------------------------------------------------
int Shape::addName (std::string s)
{
// Don't store duplicated names
for (int i = 0 ; i < names.size() ; i++)
{
#if _WIN32
if (!stricmp(names[i].data(),s.data()))
#else
if (!strcasecmp(names[i].data(),s.data()))
#endif
return i ;
}
names.push_back(s) ;
return names.size() - 1 ;
}
void Shape::calculateBounds()
{
if (!objects.size()) return ;
bounds.max = Point(-10E30F, -10E30F, -10E30F) ;
bounds.min = Point( 10E30F, 10E30F, 10E30F) ;
// Iterate through the objects instead of the meshes
// so we can easily get the default transforms.
for (int i = 0 ; i < objects.size() ; i++)
{
const Object &obj = objects[i];
Point trans;
Quaternion rot;
getNodeWorldPosRot(obj.node,trans,rot);
for (int j = 0 ; j < obj.numMeshes ; j++)
{
Box bounds2 = meshes[obj.firstMesh + j].getBounds(trans,rot) ;
bounds.min.x(min(bounds.min.x(), bounds2.min.x())) ;
bounds.min.y(min(bounds.min.y(), bounds2.min.y())) ;
bounds.min.z(min(bounds.min.z(), bounds2.min.z())) ;
bounds.max.x(max(bounds.max.x(), bounds2.max.x())) ;
bounds.max.y(max(bounds.max.y(), bounds2.max.y())) ;
bounds.max.z(max(bounds.max.z(), bounds2.max.z())) ;
}
}
}
void Shape::calculateCenter()
{
center = bounds.min.midpoint(bounds.max) ;
}
void Shape::calculateTubeRadius()
{
float maxRadius = 0.0f ;
for (int i = 0 ; i < objects.size() ; i++)
{
const Object &obj = objects[i];
Point trans;
Quaternion rot;
getNodeWorldPosRot(obj.node,trans,rot);
for (int j = 0 ; j < obj.numMeshes ; j++)
{
const Mesh &m = meshes[obj.firstMesh + j];
float meshRadius = m.getTubeRadiusFrom(trans,rot,center) ;
if (meshRadius > maxRadius)
maxRadius = meshRadius ;
}
}
tubeRadius = maxRadius ;
}
void Shape::calculateRadius()
{
float maxRadius = 0.0f ;
for (int i = 0 ; i < objects.size() ; i++)
{
const Object &obj = objects[i];
Point trans;
Quaternion rot;
getNodeWorldPosRot(obj.node,trans,rot);
for (int j = 0 ; j < obj.numMeshes ; j++)
{
const Mesh &m = meshes[obj.firstMesh + j];
float meshRadius = m.getRadiusFrom(trans,rot,center) ;
if (meshRadius > maxRadius)
maxRadius = meshRadius ;
}
}
radius = maxRadius ;
}
void Shape::setSmallestSize(int pixels)
{
if (pixels < 1)
pixels = 1;
smallestSize = pixels;
int i=0;
for (i = 0; i < detailLevels.size(); i++)
{
if (detailLevels[i].size < pixels)
break ;
}
smallestDetailLevel = i;
}
void Shape::getNodeWorldPosRot(int n, Point &trans, Quaternion &rot)
{
// Build total translation & rotation for this node
std::vector <int> nidx;
nidx.push_back(n);
while ((n = nodes[n].parent) >= 0)
nidx.push_back(n);
trans = Point(0,0,0);
rot = Quaternion::identity;
for (int i = nidx.size() - 1; i >= 0; i--)
{
trans += rot.apply(nodeDefTranslations[nidx[i]]);
rot = nodeDefRotations[nidx[i]] * rot;
}
}
}