Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / ps_mesh.cpp
blob34f964f7d1a884161eecdae170968b2e9d69e135
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2011 Robert TIMM (rti) <mail@rtti.de>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std3d.h"
22 #include "nel/3d/ps_mesh.h"
23 #include "nel/3d/ps_macro.h"
24 #include "nel/3d/shape.h"
25 #include "nel/3d/mesh.h"
26 #include "nel/3d/transform_shape.h"
27 #include "nel/3d/shape_bank.h"
28 #include "nel/3d/texture_mem.h"
29 #include "nel/3d/scene.h"
30 #include "nel/3d/ps_located.h"
31 #include "nel/3d/particle_system.h"
32 #include "nel/3d/particle_system_shape.h"
33 #include "nel/3d/particle_system_model.h"
34 #include "nel/3d/ps_iterator.h"
35 #include "nel/3d/debug_vb.h"
37 #include "nel/misc/stream.h"
38 #include "nel/misc/path.h"
40 #ifdef DEBUG_NEW
41 #define new DEBUG_NEW
42 #endif
44 namespace NL3D
47 ////////////////////
48 // static members //
49 ////////////////////
54 CPSConstraintMesh::CMeshDisplayShare CPSConstraintMesh::_MeshDisplayShare(16);
55 CVertexBuffer CPSConstraintMesh::_PreRotatedMeshVB; // mesh has no normals
56 CVertexBuffer CPSConstraintMesh::_PreRotatedMeshVBWithNormal; // mesh has normals
57 CPSConstraintMesh::TMeshName2RamVB CPSConstraintMesh::_MeshRamVBs;
61 // this produce a random unit vector
62 static CVector MakeRandomUnitVect(void)
64 NL_PS_FUNC(MakeRandomUnitVect)
65 CVector v((float) ((rand() % 20000) - 10000)
66 ,(float) ((rand() % 20000) - 10000)
67 ,(float) ((rand() % 20000) - 10000)
69 v.normalize();
70 return v;
74 ////////////////////////////
75 // CPSMesh implementation //
76 ////////////////////////////
79 //====================================================================================
84 const std::string DummyShapeName("dummy mesh shape");
86 /** a private function that create a dummy mesh :a cube with dummy textures
89 static CMesh *CreateDummyMesh(void)
91 NL_PS_FUNC(CreateDummyMesh)
92 CMesh::CMeshBuild mb;
93 CMeshBase::CMeshBaseBuild mbb;
95 mb.VertexFlags = CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag;
96 mb.Vertices.push_back(CVector(-.5f, -.5f, -.5f));
97 mb.Vertices.push_back(CVector(.5f, -.5f, -.5f));
98 mb.Vertices.push_back(CVector(.5f, -.5f, .5f));
99 mb.Vertices.push_back(CVector(-.5f, -.5f, .5f));
101 mb.Vertices.push_back(CVector(-.5f, .5f, -.5f));
102 mb.Vertices.push_back(CVector(.5f, .5f, -.5f));
103 mb.Vertices.push_back(CVector(.5f, .5f, .5f));
104 mb.Vertices.push_back(CVector(-.5f, .5f, .5f));
106 // index for each face
107 uint32 tab[] = { 4, 1, 0,
108 4, 5, 1,
109 5, 2, 1,
110 5, 6, 2,
111 6, 3, 2,
112 6, 7, 3,
113 7, 0, 3,
114 7, 4, 0,
115 7, 5, 4,
116 7, 6, 5,
117 2, 0, 1,
118 2, 3, 0
121 for (uint k = 0; k < 6; ++k)
123 CMesh::CFace f;
124 f.Corner[0].Vertex = tab[6 * k];
125 f.Corner[0].Uvws[0] = NLMISC::CUVW(0, 0, 0);
127 f.Corner[1].Vertex = tab[6 * k + 1];
128 f.Corner[1].Uvws[0] = NLMISC::CUVW(1, 1, 0);
130 f.Corner[2].Vertex = tab[6 * k + 2];
131 f.Corner[2].Uvws[0] = NLMISC::CUVW(0, 1, 0);
133 f.MaterialId = 0;
135 mb.Faces.push_back(f);
137 f.Corner[0].Vertex = tab[6 * k + 3];
138 f.Corner[0].Uvws[0] = NLMISC::CUVW(0, 0, 0);
140 f.Corner[1].Vertex = tab[6 * k + 4];
141 f.Corner[1].Uvws[0] = NLMISC::CUVW(1, 0, 0);
143 f.Corner[2].Vertex = tab[6 * k + 5];
144 f.Corner[2].Uvws[0] = NLMISC::CUVW(1, 1, 0);
146 f.MaterialId = 0;
147 mb.Faces.push_back(f);
150 CMaterial mat;
151 CTextureMem *tex = new CTextureMem;
152 tex->makeDummy();
153 mat.setTexture(0, tex);
154 mat.setLighting(false);
155 mat.setColor(CRGBA::White);
156 mbb.Materials.push_back(mat);
157 CMesh *m = new CMesh;
158 m->build(mbb, mb);
159 return m;
163 //====================================================================================
164 void CPSMesh::serial(NLMISC::IStream &f)
166 NL_PS_FUNC(CPSMesh_IStream )
167 (void)f.serialVersion(3);
168 CPSParticle::serial(f);
169 CPSSizedParticle::serialSizeScheme(f);
170 CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f);
171 CPSRotated2DParticle::serialAngle2DScheme(f);
172 f.serial(_Shape);
173 if (f.isReading())
176 uint maxSize = 0;
177 if (_Owner)
179 maxSize = _Owner->getMaxSize();
180 _Instances.resize(maxSize);
182 for(uint k = 0; k < maxSize; ++k)
184 _Instances.insert(NULL);
189 //====================================================================================
190 void CPSMesh::setShape(const std::string &shape)
192 NL_PS_FUNC(CPSMesh_setShape)
193 if (shape == _Shape) return;
194 _Shape = shape;
195 removeAllInstancesFromScene();
198 //====================================================================================
199 uint32 CPSMesh::getNumWantedTris() const
201 NL_PS_FUNC(CPSMesh_getNumWantedTris)
202 /// we don't draw any face ! (the meshs are drawn by the scene)
203 return 0;
206 //====================================================================================
207 bool CPSMesh::hasTransparentFaces(void)
209 NL_PS_FUNC(CPSMesh_hasTransparentFaces)
210 /// we don't draw any tri ! (the meshs are drawn by the scene)
211 return false;
214 //====================================================================================
215 bool CPSMesh::hasOpaqueFaces(void)
217 NL_PS_FUNC(CPSMesh_hasOpaqueFaces)
218 /// We don't draw any tri !
219 return false;
222 //====================================================================================
223 bool CPSMesh::hasLightableFaces()
225 NL_PS_FUNC(CPSMesh_hasLightableFaces)
226 /// we don't draw any tri ! (the meshs are drawn by the scene)
227 return false;
230 //====================================================================================
231 void CPSMesh::releaseAllRef()
233 NL_PS_FUNC(CPSMesh_releaseAllRef)
234 CPSParticle::releaseAllRef();
235 nlassert(_Owner && _Owner->getScene());
236 removeAllInstancesFromScene();
239 //====================================================================================
240 void CPSMesh::removeAllInstancesFromScene()
242 NL_PS_FUNC(CPSMesh_removeAllInstancesFromScene)
243 for(uint k = 0; k < _Instances.getSize(); ++k)
245 if (_Instances[k])
247 if (_Owner) _Owner->getScene()->deleteInstance(_Instances[k]);
248 _Instances[k] = NULL;
253 //====================================================================================
254 CTransformShape *CPSMesh::createInstance()
256 NL_PS_FUNC(CPSMesh_createInstance)
257 CScene *scene = _Owner->getScene();
258 nlassert(scene); // the setScene method of the particle system should have been called
259 CTransformShape *instance = scene->createInstance(_Shape);
260 if (!instance)
262 // mesh not found ...
263 IShape *is = CreateDummyMesh();
264 scene->getShapeBank()->add(DummyShapeName, is);
265 instance = scene->createInstance(DummyShapeName);
266 nlassert(instance);
268 instance->setTransformMode(CTransform::DirectMatrix);
269 instance->hide(); // the object hasn't the right matrix yet so we hide it. It'll be shown once it is computed
270 return instance;
273 //====================================================================================
274 void CPSMesh::newElement(const CPSEmitterInfo &info)
276 NL_PS_FUNC(CPSMesh_newElement)
277 newPlaneBasisElement(info);
278 newAngle2DElement(info);
279 newSizeElement(info);
280 nlassert(_Owner);
281 nlassert(_Owner->getOwner());
282 CTransformShape *instance = createInstance();
283 nlassert(instance);
284 _Instances.insert(instance);
287 //====================================================================================
288 void CPSMesh::deleteElement(uint32 index)
290 NL_PS_FUNC(CPSMesh_deleteElement)
291 deleteSizeElement(index);
292 deleteAngle2DElement(index);
293 deletePlaneBasisElement(index);
295 // check whether CTransformShape have been instanciated
296 nlassert(_Owner);
297 nlassert(_Owner->getOwner());
298 CScene *scene = _Owner->getScene();
299 nlassert(scene); // the setScene method of the particle system should have been called
300 if (_Instances[index])
302 scene->deleteInstance(_Instances[index]);
304 _Instances.remove(index);
307 //====================================================================================
308 void CPSMesh::step(TPSProcessPass pass)
310 NL_PS_FUNC(CPSMesh_step)
311 if (pass == PSMotion)
313 updatePos();
315 else
316 if (pass == PSToolRender) // edition mode only
318 showTool();
322 //====================================================================================
323 void CPSMesh::updatePos()
325 NL_PS_FUNC(CPSMesh_updatePos)
326 const uint MeshBufSize = 512;
327 PARTICLES_CHECK_MEM;
328 nlassert(_Owner);
329 const uint32 size = _Owner->getSize();
330 if (!size) return;
333 _Owner->incrementNbDrawnParticles(size); // for benchmark purpose
336 if (!_Instances[0])
338 for (uint k = 0; k < size; ++k)
340 nlassert(!_Instances[k]);
341 _Instances[k] = createInstance();
345 float sizes[MeshBufSize];
346 float angles[MeshBufSize];
347 static CPlaneBasis planeBasis[MeshBufSize];
349 uint32 leftToDo = size, toProcess;
352 float *ptCurrSize;
353 const uint ptCurrSizeIncrement = _SizeScheme ? 1 : 0;
355 float *ptCurrAngle;
356 const uint ptCurrAngleIncrement = _Angle2DScheme ? 1 : 0;
358 CPlaneBasis *ptBasis;
359 const uint ptCurrPlaneBasisIncrement = _PlaneBasisScheme ? 1 : 0;
361 TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt;
364 TInstanceCont::iterator instanceIt = _Instances.begin();
368 toProcess = leftToDo < MeshBufSize ? leftToDo : MeshBufSize;
370 if (_SizeScheme)
372 ptCurrSize = (float *) (_SizeScheme->make(_Owner, size - leftToDo, &sizes[0], sizeof(float), toProcess, true));
374 else
376 ptCurrSize =& _ParticleSize;
379 if (_Angle2DScheme)
381 ptCurrAngle = (float *) (_Angle2DScheme->make(_Owner, size - leftToDo, &angles[0], sizeof(float), toProcess, true));
383 else
385 ptCurrAngle =& _Angle2D;
389 if (_PlaneBasisScheme)
391 ptBasis = (CPlaneBasis *) (_PlaneBasisScheme->make(_Owner, size - leftToDo, &planeBasis[0], sizeof(CPlaneBasis), toProcess, true));
393 else
395 ptBasis = &_PlaneBasis;
398 endPosIt = posIt + toProcess;
399 CMatrix mat, tmat;
401 // the matrix used to get in the right basis
402 const CMatrix &transfo = getLocalToWorldMatrix();
406 tmat.identity();
407 mat.identity();
409 tmat.translate(*posIt);
413 mat.setRot( ptBasis->X * CPSUtil::getCos((sint32) *ptCurrAngle) + ptBasis->Y * CPSUtil::getSin((sint32) *ptCurrAngle)
414 , ptBasis->X * CPSUtil::getCos((sint32) *ptCurrAngle + 64) + ptBasis->Y * CPSUtil::getSin((sint32) *ptCurrAngle + 64)
415 , ptBasis->X ^ ptBasis->Y
418 mat.scale(*ptCurrSize);
420 (*instanceIt)->setMatrix(transfo * tmat * mat);
421 if (CParticleSystem::OwnerModel)
423 // make sure the visibility is the same
424 if (CParticleSystem::OwnerModel->isHrcVisible())
426 (*instanceIt)->show();
428 else
430 (*instanceIt)->hide();
432 (*instanceIt)->setClusterSystem(CParticleSystem::OwnerModel->getClusterSystem());
435 ++instanceIt;
436 ++posIt;
437 ptCurrSize += ptCurrSizeIncrement;
438 ptCurrAngle += ptCurrAngleIncrement;
439 ptBasis += ptCurrPlaneBasisIncrement;
441 while (posIt != endPosIt);
442 leftToDo -= toProcess;
444 while (leftToDo);
446 PARTICLES_CHECK_MEM;
449 //====================================================================================
450 void CPSMesh::resize(uint32 size)
452 NL_PS_FUNC(CPSMesh_resize)
453 nlassert(size < (1 << 16));
454 resizeSize(size);
455 resizeAngle2D(size);
456 resizePlaneBasis(size);
457 if (size < _Instances.getSize())
459 for(uint k = size; k < _Instances.getSize(); ++k)
461 if (_Owner) _Owner->getScene()->deleteInstance(_Instances[k]);
464 _Instances.resize(size);
468 //====================================================================================
469 CPSMesh::~CPSMesh()
471 NL_PS_FUNC(CPSMesh_CPSMeshDtor)
472 if (_Owner && _Owner->getOwner())
474 removeAllInstancesFromScene();
476 else
478 #ifdef NL_DEBUG
479 for (TInstanceCont::iterator it = _Instances.begin(); it != _Instances.end(); ++it)
481 nlassert(*it == NULL); // there's a leak..:(
483 #endif
487 //////////////////////////////////////
488 // CPSConstraintMesh implementation //
489 //////////////////////////////////////
491 /// private : eval the number of triangles in a mesh
492 static uint getMeshNumTri(const CMesh &m)
494 NL_PS_FUNC(getMeshNumTri)
495 uint numFaces = 0;
496 for (uint k = 0; k < m.getNbMatrixBlock(); ++k)
498 for (uint l = 0; l < m.getNbRdrPass(k); ++l)
500 const CIndexBuffer pb = m.getRdrPassPrimitiveBlock(k, l);
501 numFaces += pb.getNumIndexes()/3;
505 return numFaces;
509 //====================================================================================
510 /// private use : check if there are transparent and / or opaque faces in a mesh
511 static void CheckForOpaqueAndTransparentFacesInMesh(const CMesh &m, bool &hasTransparentFaces, bool &hasOpaqueFaces)
513 NL_PS_FUNC(CheckForOpaqueAndTransparentFacesInMesh)
514 hasTransparentFaces = false;
515 hasOpaqueFaces = false;
517 for (uint k = 0; k < m.getNbRdrPass(0); ++k)
519 const CMaterial &currMat = m.getMaterial(m.getRdrPassMaterial(0, k));
520 if (!currMat.getZWrite())
522 hasTransparentFaces = true;
524 else // z-buffer write or no blending -> the face is opaque
526 hasOpaqueFaces = true;
531 //====================================================================================
532 /// private use : check if there are lightable faces in a mesh
533 static bool CheckForLightableFacesInMesh(const CMesh &m)
535 NL_PS_FUNC(CheckForLightableFacesInMesh)
536 for (uint k = 0; k < m.getNbRdrPass(0); ++k)
538 const CMaterial &currMat = m.getMaterial(m.getRdrPassMaterial(0, k));
539 if (currMat.isLighted()) return true;
541 return false;
545 /** Well, we could have put a method template in CPSConstraintMesh, but some compilers
546 * want the definition of the methods in the header, and some compilers
547 * don't want friend with function template, so we use a static method template of a friend class instead,
548 * which gives us the same result :)
550 class CPSConstraintMeshHelper
552 public:
553 template <class T>
554 static void drawMeshs(T posIt, CPSConstraintMesh &m, uint size, uint32 srcStep, bool opaque)
556 NL_PS_FUNC(CPSConstraintMeshHelper_drawMeshs)
557 const CVertexBuffer &modelVb = m.getMeshVB(0);
560 // size for model vertices
561 const uint inVSize = modelVb.getVertexSize(); // vertex size
563 // driver setup
564 IDriver *driver = m.getDriver();
565 m.setupDriverModelMatrix();
567 // buffer to compute sizes
568 float sizes[ConstraintMeshBufSize];
570 float *ptCurrSize;
571 uint ptCurrSizeIncrement = m._SizeScheme ? 1 : 0;
573 T endPosIt;
574 uint leftToDo = size, toProcess;
576 /// get a vb in which to write. It has the same format than the input mesh, but can also have a color flag added
577 CPSConstraintMesh::CMeshDisplay &md= m._MeshDisplayShare.getMeshDisplay(m._Meshes[0], modelVb, modelVb.getVertexFormat()
578 | (m._ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
580 m.setupRenderPasses((float) m._Owner->getOwner()->getSystemDate() - m._GlobalAnimDate, md.RdrPasses, opaque);
582 CVertexBuffer &outVb = md.VB;
583 const uint outVSize = outVb.getVertexSize();
587 // we don't have precomputed mesh there ... so each mesh must be transformed, which is the worst case
588 CPlaneBasis planeBasis[ConstraintMeshBufSize];
589 CPlaneBasis *ptBasis;
590 uint ptBasisIncrement = m._PlaneBasisScheme ? 1 : 0;
592 const uint nbVerticesInSource = modelVb.getNumVertices();
594 sint inNormalOff=0;
595 sint outNormalOff=0;
596 if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
598 inNormalOff = modelVb.getNormalOff();
599 outNormalOff = outVb.getNormalOff();
601 if (m._ColorScheme)
603 CVertexBuffer::TVertexColorType vtc = driver->getVertexColorFormat();
604 m._ColorScheme->setColorType(vtc);
605 if (modelVb.getVertexFormat() & CVertexBuffer::PrimaryColorFlag)
607 const_cast<CVertexBuffer &>(modelVb).setVertexColorFormat(vtc);
610 CVertexBufferRead vbaRead;
611 modelVb.lock (vbaRead);
614 toProcess = std::min(leftToDo, ConstraintMeshBufSize);
615 outVb.setNumVertices(toProcess * nbVerticesInSource);
617 CVertexBufferReadWrite vba;
618 outVb.lock(vba);
619 uint8 *outVertex = (uint8 *) vba.getVertexCoordPointer();
620 if (m._SizeScheme)
622 ptCurrSize = (float *) (m._SizeScheme->make(m._Owner, size -leftToDo, &sizes[0], sizeof(float), toProcess, true, srcStep));
624 else
626 ptCurrSize = &m._ParticleSize;
629 if (m._PlaneBasisScheme)
631 ptBasis = (CPlaneBasis *) (m._PlaneBasisScheme->make(m._Owner, size -leftToDo, &planeBasis[0], sizeof(CPlaneBasis), toProcess, true, srcStep));
633 else
635 ptBasis = &m._PlaneBasis;
639 endPosIt = posIt + toProcess;
640 // transfo matrix & scaled transfo matrix;
641 CMatrix M, sM;
644 if (m._Meshes.size() == 1)
646 /// unmorphed case
649 const uint8 *inVertex = (const uint8 *) vbaRead.getVertexCoordPointer();
650 uint k = nbVerticesInSource;
652 // do we need a normal ?
653 if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
655 M.identity();
656 M.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
657 sM = M;
658 sM.scale(*ptCurrSize);
660 // offset of normals in the prerotated mesh
663 CHECK_VERTEX_BUFFER(modelVb, inVertex);
664 CHECK_VERTEX_BUFFER(outVb, outVertex);
665 CHECK_VERTEX_BUFFER(modelVb, inVertex + inNormalOff);
666 CHECK_VERTEX_BUFFER(outVb, outVertex + outNormalOff);
668 // translate and resize the vertex (relatively to the mesh origin)
669 *(CVector *) outVertex = *posIt + sM * *(CVector *) inVertex;
670 // copy the normal
671 *(CVector *) (outVertex + outNormalOff) = M * *(CVector *) (inVertex + inNormalOff);
674 inVertex += inVSize;
675 outVertex += outVSize;
677 while (--k);
679 else
681 // no normal to transform
682 sM.identity();
683 sM.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
684 sM.scale(*ptCurrSize);
688 CHECK_VERTEX_BUFFER(modelVb, inVertex);
689 CHECK_VERTEX_BUFFER(outVb, outVertex);
691 // translate and resize the vertex (relatively to the mesh origin)
692 *(CVector *) outVertex = *posIt + sM * *(CVector *) inVertex;
694 inVertex += inVSize;
695 outVertex += outVSize;
697 while (--k);
701 ++posIt;
702 ptCurrSize += ptCurrSizeIncrement;
703 ptBasis += ptBasisIncrement;
705 while (posIt != endPosIt);
707 else
709 // morphed case
711 // first, compute the morph value for each mesh
712 float morphValues[ConstraintMeshBufSize];
713 float *currMorphValue;
714 uint morphValueIncr;
716 if (m._MorphScheme) // variable case
718 currMorphValue = (float *) m._MorphScheme->make(m._Owner, size - leftToDo, &morphValues[0], sizeof(float), toProcess, true, srcStep);
719 morphValueIncr = 1;
721 else /// constant case
723 currMorphValue = &m._MorphValue;
724 morphValueIncr = 0;
729 const uint numShapes = (uint)m._Meshes.size();
730 const uint8 *m0, *m1;
731 float lambda;
732 float opLambda;
733 const CVertexBuffer *inVB0, *inVB1;
734 if (*currMorphValue >= numShapes - 1)
736 lambda = 0.f;
737 opLambda = 1.f;
738 inVB0 = inVB1 = &(m.getMeshVB(numShapes - 1));
740 else if (*currMorphValue <= 0)
742 lambda = 0.f;
743 opLambda = 1.f;
744 inVB0 = inVB1 = &(m.getMeshVB(0));
746 else
748 uint iMeshIndex = (uint) *currMorphValue;
749 lambda = *currMorphValue - iMeshIndex;
750 opLambda = 1.f - lambda;
751 inVB0 = &(m.getMeshVB(iMeshIndex));
752 inVB1 = &(m.getMeshVB(iMeshIndex + 1));
754 CVertexBufferRead vba0;
755 inVB0->lock (vba0);
756 CVertexBufferRead vba1;
757 inVB1->lock (vba1);
759 m0 = (uint8 *) vba0.getVertexCoordPointer();
760 m1 = (uint8 *) vba1.getVertexCoordPointer();
763 uint k = nbVerticesInSource;
764 // do we need a normal ?
765 if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
767 M.identity();
768 M.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
769 sM = M;
770 sM.scale(*ptCurrSize);
772 // offset of normals in the prerotated mesh
775 CHECK_VERTEX_BUFFER((*inVB0), m0);
776 CHECK_VERTEX_BUFFER((*inVB1), m1);
777 CHECK_VERTEX_BUFFER((*inVB0), m0 + inNormalOff);
778 CHECK_VERTEX_BUFFER((*inVB1), m1 + inNormalOff);
779 CHECK_VERTEX_BUFFER(outVb, outVertex);
780 CHECK_VERTEX_BUFFER(outVb, outVertex + outNormalOff);
782 // morph, and transform the vertex
783 *(CVector *) outVertex = *posIt + sM * (opLambda * *(CVector *) m0 + lambda * *(CVector *) m1);
784 // morph, and transform the normal
785 *(CVector *) (outVertex + outNormalOff) = M * (opLambda * *(CVector *) (m0 + inNormalOff)
786 + lambda * *(CVector *) (m1 + inNormalOff)).normed();
789 m0 += inVSize;
790 m1 += inVSize;
791 outVertex += outVSize;
793 while (--k);
795 else
797 // no normal to transform
798 sM.identity();
799 sM.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
800 sM.scale(*ptCurrSize);
804 CHECK_VERTEX_BUFFER((*inVB0), m0);
805 CHECK_VERTEX_BUFFER((*inVB1), m1);
806 CHECK_VERTEX_BUFFER(outVb, outVertex);
807 // morph, and transform the vertex
808 *(CVector *) outVertex = *posIt + sM * (opLambda * *(CVector *) m0 + opLambda * *(CVector *) m1);
810 m0 += inVSize;
811 m1 += inVSize;
812 outVertex += outVSize;
814 while (--k);
818 ++posIt;
819 ptCurrSize += ptCurrSizeIncrement;
820 ptBasis += ptBasisIncrement;
821 currMorphValue += morphValueIncr;
823 while (posIt != endPosIt);
826 // compute colors if needed
827 if (m._ColorScheme)
829 m.computeColors(outVb, modelVb, size - leftToDo, toProcess, srcStep, *driver, vba, vbaRead);
833 // render meshs
834 driver->activeVertexBuffer(outVb);
835 m.doRenderPasses(driver, toProcess, md.RdrPasses, opaque);
836 leftToDo -= toProcess;
839 while (leftToDo);
843 template <class T, class U>
844 static void drawPrerotatedMeshs(T posIt,
845 U indexIt,
846 CPSConstraintMesh &m,
847 uint size,
848 uint32 srcStep,
849 bool opaque)
851 // get the vb from the original mesh
852 const CVertexBuffer &modelVb = m.getMeshVB(0);
854 /// precompute rotation in a VB from the src mesh
855 CVertexBuffer &prerotVb = m.makePrerotatedVb(modelVb);
857 // driver setup
858 IDriver *driver = m.getDriver();
859 m.setupDriverModelMatrix();
861 // renderPasses setup
862 nlassert(m._Owner);
864 // storage for sizes of meshs
865 float sizes[ConstraintMeshBufSize];
867 // point the size for the current mesh
868 float *ptCurrSize;
869 uint ptCurrSizeIncrement = m._SizeScheme ? 1 : 0;
871 T endPosIt;
872 uint leftToDo = size, toProcess;
873 const uint nbVerticesInSource = modelVb.getNumVertices();
877 // size of a complete prerotated model
878 const uint prerotatedModelSize = prerotVb.getVertexSize() * modelVb.getNumVertices();
880 /// get a mesh display struct on this shape, with eventually a primary color added.
881 CPSConstraintMesh::CMeshDisplay &md = m._MeshDisplayShare.getMeshDisplay(m._Meshes[0], modelVb, modelVb.getVertexFormat()
882 | (m._ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
885 m.setupRenderPasses((float) m._Owner->getOwner()->getSystemDate() - m._GlobalAnimDate, md.RdrPasses, opaque);
887 CVertexBuffer &outVb = md.VB;
891 // size of vertices in prerotated model
892 const uint inVSize = prerotVb.getVertexSize();
894 // size ofr vertices in dest vb
895 const uint outVSize = outVb.getVertexSize();
897 // offset of normals in vertices of the prerotated model, and source model
898 uint normalOff=0;
899 uint pNormalOff=0;
900 if (prerotVb.getVertexFormat() & CVertexBuffer::NormalFlag)
902 normalOff = outVb.getNormalOff();
903 pNormalOff = prerotVb.getNormalOff();
906 if (m._ColorScheme)
908 CVertexBuffer::TVertexColorType vtc = driver->getVertexColorFormat();
909 m._ColorScheme->setColorType(vtc);
910 if (modelVb.getVertexFormat() & CVertexBuffer::PrimaryColorFlag)
912 const_cast<CVertexBuffer &>(modelVb).setVertexColorFormat(vtc);
916 CVertexBufferRead PrerotVba;
917 prerotVb.lock(PrerotVba);
920 toProcess = std::min(leftToDo, ConstraintMeshBufSize);
921 outVb.setNumVertices(toProcess * nbVerticesInSource);
923 CVertexBufferReadWrite vba;
924 outVb.lock(vba);
927 if (m._SizeScheme)
929 // compute size
930 ptCurrSize = (float *) (m._SizeScheme->make(m._Owner, size - leftToDo, &sizes[0], sizeof(float), toProcess, true, srcStep));
932 else
934 // pointer on constant size
935 ptCurrSize = &m._ParticleSize;
938 endPosIt = posIt + toProcess;
939 uint8 *outVertex = (uint8 *) vba.getVertexCoordPointer();
940 /// copy datas for several mesh
943 uint8 *inVertex = (uint8 *) PrerotVba.getVertexCoordPointer() + prerotatedModelSize * *indexIt; // prerotated vertex
944 uint k = nbVerticesInSource;
946 if (prerotVb.getVertexFormat() & CVertexBuffer::NormalFlag) // has it a normal ?
950 CHECK_VERTEX_BUFFER(outVb, outVertex);
951 CHECK_VERTEX_BUFFER(prerotVb, inVertex);
952 CHECK_VERTEX_BUFFER(outVb, outVertex + normalOff);
953 CHECK_VERTEX_BUFFER(prerotVb, inVertex + pNormalOff);
956 // translate and resize the vertex (relatively to the mesh origin)
957 *(CVector *) outVertex = *posIt + *ptCurrSize * *(CVector *) inVertex;
958 // copy the normal
959 *(CVector *) (outVertex + normalOff ) = *(CVector *) (inVertex + pNormalOff);
960 inVertex += inVSize;
961 outVertex += outVSize;
963 while (--k);
965 else
969 // translate and resize the vertex (relatively to the mesh origin)
970 CHECK_VERTEX_BUFFER(outVb, outVertex);
971 CHECK_VERTEX_BUFFER(prerotVb, inVertex);
972 *(CVector *) outVertex = *posIt + *ptCurrSize * *(CVector *) inVertex;
973 inVertex += inVSize;
974 outVertex += outVSize;
976 while (--k);
979 ++indexIt;
980 ++posIt;
981 ptCurrSize += ptCurrSizeIncrement;
983 while (posIt != endPosIt);
985 // compute colors if needed
986 if (m._ColorScheme)
988 m.computeColors(outVb, modelVb, size - leftToDo, toProcess, srcStep, *driver, vba, PrerotVba);
992 /// render the result
993 driver->activeVertexBuffer(outVb);
994 m.doRenderPasses(driver, toProcess, md.RdrPasses, opaque);
995 leftToDo -= toProcess;
998 while (leftToDo);
999 PARTICLES_CHECK_MEM
1003 CPSConstraintMesh::CPSConstraintMesh() : _NumFaces(0),
1004 _ModelBank(NULL),
1005 _ModulatedStages(0),
1006 _Touched(1),
1007 _HasOpaqueFaces(0),
1008 _VertexColorLightingForced(false),
1009 _GlobalAnimationEnabled(0),
1010 _ReinitGlobalAnimTimeOnNewElement(0),
1011 _HasLightableFaces(0),
1012 _ValidBuild(0),
1013 _MorphValue(0),
1014 _MorphScheme(NULL)
1016 NL_PS_FUNC(CPSConstraintMesh_CPSConstraintMesh)
1017 if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("ConstraintMesh");
1020 //====================================================================================
1021 uint32 CPSConstraintMesh::getNumWantedTris() const
1023 NL_PS_FUNC(CPSConstraintMesh_getNumWantedTris)
1024 // nlassert(_ModelVb);
1025 //return _NumFaces * _Owner->getMaxSize();
1026 return _NumFaces * _Owner->getSize();
1030 //====================================================================================
1031 bool CPSConstraintMesh::hasTransparentFaces(void)
1033 NL_PS_FUNC(CPSConstraintMesh_hasTransparentFaces)
1034 if (!_Touched) return _HasTransparentFaces != 0;
1035 /// we must update the mesh to know whether it has transparent faces
1036 update();
1037 return _HasTransparentFaces != 0;
1040 //====================================================================================
1041 bool CPSConstraintMesh::hasOpaqueFaces(void)
1043 NL_PS_FUNC(CPSConstraintMesh_hasOpaqueFaces)
1044 if (!_Touched) return _HasOpaqueFaces != 0;
1045 update();
1046 return _HasOpaqueFaces != 0;
1049 //====================================================================================
1050 bool CPSConstraintMesh::hasLightableFaces()
1052 NL_PS_FUNC(CPSConstraintMesh_hasLightableFaces)
1053 if (!_Touched) return _HasLightableFaces != 0;
1054 update();
1055 return _HasLightableFaces != 0;
1059 //====================================================================================
1060 void CPSConstraintMesh::setShape(const std::string &meshFileName)
1062 NL_PS_FUNC(CPSConstraintMesh_setShape)
1063 _MeshShapeFileName.resize(1);
1064 _MeshShapeFileName[0] = meshFileName;
1065 _Touched = 1;
1066 _ValidBuild = 0;
1070 //===========================================================================
1071 std::string CPSConstraintMesh::getShape(void) const
1073 NL_PS_FUNC(CPSConstraintMesh_getShape)
1074 if (_Touched)
1076 const_cast<CPSConstraintMesh *>(this)->update();
1078 nlassert(_MeshShapeFileName.size() == 1);
1079 return _MeshShapeFileName[0];
1082 //====================================================================================
1083 bool CPSConstraintMesh::isValidBuild() const
1085 NL_PS_FUNC(CPSConstraintMesh_isValidBuild)
1086 if (_Touched)
1088 const_cast<CPSConstraintMesh *>(this)->update();
1090 return _ValidBuild != 0;
1093 //====================================================================================
1094 void CPSConstraintMesh::setShapes(const std::string *shapesNames, uint numShapes)
1096 NL_PS_FUNC(CPSConstraintMesh_setShapes)
1097 _MeshShapeFileName.resize(numShapes);
1098 std::copy(shapesNames, shapesNames + numShapes, _MeshShapeFileName.begin());
1099 _Touched = 1;
1100 _ValidBuild = 0;
1103 //====================================================================================
1104 uint CPSConstraintMesh::getNumShapes() const
1106 NL_PS_FUNC(CPSConstraintMesh_getNumShapes)
1107 if (_Touched)
1109 const_cast<CPSConstraintMesh *>(this)->update();
1111 return (uint)_MeshShapeFileName.size();
1114 //====================================================================================
1115 void CPSConstraintMesh::getShapesNames(std::string *shapesNames) const
1117 NL_PS_FUNC(CPSConstraintMesh_getShapesNames)
1118 if (_Touched)
1120 const_cast<CPSConstraintMesh *>(this)->update();
1122 #ifdef NL_COMP_VC14
1123 std::copy(_MeshShapeFileName.begin(), _MeshShapeFileName.end(), stdext::make_unchecked_array_iterator(shapesNames));
1124 #else
1125 std::copy(_MeshShapeFileName.begin(), _MeshShapeFileName.end(), shapesNames);
1126 #endif
1129 //====================================================================================
1130 void CPSConstraintMesh::setShape(uint index, const std::string &shapeName)
1132 NL_PS_FUNC(CPSConstraintMesh_setShape)
1133 nlassert(index < _MeshShapeFileName.size());
1134 _MeshShapeFileName[index] = shapeName;
1135 _Touched = 1;
1136 _ValidBuild = 0;
1139 //====================================================================================
1140 const std::string &CPSConstraintMesh::getShape(uint index) const
1142 NL_PS_FUNC(CPSConstraintMesh_getShape)
1143 if (_Touched)
1145 const_cast<CPSConstraintMesh *>(this)->update();
1147 nlassert(index < _MeshShapeFileName.size());
1148 return _MeshShapeFileName[index];
1153 //====================================================================================
1154 void CPSConstraintMesh::setMorphValue(float value)
1156 NL_PS_FUNC(CPSConstraintMesh_setMorphValue)
1157 delete _MorphScheme;
1158 _MorphScheme = NULL;
1159 _MorphValue = value;
1163 //====================================================================================
1164 float CPSConstraintMesh::getMorphValue() const
1166 NL_PS_FUNC(CPSConstraintMesh_getMorphValue)
1167 return _MorphValue;
1170 //====================================================================================
1171 void CPSConstraintMesh::setMorphScheme(CPSAttribMaker<float> *scheme)
1173 NL_PS_FUNC(CPSConstraintMesh_setMorphScheme)
1174 delete _MorphScheme;
1175 _MorphScheme = scheme;
1176 if (_MorphScheme->hasMemory()) _MorphScheme->resize(_Owner->getMaxSize(), _Owner->getSize());
1179 //====================================================================================
1180 CPSAttribMaker<float> *CPSConstraintMesh::getMorphScheme()
1182 NL_PS_FUNC(CPSConstraintMesh_getMorphScheme)
1183 return _MorphScheme;
1186 //====================================================================================
1187 const CPSAttribMaker<float> *CPSConstraintMesh::getMorphScheme() const
1189 NL_PS_FUNC(CPSConstraintMesh_getMorphScheme)
1190 return _MorphScheme;
1194 //====================================================================================
1195 static CMesh *GetDummyMeshFromBank(CShapeBank &sb)
1197 NL_PS_FUNC(GetDummyMeshFromBank)
1198 static const std::string dummyMeshName("dummy constraint mesh shape");
1199 if (sb.getPresentState(dummyMeshName) == CShapeBank::Present)
1201 return NLMISC::safe_cast<CMesh *>(sb.addRef(dummyMeshName));
1203 else
1205 // no dummy shape created -> add one to the bank
1206 CMesh *m = CreateDummyMesh();
1207 sb.add(std::string("dummy constraint mesh shape"), m);
1208 return m;
1212 //====================================================================================
1213 void CPSConstraintMesh::getShapeNumVerts(std::vector<sint> &numVerts)
1215 NL_PS_FUNC(CPSConstraintMesh_getShapeNumVerts)
1216 _Touched = 1; // force reload
1217 update(&numVerts);
1220 //====================================================================================
1221 bool CPSConstraintMesh::update(std::vector<sint> *numVertsVect /*= NULL*/)
1223 NL_PS_FUNC(CPSConstraintMesh_update)
1224 bool ok = true;
1225 if (!_Touched) return ok;
1227 clean();
1229 nlassert(_Owner->getScene());
1231 CScene *scene = _Owner->getScene();
1232 _ModelBank = scene->getShapeBank();
1233 IShape *is = 0;
1236 uint32 vFormat = 0;
1237 uint numVerts = 0;
1238 uint8 uvRouting[CVertexBuffer::MaxStage];
1240 if (_MeshShapeFileName.empty())
1242 _MeshShapeFileName.resize(1);
1243 _MeshShapeFileName[0] = DummyShapeName;
1247 _Meshes.resize(_MeshShapeFileName.size());
1248 _MeshVertexBuffers.resize(_MeshShapeFileName.size());
1249 std::fill(_MeshVertexBuffers.begin(), _MeshVertexBuffers.end(), (CVertexBuffer *) NULL);
1250 if (numVertsVect) numVertsVect->resize(_MeshShapeFileName.size());
1251 for (uint k = 0; k < _MeshShapeFileName.size(); ++k)
1253 if (_ModelBank->getPresentState(_MeshShapeFileName[k]) == CShapeBank::Present)
1255 CMesh *mesh = dynamic_cast<CMesh *>( _ModelBank->addRef(_MeshShapeFileName[k]));
1256 if (!mesh)
1258 nlwarning("Tried to bind a shape that is not a mesh to a mesh particle : %s", _MeshShapeFileName[k].c_str());
1259 _ModelBank->release(is);
1260 ok = false;
1261 if (numVertsVect) (*numVertsVect)[k] = ShapeFileIsNotAMesh;
1263 else
1265 _Meshes[k] = mesh;
1266 /// get the mesh format, or check that is was the same that previous shapes ' one
1267 if (k == 0)
1269 vFormat = mesh->getVertexBuffer().getVertexFormat();
1270 numVerts = mesh->getVertexBuffer().getNumVertices();
1271 std::copy(mesh->getVertexBuffer().getUVRouting(), mesh->getVertexBuffer().getUVRouting() + CVertexBuffer::MaxStage, uvRouting);
1272 if (numVertsVect) (*numVertsVect)[k] = (sint) numVerts;
1274 else
1276 if (vFormat != mesh->getVertexBuffer().getVertexFormat())
1278 nlwarning("Vertex format differs between meshs");
1279 ok = false;
1281 if (numVerts != mesh->getVertexBuffer().getNumVertices())
1283 nlwarning("Num vertices differs between meshs");
1284 ok = false;
1286 if (!std::equal(mesh->getVertexBuffer().getUVRouting(), mesh->getVertexBuffer().getUVRouting() + CVertexBuffer::MaxStage, uvRouting))
1288 nlwarning("UV routing differs between meshs");
1289 ok = false;
1291 if (numVertsVect) (*numVertsVect)[k] = (sint) mesh->getVertexBuffer().getNumVertices();
1295 else
1299 _ModelBank->load(_MeshShapeFileName[k]);
1301 catch (const NLMISC::EPathNotFound &)
1303 nlwarning("mesh not found : %s; used as a constraint mesh particle", _MeshShapeFileName[k].c_str());
1304 // shape not found, so not present in the shape bank -> we create a dummy shape
1307 if (_ModelBank->getPresentState(_MeshShapeFileName[k]) != CShapeBank::Present)
1309 ok = false;
1310 if (numVertsVect) (*numVertsVect)[k] = ShapeFileNotLoaded;
1312 else
1314 is = _ModelBank->addRef(_MeshShapeFileName[k]);
1315 if (!dynamic_cast<CMesh *>(is)) // is it a mesh
1317 nlwarning("Tried to bind a shape that is not a mesh to a mesh particle : %s", _MeshShapeFileName[k].c_str());
1318 _ModelBank->release(is);
1319 ok = false;
1320 if (numVertsVect) (*numVertsVect)[k] = ShapeFileIsNotAMesh;
1322 else
1324 CMesh &m = * NLMISC::safe_cast<CMesh *>(is);
1325 /// make sure there are not too many vertices
1326 if (m.getVertexBuffer().getNumVertices() > ConstraintMeshMaxNumVerts)
1328 nlwarning("Tried to bind a mesh that has more than %d vertices to a particle mesh: %s", (int) ConstraintMeshMaxNumVerts, _MeshShapeFileName[k].c_str());
1329 _ModelBank->release(is);
1330 ok = false;
1331 if (numVertsVect) (*numVertsVect)[k] = ShapeHasTooMuchVertices;
1333 else
1335 _Meshes[k] = &m;
1336 if (k == 0)
1338 vFormat = m.getVertexBuffer().getVertexFormat();
1339 numVerts = m.getVertexBuffer().getNumVertices();
1340 std::copy(m.getVertexBuffer().getUVRouting(), m.getVertexBuffer().getUVRouting() + CVertexBuffer::MaxStage, uvRouting);
1341 if (numVertsVect) (*numVertsVect)[k] = numVerts;
1343 else
1345 uint32 otherVFormat = m.getVertexBuffer().getVertexFormat();
1346 uint otherNumVerts = m.getVertexBuffer().getNumVertices();
1347 if (otherVFormat != vFormat ||
1348 otherNumVerts != numVerts ||
1349 !(std::equal(m.getVertexBuffer().getUVRouting(), m.getVertexBuffer().getUVRouting() + CVertexBuffer::MaxStage, uvRouting)))
1351 ok = false;
1353 if (numVertsVect) (*numVertsVect)[k] = otherNumVerts;
1360 if (!ok && !numVertsVect) break;
1363 if (!ok)
1365 releaseShapes();
1366 _Meshes.resize(1);
1367 _MeshVertexBuffers.resize(1);
1368 _Meshes[0] = GetDummyMeshFromBank(*_ModelBank);
1369 _MeshVertexBuffers[0] = &_Meshes[0]->getVertexBuffer();
1372 const CMesh &m = *_Meshes[0];
1374 /// update the number of faces
1375 _NumFaces = getMeshNumTri(m);
1377 notifyOwnerMaxNumFacesChanged();
1378 if (_Owner && _Owner->getOwner())
1380 _Owner->getOwner()->notifyMaxNumFacesChanged();
1383 /// update opacity / transparency state
1384 bool hasTransparentFaces, hasOpaqueFaces;
1385 CheckForOpaqueAndTransparentFacesInMesh(m, hasTransparentFaces, hasOpaqueFaces);
1386 _HasTransparentFaces = hasTransparentFaces;
1387 _HasOpaqueFaces = hasOpaqueFaces;
1388 _HasLightableFaces = CheckForLightableFacesInMesh(m);
1389 _GlobalAnimDate = _Owner->getOwner()->getSystemDate();
1390 _Touched = 0;
1391 _ValidBuild = ok ? 1 : 0;
1392 nlassert(!_Meshes.empty());
1394 return ok;
1400 //====================================================================================
1401 void CPSConstraintMesh::hintRotateTheSame(uint32 nbConfiguration,
1402 float minAngularVelocity,
1403 float maxAngularVelocity
1406 NL_PS_FUNC(CPSConstraintMesh_hintRotateTheSame)
1407 nlassert(nbConfiguration <= ConstraintMeshMaxNumPrerotatedModels);
1409 // TODO : avoid code duplication with CPSFace ...
1410 _MinAngularVelocity = minAngularVelocity;
1411 _MaxAngularVelocity = maxAngularVelocity;
1415 _PrecompBasis.resize(nbConfiguration);
1417 if (nbConfiguration)
1419 // each precomp basis is created randomly;
1420 for (uint k = 0; k < nbConfiguration; ++k)
1422 CVector v = MakeRandomUnitVect();
1423 _PrecompBasis[k].Basis = CPlaneBasis(v);
1424 _PrecompBasis[k].Axis = MakeRandomUnitVect();
1425 _PrecompBasis[k].AngularVelocity = minAngularVelocity
1426 + (rand() % 20000) / 20000.f * (maxAngularVelocity - minAngularVelocity);
1430 // we need to do this because nbConfs may have changed
1431 fillIndexesInPrecompBasis();
1436 //====================================================================================
1437 void CPSConstraintMesh::fillIndexesInPrecompBasis(void)
1439 NL_PS_FUNC(CPSConstraintMesh_fillIndexesInPrecompBasis)
1440 // TODO : avoid code duplication with CPSFace ...
1441 const uint32 nbConf = (uint32)_PrecompBasis.size();
1442 if (_Owner)
1444 _IndexInPrecompBasis.resize( _Owner->getMaxSize() );
1446 for (CPSVector<uint32>::V::iterator it = _IndexInPrecompBasis.begin(); it != _IndexInPrecompBasis.end(); ++it)
1448 *it = rand() % nbConf;
1452 //====================================================================================
1453 /// serialisation. Derivers must override this, and call their parent version
1454 void CPSConstraintMesh::serial(NLMISC::IStream &f)
1456 NL_PS_FUNC(CPSConstraintMesh_IStream )
1458 sint ver = f.serialVersion(4);
1459 if (f.isReading())
1461 clean();
1464 CPSParticle::serial(f);
1465 CPSSizedParticle::serialSizeScheme(f);
1466 CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f);
1468 // prerotations ...
1470 if (f.isReading())
1472 uint32 nbConfigurations;
1473 f.serial(nbConfigurations);
1474 if (nbConfigurations)
1476 f.serial(_MinAngularVelocity, _MaxAngularVelocity);
1478 hintRotateTheSame(nbConfigurations, _MinAngularVelocity, _MaxAngularVelocity);
1480 else
1482 uint32 nbConfigurations = (uint32)_PrecompBasis.size();
1483 f.serial(nbConfigurations);
1484 if (nbConfigurations)
1486 f.serial(_MinAngularVelocity, _MaxAngularVelocity);
1490 // saves the model file name, or an empty string if nothing has been set
1491 static std::string emptyStr;
1493 if (ver < 4) // early version : no morphing support
1495 if (!f.isReading())
1497 if (!_MeshShapeFileName.empty())
1499 f.serial(_MeshShapeFileName[0]);
1501 else
1503 f.serial(emptyStr);
1506 else
1508 _MeshShapeFileName.resize(1);
1509 f.serial(_MeshShapeFileName[0]);
1510 _Touched = true;
1511 _ValidBuild = 0;
1515 if (ver > 1)
1517 CPSColoredParticle::serialColorScheme(f);
1518 f.serial(_ModulatedStages);
1519 if (f.isReading())
1521 bool vcEnabled;
1522 f.serial(vcEnabled);
1523 _VertexColorLightingForced = vcEnabled;
1525 else
1527 bool vcEnabled = (_VertexColorLightingForced != 0);
1528 f.serial(vcEnabled);
1532 if (ver > 2) // texture animation
1534 if (f.isReading())
1536 bool gaEnabled;
1537 f.serial(gaEnabled);
1538 _GlobalAnimationEnabled = gaEnabled;
1539 if (gaEnabled)
1541 PGlobalTexAnims newPtr(new CGlobalTexAnims); // create new
1542 //std::swap(_GlobalTexAnims, newPtr); // replace old
1543 _GlobalTexAnims = CUniquePtrMove(newPtr);
1544 f.serial(*_GlobalTexAnims);
1547 bool rgt;
1548 f.serial(rgt);
1549 _ReinitGlobalAnimTimeOnNewElement = rgt;
1551 else
1553 bool gaEnabled = (_GlobalAnimationEnabled != 0);
1554 f.serial(gaEnabled);
1555 if (gaEnabled)
1557 f.serial(*_GlobalTexAnims);
1560 bool rgt = _ReinitGlobalAnimTimeOnNewElement != 0;
1561 f.serial(rgt);
1565 if (ver > 3) // mesh morphing
1567 if (!f.isReading())
1569 // remove path
1570 TMeshNameVect meshNamesWithoutPath = _MeshShapeFileName;
1571 std::transform(meshNamesWithoutPath.begin(), meshNamesWithoutPath.end(), meshNamesWithoutPath.begin(), std::ptr_fun(NLMISC::CFile::getFilename));
1572 f.serialCont(meshNamesWithoutPath);
1574 else
1576 f.serialCont(_MeshShapeFileName);
1578 bool useScheme;
1579 if (f.isReading())
1581 delete _MorphScheme;
1583 else
1585 useScheme = _MorphScheme != NULL;
1587 f.serial(useScheme);
1588 if (useScheme)
1590 f.serialPolyPtr(_MorphScheme);
1592 else
1594 f.serial(_MorphValue);
1599 //====================================================================================
1600 CPSConstraintMesh::~CPSConstraintMesh()
1602 NL_PS_FUNC(CPSConstraintMesh_CPSConstraintMeshDtor)
1603 clean();
1604 delete _MorphScheme;
1609 //====================================================================================
1610 void CPSConstraintMesh::releaseShapes()
1612 NL_PS_FUNC(CPSConstraintMesh_releaseShapes)
1613 for (TMeshVect::iterator it = _Meshes.begin(); it != _Meshes.end(); ++it)
1615 if (*it)
1617 if (_ModelBank) _ModelBank->release(*it);
1620 _Meshes.clear();
1621 _MeshVertexBuffers.clear();
1624 //====================================================================================
1625 void CPSConstraintMesh::clean(void)
1627 NL_PS_FUNC(CPSConstraintMesh_clean)
1628 if (_ModelBank)
1630 releaseShapes();
1635 //====================================================================================
1636 CVertexBuffer &CPSConstraintMesh::makePrerotatedVb(const CVertexBuffer &inVb)
1638 NL_PS_FUNC(CPSConstraintMesh_makePrerotatedVb)
1639 // get a VB that has positions and eventually normals
1640 CVertexBuffer &prerotatedVb = inVb.getVertexFormat() & CVertexBuffer::NormalFlag ? _PreRotatedMeshVBWithNormal : _PreRotatedMeshVB;
1641 CVertexBufferReadWrite vba;
1642 prerotatedVb.lock (vba);
1643 CVertexBufferRead vbaIn;
1644 inVb.lock (vbaIn);
1646 // size of vertices for source VB
1647 const uint vSize = inVb.getVertexSize();
1649 // size for vertices in prerotated model
1650 const uint vpSize = prerotatedVb.getVertexSize();
1653 // offset of normals in vertices of the prerotated model, and source model
1654 uint normalOff=0;
1655 uint pNormalOff=0;
1656 if (prerotatedVb.getVertexFormat() & CVertexBuffer::NormalFlag)
1658 normalOff = inVb.getNormalOff();
1659 pNormalOff = prerotatedVb.getNormalOff();
1662 const uint nbVerticesInSource = inVb.getNumVertices();
1665 // rotate basis
1666 // and compute the set of prerotated meshs that will then duplicated (with scale and translation) to create the Vb of what must be drawn
1667 uint8 *outVertex = (uint8 *) vba.getVertexCoordPointer();
1668 for (CPSVector<CPlaneBasisPair>::V::iterator it = _PrecompBasis.begin(); it != _PrecompBasis.end(); ++it)
1670 // not optimized at all, but this will apply to very few elements anyway...
1671 CMatrix mat;
1672 mat.rotate(CQuat(it->Axis, CParticleSystem::EllapsedTime * it->AngularVelocity));
1673 CVector n = mat * it->Basis.getNormal();
1674 it->Basis = CPlaneBasis(n);
1676 mat.identity();
1677 mat.setRot(it->Basis.X, it->Basis.Y, it->Basis.X ^ it->Basis.Y);
1679 uint8 *inVertex = (uint8 *) vbaIn.getVertexCoordPointer();
1681 uint k = nbVerticesInSource;
1683 // check whether we need to rotate normals as well...
1684 if (inVb.getVertexFormat() & CVertexBuffer::NormalFlag)
1689 CHECK_VERTEX_BUFFER(inVb, inVertex);
1690 CHECK_VERTEX_BUFFER(inVb, inVertex + normalOff);
1691 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex);
1692 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex + pNormalOff);
1694 * (CVector *) outVertex = mat.mulVector(* (CVector *) inVertex);
1695 * (CVector *) (outVertex + normalOff) = mat.mulVector(* (CVector *) (inVertex + pNormalOff) );
1696 outVertex += vpSize;
1697 inVertex += vSize;
1700 while (--k);
1702 else
1704 // no normal included
1708 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex);
1709 CHECK_VERTEX_BUFFER(inVb, inVertex);
1711 * (CVector *) outVertex = mat.mulVector(* (CVector *) inVertex);
1712 outVertex += vpSize;
1713 inVertex += vSize;
1715 while (--k);
1719 return prerotatedVb;
1723 //====================================================================================
1724 void CPSConstraintMesh::step(TPSProcessPass pass)
1726 NL_PS_FUNC(CPSConstraintMesh_step)
1727 if (
1728 (pass == PSBlendRender && hasTransparentFaces())
1729 || (pass == PSSolidRender && hasOpaqueFaces())
1732 draw(pass == PSSolidRender);
1734 else
1735 if (pass == PSToolRender) // edition mode only
1737 showTool();
1741 //====================================================================================
1742 void CPSConstraintMesh::draw(bool opaque)
1744 // if (!FilterPS[4]) return;
1745 NL_PS_FUNC(CPSConstraintMesh_draw)
1746 PARTICLES_CHECK_MEM;
1747 nlassert(_Owner);
1749 update(); // update mesh datas if needed
1750 uint32 step;
1751 uint numToProcess;
1752 computeSrcStep(step, numToProcess);
1753 if (!numToProcess) return;
1754 _Owner->incrementNbDrawnParticles(numToProcess); // for benchmark purpose
1757 if (_PrecompBasis.empty()) /// do we deal with prerotated meshs ?
1759 if (step == (1 << 16))
1761 CPSConstraintMeshHelper::drawMeshs(_Owner->getPos().begin(),
1762 *this,
1763 numToProcess,
1764 step,
1765 opaque
1768 else
1770 CPSConstraintMeshHelper::drawMeshs(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
1771 *this,
1772 numToProcess,
1773 step,
1774 opaque
1778 else
1780 if (step == (1 << 16))
1782 CPSConstraintMeshHelper::drawPrerotatedMeshs(_Owner->getPos().begin(),
1783 _IndexInPrecompBasis.begin(),
1784 *this,
1785 numToProcess,
1786 step,
1787 opaque
1790 else
1792 typedef CAdvance1616Iterator<CPSVector<uint32>::V::const_iterator, uint32> TIndexIterator;
1793 CPSConstraintMeshHelper::drawPrerotatedMeshs(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
1794 TIndexIterator(_IndexInPrecompBasis.begin(), 0, step),
1795 *this,
1796 numToProcess,
1797 step,
1798 opaque
1806 //====================================================================================
1807 void CPSConstraintMesh::setupMaterialColor(CMaterial &destMat, CMaterial &srcMat)
1809 NL_PS_FUNC(CPSConstraintMesh_setupMaterialColor)
1810 if (destMat.getShader() != CMaterial::Normal) return;
1811 for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
1813 if (_ModulatedStages & (1 << k))
1815 destMat.texEnvArg0RGB(k, CMaterial::Texture, CMaterial::SrcColor);
1816 destMat.texEnvArg0Alpha(k, CMaterial::Texture, CMaterial::SrcAlpha);
1817 destMat.texEnvArg1RGB(k, CMaterial::Diffuse, CMaterial::SrcColor);
1818 destMat.texEnvArg1Alpha(k, CMaterial::Diffuse, CMaterial::SrcAlpha);
1819 destMat.texEnvOpRGB(k, CMaterial::Modulate);
1820 destMat.texEnvOpAlpha(k, CMaterial::Modulate);
1822 else // restore from source material
1824 destMat.setTexEnvMode(k, srcMat.getTexEnvMode(k));
1827 if (_ColorScheme == NULL) // per mesh color ?
1829 destMat.setColor(_Color);
1830 if (destMat.isLighted())
1832 destMat.setDiffuse(_Color);
1840 //====================================================================================
1841 void CPSConstraintMesh::setupRenderPasses(float date, TRdrPassSet &rdrPasses, bool opaque)
1843 NL_PS_FUNC(CPSConstraintMesh_setupRenderPasses)
1844 // render meshs : we process each rendering pass
1845 for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin();
1846 rdrPassIt != rdrPasses.end(); ++rdrPassIt)
1849 CMaterial &Mat = rdrPassIt->Mat;
1850 CMaterial &SourceMat = rdrPassIt->SourceMat;
1853 /// check whether this material has to be rendered
1854 if ((opaque && Mat.getZWrite()) || (!opaque && ! Mat.getZWrite()))
1858 // has to setup material constant color ?
1859 // global color not supported for mesh
1860 /* CParticleSystem &ps = *(_Owner->getOwner());
1861 if (!_ColorScheme)
1863 NLMISC::CRGBA col;
1864 col.modulateFromColor(SourceMat.getColor(), _Color);
1865 if (ps.getColorAttenuationScheme() == NULL || ps.isUserColorUsed())
1867 col.modulateFromColor(col, ps.getGlobalColor());
1869 Mat.setColor(col);
1871 else
1873 Mat.setColor(ps.getGlobalColor());
1876 /** Force modulation for some stages & setup global color
1878 setupMaterialColor(Mat, SourceMat);
1880 /// force vertex lighting
1881 bool forceVertexcolorLighting;
1882 if (_ColorScheme != NULL)
1884 forceVertexcolorLighting = _VertexColorLightingForced != 0 ? true : SourceMat.getLightedVertexColor();
1886 else
1888 forceVertexcolorLighting = false;
1890 if (forceVertexcolorLighting != Mat.getLightedVertexColor()) // avoid to touch mat if not needed
1892 Mat.setLightedVertexColor(forceVertexcolorLighting);
1895 ///global texture animation
1896 if (_GlobalAnimationEnabled != 0)
1898 for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
1900 if (Mat.getTexture(k) != NULL)
1902 Mat.enableUserTexMat(k, true);
1903 CMatrix mat;
1904 _GlobalTexAnims->Anims[k].buildMatrix(date, mat);
1905 Mat.setUserTexMat(k ,mat);
1914 //====================================================================================
1915 void CPSConstraintMesh::doRenderPasses(IDriver *driver, uint numObj, TRdrPassSet &rdrPasses, bool opaque)
1917 NL_PS_FUNC(CPSConstraintMesh_doRenderPasses)
1918 // render meshs : we process each rendering pass
1919 for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin(); rdrPassIt != rdrPasses.end(); ++rdrPassIt)
1921 CMaterial &Mat = rdrPassIt->Mat;
1922 if ((opaque && Mat.getZWrite()) || (!opaque && ! Mat.getZWrite()))
1924 /// setup number of primitives to be rendered
1925 rdrPassIt->PbTri.setNumIndexes(((rdrPassIt->PbTri.capacity()/3) * numObj / ConstraintMeshBufSize) * 3);
1926 rdrPassIt->PbLine.setNumIndexes(((rdrPassIt->PbLine.capacity()/2) * numObj / ConstraintMeshBufSize) * 2);
1928 /// render the primitives
1929 driver->activeIndexBuffer (rdrPassIt->PbTri);
1930 driver->renderTriangles(rdrPassIt->Mat, 0, rdrPassIt->PbTri.getNumIndexes()/3);
1931 if (rdrPassIt->PbLine.getNumIndexes() != 0)
1933 driver->activeIndexBuffer (rdrPassIt->PbLine);
1934 driver->renderLines(rdrPassIt->Mat, 0, rdrPassIt->PbLine.getNumIndexes()/2);
1942 //====================================================================================
1943 void CPSConstraintMesh::computeColors(CVertexBuffer &outVB, const CVertexBuffer &inVB, uint startIndex, uint toProcess, uint32 srcStep, IDriver &drv,
1944 CVertexBufferReadWrite &vba,
1945 CVertexBufferRead &vbaIn
1948 NL_PS_FUNC(CPSConstraintMesh_computeColors)
1949 nlassert(_ColorScheme);
1950 // there are 2 case : 1 - the source mesh has colors, which are modulated with the current color
1951 // 2 - the source mesh has no colors : colors are directly copied into the dest vb
1953 if (inVB.getVertexFormat() & CVertexBuffer::PrimaryColorFlag) // case 1
1955 // TODO: optimisation : avoid to duplicate colors...
1956 _ColorScheme->makeN(_Owner, startIndex, vba.getColorPointer(), outVB.getVertexSize(), toProcess, inVB.getNumVertices(), srcStep);
1957 // modulate from the source mesh
1958 // todo hulud d3d vertex color RGBA / BGRA
1959 uint8 *vDest = (uint8 *) vba.getColorPointer();
1960 uint8 *vSrc = (uint8 *) vbaIn.getColorPointer();
1961 const uint vSize = outVB.getVertexSize();
1962 const uint numVerts = inVB.getNumVertices();
1963 uint meshSize = vSize * numVerts;
1964 for (uint k = 0; k < toProcess; ++k)
1966 NLMISC::CRGBA::modulateColors((CRGBA *) vDest, (CRGBA *) vSrc, (CRGBA *) vDest, numVerts, vSize, vSize);
1967 vDest += meshSize;
1970 else // case 2
1972 _ColorScheme->makeN(_Owner, startIndex, vba.getColorPointer(), outVB.getVertexSize(), toProcess, inVB.getNumVertices(), srcStep);
1977 //====================================================================================
1978 void CPSConstraintMesh::newElement(const CPSEmitterInfo &info)
1980 NL_PS_FUNC(CPSConstraintMesh_newElement)
1981 newSizeElement(info);
1982 newPlaneBasisElement(info);
1983 // TODO : avoid code duplication with CPSFace ...
1984 const uint32 nbConf = (uint32)_PrecompBasis.size();
1985 if (nbConf) // do we use precomputed basis ?
1987 _IndexInPrecompBasis[_Owner->getNewElementIndex()] = rand() % nbConf;
1989 newColorElement(info);
1990 if (_GlobalAnimationEnabled && _ReinitGlobalAnimTimeOnNewElement)
1992 _GlobalAnimDate = _Owner->getOwner()->getSystemDate();
1994 if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->newElement(info);
1997 //====================================================================================
1998 void CPSConstraintMesh::deleteElement(uint32 index)
2000 NL_PS_FUNC(CPSConstraintMesh_deleteElement)
2001 deleteSizeElement(index);
2002 deletePlaneBasisElement(index);
2003 // TODO : avoid code cuplication with CPSFace ...
2004 if (!_PrecompBasis.empty()) // do we use precomputed basis ?
2006 // replace ourself by the last element...
2007 _IndexInPrecompBasis[index] = _IndexInPrecompBasis[_Owner->getSize() - 1];
2009 deleteColorElement(index);
2010 if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->deleteElement(index);
2013 //====================================================================================
2014 void CPSConstraintMesh::resize(uint32 size)
2016 NL_PS_FUNC(CPSConstraintMesh_resize)
2017 nlassert(size < (1 << 16));
2018 resizeSize(size);
2019 resizePlaneBasis(size);
2020 // TODO : avoid code cuplication with CPSFace ...
2021 if (!_PrecompBasis.empty()) // do we use precomputed basis ?
2023 _IndexInPrecompBasis.resize(size);
2025 resizeColor(size);
2026 if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->resize(size, _Owner->getSize());
2029 //====================================================================================
2030 void CPSConstraintMesh::updateMatAndVbForColor(void)
2032 NL_PS_FUNC(CPSConstraintMesh_updateMatAndVbForColor)
2033 // nothing to do for us...
2036 //====================================================================================
2037 void CPSConstraintMesh::forceStageModulationByColor(uint stage, bool force)
2039 NL_PS_FUNC(CPSConstraintMesh_forceStageModulationByColor)
2040 nlassert(stage < IDRV_MAT_MAXTEXTURES);
2041 if (force)
2043 _ModulatedStages |= 1 << stage;
2045 else
2047 _ModulatedStages &= ~(1 << stage);
2051 //====================================================================================
2052 bool CPSConstraintMesh::isStageModulationForced(uint stage) const
2054 NL_PS_FUNC(CPSConstraintMesh_isStageModulationForced)
2055 nlassert(stage < IDRV_MAT_MAXTEXTURES);
2056 return (_ModulatedStages & (1 << stage)) != 0;
2059 //====================================================================================
2061 /** This duplicate a primitive block n time in the destination primitive block
2062 * This is used to draw several mesh at once
2063 * For each duplication, vertices indices are shifted from the given offset (number of vertices in the mesh)
2066 static void DuplicatePrimitiveBlock(const CIndexBuffer &srcBlock, CIndexBuffer &destBlock, uint nbReplicate, uint vertOffset)
2068 NL_PS_FUNC(DuplicatePrimitiveBlock)
2069 PARTICLES_CHECK_MEM;
2071 // this must be update each time a new primitive is added
2073 // loop counters, and index of the current primitive in the dest pb
2074 uint k, l, index;
2076 // the current vertex offset.
2077 uint currVertOffset;
2080 // duplicate triangles
2081 uint numTri = srcBlock.getNumIndexes()/3;
2082 destBlock.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
2083 destBlock.setNumIndexes(3 * numTri * nbReplicate);
2085 index = 0;
2086 currVertOffset = 0;
2088 CIndexBufferRead ibaRead;
2089 srcBlock.lock (ibaRead);
2090 CIndexBufferReadWrite ibaWrite;
2091 destBlock.lock (ibaWrite);
2093 #ifdef NL_FORCE_INDEX_BUFFER_16
2094 nlassert(destBlock.getFormat() == CIndexBuffer::Indices16);
2095 #endif
2097 // TMP TMP TMP
2098 if (ibaRead.getFormat() == CIndexBuffer::Indices16)
2100 const TIndexType *triPtr = (TIndexType *) ibaRead.getPtr();
2101 const TIndexType *currTriPtr; // current Tri
2102 for (k = 0; k < nbReplicate; ++k)
2104 currTriPtr = triPtr;
2105 for (l = 0; l < numTri; ++l)
2107 ibaWrite.setTri(3*index, currTriPtr[0] + currVertOffset, currTriPtr[1] + currVertOffset, currTriPtr[2] + currVertOffset);
2108 currTriPtr += 3;
2109 ++ index;
2111 currVertOffset += vertOffset;
2114 else
2116 const uint32 *triPtr = (uint32 *) ibaRead.getPtr();
2117 const uint32 *currTriPtr; // current Tri
2118 for (k = 0; k < nbReplicate; ++k)
2120 currTriPtr = triPtr;
2121 for (l = 0; l < numTri; ++l)
2123 nlassert(currTriPtr[0] + currVertOffset <= 0xffff);
2124 nlassert(currTriPtr[1] + currVertOffset <= 0xffff);
2125 nlassert(currTriPtr[2] + currVertOffset <= 0xffff);
2127 ibaWrite.setTri(3*index, (uint16) (currTriPtr[0] + currVertOffset), (uint16) (currTriPtr[1] + currVertOffset), (uint16) (currTriPtr[2] + currVertOffset));
2128 currTriPtr += 3;
2129 ++ index;
2131 currVertOffset += vertOffset;
2137 // TODO quad / strips duplication : (unimplemented in primitive blocks for now)
2139 PARTICLES_CHECK_MEM;
2142 //====================================================================================
2143 void CPSConstraintMesh::initPrerotVB()
2145 NL_PS_FUNC(CPSConstraintMesh_initPrerotVB)
2146 // position, no normals
2147 _PreRotatedMeshVB.setVertexFormat(CVertexBuffer::PositionFlag);
2148 _PreRotatedMeshVB.setNumVertices(ConstraintMeshMaxNumPrerotatedModels * ConstraintMeshMaxNumVerts);
2149 _PreRotatedMeshVB.setName("CPSConstraintMesh::_PreRotatedMeshVB");
2151 // position & normals
2152 _PreRotatedMeshVBWithNormal.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag);
2153 _PreRotatedMeshVBWithNormal.setNumVertices(ConstraintMeshMaxNumPrerotatedModels * ConstraintMeshMaxNumVerts);
2154 _PreRotatedMeshVB.setName("CPSConstraintMesh::_PreRotatedMeshVBWithNormal");
2157 //====================================================================================
2158 CPSConstraintMesh::CMeshDisplay &CPSConstraintMesh::CMeshDisplayShare::getMeshDisplay(CMesh *mesh, const CVertexBuffer &meshVB, uint32 format)
2160 NL_PS_FUNC(CMeshDisplayShare_getMeshDisplay)
2161 nlassert(mesh);
2162 // linear search is ok because of small size
2163 for(std::list<CMDEntry>::iterator it = _Cache.begin(); it != _Cache.end(); ++it)
2165 if (it->Format == format && it->Mesh == mesh)
2167 // relink at start (most recent use)
2168 _Cache.splice(_Cache.begin(), _Cache, it);
2169 return it->MD;
2172 if (_NumMD == _MaxNumMD)
2174 _Cache.pop_back(); // remove least recently used mesh
2175 -- _NumMD;
2177 //NLMISC::TTicks start = NLMISC::CTime::getPerformanceTime();
2178 _Cache.push_front(CMDEntry());
2179 _Cache.front().Mesh = mesh;
2180 _Cache.front().Format = format;
2181 buildRdrPassSet(_Cache.front().MD.RdrPasses, *mesh);
2182 _Cache.front().MD.VB.setName("CPSConstraintMesh::CMeshDisplay");
2183 buildVB(_Cache.front().MD.VB, meshVB, format);
2184 ++ _NumMD;
2185 /*NLMISC::TTicks end = NLMISC::CTime::getPerformanceTime();
2186 nlinfo("mesh setup time = %.2f", (float) (1000 * NLMISC::CTime::ticksToSecond(end - start))); */
2187 return _Cache.front().MD;
2190 //====================================================================================
2191 void CPSConstraintMesh::CMeshDisplayShare::buildRdrPassSet(TRdrPassSet &dest, const CMesh &m)
2193 NL_PS_FUNC(CMeshDisplayShare_buildRdrPassSet)
2194 // we don't support skinning for mesh particles, so there must be only one matrix block
2195 nlassert(m.getNbMatrixBlock() == 1); // SKINNING UNSUPPORTED
2197 dest.resize(m.getNbRdrPass(0));
2198 const CVertexBuffer &srcVb = m.getVertexBuffer();
2200 for (uint k = 0; k < m.getNbRdrPass(0); ++k)
2202 dest[k].Mat = m.getMaterial(m.getRdrPassMaterial(0, k));
2203 dest[k].SourceMat = dest[k].Mat;
2204 DuplicatePrimitiveBlock(m.getRdrPassPrimitiveBlock(0, k), dest[k].PbTri, ConstraintMeshBufSize, srcVb.getNumVertices() );
2210 //====================================================================================
2211 void CPSConstraintMesh::CMeshDisplayShare::buildVB(CVertexBuffer &dest, const CVertexBuffer &meshVb, uint32 destFormat)
2213 NL_PS_FUNC(CMeshDisplayShare_buildVB)
2214 /// we duplicate the original mesh data's 'ConstraintMeshBufSize' times, eventually adding a color
2215 nlassert(destFormat == meshVb.getVertexFormat() || destFormat == (meshVb.getVertexFormat() | (uint32) CVertexBuffer::PrimaryColorFlag) );
2216 dest.setVertexFormat(destFormat);
2217 dest.setPreferredMemory(CVertexBuffer::AGPVolatile, true);
2218 dest.setNumVertices(ConstraintMeshBufSize * meshVb.getNumVertices());
2219 for(uint k = 0; k < CVertexBuffer::MaxStage; ++k)
2221 dest.setUVRouting((uint8) k, meshVb.getUVRouting()[k]);
2224 CVertexBufferReadWrite vba;
2225 dest.lock (vba);
2226 CVertexBufferRead vbaIn;
2227 meshVb.lock (vbaIn);
2229 uint8 *outPtr = (uint8 *) vba.getVertexCoordPointer();
2230 uint8 *inPtr = (uint8 *) vbaIn.getVertexCoordPointer();
2231 uint meshSize = dest.getVertexSize() * meshVb.getNumVertices();
2233 if (destFormat == meshVb.getVertexFormat()) // no color added
2235 for (uint k = 0; k < ConstraintMeshBufSize; ++k)
2237 ::memcpy((void *) (outPtr + k * meshSize), (void *) inPtr, meshSize);
2240 else // color added, but not available in src
2242 sint colorOff = dest.getColorOff();
2243 uint inVSize = meshVb.getVertexSize();
2244 uint outVSize = dest.getVertexSize();
2245 for (uint k = 0; k < ConstraintMeshBufSize; ++k)
2247 for (uint v = 0; v < meshVb.getNumVertices(); ++v)
2249 // copy until color
2250 ::memcpy((void *) (outPtr + k * meshSize + v * outVSize), (void *) (inPtr + v * inVSize), colorOff);
2251 // copy datas after color
2252 ::memcpy((void *) (outPtr + k * meshSize + v * outVSize + colorOff + sizeof(uint8[4])), (void *) (inPtr + v * inVSize + colorOff), inVSize - colorOff);
2259 //=====================================================================================
2260 CPSConstraintMesh::CGlobalTexAnim::CGlobalTexAnim() : TransOffset(NLMISC::CVector2f::Null),
2261 TransSpeed(NLMISC::CVector2f::Null),
2262 TransAccel(NLMISC::CVector2f::Null),
2263 ScaleStart(1 ,1),
2264 ScaleSpeed(NLMISC::CVector2f::Null),
2265 ScaleAccel(NLMISC::CVector2f::Null),
2266 WRotSpeed(0),
2267 WRotAccel(0)
2269 NL_PS_FUNC(CGlobalTexAnim_CGlobalTexAnim)
2272 //=====================================================================================
2273 void CPSConstraintMesh::CGlobalTexAnim::serial(NLMISC::IStream &f)
2275 NL_PS_FUNC(CGlobalTexAnim_IStream )
2276 // version 1 : added offset
2277 sint ver = f.serialVersion(1);
2278 if (ver >= 1)
2280 f.serial(TransOffset);
2282 f.serial(TransSpeed, TransAccel, ScaleStart, ScaleSpeed, ScaleAccel);
2283 f.serial(WRotSpeed, WRotAccel);
2286 //=====================================================================================
2287 void CPSConstraintMesh::CGlobalTexAnim::buildMatrix(float date, NLMISC::CMatrix &dest)
2289 NL_PS_FUNC(CGlobalTexAnim_buildMatrix)
2290 float fDate = (float) date;
2291 float halfDateSquared = 0.5f * fDate * fDate;
2292 NLMISC::CVector2f pos = fDate * TransSpeed + halfDateSquared * fDate * TransAccel + TransOffset;
2293 NLMISC::CVector2f scale = ScaleStart + fDate * ScaleSpeed + halfDateSquared * fDate * ScaleAccel;
2294 float rot = fDate * WRotSpeed + halfDateSquared * WRotAccel;
2297 float fCos, fSin;
2298 if (rot != 0.f)
2300 fCos = ::cosf(- rot);
2301 fSin = ::sinf(- rot);
2303 else
2305 fCos = 1.f;
2306 fSin = 0.f;
2309 NLMISC::CVector I(fCos, fSin, 0);
2310 NLMISC::CVector J(-fSin, fCos, 0);
2311 dest.setRot(scale.x * I, scale.y * J, NLMISC::CVector::K);
2312 NLMISC::CVector center(-0.5f, -0.5f, 0.f);
2313 NLMISC::CVector t(pos.x, pos.y, 0);
2314 dest.setPos(t + dest.mulVector(center) - center);
2317 //=====================================================================================
2318 void CPSConstraintMesh::setGlobalTexAnim(uint stage, const CGlobalTexAnim &properties)
2320 NL_PS_FUNC(CPSConstraintMesh_setGlobalTexAnim)
2321 nlassert(_GlobalAnimationEnabled != 0);
2322 nlassert(stage < IDRV_MAT_MAXTEXTURES);
2323 nlassert(_GlobalTexAnims.get());
2324 _GlobalTexAnims->Anims[stage] = properties;
2327 //=====================================================================================
2328 const CPSConstraintMesh::CGlobalTexAnim &CPSConstraintMesh::getGlobalTexAnim(uint stage) const
2330 NL_PS_FUNC(CPSConstraintMesh_getGlobalTexAnim)
2331 nlassert(_GlobalAnimationEnabled != 0);
2332 nlassert(stage < IDRV_MAT_MAXTEXTURES);
2333 nlassert(_GlobalTexAnims.get());
2334 return _GlobalTexAnims->Anims[stage];
2338 //=====================================================================================
2339 CPSConstraintMesh::TTexAnimType CPSConstraintMesh::getTexAnimType() const
2341 NL_PS_FUNC(CPSConstraintMesh_getTexAnimType)
2342 return (TTexAnimType) (_GlobalAnimationEnabled != 0 ? GlobalAnim : NoAnim);
2345 //=====================================================================================
2346 void CPSConstraintMesh::setTexAnimType(TTexAnimType type)
2348 NL_PS_FUNC(CPSConstraintMesh_setTexAnimType)
2349 nlassert(type < Last);
2350 if (type == getTexAnimType()) return; // does the type of animation change ?
2351 switch (type)
2353 case NoAnim:
2354 _GlobalTexAnims.reset();
2355 restoreMaterials();
2356 _GlobalAnimationEnabled = 0;
2357 break;
2358 case GlobalAnim:
2360 PGlobalTexAnims newPtr(new CGlobalTexAnims);
2361 //std::swap(_GlobalTexAnims, newPtr);
2362 _GlobalTexAnims = CUniquePtrMove(newPtr);
2363 _GlobalAnimationEnabled = 1;
2365 break;
2366 default: break;
2370 //=====================================================================================
2371 void CPSConstraintMesh::CGlobalTexAnims::serial(NLMISC::IStream &f)
2373 NL_PS_FUNC(CGlobalTexAnims_IStream )
2374 f.serialVersion(0);
2375 for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
2377 f.serial(Anims[k]);
2381 //=====================================================================================
2382 void CPSConstraintMesh::restoreMaterials()
2384 NL_PS_FUNC(CPSConstraintMesh_restoreMaterials)
2385 update();
2386 CMeshDisplay &md= _MeshDisplayShare.getMeshDisplay(_Meshes[0], getMeshVB(0), _Meshes[0]->getVertexBuffer().getVertexFormat() | (_ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
2387 TRdrPassSet rdrPasses = md.RdrPasses;
2388 // render meshs : we process each rendering pass
2389 for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin(); rdrPassIt != rdrPasses.end(); ++rdrPassIt)
2391 rdrPassIt->Mat = rdrPassIt->SourceMat;
2395 //=====================================================================================
2396 const CVertexBuffer &CPSConstraintMesh::getMeshVB(uint index)
2398 nlassert(!_Touched);
2399 nlassert(index < _Meshes.size());
2400 nlassert(_MeshVertexBuffers.size() == _Meshes.size());
2401 const CVertexBuffer *vb = _MeshVertexBuffers[index];
2402 if (!vb )
2404 CMesh &mesh = * NLMISC::safe_cast<CMesh *>((IShape *) _Meshes[index]);
2405 vb = _MeshVertexBuffers[index] = &mesh.getVertexBuffer();
2407 if (vb->getLocation() != CVertexBuffer::NotResident)
2409 TMeshName2RamVB::iterator it = _MeshRamVBs.find(_MeshShapeFileName[index]);
2410 if (it == _MeshRamVBs.end())
2412 CVertexBuffer &destVb = _MeshRamVBs[_MeshShapeFileName[index]];
2413 CMesh &mesh = * NLMISC::safe_cast<CMesh *>((IShape *) _Meshes[index]);
2414 mesh.getVertexBuffer().copyVertices(destVb);
2415 _MeshVertexBuffers[index] = vb = &destVb;
2417 else
2419 _MeshVertexBuffers[index] = vb = &it->second;
2422 nlassert(vb->getLocation() == CVertexBuffer::NotResident);
2423 return *vb;
2426 //=====================================================================================
2427 void CPSMesh::onShow(bool shown)
2429 for(uint k = 0; k < _Instances.getSize(); ++k)
2431 if (_Instances[k])
2433 if (shown)
2435 _Instances[k]->show();
2437 else
2439 _Instances[k]->hide();
2445 } // NL3D