1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2011 Robert TIMM (rti) <mail@rtti.de>
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/>.
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"
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)
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
)
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,
121 for (uint k
= 0; k
< 6; ++k
)
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);
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);
147 mb
.Faces
.push_back(f
);
151 CTextureMem
*tex
= new CTextureMem
;
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
;
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
);
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;
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)
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)
214 //====================================================================================
215 bool CPSMesh::hasOpaqueFaces(void)
217 NL_PS_FUNC(CPSMesh_hasOpaqueFaces
)
218 /// We don't draw any tri !
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)
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
)
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
);
262 // mesh not found ...
263 IShape
*is
= CreateDummyMesh();
264 scene
->getShapeBank()->add(DummyShapeName
, is
);
265 instance
= scene
->createInstance(DummyShapeName
);
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
273 //====================================================================================
274 void CPSMesh::newElement(const CPSEmitterInfo
&info
)
276 NL_PS_FUNC(CPSMesh_newElement
)
277 newPlaneBasisElement(info
);
278 newAngle2DElement(info
);
279 newSizeElement(info
);
281 nlassert(_Owner
->getOwner());
282 CTransformShape
*instance
= createInstance();
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
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
)
316 if (pass
== PSToolRender
) // edition mode only
322 //====================================================================================
323 void CPSMesh::updatePos()
325 NL_PS_FUNC(CPSMesh_updatePos
)
326 const uint MeshBufSize
= 512;
329 const uint32 size
= _Owner
->getSize();
333 _Owner
->incrementNbDrawnParticles(size
); // for benchmark purpose
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
;
353 const uint ptCurrSizeIncrement
= _SizeScheme
? 1 : 0;
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
;
372 ptCurrSize
= (float *) (_SizeScheme
->make(_Owner
, size
- leftToDo
, &sizes
[0], sizeof(float), toProcess
, true));
376 ptCurrSize
=& _ParticleSize
;
381 ptCurrAngle
= (float *) (_Angle2DScheme
->make(_Owner
, size
- leftToDo
, &angles
[0], sizeof(float), toProcess
, true));
385 ptCurrAngle
=& _Angle2D
;
389 if (_PlaneBasisScheme
)
391 ptBasis
= (CPlaneBasis
*) (_PlaneBasisScheme
->make(_Owner
, size
- leftToDo
, &planeBasis
[0], sizeof(CPlaneBasis
), toProcess
, true));
395 ptBasis
= &_PlaneBasis
;
398 endPosIt
= posIt
+ toProcess
;
401 // the matrix used to get in the right basis
402 const CMatrix
&transfo
= getLocalToWorldMatrix();
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();
430 (*instanceIt
)->hide();
432 (*instanceIt
)->setClusterSystem(CParticleSystem::OwnerModel
->getClusterSystem());
437 ptCurrSize
+= ptCurrSizeIncrement
;
438 ptCurrAngle
+= ptCurrAngleIncrement
;
439 ptBasis
+= ptCurrPlaneBasisIncrement
;
441 while (posIt
!= endPosIt
);
442 leftToDo
-= toProcess
;
449 //====================================================================================
450 void CPSMesh::resize(uint32 size
)
452 NL_PS_FUNC(CPSMesh_resize
)
453 nlassert(size
< (1 << 16));
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 //====================================================================================
471 NL_PS_FUNC(CPSMesh_CPSMeshDtor
)
472 if (_Owner
&& _Owner
->getOwner())
474 removeAllInstancesFromScene();
479 for (TInstanceCont::iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
481 nlassert(*it
== NULL
); // there's a leak..:(
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
)
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;
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;
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
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
564 IDriver
*driver
= m
.getDriver();
565 m
.setupDriverModelMatrix();
567 // buffer to compute sizes
568 float sizes
[ConstraintMeshBufSize
];
571 uint ptCurrSizeIncrement
= m
._SizeScheme
? 1 : 0;
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();
596 if (modelVb
.getVertexFormat() & CVertexBuffer::NormalFlag
)
598 inNormalOff
= modelVb
.getNormalOff();
599 outNormalOff
= outVb
.getNormalOff();
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
;
619 uint8
*outVertex
= (uint8
*) vba
.getVertexCoordPointer();
622 ptCurrSize
= (float *) (m
._SizeScheme
->make(m
._Owner
, size
-leftToDo
, &sizes
[0], sizeof(float), toProcess
, true, srcStep
));
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
));
635 ptBasis
= &m
._PlaneBasis
;
639 endPosIt
= posIt
+ toProcess
;
640 // transfo matrix & scaled transfo matrix;
644 if (m
._Meshes
.size() == 1)
649 const uint8
*inVertex
= (const uint8
*) vbaRead
.getVertexCoordPointer();
650 uint k
= nbVerticesInSource
;
652 // do we need a normal ?
653 if (modelVb
.getVertexFormat() & CVertexBuffer::NormalFlag
)
656 M
.setRot(ptBasis
->X
, ptBasis
->Y
, ptBasis
->X
^ ptBasis
->Y
);
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
;
671 *(CVector
*) (outVertex
+ outNormalOff
) = M
* *(CVector
*) (inVertex
+ inNormalOff
);
675 outVertex
+= outVSize
;
681 // no normal to transform
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
;
695 outVertex
+= outVSize
;
702 ptCurrSize
+= ptCurrSizeIncrement
;
703 ptBasis
+= ptBasisIncrement
;
705 while (posIt
!= endPosIt
);
711 // first, compute the morph value for each mesh
712 float morphValues
[ConstraintMeshBufSize
];
713 float *currMorphValue
;
716 if (m
._MorphScheme
) // variable case
718 currMorphValue
= (float *) m
._MorphScheme
->make(m
._Owner
, size
- leftToDo
, &morphValues
[0], sizeof(float), toProcess
, true, srcStep
);
721 else /// constant case
723 currMorphValue
= &m
._MorphValue
;
729 const uint numShapes
= (uint
)m
._Meshes
.size();
730 const uint8
*m0
, *m1
;
733 const CVertexBuffer
*inVB0
, *inVB1
;
734 if (*currMorphValue
>= numShapes
- 1)
738 inVB0
= inVB1
= &(m
.getMeshVB(numShapes
- 1));
740 else if (*currMorphValue
<= 0)
744 inVB0
= inVB1
= &(m
.getMeshVB(0));
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
;
756 CVertexBufferRead 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
)
768 M
.setRot(ptBasis
->X
, ptBasis
->Y
, ptBasis
->X
^ ptBasis
->Y
);
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();
791 outVertex
+= outVSize
;
797 // no normal to transform
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
);
812 outVertex
+= outVSize
;
819 ptCurrSize
+= ptCurrSizeIncrement
;
820 ptBasis
+= ptBasisIncrement
;
821 currMorphValue
+= morphValueIncr
;
823 while (posIt
!= endPosIt
);
826 // compute colors if needed
829 m
.computeColors(outVb
, modelVb
, size
- leftToDo
, toProcess
, srcStep
, *driver
, vba
, vbaRead
);
834 driver
->activeVertexBuffer(outVb
);
835 m
.doRenderPasses(driver
, toProcess
, md
.RdrPasses
, opaque
);
836 leftToDo
-= toProcess
;
843 template <class T
, class U
>
844 static void drawPrerotatedMeshs(T posIt
,
846 CPSConstraintMesh
&m
,
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
);
858 IDriver
*driver
= m
.getDriver();
859 m
.setupDriverModelMatrix();
861 // renderPasses setup
864 // storage for sizes of meshs
865 float sizes
[ConstraintMeshBufSize
];
867 // point the size for the current mesh
869 uint ptCurrSizeIncrement
= m
._SizeScheme
? 1 : 0;
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
900 if (prerotVb
.getVertexFormat() & CVertexBuffer::NormalFlag
)
902 normalOff
= outVb
.getNormalOff();
903 pNormalOff
= prerotVb
.getNormalOff();
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
;
930 ptCurrSize
= (float *) (m
._SizeScheme
->make(m
._Owner
, size
- leftToDo
, &sizes
[0], sizeof(float), toProcess
, true, srcStep
));
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
;
959 *(CVector
*) (outVertex
+ normalOff
) = *(CVector
*) (inVertex
+ pNormalOff
);
961 outVertex
+= outVSize
;
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
;
974 outVertex
+= outVSize
;
981 ptCurrSize
+= ptCurrSizeIncrement
;
983 while (posIt
!= endPosIt
);
985 // compute colors if needed
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
;
1003 CPSConstraintMesh::CPSConstraintMesh() : _NumFaces(0),
1005 _ModulatedStages(0),
1008 _VertexColorLightingForced(false),
1009 _GlobalAnimationEnabled(0),
1010 _ReinitGlobalAnimTimeOnNewElement(0),
1011 _HasLightableFaces(0),
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
1037 return _HasTransparentFaces
!= 0;
1040 //====================================================================================
1041 bool CPSConstraintMesh::hasOpaqueFaces(void)
1043 NL_PS_FUNC(CPSConstraintMesh_hasOpaqueFaces
)
1044 if (!_Touched
) return _HasOpaqueFaces
!= 0;
1046 return _HasOpaqueFaces
!= 0;
1049 //====================================================================================
1050 bool CPSConstraintMesh::hasLightableFaces()
1052 NL_PS_FUNC(CPSConstraintMesh_hasLightableFaces
)
1053 if (!_Touched
) return _HasLightableFaces
!= 0;
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
;
1070 //===========================================================================
1071 std::string
CPSConstraintMesh::getShape(void) const
1073 NL_PS_FUNC(CPSConstraintMesh_getShape
)
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
)
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());
1103 //====================================================================================
1104 uint
CPSConstraintMesh::getNumShapes() const
1106 NL_PS_FUNC(CPSConstraintMesh_getNumShapes
)
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
)
1120 const_cast<CPSConstraintMesh
*>(this)->update();
1123 std::copy(_MeshShapeFileName
.begin(), _MeshShapeFileName
.end(), stdext::make_unchecked_array_iterator(shapesNames
));
1125 std::copy(_MeshShapeFileName
.begin(), _MeshShapeFileName
.end(), shapesNames
);
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
;
1139 //====================================================================================
1140 const std::string
&CPSConstraintMesh::getShape(uint index
) const
1142 NL_PS_FUNC(CPSConstraintMesh_getShape
)
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
)
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
));
1205 // no dummy shape created -> add one to the bank
1206 CMesh
*m
= CreateDummyMesh();
1207 sb
.add(std::string("dummy constraint mesh shape"), m
);
1212 //====================================================================================
1213 void CPSConstraintMesh::getShapeNumVerts(std::vector
<sint
> &numVerts
)
1215 NL_PS_FUNC(CPSConstraintMesh_getShapeNumVerts
)
1216 _Touched
= 1; // force reload
1220 //====================================================================================
1221 bool CPSConstraintMesh::update(std::vector
<sint
> *numVertsVect
/*= NULL*/)
1223 NL_PS_FUNC(CPSConstraintMesh_update
)
1225 if (!_Touched
) return ok
;
1229 nlassert(_Owner
->getScene());
1231 CScene
*scene
= _Owner
->getScene();
1232 _ModelBank
= scene
->getShapeBank();
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
]));
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
);
1261 if (numVertsVect
) (*numVertsVect
)[k
] = ShapeFileIsNotAMesh
;
1266 /// get the mesh format, or check that is was the same that previous shapes ' one
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
;
1276 if (vFormat
!= mesh
->getVertexBuffer().getVertexFormat())
1278 nlwarning("Vertex format differs between meshs");
1281 if (numVerts
!= mesh
->getVertexBuffer().getNumVertices())
1283 nlwarning("Num vertices differs between meshs");
1286 if (!std::equal(mesh
->getVertexBuffer().getUVRouting(), mesh
->getVertexBuffer().getUVRouting() + CVertexBuffer::MaxStage
, uvRouting
))
1288 nlwarning("UV routing differs between meshs");
1291 if (numVertsVect
) (*numVertsVect
)[k
] = (sint
) mesh
->getVertexBuffer().getNumVertices();
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
)
1310 if (numVertsVect
) (*numVertsVect
)[k
] = ShapeFileNotLoaded
;
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
);
1320 if (numVertsVect
) (*numVertsVect
)[k
] = ShapeFileIsNotAMesh
;
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
);
1331 if (numVertsVect
) (*numVertsVect
)[k
] = ShapeHasTooMuchVertices
;
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
;
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
)))
1353 if (numVertsVect
) (*numVertsVect
)[k
] = otherNumVerts
;
1360 if (!ok
&& !numVertsVect
) break;
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();
1391 _ValidBuild
= ok
? 1 : 0;
1392 nlassert(!_Meshes
.empty());
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();
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);
1464 CPSParticle::serial(f
);
1465 CPSSizedParticle::serialSizeScheme(f
);
1466 CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f
);
1472 uint32 nbConfigurations
;
1473 f
.serial(nbConfigurations
);
1474 if (nbConfigurations
)
1476 f
.serial(_MinAngularVelocity
, _MaxAngularVelocity
);
1478 hintRotateTheSame(nbConfigurations
, _MinAngularVelocity
, _MaxAngularVelocity
);
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
1497 if (!_MeshShapeFileName
.empty())
1499 f
.serial(_MeshShapeFileName
[0]);
1508 _MeshShapeFileName
.resize(1);
1509 f
.serial(_MeshShapeFileName
[0]);
1517 CPSColoredParticle::serialColorScheme(f
);
1518 f
.serial(_ModulatedStages
);
1522 f
.serial(vcEnabled
);
1523 _VertexColorLightingForced
= vcEnabled
;
1527 bool vcEnabled
= (_VertexColorLightingForced
!= 0);
1528 f
.serial(vcEnabled
);
1532 if (ver
> 2) // texture animation
1537 f
.serial(gaEnabled
);
1538 _GlobalAnimationEnabled
= gaEnabled
;
1541 PGlobalTexAnims
newPtr(new CGlobalTexAnims
); // create new
1542 //std::swap(_GlobalTexAnims, newPtr); // replace old
1543 _GlobalTexAnims
= CUniquePtrMove(newPtr
);
1544 f
.serial(*_GlobalTexAnims
);
1549 _ReinitGlobalAnimTimeOnNewElement
= rgt
;
1553 bool gaEnabled
= (_GlobalAnimationEnabled
!= 0);
1554 f
.serial(gaEnabled
);
1557 f
.serial(*_GlobalTexAnims
);
1560 bool rgt
= _ReinitGlobalAnimTimeOnNewElement
!= 0;
1565 if (ver
> 3) // mesh morphing
1570 TMeshNameVect meshNamesWithoutPath
= _MeshShapeFileName
;
1571 std::transform(meshNamesWithoutPath
.begin(), meshNamesWithoutPath
.end(), meshNamesWithoutPath
.begin(), std::ptr_fun(NLMISC::CFile::getFilename
));
1572 f
.serialCont(meshNamesWithoutPath
);
1576 f
.serialCont(_MeshShapeFileName
);
1581 delete _MorphScheme
;
1585 useScheme
= _MorphScheme
!= NULL
;
1587 f
.serial(useScheme
);
1590 f
.serialPolyPtr(_MorphScheme
);
1594 f
.serial(_MorphValue
);
1599 //====================================================================================
1600 CPSConstraintMesh::~CPSConstraintMesh()
1602 NL_PS_FUNC(CPSConstraintMesh_CPSConstraintMeshDtor
)
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
)
1617 if (_ModelBank
) _ModelBank
->release(*it
);
1621 _MeshVertexBuffers
.clear();
1624 //====================================================================================
1625 void CPSConstraintMesh::clean(void)
1627 NL_PS_FUNC(CPSConstraintMesh_clean
)
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
;
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
1656 if (prerotatedVb
.getVertexFormat() & CVertexBuffer::NormalFlag
)
1658 normalOff
= inVb
.getNormalOff();
1659 pNormalOff
= prerotatedVb
.getNormalOff();
1662 const uint nbVerticesInSource
= inVb
.getNumVertices();
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...
1672 mat
.rotate(CQuat(it
->Axis
, CParticleSystem::EllapsedTime
* it
->AngularVelocity
));
1673 CVector n
= mat
* it
->Basis
.getNormal();
1674 it
->Basis
= CPlaneBasis(n
);
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
;
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
;
1719 return prerotatedVb
;
1723 //====================================================================================
1724 void CPSConstraintMesh::step(TPSProcessPass pass
)
1726 NL_PS_FUNC(CPSConstraintMesh_step
)
1728 (pass
== PSBlendRender
&& hasTransparentFaces())
1729 || (pass
== PSSolidRender
&& hasOpaqueFaces())
1732 draw(pass
== PSSolidRender
);
1735 if (pass
== PSToolRender
) // edition mode only
1741 //====================================================================================
1742 void CPSConstraintMesh::draw(bool opaque
)
1744 // if (!FilterPS[4]) return;
1745 NL_PS_FUNC(CPSConstraintMesh_draw
)
1746 PARTICLES_CHECK_MEM
;
1749 update(); // update mesh datas if needed
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(),
1770 CPSConstraintMeshHelper::drawMeshs(TIteratorVectStep1616(_Owner
->getPos().begin(), 0, step
),
1780 if (step
== (1 << 16))
1782 CPSConstraintMeshHelper::drawPrerotatedMeshs(_Owner
->getPos().begin(),
1783 _IndexInPrecompBasis
.begin(),
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
),
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());
1864 col.modulateFromColor(SourceMat.getColor(), _Color);
1865 if (ps.getColorAttenuationScheme() == NULL || ps.isUserColorUsed())
1867 col.modulateFromColor(col, ps.getGlobalColor());
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();
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);
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
);
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));
2019 resizePlaneBasis(size
);
2020 // TODO : avoid code cuplication with CPSFace ...
2021 if (!_PrecompBasis
.empty()) // do we use precomputed basis ?
2023 _IndexInPrecompBasis
.resize(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
);
2043 _ModulatedStages
|= 1 << stage
;
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
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
);
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
);
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
);
2111 currVertOffset
+= vertOffset
;
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
));
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
)
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
);
2172 if (_NumMD
== _MaxNumMD
)
2174 _Cache
.pop_back(); // remove least recently used mesh
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
);
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
;
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
)
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
),
2264 ScaleSpeed(NLMISC::CVector2f::Null
),
2265 ScaleAccel(NLMISC::CVector2f::Null
),
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);
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
;
2300 fCos
= ::cosf(- rot
);
2301 fSin
= ::sinf(- rot
);
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 ?
2354 _GlobalTexAnims
.reset();
2356 _GlobalAnimationEnabled
= 0;
2360 PGlobalTexAnims
newPtr(new CGlobalTexAnims
);
2361 //std::swap(_GlobalTexAnims, newPtr);
2362 _GlobalTexAnims
= CUniquePtrMove(newPtr
);
2363 _GlobalAnimationEnabled
= 1;
2370 //=====================================================================================
2371 void CPSConstraintMesh::CGlobalTexAnims::serial(NLMISC::IStream
&f
)
2373 NL_PS_FUNC(CGlobalTexAnims_IStream
)
2375 for (uint k
= 0; k
< IDRV_MAT_MAXTEXTURES
; ++k
)
2381 //=====================================================================================
2382 void CPSConstraintMesh::restoreMaterials()
2384 NL_PS_FUNC(CPSConstraintMesh_restoreMaterials
)
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
];
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
;
2419 _MeshVertexBuffers
[index
] = vb
= &it
->second
;
2422 nlassert(vb
->getLocation() == CVertexBuffer::NotResident
);
2426 //=====================================================================================
2427 void CPSMesh::onShow(bool shown
)
2429 for(uint k
= 0; k
< _Instances
.getSize(); ++k
)
2435 _Instances
[k
]->show();
2439 _Instances
[k
]->hide();