953 lines
25 KiB
C++
953 lines
25 KiB
C++
/*=========================================================================
|
|
|
|
EXPMODEL.CPP
|
|
|
|
Author: Tim Swann @ CLIMAX
|
|
Created:
|
|
Project:
|
|
Purpose:
|
|
|
|
Copyright (c) 1998 Climax Development Ltd
|
|
|
|
===========================================================================*/
|
|
|
|
/*----------------------------------------------------------------------
|
|
Includes
|
|
-------- */
|
|
|
|
#include "AsciiExp.h"
|
|
|
|
|
|
/* Std Lib
|
|
------- */
|
|
|
|
/* Glib
|
|
---- */
|
|
|
|
/* Local
|
|
----- */
|
|
|
|
/* Graphics
|
|
-------- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Tyepdefs && Defines
|
|
------------------- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Structure defintions
|
|
-------------------- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Positional Vars
|
|
--------------- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function Prototypes
|
|
------------------- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Vars
|
|
---- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Data
|
|
---- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
|
|
void AsciiExp::ExportModel(INode* node)
|
|
{
|
|
ObjectState os = node->EvalWorldState( ip->GetAnimRange().Start() );
|
|
char nodeName[256];
|
|
|
|
// Targets are actually geomobjects, but we will export them
|
|
// from the camera and light objects, so we skip them here.
|
|
if (os.obj->ClassID() == Class_ID(TARGET_CLASS_ID, 0)) return;
|
|
ip->ProgressUpdate(0,0,"Export Model0");
|
|
|
|
sprintf(nodeName, "%s", node->GetName());
|
|
strupr(nodeName);
|
|
if (nodeName[0] != 'R' ||
|
|
nodeName[1] != 'O' ||
|
|
nodeName[2] != 'O' ||
|
|
nodeName[3] != 'T')
|
|
{
|
|
ip->ProgressUpdate(0,0,"Export ModelRoot");
|
|
WriteChunkHdr( (char*)OBJ_ID, 0 );
|
|
fwrite(&totFrames, sizeof(int), 1, expStream);
|
|
fwrite(nodeName, MAX_NAME_LENGTH, 1, expStream);
|
|
|
|
ip->ProgressUpdate(0,0,"Export Model-Mesh");
|
|
ExportMesh( node );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
|
|
void AsciiExp::ExportMesh( INode* node )
|
|
{
|
|
|
|
Matrix3 tm = node->GetObjTMAfterWSM( ip->GetAnimRange().Start() );
|
|
Uint32 EvalFlags = 0;
|
|
Point3 ObjPos;
|
|
Point3 ObjRot;
|
|
Point3 ObjSca;
|
|
Point3 center = Point3(0.f, 0.f, 0.f);
|
|
AffineParts ap;
|
|
Mesh * mesh;
|
|
ObjectState os;
|
|
Object * obj;
|
|
BOOL needDel;
|
|
TriObject * tri;
|
|
|
|
os = node->EvalWorldState( ip->GetAnimRange().Start() );
|
|
obj = node->EvalWorldState( ip->GetAnimRange().Start() ).obj;
|
|
|
|
Mtl * nodeMtl = node->GetMtl();
|
|
if (!nodeMtl) return;
|
|
|
|
if (!os.obj) return;
|
|
if (!obj->IsRenderable()) return;
|
|
if (node->IsNodeHidden()) return;
|
|
if (!obj || os.obj->SuperClassID() != GEOMOBJECT_CLASS_ID) return; // Safety net. This shouldn't happen.
|
|
|
|
tri = GetTriObjectFromNode(node, ip->GetAnimRange().Start(), needDel);
|
|
if (!tri) return;
|
|
|
|
mesh = &tri->mesh;
|
|
|
|
mtlList.AddMtl(nodeMtl);
|
|
|
|
ip->ProgressUpdate(0,0,"ExportMeshList");
|
|
ExportMeshList( node, mesh );
|
|
ip->ProgressUpdate(0,0,"ExportPoints");
|
|
ExportPoints( node, mesh );
|
|
ip->ProgressUpdate(0,0,"ExportVectors");
|
|
ExportVectors( node, mesh);
|
|
ip->ProgressUpdate(0,0,"ExportVectorsDone");
|
|
|
|
if (needDel) delete tri;
|
|
|
|
tri = GetTriObjectFromNode(node, ip->GetAnimRange().End(), needDel);
|
|
if (!tri) return;
|
|
|
|
mesh = &tri->mesh;
|
|
ip->ProgressUpdate(0,0,"ExportNormals");
|
|
ExportNormals( node, mesh );
|
|
if (needDel) delete tri;
|
|
ip->ProgressUpdate(0,0,"ExportNormalsDone");
|
|
|
|
tm = node->GetObjTMAfterWSM(ip->GetAnimRange().Start());// * Inverse(node->GetParentTM(t));
|
|
decomp_affine(tm, &ap);
|
|
|
|
ip->ProgressUpdate(0,0,"WriteHeader0");
|
|
WriteChunkHdr( (char*)MODEL_ID, 0 );
|
|
fwrite( &nCurObj, sizeof(long), 1, expStream );
|
|
char NodeName[MAX_NAME_LENGTH];
|
|
sprintf(NodeName,"%s",node->GetName());
|
|
// fwrite( node->GetName(), MAX_NAME_LENGTH, 1, expStream);
|
|
fwrite( NodeName, MAX_NAME_LENGTH, 1, expStream);
|
|
fwrite( &radius, sizeof(float), 1, expStream );
|
|
fwrite( ¢er.x, sizeof(float), 1, expStream );
|
|
fwrite( ¢er.y, sizeof(float), 1, expStream );
|
|
fwrite( ¢er.z, sizeof(float), 1, expStream );
|
|
fwrite( &ap.t.x, sizeof(float), 1, expStream );
|
|
fwrite( &ap.t.z, sizeof(float), 1, expStream );
|
|
fwrite( &ap.t.y, sizeof(float), 1, expStream );
|
|
//ProgressUpdate(int pct, BOOL showPct = TRUE, TCHAR *title = NULL)=0
|
|
|
|
ip->ProgressUpdate(0,0,"WriteHeaderDone");
|
|
|
|
ip->ProgressUpdate(0,0,"FindPhysiqueModifier");
|
|
if (FindPhysiqueModifier(node))
|
|
{
|
|
ip->ProgressUpdate(0,0,"ExportWeights");
|
|
ExportWeights(node);
|
|
}
|
|
else
|
|
ip->ProgressUpdate(0,0,"FindFFDModifier");
|
|
if (FindFFDModifier(node))
|
|
{
|
|
}
|
|
else
|
|
{
|
|
ip->ProgressUpdate(0,0,"ExportNodeAnimMesh");
|
|
ExportNodeAnimMesh( node );
|
|
}
|
|
|
|
// ExportAnimMesh( node );
|
|
ip->ProgressUpdate(0,0,"FindEditableMesh");
|
|
FindEditableMesh(node);
|
|
ip->ProgressUpdate(0,0,"ExportVisTrack");
|
|
ExportVisTrack( node );
|
|
nCurObj++;
|
|
}
|
|
|
|
void AsciiExp::FindEditableMesh(INode *node)
|
|
{
|
|
Object *o = node->GetObjectRef();
|
|
while (o && o->SuperClassID() == GEN_DERIVOB_CLASS_ID)
|
|
{
|
|
o = ((IDerivedObject*)o)->GetObjRef();
|
|
}
|
|
if (o && o->ClassID() == Class_ID(EDITTRIOBJ_CLASS_ID,0))
|
|
{
|
|
ExportMeshVertAnim(node, (EditTriObject*)o);
|
|
}
|
|
}
|
|
|
|
void AsciiExp::ExportMeshVertAnim(INode *node, EditTriObject *e)
|
|
{
|
|
TimeValue start = ip->GetAnimRange().Start();
|
|
TimeValue end = ip->GetAnimRange().End();
|
|
int delta = GetTicksPerFrame();
|
|
|
|
int Controls = e->cont.Count();
|
|
|
|
|
|
Matrix3 tm = node->GetObjTMAfterWSM( ip->GetAnimRange().Start() );
|
|
Point3 p;
|
|
|
|
Controls = 0;
|
|
for (int i=0; i<e->cont.Count(); i++) {
|
|
if (e->cont[i]) {
|
|
Controls++;
|
|
}
|
|
}
|
|
|
|
ITCBPoint3Key tcbPosKey;
|
|
IBezPoint3Key bezPosKey;
|
|
|
|
WriteChunkHdr( (char*)KEY_ID, 0);
|
|
fwrite( &CHANNEL_TYPE_VERTEX, sizeof( Uint32 ), 1, expStream );
|
|
fwrite( &CHANNEL_INFO_POSITION, sizeof( Uint32) , 1, expStream);
|
|
fwrite( &nCurObj, sizeof( Uint32 ), 1, expStream );
|
|
fwrite( &Controls, sizeof(int), 1, expStream);
|
|
|
|
for (i=0; i<e->cont.Count(); i++) {
|
|
if (e->cont[i]) {
|
|
Control *c = GetControlInterface(e->cont[i]);
|
|
IKeyControl *ikeys;
|
|
TimeList tl;
|
|
TimeValue time;
|
|
tl.Clear();
|
|
if (c) {
|
|
ikeys = GetKeyControlInterface(c);
|
|
int num = ikeys->GetNumKeys();
|
|
for (int j = 0; j<num; j++)
|
|
{
|
|
if (c->ClassID() == Class_ID(TCBINTERP_POINT3_CLASS_ID, 0)) {
|
|
ikeys->GetKey(j, &tcbPosKey);
|
|
time = tcbPosKey.time;
|
|
}
|
|
else
|
|
if (c->ClassID() == Class_ID(HYBRIDINTERP_POINT3_CLASS_ID, 0))
|
|
{
|
|
ikeys->GetKey(j, &bezPosKey);
|
|
time = bezPosKey.time;
|
|
}
|
|
tl.Add(time);
|
|
}
|
|
num = tl.Count();
|
|
fwrite(&i, sizeof(int), 1, expStream);
|
|
fwrite(&num, sizeof(int), 1, expStream);
|
|
for (j=0; j<num; j++) {
|
|
time = tl.Get(j);
|
|
tm = node->GetObjTMAfterWSM(time);
|
|
e->cont[i]->GetValue(time,&p,FOREVER);
|
|
p = tm * p;
|
|
time = (time-start) / delta;
|
|
fwrite(&time, sizeof(int), 1, expStream);
|
|
fwrite(&p.x, sizeof(float), 1, expStream);
|
|
fwrite(&p.z, sizeof(float), 1, expStream);
|
|
fwrite(&p.y, sizeof(float), 1, expStream);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
---------------------------------------------------------------------- */
|
|
int GetSubMtlCount(Mtl* mtl, bool recurse = false)
|
|
{
|
|
int Count = 0;
|
|
if (!mtl)
|
|
return 0;
|
|
if (mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0))
|
|
Count ++;
|
|
|
|
if (mtl->NumSubMtls() > 0)
|
|
{
|
|
int c = (recurse) ? 1 : mtl->NumSubMtls();
|
|
for (int i=0; i<c; i++)
|
|
{
|
|
Mtl* subMtl = mtl->GetSubMtl(i);
|
|
if (subMtl)
|
|
{
|
|
Count += GetSubMtlCount( subMtl, true);
|
|
}
|
|
}
|
|
}
|
|
return Count;
|
|
}
|
|
|
|
void AsciiExp::ExportMeshList(INode * node, Mesh * mesh)
|
|
{
|
|
MtlID matid;
|
|
MtlID matref;
|
|
Mtl * nodeMtl = node->GetMtl();
|
|
int m;
|
|
ObjectState os;
|
|
Object * obj;
|
|
Matrix3 tm = node->GetObjTMAfterWSM( ip->GetAnimRange().Start() );
|
|
BOOL negScale = TMNegParity(tm);
|
|
int vx1, vx2, vx3;
|
|
const char * name = node->GetName();
|
|
|
|
|
|
// fprintf( tempStream, "MESHLIST = %s\n\n", name );
|
|
|
|
obj = node->EvalWorldState( ip->GetAnimRange().Start() ).obj;
|
|
mesh->buildNormals();
|
|
|
|
// Order of the vertices. Get 'em counter clockwise if the objects is
|
|
// negatively scaled.
|
|
if (negScale)
|
|
{
|
|
vx1 = 2;
|
|
vx2 = 1;
|
|
vx3 = 0;
|
|
}
|
|
else
|
|
{
|
|
vx1 = 0;
|
|
vx2 = 1;
|
|
vx3 = 2;
|
|
}
|
|
|
|
int MtlCount = GetSubMtlCount(nodeMtl);
|
|
if (MtlCount == 0) return;
|
|
// Find all mesh materials used
|
|
nbMeshs = 0;
|
|
for (int i=0; i<mesh->getNumFaces(); i++)
|
|
{
|
|
Bool found = FALSE;
|
|
|
|
matid = ((unsigned long)mesh->getFaceMtlIndex(i)) % MtlCount;
|
|
|
|
// fprintf( tempStream, "MATID = %d - FACEID = %d\n", mesh->faces[i].getMatID(), mesh->getFaceMtlIndex(i) );
|
|
|
|
for (int f=0;f<nbMeshs;f++)
|
|
{
|
|
if (matid == MeshSet[f].MatId)
|
|
{
|
|
MeshSet[f].nbFaces++;
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
MeshSet[nbMeshs].MatId = matid;
|
|
MeshSet[nbMeshs].nbFaces = 1;
|
|
nbMeshs++;
|
|
if(nbMeshs>= MAXCOUNT) MessageBox( MAX_hWnd, "nbMeshs Overflow", "ERROR", MB_OK);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// Sort material id's for ease of access
|
|
|
|
for (m=0;m<nbMeshs;m++)
|
|
{
|
|
for (int m2=0;m2<(nbMeshs-1);m2++)
|
|
{
|
|
if (MeshSet[m2].MatId > MeshSet[m2+1].MatId)
|
|
{
|
|
MESH_SET meshset = MeshSet[m2];
|
|
MeshSet[m2] = MeshSet[m2+1];
|
|
MeshSet[m2+1] = meshset;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
for (m=0;m<nbMeshs;m++)
|
|
{
|
|
int nbFaces;
|
|
|
|
// EXPORT POLY CONNECT LIST - PER MESH
|
|
WriteChunkHdr( (char*)POLY_ID, 0 );
|
|
fwrite( &nCurObj, sizeof(Uint16), 1, expStream );
|
|
fwrite( &m, sizeof(Uint16), 1, expStream );
|
|
nbFaces = MeshSet[m].nbFaces;
|
|
fwrite( &nbFaces, sizeof(Uint32), 1, expStream );
|
|
|
|
for (i=0; i<mesh->getNumFaces(); i++)
|
|
{
|
|
matid = ((unsigned long)mesh->getFaceMtlIndex(i)) % MtlCount;
|
|
if (matid == MeshSet[m].MatId)
|
|
{
|
|
fwrite( &mesh->faces[i].v[vx1], sizeof(long), 1, expStream );
|
|
fwrite( &mesh->faces[i].v[vx2], sizeof(long), 1, expStream );
|
|
fwrite( &mesh->faces[i].v[vx3], sizeof(long), 1, expStream );
|
|
long HF0=mesh->faces[i].getEdgeVis(vx1);
|
|
long HF1=mesh->faces[i].getEdgeVis(vx2);
|
|
long HF2=mesh->faces[i].getEdgeVis(vx3);
|
|
fwrite( &HF0, sizeof(long), 1, expStream );
|
|
fwrite( &HF1, sizeof(long), 1, expStream );
|
|
fwrite( &HF2, sizeof(long), 1, expStream );
|
|
// fprintf( tempStream, "Face = %d - HF= %d %d %d\n", i,HF0,HF1,HF2);
|
|
}
|
|
}
|
|
|
|
|
|
// EXPORT FACE MAP TEXCOORDS IF WE HAVE THEM...
|
|
if (obj->HasUVW())
|
|
{
|
|
if (!CheckForAndExportFaceMap(nodeMtl, mesh, m))
|
|
{
|
|
// If not, export standard tverts
|
|
int numTVx = mesh->getNumTVerts();
|
|
|
|
if (numTVx)
|
|
{
|
|
int nbFaces;
|
|
|
|
WriteChunkHdr( (char*)UV_ID, 0 );
|
|
fwrite( &nCurObj, sizeof(Uint16), 1, expStream );
|
|
fwrite( &m, sizeof(Uint16), 1, expStream );
|
|
nbFaces = MeshSet[m].nbFaces;
|
|
fwrite( &nbFaces, sizeof(Uint32), 1, expStream );
|
|
|
|
for (i=0; i<mesh->getNumFaces(); i++)
|
|
{
|
|
matid = ((unsigned long)mesh->getFaceMtlIndex(i)) % MtlCount;
|
|
|
|
if (matid == MeshSet[m].MatId)
|
|
{
|
|
UVVert tv;
|
|
int idx;
|
|
|
|
idx = mesh->tvFace[i].t[vx1];
|
|
tv = mesh->tVerts[idx];
|
|
fwrite(&tv.x, sizeof(float), 1, expStream);
|
|
fwrite(&tv.y, sizeof(float), 1, expStream);
|
|
|
|
idx = mesh->tvFace[i].t[vx2];
|
|
tv = mesh->tVerts[idx];
|
|
fwrite(&tv.x, sizeof(float), 1, expStream);
|
|
fwrite(&tv.y, sizeof(float), 1, expStream);
|
|
|
|
idx = mesh->tvFace[i].t[vx3];
|
|
tv = mesh->tVerts[idx];
|
|
fwrite(&tv.x, sizeof(float), 1, expStream);
|
|
fwrite(&tv.y, sizeof(float), 1, expStream);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
{
|
|
int nbFaces;
|
|
|
|
WriteChunkHdr( (char*)FACENORMAL_ID, 0 );
|
|
fwrite( &nCurObj, sizeof(Uint16), 1, expStream );
|
|
fwrite( &m, sizeof(Uint16), 1, expStream );
|
|
nbFaces = MeshSet[m].nbFaces;
|
|
fwrite( &nbFaces, sizeof(Uint32), 1, expStream );
|
|
|
|
for (i=0; i<mesh->getNumFaces(); i++)
|
|
{
|
|
matid = ((unsigned long)mesh->getFaceMtlIndex(i)) % MtlCount;
|
|
if (matid == MeshSet[m].MatId)
|
|
{
|
|
Point3 n=GetVertexNormal(mesh, i,mesh->getRVertPtr(mesh->faces[i].v[vx1]));
|
|
fwrite(&n.x, sizeof(float), 1, expStream);
|
|
fwrite(&n.y, sizeof(float), 1, expStream);
|
|
fwrite(&n.z, sizeof(float), 1, expStream);
|
|
|
|
n=GetVertexNormal(mesh, i,mesh->getRVertPtr(mesh->faces[i].v[vx2]));
|
|
fwrite(&n.x, sizeof(float), 1, expStream);
|
|
fwrite(&n.y, sizeof(float), 1, expStream);
|
|
fwrite(&n.z, sizeof(float), 1, expStream);
|
|
|
|
n=GetVertexNormal(mesh, i,mesh->getRVertPtr(mesh->faces[i].v[vx3]));
|
|
fwrite(&n.x, sizeof(float), 1, expStream);
|
|
fwrite(&n.y, sizeof(float), 1, expStream);
|
|
fwrite(&n.z, sizeof(float), 1, expStream);
|
|
}
|
|
}
|
|
}
|
|
// tris[result].VertNormals[s] = Normalize(transpose * (m * get_vertex_normal(&triobj->mesh, j, triobj->mesh.getRVertPtr(fces[j].v[s]))));
|
|
if (mesh->getNumVertCol())
|
|
{
|
|
Point3 vc;
|
|
WriteChunkHdr( (char*)VCOL_ID, 0 );
|
|
fwrite( &nCurObj, sizeof(Uint32), 1, expStream );
|
|
fwrite( &m , sizeof(Uint32), 1, expStream );
|
|
int nbFaces = MeshSet[m].nbFaces;
|
|
fwrite( &nbFaces, sizeof(Uint32), 1, expStream );
|
|
for (i=0; i<mesh->getNumFaces(); i++)
|
|
{
|
|
matid = ((unsigned long)mesh->getFaceMtlIndex(i)) % MtlCount;
|
|
|
|
if (matid == MeshSet[m].MatId)
|
|
{
|
|
TVFace *f = &mesh->vcFace[i];
|
|
int vert = f->t[vx1];
|
|
vc = mesh->vertCol[vert];
|
|
fwrite(&vc.x, sizeof(float), 1, expStream);
|
|
fwrite(&vc.y, sizeof(float), 1, expStream);
|
|
fwrite(&vc.z, sizeof(float), 1, expStream);
|
|
|
|
vert = f->t[vx2];
|
|
vc = mesh->vertCol[vert];
|
|
fwrite(&vc.x, sizeof(float), 1, expStream);
|
|
fwrite(&vc.y, sizeof(float), 1, expStream);
|
|
fwrite(&vc.z, sizeof(float), 1, expStream);
|
|
|
|
vert = f->t[vx3];
|
|
vc = mesh->vertCol[vert];
|
|
fwrite(&vc.x, sizeof(float), 1, expStream);
|
|
fwrite(&vc.y, sizeof(float), 1, expStream);
|
|
fwrite(&vc.z, sizeof(float), 1, expStream);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// EXPORT MESHSET INFO
|
|
WriteChunkHdr( (char*)MESH_ID, 0 );
|
|
fwrite( &nCurObj, sizeof(long), 1, expStream );
|
|
fwrite( &nbMeshs, sizeof(long), 1, expStream );
|
|
|
|
int NodeMatRef = mtlList.GetMtlID(nodeMtl);
|
|
for (m=0;m<nbMeshs;m++)
|
|
{
|
|
matref = MeshSet[m].MatId + NodeMatRef;
|
|
// fprintf( tempStream, "matIdx = %d %d\n", MeshSet[m].MatId, matref );
|
|
|
|
fwrite(&matref, sizeof(Uint16), 1, expStream);
|
|
fwrite(&MeshSet[m].nbFaces, sizeof(Uint16), 1, expStream);
|
|
|
|
Uint32 TempStore;
|
|
TempStore = m;
|
|
fwrite(&TempStore, sizeof(Uint32), 1, expStream); // polt list
|
|
TempStore = -1;
|
|
fwrite(&TempStore, sizeof(Uint32), 1, expStream); // attr list
|
|
fwrite(&TempStore, sizeof(Uint32), 1, expStream); // normal list
|
|
TempStore = -1;
|
|
if (!mesh->vertCol)
|
|
TempStore = m;
|
|
fwrite(&TempStore, sizeof(Uint32), 1, expStream); // vertex col list
|
|
TempStore = -1;
|
|
if (obj->HasUVW())
|
|
TempStore = m;
|
|
fwrite(&TempStore, sizeof(Uint32), 1, expStream); // texture list
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
---------------------------------------------------------------------- */
|
|
|
|
BOOL AsciiExp::CheckForAndExportFaceMap(Mtl* mtl, Mesh* mesh, int meshno)
|
|
{
|
|
MtlID matid;
|
|
ULONG matreq;
|
|
|
|
return FALSE;
|
|
|
|
if (!mtl || !mesh) return FALSE;
|
|
|
|
matreq = mtl->Requirements(-1);
|
|
|
|
// ARE WE USING FACE MAPPING?
|
|
if (!(matreq & MTLREQ_FACEMAP)) return FALSE;
|
|
|
|
|
|
// OK, WE HAVE A FACEMAP SITUATION HERE...
|
|
|
|
WriteChunkHdr( (char*)UV_ID, 0 );
|
|
fwrite( &nCurObj, sizeof(Uint16), 1, expStream );
|
|
fwrite( &meshno, sizeof(Uint16), 1, expStream );
|
|
Uint32 mnf = MeshSet[meshno].nbFaces;
|
|
fwrite( &mnf, sizeof(Uint32), 1, expStream );
|
|
|
|
for (int i=0; i<mesh->getNumFaces(); i++)
|
|
{
|
|
matid = mesh->getFaceMtlIndex(i);//faces[i].getMatID();
|
|
|
|
if (matid == MeshSet[meshno].MatId)
|
|
{
|
|
Point3 tv[3];
|
|
Face * f;
|
|
// NJS_COLOR uv;
|
|
|
|
f = &mesh->faces[i];
|
|
make_face_uv( f, tv );
|
|
|
|
fwrite(&tv[0].x, sizeof(float), 1, expStream);
|
|
fwrite(&tv[0].y, sizeof(float), 1, expStream);
|
|
fwrite(&tv[1].x, sizeof(float), 1, expStream);
|
|
fwrite(&tv[1].y, sizeof(float), 1, expStream);
|
|
fwrite(&tv[2].x, sizeof(float), 1, expStream);
|
|
fwrite(&tv[2].y, sizeof(float), 1, expStream);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
---------------------------------------------------------------------- */
|
|
|
|
void AsciiExp::ExportPoints(INode * node, Mesh * mesh)
|
|
{
|
|
Matrix3 tm = node->GetObjTMAfterWSM( ip->GetAnimRange().Start() );
|
|
Point3 Trans;
|
|
int nbVerts;
|
|
|
|
radius = 0.f;
|
|
nbVerts = mesh->getNumVerts();
|
|
|
|
// EXPORT MODEL POINTS
|
|
WriteChunkHdr( (char*)POINTS_ID, 0 );
|
|
fwrite( &nCurObj, sizeof(Uint32), 1, expStream );
|
|
fwrite( &nbVerts, sizeof(Uint32), 1, expStream );
|
|
|
|
for (int i=0; i<nbVerts; i++)
|
|
{
|
|
Point3 v1;
|
|
Point3 v2;
|
|
|
|
tm = node->GetObjTMAfterWSM( ip->GetAnimRange().Start() );
|
|
v1 = mesh->verts[i];
|
|
//v2 = VectorTransform( tm, v1 );
|
|
//v2 += tm.GetTrans();
|
|
v2 = tm * v1;
|
|
Trans = v2;
|
|
|
|
//Trans.y = Trans.y;
|
|
fwrite( &Trans.x, sizeof(float), 1, expStream );
|
|
fwrite( &Trans.z, sizeof(float), 1, expStream );
|
|
fwrite( &Trans.y, sizeof(float), 1, expStream );
|
|
|
|
if (radius < fabs(Trans.x)) radius = (float)fabs(Trans.x);
|
|
if (radius < fabs(Trans.y)) radius = (float)fabs(Trans.y);
|
|
if (radius < fabs(Trans.z)) radius = (float)fabs(Trans.z);
|
|
}
|
|
}
|
|
|
|
void AsciiExp::ExportVectors(INode * node, Mesh * mesh)
|
|
{
|
|
Matrix3 tm = node->GetObjTMAfterWSM( ip->GetAnimRange().Start() );
|
|
Point3 Trans;
|
|
int nbVerts;
|
|
|
|
radius = 0.f;
|
|
nbVerts = mesh->getNumVerts();
|
|
|
|
// EXPORT MODEL POINTS
|
|
WriteChunkHdr( (char*)VECT_ID, 0 );
|
|
fwrite( &nCurObj, sizeof(Uint32), 1, expStream );
|
|
fwrite( &nbVerts, sizeof(Uint32), 1, expStream );
|
|
|
|
for (int i=0; i<nbVerts; i++)
|
|
{
|
|
Point3 v1;
|
|
|
|
v1 = mesh->verts[i];
|
|
|
|
fwrite( &v1.x, sizeof(float), 1, expStream );
|
|
fwrite( &v1.z, sizeof(float), 1, expStream );
|
|
fwrite( &v1.y, sizeof(float), 1, expStream );
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
---------------------------------------------------------------------- */
|
|
|
|
void AsciiExp::ExportNormals(INode * node, Mesh * mesh)
|
|
{
|
|
int nbVerts;
|
|
Point3 * vnorms;
|
|
Point3 fn; // Face normal
|
|
Point3 vn; // Vertex normal
|
|
|
|
int i;
|
|
Matrix3 tm = node->GetObjTMAfterWSM( ip->GetAnimRange().End() );
|
|
BOOL negScale = TMNegParity(tm);
|
|
int vx1, vx2, vx3;
|
|
|
|
|
|
if (negScale)
|
|
{
|
|
vx1 = 2;
|
|
vx2 = 1;
|
|
vx3 = 0;
|
|
}
|
|
else
|
|
{
|
|
vx1 = 0;
|
|
vx2 = 1;
|
|
vx3 = 2;
|
|
}
|
|
|
|
|
|
mesh->buildNormals();
|
|
|
|
nbVerts = mesh->getNumVerts();
|
|
vnorms = new Point3[nbVerts];
|
|
|
|
for (i=0; i<mesh->getNumVerts(); i++)
|
|
{
|
|
vnorms[i] = GetAverageVertNormal(node, mesh, i);
|
|
}
|
|
|
|
|
|
// EXPORT MODEL NORMALS
|
|
WriteChunkHdr( (char*)NORMAL_ID, 0 );
|
|
fwrite( &nCurObj, sizeof(Uint32), 1, expStream );
|
|
fwrite( &nbVerts, sizeof(Uint32), 1, expStream );
|
|
|
|
for (i=0; i<nbVerts; i++)
|
|
{
|
|
vn = vnorms[i];
|
|
fwrite( &vn.x, sizeof(float), 1, expStream );
|
|
fwrite( &vn.z, sizeof(float), 1, expStream );
|
|
fwrite( &vn.y, sizeof(float), 1, expStream );
|
|
}
|
|
|
|
delete vnorms;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
|
|
Point3 AsciiExp::GetVertexNormal(Mesh* mesh, int faceNo, RVertex* rv)
|
|
{
|
|
Face* f = &mesh->faces[faceNo];
|
|
DWORD smGroup = f->smGroup;
|
|
int numNormals;
|
|
Point3 vertexNormal;
|
|
|
|
// Is normal specified
|
|
// SPCIFIED is not currently used, but may be used in future versions.
|
|
if (rv->rFlags & SPECIFIED_NORMAL)
|
|
{
|
|
// fprintf( pStream, "SPECIFIED_NORMAL\n");
|
|
vertexNormal = rv->rn.getNormal();
|
|
}
|
|
// If normal is not specified it's only available if the face belongs
|
|
// to a smoothing group
|
|
else if ((numNormals = rv->rFlags & NORCT_MASK) && smGroup)
|
|
{
|
|
// If there is only one vertex is found in the rn member.
|
|
if (numNormals == 1)
|
|
{
|
|
// fprintf( pStream, "SINGLE SMOOTHING GROUP\n");
|
|
vertexNormal = rv->rn.getNormal();
|
|
}
|
|
else
|
|
{
|
|
// fprintf( pStream, "SMOOTHING GROUP %d\n", numNormals);
|
|
|
|
// If two or more vertices are there you need to step through them
|
|
// and find the vertex with the same smoothing group as the current face.
|
|
// You will find multiple normals in the ern member.
|
|
for (int i = 0; i < numNormals; i++)
|
|
{
|
|
vertexNormal = rv->ern[i].getNormal();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// fprintf( pStream, "NO SMOOTHING GROUP\n");
|
|
// Get the normal from the Face if no smoothing groups are there
|
|
vertexNormal = mesh->getFaceNormal(faceNo);
|
|
}
|
|
|
|
return vertexNormal;
|
|
}
|
|
|
|
Point3 AsciiExp::GetAverageVertNormal(INode *node, Mesh* mesh, int VertNo)
|
|
{
|
|
int i;
|
|
int c=0;
|
|
Matrix3 tm = node->GetNodeTM(ip->GetAnimRange().Start());
|
|
tm.NoTrans();
|
|
Point3 n= Point3(0.f,0.f,0.f);
|
|
for (i=0; i<mesh->getNumFaces(); i++) {
|
|
if (mesh->faces[i].v[0] == VertNo || mesh->faces[i].v[1] == VertNo || mesh->faces[i].v[2] == VertNo)
|
|
{
|
|
Point3 p0 = tm * mesh->verts[mesh->faces[i].v[0]];
|
|
Point3 p1 = tm * mesh->verts[mesh->faces[i].v[1]];
|
|
Point3 p2 = tm * mesh->verts[mesh->faces[i].v[2]];
|
|
Point3 Nrm = Normalize(CrossProd(p0 - p1, p0 - p2));
|
|
n += Nrm;
|
|
c ++;
|
|
}
|
|
}
|
|
n /= (float)c;
|
|
return Normalize(n);
|
|
}
|
|
|
|
void AsciiExp::ExportNodeAnimMesh( INode* node )
|
|
{
|
|
INode *parent;
|
|
Matrix3 parentTM, nodeTM, localTM;
|
|
parent = node->GetParentNode();
|
|
|
|
TimeValue start = ip->GetAnimRange().Start();
|
|
TimeValue end = ip->GetAnimRange().End();
|
|
int delta = GetTicksPerFrame();
|
|
TimeValue t;
|
|
Matrix3 tm;
|
|
Matrix3 StartM;
|
|
AffineParts ap;
|
|
int i;
|
|
Quat q;
|
|
Quat StartQ, StartU;
|
|
Point3 StartP, StartS;
|
|
|
|
nodeTM = node->GetNodeTM(start);
|
|
parentTM = parent->GetNodeTM(start);
|
|
StartM = nodeTM*Inverse(parentTM);
|
|
|
|
for (t=start; t<=end; t+=delta)
|
|
{
|
|
nodeTM = node->GetNodeTM(t);
|
|
parentTM = parent->GetNodeTM(t);
|
|
tm = nodeTM*Inverse(parentTM);
|
|
for (i=0;i<4;i++) {
|
|
Point3 m0 = StartM.GetRow(i);
|
|
Point3 m1 = tm.GetRow(i);
|
|
if (fabs(m0.x-m1.x)>0.001 ||
|
|
fabs(m0.y-m1.y)>0.001 ||
|
|
fabs(m0.z-m1.z)>0.001)
|
|
break;
|
|
|
|
}
|
|
if (i!=4)
|
|
break;
|
|
}
|
|
if (t==end)
|
|
return;
|
|
|
|
char text[250];
|
|
sprintf(text,"%s", node->GetName());
|
|
|
|
WriteChunkHdr( (char*)ANIM_ID, 0);
|
|
fwrite( &CHANNEL_TYPE_NODE, sizeof( Uint32 ), 1, expStream );
|
|
fwrite( &nCurObj, sizeof( Uint32 ), 1, expStream );
|
|
fwrite( &totFrames, sizeof( Uint32 ), 1, expStream );
|
|
for (t=start; t<=end; t+=delta) {
|
|
// TRANSLATION
|
|
tm = node->GetNodeTM(t) * Inverse(node->GetParentTM(t));
|
|
decomp_affine(tm, &ap);
|
|
|
|
fwrite( &ap.t.x, sizeof(float), 1, expStream ); // WRITE BONE X-POS
|
|
fwrite( &ap.t.z, sizeof(float), 1, expStream ); // WRITE BONE Y-POS
|
|
fwrite( &ap.t.y, sizeof(float), 1, expStream ); // WRITE BONE Z-POS
|
|
|
|
fwrite( &ap.q.x, sizeof(float), 1, expStream ); // WRITE BONE X-POS
|
|
fwrite( &ap.q.z, sizeof(float), 1, expStream ); // WRITE BONE Y-POS
|
|
fwrite( &ap.q.y, sizeof(float), 1, expStream ); // WRITE BONE Z-POS
|
|
fwrite( &ap.q.w, sizeof(float), 1, expStream ); // WRITE BONE Z-POS
|
|
|
|
fwrite( &ap.k.x, sizeof(float), 1, expStream ); // WRITE BONE X-POS
|
|
fwrite( &ap.k.z, sizeof(float), 1, expStream ); // WRITE BONE Y-POS
|
|
fwrite( &ap.k.y, sizeof(float), 1, expStream ); // WRITE BONE Z-POS
|
|
|
|
fwrite( &ap.u.x, sizeof(float), 1, expStream ); // WRITE BONE X-POS
|
|
fwrite( &ap.u.z, sizeof(float), 1, expStream ); // WRITE BONE Y-POS
|
|
fwrite( &ap.u.y, sizeof(float), 1, expStream ); // WRITE BONE Z-POS
|
|
fwrite( &ap.u.w, sizeof(float), 1, expStream ); // WRITE BONE Z-POS
|
|
}
|
|
}
|
|
|
|
void AsciiExp::ExportVisTrack( INode* node )
|
|
{
|
|
Control *VisControl = node->GetVisController();
|
|
if (VisControl) {
|
|
float VisF;
|
|
TimeValue start = ip->GetAnimRange().Start();
|
|
TimeValue end = ip->GetAnimRange().End();
|
|
int delta = GetTicksPerFrame();
|
|
TimeValue t;
|
|
WriteChunkHdr( (char*)VIS_ID, 0);
|
|
fwrite( &nCurObj, sizeof( Uint32 ), 1, expStream );
|
|
fwrite( &totFrames, sizeof( Uint32 ), 1, expStream );
|
|
for (t=start; t<=end; t+=delta) {
|
|
Interval I = Interval(t, t);
|
|
VisControl->GetValue(t, &VisF, I, CTRL_ABSOLUTE);
|
|
fwrite( &VisF, sizeof(float), 1, expStream);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void AsciiExp::ExportAnimMesh( INode* node )
|
|
{
|
|
TimeValue start = ip->GetAnimRange().Start();
|
|
TimeValue end = ip->GetAnimRange().End();
|
|
int delta = GetTicksPerFrame();
|
|
BOOL needDel;
|
|
Mesh *mesh;
|
|
TriObject *tri;
|
|
TimeValue t;
|
|
|
|
WriteChunkHdr( (char*)ANIM_ID, 0);
|
|
fwrite( &CHANNEL_TYPE_VERTEX, sizeof( Uint32 ), 1, expStream );
|
|
fwrite( &nCurObj, sizeof( Uint32 ), 1, expStream );
|
|
fwrite( &totFrames, sizeof( Uint32 ), 1, expStream );
|
|
for (t=start; t<=end; t+=delta)
|
|
{
|
|
tri = GetTriObjectFromNode(node, t, needDel);
|
|
if (!tri) return;
|
|
mesh = &tri->mesh;
|
|
Matrix3 tm = node->GetObjTMAfterWSM( t );
|
|
for (int i=0; i<mesh->getNumVerts(); i++)
|
|
{
|
|
Point3 v1;
|
|
Point3 v2;
|
|
|
|
v1 = mesh->verts[i];
|
|
v2 = tm * v1;
|
|
|
|
fwrite( &v2.x, sizeof(float), 1, expStream );
|
|
fwrite( &v2.z, sizeof(float), 1, expStream );
|
|
fwrite( &v2.y, sizeof(float), 1, expStream );
|
|
}
|
|
if (needDel) tri->DeleteThis();
|
|
}
|
|
}
|
|
|
|
/*===========================================================================
|
|
end */
|