2 fegdk: FE Game Development Kit
3 Copyright (C) 2001-2008 Alexey "waker" Yakovenko
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 waker@users.sourceforge.net
26 #include "f_expmodel.h"
27 #include "f_material.h"
30 #include "f_texture.h"
32 #include "f_resourcemgr.h"
37 //----------------------
39 //----------------------
41 expScene::expScene (void)
45 expScene::~expScene ()
49 int expScene::load (const char *fname
)
51 const char *tmp
= fname
;
64 fprintf (stderr
, "fname is %s, modelname is %s\n", fname
, fn
);
65 #ifdef FE_NO_FILESYSTEM
66 charParser
p (fname
, true);
68 // this thing always uses stdio
69 charParser
p (NULL
, fname
, true);
76 void expScene::load (charParser
&p
)
81 if (!p
.cmptoken ("materials"))
87 if (p
.token () == "}")
89 mMtlNameList
.push_back (p
.token ());
92 materialPtr mtl
= g_engine
->getResourceMgr ()->createMaterial (p
.token ()); mMtlList
.push_back (mtl
);
96 else if (!p
.cmptoken ("bones"))
103 if (!p
.cmptoken ("}"))
105 mBoneList
.push_back (p
.token ());
110 mpSceneRoot
= loadObject (p
);
112 p
.generalSyntaxError ();
118 expObjectPtr
expScene::loadObject (charParser
&p
)
121 if (!p
.cmptoken ("triobject"))
123 o
= new expTriObject (NULL
);
124 o
->load (p
, name ());
126 else if (!p
.cmptoken ("dummy"))
128 o
= new expDummyObject (NULL
);
129 o
->load (p
, name ());
131 else if (!p
.cmptoken ("entity"))
133 o
= new expEntityObject (NULL
);
134 o
->load (p
, name ());
139 void expScene::render ()
142 getRootNode ()->render (this);
145 //----------------------
147 //----------------------
149 expTriObject::expTriObject (expObject
*parent
)
152 mClassID
= TRI_OBJECT_CLASS_ID
;
155 void expTriObject::load (charParser
&p
, const char *filename
)
161 cStr fname
= filename
;
163 // try to load tangentspace
168 // old code which relied on tangent-space matrix built by normalmap generator
169 FILE *fp = fopen (fname + ".tgs", "rb");
174 fread (magic, 7, 1, fp);
176 // 1.00 contained SxT too, was removed in 1.01
177 if (strcmp (magic, "TGS0101"))
178 throw genericError ("invalid signature inf file '%s.tgs'", fname.c_str ());
180 fread (&sz, sizeof (sz), 1, fp);
181 mTSVerts.resize (sz);
182 fread (&mTSVerts.front (), sz, sizeof (vertexTangentSpace), fp);
183 fread (&sz, sizeof (sz), 1, fp);
184 mTSFaces.resize (sz);
185 fread (&mTSFaces.front (), sz, sizeof (expFace), fp);
192 if (p
.token () == "}")
194 else if (baseLoad (p
, fname
))
197 else if (!p
.cmptoken ("verts"))
201 p
.matchToken ("count");
203 int cnt
= atoi (p
.token ());
205 for (int i
= 0; i
< cnt
; i
++)
209 mVerts
[i
].x
= atof (p
.token ());
211 mVerts
[i
].y
= atof (p
.token ());
213 mVerts
[i
].z
= atof (p
.token ());
217 else if (!p
.cmptoken ("faces"))
221 p
.matchToken ("count");
223 int cnt
= atoi (p
.token ());
225 for (int i
= 0; i
< cnt
; i
++)
229 mFaces
[i
].v
[0] = atoi (p
.token ());
231 mFaces
[i
].v
[1] = atoi (p
.token ());
233 mFaces
[i
].v
[2] = atoi (p
.token ());
237 else if (!p
.cmptoken ("colors"))
241 p
.matchToken ("count");
243 int cnt
= atoi (p
.token ());
244 mColors
.resize (cnt
);
245 for (int i
= 0; i
< cnt
; i
++)
249 mColors
[i
].x
= atof (p
.token ());
251 mColors
[i
].y
= atof (p
.token ());
253 mColors
[i
].z
= atof (p
.token ());
257 else if (!p
.cmptoken ("ColorFaces"))
261 p
.matchToken ("count");
263 int cnt
= atoi (p
.token ());
264 mColorFaces
.resize (cnt
);
265 for (int i
= 0; i
< cnt
; i
++)
269 mColorFaces
[i
].v
[0] = atoi (p
.token ());
271 mColorFaces
[i
].v
[1] = atoi (p
.token ());
273 mColorFaces
[i
].v
[2] = atoi (p
.token ());
277 else if (!p
.cmptoken ("normals"))
281 p
.matchToken ("count");
283 int cnt
= atoi (p
.token ());
284 mNormals
.resize (cnt
);
285 for (int i
= 0; i
< cnt
; i
++)
289 mNormals
[i
].x
= atof (p
.token ());
291 mNormals
[i
].y
= atof (p
.token ());
293 mNormals
[i
].z
= atof (p
.token ());
297 else if (!p
.cmptoken ("normalFaces"))
301 p
.matchToken ("count");
303 int cnt
= atoi (p
.token ());
304 mNormalFaces
.resize (cnt
);
305 for (int i
= 0; i
< cnt
; i
++)
309 mNormalFaces
[i
].v
[0] = atoi (p
.token ());
311 mNormalFaces
[i
].v
[1] = atoi (p
.token ());
313 mNormalFaces
[i
].v
[2] = atoi (p
.token ());
317 else if (!p
.cmptoken ("uvVerts"))
321 p
.matchToken ("count");
323 int cnt
= atoi (p
.token ());
324 mTexCoords
.resize (cnt
);
325 for (int i
= 0; i
< cnt
; i
++)
329 mTexCoords
[i
].x
= atof (p
.token ());
331 mTexCoords
[i
].y
= atof (p
.token ());
335 else if (!p
.cmptoken ("uvFaces"))
339 p
.matchToken ("count");
341 int cnt
= atoi (p
.token ());
342 mTexCoordFaces
.resize (cnt
);
343 for (int i
= 0; i
< cnt
; i
++)
347 mTexCoordFaces
[i
].v
[0] = atoi (p
.token ());
349 mTexCoordFaces
[i
].v
[1] = atoi (p
.token ());
351 mTexCoordFaces
[i
].v
[2] = atoi (p
.token ());
355 else if (!p
.cmptoken ("uvLightmap"))
359 p
.matchToken ("count");
361 int cnt
= atoi (p
.token ());
362 mLightmapTexCoords
.resize (cnt
);
363 for (int i
= 0; i
< cnt
; i
++)
367 mLightmapTexCoords
[i
].x
= atof (p
.token ());
369 mLightmapTexCoords
[i
].y
= atof (p
.token ());
373 else if (!p
.cmptoken ("uvLightmapFaces"))
377 p
.matchToken ("count");
379 int cnt
= atoi (p
.token ());
380 mLightmapTexCoordFaces
.resize (cnt
);
381 for (int i
= 0; i
< cnt
; i
++)
385 mLightmapTexCoordFaces
[i
].v
[0] = atoi (p
.token ());
387 mLightmapTexCoordFaces
[i
].v
[1] = atoi (p
.token ());
389 mLightmapTexCoordFaces
[i
].v
[2] = atoi (p
.token ());
393 else if (!p
.cmptoken ("mtlIndex"))
397 p
.matchToken ("count");
399 int cnt
= atoi (p
.token ());
400 mMtlIndex
.resize (cnt
);
401 for (int i
= 0; i
< cnt
; i
++)
405 mMtlIndex
[i
] = atoi (p
.token ());
409 else if (!p
.cmptoken ("vertexInfluences"))
412 p
.matchToken ("count");
414 int cnt
= atoi (p
.token ());
415 mVertexInfluences
.resize (cnt
);
416 for (int i
= 0; i
< cnt
; i
++)
420 int vtx
= atoi (p
.token ());
422 int wcnt
= atoi (p
.token ());
423 mVertexInfluences
[i
].resize (wcnt
);
424 for (int k
= 0; k
< wcnt
; k
++)
427 mVertexInfluences
[vtx
][wcnt
].bone
= atoi (p
.token ());
429 mVertexInfluences
[vtx
][wcnt
].weight
= atof (p
.token ());
435 printf ("'%s' triobj stats:\n", name ());
436 printf (" %d verts\n", mVerts
.size ());
437 printf (" %d colors\n", mColors
.size ());
438 printf (" %d normals\n", mNormals
.size ());
439 printf (" %d texcoords\n", mTexCoords
.size ());
440 printf (" %d litmapcoords\n", mLightmapTexCoords
.size ());
441 printf (" %d faces\n", mFaces
.size ());
442 printf (" %d colorfaces\n", mColorFaces
.size ());
443 printf (" %d normalfaces\n", mNormalFaces
.size ());
444 printf (" %d tcfaces\n", mTexCoordFaces
.size ());
445 printf (" %d lightmaptcfaces\n", mLightmapTexCoordFaces
.size ());
446 printf (" %d mtlindexes\n", mMtlIndex
.size ());
447 printf (" %d tangents\n", mTangents
.size ());
448 printf (" %d binormals\n", mBinormals
.size ());
449 printf (" %d tsfaces\n", mTSFaces
.size ());
454 if (!mTangentSpace
.empty ())
456 assert (mTangentSpace
.size () == mFaces
.size ());
461 void expTriObject::transformIntoWorldSpace (void)
464 for (i
= 0; i
< mVerts
.size (); i
++)
465 mVerts
[i
] = mVerts
[i
] * mWorldMatrix
;
466 for (i
= 0; i
< mNormals
.size (); i
++)
468 mNormals
[i
] = mWorldMatrix
.transform (mNormals
[i
]);
469 mNormals
[i
].normalize ();
473 void expTriObject::render (expScene
*scene
)
476 if (mtlIndex ().empty ())
479 gpD3DDev
->SetTransform (D3DTS_WORLD
, (D3DMATRIX
*)&getWorldMatrix ());
486 for (size_t face_i
= 0; face_i
< faces ().size (); face_i
++)
488 if ( (!mtlIndex ().empty () && mtlIndex ()[face_i
] != prevMtl
) || nFaces
* 3 > engine::DYNAMIC_VB_SIZE
- 3)
494 flush (scene
, prevMtl
, firstFace
, nFaces
);
502 prevMtl
= mtlIndex ()[face_i
];
505 flush (scene
, prevMtl
, firstFace
, nFaces
);
507 expObject::render (scene
);
510 void expTriObject::flush (expScene
*scene
, int mtl
, int firstFace
, int nFaces
)
513 // flush & restart vb
514 dynamicVB
< fFVertex
> *vb
= engine::get ()->dynamicVB ();
516 fFVertex
*data
= vb
->lock (nFaces
* 3, start
);
517 for (int f
= 0; f
< nFaces
; f
++)
519 if (texCoords ().empty ())
521 *data
= fFVertex (verts ()[faces ()[firstFace
+f
].v
[0]], 0, vector2 (0, 0));
523 *data
= fFVertex (verts ()[faces ()[firstFace
+f
].v
[1]], 0, vector2 (0, 0));
525 *data
= fFVertex (verts ()[faces ()[firstFace
+f
].v
[2]], 0, vector2 (0, 0));
530 *data
= fFVertex (verts ()[faces ()[firstFace
+f
].v
[0]], 0, texCoords ()[texCoordFaces ()[firstFace
+f
].v
[0]]);
532 *data
= fFVertex (verts ()[faces ()[firstFace
+f
].v
[1]], 0, texCoords ()[texCoordFaces ()[firstFace
+f
].v
[1]]);
534 *data
= fFVertex (verts ()[faces ()[firstFace
+f
].v
[2]], 0, texCoords ()[texCoordFaces ()[firstFace
+f
].v
[2]]);
541 scene
->mtlList ()[mtl
]->setupEffectInputs ();
542 effect
*e
= scene
->mtlList ()[mtl
]->getEffect ();
543 e
->setBestTechnique ();
546 gpD3DDev
->DrawPrimitive (D3DPT_TRIANGLELIST
, start
, nFaces
);
551 //----------------------
553 //----------------------
555 expModel::expModel (expModel
*parent
)
556 : sceneObject (parent
)
562 expModel::~expModel ()
566 void expModel::convertFrom (const expScenePtr
&s
, const expObjectPtr
&root
)
568 expObjectPtr oo
= root
;
569 if (s
->getRootNode () == oo
&& oo
->children ().size () == 1)
571 // discard rootnode, convert from child #1 instead
572 oo
= oo
->children ().front ();
573 fprintf (stderr
, "root node is redundant, starting from 1st child (%s)...\n", oo
->name ());
575 else if (s
->getRootNode () == oo
)
576 fprintf (stderr
, "root node will be included in resulting scene, contains %d children...\n", oo
->children ().size ());
577 setName (oo
->name ());
580 if (oo
->getClassID () == TRI_OBJECT_CLASS_ID
)
582 fprintf (stderr
, "converting mesh for triobject %s...\n", oo
->name ());
583 const expTriObject
*o
= checked_cast
<const expTriObject
*> ( (const expObject
*)oo
);
584 // for now we always build tangentspace (by default)
585 mbTangents
= true; // o->tsVerts ().empty () ? false : true;
586 mbLightmaps
= o
->lightmapTexCoords ().empty () ? false : true;
588 mLightmapName
= oo
->name () + cStr ("_lm.tga"); // max uses tga by default
594 // FIXME: optimize tangentspace calculation - this is very slow unoptimized code
596 fprintf (stderr
, "calculating tangent space basis for all faces...\n");
598 // calc tangent space for all faces
599 vector3
*faceTangents
= new vector3
[o
->faces ().size () * 2];
600 for (int i
= 0; i
< o
->faces ().size (); i
++)
602 const vector3
&V0
= o
->verts ()[o
->faces ()[i
].v
[0]];
603 const vector3
&V1
= o
->verts ()[o
->faces ()[i
].v
[1]];
604 const vector3
&V2
= o
->verts ()[o
->faces ()[i
].v
[2]];
605 const vector2
&v0st
= o
->texCoords ()[o
->texCoordFaces ()[i
].v
[0]];
606 const vector2
&v1st
= o
->texCoords ()[o
->texCoordFaces ()[i
].v
[1]];
607 const vector2
&v2st
= o
->texCoords ()[o
->texCoordFaces ()[i
].v
[2]];
608 calcTriangleBasis (V0
, V1
, V2
,
609 v0st
[0], v0st
[1], v1st
[0], v1st
[1], v2st
[0], v2st
[1],
610 faceTangents
[i
*2+0], faceTangents
[i
*2+1]);
614 vector3
*tangents
= new vector3
[o
->faces ().size () * 3];
615 vector3
*binormals
= new vector3
[o
->faces ().size () * 3];
616 int *cnt
= new int[o
->faces ().size () * 3];
617 memset (tangents
, 0, sizeof (vector3
) * o
->faces ().size () * 3);
618 memset (binormals
, 0, sizeof (vector3
) * o
->faces ().size () * 3);
619 memset (cnt
, 0, sizeof (int) * o
->faces ().size () * 3);
623 for (j
= 0; j
< o
->faces ().size () * 3; j
++)
625 // add tangent space to vertex
626 tangents
[j
] += faceTangents
[j
/3*2+0];
627 binormals
[j
] += faceTangents
[j
/3*2+1];
630 const vector3
&pos
= o
->verts ()[o
->faces ()[j
/3].v
[j
%3]];
631 const vector3
&norm
= o
->normals ()[o
->normalFaces ()[j
/3].v
[j
%3]];
633 // find all verts which share same position and normal (i.e. share smoothing groups)
634 for (int k
= 0; k
< o
->faces ().size ()*3; k
++)
636 const vector3
&pos2
= o
->verts ()[o
->faces ()[k
/3].v
[k
%3]];
637 const vector3
&norm2
= o
->normals ()[o
->normalFaces ()[k
/3].v
[k
%3]];
638 if (pos
== pos2
&& norm
== norm2
)
640 // check if angle between tangents ate ok
641 float d_t
= faceTangents
[j
/3*2+0].dot (faceTangents
[k
/3*2+0]);
642 float d_b
= faceTangents
[j
/3*2+1].dot (faceTangents
[k
/3*2+1]);
643 if (d_t
> 0 && d_b
> 0)
646 tangents
[j
] += faceTangents
[k
/3*2+0];
647 binormals
[j
] += faceTangents
[k
/3*2+1];
653 for (j
= 0; j
< o
->faces ().size (); j
++)
655 for (i
= 0; i
< 3; i
++)
657 tangents
[j
*3+i
] /= cnt
[j
*3+i
];
658 binormals
[j
*3+i
] /= cnt
[j
*3+i
];
659 tangents
[j
*3+i
].normalize ();
660 binormals
[j
*3+i
].normalize ();
661 tangents
[j
*3+i
] = orthogonalize (o
->normals ()[o
->normalFaces ()[j
].v
[i
]], tangents
[j
*3+i
]);
662 binormals
[j
*3+i
] = orthogonalize (o
->normals ()[o
->normalFaces ()[j
].v
[i
]], binormals
[j
*3+i
]);
666 delete[] faceTangents
;
669 fprintf (stderr
, "creating vertex and index buffer...\n");
671 for (mtl_i
= 0; mtl_i
< (int)s
->mtlNameList ().size (); mtl_i
++)
673 std::vector
< drawVertex_t
> verts
;
674 std::vector
< face
> faces
;
675 fprintf (stderr
, "subset %d (mtl=%s)...\n", mtl_i
, s
->mtlNameList ()[mtl_i
].c_str ());
676 for (face_i
= 0; face_i
< (int)o
->faces ().size (); face_i
++)
678 if (o
->mtlIndex ().empty () || o
->mtlIndex ()[face_i
] == mtl_i
)
681 // fprintf (stderr, "fetching face %d...\n", face_i);
682 const expFace
&f
= o
->faces ()[face_i
];
683 // fprintf (stderr, "fetching normface %d...\n", face_i);
684 const expFace
&nf
= o
->normalFaces ()[face_i
];
685 // fprintf (stderr, "fetching tcface %d...\n", face_i);
686 const expFace
&tf
= o
->texCoordFaces ()[face_i
];
687 // fprintf (stderr, "fetching lmtcface %d...\n", face_i);
688 const expFace
*ltf
= o
->lightmapTexCoordFaces ().empty () ? NULL
: &o
->lightmapTexCoordFaces ()[face_i
];
691 int remap_face
[] = {0,2,1};
693 for (vertex_i
= 0; vertex_i
< 3; vertex_i
++)
696 // fprintf (stderr, "fetching vx %d...\n", f.v[vertex_i]);
697 v
.pos
= o
->verts ()[f
.v
[vertex_i
]];
698 // fprintf (stderr, "fetching norm %d...\n", nf.v[vertex_i]);
699 v
.norm
= o
->normals ()[nf
.v
[vertex_i
]];
700 // fprintf (stderr, "fetching uv %d...\n", tf.v[vertex_i]);
701 v
.uv
= o
->texCoords ().empty () ? vector2 (0, 0) : o
->texCoords ()[tf
.v
[vertex_i
]];
702 // fprintf (stderr, "fetching ligthmap uv %d...\n", ltf ? ltf->v[vertex_i] : -1);
704 v
.uvLightmap
= o
->lightmapTexCoords ()[ltf
->v
[vertex_i
]];
705 // fprintf (stderr, "fetching tangent %d...\n", face_i*3+vertex_i);
706 // fprintf (stderr, "fetching binormal %d...\n", face_i*3+vertex_i);
707 v
.tangents
[0] = tangents
[face_i
*3+vertex_i
];
708 v
.tangents
[1] = binormals
[face_i
*3+vertex_i
];
710 std::vector
< drawVertex_t
>::iterator it
;
711 it
= std::find (verts
.begin (), verts
.end (), v
);
712 if (it
!= verts
.end ())
713 outface
.v
[remap_face
[vertex_i
]] = it
- verts
.begin ();
716 outface
.v
[remap_face
[vertex_i
]] = (int)verts
.size ();
720 faces
.push_back (outface
);
725 fprintf (stderr
, "adding %d verts, %d faces...\n", verts
.size (), faces
.size ());
728 s
.firstVertex
= (int)mVerts
.size ();
729 s
.firstFace
= (int)mFaces
.size ();
730 s
.numVerts
= (int)verts
.size ();
731 s
.numFaces
= (int)faces
.size ();
733 mSubSets
.push_back (s
);
735 for (vertex_i
= 0; vertex_i
< (int)verts
.size (); vertex_i
++)
736 mVerts
.push_back (verts
[vertex_i
]);
738 for (face_i
= 0; face_i
< (int)faces
.size (); face_i
++)
740 mFaces
.push_back (faces
[face_i
]);
741 mMtlIndex
.push_back (s
.mtl
);
753 mRelativeMatrix
= oo
->getMatrix ();
754 mWorldMatrix
= mpParentObject
? mRelativeMatrix
* mpParentObject
->getWorldMatrix () : mRelativeMatrix
;
756 // ... win32 version should create d3dxmesh and optimize here ...
758 for (int i
= 0; i
< (int)oo
->children ().size (); i
++)
760 expModel
*m
= new expModel (this);
761 m
->convertFrom (s
, oo
->children ()[i
]);
766 void expModel::save (const char *fname
, const expScenePtr
&s
) const
768 FILE *fp
= fopen (fname
, "w+b");
771 fprintf (stderr
, "failed to open file '%s' for writing\n", fname
);
777 // 0101 -- added lightmaps support
778 // 0102 -- animation is now separate file
780 char mgc
[] = "FEMDL0102";
781 fwrite (mgc
, strlen (mgc
), 1, fp
);
787 fprintf (stderr
, "writing materials...\n");
788 sp
= (ulong
)s
->mtlNameList ().size ();
789 fwrite (&sp
, sizeof (ulong
), 1, fp
);
791 for (i
= 0; i
< (int)s
->mtlNameList ().size (); i
++)
793 cStr mtlName
= s
->mtlNameList ()[i
];
794 uchar l
= (uchar
)mtlName
.size ();
795 fwrite (&l
, 1, 1, fp
);
796 fwrite (mtlName
.c_str (), mtlName
.size (), 1, fp
);
799 fprintf (stderr
, "writing scene hierarchy...\n");
805 void expModel::saveGeometry (FILE *fp
) const
809 fprintf (stderr
, "writing name: %s\n", name ());
810 char nsz
= strlen (name ());
811 fwrite (&nsz
, sizeof (char), 1, fp
);
813 fwrite (name (), nsz
, 1, fp
);
815 sp
= sizeof (matrix4
);
816 fwrite (&mRelativeMatrix
, sp
, 1, fp
);
818 fprintf (stderr
, "writing %d subsets\n", mSubSets
.size ());
819 sp
= (ulong
)mSubSets
.size ();
820 fwrite (&sp
, sizeof (ulong
), 1, fp
);
821 fwrite (&mSubSets
.front (), sizeof (subset
), mSubSets
.size (), fp
);
823 fprintf (stderr
, "tangents: %s\n", mbTangents
? "yes" : "no");
824 uchar tangents
= mbTangents
? 1 : 0;
825 fwrite (&tangents
, sizeof (uchar
), 1, fp
);
827 fprintf (stderr
, "ligthmap coords: %s\n", mbLightmaps
? "yes" : "no");
828 uchar lightmaps
= mbLightmaps
? 1 : 0;
829 fwrite (&lightmaps
, sizeof (uchar
), 1, fp
);
832 // write lightmap texture name
833 uchar sz
= mLightmapName
.size ();
834 fwrite (&sz
, 1, 1, fp
);
836 fwrite (&mLightmapName
[0], sz
, 1, fp
);
839 fprintf (stderr
, "%d verts\n", mVerts
.size ());
840 sp
= (ulong
)mVerts
.size ();
841 fwrite (&sp
, sizeof (ulong
), 1, fp
);
842 fwrite (&mVerts
.front (), sizeof (drawVertex_t
), mVerts
.size (), fp
);
844 fprintf (stderr
, "%d faces\n", mFaces
.size ());
845 sp
= (ulong
)mFaces
.size ();
846 fwrite (&sp
, sizeof (ulong
), 1, fp
);
847 fwrite (&mFaces
.front (), sizeof (face
), mFaces
.size (), fp
);
851 uchar b
= mpAnimationController
->numFrames () != 0;
852 fwrite (&b
, sizeof (uchar
), 1, fp
);
855 float fr
= mpAnimationController
->frameRate ();
856 fwrite (&fr
, sizeof (float), 1, fp
);
857 sp
= (ulong
)mpAnimationController
->numFrames ();
858 fwrite (&sp
, sizeof (ulong
), 1, fp
);
859 for (int i
= 0; i
< (int)sp
; i
++)
861 const animationFrame
&frm
= mpAnimationController
->getFrame (i
);
862 fwrite (&frm
, sizeof (animationFrame
), 1, fp
);
868 for (sceneObject
*c
= mpChildren
; c
; c
= c
->getNextChild (), sp
++);
870 fwrite (&sp
, sizeof (ulong
), 1, fp
);
872 for (sceneObject
*c
= mpChildren
; c
; c
= c
->getNextChild ())
874 const expModel
*exp
= checked_cast
<const expModel
*> (c
);
875 exp
->saveGeometry (fp
);
879 //----------------------
881 //----------------------
882 expRefObject::expRefObject (expObject
*parent
)
885 mClassID
= REF_OBJECT_CLASS_ID
;
889 void expRefObject::load (charParser
&p
, const char *fname
)
894 void expRefObject::render (expScene
*scene
)
898 expObject::render (scene
);
901 //----------------------
903 //----------------------
904 expEntityObject::expEntityObject (expObject
*parent
)
907 mClassID
= ENTITY_OBJECT_CLASS_ID
;
910 void expEntityObject::load (charParser
&p
, const char *filename
)
916 cStr fname
= filename
;
924 if (p
.token () == "}")
926 else if (baseLoad (p
, fname
))
929 else if (!p
.cmptoken ("prop"))
932 cStr key
= p
.token ();
934 mProps
[key
] = p
.token ();
937 p
.generalSyntaxError ();
941 void expEntityObject::render (expScene
*scene
)
943 expObject::render (scene
);
946 //----------------------
948 //----------------------
950 expDummyObject::expDummyObject (expObject
*parent
)
953 mClassID
= DUMMY_OBJECT_CLASS_ID
;
956 void expDummyObject::load (charParser
&p
, const char *filename
)
962 cStr fname
= filename
;
969 if (p
.token () == "}")
971 else if (baseLoad (p
, fname
))
975 p
.generalSyntaxError ();
979 void expDummyObject::render (expScene
*scene
)
981 expObject::render (scene
);
984 //----------------------
986 //----------------------
987 expObject::expObject (expObject
*parent
)
993 bool expObject::baseLoad (charParser
&p
, const char *fname
)
995 if (!p
.cmptoken ("nodeTransform"))
1000 for (int i
= 0; i
< 4; i
++)
1002 for (int k
= 0; k
< 3; k
++)
1005 mMatrix
.m
[i
][k
] = atof (p
.token ());
1011 mWorldMatrix
= mMatrix
* mpParent
->getWorldMatrix ();
1013 mWorldMatrix
= mMatrix
;
1015 else if (!p
.cmptoken ("dummy"))
1017 expDummyObject
*o
= new expDummyObject (this);
1019 mChildren
.push_back (o
);
1021 else if (!p
.cmptoken ("triobject"))
1023 expTriObject
*o
= new expTriObject (this);
1025 mChildren
.push_back (o
);
1027 else if (!p
.cmptoken ("entity"))
1029 expEntityObject
*o
= new expEntityObject (this);
1031 mChildren
.push_back (o
);
1039 void expObject::setMatrix (const matrix4
&m
)
1043 // recalc world matrix
1044 mWorldMatrix
= mpParent
? mMatrix
* mpParent
->getWorldMatrix () : mMatrix
;
1046 // retransform children
1047 for (size_t i
= 0; i
< mChildren
.size (); i
++)
1049 mChildren
[i
]->recalcWorldTransforms ();
1053 void expObject::setWorldMatrix (const matrix4
&m
)
1057 // recalc relative matrix
1058 mMatrix
= mpParent
? mWorldMatrix
* mpParent
->getWorldMatrix ().inverse () : mWorldMatrix
;
1060 // retransform children
1061 for (size_t i
= 0; i
< mChildren
.size (); i
++)
1063 mChildren
[i
]->recalcWorldTransforms ();
1067 void expObject::recalcWorldTransforms (void)
1069 mWorldMatrix
= mpParent
? mMatrix
* mpParent
->getWorldMatrix () : mMatrix
;
1070 for (size_t i
= 0; i
< mChildren
.size (); i
++)
1072 mChildren
[i
]->recalcWorldTransforms ();
1076 void expObject::render (const expScenePtr
&scene
) const
1078 for (size_t i
= 0; i
< mChildren
.size (); i
++)
1079 mChildren
[i
]->render (scene
);
1082 void expObject::addChild (const expObjectPtr
&child
)
1084 child
->setParent (this);
1087 void expObject::removeChild (const expObjectPtr
&child
)
1090 assert (child
->getParent () == this);
1091 child
->setParent (NULL
);
1094 void expObject::setParent (expObject
*parent
)
1096 if (NULL
!= mpParent
)
1098 for (childrenList::iterator it
= mpParent
->mChildren
.begin (); it
!= mpParent
->mChildren
.end (); it
++)
1102 mpParent
->mChildren
.erase (it
);
1112 mpParent
->mChildren
.push_back (this);