changed copyright years in source files
[fegdk.git] / core / code / system / f_expmodel.cpp
blobcff1471cadbae7d816e091342eda40b83f01cb78
1 /*
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
19 Alexey Yakovenko
20 waker@users.sourceforge.net
23 #include "pch.h"
24 #include "f_types.h"
25 #include "f_parser.h"
26 #include "f_expmodel.h"
27 #include "f_material.h"
28 #include "f_error.h"
29 #include "f_engine.h"
30 #include "f_texture.h"
31 #include "f_effect.h"
32 #include "f_resourcemgr.h"
34 namespace fe
37 //----------------------
38 // expScene
39 //----------------------
41 expScene::expScene (void)
45 expScene::~expScene ()
49 int expScene::load (const char *fname)
51 const char *tmp = fname;
52 const char *fn = tmp;
53 while (*tmp)
55 if (*tmp == '/')
56 fn = tmp;
57 tmp++;
59 if (*fn == '/')
60 fn++;
62 mName = fn;
64 fprintf (stderr, "fname is %s, modelname is %s\n", fname, fn);
65 #ifdef FE_NO_FILESYSTEM
66 charParser p (fname, true);
67 #else
68 // this thing always uses stdio
69 charParser p (NULL, fname, true);
70 #endif
71 load (p);
73 return 0;
76 void expScene::load (charParser &p)
78 for (;;)
80 p.getToken ();
81 if (!p.cmptoken ("materials"))
83 p.matchToken ("{");
84 for (;;)
86 p.getToken ();
87 if (p.token () == "}")
88 break;
89 mMtlNameList.push_back (p.token ());
90 if (g_engine)
92 materialPtr mtl = g_engine->getResourceMgr ()->createMaterial (p.token ()); mMtlList.push_back (mtl);
96 else if (!p.cmptoken ("bones"))
98 // read bones
99 p.matchToken ("{");
100 for (;;)
102 p.getToken ();
103 if (!p.cmptoken ("}"))
104 break;
105 mBoneList.push_back (p.token ());
108 else
110 mpSceneRoot = loadObject (p);
111 if (!mpSceneRoot)
112 p.generalSyntaxError ();
113 return;
118 expObjectPtr expScene::loadObject (charParser &p)
120 expObject *o = NULL;
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 ());
136 return o;
139 void expScene::render ()
141 if (getRootNode ())
142 getRootNode ()->render (this);
145 //----------------------
146 // expTriObject
147 //----------------------
149 expTriObject::expTriObject (expObject *parent)
150 : expObject (parent)
152 mClassID = TRI_OBJECT_CLASS_ID;
155 void expTriObject::load (charParser &p, const char *filename)
157 p.getToken ();
158 mName = p.token ();
159 p.matchToken ("{");
161 cStr fname = filename;
163 // try to load tangentspace
164 fname += "_";
165 fname += mName;
168 // old code which relied on tangent-space matrix built by normalmap generator
169 FILE *fp = fopen (fname + ".tgs", "rb");
170 if (fp)
172 // read magic
173 char magic[8];
174 fread (magic, 7, 1, fp);
175 magic[7] = 0;
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 ());
179 ulong sz;
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);
186 fclose (fp);
189 for (;;)
191 p.getToken ();
192 if (p.token () == "}")
193 break;
194 else if (baseLoad (p, fname))
197 else if (!p.cmptoken ("verts"))
199 // verts
200 p.matchToken ("{");
201 p.matchToken ("count");
202 p.getToken ();
203 int cnt = atoi (p.token ());
204 mVerts.resize (cnt);
205 for (int i = 0; i < cnt; i++)
207 p.matchToken ("v");
208 p.getToken ();
209 mVerts[i].x = atof (p.token ());
210 p.getToken ();
211 mVerts[i].y = atof (p.token ());
212 p.getToken ();
213 mVerts[i].z = atof (p.token ());
215 p.matchToken ("}");
217 else if (!p.cmptoken ("faces"))
219 // faces
220 p.matchToken ("{");
221 p.matchToken ("count");
222 p.getToken ();
223 int cnt = atoi (p.token ());
224 mFaces.resize (cnt);
225 for (int i = 0; i < cnt; i++)
227 p.matchToken ("f");
228 p.getToken ();
229 mFaces[i].v[0] = atoi (p.token ());
230 p.getToken ();
231 mFaces[i].v[1] = atoi (p.token ());
232 p.getToken ();
233 mFaces[i].v[2] = atoi (p.token ());
235 p.matchToken ("}");
237 else if (!p.cmptoken ("colors"))
239 // verts
240 p.matchToken ("{");
241 p.matchToken ("count");
242 p.getToken ();
243 int cnt = atoi (p.token ());
244 mColors.resize (cnt);
245 for (int i = 0; i < cnt; i++)
247 p.matchToken ("v");
248 p.getToken ();
249 mColors[i].x = atof (p.token ());
250 p.getToken ();
251 mColors[i].y = atof (p.token ());
252 p.getToken ();
253 mColors[i].z = atof (p.token ());
255 p.matchToken ("}");
257 else if (!p.cmptoken ("ColorFaces"))
259 // ColorFaces
260 p.matchToken ("{");
261 p.matchToken ("count");
262 p.getToken ();
263 int cnt = atoi (p.token ());
264 mColorFaces.resize (cnt);
265 for (int i = 0; i < cnt; i++)
267 p.matchToken ("f");
268 p.getToken ();
269 mColorFaces[i].v[0] = atoi (p.token ());
270 p.getToken ();
271 mColorFaces[i].v[1] = atoi (p.token ());
272 p.getToken ();
273 mColorFaces[i].v[2] = atoi (p.token ());
275 p.matchToken ("}");
277 else if (!p.cmptoken ("normals"))
279 // normals
280 p.matchToken ("{");
281 p.matchToken ("count");
282 p.getToken ();
283 int cnt = atoi (p.token ());
284 mNormals.resize (cnt);
285 for (int i = 0; i < cnt; i++)
287 p.matchToken ("v");
288 p.getToken ();
289 mNormals[i].x = atof (p.token ());
290 p.getToken ();
291 mNormals[i].y = atof (p.token ());
292 p.getToken ();
293 mNormals[i].z = atof (p.token ());
295 p.matchToken ("}");
297 else if (!p.cmptoken ("normalFaces"))
299 // normalFaces
300 p.matchToken ("{");
301 p.matchToken ("count");
302 p.getToken ();
303 int cnt = atoi (p.token ());
304 mNormalFaces.resize (cnt);
305 for (int i = 0; i < cnt; i++)
307 p.matchToken ("f");
308 p.getToken ();
309 mNormalFaces[i].v[0] = atoi (p.token ());
310 p.getToken ();
311 mNormalFaces[i].v[1] = atoi (p.token ());
312 p.getToken ();
313 mNormalFaces[i].v[2] = atoi (p.token ());
315 p.matchToken ("}");
317 else if (!p.cmptoken ("uvVerts"))
319 // uvVerts
320 p.matchToken ("{");
321 p.matchToken ("count");
322 p.getToken ();
323 int cnt = atoi (p.token ());
324 mTexCoords.resize (cnt);
325 for (int i = 0; i < cnt; i++)
327 p.matchToken ("v");
328 p.getToken ();
329 mTexCoords[i].x = atof (p.token ());
330 p.getToken ();
331 mTexCoords[i].y = atof (p.token ());
333 p.matchToken ("}");
335 else if (!p.cmptoken ("uvFaces"))
337 // uvFaces
338 p.matchToken ("{");
339 p.matchToken ("count");
340 p.getToken ();
341 int cnt = atoi (p.token ());
342 mTexCoordFaces.resize (cnt);
343 for (int i = 0; i < cnt; i++)
345 p.matchToken ("f");
346 p.getToken ();
347 mTexCoordFaces[i].v[0] = atoi (p.token ());
348 p.getToken ();
349 mTexCoordFaces[i].v[1] = atoi (p.token ());
350 p.getToken ();
351 mTexCoordFaces[i].v[2] = atoi (p.token ());
353 p.matchToken ("}");
355 else if (!p.cmptoken ("uvLightmap"))
357 // uvVerts
358 p.matchToken ("{");
359 p.matchToken ("count");
360 p.getToken ();
361 int cnt = atoi (p.token ());
362 mLightmapTexCoords.resize (cnt);
363 for (int i = 0; i < cnt; i++)
365 p.matchToken ("v");
366 p.getToken ();
367 mLightmapTexCoords[i].x = atof (p.token ());
368 p.getToken ();
369 mLightmapTexCoords[i].y = atof (p.token ());
371 p.matchToken ("}");
373 else if (!p.cmptoken ("uvLightmapFaces"))
375 // uvFaces
376 p.matchToken ("{");
377 p.matchToken ("count");
378 p.getToken ();
379 int cnt = atoi (p.token ());
380 mLightmapTexCoordFaces.resize (cnt);
381 for (int i = 0; i < cnt; i++)
383 p.matchToken ("f");
384 p.getToken ();
385 mLightmapTexCoordFaces[i].v[0] = atoi (p.token ());
386 p.getToken ();
387 mLightmapTexCoordFaces[i].v[1] = atoi (p.token ());
388 p.getToken ();
389 mLightmapTexCoordFaces[i].v[2] = atoi (p.token ());
391 p.matchToken ("}");
393 else if (!p.cmptoken ("mtlIndex"))
395 // uvFaces
396 p.matchToken ("{");
397 p.matchToken ("count");
398 p.getToken ();
399 int cnt = atoi (p.token ());
400 mMtlIndex.resize (cnt);
401 for (int i = 0; i < cnt; i++)
403 p.matchToken ("f");
404 p.getToken ();
405 mMtlIndex[i] = atoi (p.token ());
407 p.matchToken ("}");
409 else if (!p.cmptoken ("vertexInfluences"))
411 p.matchToken ("{");
412 p.matchToken ("count");
413 p.getToken ();
414 int cnt = atoi (p.token ());
415 mVertexInfluences.resize (cnt);
416 for (int i = 0; i < cnt; i++)
418 p.matchToken ("w");
419 p.getToken ();
420 int vtx = atoi (p.token ());
421 p.getToken ();
422 int wcnt = atoi (p.token ());
423 mVertexInfluences[i].resize (wcnt);
424 for (int k = 0; k < wcnt; k++)
426 p.getToken ();
427 mVertexInfluences[vtx][wcnt].bone = atoi (p.token ());
428 p.getToken ();
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 ());
453 #if 0
454 if (!mTangentSpace.empty ())
456 assert (mTangentSpace.size () == mFaces.size ());
458 #endif
461 void expTriObject::transformIntoWorldSpace (void)
463 size_t i;
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)
475 #if 0
476 if (mtlIndex ().empty ())
477 return;
478 // set transforms
479 gpD3DDev->SetTransform (D3DTS_WORLD, (D3DMATRIX*)&getWorldMatrix ());
481 // render mesh
482 int prevMtl = -1;
483 int firstFace = 0;
484 int nFaces = 0;
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)
490 if (nFaces)
492 if (prevMtl != -1)
494 flush (scene, prevMtl, firstFace, nFaces);
496 nFaces = 0;
497 firstFace = face_i;
501 nFaces++;
502 prevMtl = mtlIndex ()[face_i];
504 if (nFaces)
505 flush (scene, prevMtl, firstFace, nFaces);
506 #endif
507 expObject::render (scene);
510 void expTriObject::flush (expScene *scene, int mtl, int firstFace, int nFaces)
512 #if 0
513 // flush & restart vb
514 dynamicVB< fFVertex > *vb = engine::get ()->dynamicVB ();
515 uint start;
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));
522 data++;
523 *data = fFVertex (verts ()[faces ()[firstFace+f].v[1]], 0, vector2 (0, 0));
524 data++;
525 *data = fFVertex (verts ()[faces ()[firstFace+f].v[2]], 0, vector2 (0, 0));
526 data++;
528 else
530 *data = fFVertex (verts ()[faces ()[firstFace+f].v[0]], 0, texCoords ()[texCoordFaces ()[firstFace+f].v[0]]);
531 data++;
532 *data = fFVertex (verts ()[faces ()[firstFace+f].v[1]], 0, texCoords ()[texCoordFaces ()[firstFace+f].v[1]]);
533 data++;
534 *data = fFVertex (verts ()[faces ()[firstFace+f].v[2]], 0, texCoords ()[texCoordFaces ()[firstFace+f].v[2]]);
535 data++;
538 vb->unlock ();
540 // setup mtl
541 scene->mtlList ()[mtl]->setupEffectInputs ();
542 effect *e = scene->mtlList ()[mtl]->getEffect ();
543 e->setBestTechnique ();
544 e->begin ();
545 e->pass (0);
546 gpD3DDev->DrawPrimitive (D3DPT_TRIANGLELIST, start, nFaces);
547 e->end ();
548 #endif
551 //----------------------
552 // expModel
553 //----------------------
555 expModel::expModel (expModel *parent)
556 : sceneObject (parent)
558 mbLightmaps = false;
559 mbTangents = false;
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 ());
579 // fill vb
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;
587 if (mbLightmaps)
588 mLightmapName = oo->name () + cStr ("_lm.tga"); // max uses tga by default
590 int mtl_i;
591 int face_i;
592 int vertex_i;
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]);
613 // find average
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);
621 int i, j;
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];
628 cnt[j]++;
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)
645 // smooth
646 tangents[j] += faceTangents[k/3*2+0];
647 binormals[j] += faceTangents[k/3*2+1];
648 cnt[j]++;
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;
667 delete[] cnt;
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)
680 // add verts
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];
690 face outface;
691 int remap_face[] = {0,2,1};
693 for (vertex_i = 0; vertex_i < 3; vertex_i++)
695 drawVertex_t v;
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);
703 if (ltf)
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 ();
714 else
716 outface.v[remap_face[vertex_i]] = (int)verts.size ();
717 verts.push_back (v);
720 faces.push_back (outface);
723 if (!verts.empty ())
725 fprintf (stderr, "adding %d verts, %d faces...\n", verts.size (), faces.size ());
726 // add subset
727 subset s;
728 s.firstVertex = (int)mVerts.size ();
729 s.firstFace = (int)mFaces.size ();
730 s.numVerts = (int)verts.size ();
731 s.numFaces = (int)faces.size ();
732 s.mtl = mtl_i;
733 mSubSets.push_back (s);
734 // add verts
735 for (vertex_i = 0; vertex_i < (int)verts.size (); vertex_i++)
736 mVerts.push_back (verts[vertex_i]);
737 // add faces
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);
745 if (mtl_i == -1)
746 break;
748 delete[] tangents;
749 delete[] binormals;
752 // matrix
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]);
762 addChild (m);
766 void expModel::save (const char *fname, const expScenePtr &s) const
768 FILE *fp = fopen (fname, "w+b");
769 if (!fp)
771 fprintf (stderr, "failed to open file '%s' for writing\n", fname);
772 return;
775 // write magic
776 // 0100 -- original
777 // 0101 -- added lightmaps support
778 // 0102 -- animation is now separate file
780 char mgc[] = "FEMDL0102";
781 fwrite (mgc, strlen (mgc), 1, fp);
783 ulong sp;
784 int i;
786 // save materials
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");
800 saveGeometry (fp);
802 fclose (fp);
805 void expModel::saveGeometry (FILE *fp) const
807 ulong sp;
809 fprintf (stderr, "writing name: %s\n", name ());
810 char nsz = strlen (name ());
811 fwrite (&nsz, sizeof (char), 1, fp);
812 if (nsz)
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);
830 if (mbLightmaps)
832 // write lightmap texture name
833 uchar sz = mLightmapName.size ();
834 fwrite (&sz, 1, 1, fp);
835 if (sz)
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);
849 #if 0
850 // animation
851 uchar b = mpAnimationController->numFrames () != 0;
852 fwrite (&b, sizeof (uchar), 1, fp);
853 if (b)
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);
865 #endif
866 // write children
867 sp = 0;
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 //----------------------
880 // expRefObject
881 //----------------------
882 expRefObject::expRefObject (expObject *parent)
883 : expObject (parent)
885 mClassID = REF_OBJECT_CLASS_ID;
886 mpScene = NULL;
889 void expRefObject::load (charParser &p, const char *fname)
894 void expRefObject::render (expScene *scene)
896 if (mpScene)
897 mpScene->render ();
898 expObject::render (scene);
901 //----------------------
902 // expEntityObject
903 //----------------------
904 expEntityObject::expEntityObject (expObject *parent)
905 : expObject (parent)
907 mClassID = ENTITY_OBJECT_CLASS_ID;
910 void expEntityObject::load (charParser &p, const char *filename)
912 p.getToken ();
913 mName = p.token ();
914 p.matchToken ("{");
916 cStr fname = filename;
918 fname += "_";
919 fname += mName;
921 for (;;)
923 p.getToken ();
924 if (p.token () == "}")
925 break;
926 else if (baseLoad (p, fname))
929 else if (!p.cmptoken ("prop"))
931 p.getToken ();
932 cStr key = p.token ();
933 p.getToken ();
934 mProps[key] = p.token ();
936 else
937 p.generalSyntaxError ();
941 void expEntityObject::render (expScene *scene)
943 expObject::render (scene);
946 //----------------------
947 // expDummyObject
948 //----------------------
950 expDummyObject::expDummyObject (expObject *parent)
951 : expObject (parent)
953 mClassID = DUMMY_OBJECT_CLASS_ID;
956 void expDummyObject::load (charParser &p, const char *filename)
958 p.getToken ();
959 mName = p.token ();
960 p.matchToken ("{");
962 cStr fname = filename;
963 fname += _T ("_");
964 fname += mName;
966 for (;;)
968 p.getToken ();
969 if (p.token () == "}")
970 break;
971 else if (baseLoad (p, fname))
974 else
975 p.generalSyntaxError ();
979 void expDummyObject::render (expScene *scene)
981 expObject::render (scene);
984 //----------------------
985 // expObject
986 //----------------------
987 expObject::expObject (expObject *parent)
988 : mMatrix (true)
990 mpParent = parent;
993 bool expObject::baseLoad (charParser &p, const char *fname)
995 if (!p.cmptoken ("nodeTransform"))
997 p.matchToken ("{");
998 // matrix
999 mMatrix.identity ();
1000 for (int i = 0; i < 4; i++)
1002 for (int k = 0; k < 3; k++)
1004 p.getToken ();
1005 mMatrix.m[i][k] = atof (p.token ());
1008 p.matchToken ("}");
1010 if (mpParent)
1011 mWorldMatrix = mMatrix * mpParent->getWorldMatrix ();
1012 else
1013 mWorldMatrix = mMatrix;
1015 else if (!p.cmptoken ("dummy"))
1017 expDummyObject *o = new expDummyObject (this);
1018 o->load (p, fname);
1019 mChildren.push_back (o);
1021 else if (!p.cmptoken ("triobject"))
1023 expTriObject *o = new expTriObject (this);
1024 o->load (p, fname);
1025 mChildren.push_back (o);
1027 else if (!p.cmptoken ("entity"))
1029 expEntityObject *o = new expEntityObject (this);
1030 o->load (p, fname);
1031 mChildren.push_back (o);
1033 else
1034 return false;
1036 return true;
1039 void expObject::setMatrix (const matrix4 &m)
1041 mMatrix = 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)
1055 mWorldMatrix = 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)
1089 assert (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++)
1100 if (*it == this)
1102 mpParent->mChildren.erase (it);
1103 mpParent = NULL;
1104 break;
1109 if (NULL != parent)
1111 mpParent = parent;
1112 mpParent->mChildren.push_back (this);