added everything

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

188
lib/dtsSDK/DTSBrushMesh.cpp Executable file
View File

@ -0,0 +1,188 @@
#pragma warning ( disable: 4786 )
#include <vector>
#include <cmath>
#include "DTSBrushMesh.h"
#ifndef M_PI
#define M_PI 3.1415926535f
#endif
namespace DTS
{
void BrushMesh::addVertex(float x, float y, float z)
{
verts.push_back(Point(x, y, z));
tverts.push_back(Point2D(x+z, y+z));
Point normal = Point(x, y, z) - getCenter() ;
normal.normalize() ;
normals.push_back(normal) ;
enormals.push_back(encodeNormal(normal)) ;
}
// -----------------------------------------------------------------------
// Creates a vertical cylinder
// -----------------------------------------------------------------------
CylinderMesh::CylinderMesh (Box &_bounds, float _radius, float _complexity)
{
setRadius (_radius) ;
setBounds (_bounds) ;
setCenter (_bounds.min.midpoint(_bounds.max)) ;
complexity = _complexity ;
construct() ;
}
void CylinderMesh::construct()
{
int i, firstTop ;
int steps = (unsigned int)(complexity * 64.0f) ;
float angle ;
Point normal ;
Box bounds = getBounds() ;
Point center = getCenter() ;
float radius = getRadius() ;
Primitive p ;
p.type = Primitive::NoMaterial | Primitive::Strip | Primitive::Indexed ;
if (steps < 4) steps = 4 ;
if (steps > 64) steps = 64 ;
steps &= ~1 ;
// Bottom
addVertex (center.x(), center.y(), bounds.min.z()) ;
for (angle = 0.0f, i = 0 ; i < steps ; i++, angle += 2.0f*M_PI/(float)steps)
{
addVertex (cosf(angle)*radius + center.x(), sinf(angle)*radius + center.y(),
bounds.min.z()) ;
}
for (i = 1 ; i <= steps ; i++)
{
p.firstElement = indices.size() ;
p.numElements = 3 ;
indices.push_back (0) ;
indices.push_back (i) ;
indices.push_back (i == steps ? 1 : i+1) ;
primitives.push_back(p) ;
}
// Top
firstTop = verts.size() ;
addVertex (center.x(), center.y(), bounds.max.z()) ;
for (angle = 0.0f, i = 0 ; i < steps ; i++, angle += 2.0f*M_PI/(float)steps)
{
addVertex (cosf(angle)*radius + center.x(), sinf(angle)*radius + center.y(),
bounds.max.z()) ;
}
for (i = 1 ; i <= steps ; i++)
{
p.firstElement = indices.size() ;
p.numElements = 3 ;
indices.push_back (firstTop) ;
indices.push_back (firstTop+(i == steps ? 1 : i+1)) ;
indices.push_back (firstTop+i) ;
primitives.push_back(p) ;
}
// Walls
int pos ;
for (pos = indices.size(), i = 0 ; i < steps-1 ; i++, pos += 4)
{
indices.push_back (i+1) ;
indices.push_back (firstTop+i+1) ;
indices.push_back (i+2) ;
indices.push_back (firstTop+i+2) ;
p.firstElement = pos ;
p.numElements = 4 ;
primitives.push_back(p) ;
}
indices.push_back (i+1) ;
indices.push_back (firstTop+i+1) ;
indices.push_back (1) ;
indices.push_back (firstTop+1) ;
p.firstElement = pos ;
p.numElements = 4 ;
primitives.push_back(p) ;
// Other stuff
setFrames (1) ;
setParent (-1) ;
calculateBounds() ;
calculateCenter() ;
calculateRadius() ;
}
// -----------------------------------------------------------------------
// Creates a box
// -----------------------------------------------------------------------
BoxMesh::BoxMesh (Box & _bounds)
{
setBounds(_bounds) ;
construct() ;
}
void BoxMesh::construct()
{
int i ;
Box bounds = getBounds() ;
Point center = (bounds.max - bounds.min) / 2 ;
// Vertex
verts.push_back(Point(bounds.min.x(), bounds.min.y(), bounds.min.z()));
verts.push_back(Point(bounds.max.x(), bounds.min.y(), bounds.min.z()));
verts.push_back(Point(bounds.min.x(), bounds.max.y(), bounds.min.z()));
verts.push_back(Point(bounds.max.x(), bounds.max.y(), bounds.min.z()));
verts.push_back(Point(bounds.min.x(), bounds.min.y(), bounds.max.z()));
verts.push_back(Point(bounds.max.x(), bounds.min.y(), bounds.max.z()));
verts.push_back(Point(bounds.min.x(), bounds.max.y(), bounds.max.z()));
verts.push_back(Point(bounds.max.x(), bounds.max.y(), bounds.max.z()));
// Texture coordinates
for (i = 0 ; i < 8 ; i++)
tverts.push_back(Point2D(0,0));
// Indices
int inds[] = { 0, 4, 1, 5, 3, 7, 2, 6, 0, 4, 6, 7, 4, 5, 0, 1, 2, 3 } ;
for (i = 0 ; i < sizeof(inds)/sizeof(inds[0]) ; i++)
indices.push_back(inds[i]);
// Primitives
Primitive p ;
p.firstElement = 0 ;
p.numElements = 10 ;
p.type = Primitive::NoMaterial | Primitive::Strip | Primitive::Indexed ;
primitives.push_back(p) ;
p.firstElement = 10 ;
p.numElements = 4 ;
primitives.push_back(p) ;
p.firstElement = 14 ;
primitives.push_back(p) ;
// Normals
std::vector<Point>::iterator ptr ;
for (ptr = verts.begin() ; ptr != verts.end() ; ptr++)
{
Point normal ;
normal = *ptr - center ;
normal.normalize() ;
normals.push_back (normal) ;
enormals.push_back (encodeNormal(normal)) ;
}
// Other stuff
setFrames (1) ;
setParent (-1) ;
calculateCenter() ;
calculateRadius() ;
}
}

51
lib/dtsSDK/DTSBrushMesh.h Executable file
View File

@ -0,0 +1,51 @@
#ifndef __DTSBRUSHMESH_H
#define __DTSBRUSHMESH_H
#include "DTSMesh.h"
namespace DTS
{
class BrushMesh : public Mesh
{
public:
//! Creates an standard mesh by default
BrushMesh() : Mesh(T_Standard) {}
//! Creates (or recreates) the mesh
virtual void construct() = 0 ;
protected:
//! Create a new vertex with convenient (altough arbitrary) normal/texture data
void addVertex (float, float, float) ;
};
class CylinderMesh : public BrushMesh
{
public:
//! Create a standard mesh as a cylinder (the box is used for the center and Z range)
CylinderMesh (Box &, float radius, float complexity = 0.25f) ;
//! Creates (or recreates) the mesh
virtual void construct() ;
private:
float complexity ;
};
class BoxMesh : public BrushMesh
{
public:
//! Create a standard mesh as a box
BoxMesh (Box &) ;
//! Creates (or recreates) the mesh
virtual void construct() ;
};
}
#endif

85
lib/dtsSDK/DTSEndian.h Executable file
View File

@ -0,0 +1,85 @@
#ifndef __DTSENDIAN_H
#define __DTSENDIAN_H
// Big endian support. Note that one should not hold onto the
// returned reference in the FIX_ENDIAN methods. Return reference
// to a static variable so that one can use & operator on return value.
namespace DTS
{
inline bool isLittleEndian()
{
int test = 1;
char * t0 = (char*)&test;
++*t0;
return (test==2);
}
inline void FIX_ENDIAN2(void * val)
{
char * ptr = (char*)val;
char tmp = ptr[0];
ptr[0] = ptr[1];
ptr[1] = tmp;
}
inline void FIX_ENDIAN4(void * val)
{
char * ptr = (char*)val;
char tmp = ptr[0];
ptr[0] = ptr[3];
ptr[3] = tmp;
tmp = ptr[1];
ptr[1] = ptr[2];
ptr[2] = tmp;
}
inline short & FIX_ENDIAN(short val)
{
if (!isLittleEndian())
FIX_ENDIAN2(&val);
static short out;
out = val;
return out;
}
inline unsigned short & FIX_ENDIAN(unsigned short val)
{
return (unsigned short&)FIX_ENDIAN(short(val));
}
inline int & FIX_ENDIAN(int val)
{
if (!isLittleEndian())
FIX_ENDIAN4(&val);
static int out;
out = val;
return out;
}
inline unsigned int & FIX_ENDIAN(unsigned int val)
{
return (unsigned int&)FIX_ENDIAN( int(val));
}
inline float & FIX_ENDIAN(float val)
{
if (!isLittleEndian())
FIX_ENDIAN4(&val);
static float out;
out = val;
return out;
}
#ifdef __APPLE__
inline int & FIX_ENDIAN(size_t val)
{
static int out;
out = val;
if (!isLittleEndian())
FIX_ENDIAN4(&out);
return out;
}
#endif
}
#endif

348
lib/dtsSDK/DTSInputStream.h Executable file
View File

@ -0,0 +1,348 @@
#ifndef __DTSINPUTSTREAM_H
#define __DTSINPUTSTREAM_H
#include <cassert>
#include <vector>
#include <fstream>
#include "DTSShape.h"
using namespace std;
namespace DTS
{
// -------------------------------------------------------------------------
// class InputStream
// --------------------------------------------------------------------------
/*! This is more or less a quick hack to provide future loading
features to the library. Refere to the OutputStream for info,
this is almost a copy of that.
*/
class InputStream
{
public:
//! Load the stream.
InputStream (std::istream &) ;
~InputStream () ;
int version() { return DTSVersion ; }
//! Read "count" dwords (= count x 4 bytes). A null pointer is OK
void read (int *, int count) ;
//! Read "count" words (= count x 2 bytes). A null pointer is OK
void read (short *, int count) ;
//! Read "count" bytes . A null pointer is OK
void read (char *, int count) ;
//! Read one dword . A null pointer is used to discard the value
InputStream & operator >> (int &value) { read(&value, 1) ; return *this ; }
//! Read one word
InputStream & operator >> (short &value) { read(&value, 1) ; return *this ; }
InputStream & operator >> (unsigned short &value) { read((short*)&value, 1) ; return *this ; }
//! Read one byte
InputStream & operator >> (char &value) { read(&value, 1) ; return *this ; }
//! Read one dword (1 float == 32 bits)
InputStream & operator >> (float &value)
{
read((int *)&value, 1) ;
return *this ;
}
//! Read one byte (provided for convenience)
InputStream & operator >> (unsigned char &value)
{
read((char *)&value, 1) ;
return *this ;
}
//! Read a string (1 byte len first, then n byte-sized characters)
InputStream & operator >> (std::string &s) ;
// Operators to read some usual structs
InputStream & operator >> (Point &) ;
InputStream & operator >> (Point2D &) ;
InputStream & operator >> (Box &) ;
InputStream & operator >> (Quaternion &) ;
InputStream & operator >> (Node &) ;
InputStream & operator >> (Object &) ;
InputStream & operator >> (Decal &) ;
InputStream & operator >> (IFLMaterial &) ;
InputStream & operator >> (DecalState &) ;
InputStream & operator >> (DetailLevel &) ;
InputStream & operator >> (ObjectState &) ;
InputStream & operator >> (Subshape &) ;
InputStream & operator >> (Trigger &) ;
InputStream & operator >> (Primitive &) ;
InputStream & operator >> (Mesh &) ;
//! Stores checkpoint values in the streams
void readCheck (int checkPoint = -1) ;
private:
std::istream & in ;
int DTSVersion ;
int checkCount ;
// Pointers to the 3 memory buffers
int * Buffer32 ;
short * Buffer16 ;
char * Buffer8 ;
// Values allocated in each buffer
unsigned long Allocated32 ;
unsigned long Allocated16 ;
unsigned long Allocated8 ;
// Values actually used in each buffer
unsigned long Used32 ;
unsigned long Used16 ;
unsigned long Used8 ;
};
// --------------------------------------------------------------------------
// Construction and destruction
// --------------------------------------------------------------------------
inline InputStream::InputStream (std::istream & s) : in(s)
{
int totalSize ;
int offset16 ;
int offset8 ;
// Read the header
in.read ((char *) &DTSVersion, 4) ;
in.read ((char *) &totalSize, 4) ;
in.read ((char *) &offset16, 4) ;
in.read ((char *) &offset8, 4) ;
// Create buffers
Allocated32 = offset16 ;
Allocated16 = (offset8-offset16) * 2 ;
Allocated8 = (totalSize-offset8) * 4 ;
Buffer32 = new int [Allocated32] ;
Buffer16 = new short [Allocated16] ;
Buffer8 = new char [Allocated8] ;
// Read the data
in.read ((char *) Buffer32, 4 * Allocated32) ;
in.read ((char *) Buffer16, 2 * Allocated16) ;
in.read (Buffer8, Allocated8) ;
checkCount = 0 ;
Used32 = 0 ;
Used16 = 0 ;
Used8 = 0 ;
}
inline InputStream::~InputStream()
{
delete [] Buffer8 ;
delete [] Buffer16 ;
delete [] Buffer32 ;
}
// --------------------------------------------------------------------------
// Read functions
// --------------------------------------------------------------------------
inline void InputStream::read (int * data, int count)
{
assert (count > 0) ;
assert (Used32+count < Allocated32) ;
if (data != 0)
memcpy (data, Buffer32 + Used32, sizeof(int) * count) ;
Used32 += count ;
}
// The other read methods are exactly the same, except for the buffer used
inline void InputStream::read (short * data, int count)
{
assert (count > 0) ;
assert (Used16 < Allocated16) ;
if (data != 0)
memcpy (data, Buffer16 + Used16, sizeof(short) * count) ;
Used16 += count ;
}
inline void InputStream::read (char * data, int count)
{
assert (count > 0) ;
assert (Used8 < Allocated8) ;
if (data == 0)
memcpy (data, Buffer8 + Used8, sizeof(char) * count) ;
Used8 += count ;
}
// --------------------------------------------------------------------------
// Read operators
// --------------------------------------------------------------------------
inline InputStream & InputStream::operator >> (Point &p)
{
float x, y, z ;
(*this) >> x >> y >> z ;
p.x(x) ;
p.y(y) ;
p.z(z) ;
return *this ;
}
inline InputStream & InputStream::operator >> (Point2D &p)
{
float x, y ;
(*this) >> x >> y ;
p.x(x) ;
p.y(y) ;
return *this ;
}
inline InputStream & InputStream::operator >> (Box &b)
{
return (*this) >> b.min >> b.max ;
}
inline InputStream & InputStream::operator >> (Quaternion &q)
{
short x, y, z, w ;
(*this) >> x >> y >> z >> w ;
q.x(x / 32767.0f) ;
q.y(y / 32767.0f) ;
q.z(z / 32767.0f) ;
q.w(w / 32767.0f) ;
return (*this) ;
}
inline InputStream & InputStream::operator >> (Node &n)
{
return (*this) >> n.name >> n.parent >> n.firstObject
>> n.child >> n.sibling ;
}
inline InputStream & InputStream::operator >> (Object &o)
{
return (*this) >> o.name >> o.numMeshes >> o.firstMesh
>> o.node >> o.sibling >> o.firstDecal ;
}
inline InputStream & InputStream::operator >> (Decal &d)
{
return (*this) >> d.name >> d.numMeshes >> d.firstMesh
>> d.object >> d.sibling ;
}
inline InputStream & InputStream::operator >> (IFLMaterial &m)
{
return (*this) >> m.name >> m.slot >> m.firstFrame
>> m.time >> m.numFrames ;
}
inline InputStream & InputStream::operator >> (Subshape &s)
{
assert (0 && "Subshapes should be written in block") ;
}
inline InputStream & InputStream::operator >> (Trigger &d)
{
return (*this) >> d.state >> d.pos ;
}
inline InputStream & InputStream::operator >> (DecalState &d)
{
return (*this) >> d.frame ;
}
inline InputStream & InputStream::operator >> (ObjectState &o)
{
return (*this) >> o.vis >> o.frame >> o.matFrame ;
}
inline InputStream & InputStream::operator >> (DetailLevel &d)
{
return (*this) >> d.name >> d.subshape >> d.objectDetail >> d.size
>> d.avgError >> d.maxError >> d.polyCount ;
}
inline InputStream & InputStream::operator >> (Primitive &p)
{
return (*this) >> p.firstElement >> p.numElements >> p.type ;
}
inline InputStream & InputStream::operator >> (Mesh &m)
{
m.read(*this) ;
return *this ;
}
inline InputStream & InputStream::operator >> (std::string &s)
{
char c ;
for (s = "" ;;)
{
(*this) >> c ;
if (!c) break ;
s += c ;
}
return *this ;
}
template <class type>
inline InputStream & operator >> (InputStream & in, std::vector<type> &v)
{
typename std::vector<type>::iterator pos = v.begin() ;
while (pos != v.end())
{
in >> *pos++ ;
}
return in ;
}
// --------------------------------------------------------------------------
// Checkpoints and alignment
// --------------------------------------------------------------------------
/*! Sometimes during the storing process, a checkpoint value is
stored to all the buffers at the same time. This check helps
to determine if the files are not corrupted. */
inline void InputStream::readCheck(int checkPoint)
{
if (checkPoint >= 0)
assert (checkPoint == checkCount) ;
int checkCount_int ;
short checkCount_short ;
char checkCount_char ;
(*this) >> checkCount_int ;
(*this) >> checkCount_short ;
(*this) >> checkCount_char ;
assert (checkCount_char == (char) checkCount) ;
assert (checkCount_short == (short)checkCount) ;
assert (checkCount_int == (int) checkCount) ;
checkCount++ ;
}
}
#endif

50
lib/dtsSDK/DTSInterpolation.h Executable file
View File

@ -0,0 +1,50 @@
#ifndef __DTS_INTERPOLATION_H
#define __DTS_INTERPOLATION_H
#include <cmath>
namespace DTS
{
//! Not really a class, but a bunch of static interpolation functions
struct Interpolation
{
template <class type>
static inline type linear (const type &a, const type &b, float s)
{
return s*a + (1-s)*b ;
}
template <class type>
static inline type quadratic (const type &a, const type &b, float s)
{
return sqrt( s*a*a + (1-s)*b*b );
}
template <class type>
static inline type spherical (const type &a, const type &b, float s)
{
return exp( s*ln(a) + (1-s)*ln(b) );
}
template <class type>
static inline type bezier (const type &a, const type &b, const type &ac, const type &bc, float s)
{
return (-1*s*s*s +3*s*s -3*s +1) * a
+ (+3*s*s*s -6*s*s +3*s ) * b
+ (-3*s*s*s +3*s*s ) * ac
+ (+1*s*s*s ) * bc ;
}
template <class type>
static inline type hermite (const type &a, const type &b, const type &at, const type &bt, float s)
{
return (+2*s*s*s -3*s*s +1) * a
+ (-2*s*s*s +3*s*s ) * b
+ (+1*s*s*s -2*s*s +s ) * at
+ (+1*s*s*s -1*s*s ) * bt ;
}
};
}
#endif

15
lib/dtsSDK/DTSMatrix.cpp Executable file
View File

@ -0,0 +1,15 @@
#pragma warning ( disable: 4786 4018 )
#include <vector>
#include <cmath>
#include "DTSMatrix.h"
namespace DTS
{
void test()
{
Matrix<4,4> m ;
m.inverse() ;
}
}

347
lib/dtsSDK/DTSMatrix.h Executable file
View File

@ -0,0 +1,347 @@
#ifndef __DTSMATRIX_H
#define __DTSMATRIX_H
#include <iomanip>
#include <vector>
#include <string>
#include <ostream>
#include <cmath>
#include <cassert>
#include "DTSVector.h"
#include "DTSPoint.h"
namespace DTS
{
//! Defines matrices
template <int rows=4, int cols=4, class type=float>
class Matrix : public Vector<Vector<type,cols>, rows>
{
public:
typedef Vector<type,cols> Row ;
typedef type Cell ;
Matrix() { /* No initialization */ }
Vector<type,rows> col (int n) {
assert (n >= 0 && n < rows) ;
Vector<type,rows> result ;
for (int r = 0 ; r < rows ; r++)
result[r] = (*this)[r][n] ;
return result ;
}
void setCol (int n,Vector<type,rows> col) {
assert (n >= 0 && n < rows) ;
for (int r = 0 ; r < rows ; r++)
(*this)[r][n] = col[r];
}
Matrix(const type *p) {
for (int r = 0 ; r < rows ; r++)
for (int c = 0 ; c < cols ; c++)
(*this)[r][c] = *p++ ;
}
inline static Matrix<rows,cols,type> identity() {
Matrix <rows,cols,type> result ;
for (int r = 0 ; r < rows ; r++)
for (int c = 0 ; c < cols ; c++)
result[r][c] = type(r == c ? 1 : 0) ;
return result ;
}
Matrix <rows, cols, type> transpose() const
{
Matrix <rows,cols,type> result ;
for (int r = 0 ; r < rows ; r++)
for (int c = 0 ; c < cols ; c++)
result[c][r] = (*this)[r][c] ;
return result ;
}
type determinant() const ;
Matrix <rows, cols, type> inverse() const ;
//!{ Matrix operators
Matrix<rows,cols,type> & operator = (const Matrix<rows,cols,type> &a) {
for (int r = 0 ; r < rows ; r++)
for (int c = 0 ; c < cols ; c++)
(*this)[r][c] = a[r][c] ;
return *this ;
}
template <int rows2, int cols2>
Matrix<rows,cols2,type>
operator * (const Matrix<rows2,cols2,type> &b)
{
Matrix<rows,cols2,type> result ;
assert (rows2 == cols) ;
for (int r = 0 ; r < rows ; r++)
{
for (int c = 0 ; c < cols2 ; c++)
{
type cell = (*this)[r][0] * b[0][c] ;
for (int e = 1 ; e < cols ; e++)
cell += (*this)[r][e] * b[e][c] ;
result[r][c] = cell ;
}
}
return result ;
}
Vector<type,rows> operator * (const Vector<type,rows> &v)
{
Vector<type,rows> result ;
for (int r = 0 ; r < rows ; r++)
{
type cell = (*this)[r][0] * v[0] ;
for (int e = 1 ; e < cols ; e++)
cell += (*this)[r][e] * v[e] ;
result[r] = cell ;
}
return result ;
}
// Not needed -- and doesn't work with vc7
//template <int rows2, int cols2>
//operator *= (const Matrix<rows2,cols2,type> &a) { (*this) = (*this) * a ; }
template <int rows2, int cols2>
Matrix<rows,cols,type> operator + (const Matrix<rows,cols,type> &b)
{
Matrix<rows,cols2,type> result ;
for (int r = 0 ; r < rows ; r++)
for (int c = 0 ; c < cols2 ; c++)
result[r][c] = (*this)[r][c] + b[r][c] ;
return result ;
}
template <int rows2, int cols2>
Matrix<rows,cols,type> operator += (const Matrix<rows,cols,type> &b)
{
Matrix<rows,cols2,type> result ;
for (int r = 0 ; r < rows ; r++)
for (int c = 0 ; c < cols2 ; c++)
(*this)[r][c] += b[r][c] ;
return result ;
}
template <int rows2, int cols2>
Matrix<rows,cols,type> operator - (const Matrix<rows,cols,type> &b)
{
Matrix<rows,cols2,type> result ;
for (int r = 0 ; r < rows ; r++)
for (int c = 0 ; c < cols2 ; c++)
result[r][c] = (*this)[r][c] - b[r][c] ;
return result ;
}
template <int rows2, int cols2>
Matrix<rows,cols,type> operator -= (const Matrix<rows,cols,type> &b)
{
Matrix<rows,cols2,type> result ;
for (int r = 0 ; r < rows ; r++)
for (int c = 0 ; c < cols2 ; c++)
(*this)[r][c] -= b[r][c] ;
return result ;
}
//!}
inline static Matrix<4,4> rotationX(float angle)
{
float cells[] = {
1, 0, 0, 0,
0, cosf(angle), -sinf(angle), 0,
0, sinf(angle), cosf(angle), 0,
0, 0, 0, 1
} ;
return Matrix<4,4> (cells) ;
}
inline static Matrix<4,4> rotationZ(float angle)
{
float cells[] = {
cosf(angle), -sinf(angle), 0, 0,
sinf(angle), cosf(angle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
} ;
return Matrix<4,4> (cells) ;
}
inline static Matrix<4,4> rotationY(float angle)
{
float cells[] = {
cosf(angle), 0, -sinf(angle), 0,
0, 1, 0, 0,
sinf(angle), 0, cosf(angle), 0,
0, 0, 0, 1
} ;
return Matrix<4,4> (cells) ;
}
};
template <int rows, int cols, class type>
type Matrix<rows,cols,type>::determinant() const
{
int r, c, f ;
type result = 0 ;
const Matrix<rows,cols,type> &m = *this ;
assert (rows == cols) ;
switch (rows)
{
case 1:
return m[0][0] ;
case 2:
return m[0][0]*m[1][1] - m[0][1]*m[1][0] ;
case 3:
return m[0][0] * ( m[1][1]*m[2][2] - m[1][2]*m[2][1] )
- m[0][1] * ( m[1][0]*m[2][2] - m[1][2]*m[2][0] )
+ m[0][2] * ( m[1][0]*m[2][1] - m[1][1]*m[2][0] ) ;
#define GREATER_ORDER(o) \
case o: \
for (f = 0 ; f < o ; f++) \
{ \
type data[(o-1)*(o-1)], *ptr = data ; \
for (r = 0 ; r < o ; r++) \
{ \
if (r == f) continue ; \
for (c = 1 ; c < o ; c++) \
*ptr++ = m[r][c] ; \
} \
result += m[f][0] * Matrix<o-1,o-1,type>(data) \
.determinant() * ((f&1) ? -1:1) ; \
} \
return result ;
GREATER_ORDER(4)
GREATER_ORDER(5)
GREATER_ORDER(6)
GREATER_ORDER(7)
GREATER_ORDER(8)
GREATER_ORDER(9)
#undef GREATER_ORDER
default:
return 0 ;
}
}
template <int rows, int cols, class type>
Matrix<rows,cols,type> Matrix<rows,cols,type>::inverse() const
{
int r, c, r2, c2 ;
type det = determinant() ;
type p[rows][cols] ;
const Matrix<rows,cols,type> &m = *this ;
assert (rows == cols) ;
assert (det != 0) ;
switch (rows)
{
case 1:
p[0][0] = m[0][0]/det ;
break ;
case 2:
p[0][0] = m[1][1] / det ;
p[0][1] = -m[0][1] / det ;
p[1][0] = -m[1][0] / det ;
p[1][1] = m[0][0] / det ;
break ;
case 3:
p[0][0] = ( m[1][1]*m[2][2] - m[1][2]*m[2][1] ) / det ;
p[1][0] = -( m[1][0]*m[2][2] - m[1][2]*m[2][0] ) / det ;
p[2][0] = ( m[1][0]*m[2][1] - m[1][1]*m[2][0] ) / det ;
p[0][1] = -( m[0][1]*m[2][2] - m[0][2]*m[2][1] ) / det ;
p[1][1] = ( m[0][0]*m[2][2] - m[0][2]*m[2][0] ) / det ;
p[2][1] = -( m[0][0]*m[2][1] - m[0][1]*m[2][0] ) / det ;
p[0][2] = ( m[0][1]*m[1][2] - m[0][2]*m[1][1] ) / det ;
p[1][2] = -( m[0][0]*m[1][2] - m[0][2]*m[1][0] ) / det ;
p[2][2] = ( m[0][0]*m[1][1] - m[0][1]*m[1][0] ) / det ;
break ;
#define GREATER_ORDER(o) \
case o: \
for (r = 0 ; r < o ; r++) \
{ \
for (c = 0 ; c < o ; c++) \
{ \
type data[o*o], *ptr = data ; \
for (r2 = 0 ; r2 < o ; r2++) \
{ \
if (r2 == r) continue ; \
for (c2 = 0 ; c2 < o ; c2++) \
{ \
if (c2 == c) continue ; \
*ptr++ = m[r2][c2] ; \
} \
} \
type sign = float(1-((r+c)%2)*2) ; \
p[c][r] = Matrix<o-1,o-1,type>(data) \
.determinant() * sign / det ; \
} \
} \
break ;
GREATER_ORDER(4)
GREATER_ORDER(5)
GREATER_ORDER(6)
GREATER_ORDER(7)
GREATER_ORDER(8)
GREATER_ORDER(9)
#undef GREATER_ORDER
default:
return 0 ;
}
return Matrix<rows,cols,type> (&p[0][0]) ;
}
template <int rows, int cols, class type>
std::ostream & operator << (std::ostream &out, const Matrix<rows,cols,type> &m)
{
out << std::setprecision(2) << std::setiosflags(std::ios::fixed) ;
for (int r = 0 ; r < rows ; r++)
{
out << "| " ;
for (int c = 0 ; c < cols ; c++)
out << std::setw(7) << m[r][c] << ' ' ;
out << "|\n" ;
}
return out ;
}
inline Point operator * (const Point &p, const Matrix<> &m)
{
Point result ;
result.x( p.x()*m[0][0] + p.y()*m[0][1] + p.z()*m[0][2] + m[0][3] ) ;
result.y( p.x()*m[1][0] + p.y()*m[1][1] + p.z()*m[1][2] + m[1][3] ) ;
result.z( p.x()*m[2][0] + p.y()*m[2][1] + p.z()*m[2][2] + m[2][3] ) ;
return result ;
}
inline Point operator * (const Matrix<> &m, const Point &p)
{
return p * m ;
}
}
#endif

462
lib/dtsSDK/DTSMesh.cpp Executable file
View File

@ -0,0 +1,462 @@
#pragma warning ( disable: 4786 4018 )
#include <vector>
#include <cmath>
#include "DTSMesh.h"
#include "DTSOutputStream.h"
#include "DTSInputStream.h"
namespace DTS
{
// -----------------------------------------------------------------------
// Normal encoding transformation
// -----------------------------------------------------------------------
#include "DTSNormalTable.cpp"
char Mesh::encodeNormal(const Point & normal)
{
unsigned char bestIndex = 0;
float bestDot = -10E30F ;
for (int i = 0 ; i < 256 ; i++)
{
float dot =
( normal.x() * normalTable[i][0]
+ normal.y() * normalTable[i][1]
+ normal.z() * normalTable[i][2] ) ;
if (dot > bestDot)
{
bestIndex = i;
bestDot = dot;
}
}
return * (char*)&bestIndex;
}
// -----------------------------------------------------------------------
// Searchs for minor and maximum vertex coordinates
// -----------------------------------------------------------------------
void Mesh::calculateBounds()
{
std::vector<Point>::iterator vertex ;
bounds.max = Point(-10E30F, -10E30F, -10E30F) ;
bounds.min = Point( 10E30F, 10E30F, 10E30F) ;
for (vertex = verts.begin() ; vertex != verts.end() ; vertex++)
{
if (vertex->x() < bounds.min.x())
bounds.min.x(vertex->x()) ;
if (vertex->y() < bounds.min.y())
bounds.min.y(vertex->y()) ;
if (vertex->z() < bounds.min.z())
bounds.min.z(vertex->z()) ;
if (vertex->x() > bounds.max.x())
bounds.max.x(vertex->x()) ;
if (vertex->y() > bounds.max.y())
bounds.max.y(vertex->y()) ;
if (vertex->z() > bounds.max.z())
bounds.max.z(vertex->z()) ;
}
}
Box Mesh::getBounds(Point trans,Quaternion rot) const
{
// Compute the bounding box using the given transform.
Box bounds2;
bounds2.max = Point(-10E30F, -10E30F, -10E30F) ;
bounds2.min = Point( 10E30F, 10E30F, 10E30F) ;
std::vector<Point>::const_iterator vertex ;
for (vertex = verts.begin() ; vertex != verts.end() ; vertex++)
{
Point tv = rot.apply(*vertex) + trans;
if (tv.x() < bounds2.min.x())
bounds2.min.x(tv.x()) ;
if (tv.y() < bounds2.min.y())
bounds2.min.y(tv.y()) ;
if (tv.z() < bounds2.min.z())
bounds2.min.z(tv.z()) ;
if (tv.x() > bounds2.max.x())
bounds2.max.x(tv.x()) ;
if (tv.y() > bounds2.max.y())
bounds2.max.y(tv.y()) ;
if (tv.z() > bounds2.max.z())
bounds2.max.z(tv.z()) ;
}
return bounds2;
}
// -----------------------------------------------------------------------
// Calculates center of bounding box
// -----------------------------------------------------------------------
void Mesh::calculateCenter()
{
center = bounds.max.midpoint(bounds.min) ;
}
// -----------------------------------------------------------------------
// Search for the maximum vertex distance from center
// -----------------------------------------------------------------------
void Mesh::calculateRadius()
{
radius = getRadiusFrom(Point(0,0,0),Quaternion::identity,center) ;
}
float Mesh::getRadiusFrom(Point trans, Quaternion rot, Point center) const
{
std::vector<Point>::const_iterator vertex ;
float radius = 0.0F ;
for (vertex = verts.begin() ; vertex != verts.end() ; vertex++)
{
Point tv = rot.apply(*vertex) + trans;
float distance = (tv - center).length() ;
if (distance > radius)
radius = distance ;
}
return radius ;
}
float Mesh::getTubeRadius() const
{
std::vector<Point>::const_iterator vertex ;
float radius = 0.0F ;
for (vertex = verts.begin() ; vertex != verts.end() ; vertex++)
{
float distance = (*vertex - center).length(2) ;
if (distance > radius)
radius = distance ;
}
return radius ;
}
float Mesh::getTubeRadiusFrom(Point trans, Quaternion rot, Point center) const
{
std::vector<Point>::const_iterator vertex ;
float radius = 0.0F ;
for (vertex = verts.begin() ; vertex != verts.end() ; vertex++)
{
Point tv = rot.apply(*vertex) + trans;
float distance = (tv - center).length(2) ;
if (distance > radius)
radius = distance ;
}
return radius ;
}
// -----------------------------------------------------------------------
// Calculate the polygon count
// -----------------------------------------------------------------------
int Mesh::getPolyCount() const
{
int count = 0 ;
std::vector<Primitive>::const_iterator p ;
for (p = primitives.begin() ; p != primitives.end() ; p++)
{
if (p->type & Primitive::Strip)
count += p->numElements - 2 ;
else
count += p->numElements / 3 ;
}
return count ;
}
// -----------------------------------------------------------------------
// Creates an empty mesh
// -----------------------------------------------------------------------
Mesh::Mesh(Type t)
{
bounds.min = Point(0,0,0) ;
bounds.max = Point(0,0,0) ;
center = Point(0,0,0) ;
radius = 0.0f ;
numFrames = 1 ;
matFrames = 1 ;
vertsPerFrame = 0 ;
parent = -1 ;
flags = 0 ;
type = t ;
}
// -----------------------------------------------------------------------
// Joins another mesh with this one
// -----------------------------------------------------------------------
Mesh & Mesh::operator += (const Mesh & m)
{
int firstIndex = indices.size();
int firstVertex = verts.size() ;
int firstPrimit = primitives.size() ;
int i ;
verts.insert (verts.end(), m.verts.begin(), m.verts.end()) ;
tverts.insert (tverts.end(), m.tverts.begin(), m.tverts.end()) ;
indices.insert (indices.end(), m.indices.begin(), m.indices.end()) ;
normals.insert (normals.end(), m.normals.begin(), m.normals.end()) ;
enormals.insert (enormals.end(), m.enormals.begin(), m.enormals.end()) ;
primitives.insert (primitives.end(), m.primitives.begin(), m.primitives.end()) ;
for (i = firstIndex ; i < indices.size() ; i++)
indices[i] += firstVertex ;
for (i = firstPrimit ; i < primitives.size() ; i++)
primitives[i].firstElement += firstIndex ;
calculateBounds() ;
calculateCenter() ;
calculateRadius() ;
vertsPerFrame = verts.size() ;
return *this ;
}
// -----------------------------------------------------------------------
// Input/output
// -----------------------------------------------------------------------
void Mesh::read (InputStream &stream)
{
stream >> type ;
if (type == T_Null) return ;
stream.readCheck() ;
// Header & Bounds
stream >> numFrames >> matFrames >> parent ;
stream >> bounds >> center ;
int radiusInt ;
stream >> radiusInt ;
radius = (float)radiusInt ;
// Vertexes
int numVertexes ;
stream >> numVertexes ;
verts.resize (numVertexes) ;
stream >> verts ;
// Texture coordinates
int numTVerts ;
stream >> numTVerts ;
tverts.resize (numTVerts) ;
stream >> tverts ;
// Normals
normals.resize (numVertexes) ;
enormals.resize (numVertexes) ;
stream >> normals ;
stream >> enormals ;
// Primitives and other stuff
int numPrimitives ;
stream >> numPrimitives ;
primitives.resize (numPrimitives) ;
stream >> primitives ;
int numIndices ;
stream >> numIndices ;
indices.resize (numIndices) ;
stream >> indices ;
int numMIndices ;
stream >> numMIndices ;
mindices.resize (numMIndices) ;
stream >> mindices ;
stream >> vertsPerFrame >> flags ;
stream.readCheck() ;
}
void Mesh::save (OutputStream &stream) const
{
// Mesh Type
stream << type ;
if (type == T_Null) return ; // Null mesh has no data
stream.storeCheck() ;
// Header
stream << numFrames << matFrames << parent ; // Header
stream << bounds << center << (int)radius ; // Bounds
// Vertexes
stream << (int) verts.size() ;
stream << verts ;
// Texture coordinates
assert (tverts.size() == verts.size()) ;
stream << (int) tverts.size() ;
stream << tverts ;
// Normals
assert (normals.size() == verts.size()) ;
assert (enormals.size() == verts.size()) ;
stream << normals ;
stream << enormals ;
// Primitives
stream << (int) primitives.size() ;
stream << primitives ;
stream << (int) indices.size() ;
stream << indices ;
stream << (int) mindices.size() ;
stream << mindices ;
// Other small stuff
stream << vertsPerFrame << flags ;
stream.storeCheck() ;
// Skin Mesh support
if (type == T_Skin) {
// Initial skin vertices & normals of affected vertices.
// Yes, we did just write these out, but this is what it wants.
stream << (int) verts.size() ;
stream << verts;
stream << normals;
stream << enormals;
// Inverse world transforms for bones used in vertex weighting
assert(nodeTransform.size() == nodeIndex.size());
stream << (int) nodeIndex.size();
for (int n = 0; n < nodeIndex.size(); n++)
stream << nodeTransform[n];
// Vertex tuples. If this more than one entry per vertex, then
// these tables should be sorted by vindex.
assert (vweight.size() == vindex.size());
assert (vbone.size() == vindex.size());
stream << (int) vindex.size();
stream << vindex;
stream << vbone;
stream << vweight;
// Vertex bone to node table
stream << (int) nodeIndex.size();
stream << nodeIndex;
stream.storeCheck();
}
if (type == T_Sorted) {
stream << (int) clusters.size();
stream << clusters;
stream << (int) startCluster.size();
stream << startCluster;
stream << (int) firstVerts.size();
stream << firstVerts;
stream << (int) numVerts.size();
stream << numVerts;
stream << (int) firstTVerts.size();
stream << firstTVerts;
stream << (int) alwaysWriteDepth; // alwaysWriteDepth deprecated
stream.storeCheck();
}
}
// -----------------------------------------------------------------------
// Utility stuff
// -----------------------------------------------------------------------
void Mesh::setMaterial (int n)
{
std::vector<Primitive>::iterator p ;
for (p = primitives.begin() ; p != primitives.end() ; p++)
{
p->type = (p->type & ~Primitive::MaterialMask) |
(n & Primitive::MaterialMask) ;
// Just in case
p->type &= ~Primitive::NoMaterial ;
}
}
void Mesh::translate(const Point n)
{
std::vector<Point>::iterator v ;
for (v = verts.begin() ; v != verts.end() ; v++)
*v += n ;
calculateBounds() ;
calculateCenter() ;
calculateRadius() ;
}
void Mesh::rotate (const Quaternion &q)
{
std::vector<Point>::iterator v ;
for (v = verts.begin() ; v != verts.end() ; v++)
*v = q.apply(*v);
calculateBounds() ;
calculateCenter() ;
calculateRadius() ;
}
int Mesh::getVertexBone(int node)
{
// Finds the bone index in the table, or adds it if it's
// not there. The vertex bone & nodeIndex list are here to
// track which bones are used by this mesh.
int b = 0;
for (; b < nodeIndex.size(); b++)
if (nodeIndex[b] == node)
return b;
nodeIndex.push_back(node);
nodeTransform.push_back(Matrix<4,4>::identity());
return b;
}
void Mesh::setNodeTransform(int node,Point t, Quaternion q)
{
// Build inverse transform, the mesh wants to be able to
// transform the vertices into node space.
assert(node < nodeTransform.size());
t = q.inverse().apply(-t);
Matrix<4,4>::Row row;
row[0] = t.x(); row[1] = t.y(); row[2] = t.z(); row[3] = 1;
// The toMatrix builds a transposed transform from what we
// want, so we need to pass the original quaternion to get
// the inverse.
nodeTransform[node] = q.toMatrix();
nodeTransform[node].setCol(3,row);
}
};

201
lib/dtsSDK/DTSMesh.h Executable file
View File

@ -0,0 +1,201 @@
#ifndef __DTSMESH_H
#define __DTSMESH_H
#include "DTSPoint.h"
#include "DTSMatrix.h"
namespace DTS
{
// Forward reference;
class Quaternion;
//! Defines a primitive as stored in the DTS file
struct Primitive
{
short firstElement ; //!< Number of consecutive indices used
short numElements ; //!< Number of the first index
int type ; //!< Type of primitive and number of material used
enum /* type */
{
Triangles = 0x00000000,
Strip = 0x40000000,
Fan = 0x80000000, //!< WARNING! May not be supported
TypeMask = 0xC0000000,
Indexed = 0x20000000, //!< WARNING! Non-indexed primitives not supported in the engine
NoMaterial = 0x10000000,
MaterialMask = 0x0FFFFFFF,
};
};
//! Defines type used by sort meshes (cluster of faces that are rendered together)
struct Cluster
{
int startPrimitive;
int endPrimitive;
Point3D normal;
float k;
int frontCluster; ///< go to this cluster if in front of plane, if frontCluster<0, no cluster
int backCluster; ///< go to this cluster if in back of plane, if backCluster<0, no cluster
///< if frontCluster==backCluster, no plane to test against...
};
//! Defines a Mesh as stored in the DTS file
// Skin render...
// NodeIndex loop
// Vb[n] = nodeTransform[nodeIndex[n]] * InitialTransform[n]
// Vertex loop
// v[vindex[n]] += initialVerts[n] * Vb[boneIndex[n]] * weight[n]
class Mesh
{
friend class ShapeMimic;
friend class TranslucentSort;
public:
//! Mesh types
enum Type
{
T_Standard = 0, //!< Rigid mesh
T_Skin = 1, //!< TODO: Skined (mesh with bones)
T_Decal = 2, //!< DEPRECATED
T_Sorted = 3, //!< BSP Sorted for correct alpha rendering
T_Null = 4 //!< Null mesh, used in collision objects as the visible meshes
};
//!< Mesh flags
enum Flag
{
Billboard = 0x80000000, //!< Mesh always faces the camera
HasDetail = 0x40000000, //!< Mesh use Detailmap, search for Detailmap reference in Material
BillboardZ = 0x20000000, //!< If billboard, only rotate around Z axis
EncodedNormals = 0x10000000, //!< Mesh uses encoded normals
} ;
//! Create an empty mesh of the given type
Mesh (Type t = T_Null) ;
//! Change object type
Type getType() { return (Type)type; }
void setType(Type t) { type = t; }
//! Set mesh flags
void setFlag(int f) { flags |= f; }
//! Save the mesh to a special DTS stream
void save (class OutputStream &) const ;
//! Read the mesh from a special DTS stream
void read (class InputStream &stream) ;
//! Calculates and returns the number of polygons
int getPolyCount() const ;
//! Get the radius of the bounding sphere
float getRadius() const { return radius ; }
//! Get the center point of mesh (and mesh's bounding sphere)
Point getCenter() const { return center ; }
//! Get the bounding box of the mesh
Box getBounds() const { return bounds ; }
//! Get the transformed bounding box of the mesh
Box getBounds(Point, Quaternion) const;
//! Calculate the radius of a bounding sphere, if it is centered in the given point
float getRadiusFrom(Point, Quaternion, Point center) const ;
//! Get the tube radius (radius of bounding cylinder)
float getTubeRadius() const ;
//! Calculate the radius of a bounding cylinder, if it is centered in the given point
float getTubeRadiusFrom(Point, Quaternion, Point center) const ;
//! Joins another mesh with this one (imports all vertexes and triangles)
Mesh & operator += (const Mesh &) ;
//! Change the material of the mesh
void setMaterial(int n) ;
//! Move all the vertexes in a direction
void translate(const Point n) ;
//! Rotates all vertexes
void rotate (const class Quaternion &q) ;
//! Return a vertex bone number for the given node
int getVertexBone(int node);
//! Return the node for a given vertex bone
int getNodeIndexCount() { return nodeIndex.size(); }
int getNodeIndex(int node) {
return (node >= 0 && node < int(nodeIndex.size())) ? nodeIndex[node] : -1;
}
void setNodeTransform(int node,Point t, Quaternion q);
protected:
void setCenter(Point c) { center = c; }
void setBounds(Box b) { bounds = b; }
void setRadius(float r) { radius = r; }
void setFrames(int n) { numFrames = n ; vertsPerFrame = verts.size()/n ; }
void setParent(int n) { parent = n; }
protected:
void calculateBounds() ;
void calculateCenter() ;
void calculateRadius() ;
static char encodeNormal(const Point &) ;
std::vector <Point> verts ; //!< Contains all mesh vertexes
std::vector <Point2D> tverts ; //!< Texture coordinates s, t for each vertex
std::vector <Point> normals ; //!< Normals for each vertex
std::vector <char> enormals ; //!< Encoded normals (see encodeNormal)
std::vector <Primitive> primitives; //!< Mesh primitives
std::vector <unsigned short> indices ; //!< Vertex index array, for primitives
std::vector <unsigned short> mindices ; //!< ?
// Extended data used by Skin Meshes
std::vector <int> vindex; //!< Vertex index
std::vector <int> vbone; //!< Vertex vbone
std::vector <float> vweight; //!< Vertex weight
std::vector <int> nodeIndex; //!< vbone -> node
std::vector <Matrix<4,4> > nodeTransform; //!<
// Extended data used by sort Meshes
std::vector <Cluster> clusters; ///< All of the clusters of primitives to be drawn
std::vector <int> startCluster; ///< indexed by frame number
std::vector <int> firstVerts; ///< indexed by frame number
std::vector <int> numVerts; ///< indexed by frame number
std::vector <int> firstTVerts; ///< indexed by frame number or matFrame number, depending on which one animates (never both)
bool alwaysWriteDepth;
private:
int type ;
int numFrames ;
int matFrames ;
int parent ;
Box bounds ;
Point center ;
float radius ;
int vertsPerFrame ;
int flags ;
};
}
#endif

261
lib/dtsSDK/DTSNormalTable.cpp Executable file
View File

@ -0,0 +1,261 @@
const static float normalTable[256][3] =
{
{ 0.565061f, -0.270644f, -0.779396f },
{ -0.309804f, -0.731114f, 0.607860f },
{ -0.867412f, 0.472957f, 0.154619f },
{ -0.757488f, 0.498188f, -0.421925f },
{ 0.306834f, -0.915340f, 0.260778f },
{ 0.098754f, 0.639153f, -0.762713f },
{ 0.713706f, -0.558862f, -0.422252f },
{ -0.890431f, -0.407603f, -0.202466f },
{ 0.848050f, -0.487612f, -0.207475f },
{ -0.232226f, 0.776855f, 0.585293f },
{ -0.940195f, 0.304490f, -0.152706f },
{ 0.602019f, -0.491878f, -0.628991f },
{ -0.096835f, -0.494354f, -0.863850f },
{ 0.026630f, -0.323659f, -0.945799f },
{ 0.019208f, 0.909386f, 0.415510f },
{ 0.854440f, 0.491730f, 0.167731f },
{ -0.418835f, 0.866521f, -0.271512f },
{ 0.465024f, 0.409667f, 0.784809f },
{ -0.674391f, -0.691087f, -0.259992f },
{ 0.303858f, -0.869270f, -0.389922f },
{ 0.991333f, 0.090061f, -0.095640f },
{ -0.275924f, -0.369550f, 0.887298f },
{ 0.426545f, -0.465962f, 0.775202f },
{ -0.482741f, -0.873278f, -0.065920f },
{ 0.063616f, 0.932012f, -0.356800f },
{ 0.624786f, -0.061315f, 0.778385f },
{ -0.530300f, 0.416850f, 0.738253f },
{ 0.312144f, -0.757028f, -0.573999f },
{ 0.399288f, -0.587091f, -0.704197f },
{ -0.132698f, 0.482877f, 0.865576f },
{ 0.950966f, 0.306530f, 0.041268f },
{ -0.015923f, -0.144300f, 0.989406f },
{ -0.407522f, -0.854193f, 0.322925f },
{ -0.932398f, 0.220464f, 0.286408f },
{ 0.477509f, 0.876580f, 0.059936f },
{ 0.337133f, 0.932606f, -0.128796f },
{ -0.638117f, 0.199338f, 0.743687f },
{ -0.677454f, 0.445349f, 0.585423f },
{ -0.446715f, 0.889059f, -0.100099f },
{ -0.410024f, 0.909168f, 0.072759f },
{ 0.708462f, 0.702103f, -0.071641f },
{ -0.048801f, -0.903683f, -0.425411f },
{ -0.513681f, -0.646901f, 0.563606f },
{ -0.080022f, 0.000676f, -0.996793f },
{ 0.066966f, -0.991150f, -0.114615f },
{ -0.245220f, 0.639318f, -0.728793f },
{ 0.250978f, 0.855979f, 0.452006f },
{ -0.123547f, 0.982443f, -0.139791f },
{ -0.794825f, 0.030254f, -0.606084f },
{ -0.772905f, 0.547941f, 0.319967f },
{ 0.916347f, 0.369614f, -0.153928f },
{ -0.388203f, 0.105395f, 0.915527f },
{ -0.700468f, -0.709334f, 0.078677f },
{ -0.816193f, 0.390455f, 0.425880f },
{ -0.043007f, 0.769222f, -0.637533f },
{ 0.911444f, 0.113150f, 0.395560f },
{ 0.845801f, 0.156091f, -0.510153f },
{ 0.829801f, -0.029340f, 0.557287f },
{ 0.259529f, 0.416263f, 0.871418f },
{ 0.231128f, -0.845982f, 0.480515f },
{ -0.626203f, -0.646168f, 0.436277f },
{ -0.197047f, -0.065791f, 0.978184f },
{ -0.255692f, -0.637488f, -0.726794f },
{ 0.530662f, -0.844385f, -0.073567f },
{ -0.779887f, 0.617067f, -0.104899f },
{ 0.739908f, 0.113984f, 0.662982f },
{ -0.218801f, 0.930194f, -0.294729f },
{ -0.374231f, 0.818666f, 0.435589f },
{ -0.720250f, -0.028285f, 0.693137f },
{ 0.075389f, 0.415049f, 0.906670f },
{ -0.539724f, -0.106620f, 0.835063f },
{ -0.452612f, -0.754669f, -0.474991f },
{ 0.682822f, 0.581234f, -0.442629f },
{ 0.002435f, -0.618462f, -0.785811f },
{ -0.397631f, 0.110766f, -0.910835f },
{ 0.133935f, -0.985438f, 0.104754f },
{ 0.759098f, -0.608004f, 0.232595f },
{ -0.825239f, -0.256087f, 0.503388f },
{ 0.101693f, -0.565568f, 0.818408f },
{ 0.386377f, 0.793546f, -0.470104f },
{ -0.520516f, -0.840690f, 0.149346f },
{ -0.784549f, -0.479672f, 0.392935f },
{ -0.325322f, -0.927581f, -0.183735f },
{ -0.069294f, -0.428541f, 0.900861f },
{ 0.993354f, -0.115023f, -0.004288f },
{ -0.123896f, -0.700568f, 0.702747f },
{ -0.438031f, -0.120880f, -0.890795f },
{ 0.063314f, 0.813233f, 0.578484f },
{ 0.322045f, 0.889086f, -0.325289f },
{ -0.133521f, 0.875063f, -0.465228f },
{ 0.637155f, 0.564814f, 0.524422f },
{ 0.260092f, -0.669353f, 0.695930f },
{ 0.953195f, 0.040485f, -0.299634f },
{ -0.840665f, -0.076509f, 0.536124f },
{ -0.971350f, 0.202093f, 0.125047f },
{ -0.804307f, -0.396312f, -0.442749f },
{ -0.936746f, 0.069572f, 0.343027f },
{ 0.426545f, -0.465962f, 0.775202f },
{ 0.794542f, -0.227450f, 0.563000f },
{ -0.892172f, 0.091169f, -0.442399f },
{ -0.312654f, 0.541264f, 0.780564f },
{ 0.590603f, -0.735618f, -0.331743f },
{ -0.098040f, -0.986713f, 0.129558f },
{ 0.569646f, 0.283078f, -0.771603f },
{ 0.431051f, -0.407385f, -0.805129f },
{ -0.162087f, -0.938749f, -0.304104f },
{ 0.241533f, -0.359509f, 0.901341f },
{ -0.576191f, 0.614939f, 0.538380f },
{ -0.025110f, 0.085740f, 0.996001f },
{ -0.352693f, -0.198168f, 0.914515f },
{ -0.604577f, 0.700711f, 0.378802f },
{ 0.465024f, 0.409667f, 0.784809f },
{ -0.254684f, -0.030474f, -0.966544f },
{ -0.604789f, 0.791809f, 0.085259f },
{ -0.705147f, -0.399298f, 0.585943f },
{ 0.185691f, 0.017236f, -0.982457f },
{ 0.044588f, 0.973094f, 0.226052f },
{ -0.405463f, 0.642367f, 0.650357f },
{ -0.563959f, 0.599136f, -0.568319f },
{ 0.367162f, -0.072253f, -0.927347f },
{ 0.960429f, -0.213570f, -0.178783f },
{ -0.192629f, 0.906005f, 0.376893f },
{ -0.199718f, -0.359865f, -0.911378f },
{ 0.485072f, 0.121233f, -0.866030f },
{ 0.467163f, -0.874294f, 0.131792f },
{ -0.638953f, -0.716603f, 0.279677f },
{ -0.622710f, 0.047813f, -0.780990f },
{ 0.828724f, -0.054433f, -0.557004f },
{ 0.130241f, 0.991080f, 0.028245f },
{ 0.310995f, -0.950076f, -0.025242f },
{ 0.818118f, 0.275336f, 0.504850f },
{ 0.676328f, 0.387023f, 0.626733f },
{ -0.100433f, 0.495114f, -0.863004f },
{ -0.949609f, -0.240681f, -0.200786f },
{ -0.102610f, 0.261831f, -0.959644f },
{ -0.845732f, -0.493136f, 0.203850f },
{ 0.672617f, -0.738838f, 0.041290f },
{ 0.380465f, 0.875938f, 0.296613f },
{ -0.811223f, 0.262027f, -0.522742f },
{ -0.074423f, -0.775670f, -0.626736f },
{ -0.286499f, 0.755850f, -0.588735f },
{ 0.291182f, -0.276189f, -0.915933f },
{ -0.638117f, 0.199338f, 0.743687f },
{ 0.439922f, -0.864433f, -0.243359f },
{ 0.177649f, 0.206919f, 0.962094f },
{ 0.277107f, 0.948521f, 0.153361f },
{ 0.507629f, 0.661918f, -0.551523f },
{ -0.503110f, -0.579308f, -0.641313f },
{ 0.600522f, 0.736495f, -0.311364f },
{ -0.691096f, -0.715301f, -0.103592f },
{ -0.041083f, -0.858497f, 0.511171f },
{ 0.207773f, -0.480062f, -0.852274f },
{ 0.795719f, 0.464614f, 0.388543f },
{ -0.100433f, 0.495114f, -0.863004f },
{ 0.703249f, 0.065157f, -0.707951f },
{ -0.324171f, -0.941112f, 0.096024f },
{ -0.134933f, -0.940212f, 0.312722f },
{ -0.438240f, 0.752088f, -0.492249f },
{ 0.964762f, -0.198855f, 0.172311f },
{ -0.831799f, 0.196807f, 0.519015f },
{ -0.508008f, 0.819902f, 0.263986f },
{ 0.471075f, -0.001146f, 0.882092f },
{ 0.919512f, 0.246162f, -0.306435f },
{ -0.960050f, 0.279828f, -0.001187f },
{ 0.110232f, -0.847535f, -0.519165f },
{ 0.208229f, 0.697360f, 0.685806f },
{ -0.199680f, -0.560621f, 0.803637f },
{ 0.170135f, -0.679985f, -0.713214f },
{ 0.758371f, -0.494907f, 0.424195f },
{ 0.077734f, -0.755978f, 0.649965f },
{ 0.612831f, -0.672475f, 0.414987f },
{ 0.142776f, 0.836698f, -0.528726f },
{ -0.765185f, 0.635778f, 0.101382f },
{ 0.669873f, -0.419737f, 0.612447f },
{ 0.593549f, 0.194879f, 0.780847f },
{ 0.646930f, 0.752173f, 0.125368f },
{ 0.837721f, 0.545266f, -0.030127f },
{ 0.541505f, 0.768070f, 0.341820f },
{ 0.760679f, -0.365715f, -0.536301f },
{ 0.381516f, 0.640377f, 0.666605f },
{ 0.565794f, -0.072415f, -0.821361f },
{ -0.466072f, -0.401588f, 0.788356f },
{ 0.987146f, 0.096290f, 0.127560f },
{ 0.509709f, -0.688886f, -0.515396f },
{ -0.135132f, -0.988046f, -0.074192f },
{ 0.600499f, 0.476471f, -0.642166f },
{ -0.732326f, -0.275320f, -0.622815f },
{ -0.881141f, -0.470404f, 0.048078f },
{ 0.051548f, 0.601042f, 0.797553f },
{ 0.402027f, -0.763183f, 0.505891f },
{ 0.404233f, -0.208288f, 0.890624f },
{ -0.311793f, 0.343843f, 0.885752f },
{ 0.098132f, -0.937014f, 0.335223f },
{ 0.537158f, 0.830585f, -0.146936f },
{ 0.725277f, 0.298172f, -0.620538f },
{ -0.882025f, 0.342976f, -0.323110f },
{ -0.668829f, 0.424296f, -0.610443f },
{ -0.408835f, -0.476442f, -0.778368f },
{ 0.809472f, 0.397249f, -0.432375f },
{ -0.909184f, -0.205938f, -0.361903f },
{ 0.866930f, -0.347934f, -0.356895f },
{ 0.911660f, -0.141281f, -0.385897f },
{ -0.431404f, -0.844074f, -0.318480f },
{ -0.950593f, -0.073496f, 0.301614f },
{ -0.719716f, 0.626915f, -0.298305f },
{ -0.779887f, 0.617067f, -0.104899f },
{ -0.475899f, -0.542630f, 0.692151f },
{ 0.081952f, -0.157248f, -0.984153f },
{ 0.923990f, -0.381662f, -0.024025f },
{ -0.957998f, 0.120979f, -0.260008f },
{ 0.306601f, 0.227975f, -0.924134f },
{ -0.141244f, 0.989182f, 0.039601f },
{ 0.077097f, 0.186288f, -0.979466f },
{ -0.630407f, -0.259801f, 0.731499f },
{ 0.718150f, 0.637408f, 0.279233f },
{ 0.340946f, 0.110494f, 0.933567f },
{ -0.396671f, 0.503020f, -0.767869f },
{ 0.636943f, -0.245005f, 0.730942f },
{ -0.849605f, -0.518660f, -0.095724f },
{ -0.388203f, 0.105395f, 0.915527f },
{ -0.280671f, -0.776541f, -0.564099f },
{ -0.601680f, 0.215451f, -0.769131f },
{ -0.660112f, -0.632371f, -0.405412f },
{ 0.921096f, 0.284072f, 0.266242f },
{ 0.074850f, -0.300846f, 0.950731f },
{ 0.943952f, -0.067062f, 0.323198f },
{ -0.917838f, -0.254589f, 0.304561f },
{ 0.889843f, -0.409008f, 0.202219f },
{ -0.565849f, 0.753721f, -0.334246f },
{ 0.791460f, 0.555918f, -0.254060f },
{ 0.261936f, 0.703590f, -0.660568f },
{ -0.234406f, 0.952084f, 0.196444f },
{ 0.111205f, 0.979492f, -0.168014f },
{ -0.869844f, -0.109095f, -0.481113f },
{ -0.337728f, -0.269701f, -0.901777f },
{ 0.366793f, 0.408875f, -0.835634f },
{ -0.098749f, 0.261316f, 0.960189f },
{ -0.272379f, -0.847100f, 0.456324f },
{ -0.319506f, 0.287444f, -0.902935f },
{ 0.873383f, -0.294109f, 0.388203f },
{ -0.088950f, 0.710450f, 0.698104f },
{ 0.551238f, -0.786552f, 0.278340f },
{ 0.724436f, -0.663575f, -0.186712f },
{ 0.529741f, -0.606539f, 0.592861f },
{ -0.949743f, -0.282514f, 0.134809f },
{ 0.155047f, 0.419442f, -0.894443f },
{ -0.562653f, -0.329139f, -0.758346f },
{ 0.816407f, -0.576953f, 0.024576f },
{ 0.178550f, -0.950242f, -0.255266f },
{ 0.479571f, 0.706691f, 0.520192f },
{ 0.391687f, 0.559884f, -0.730145f },
{ 0.724872f, -0.205570f, -0.657496f },
{ -0.663196f, -0.517587f, -0.540624f },
{ -0.660054f, -0.122486f, -0.741165f },
{ -0.531989f, 0.374711f, -0.759328f },
{ 0.194979f, -0.059120f, 0.979024f }
} ;

438
lib/dtsSDK/DTSOutputStream.h Executable file
View File

@ -0,0 +1,438 @@
#ifndef __DTSOUTPUTSTREAM_H
#define __DTSOUTPUTSTREAM_H
#include <cassert>
#include <vector>
#include <fstream>
#include "DTSShape.h"
#include "DTSQuaternion.h"
#include "DTSMatrix.h"
#include "DTSEndian.h"
using namespace std;
namespace DTS
{
// -------------------------------------------------------------------------
// class OutputStream
// --------------------------------------------------------------------------
/*! The DTS file format stores in separate buffers values of 8, 16 or 32
bits of length, in order to speed up loading in non-Intel platforms.
In order to create a DTS file you should create the three buffers in
memory and then begin writting the data using helper functions. This
mimics the way the data is retrieved in the engine.
This class provides the needed functionality. Simply create a
OutputStream object and write the data using the "write" method,
that stores the values in the correct buffer. The "flush" method
creates finally the file in the format expected by the V12 engine.
The class knowns about all DTS namespace simple objects and can
save them (operator <<) in the expected format.
*** WARNING *** THIS CODE IS NOT PORTABLE
This code assumes a little-endian 32 bits machine
*/
class OutputStream
{
public:
//! Initialize the stream. The version number is written in the header
OutputStream (std::ostream &, int DTSVersion = 24) ;
~OutputStream () ;
//! Wite "count" dwords (= count x 4 bytes)
void write (const int *, int count) ;
//! Write "count" words (= count x 2 bytes)
void write (const short *, int count) ;
//! Write "count" bytes
void write (const char *, int count) ;
//! Write one dword
OutputStream & operator << (const int value) { write(&value, 1) ; return *this ; }
//! Write one word
OutputStream & operator << (const short value) { write(&value, 1) ; return *this ; }
OutputStream & operator << (const unsigned short value) { write((const short*)&value, 1) ; return *this ; }
//! Write one byte
OutputStream & operator << (const char value) { write(&value, 1) ; return *this ; }
//! Write one dword (1 float == 32 bits)
OutputStream & operator << (const float value)
{
write((int *)&value, 1) ;
return *this ;
}
//! Write one byte (provided for convenience)
OutputStream & operator << (const unsigned char value)
{
write((char *)&value, 1) ;
return *this ;
}
//! Write a string (1 byte len first, then n byte-sized characters)
OutputStream & operator << (const std::string &s) ;
// Operators to write some usual structs
OutputStream & operator << (const Point &) ;
OutputStream & operator << (const Point2D &) ;
OutputStream & operator << (const Box &) ;
OutputStream & operator << (const Quaternion &) ;
OutputStream & operator << (const Node &) ;
OutputStream & operator << (const Object &) ;
OutputStream & operator << (const Decal &) ;
OutputStream & operator << (const IFLMaterial &) ;
OutputStream & operator << (const DecalState &) ;
OutputStream & operator << (const DetailLevel &) ;
OutputStream & operator << (const ObjectState &) ;
OutputStream & operator << (const Subshape &) ;
OutputStream & operator << (const Trigger &) ;
OutputStream & operator << (const Primitive &) ;
OutputStream & operator << (const Mesh &) ;
OutputStream & operator << (const Cluster &) ;
OutputStream & operator << (const Matrix<4,4> &) ;
//! Stores checkpoint values in the streams
void storeCheck (int checkPoint = -1) ;
//! When you're finished, call this method to create the file
//! You'll still need to write the sequence data to the stream, next
void flush () ;
private:
std::ostream & out ;
int DTSVersion ;
int checkCount ;
// Pointers to the 3 memory buffers
int * Buffer32 ;
short * Buffer16 ;
char * Buffer8 ;
// Values allocated in each buffer
unsigned long Allocated32 ;
unsigned long Allocated16 ;
unsigned long Allocated8 ;
// Values actually used in each buffer
unsigned long Used32 ;
unsigned long Used16 ;
unsigned long Used8 ;
};
// --------------------------------------------------------------------------
// Construction and destruction
// --------------------------------------------------------------------------
inline OutputStream::OutputStream (std::ostream & s, int version)
: out(s), DTSVersion(version)
{
// Versions 17 and down don't use the buffers
assert (version >= 18) ;
// Create buffers with some unused space in
Buffer32 = new int [64] ;
Buffer16 = new short [128] ;
Buffer8 = new char [256] ;
Allocated32 = 64 ;
Allocated16 = 128 ;
Allocated8 = 256 ;
Used32 = 0 ;
Used16 = 0 ;
Used8 = 0 ;
checkCount = 0 ;
}
inline OutputStream::~OutputStream()
{
delete [] Buffer8 ;
delete [] Buffer16 ;
delete [] Buffer32 ;
}
// --------------------------------------------------------------------------
// Write functions
// --------------------------------------------------------------------------
/*! All 32 bits dwords must be written to the internal 32-bits buffer
so they can be reversed in a single pass in big-endian machines */
inline void OutputStream::write (const int * data, int count)
{
assert (count > 0) ;
assert (data != 0) ;
if (Used32 + count > Allocated32)
{
// Not enough space allocated. Alloc a bigger buffer,
// with a multiple of 64 number of elements, but enough
// to add the new data, and swap the old buffer for it
Allocated32 = ((Used32 + count) & ~63) + 64 ;
assert (Allocated32 > Used32 + count) ;
int * NewBuffer32 = new int[Allocated32] ;
memcpy (NewBuffer32, Buffer32, sizeof(int) * Used32) ;
delete [] Buffer32 ;
Buffer32 = NewBuffer32 ;
}
// Add the new data to the buffer
memcpy (Buffer32 + Used32, data, sizeof(int) * count) ;
Used32 += count ;
}
// The other write methods are exactly the same, except for the buffer used
inline void OutputStream::write (const short * data, int count)
{
assert (count > 0) ;
assert (data != 0) ;
if (Used16 + count > Allocated16)
{
Allocated16 = ((Used16 + count) & ~63) + 64 ;
assert (Allocated16 > Used16 + count) ;
short * NewBuffer16 = new short[Allocated16] ;
memcpy (NewBuffer16, Buffer16, sizeof(short) * Used16) ;
delete [] Buffer16 ;
Buffer16 = NewBuffer16 ;
}
memcpy (Buffer16 + Used16, data, sizeof(short) * count) ;
Used16 += count ;
}
inline void OutputStream::write (const char * data, int count)
{
assert (count > 0) ;
assert (data != 0) ;
if (Used8 + count > Allocated8)
{
Allocated8 = ((Used8 + count) & ~63) + 64 ;
assert (Allocated8 > Used8 + count) ;
char * NewBuffer8 = new char[Allocated8] ;
memcpy (NewBuffer8, Buffer8, sizeof(char) * Used8) ;
delete [] Buffer8 ;
Buffer8 = NewBuffer8 ;
}
memcpy (Buffer8 + Used8, data, sizeof(char) * count) ;
Used8 += count ;
}
// --------------------------------------------------------------------------
// Write operators
// --------------------------------------------------------------------------
inline OutputStream & OutputStream::operator << (const Point &p)
{
return (*this) << p.x() << p.y() << p.z() ;
}
inline OutputStream & OutputStream::operator << (const Point2D &p)
{
return (*this) << p.x() << p.y() ;
}
inline OutputStream & OutputStream::operator << (const Box &b)
{
return (*this) << b.min << b.max ;
}
inline OutputStream & OutputStream::operator << (const Quaternion &q)
{
return (*this) << (short)(q.x() * 32767.0f)
<< (short)(q.y() * 32767.0f)
<< (short)(q.z() * 32767.0f)
<< (short)(q.w() * 32767.0f) ;
}
inline OutputStream & OutputStream::operator << (const Node &n)
{
return (*this) << n.name << n.parent << n.firstObject
<< n.child << n.sibling ;
}
inline OutputStream & OutputStream::operator << (const Object &o)
{
return (*this) << o.name << o.numMeshes << o.firstMesh
<< o.node << o.sibling << o.firstDecal ;
}
inline OutputStream & OutputStream::operator << (const Decal &d)
{
return (*this) << d.name << d.numMeshes << d.firstMesh
<< d.object << d.sibling ;
}
inline OutputStream & OutputStream::operator << (const IFLMaterial &m)
{
return (*this) << m.name << m.slot << m.firstFrame
<< m.time << m.numFrames ;
}
inline OutputStream & OutputStream::operator << (const Subshape &s)
{
assert (0 && "Subshapes should be written in block") ;
}
inline OutputStream & OutputStream::operator << (const Trigger &d)
{
return (*this) << d.state << d.pos ;
}
inline OutputStream & OutputStream::operator << (const DecalState &d)
{
return (*this) << d.frame ;
}
inline OutputStream & OutputStream::operator << (const ObjectState &o)
{
return (*this) << o.vis << o.frame << o.matFrame ;
}
inline OutputStream & OutputStream::operator << (const DetailLevel &d)
{
return (*this) << d.name << d.subshape << d.objectDetail << d.size
<< d.avgError << d.maxError << d.polyCount ;
}
inline OutputStream & OutputStream::operator << (const Primitive &p)
{
return (*this) << p.firstElement << p.numElements << p.type ;
}
inline OutputStream & OutputStream::operator << (const Mesh &m)
{
m.save(*this) ;
return *this ;
}
inline OutputStream & OutputStream::operator << (const Cluster &c)
{
return *this << c.startPrimitive << c.endPrimitive << c.normal << c.k << c.frontCluster << c.backCluster;
}
inline OutputStream & OutputStream::operator << (const std::string &s)
{
std::string::const_iterator pos = s.begin() ;
while (pos != s.end()) (*this) << *pos++ ;
(*this) << '\x00' ;
return *this ;
}
template <class type>
inline OutputStream & operator << (OutputStream & out, const std::vector<type> &v)
{
typename vector<type>::const_iterator pos = v.begin() ;
while (pos != v.end())
{
out << *pos++ ;
}
return out ;
}
inline OutputStream & OutputStream::operator << (const Matrix<4,4> &m)
{
for (int r = 0 ; r < 4 ; r++)
for (int c = 0 ; c < 4 ; c++)
(*this) << m[r][c];
return *this;
}
// --------------------------------------------------------------------------
// Checkpoints and alignment
// --------------------------------------------------------------------------
/*! Sometimes during the storing process, a checkpoint value is
stored to all the buffers at the same time. This check helps
to determine if the files are not corrupted. */
inline void OutputStream::storeCheck(int checkPoint)
{
if (checkPoint >= 0)
assert (checkPoint == checkCount) ;
(*this) << (int) checkCount ;
(*this) << (short) checkCount ;
(*this) << (char) checkCount ;
checkCount++ ;
}
// --------------------------------------------------------------------------
// Flush method
// --------------------------------------------------------------------------
/*! The file format wants a header with the version number, total size
of all three buffers (in dwords), and the offsets of the 16-bits
and 8-bits buffers, followed with the buffer data itself.
There is additional information that is stored after this data,
but we don't know about it here */
inline void OutputStream::flush ()
{
int totalSize ;
int offset16 ;
int offset8 ;
int i;
// Force all buffers to have a size multiple of 4 bytes
if (Used16 & 0x0001) (*this) << (short)0 ;
while (Used8 & 0x0003) (*this) << (char) 0 ;
// Compute the header values (in dwords)
offset16 = Used32 ;
offset8 = Used32 + Used16/2 ;
totalSize = Used32 + Used16/2 + Used8/4 ;
// Fix endian...
if (!isLittleEndian())
{
for (i=0; i<Used16; i++)
Buffer16[i] = FIX_ENDIAN(Buffer16[i]);
for (i=0; i<Used32; i++)
Buffer32[i] = FIX_ENDIAN(Buffer32[i]);
}
// Write the resulting data to the file
std::streampos pos = out.tellp() ;
out.write ((char *) &FIX_ENDIAN(DTSVersion), 4) ;
out.write ((char *) &FIX_ENDIAN(totalSize), 4) ;
out.write ((char *) &FIX_ENDIAN(offset16), 4) ;
out.write ((char *) &FIX_ENDIAN(offset8), 4) ;
out.write ((char *) Buffer32, 4 * Used32) ;
out.write ((char *) Buffer16, 2 * Used16) ;
out.write (Buffer8, Used8) ;
std::streampos endpos = out.tellp() ;
assert ((endpos - pos) == (std::streampos)(4*Used32 + 2*Used16 + 1*Used8 + 16)) ;
}
}
#endif

75
lib/dtsSDK/DTSPoint.h Executable file
View File

@ -0,0 +1,75 @@
#ifndef __DTSPOINT_H
#define __DTSPOINT_H
#include <iomanip>
#include <iostream>
#include "DTSVector.h"
namespace DTS
{
class Point3D : public Vector<float, 3>
{
public:
Point3D() {}
Point3D(const Point3D &n) : Vector<float,3>(n) {}
Point3D(const Vector<float,3> &n) : Vector<float,3>(n) {}
Point3D(float x, float y, float z) { set (0,x), set(1,y), set(2,z); }
float x() const { return get(0); }
float y() const { return get(1); }
float z() const { return get(2); }
void x(float n) { set (0, n) ; }
void y(float n) { set (1, n) ; }
void z(float n) { set (2, n) ; }
};
typedef Point3D Point ;
class Point2D : public Vector<float, 2>
{
public:
Point2D() {}
Point2D(const Point2D &n) : Vector<float,2>(n) {}
Point2D(const Vector<float,2> &n) : Vector<float,2>(n) {}
Point2D(float x, float y) { set(0,x), set(1,y); }
float x() const { return get(0); }
float y() const { return get(1); }
void x(float n) { set (0, n) ; }
void y(float n) { set (1, n) ; }
};
//! Defines a box in space. Used for bounding boxes.
struct Box
{
Point min, max ;
Box() {}
//! Create a box from two size in space. Note that no check is done,
//! the two size need to define a correct box (min < max)
Box(Point MIN, Point MAX) { min = MIN; max = MAX; }
};
inline std::ostream & operator << (std::ostream &out, const Point3D &q)
{
out << std::setprecision(2) << std::setiosflags(std::ios::fixed) ;
return out << "< " << q.x() << ", " << q.y() << ", " << q.z() << " >" ;
}
inline std::ostream & operator << (std::ostream &out, const Point2D &q)
{
out << std::setprecision(2) << std::setiosflags(std::ios::fixed) ;
return out << "< " << q.x() << ", " << q.y() << " >" ;
}
inline std::ostream & operator << (std::ostream &out, const Box &q)
{
out << std::setprecision(2) << std::setiosflags(std::ios::fixed) ;
return out << "( " << q.min << " - " ;
}
}
#endif

140
lib/dtsSDK/DTSQuaternion.cpp Executable file
View File

@ -0,0 +1,140 @@
#pragma warning ( disable: 4786 4018 )
#include <vector>
#include <cmath>
#include "DTSQuaternion.h"
namespace DTS
{
Quaternion Quaternion::identity (0,0,0,1) ;
/*! Create a quaternion from three spherical rotation angles
(XY rotation angle, latitude and longitude) in radians */
Quaternion::Quaternion (float angle, float latitude, float longitude)
{
Quaternion x (Point( 1, 0, 0), angle) ;
Quaternion y (Point( 0, 1, 0), latitude) ;
Quaternion z (Point( 0, 0, 1), longitude) ;
// This order is a little wierd, but we flip the x & y
// axis when importing from MilkShape.
(*this) = x * z * y;
}
/*! Calculate the angle in radians between this and another quaternion */
float Quaternion::angleBetween (const Quaternion &b) const
{
return acos (x()*b.x() + y()*b.y() + z()*b.z() + w()*b.w()) ;
}
/*! Calculate the rotation matrix */
Matrix<4,4> Quaternion::toMatrix () const
{
float xx = x() * x() ;
float xy = x() * y(), yy = y() * y() ;
float xz = x() * z(), yz = y() * z(), zz = z() * z() ;
float xw = x() * w(), yw = y() * w(), zw = z() * w(), ww = w() * w() ;
Matrix<4,4>::Cell data[] = {
1 - 2 * (yy+zz), 2 * (xy-zw), 2 * (xz+yw), 0,
2 * (xy+zw), 1 - 2 * (xx+zz), 2 * (yz-xw), 0,
2 * (xz-yw), 2 * (yz+xw), 1 - 2 * (xx+yy), 0,
0, 0, 0, 1
} ;
return Matrix<4,4>(data) ;
}
/*! Create a quaternion from a rotation matrix */
Quaternion::Quaternion (const Matrix<> &m)
{
fromMatrix(m) ;
}
void Quaternion::fromAxis (Point axis, float angle)
{
axis.normalize() ;
float s = sin(angle / 2.0f) ;
x(axis.x() * s) ;
y(axis.y() * s) ;
z(axis.z() * s) ;
w(cos(angle / 2.0f)) ;
}
void Quaternion::fromMatrix (const Matrix<> &m)
{
float qw2 = (1+ m[0][0] + m[1][1] + m[2][2]) * 0.25f ;
float qx2 = qw2 - 0.5f * (m[1][1] + m[2][2]) ;
float qy2 = qw2 - 0.5f * (m[0][0] + m[2][2]) ;
float qz2 = qw2 - 0.5f * (m[0][0] + m[1][1]) ;
float s ;
if (qw2 > qx2 && qw2 > qy2 && qw2 > qz2)
{
w( sqrtf(qw2) ); s = 0.25f / w() ;
x( (m[2][1] - m[1][2]) * s );
y( (m[0][2] - m[2][0]) * s );
z( (m[1][0] - m[0][1]) * s );
}
else if (qx2 > qy2 && qx2 > qz2)
{
x( sqrtf(qx2) ); s = 0.25f / x() ;
w( (m[2][1] - m[1][2]) * s );
y( (m[0][1] - m[1][0]) * s );
z( (m[2][0] - m[0][2]) * s );
}
else if (qy2 > qz2)
{
y( sqrtf(qy2) ); s = 0.25f / y() ;
w( (m[0][2] - m[2][0]) * s );
x( (m[0][1] - m[1][0]) * s );
z( (m[1][2] - m[2][1]) * s );
}
else
{
z( sqrtf(qz2) ); s = 0.25f / z() ;
w( (m[1][0] - m[0][1]) * s );
x( (m[0][2] - m[2][0]) * s );
y( (m[1][2] - m[2][1]) * s );
}
//normalize() ;
}
/*! Return the inverse of a quaternion */
Quaternion Quaternion::inverse() const
{
float norm = x()*x() + y()*y() + z()*z() + w()*w() ;
return conjugate() * (1.0f / norm) ;
}
Quaternion operator * (const Quaternion &a, const Quaternion &b)
{
return Quaternion (
+a[0]*b[3] +a[1]*b[2] -a[2]*b[1] +a[3]*b[0],
-a[0]*b[2] +a[1]*b[3] +a[2]*b[0] +a[3]*b[1],
+a[0]*b[1] -a[1]*b[0] +a[2]*b[3] +a[3]*b[2],
-a[0]*b[0] -a[1]*b[1] -a[2]*b[2] +a[3]*b[3]
) ;
}
Point Quaternion::apply (const Point &v) const
{
// Torque uses column vectors, which means quaternions
// rotate backwards from what you might normally expect.
Quaternion q(v.x(), v.y(), v.z(), 0) ;
Quaternion r = conjugate() * q * (*this);
return Point(r.x(), r.y(), r.z()) ;
// The following should give the same result:
//Matrix<> m = toMatrix() ;
//return m * v ;
}
}

59
lib/dtsSDK/DTSQuaternion.h Executable file
View File

@ -0,0 +1,59 @@
#ifndef __DTSQUATERNION_H
#define __DTSQUATERNION_H
#include "DTSVector.h"
#include "DTSMatrix.h"
#include "DTSPoint.h"
namespace DTS
{
//! Defines a quaternion. Used for rotation information.
class Quaternion : public Vector <float, 4>
{
public:
Quaternion() {}
Quaternion(const Quaternion &n) : Vector<float,4>(n) {}
Quaternion(const Vector<float,4> &n) : Vector<float,4>(n) {}
Quaternion(float X, float Y, float Z, float W) { x(X),y(Y),z(Z),w(W); }
Quaternion(float angle, float latitude, float longitude) ;
Quaternion(const Matrix<4,4> &m) ;
Quaternion(const Point &axis, float angle) { fromAxis(axis,angle); }
float x() const { return get(0); }
float y() const { return get(1); }
float z() const { return get(2); }
float w() const { return get(3); }
void x(float n) { set (0, n) ; }
void y(float n) { set (1, n) ; }
void z(float n) { set (2, n) ; }
void w(float n) { set (3, n) ; }
// -------------------------------------------------------------
Quaternion conjugate() const { return Quaternion (-x(),-y(),-z(),w()) ; }
Quaternion inverse() const ;
Matrix<4,4> toMatrix() const ;
void fromMatrix (const Matrix<4,4> &m) ;
void fromAxis (Point axis, float angle) ;
float angleBetween (const Quaternion &) const ;
Point apply (const Point &) const ;
friend Quaternion operator * (const Quaternion &a, const Quaternion &b) ;
Quaternion & operator *= (const Quaternion &a) { return (*this) = (*this) * a; }
// -------------------------------------------------------------
static Quaternion identity ;
};
inline std::ostream & operator << (std::ostream &out, const Quaternion &q)
{
out << std::setprecision(2) << std::setiosflags(std::ios::fixed) ;
return out << "[ " << q.x() << ' ' << q.y() << ' ' << q.z() << ' ' << q.w() << " ]" ;
}
}
#endif

776
lib/dtsSDK/DTSShape.cpp Executable file
View File

@ -0,0 +1,776 @@
#pragma warning ( disable: 4786 4018 )
#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 = float(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;
}
}
}

280
lib/dtsSDK/DTSShape.h Executable file
View File

@ -0,0 +1,280 @@
#ifndef __DTS_SHAPE_H
#define __DTS_SHAPE_H
#include "DTSPoint.h"
#include "DTSQuaternion.h"
#include "DTSMesh.h"
namespace DTS
{
//! Defines a tree node, as stored in the DTS file
struct Node
{
int name ; //!< Index of its name in the DTS string table
int parent ; //!< Number of the parent node, -1 if it is root
int firstObject ; //!< Deprecated: set to -1 (Note: not quite true, used in TSShape, set on load, but not used by exporter)
int child ; //!< Deprecated: set to -1 (Note: not quite true, used in TSShape, set on load, but not used by exporter)
int sibling ; //!< Deprecated: set to -1 (Note: not quite true, used in TSShape, set on load, but not used by exporter)
Node() {
// These values unused in data file
firstObject = child = sibling = -1;
}
};
//! Defines an object, as stored in the DTS file
struct Object
{
int name ; //!< Index of its name in the DTS string table
int numMeshes ; //!< Number of meshes (only one mesh is used for detail level)
int firstMesh ; //!< Number of the first mesh (they must be consecutive)
int node ; //!< Number of the node where the object is stored
int sibling ; //!< Deprecated: set to -1. (Note: not quite true, used in TSShape, set on load, but not used by exporter)
int firstDecal ; //!< Deprecated: set to -1
Object() {
// These values unused in data file
firstDecal = sibling = -1;
}
};
//! Defines a decal, as stored in the DTS file. DEPRECATED.
struct Decal
{
int name ;
int numMeshes ;
int firstMesh ;
int object ;
int sibling ;
};
//! Defines a material, as stored in the DTS file
struct Material
{
std::string name ; //!< Texture name. Materials don't use the DTS string table
int flags ; //!< Boolean properties
int reflectance ; //!< Number of reflectance map (?)
int bump ; //!< Number of bump map (?) or -1 if none
int detail ; //!< Index of the material, which stores the Detailmap for this material or -1 if none
float detailScale ; //!< Scale of the Detailmap, Default = 1.0f
float reflection ; //!< ?
enum //!< Material flags
{
SWrap = 0x00000001,
TWrap = 0x00000002,
Translucent = 0x00000004,
Additive = 0x00000008,
Subtractive = 0x00000010,
SelfIlluminating = 0x00000020,
NeverEnvMap = 0x00000040,
NoMipMap = 0x00000080,
MipMapZeroBorder = 0x00000100,
IFLMaterial = 0x08000000,
IFLFrame = 0x10000000,
DetailMap = 0x20000000,
BumpMap = 0x40000000,
ReflectanceMap = 0x80000000,
AuxiliaryMask = 0xE0000000
};
};
//! Defines an animated material as stored in the DTS file
struct IFLMaterial
{
int name ;
int slot ;
int firstFrame ;
int time ;
int numFrames ;
};
//! Defines a detail level as stored in the DTS file
struct DetailLevel
{
int name ; //!< Index of the name in the DTS string table
int subshape ; //!< Number of the subshape it belongs
int objectDetail ; //!< Number of object mesh to draw for each object
float size ; //!< Minimum pixel size (store details from big to small)
float avgError ; //!< Don't know, use -1
float maxError ; //!< Don't know, use -1
int polyCount ; //!< Polygon count of the meshes to draw.
};
//! Defines a subshape as stored in the DTS file. A subshape defines a range
//! of nodes and objects.
struct Subshape
{
int firstNode ;
int firstObject ;
int firstDecal ;
int numNodes ;
int numObjects ;
int numDecals ;
int firstTranslucent ; //!< Not used/stored (?)
};
//! Defines an object state as stored in the DTS file.
//! Not sure about what does, but it may be related to animated materials.
struct ObjectState
{
float vis ;
int frame ;
int matFrame ;
};
//! Defines a decal state as stored in the DTS file. DEPRECATED.
struct DecalState
{
int frame ;
};
//! Defines a trigger as stored in the DTS file.
struct Trigger
{
int state ;
float pos ;
};
//! Defines a sequence as stored in the DTS file
struct Sequence
{
int nameIndex ;
int flags ;
int numKeyFrames ;
float duration ;
int priority ;
int firstGroundFrame ;
int numGroundFrames ;
int baseRotation ;
int baseTranslation ;
int baseScale ;
int baseObjectState ;
int baseDecalState ;
int firstTrigger ;
int numTriggers ;
float toolBegin ;
enum /* flags */
{
UniformScale = 0x0001,
AlignedScale = 0x0002,
ArbitraryScale = 0x0004,
Blend = 0x0008,
Cyclic = 0x0010,
MakePath = 0x0020,
IFLInit = 0x0040,
HasTranslucency = 0x0080
};
struct matters_array {
std::vector<bool> rotation ;
std::vector<bool> translation ;
std::vector<bool> scale ;
std::vector<bool> decal ;
std::vector<bool> ifl ;
std::vector<bool> vis ;
std::vector<bool> frame ;
std::vector<bool> matframe ;
}
matters ;
Sequence() ;
};
//! Defines a DTS shape
class Shape
{
friend class ShapeMimic;
friend class AppConfig;
public:
enum //! ImportConfig collision types
{
C_None = 0,
C_BBox,
C_Cylinder,
C_Mesh
} ;
//! Create an empty shape
Shape () ;
//! Write the shape to a file or stream
void save (std::ostream & out) const ;
//! Write the shape's sequences to a file or stream
void saveSequences (std::ostream & out) const ;
//! Read the shape from a file or stream
void read (std::istream & in) ;
Box getBounds() const { return bounds; }
float getRadius() const { return radius; }
float getTubeRadius() const { return tubeRadius; }
protected:
int addName (std::string s) ;
void calculateBounds() ;
void calculateRadius() ;
void calculateTubeRadius() ;
void calculateCenter() ;
void setSmallestSize(int) ;
void setCenter(Point &p) { center = p; }
void getNodeWorldPosRot(int n,Point &trans, Quaternion &rot);
void write(std::ostream & out,const std::vector<bool> * ptr) const;
protected:
std::vector <Node> nodes ;
std::vector <Object> objects ;
std::vector <Decal> decals ;
std::vector <Subshape> subshapes ;
std::vector <IFLMaterial> IFLmaterials ;
std::vector <Material> materials ;
std::vector <Quaternion> nodeDefRotations ;
std::vector <Point> nodeDefTranslations ;
std::vector <Quaternion> nodeRotations ;
std::vector <Point> nodeTranslations ;
std::vector <float> nodeScalesUniform ;
std::vector <Point> nodeScalesAligned ;
std::vector <Point> nodeScalesArbitrary ;
std::vector <Quaternion> nodeScaleRotsArbitrary ;
std::vector <Quaternion> groundRotations ;
std::vector <Point> groundTranslations ;
std::vector <ObjectState> objectStates ;
std::vector <DecalState> decalStates ;
std::vector <Trigger> triggers ;
std::vector <DetailLevel> detailLevels ;
std::vector <Mesh> meshes ;
std::vector <Sequence> sequences ;
std::vector <std::string> names ;
private:
float smallestSize ;
int smallestDetailLevel ;
float radius ;
float tubeRadius ;
Point center ;
Box bounds ;
};
}
#endif

29
lib/dtsSDK/DTSTypes.h Executable file
View File

@ -0,0 +1,29 @@
#ifndef __DTSTYPES_H
#define __DTSTYPES_H
#include <vector>
#include <string>
#include <ostream>
#include <cmath>
#include <cassert>
#include "DTSPoint.h"
#ifndef _WIN32
#define __cdecl
#define strnicmp strncasecmp
#define stricmp strcasecmp
inline float min(float a, float b) { return a<b ? a : b; }
inline float max(float a, float b) { return a>b ? a : b; }
#endif
//! The DTS namespace implements all the classes needed to load a DTS model
//! and to create one from the Milkshape data. There are many basic classes
//! here, such as Point or Quaternion.
namespace DTS
{
}
#endif

239
lib/dtsSDK/DTSVector.h Executable file
View File

@ -0,0 +1,239 @@
#ifndef __DTSVECTOR_H
#define __DTSVECTOR_H
#include <vector>
#include <string>
#include <ostream>
#include <cmath>
namespace DTS
{
//! Defines a generic vector class
template <class type, int size> class Vector
{
public:
//! Create a null vector
Vector () {
// No initialization. Derivated classes have no overhead.
}
//! Create a vector from a data array
Vector (const type *d) {
for (int n = 0 ; n < size ; n++) members[n] = d[n] ;
}
//! Create a point with given space coordinates
Vector<type, size> (const Vector<type, size> &v) {
for (int n = 0 ; n < size ; n++) members[n] = v.members[n] ;
}
//! Member access
const type & get (int n) const { return members[n] ; }
type & operator[] (int n) { return members[n] ; }
const type & operator[] (int n) const { return members[n] ; }
void set (int n, type value) { members[n] = value ; }
//!{ Member operators *************************************************
Vector<type, size> operator - () const {
Vector<type, size> r ;
for (int n = 0 ; n < size ; n++) r.members[n] = -members[n];
return r ;
}
Vector<type, size> & operator = (const Vector<type, size> &v) {
for (int n = 0 ; n < size ; n++) members[n] = v.members[n] ;
return *this ;
}
Vector<type, size> & operator += (const Vector<type, size> &r) {
for (int n = 0 ; n < size ; n++) members[n] += r.members[n];
return *this ;
}
Vector<type, size> & operator -= (const Vector<type, size> &r) {
for (int n = 0 ; n < size ; n++) members[n] -= r.members[n];
return *this ;
}
Vector<type, size> & operator *= (const type r) {
for (int n = 0 ; n < size ; n++) members[n] *= r;
return *this ;
}
Vector<type, size> & operator /= (const type r) {
for (int n = 0 ; n < size ; n++) members[n] /= r;
return *this ;
}
//!}
//!{ Non-member operators *********************************************
friend bool operator < (const Vector<type,size> &a, const Vector<type,size> &b) {
for (int n = 0 ; n < size ; n++) if (a.members[n] < b.members[n]) return true ;
return false ;
}
friend bool operator > (const Vector<type,size> &a, const Vector<type,size> &b) {
int n;
for (n = 0 ; n < size ; n++) if (a.members[n] < b.members[n]) return false ;
return a[n] != b[n] ;
}
friend bool operator == (const Vector<type,size> &a, const Vector<type,size> &b) {
for (int n = 0 ; n < size ; n++) if (a.members[n] != b.members[n]) return false ;
return true ;
}
friend bool operator != (const Vector<type,size> &a, const Vector<type,size> &b) {
for (int n = 0 ; n < size ; n++) if (a.members[n] != b.members[n]) return true ;
return false ;
}
//!}
//!{ Vector utilities *************************************************
//! Normalize the vector (reduce it to 1 unit in length)
void normalize() ;
//! Length of the vector
type length(int nc = size) const ;
//! Dot product
type dot (const Vector<type, size> &r) const ;
//! Angle in radians between two vectors
type angle (const Vector<type, size> &r) const ;
//! Middle point between two points/vectors
Vector<type, size> midpoint (const Vector<type, size> & p) const ;
//! Some sintactic sugar stuff
bool isPerpendicular (Vector<type, size> &r) const { return dot(r) == 0.0f ; }
//! Returns true if all members are 0 (do not use operator (bool))
bool isNull() const ;
private:
type members[size] ;
};
// -----------------------------------------------------------------------
// Implementation
// -----------------------------------------------------------------------
template <class type, int size>
inline Vector<type, size> operator + (const Vector<type, size> &a, const Vector<type, size> &b)
{
Vector<type, size> result ;
for (int n = 0 ; n < size ; n++)
result.set (n, a.get(n) + b.get(n)) ;
return result ;
}
template <class type, int size>
inline Vector<type, size> operator - (const Vector<type, size> &a, const Vector<type, size> &b)
{
Vector<type, size> result ;
for (int n = 0 ; n < size ; n++)
result.set (n, a.get(n) - b.get(n)) ;
return result ;
}
template <class type, int size>
inline bool operator == (const Vector<type, size> &a, const Vector<type, size> &b)
{
for (int n = 0 ; n < size ; n++)
if (a.members[n] != b.members[n]) return false ;
return true ;
}
template <class type, int size>
inline bool operator != (const Vector<type, size> &a, const Vector<type, size> &b)
{
for (int n = 0 ; n < size ; n++)
if (a.members[n] != b.members[n]) return true ;
return false ;
}
//! Multiply by constant
template <class type, int size>
inline Vector<type, size> operator * (const Vector<type, size> &p, float c)
{
Vector<type, size> result ;
for (int n = 0 ; n < size ; n++)
result.set (n, p.get(n) * c) ;
return result ;
}
//! Divide by constant
template <class type, int size>
inline Vector<type, size> operator / (const Vector<type, size> &p, float c)
{
Vector<type, size> result ;
for (int n = 0 ; n < size ; n++)
result.set (n, p.get(n) / c) ;
return result ;
}
//! Dot product
template <class type, int size>
inline type Vector<type, size>::dot (const Vector<type, size> &r) const
{
type result = r.members[0] * members[0] ;
for (int n = 1 ; n < size ; n++)
result += r.members[n] * members[n] ;
return result ;
}
//! Length
template <class type, int size>
inline type Vector<type, size>::length(int nc) const
{
type result = members[0] * members[0] ;
for (int n = 1 ; n < nc ; n++)
result += members[n] * members[n] ;
return sqrt(result) ;
}
//! Angle between two vectors
template <class type, int size>
inline type Vector<type, size>::angle (const Vector<type, size> &r) const
{
return acos (dot(r) / length() / r.length()) ;
}
//! Angle between two vectors
template <class type, int size>
inline Vector<type,size> Vector<type, size>::midpoint (const Vector<type, size> &r) const
{
Vector<type,size> result ;
for (int n = 0 ; n < size ; n++)
result.set (n, (r.members[n] - members[n])/2 + members[n]) ;
return result ;
}
//! Normalices a vector. If it is a null vector (0, 0, 0) then it is left untouched
template <class type, int size>
inline void Vector<type, size>::normalize()
{
float dist = length() ;
if (dist != 0.0f)
{
for (int n = 0 ; n < size ; n++)
members[n] /= dist ;
}
}
template <class type, int size>
inline bool Vector<type,size>::isNull() const
{
for (int n = 0 ; n < size ; n++)
if (members[n] != 0) return false ;
return true ;
}
}
#endif