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
27 #include "f_resourcemgr.h"
28 #include "f_basetexture.h"
29 #include "f_material.h"
30 #include "f_modeldata.h"
31 #include "f_lightsource.h"
36 class mtlBlock
: public baseObject
39 std::vector
<materialPtr
> mMtlList
;
42 void add (const materialPtr
&mtl
) { mMtlList
.push_back (mtl
); }
43 int numMtls (void) const { return (int)mMtlList
.size (); }
44 materialPtr
getMtl (int i
) { return mMtlList
[i
]; }
48 f
->readUINT32 (&sp
, 1);
52 for (uint32 i
= 0; i
< sp
; i
++)
56 char *str
= new char[ln
+1];
59 materialPtr m
= g_engine
->getResourceMgr ()->createMaterial (str
);
73 memset (&mTris, 0, sizeof (mTris));*/
76 sceneObject
* model::load (const char *fname
)
88 bool noscript
= false;
89 // check if we got bmdl
90 if (strstr (fname
, ".bmdl"))
97 // no, try loading script
99 charParser
p(g_engine
->getFileSystem (), fname
);
100 // file must contain only model def, and nothing more (no name, nothing)
103 catch (parserException e
)
105 if (e
== parserException::FILE_NOT_FOUND
)
107 else if (e
!= parserException::END_OF_FILE
)
109 fprintf (stderr
, "ERROR: failed to load script for model %s,\nerrors: %s", fname
, cStr (e
).c_str ());
118 file
*f
= g_engine
->getFileSystem ()->openFile (fname
, FS_MODE_READ
);
124 model::model (charParser
&parser
, const char *fname
, model
*parent
)
129 memset (&mTris
, 0, sizeof (mTris
));
131 charParser
p(g_engine
->getFileSystem (), fname
);
132 // file must contain only model def, and nothing more (no name, nothing)
135 catch (parserException e
)
137 if (e
!= parserException::END_OF_FILE
)
138 throw genericError ("failed to load script for model %s,\nerrors: %s",
139 fname
, cStr (e
).c_str ());
143 model::model (const char *name
, model
*parent
, const matrix4
&mtx
, const std::vector
<drawVertex_t
> &verts
, std::vector
<ushort
> &inds
, const std::vector
<modelSubset_t
> &subs
, const std::vector
<materialPtr
> &mtls
)
149 memset (&mTris
, 0, sizeof (mTris
));
150 mRelativeMatrix
= mtx
;
151 mWorldMatrix
= mpParentObject
? mRelativeMatrix
* mpParentObject
->getWorldMatrix() : mRelativeMatrix
;
155 size_t nsubs
= subs
.size ();
156 for (size_t s
= 0; s
< nsubs
; s
++)
158 mSurfaces
[s
].tris
= &mTris
;
162 mTris
.numVerts
= verts
.size ();
163 mTris
.verts
= new drawVertex_t
[verts
.size ()];
164 memcpy (mTris
.verts
, &verts
.front (), verts
.size () * sizeof (drawVertex_t
));
165 mTris
.numIndexes
= inds
.size ();
166 mTris
.indexes
= new ushort
[inds
.size ()];
167 memcpy (mTris
.indexes
, &inds
.front (), inds
.size () * sizeof (ushort
));
174 void model::init (void)
176 #if 0 // FIXME: all this should be in mesh data!!
178 mTris
.facePlanes
= new plane
[mTris
.numIndexes
/3];
179 for (int i
= 0; i
< mTris
.numIndexes
/3; i
++)
181 mTris
.facePlanes
[i
].fromPoints (
182 mTris
.verts
[mTris
.indexes
[i
*3+0]].pos
,
183 mTris
.verts
[mTris
.indexes
[i
*3+1]].pos
,
184 mTris
.verts
[mTris
.indexes
[i
*3+2]].pos
);
188 // FIXME: move to fgp
189 mTris
.silIndexes
= new ushort
[mTris
.numIndexes
];
190 for (int i
= 0; i
< mTris
.numIndexes
; i
++)
192 vector3
*v
= &mTris
.verts
[mTris
.indexes
[i
]].pos
;
194 for (j
= 0; j
< mTris
.numVerts
; j
++)
196 if (*v
== mTris
.verts
[j
].pos
)
198 mTris
.silIndexes
[i
] = j
;
202 assert (j
!= mTris
.numVerts
);
206 // vertex indexes are from silIndexes
208 mTris
.numSilEdges
= 0;
209 mTris
.silEdges
= new silEdge_t
[mTris
.numIndexes
/3 * 2];
210 for (int i
= 0; i
< mTris
.numIndexes
/3; i
++)
212 for (int k
= 0; k
< 3; k
++)
214 int v1
= mTris
.silIndexes
[i
* 3 + k
];
215 int v2
= mTris
.silIndexes
[i
* 3 + ((k
+1)%3)];
217 for (int j
= 0; j
< mTris
.numIndexes
/3; j
++)
221 for (int n
= 0; n
< 3; n
++)
223 int vv1
= mTris
.silIndexes
[j
* 3 + n
];
224 int vv2
= mTris
.silIndexes
[j
* 3 + ((n
+1)%3)];
225 if (v1
== vv2
&& v2
== vv1
)
229 for (m
= 0; m
< mTris
.numSilEdges
; m
++)
231 if ((mTris
.silEdges
[m
].v1
== v1
&& mTris
.silEdges
[m
].v2
== v2
)
232 || (mTris
.silEdges
[m
].v1
== v2
&& mTris
.silEdges
[m
].v2
== v1
))
237 if (m
== mTris
.numSilEdges
)
240 mTris
.silEdges
[mTris
.numSilEdges
].f1
= i
;
241 mTris
.silEdges
[mTris
.numSilEdges
].f2
= j
;
242 mTris
.silEdges
[mTris
.numSilEdges
].v1
= v1
;
243 mTris
.silEdges
[mTris
.numSilEdges
].v2
= v2
;
253 // each edge forms a quad, which is 2 triangles, which is 6 indexes
254 // in case we're using vertexshader - we will index normal vertex array, and pass
255 // extrusion as one of vertex attributes
256 // in case we're not using vertex shader - we'll make dynamic vertex array,
257 // which will contain entire (extruded) shadow volume
258 mTris
.shadowVolumeIndexes
= new ushort
[mTris
.numIndexes
/3 * 2 * 6 + mTris
.numIndexes
];
259 mTris
.shadowVerts
= new shadowVertex_t
[mTris
.numVerts
* 2];
261 // verts are going in interleaved order, i.e. v0: normal, v1: extruded (to minimize cache misses)
262 for (int i
= 0; i
< mTris
.numVerts
; i
++)
264 mTris
.shadowVerts
[i
].xyzw
= vector4 (mTris
.verts
[i
].pos
.x
, mTris
.verts
[i
].pos
.y
, mTris
.verts
[i
].pos
.z
, 1);
271 // mpData = new modelData (this);
273 // fill meshData from model
281 delete[] mTris
.verts
;
283 delete[] mTris
.indexes
;
284 if (mTris
.silIndexes
)
285 delete[] mTris
.silIndexes
;
286 if (mTris
.facePlanes
)
287 delete[] mTris
.facePlanes
;
289 delete[] mTris
.silEdges
;
290 // if (mTris.mtlIndexes)
291 // delete[] mTris.mtlIndexes;
293 delete[] mTris
.dupVerts
;
294 if (mTris
.shadowVolumeIndexes
)
295 delete[] mTris
.shadowVolumeIndexes
;
296 if (mTris
.shadowVerts
)
297 delete[] mTris
.shadowVerts
;
303 glDeleteBuffersARB (1, &mpMeshData
->vbo
);
308 glDeleteBuffersARB (1, &mpMeshData
->ibo
);
311 if (mpMeshData
->verts
)
313 delete[] mpMeshData
->verts
;
314 mpMeshData
->verts
= NULL
;
316 if (mpMeshData
->inds
)
318 delete[] mpMeshData
->inds
;
319 mpMeshData
->inds
= NULL
;
324 void model::loadMesh (file
*f
, int majorver
, int minorver
, std::vector
<materialPtr
> &mtls
, int numSubsets
, renderable
*rend
)
326 drawSurf_t
*ds
= NULL
;
329 mMeshDataCount
= numSubsets
;
330 mpMeshData
= new meshData_t
[mMeshDataCount
];
331 ds
= new drawSurf_t
[mMeshDataCount
];
332 memset (mpMeshData
, 0, sizeof (meshData_t
) * mMeshDataCount
);
333 memset (ds
, 0, sizeof (drawSurf_t
) * mMeshDataCount
);
334 rend
->setDrawSurfs (ds
, mMeshDataCount
);
335 for (int i
= 0; i
< mMeshDataCount
; i
++)
337 // meshData/geomSource stuff (shared)
338 f
->readUINT32 (&mpMeshData
[i
].firstVertex
, 1);
339 f
->readUINT32 (&mpMeshData
[i
].firstIndex
, 1);
340 mpMeshData
[i
].firstIndex
*= 3;
341 f
->readUINT32 (&mpMeshData
[i
].numVerts
, 1);
342 f
->readUINT32 (&mpMeshData
[i
].numInds
, 1);
343 mpMeshData
[i
].numInds
*= 3;
344 // material is going to drawSurf (not shared)
346 f
->readUINT32 (&mtl
, 1);
347 ds
[i
].mtl
= mtls
[mtl
];
348 // ds[i].obj = node; // no need to set this at load time! it will be set during getNewInstance
349 ds
[i
].mesh
= &mpMeshData
[i
];
350 // mSurfaces[i].tris = &mTris;
357 f
->read (&tangents
, sizeof (uchar
));
358 //fprintf (stderr, "tangents: %s\n", tangents ? "yes" : "no");
363 f
->read (&lightmaps
, sizeof (uchar
));
365 //fprintf (stderr, "lightmaps: %s\n", lightmaps ? "yes" : "no");
369 f
->read (&sz
, sizeof (uchar
));
374 f
->read ((char *)&s
[0], sz
);
375 // read lightmap texture
376 baseTexturePtr t
= g_engine
->getResourceMgr ()->createTexture ("lightmaps/" + s
);
377 for (size_t i
= 0; i
< mMeshDataCount
; i
++)
384 // vertex buffer (meshData stuff)
385 // it is shared for entire model (all subsets) so don't delete VBO for each subset please!
387 f
->readUINT32 (&sp
, 1);
388 //fprintf (stderr, "%d verts\n", sp);
393 vertSize
= sizeof (vector3
) * 2 + sizeof (vector2
); // pos + norm + uv
397 vertSize
+= sizeof (vector2
);
399 vertSize
+= sizeof (vector3
) * 2;
400 int size
= (int)(vertSize
* numVerts
);
401 // init vertex/index buffers
408 vb
= new uchar
[size
];
411 // mTris.verts = new drawVertex_t[mTris.numVerts];
412 for (int i
= 0; i
< numVerts
; i
++)
414 f
->readFloat ((float*)ptr
, 3);
415 ptr
+= sizeof (vector3
);
416 f
->readFloat ((float*)ptr
, 3);
417 ptr
+= sizeof (vector3
);
418 f
->readFloat ((float*)ptr
, 2);
419 ptr
+= sizeof (vector2
);
420 if (colors
) // FIXME: bmdl never contain colors now
428 f
->readFloat ((float*)&lm
, 2);
432 f
->readFloat ((float*)ptr
, 2);
433 ptr
+= sizeof (vector2
);
438 f
->readFloat ((float*)&tn
, 6);
442 f
->readFloat ((float*)ptr
, 6);
443 ptr
+= sizeof (vector3
) * 2;
448 f
->read (&clr
, sizeof (clr
)); // color?
451 if (GLEW_ARB_vertex_buffer_object
)
453 glGenBuffersARB (1, &vbo
);
454 glBindBufferARB (GL_ARRAY_BUFFER_ARB
, vbo
);
455 glBufferDataARB (GL_ARRAY_BUFFER_ARB
, size
, NULL
, GL_STATIC_DRAW_ARB
);
456 uchar
*p
= (uchar
*)glMapBufferARB (GL_ARRAY_BUFFER_ARB
, GL_WRITE_ONLY_ARB
);
457 memcpy (p
, vb
, size
);
458 glUnmapBufferARB (GL_ARRAY_BUFFER_ARB
);
461 // set vb to meshdata
462 for (int j
= 0; j
< mMeshDataCount
; j
++)
464 mpMeshData
[j
].verts
= vb
;
465 mpMeshData
[j
].vbo
= vbo
;
466 mpMeshData
[j
].primType
= GL_TRIANGLES
;
467 mpMeshData
[j
].vertexSize
= vertSize
;
468 mpMeshData
[j
].have_colors
= colors
? 1 : 0;
469 mpMeshData
[j
].have_lightmaps
= lightmaps
? 1 : 0;
470 mpMeshData
[j
].have_tangents
= tangents
? 1 : 0;
475 f
->readUINT32 (&sp
, 1);
479 int numIndexes
= sp
* 3;
485 ib
= new uchar
[sizeof (ushort
) * numIndexes
];
486 f
->readUINT16 ((uint16
*)ib
, numIndexes
);
488 if (GLEW_ARB_vertex_buffer_object
)
490 glGenBuffersARB (1, &ibo
);
491 glBindBufferARB (GL_ELEMENT_ARRAY_BUFFER_ARB
, ibo
);
492 glBufferDataARB (GL_ELEMENT_ARRAY_BUFFER_ARB
, numIndexes
* sizeof (ushort
), ib
, GL_STATIC_DRAW_ARB
);
494 // set ib to meshdata
495 for (int j
= 0; j
< mMeshDataCount
; j
++)
497 mpMeshData
[j
].inds
= ib
;
498 mpMeshData
[j
].ibo
= ibo
;
504 // skip old version animation flag
506 f
->read (&b
, sizeof (b
));
510 sceneObject
* model::load (file
*f
, mtlBlock
*mtls
, sceneObject
*parent
)
512 // FIXME: pass as formal parameter?
513 static int minorver
= 0;
514 static int majorver
= 1;
515 sceneObject
*node
= new sceneObject (parent
);
516 renderable
*rend
= new renderable (this);
517 node
->attachRenderable (rend
);
524 if (!strcmp (mgc
, "FEMDL0101"))
529 else if (!strcmp (mgc
, "FEMDL0102"))
535 sys_error ( "Invalid model file signature (%s).\n", f
->name());
538 mtls
= new mtlBlock ();
545 f
->read (&nsz
, sizeof (char));
554 //fprintf (stderr, "got object %s\n", name ());
561 f
->readMatrix4 (&mtx
, 1);
562 matrix4 worldMtx
= parent
? mtx
* parent
->getWorldMatrix() : mtx
;
563 node
->setRelativeMatrix (mtx
);
564 node
->setWorldMatrix (worldMtx
);
567 f
->readUINT32 (&sp
, 1);
568 //fprintf (stderr, "got %d subsets\n", sp);
569 drawSurf_t
*ds
= NULL
;
572 // mSurfaces.resize( sp );
574 mpMeshData
= new meshData_t
[sp
];
575 ds
= new drawSurf_t
[sp
];
576 memset (mpMeshData
, 0, sizeof (meshData_t
) * sp
);
577 memset (ds
, 0, sizeof (drawSurf_t
) * sp
);
578 rend
->setDrawSurfs (ds
, sp
);
579 for (size_t i
= 0; i
< sp
; i
++)
581 // meshData/geomSource stuff (shared)
582 f
->readUINT32 (&mpMeshData
[i
].firstVertex
, 1);
583 f
->readUINT32 (&mpMeshData
[i
].firstIndex
, 1);
584 mpMeshData
[i
].firstIndex
*= 3;
585 f
->readUINT32 (&mpMeshData
[i
].numVerts
, 1);
586 f
->readUINT32 (&mpMeshData
[i
].numInds
, 1);
587 mpMeshData
[i
].numInds
*= 3;
588 // material is going to drawSurf (not shared)
590 f
->readUINT32 (&mtl
, 1);
591 ds
[i
].mtl
= mtls
->getMtl (mtl
);
593 ds
[i
].mesh
= &mpMeshData
[i
];
594 // mSurfaces[i].tris = &mTris;
600 f
->read(&tangents
, sizeof(uchar
));
601 //fprintf (stderr, "tangents: %s\n", tangents ? "yes" : "no");
606 f
->read (&lightmaps
, sizeof (uchar
));
608 //fprintf (stderr, "lightmaps: %s\n", lightmaps ? "yes" : "no");
612 f
->read (&sz
, sizeof (uchar
));
615 char nm
[200] = "lightmaps/";
617 f
->read (nm
+ l
, sz
);
619 // read lightmap texture
620 baseTexturePtr t
= g_engine
->getResourceMgr ()->createTexture (nm
);
621 for (size_t i
= 0; i
< mMeshDataCount
; i
++)
628 // vertex buffer (meshData stuff)
629 // it is shared for entire model (all subsets) so don't delete VBO for each subset please!
631 f
->readUINT32 (&sp
, 1);
632 //fprintf (stderr, "%d verts\n", sp);
637 vertSize
= sizeof (vector3
) * 2 + sizeof (vector2
); // pos + norm + uv
641 vertSize
+= sizeof (vector2
);
643 vertSize
+= sizeof (vector3
) * 2;
644 int size
= (int)(vertSize
* numVerts
);
645 // init vertex/index buffers
652 vb
= new uchar
[size
];
655 // mTris.verts = new drawVertex_t[mTris.numVerts];
656 for (int i
= 0; i
< numVerts
; i
++)
658 f
->readFloat ((float*)ptr
, 3);
659 ptr
+= sizeof (vector3
);
660 f
->readFloat ((float*)ptr
, 3);
661 ptr
+= sizeof (vector3
);
662 f
->readFloat ((float*)ptr
, 2);
663 ptr
+= sizeof (vector2
);
664 if (colors
) // FIXME: bmdl never contain colors now
671 // skipt lightmap stub
672 // FIXME: do not include this when not needed
674 f
->readFloat ((float*)&lm
, 2);
678 f
->readFloat ((float*)ptr
, 2);
679 ptr
+= sizeof (vector2
);
684 f
->readFloat ((float*)&tn
, 3);
688 f
->readFloat ((float*)ptr
, 6);
689 ptr
+= sizeof (vector3
) * 2;
693 // stub-skip colors (where is this came from?)
695 f
->read (&clr
, sizeof (clr
)); // color?
698 if (GLEW_ARB_vertex_buffer_object
)
700 glGenBuffersARB (1, &vbo
);
701 glBindBufferARB (GL_ARRAY_BUFFER_ARB
, vbo
);
702 glBufferDataARB (GL_ARRAY_BUFFER_ARB
, size
, NULL
, GL_STATIC_DRAW_ARB
);
703 uchar
*p
= (uchar
*)glMapBufferARB (GL_ARRAY_BUFFER_ARB
, GL_WRITE_ONLY_ARB
);
704 memcpy (p
, vb
, size
);
705 glUnmapBufferARB (GL_ARRAY_BUFFER_ARB
);
708 // set vb to meshdata
709 for (int j
= 0; j
< mMeshDataCount
; j
++)
711 mpMeshData
[j
].verts
= vb
;
712 mpMeshData
[j
].vbo
= vbo
;
713 mpMeshData
[j
].primType
= GL_TRIANGLES
;
714 mpMeshData
[j
].vertexSize
= vertSize
;
715 mpMeshData
[j
].have_colors
= colors
? 1 : 0;
716 mpMeshData
[j
].have_lightmaps
= lightmaps
? 1 : 0;
717 mpMeshData
[j
].have_tangents
= tangents
? 1 : 0;
722 f
->readUINT32 (&sp
, 1);
726 int numIndexes
= sp
* 3;
732 ib
= new uchar
[sizeof (ushort
) * numIndexes
];
733 f
->readUINT16 ((uint16
*)ib
, numIndexes
);
735 if (GLEW_ARB_vertex_buffer_object
)
737 glGenBuffersARB (1, &ibo
);
738 glBindBufferARB (GL_ELEMENT_ARRAY_BUFFER_ARB
, ibo
);
739 glBufferDataARB (GL_ELEMENT_ARRAY_BUFFER_ARB
, numIndexes
* sizeof (ushort
), ib
, GL_STATIC_DRAW_ARB
);
741 // set ib to meshdata
742 for (int j
= 0; j
< mMeshDataCount
; j
++)
744 mpMeshData
[j
].inds
= ib
;
745 mpMeshData
[j
].ibo
= ibo
;
751 // skip old version animation flag
753 f
->read (&b
, sizeof (b
));
757 f
->readUINT32 (&sp
, 1);
759 // mChildren.resize( sp );
760 for (uint32 i
= 0; i
< nChildren
; i
++)
762 model
* m
= new model
;
763 sceneObject
*c
= m
->load (f
, mtls
, node
);
774 /* typedef smartPtr <mtlBlock> mtlBlockPtr;
776 mtlBlockPtr mpMtlBlock;*/
778 /* // renderable implementation
779 int model::numSubsets (void) const
781 return (int)mSurfaces.size ();
784 materialPtr model::getMtl (int subset) const
786 return mpMtlBlock ? mSurfaces[subset].mtl : NULL;
789 void model::prepare (int subset
) const
792 g_engine->getEffectParms()->setMatrix( effectParm_WorldMatrix, mWorldMatrix );
793 if (mSurfaces[subset].lightmap)
794 g_engine->getEffectParms ()->setTexture (effectParm_LightmapTexture, mSurfaces[subset].lightmap);*/
797 void model::render (int subset
, int pass
) const
800 mpData
->drawSubset (subset
, pass
);
803 /* void model::renderShadowVolume (bool withChildren) const
805 if (mpData) // FIXME: model can contain NULL mpData, but this is the case for dummy object, which can be handled in more efficient way
806 mpData->renderShadowVolume ();
807 sceneObject::renderShadowVolume (withChildren);
811 void model::buildShadowVolume (const lightSource
&src
)
814 lightSource::type t
= src
.getType ();
816 // lightpos is transformed just like everything other, but we want it in model space
817 matrix4 light2model
= src
.getWorldMatrix () * getWorldMatrix ().inverse ();
818 vector3 pos
= src
.getPosition () * light2model
;
820 vector3 L
= src
.getPosition () * light2model
;
821 if (src
.getType () == lightSource::direct
)
823 vector3 dir
= light2model
.transform (src
.getDirection ());
828 for (int i
= 0; i
< mTris
.numVerts
; i
++)
830 if (src
.getType () != lightSource::direct
)
832 dir
= (vector3
&)mTris
.shadowVerts
[i
] - src
.getPosition ();
836 // V.w*L + float4 (V.xyz - L.xyz, 0)
837 mTris
.shadowVerts
[i
+ mTris
.numVerts
].xyzw
.x
= mTris
.shadowVerts
[i
].xyzw
.x
- L
.x
;
838 mTris
.shadowVerts
[i
+ mTris
.numVerts
].xyzw
.y
= mTris
.shadowVerts
[i
].xyzw
.y
- L
.y
;
839 mTris
.shadowVerts
[i
+ mTris
.numVerts
].xyzw
.z
= mTris
.shadowVerts
[i
].xyzw
.z
- L
.z
;
840 mTris
.shadowVerts
[i
+ mTris
.numVerts
].xyzw
.w
= 0;
843 // write indexes, build shadow volume
844 mTris
.numShadowVolumeIndexes
= 0;
845 for (int i
= 0; i
< mTris
.numSilEdges
; i
++)
847 // check if only one of two faces forming the edge is visible from light
848 const vector3
&n1
= mTris
.facePlanes
[mTris
.silEdges
[i
].f1
].normal ();
849 const vector3
&n2
= mTris
.facePlanes
[mTris
.silEdges
[i
].f2
].normal ();
850 float d1
= n1
.dot (dir
);
851 float d2
= n2
.dot (dir
);
852 #define s_idx (mTris.shadowVolumeIndexes)
853 #define n_idx (mTris.numShadowVolumeIndexes)
854 // add edge verts to list of shadow volume indexes, forming a quad
855 if (d1
< 0 && d2
> 0) // f1 is visible, v2-v1 form CCW order
857 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v2
;
858 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v1
;
859 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v1
+ mTris
.numVerts
;
860 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v2
;
861 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v1
+ mTris
.numVerts
;
862 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v2
+ mTris
.numVerts
;
864 else if (d2
< 0 && d1
> 0) // f2 is visible, v1-v2 form CCW order
866 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v1
;
867 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v2
;
868 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v1
+ mTris
.numVerts
;
869 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v2
;
870 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v2
+ mTris
.numVerts
;
871 s_idx
[n_idx
++] = mTris
.silEdges
[i
].v1
+ mTris
.numVerts
;
875 // front/back caps are not added to shadow vertex list, because they are taken from normal vertex array
876 // but we write caps indexes
878 for (int i
= 0; i
< mTris
.numIndexes
/3; i
++)
880 float d
= mTris
.facePlanes
[i
].normal ().dot (dir
);
881 if (d
< 0) // visible
884 s_idx
[n_idx
++] = mTris
.silIndexes
[i
*3+0];
885 s_idx
[n_idx
++] = mTris
.silIndexes
[i
*3+2];
886 s_idx
[n_idx
++] = mTris
.silIndexes
[i
*3+1];
890 // back cap (from extruded list)
891 s_idx
[n_idx
++] = mTris
.silIndexes
[i
*3+0] + mTris
.numVerts
;
892 s_idx
[n_idx
++] = mTris
.silIndexes
[i
*3+2] + mTris
.numVerts
;
893 s_idx
[n_idx
++] = mTris
.silIndexes
[i
*3+1] + mTris
.numVerts
;
898 for (size_t i
= 0; i
< mChildren
.size (); i
++)
900 if (mChildren
[i
]->isTypeOf (TypeId
))
902 mChildren
[i
].dynamicCast
<model
>()->buildShadowVolume (src
);
911 const modelTriangles_t
& model::getTriangles (void) const