00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/ps_mesh.h"
00029 #include "3d/ps_macro.h"
00030 #include "3d/shape.h"
00031 #include "3d/mesh.h"
00032 #include "3d/transform_shape.h"
00033 #include "3d/shape_bank.h"
00034 #include "3d/texture_mem.h"
00035 #include "3d/scene.h"
00036 #include "3d/ps_located.h"
00037 #include "3d/particle_system.h"
00038 #include "3d/particle_system_shape.h"
00039 #include "3d/ps_iterator.h"
00040 #include "nel/misc/stream.h"
00041 #include "nel/misc/path.h"
00042
00043 #include <memory>
00044
00045
00046
00047
00048
00049 namespace NL3D
00050 {
00051
00053
00055
00056
00057
00058
00059 CPSConstraintMesh::CMeshDisplayShare CPSConstraintMesh::_MeshDisplayShare(16);
00060 CVertexBuffer CPSConstraintMesh::_PreRotatedMeshVB;
00061 CVertexBuffer CPSConstraintMesh::_PreRotatedMeshVBWithNormal;
00062
00063
00064
00065
00066 static CVector MakeRandomUnitVect(void)
00067 {
00068 CVector v((float) ((rand() % 20000) - 10000)
00069 ,(float) ((rand() % 20000) - 10000)
00070 ,(float) ((rand() % 20000) - 10000)
00071 );
00072 v.normalize();
00073 return v;
00074 }
00075
00076
00078
00080
00081
00082
00083
00084
00085
00086
00087 const std::string DummyShapeName("dummy mesh shape");
00088
00092 static CMesh *CreateDummyShape(void)
00093 {
00094 CMesh::CMeshBuild mb;
00095 CMeshBase::CMeshBaseBuild mbb;
00096
00097 mb.VertexFlags = CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag;
00098 mb.Vertices.push_back(CVector(-.5f, -.5f, -.5f));
00099 mb.Vertices.push_back(CVector(.5f, -.5f, -.5f));
00100 mb.Vertices.push_back(CVector(.5f, -.5f, .5f));
00101 mb.Vertices.push_back(CVector(-.5f, -.5f, .5f));
00102
00103 mb.Vertices.push_back(CVector(-.5f, .5f, -.5f));
00104 mb.Vertices.push_back(CVector(.5f, .5f, -.5f));
00105 mb.Vertices.push_back(CVector(.5f, .5f, .5f));
00106 mb.Vertices.push_back(CVector(-.5f, .5f, .5f));
00107
00108
00109 uint32 tab[] = { 4, 1, 0,
00110 4, 5, 1,
00111 5, 2, 1,
00112 5, 6, 2,
00113 6, 3, 2,
00114 6, 7, 3,
00115 7, 0, 3,
00116 7, 4, 0,
00117 7, 5, 4,
00118 7, 6, 5,
00119 2, 0, 1,
00120 2, 3, 0
00121 };
00122
00123 for (uint k = 0; k < 6; ++k)
00124 {
00125 CMesh::CFace f;
00126 f.Corner[0].Vertex = tab[6 * k];
00127 f.Corner[0].Uvws[0] = NLMISC::CUVW(0, 0, 0);
00128
00129 f.Corner[1].Vertex = tab[6 * k + 1];
00130 f.Corner[1].Uvws[0] = NLMISC::CUVW(1, 1, 0);
00131
00132 f.Corner[2].Vertex = tab[6 * k + 2];
00133 f.Corner[2].Uvws[0] = NLMISC::CUVW(0, 1, 0);
00134
00135 f.MaterialId = 0;
00136
00137 mb.Faces.push_back(f);
00138
00139 f.Corner[0].Vertex = tab[6 * k + 3];
00140 f.Corner[0].Uvws[0] = NLMISC::CUVW(0, 0, 0);
00141
00142 f.Corner[1].Vertex = tab[6 * k + 4];
00143 f.Corner[1].Uvws[0] = NLMISC::CUVW(1, 0, 0);
00144
00145 f.Corner[2].Vertex = tab[6 * k + 5];
00146 f.Corner[2].Uvws[0] = NLMISC::CUVW(1, 1, 0);
00147
00148 f.MaterialId = 0;
00149 mb.Faces.push_back(f);
00150 }
00151
00152 CMaterial mat;
00153 CTextureMem *tex = new CTextureMem;
00154 tex->makeDummy();
00155 mat.setTexture(0, tex);
00156 mat.setLighting(false);
00157 mat.setColor(CRGBA::White);
00158 mbb.Materials.push_back(mat);
00159 CMesh *m = new CMesh;
00160 m->build(mbb, mb);
00161 return m;
00162 }
00163
00164
00165
00166 void CPSMesh::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00167 {
00168 (void)f.serialVersion(3);
00169 CPSParticle::serial(f);
00170 CPSSizedParticle::serialSizeScheme(f);
00171 CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f);
00172 CPSRotated2DParticle::serialAngle2DScheme(f);
00173 f.serial(_Shape);
00174 if (f.isReading())
00175 {
00176 invalidate();
00177 }
00178 }
00179
00180
00181
00182 uint32 CPSMesh::getMaxNumFaces(void) const
00183 {
00185 return 0;
00186 }
00187
00188
00189 bool CPSMesh::hasTransparentFaces(void)
00190 {
00192 return false;
00193 }
00194
00195
00196 bool CPSMesh::hasOpaqueFaces(void)
00197 {
00199 return false;
00200 }
00201
00202
00203 void CPSMesh::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00204 {
00205 newPlaneBasisElement(emitterLocated, emitterIndex);
00206 newAngle2DElement(emitterLocated, emitterIndex);
00207 newSizeElement(emitterLocated, emitterIndex);
00208
00209 nlassert(_Owner);
00210 nlassert(_Owner->getOwner());
00211
00212 CScene *scene = _Owner->getScene();
00213 nlassert(scene);
00214
00215
00216 CTransformShape *instance = scene->createInstance(_Shape);
00217
00218 if (!instance)
00219 {
00220
00221
00222 IShape *is = CreateDummyShape();
00223 scene->getShapeBank()->add(DummyShapeName, is);
00224 instance = scene->createInstance(DummyShapeName);
00225 nlassert(instance);
00226 }
00227
00228
00229 instance->setTransformMode(CTransform::DirectMatrix);
00230
00231 instance->hide();
00232 nlassert(instance);
00233
00234 _Instances.insert(instance);
00235 }
00236
00237
00238 void CPSMesh::deleteElement(uint32 index)
00239 {
00240 deleteSizeElement(index);
00241 deleteAngle2DElement(index);
00242 deletePlaneBasisElement(index);
00243
00244
00245 if (_Invalidated) return;
00246
00247 nlassert(_Owner);
00248 nlassert(_Owner->getOwner());
00249
00250 CScene *scene = _Owner->getScene();
00251 nlassert(scene);
00252
00253 scene->deleteInstance(_Instances[index]);
00254 _Instances.remove(index);
00255 }
00256
00257
00258 void CPSMesh::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEt)
00259 {
00260 if (pass == PSSolidRender)
00261 {
00262 updatePos();
00263 }
00264 else
00265 if (pass == PSToolRender)
00266 {
00267 showTool();
00268 }
00269
00270 }
00271
00272
00273 void CPSMesh::updatePos()
00274 {
00275 const uint MeshBufSize = 512;
00276 PARTICLES_CHECK_MEM;
00277 nlassert(_Owner);
00278 const uint32 size = _Owner->getSize();
00279 if (!size) return;
00280
00281
00282 _Owner->incrementNbDrawnParticles(size);
00283
00284
00285 if (_Invalidated)
00286 {
00287
00288 nlassert(_Owner);
00289 nlassert(_Owner->getOwner());
00290
00291 CScene *scene = _Owner->getScene();
00292 nlassert(scene);
00293
00294
00295 resize(_Owner->getMaxSize());
00296
00297 for (uint k = 0; k < size; ++k)
00298 {
00299 CTransformShape *instance = scene->createInstance(_Shape);
00300 instance->setTransformMode(CTransform::DirectMatrix);
00301 instance->hide();
00302 _Instances.insert(instance);
00303 }
00304
00305 _Invalidated = false;
00306 }
00307
00308 float sizes[MeshBufSize];
00309 float angles[MeshBufSize];
00310 static CPlaneBasis planeBasis[MeshBufSize];
00311
00312 uint32 leftToDo = size, toProcess;
00313
00314
00315 float *ptCurrSize;
00316 const uint ptCurrSizeIncrement = _SizeScheme ? 1 : 0;
00317
00318 float *ptCurrAngle;
00319 const uint ptCurrAngleIncrement = _Angle2DScheme ? 1 : 0;
00320
00321 CPlaneBasis *ptBasis;
00322 const uint ptCurrPlaneBasisIncrement = _PlaneBasisScheme ? 1 : 0;
00323
00324 TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt;
00325
00326
00327 TInstanceCont::iterator instanceIt = _Instances.begin();
00328
00329 do
00330 {
00331 toProcess = leftToDo < MeshBufSize ? leftToDo : MeshBufSize;
00332
00333 if (_SizeScheme)
00334 {
00335 ptCurrSize = (float *) (_SizeScheme->make(_Owner, size - leftToDo, &sizes[0], sizeof(float), toProcess, true));
00336 }
00337 else
00338 {
00339 ptCurrSize =& _ParticleSize;
00340 }
00341
00342 if (_Angle2DScheme)
00343 {
00344 ptCurrAngle = (float *) (_Angle2DScheme->make(_Owner, size - leftToDo, &angles[0], sizeof(float), toProcess, true));
00345 }
00346 else
00347 {
00348 ptCurrAngle =& _Angle2D;
00349 }
00350
00351
00352 if (_PlaneBasisScheme)
00353 {
00354 ptBasis = (CPlaneBasis *) (_PlaneBasisScheme->make(_Owner, size - leftToDo, &planeBasis[0], sizeof(CPlaneBasis), toProcess, true));
00355 }
00356 else
00357 {
00358 ptBasis = &_PlaneBasis;
00359 }
00360
00361 endPosIt = posIt + toProcess;
00362 CMatrix mat, tmat;
00363
00364
00365 const CMatrix &transfo = _Owner->isInSystemBasis() ? getSysMat() : CMatrix::Identity;
00366 do
00367 {
00368 (*instanceIt)->show();
00369
00370 tmat.identity();
00371 mat.identity();
00372
00373 tmat.translate(*posIt);
00374
00375
00376
00377 mat.setRot( ptBasis->X * CPSUtil::getCos((sint32) *ptCurrAngle) + ptBasis->Y * CPSUtil::getSin((sint32) *ptCurrAngle)
00378 , ptBasis->X * CPSUtil::getCos((sint32) *ptCurrAngle + 64) + ptBasis->Y * CPSUtil::getSin((sint32) *ptCurrAngle + 64)
00379 , ptBasis->X ^ ptBasis->Y
00380 );
00381
00382 mat.scale(*ptCurrSize);
00383
00384 (*instanceIt)->setMatrix(transfo * tmat * mat);
00385
00386 ++instanceIt;
00387 ++posIt;
00388 ptCurrSize += ptCurrSizeIncrement;
00389 ptCurrAngle += ptCurrAngleIncrement;
00390 ptBasis += ptCurrPlaneBasisIncrement;
00391 }
00392 while (posIt != endPosIt);
00393 leftToDo -= toProcess;
00394 }
00395 while (leftToDo);
00396
00397 PARTICLES_CHECK_MEM;
00398 }
00399
00400
00401 void CPSMesh::resize(uint32 size)
00402 {
00403 nlassert(size < (1 << 16));
00404 resizeSize(size);
00405 resizeAngle2D(size);
00406 resizePlaneBasis(size);
00407 _Instances.resize(size);
00408 }
00409
00410
00411
00412 CPSMesh::~CPSMesh()
00413 {
00414 if (_Owner && _Owner->getOwner())
00415 {
00416 CScene *scene = _Owner->getScene();
00417 nlassert(scene);
00418
00419 for (TInstanceCont::iterator it = _Instances.begin(); it != _Instances.end(); ++it)
00420 {
00421 scene->deleteInstance(*it);
00422 }
00423 }
00424 }
00425
00427
00429
00431
00432 {
00433 uint numFaces = 0;
00434 for (uint k = 0; k < m.getNbMatrixBlock(); ++k)
00435 {
00436 for (uint l = 0; l < m.getNbRdrPass(k); ++l)
00437 {
00438 const CPrimitiveBlock pb = m.getRdrPassPrimitiveBlock(k, l);
00439 numFaces += (pb.getNumLine() << 1) + pb.getNumTri() + (pb.getNumQuad() << 1);
00440
00441 }
00442 }
00443 return numFaces;
00444 }
00445
00446
00447
00449
00450 {
00451 hasTransparentFaces = false;
00452 hasOpaqueFaces = false;
00453
00454 for (uint k = 0; k < m.getNbRdrPass(0); ++k)
00455 {
00456 const CMaterial &currMat = m.getMaterial(m.getRdrPassMaterial(0, k));
00457 if (!currMat.getZWrite())
00458 {
00459 hasTransparentFaces = true;
00460 }
00461 else
00462 {
00463 hasOpaqueFaces = true;
00464 }
00465 }
00466 }
00467
00468
00469
00475 class CPSConstraintMeshHelper
00476 {
00477 public:
00478 template <class T>
00479 static void drawMeshs(T posIt, CPSConstraintMesh &m, uint size, uint32 srcStep, bool opaque)
00480 {
00481 CMesh &mesh = * NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[0]);
00482 const CVertexBuffer &modelVb = mesh.getVertexBuffer();
00483
00484
00485 const uint inVSize = modelVb.getVertexSize();
00486
00487
00488 IDriver *driver = m.getDriver();
00489 m.setupDriverModelMatrix();
00490
00491
00492 float sizes[ConstraintMeshBufSize];
00493
00494 float *ptCurrSize;
00495 uint ptCurrSizeIncrement = m._SizeScheme ? 1 : 0;
00496
00497 T endPosIt;
00498 uint leftToDo = size, toProcess;
00499
00501 CPSConstraintMesh::CMeshDisplay &md= m._MeshDisplayShare.getMeshDisplay(m._Shapes[0], modelVb.getVertexFormat()
00502 | (m._ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
00503
00504 m.setupRenderPasses((float) m._Owner->getOwner()->getSystemDate() - m._GlobalAnimDate, md.RdrPasses, opaque);
00505
00506 CVertexBuffer &outVb = md.VB;
00507 const uint outVSize = outVb.getVertexSize();
00508
00509 driver->activeVertexBuffer(outVb);
00510
00511
00512 CPlaneBasis planeBasis[ConstraintMeshBufSize];
00513 CPlaneBasis *ptBasis;
00514 uint ptBasisIncrement = m._PlaneBasisScheme ? 1 : 0;
00515
00516 const uint nbVerticesInSource = modelVb.getNumVertices();
00517
00518 sint inNormalOff=0;
00519 sint outNormalOff=0;
00520 if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00521 {
00522 inNormalOff = modelVb.getNormalOff();
00523 outNormalOff = outVb.getNormalOff();
00524 }
00525
00526 do
00527 {
00528 uint8 *outVertex = (uint8 *) outVb.getVertexCoordPointer();
00529
00530 toProcess = std::min(leftToDo, ConstraintMeshBufSize);
00531
00532 if (m._SizeScheme)
00533 {
00534 ptCurrSize = (float *) (m._SizeScheme->make(m._Owner, size -leftToDo, &sizes[0], sizeof(float), toProcess, true, srcStep));
00535 }
00536 else
00537 {
00538 ptCurrSize = &m._ParticleSize;
00539 }
00540
00541 if (m._PlaneBasisScheme)
00542 {
00543 ptBasis = (CPlaneBasis *) (m._PlaneBasisScheme->make(m._Owner, size -leftToDo, &planeBasis[0], sizeof(CPlaneBasis), toProcess, true, srcStep));
00544 }
00545 else
00546 {
00547 ptBasis = &m._PlaneBasis;
00548 }
00549
00550
00551 endPosIt = posIt + toProcess;
00552
00553 CMatrix M, sM;
00554
00555
00556 if (m._Shapes.size() == 1)
00557 {
00559 do
00560 {
00561
00562 uint8 *inVertex = (uint8 *) modelVb.getVertexCoordPointer();
00563 uint k = nbVerticesInSource;
00564
00565
00566 if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00567 {
00568 M.identity();
00569 M.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00570 sM = M;
00571 sM.scale(*ptCurrSize);
00572
00573
00574 do
00575 {
00576 CHECK_VERTEX_BUFFER(modelVb, inVertex);
00577 CHECK_VERTEX_BUFFER(outVb, outVertex);
00578 CHECK_VERTEX_BUFFER(modelVb, inVertex + inNormalOff);
00579 CHECK_VERTEX_BUFFER(outVb, outVertex + outNormalOff);
00580
00581
00582 *(CVector *) outVertex = *posIt + sM * *(CVector *) inVertex;
00583
00584 *(CVector *) (outVertex + outNormalOff) = M * *(CVector *) (inVertex + inNormalOff);
00585
00586
00587 inVertex += inVSize;
00588 outVertex += outVSize;
00589 }
00590 while (--k);
00591 }
00592 else
00593 {
00594
00595 sM.identity();
00596 sM.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00597 sM.scale(*ptCurrSize);
00598
00599 do
00600 {
00601 CHECK_VERTEX_BUFFER(modelVb, inVertex);
00602 CHECK_VERTEX_BUFFER(outVb, outVertex);
00603
00604
00605 *(CVector *) outVertex = *posIt + sM * *(CVector *) inVertex;
00606
00607 inVertex += inVSize;
00608 outVertex += outVSize;
00609 }
00610 while (--k);
00611 }
00612
00613
00614 ++posIt;
00615 ptCurrSize += ptCurrSizeIncrement;
00616 ptBasis += ptBasisIncrement;
00617 }
00618 while (posIt != endPosIt);
00619 }
00620 else
00621 {
00622
00623
00624
00625 float morphValues[ConstraintMeshBufSize];
00626 float *currMorphValue;
00627 uint morphValueIncr;
00628
00629 if (m._MorphScheme)
00630 {
00631 currMorphValue = (float *) m._MorphScheme->make(m._Owner, size - leftToDo, &morphValues[0], sizeof(float), toProcess, true, srcStep);
00632 morphValueIncr = 1;
00633 }
00634 else
00635 {
00636 currMorphValue = &m._MorphValue;
00637 morphValueIncr = 0;
00638 }
00639
00640 do
00641 {
00642 const uint numShapes = m._Shapes.size();
00643 const uint8 *m0, *m1;
00644 float lambda;
00645 float opLambda;
00646 const CVertexBuffer *inVB0, *inVB1;
00647 if (*currMorphValue >= numShapes - 1)
00648 {
00649 lambda = 0.f;
00650 opLambda = 1.f;
00651 inVB0 = inVB1 = &NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[numShapes - 1])->getVertexBuffer();
00652 }
00653 else if (*currMorphValue <= 0)
00654 {
00655 lambda = 0.f;
00656 opLambda = 1.f;
00657 inVB0 = inVB1 = &NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[0])->getVertexBuffer();
00658 }
00659 else
00660 {
00661 uint iMeshIndex = (uint) *currMorphValue;
00662 lambda = *currMorphValue - iMeshIndex;
00663 opLambda = 1.f - lambda;
00664 inVB0 = &NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[iMeshIndex])->getVertexBuffer();
00665 inVB1 = &NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[iMeshIndex + 1])->getVertexBuffer();
00666 }
00667
00668 m0 = (uint8 *) inVB0->getVertexCoordPointer();
00669 m1 = (uint8 *) inVB1->getVertexCoordPointer();
00670
00671
00672 uint k = nbVerticesInSource;
00673
00674 if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00675 {
00676 M.identity();
00677 M.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00678 sM = M;
00679 sM.scale(*ptCurrSize);
00680
00681
00682 do
00683 {
00684 CHECK_VERTEX_BUFFER((*inVB0), m0);
00685 CHECK_VERTEX_BUFFER((*inVB1), m1);
00686 CHECK_VERTEX_BUFFER((*inVB0), m0 + inNormalOff);
00687 CHECK_VERTEX_BUFFER((*inVB1), m1 + inNormalOff);
00688 CHECK_VERTEX_BUFFER(outVb, outVertex);
00689 CHECK_VERTEX_BUFFER(outVb, outVertex + outNormalOff);
00690
00691
00692 *(CVector *) outVertex = *posIt + sM * (opLambda * *(CVector *) m0 + lambda * *(CVector *) m1);
00693
00694 *(CVector *) (outVertex + outNormalOff) = M * (opLambda * *(CVector *) (m0 + inNormalOff)
00695 + lambda * *(CVector *) (m1 + inNormalOff)).normed();
00696
00697
00698 m0 += inVSize;
00699 m1 += inVSize;
00700 outVertex += outVSize;
00701 }
00702 while (--k);
00703 }
00704 else
00705 {
00706
00707 sM.identity();
00708 sM.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00709 sM.scale(*ptCurrSize);
00710
00711 do
00712 {
00713 CHECK_VERTEX_BUFFER((*inVB0), m0);
00714 CHECK_VERTEX_BUFFER((*inVB1), m1);
00715 CHECK_VERTEX_BUFFER(outVb, outVertex);
00716
00717 *(CVector *) outVertex = *posIt + sM * (opLambda * *(CVector *) m0 + opLambda * *(CVector *) m1);
00718
00719 m0 += inVSize;
00720 m1 += inVSize;
00721 outVertex += outVSize;
00722 }
00723 while (--k);
00724 }
00725
00726
00727 ++posIt;
00728 ptCurrSize += ptCurrSizeIncrement;
00729 ptBasis += ptBasisIncrement;
00730 currMorphValue += morphValueIncr;
00731 }
00732 while (posIt != endPosIt);
00733 }
00734
00735
00736 if (m._ColorScheme)
00737 {
00738 m.computeColors(outVb, modelVb, size - leftToDo, toProcess, srcStep);
00739 }
00740
00741
00742 m.doRenderPasses(driver, toProcess, md.RdrPasses, opaque);
00743 leftToDo -= toProcess;
00744
00745 }
00746 while (leftToDo);
00747 }
00748
00749
00750 template <class T, class U>
00751 static void drawPrerotatedMeshs(T posIt,
00752 U indexIt,
00753 CPSConstraintMesh &m,
00754 uint size,
00755 uint32 srcStep,
00756 bool opaque,
00757 TAnimationTime ellapsedTime)
00758 {
00759
00760 CMesh &mesh = * NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[0]);
00761 const CVertexBuffer &modelVb = mesh.getVertexBuffer();
00762
00764 CVertexBuffer &prerotVb = m.makePrerotatedVb(modelVb, ellapsedTime);
00765
00766
00767 IDriver *driver = m.getDriver();
00768 m.setupDriverModelMatrix();
00769
00770
00771 nlassert(m._Owner)
00772
00773
00774 float sizes[ConstraintMeshBufSize];
00775
00776
00777 float *ptCurrSize;
00778 uint ptCurrSizeIncrement = m._SizeScheme ? 1 : 0;
00779
00780 T endPosIt;
00781 uint leftToDo = size, toProcess;
00782 const uint nbVerticesInSource = modelVb.getNumVertices();
00783
00784
00785
00786
00787 const uint prerotatedModelSize = prerotVb.getVertexSize() * modelVb.getNumVertices();
00788
00790 CPSConstraintMesh::CMeshDisplay &md = m._MeshDisplayShare.getMeshDisplay(m._Shapes[0], modelVb.getVertexFormat()
00791 | (m._ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
00792
00793
00794 m.setupRenderPasses((float) m._Owner->getOwner()->getSystemDate() - m._GlobalAnimDate, md.RdrPasses, opaque);
00795
00796 CVertexBuffer &outVb = md.VB;
00797
00798 driver->activeVertexBuffer(outVb);
00799
00800
00801
00802 const uint inVSize = prerotVb.getVertexSize();
00803
00804
00805 const uint outVSize = outVb.getVertexSize();
00806
00807
00808 uint normalOff=0;
00809 uint pNormalOff=0;
00810 if (prerotVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00811 {
00812 normalOff = outVb.getNormalOff();
00813 pNormalOff = prerotVb.getNormalOff();
00814 }
00815
00816 do
00817 {
00818 toProcess = std::min(leftToDo, ConstraintMeshBufSize);
00819
00820 if (m._SizeScheme)
00821 {
00822
00823 ptCurrSize = (float *) (m._SizeScheme->make(m._Owner, size - leftToDo, &sizes[0], sizeof(float), toProcess, true, srcStep));
00824 }
00825 else
00826 {
00827
00828 ptCurrSize = &m._ParticleSize;
00829 }
00830
00831 endPosIt = posIt + toProcess;
00832 uint8 *outVertex = (uint8 *) outVb.getVertexCoordPointer();
00834 do
00835 {
00836 uint8 *inVertex = (uint8 *) prerotVb.getVertexCoordPointer() + prerotatedModelSize * *indexIt;
00837 uint k = nbVerticesInSource;
00838
00839 if (prerotVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00840 {
00841 do
00842 {
00843 CHECK_VERTEX_BUFFER(outVb, outVertex);
00844 CHECK_VERTEX_BUFFER(prerotVb, inVertex);
00845 CHECK_VERTEX_BUFFER(outVb, outVertex + normalOff);
00846 CHECK_VERTEX_BUFFER(prerotVb, inVertex + pNormalOff);
00847
00848
00849
00850 *(CVector *) outVertex = *posIt + *ptCurrSize * *(CVector *) inVertex;
00851
00852 *(CVector *) (outVertex + normalOff ) = *(CVector *) (inVertex + pNormalOff);
00853 inVertex += inVSize;
00854 outVertex += outVSize;
00855 }
00856 while (--k);
00857 }
00858 else
00859 {
00860 do
00861 {
00862
00863 CHECK_VERTEX_BUFFER(outVb, outVertex);
00864 CHECK_VERTEX_BUFFER(prerotVb, inVertex);
00865 *(CVector *) outVertex = *posIt + *ptCurrSize * *(CVector *) inVertex;
00866 inVertex += inVSize;
00867 outVertex += outVSize;
00868 }
00869 while (--k);
00870 }
00871
00872 ++indexIt;
00873 ++posIt;
00874 ptCurrSize += ptCurrSizeIncrement;
00875 }
00876 while (posIt != endPosIt);
00877
00878
00879 if (m._ColorScheme)
00880 {
00881 m.computeColors(outVb, modelVb, size - leftToDo, toProcess, srcStep);
00882 }
00883
00884
00886 m.doRenderPasses(driver, toProcess, md.RdrPasses, opaque);
00887 leftToDo -= toProcess;
00888
00889 }
00890 while (leftToDo);
00891 PARTICLES_CHECK_MEM
00892 }
00893 };
00894
00895 CPSConstraintMesh::CPSConstraintMesh() : _NumFaces(0),
00896 _ModelBank(NULL),
00897 _ModulatedStages(0),
00898 _Touched(1),
00899 _VertexColorLightingForced(false),
00900 _GlobalAnimationEnabled(0),
00901 _ReinitGlobalAnimTimeOnNewElement(0),
00902 _MorphValue(0),
00903 _MorphScheme(NULL)
00904 {
00905 _Name = std::string("ConstraintMesh");
00906 }
00907
00908
00909 uint32 CPSConstraintMesh::getMaxNumFaces(void) const
00910 {
00911
00912 return _NumFaces * _Owner->getMaxSize();
00913
00914 }
00915
00916
00917
00918 bool CPSConstraintMesh::hasTransparentFaces(void)
00919 {
00920 if (!_Touched) return _HasTransparentFaces != 0;
00922 update();
00923 return _HasTransparentFaces != 0;
00924 }
00925
00926
00927 bool CPSConstraintMesh::hasOpaqueFaces(void)
00928 {
00929 if (!_Touched) return _HasOpaqueFaces != 0;
00930 update();
00931 return _HasOpaqueFaces != 0;
00932 }
00933
00934
00935 void CPSConstraintMesh::setShape(const std::string &meshFileName)
00936 {
00937 _MeshShapeFileName.resize(1);
00938 _MeshShapeFileName[0] = meshFileName;
00939 _Touched = 1;
00940 }
00941
00942
00943
00944 std::string CPSConstraintMesh::getShape(void) const
00945 {
00946 nlassert(_MeshShapeFileName.size() == 1);
00947 return _MeshShapeFileName[0];
00948 }
00949
00950
00951 void CPSConstraintMesh::setShapes(const std::string *shapesNames, uint numShapes)
00952 {
00953 _MeshShapeFileName.resize(numShapes);
00954 std::copy(shapesNames, shapesNames + numShapes, _MeshShapeFileName.begin());
00955 _Touched = 1;
00956 }
00957
00958
00959 uint CPSConstraintMesh::getNumShapes() const
00960 {
00961 return _MeshShapeFileName.size();
00962 }
00963
00964
00965 void CPSConstraintMesh::getShapesNames(std::string *shapesNames) const
00966 {
00967 std::copy(_MeshShapeFileName.begin(), _MeshShapeFileName.end(), shapesNames);
00968 }
00969
00970
00971
00972
00973 void CPSConstraintMesh::setShape(uint index, const std::string &shapeName)
00974 {
00975 nlassert(index < _MeshShapeFileName.size());
00976 _MeshShapeFileName[index] = shapeName;
00977 _Touched = 1;
00978 }
00979
00980
00981
00982 const std::string &CPSConstraintMesh::getShape(uint index) const
00983 {
00984 nlassert(index < _MeshShapeFileName.size());
00985 return _MeshShapeFileName[index];
00986 }
00987
00988
00989
00990
00991 void CPSConstraintMesh::setMorphValue(float value)
00992 {
00993 delete _MorphScheme;
00994 _MorphScheme = NULL;
00995 _MorphValue = value;
00996 }
00997
00998
00999
01000 float CPSConstraintMesh::getMorphValue() const
01001 {
01002 return _MorphValue;
01003 }
01004
01005
01006 void CPSConstraintMesh::setMorphScheme(CPSAttribMaker<float> *scheme)
01007 {
01008 delete _MorphScheme;
01009 _MorphScheme = scheme;
01010 if (_MorphScheme->hasMemory()) _MorphScheme->resize(_Owner->getMaxSize(), _Owner->getSize());
01011 }
01012
01013
01014 CPSAttribMaker<float> *CPSConstraintMesh::getMorphScheme()
01015 {
01016 return _MorphScheme;
01017 }
01018
01019
01020 const CPSAttribMaker<float> *CPSConstraintMesh::getMorphScheme() const
01021 {
01022 return _MorphScheme;
01023 }
01024
01025
01026
01027 static IShape *GetDummyShapeFromBank(CShapeBank &sb)
01028 {
01029 static const std::string dummyMeshName("dummy constraint mesh shape");
01030 if (sb.isPresent(dummyMeshName) == CShapeBank::Present)
01031 {
01032 return sb.addRef(dummyMeshName);
01033 }
01034 else
01035 {
01036
01037 IShape *is = CreateDummyShape();
01038 sb.add(std::string("dummy constraint mesh shape"), is);
01039 return is;
01040 }
01041 }
01042
01043
01044 bool CPSConstraintMesh::update(void)
01045 {
01046 bool ok = true;
01047 if (!_Touched) return ok;
01048
01049 clean();
01050
01051 nlassert(_Owner->getScene());
01052
01053 CScene *scene = _Owner->getScene();
01054 CShapeBank *sb = scene->getShapeBank();
01055 IShape *is;
01056
01057
01058 uint32 vFormat=0;
01059 uint numVerts=0;
01060
01061 if (_MeshShapeFileName.size() == 0)
01062 {
01063 _MeshShapeFileName.resize(1);
01064 _MeshShapeFileName[0] = DummyShapeName;
01065 }
01066
01067
01068 _Shapes.resize(_MeshShapeFileName.size());
01069 for (uint k = 0; k < _MeshShapeFileName.size(); ++k)
01070 {
01071 if (sb->isPresent(_MeshShapeFileName[k]) == CShapeBank::Present)
01072 {
01073 _Shapes[k] = sb->addRef(_MeshShapeFileName[k]);
01074
01076 const CMesh &m = * NLMISC::safe_cast<CMesh *>((IShape *) _Shapes[k]);
01077 if (k == 0)
01078 {
01079 vFormat = m.getVertexBuffer().getVertexFormat();
01080 numVerts = m.getVertexBuffer().getNumVertices();
01081 }
01082 else
01083 {
01084 if (vFormat != m.getVertexBuffer().getVertexFormat()
01085 || numVerts != m.getVertexBuffer().getNumVertices())
01086 {
01087 ok = false;
01088 }
01089 }
01090 }
01091 else
01092 {
01093 try
01094 {
01095 sb->load(_MeshShapeFileName[k]);
01096 }
01097 catch (NLMISC::EPathNotFound &)
01098 {
01099 nlwarning("mesh not found : %s; used as a constraint mesh particle", _MeshShapeFileName[k].c_str());
01100
01101 }
01102
01103 if (sb->isPresent(_MeshShapeFileName[k]) != CShapeBank::Present)
01104 {
01105 ok = false;
01106 }
01107 else
01108 {
01109 is = sb->addRef(_MeshShapeFileName[k]);
01110 if (!dynamic_cast<CMesh *>(is))
01111 {
01112 nlwarning("Tried to bind a shape that is not a mesh to a mesh particle : %s", _MeshShapeFileName[k].c_str());
01113 sb->release(is);
01114 ok = false;
01115 }
01116 else
01117 {
01118 const CMesh &m = * NLMISC::safe_cast<CMesh *>(is);
01120 if (m.getVertexBuffer().getNumVertices() > ConstraintMeshMaxNumVerts)
01121 {
01122 nlwarning("Tried to bind a mesh that has more than %d vertices to a particle mesh: %s", (int) ConstraintMeshMaxNumVerts, _MeshShapeFileName[k].c_str());
01123 sb->release(is);
01124 ok = false;
01125 }
01126 else
01127 {
01128 _Shapes[k] = is;
01130 const CMesh &m = * NLMISC::safe_cast<CMesh *>((IShape *) _Shapes[k]);
01131 if (k == 0)
01132 {
01133 vFormat = m.getVertexBuffer().getVertexFormat();
01134 numVerts = m.getVertexBuffer().getNumVertices();
01135 }
01136 else
01137 {
01138 if (vFormat != m.getVertexBuffer().getVertexFormat()
01139 || numVerts != m.getVertexBuffer().getNumVertices())
01140 {
01141 ok = false;
01142 }
01143 }
01144 }
01145 }
01146 }
01147 }
01148
01149 if (!ok)
01150 {
01151 releaseShapes();
01152 _Shapes.resize(1);
01153 _Shapes[0] = GetDummyShapeFromBank(*sb);
01154 break;
01155 }
01156 }
01157
01158
01159 const CMesh &m = * NLMISC::safe_cast<CMesh *>((IShape *) _Shapes[0]);
01160
01162 _NumFaces = getMeshNumTri(m);
01163 notifyOwnerMaxNumFacesChanged();
01164
01166 bool hasTransparentFaces, hasOpaqueFaces;
01167 CheckForOpaqueAndTransparentFacesInMesh(m, hasTransparentFaces, hasOpaqueFaces);
01168 _HasTransparentFaces = hasTransparentFaces;
01169 _HasOpaqueFaces = hasOpaqueFaces;
01170 _ModelBank = sb;
01171 _GlobalAnimDate = _Owner->getOwner()->getSystemDate();
01172 _Touched = 0;
01173 nlassert(_Shapes.size() > 0);
01174
01175 #ifdef NL_DEBUG
01176 for (uint j = 0; j < _Shapes.size(); ++j)
01177 {
01178 nlassert(dynamic_cast<CMesh *>((IShape *) _Shapes[j]));
01179 }
01180 #endif
01181
01182 return ok;
01183
01184 }
01185
01186
01187
01188
01189 void CPSConstraintMesh::hintRotateTheSame(uint32 nbConfiguration,
01190 float minAngularVelocity,
01191 float maxAngularVelocity
01192 )
01193 {
01194 nlassert(nbConfiguration <= ConstraintMeshMaxNumPrerotatedModels);
01195
01196
01197 _MinAngularVelocity = minAngularVelocity;
01198 _MaxAngularVelocity = maxAngularVelocity;
01199
01200
01201
01202 _PrecompBasis.resize(nbConfiguration);
01203
01204 if (nbConfiguration)
01205 {
01206
01207 for (uint k = 0; k < nbConfiguration; ++k)
01208 {
01209 CVector v = MakeRandomUnitVect();
01210 _PrecompBasis[k].Basis = CPlaneBasis(v);
01211 _PrecompBasis[k].Axis = MakeRandomUnitVect();
01212 _PrecompBasis[k].AngularVelocity = minAngularVelocity
01213 + (rand() % 20000) / 20000.f * (maxAngularVelocity - minAngularVelocity);
01214
01215 }
01216
01217
01218 fillIndexesInPrecompBasis();
01219 }
01220 }
01221
01222
01223
01224 void CPSConstraintMesh::fillIndexesInPrecompBasis(void)
01225 {
01226
01227 const uint32 nbConf = _PrecompBasis.size();
01228 if (_Owner)
01229 {
01230 _IndexInPrecompBasis.resize( _Owner->getMaxSize() );
01231 }
01232 for (std::vector<uint32>::iterator it = _IndexInPrecompBasis.begin(); it != _IndexInPrecompBasis.end(); ++it)
01233 {
01234 *it = rand() % nbConf;
01235 }
01236 }
01237
01238
01240
01241 {
01242
01243 sint ver = f.serialVersion(4);
01244 if (f.isReading())
01245 {
01246 clean();
01247 }
01248
01249 CPSParticle::serial(f);
01250 CPSSizedParticle::serialSizeScheme(f);
01251 CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f);
01252
01253
01254
01255 if (f.isReading())
01256 {
01257 uint32 nbConfigurations;
01258 f.serial(nbConfigurations);
01259 if (nbConfigurations)
01260 {
01261 f.serial(_MinAngularVelocity, _MaxAngularVelocity);
01262 }
01263 hintRotateTheSame(nbConfigurations, _MinAngularVelocity, _MaxAngularVelocity);
01264 }
01265 else
01266 {
01267 uint32 nbConfigurations = _PrecompBasis.size();
01268 f.serial(nbConfigurations);
01269 if (nbConfigurations)
01270 {
01271 f.serial(_MinAngularVelocity, _MaxAngularVelocity);
01272 }
01273 }
01274
01275
01276 static std::string emptyStr;
01277
01278 if (ver < 4)
01279 {
01280 if (!f.isReading())
01281 {
01282 if (_MeshShapeFileName.size() > 0)
01283 {
01284 f.serial(_MeshShapeFileName[0]);
01285 }
01286 else
01287 {
01288 f.serial(emptyStr);
01289 }
01290 }
01291 else
01292 {
01293 _MeshShapeFileName.resize(1);
01294 f.serial(_MeshShapeFileName[0]);
01295 _Touched = true;
01296 }
01297 }
01298
01299 if (ver > 1)
01300 {
01301 CPSColoredParticle::serialColorScheme(f);
01302 f.serial(_ModulatedStages);
01303 if (f.isReading())
01304 {
01305 bool vcEnabled;
01306 f.serial(vcEnabled);
01307 _VertexColorLightingForced = vcEnabled;
01308 }
01309 else
01310 {
01311 bool vcEnabled = (_VertexColorLightingForced != 0);
01312 f.serial(vcEnabled);
01313 }
01314 }
01315
01316 if (ver > 2)
01317 {
01318 if (f.isReading())
01319 {
01320 bool gaEnabled;
01321 f.serial(gaEnabled);
01322 _GlobalAnimationEnabled = gaEnabled;
01323 if (gaEnabled)
01324 {
01325 PGlobalTexAnims newPtr(new CGlobalTexAnims);
01326 std::swap(_GlobalTexAnims, newPtr);
01327 f.serial(*_GlobalTexAnims);
01328 }
01329
01330 bool rgt;
01331 f.serial(rgt);
01332 _ReinitGlobalAnimTimeOnNewElement = rgt;
01333 }
01334 else
01335 {
01336 bool gaEnabled = (_GlobalAnimationEnabled != 0);
01337 f.serial(gaEnabled);
01338 if (gaEnabled)
01339 {
01340 f.serial(*_GlobalTexAnims);
01341 }
01342
01343 bool rgt = _ReinitGlobalAnimTimeOnNewElement != 0;
01344 f.serial(rgt);
01345 }
01346 }
01347
01348 if (ver > 3)
01349 {
01350 f.serialCont(_MeshShapeFileName);
01351 bool useScheme;
01352 if (f.isReading())
01353 {
01354 delete _MorphScheme;
01355 }
01356 else
01357 {
01358 useScheme = _MorphScheme != NULL;
01359 }
01360 f.serial(useScheme);
01361 if (useScheme)
01362 {
01363 f.serialPolyPtr(_MorphScheme);
01364 }
01365 else
01366 {
01367 f.serial(_MorphValue);
01368 }
01369 }
01370 }
01371
01372
01373 CPSConstraintMesh::~CPSConstraintMesh()
01374 {
01375 clean();
01376 delete _MorphScheme;
01377 }
01378
01379
01380
01381
01382 void CPSConstraintMesh::releaseShapes()
01383 {
01384 for (TShapeVect::iterator it = _Shapes.begin(); it != _Shapes.end(); ++it)
01385 {
01386 if (*it)
01387 {
01388 _ModelBank->release(*it);
01389 }
01390 }
01391 _Shapes.clear();
01392 }
01393
01394
01395 void CPSConstraintMesh::clean(void)
01396 {
01397 if (_ModelBank)
01398 {
01399 releaseShapes();
01400 }
01401 }
01402
01403
01404
01405 CVertexBuffer &CPSConstraintMesh::makePrerotatedVb(const CVertexBuffer &inVb, TAnimationTime ellapsedTime)
01406 {
01407
01408 CVertexBuffer &prerotatedVb = inVb.getVertexFormat() & CVertexBuffer::NormalFlag ? _PreRotatedMeshVBWithNormal : _PreRotatedMeshVB;
01409
01410
01411 const uint vSize = inVb.getVertexSize();
01412
01413
01414 const uint vpSize = prerotatedVb.getVertexSize();
01415
01416
01417
01418 uint normalOff=0;
01419 uint pNormalOff=0;
01420 if (prerotatedVb.getVertexFormat() & CVertexBuffer::NormalFlag)
01421 {
01422 normalOff = inVb.getNormalOff();
01423 pNormalOff = prerotatedVb.getNormalOff();
01424 }
01425
01426 const uint nbVerticesInSource = inVb.getNumVertices();
01427
01428
01429
01430
01431 uint8 *outVertex = (uint8 *) prerotatedVb.getVertexCoordPointer();
01432 for (std::vector< CPlaneBasisPair >::iterator it = _PrecompBasis.begin(); it != _PrecompBasis.end(); ++it)
01433 {
01434
01435 CMatrix mat;
01436 mat.rotate(CQuat(it->Axis, ellapsedTime * it->AngularVelocity));
01437 CVector n = mat * it->Basis.getNormal();
01438 it->Basis = CPlaneBasis(n);
01439
01440 mat.identity();
01441 mat.setRot(it->Basis.X, it->Basis.Y, it->Basis.X ^ it->Basis.Y);
01442
01443 uint8 *inVertex = (uint8 *) inVb.getVertexCoordPointer();
01444
01445 uint k = nbVerticesInSource;
01446
01447
01448 if (inVb.getVertexFormat() & CVertexBuffer::NormalFlag)
01449 {
01450
01451 do
01452 {
01453 CHECK_VERTEX_BUFFER(inVb, inVertex);
01454 CHECK_VERTEX_BUFFER(inVb, inVertex + normalOff);
01455 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex);
01456 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex + pNormalOff);
01457
01458 * (CVector *) outVertex = mat.mulVector(* (CVector *) inVertex);
01459 * (CVector *) (outVertex + normalOff) = mat.mulVector(* (CVector *) (inVertex + pNormalOff) );
01460 outVertex += vpSize;
01461 inVertex += vSize;
01462
01463 }
01464 while (--k);
01465 }
01466 else
01467 {
01468
01469 do
01470 {
01471
01472 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex);
01473 CHECK_VERTEX_BUFFER(inVb, inVertex);
01474
01475 * (CVector *) outVertex = mat.mulVector(* (CVector *) inVertex);
01476 outVertex += vpSize;
01477 inVertex += vSize;
01478 }
01479 while (--k);
01480
01481 }
01482 }
01483 return prerotatedVb;
01484 }
01485
01486
01487
01488 void CPSConstraintMesh::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEt)
01489 {
01490 if (
01491 (pass == PSBlendRender && hasTransparentFaces())
01492 || (pass == PSSolidRender && hasOpaqueFaces())
01493 )
01494 {
01495 draw(pass == PSSolidRender, ellapsedTime);
01496 }
01497 else
01498 if (pass == PSToolRender)
01499 {
01500 showTool();
01501 }
01502 }
01503
01504
01505 void CPSConstraintMesh::draw(bool opaque, TAnimationTime ellapsedTime)
01506 {
01507 PARTICLES_CHECK_MEM;
01508 nlassert(_Owner);
01509
01510 update();
01511 uint32 step;
01512 uint numToProcess;
01513 computeSrcStep(step, numToProcess);
01514 if (!numToProcess) return;
01515 _Owner->incrementNbDrawnParticles(numToProcess);
01516
01517
01518 if (_PrecompBasis.size() == 0)
01519 {
01520 if (step == (1 << 16))
01521 {
01522 CPSConstraintMeshHelper::drawMeshs(_Owner->getPos().begin(),
01523 *this,
01524 numToProcess,
01525 step,
01526 opaque
01527 );
01528 }
01529 else
01530 {
01531 CPSConstraintMeshHelper::drawMeshs(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
01532 *this,
01533 numToProcess,
01534 step,
01535 opaque
01536 );
01537 }
01538 }
01539 else
01540 {
01541 if (step == (1 << 16))
01542 {
01543 CPSConstraintMeshHelper::drawPrerotatedMeshs(_Owner->getPos().begin(),
01544 _IndexInPrecompBasis.begin(),
01545 *this,
01546 numToProcess,
01547 step,
01548 opaque,
01549 ellapsedTime
01550 );
01551 }
01552 else
01553 {
01554 typedef CAdvance1616Iterator<std::vector<uint32>::const_iterator, uint32> TIndexIterator;
01555 CPSConstraintMeshHelper::drawPrerotatedMeshs(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
01556 TIndexIterator(_IndexInPrecompBasis.begin(), 0, step),
01557 *this,
01558 numToProcess,
01559 step,
01560 opaque,
01561 ellapsedTime
01562 );
01563 }
01564 }
01565
01566
01567 }
01568
01569
01570
01571 static inline void ForceMaterialModulation(CMaterial &destMat, CMaterial &srcMat, uint8 modulatedStages)
01572 {
01573 for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
01574 {
01575 if (modulatedStages & (1 << k))
01576 {
01577 destMat.texEnvArg0RGB(k, CMaterial::Previous, CMaterial::SrcColor);
01578 destMat.texEnvArg0Alpha(k, CMaterial::Previous, CMaterial::SrcAlpha);
01579 destMat.texEnvArg1RGB(k, CMaterial::Constant, CMaterial::SrcColor);
01580 destMat.texEnvArg1Alpha(k, CMaterial::Constant, CMaterial::SrcAlpha);
01581 destMat.texEnvOpRGB(k, CMaterial::Modulate);
01582 destMat.texEnvOpAlpha(k, CMaterial::Modulate);
01583 }
01584 else
01585 {
01586 destMat.setTexEnvMode(k, srcMat.getTexEnvMode(k));
01587 }
01588 }
01589 }
01590
01591
01592
01593 void CPSConstraintMesh::setupRenderPasses(float date, TRdrPassSet &rdrPasses, bool opaque)
01594 {
01595
01596 for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin()
01597 ; rdrPassIt != rdrPasses.end(); ++rdrPassIt)
01598 {
01599
01600 CMaterial &Mat = rdrPassIt->Mat;
01601 CMaterial &SourceMat = rdrPassIt->SourceMat;
01602
01603
01605 if ((opaque && Mat.getZWrite()) || (!opaque && ! Mat.getZWrite()))
01606 {
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01628 ForceMaterialModulation(Mat, SourceMat, _ModulatedStages);
01629
01631 bool forceVertexcolorLighting = _VertexColorLightingForced != 0 ? true : SourceMat.getLightedVertexColor();
01632 if (forceVertexcolorLighting != Mat.getLightedVertexColor())
01633 {
01634 Mat.setLightedVertexColor(forceVertexcolorLighting);
01635 }
01636
01638 if (_GlobalAnimationEnabled != 0)
01639 {
01640 for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
01641 {
01642 if (Mat.getTexture(k) != NULL)
01643 {
01644 Mat.enableUserTexMat(k, true);
01645 CMatrix mat;
01646 _GlobalTexAnims->Anims[k].buildMatrix(date, mat);
01647 Mat.setUserTexMat(k ,mat);
01648 }
01649 }
01650 }
01651 }
01652 }
01653
01654 }
01655
01656
01657 void CPSConstraintMesh::doRenderPasses(IDriver *driver, uint numObj, TRdrPassSet &rdrPasses, bool opaque)
01658 {
01659
01660 for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin()
01661 ; rdrPassIt != rdrPasses.end(); ++rdrPassIt)
01662 {
01663 CMaterial &Mat = rdrPassIt->Mat;
01664 if ((opaque && Mat.getZWrite()) || (!opaque && ! Mat.getZWrite()))
01665 {
01667 rdrPassIt->Pb.setNumTri(rdrPassIt->Pb.capacityTri() * numObj / ConstraintMeshBufSize);
01668 rdrPassIt->Pb.setNumQuad(rdrPassIt->Pb.capacityQuad() * numObj / ConstraintMeshBufSize);
01669 rdrPassIt->Pb.setNumLine(rdrPassIt->Pb.capacityLine() * numObj / ConstraintMeshBufSize);
01670
01672 driver->render(rdrPassIt->Pb, rdrPassIt->Mat);
01673 }
01674 }
01675
01676 }
01677
01678
01679
01680 void CPSConstraintMesh::computeColors(CVertexBuffer &outVB, const CVertexBuffer &inVB, uint startIndex, uint toProcess, uint32 srcStep)
01681 {
01682 nlassert(_ColorScheme);
01683
01684
01685
01686 if (inVB.getVertexFormat() & CVertexBuffer::PrimaryColorFlag)
01687 {
01688
01689 _ColorScheme->makeN(_Owner, startIndex, outVB.getColorPointer(), outVB.getVertexSize(), toProcess, inVB.getNumVertices(), srcStep);
01690
01691 uint8 *vDest = (uint8 *) outVB.getColorPointer();
01692 uint8 *vSrc = (uint8 *) inVB.getColorPointer();
01693 const uint vSize = outVB.getVertexSize();
01694 const uint numVerts = inVB.getNumVertices();
01695 uint meshSize = vSize * numVerts;
01696 for (uint k = 0; k < toProcess; ++k)
01697 {
01698 NLMISC::CRGBA::modulateColors((CRGBA *) vDest, (CRGBA *) vSrc, (CRGBA *) vDest, numVerts, vSize, vSize);
01699 vDest += meshSize;
01700 }
01701 }
01702 else
01703 {
01704 _ColorScheme->makeN(_Owner, startIndex, outVB.getColorPointer(), outVB.getVertexSize(), toProcess, inVB.getNumVertices(), srcStep);
01705 }
01706 }
01707
01708
01709
01710 void CPSConstraintMesh::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
01711 {
01712 newSizeElement(emitterLocated, emitterIndex);
01713 newPlaneBasisElement(emitterLocated, emitterIndex);
01714
01715 const uint32 nbConf = _PrecompBasis.size();
01716 if (nbConf)
01717 {
01718 _IndexInPrecompBasis[_Owner->getNewElementIndex()] = rand() % nbConf;
01719 }
01720 newColorElement(emitterLocated, emitterIndex);
01721 if (_GlobalAnimationEnabled && _ReinitGlobalAnimTimeOnNewElement)
01722 {
01723 _GlobalAnimDate = _Owner->getOwner()->getSystemDate();
01724 }
01725 if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->newElement(emitterLocated, emitterIndex);
01726 }
01727
01728
01729 void CPSConstraintMesh::deleteElement(uint32 index)
01730 {
01731 deleteSizeElement(index);
01732 deletePlaneBasisElement(index);
01733
01734 if (_PrecompBasis.size())
01735 {
01736
01737 _IndexInPrecompBasis[index] = _IndexInPrecompBasis[_Owner->getSize() - 1];
01738 }
01739 deleteColorElement(index);
01740 if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->deleteElement(index);
01741 }
01742
01743
01744 void CPSConstraintMesh::resize(uint32 size)
01745 {
01746 nlassert(size < (1 << 16));
01747 resizeSize(size);
01748 resizePlaneBasis(size);
01749
01750 if (_PrecompBasis.size())
01751 {
01752 _IndexInPrecompBasis.resize(size);
01753 }
01754 resizeColor(size);
01755 if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->resize(size, _Owner->getSize());
01756 }
01757
01758
01759 void CPSConstraintMesh::updateMatAndVbForColor(void)
01760 {
01761
01762 }
01763
01764
01765 void CPSConstraintMesh::forceStageModulationByColor(uint stage, bool force)
01766 {
01767 nlassert(stage < IDRV_MAT_MAXTEXTURES);
01768 if (force)
01769 {
01770 _ModulatedStages |= 1 << stage;
01771 }
01772 else
01773 {
01774 _ModulatedStages &= ~(1 << stage);
01775 }
01776 }
01777
01778
01779 bool CPSConstraintMesh::isStageModulationForced(uint stage) const
01780 {
01781 nlassert(stage < IDRV_MAT_MAXTEXTURES);
01782 return (_ModulatedStages & (1 << stage)) != 0;
01783 }
01784
01785
01786
01792 static void DuplicatePrimitiveBlock(const CPrimitiveBlock &srcBlock, CPrimitiveBlock &destBlock, uint nbReplicate, uint vertOffset)
01793 {
01794 PARTICLES_CHECK_MEM;
01795
01796
01797
01798
01799 uint k, l, index;
01800
01801
01802 uint currVertOffset;
01803
01804
01805
01806 uint numTri = srcBlock.getNumTri();
01807 destBlock.reserveTri(numTri * nbReplicate);
01808
01809 index = 0;
01810 currVertOffset = 0;
01811
01812 const uint32 *triPtr = srcBlock.getTriPointer();
01813 const uint32 *currTriPtr;
01814 for (k = 0; k < nbReplicate; ++k)
01815 {
01816 currTriPtr = triPtr;
01817 for (l = 0; l < numTri; ++l)
01818 {
01819 destBlock.setTri(index, currTriPtr[0] + currVertOffset, currTriPtr[1] + currVertOffset, currTriPtr[2] + currVertOffset);
01820 currTriPtr += 3;
01821 ++ index;
01822 }
01823 currVertOffset += vertOffset;
01824 }
01825
01826
01827
01828 uint numQuad = srcBlock.getNumQuad();
01829 destBlock.reserveQuad(numQuad * nbReplicate);
01830
01831 index = 0;
01832 currVertOffset = 0;
01833
01834 const uint32 *QuadPtr = srcBlock.getQuadPointer();
01835 const uint32 *currQuadPtr;
01836 for (k = 0; k < nbReplicate; ++k)
01837 {
01838 currQuadPtr = QuadPtr;
01839 for (l = 0; l < numQuad; ++l)
01840 {
01841 destBlock.setQuad(index, currQuadPtr[0] + currVertOffset, currQuadPtr[1] + currVertOffset, currQuadPtr[2] + currVertOffset, currQuadPtr[3] + currVertOffset);
01842 currQuadPtr += 4;
01843 ++ index;
01844 }
01845 currVertOffset += vertOffset;
01846 }
01847
01848
01849 uint numLine = srcBlock.getNumLine();
01850 destBlock.reserveLine(numLine * nbReplicate);
01851
01852 index = 0;
01853 currVertOffset = 0;
01854
01855 const uint32 *LinePtr = srcBlock.getLinePointer();
01856 const uint32 *currLinePtr;
01857 for (k = 0; k < nbReplicate; ++k)
01858 {
01859 currLinePtr = LinePtr;
01860 for (l = 0; l < numLine; ++l)
01861 {
01862 destBlock.setLine(index, currLinePtr[0] + currVertOffset, currLinePtr[1] + currVertOffset);
01863 currLinePtr += 4;
01864 ++ index;
01865 }
01866 currVertOffset += vertOffset;
01867 }
01868
01869
01870
01871
01872 PARTICLES_CHECK_MEM;
01873 }
01874
01875
01876 void CPSConstraintMesh::initPrerotVB()
01877 {
01878
01879 _PreRotatedMeshVB.setVertexFormat(CVertexBuffer::PositionFlag);
01880 _PreRotatedMeshVB.setNumVertices(ConstraintMeshMaxNumPrerotatedModels * ConstraintMeshMaxNumVerts);
01881
01882
01883 _PreRotatedMeshVBWithNormal.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag);
01884 _PreRotatedMeshVBWithNormal.setNumVertices(ConstraintMeshMaxNumPrerotatedModels * ConstraintMeshMaxNumVerts);
01885 }
01886
01887
01888 CPSConstraintMesh::CMeshDisplay &CPSConstraintMesh::CMeshDisplayShare::getMeshDisplay(IShape *shape, uint32 format)
01889 {
01890 CKey key;
01891 key.Shape = shape;
01892 key.Format = format;
01893 if (MDMap.count(key))
01894 {
01895 nlassert(MDMap[key]);
01896 return *MDMap[key];
01897 }
01898 else
01899 {
01900 if (MDQueue.size() == _MaxNumMD)
01901 {
01902
01903 nlassert(MDMap.count(MDQueue.front()));
01904 MDMap.erase(MDQueue.front());
01905 MDQueue.pop();
01906 }
01907 std::auto_ptr<CMeshDisplay> MD(new CMeshDisplay);
01908
01909
01910 buildRdrPassSet(MD->RdrPasses, shape);
01911
01912
01913 buildVB(format, MD->VB, shape);
01914
01915 MDQueue.push(key);
01916 MDMap[key] = MD.get();
01917 return *(MD.release());
01918 }
01919 }
01920
01921
01922
01923 CPSConstraintMesh::CMeshDisplayShare::~CMeshDisplayShare()
01924 {
01925 for (TMDMap::iterator it = MDMap.begin(); it != MDMap.end(); ++it)
01926 {
01927 delete it->second;
01928 }
01929 }
01930
01931
01932 void CPSConstraintMesh::CMeshDisplayShare::buildRdrPassSet(TRdrPassSet &dest, const IShape *shape)
01933 {
01934 const CMesh &m = *NLMISC::safe_cast<const CMesh *>(shape);
01935
01936 nlassert(m.getNbMatrixBlock() == 1);
01937
01938 dest.resize(m.getNbRdrPass(0));
01939 const CVertexBuffer &srcVb = m.getVertexBuffer();
01940
01941 for (uint k = 0; k < m.getNbRdrPass(0); ++k)
01942 {
01943 dest[k].Mat = m.getMaterial(m.getRdrPassMaterial(0, k));
01944 dest[k].SourceMat = dest[k].Mat;
01945 DuplicatePrimitiveBlock(m.getRdrPassPrimitiveBlock(0, k), dest[k].Pb, ConstraintMeshBufSize, srcVb.getNumVertices() );
01946 }
01947 }
01948
01949
01950 void CPSConstraintMesh::CMeshDisplayShare::buildVB(uint32 destFormat, CVertexBuffer &dest, const IShape *shape)
01951 {
01953 nlassert(shape);
01954 const CMesh &m = *NLMISC::safe_cast<const CMesh *>(shape);
01955 const CVertexBuffer &meshVb = m.getVertexBuffer();
01956 nlassert(destFormat == meshVb.getVertexFormat() || destFormat == (meshVb.getVertexFormat() | (uint32) CVertexBuffer::PrimaryColorFlag) );
01957 dest.setVertexFormat(destFormat);
01958 dest.setNumVertices(ConstraintMeshBufSize * meshVb.getNumVertices());
01959
01960 uint8 *outPtr = (uint8 *) dest.getVertexCoordPointer();
01961 uint8 *inPtr = (uint8 *) meshVb.getVertexCoordPointer();
01962 uint meshSize = dest.getVertexSize() * meshVb.getNumVertices();
01963
01964 if (destFormat == meshVb.getVertexFormat())
01965 {
01966 for (uint k = 0; k < ConstraintMeshBufSize; ++k)
01967 {
01968 ::memcpy((void *) (outPtr + k * meshSize), (void *) inPtr, meshSize);
01969 }
01970 }
01971 else
01972 {
01973 sint colorOff = dest.getColorOff();
01974 uint inVSize = meshVb.getVertexSize();
01975 uint outVSize = dest.getVertexSize();
01976 for (uint k = 0; k < ConstraintMeshBufSize; ++k)
01977 {
01978 for (uint v = 0; v < meshVb.getNumVertices(); ++v)
01979 {
01980
01981 ::memcpy((void *) (outPtr + k * meshSize + v * outVSize), (void *) (inPtr + v * inVSize), colorOff);
01982
01983 ::memcpy((void *) (outPtr + k * meshSize + v * outVSize + colorOff + sizeof(uint8[4])), (void *) (inPtr + v * inVSize + colorOff), inVSize - colorOff);
01984 }
01985 }
01986 }
01987 }
01988
01989
01990 CPSConstraintMesh::CMeshDisplayShare::CKey::~CKey()
01991 {
01992 }
01993
01994
01995 CPSConstraintMesh::CGlobalTexAnim::CGlobalTexAnim() : TransSpeed(NLMISC::CVector2f::Null),
01996 TransAccel(NLMISC::CVector2f::Null),
01997 ScaleStart(1 ,1),
01998 ScaleSpeed(NLMISC::CVector2f::Null),
01999 ScaleAccel(NLMISC::CVector2f::Null),
02000 WRotSpeed(0),
02001 WRotAccel(0)
02002 {
02003 }
02004
02005
02006 void CPSConstraintMesh::CGlobalTexAnim::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02007 {
02008 f.serialVersion(0);
02009 f.serial(TransSpeed, TransAccel, ScaleStart, ScaleSpeed, ScaleAccel);
02010 f.serial(WRotSpeed, WRotAccel);
02011 }
02012
02013
02014 void CPSConstraintMesh::CGlobalTexAnim::buildMatrix(float &date, NLMISC::CMatrix &dest)
02015 {
02016 float fDate = (float) date;
02017 float halfDateSquared = 0.5f * fDate * fDate;
02018 NLMISC::CVector2f pos = fDate * TransSpeed + halfDateSquared * fDate * TransAccel;
02019 NLMISC::CVector2f scale = ScaleStart + fDate * ScaleSpeed + halfDateSquared * fDate * ScaleAccel;
02020 float rot = fDate * WRotSpeed + halfDateSquared * WRotAccel;
02021
02022
02023 float fCos, fSin;
02024 if (rot != 0.f)
02025 {
02026 fCos = ::cosf(- rot);
02027 fSin = ::sinf(- rot);
02028 }
02029 else
02030 {
02031 fCos = 1.f;
02032 fSin = 0.f;
02033 }
02034
02035 NLMISC::CVector I(fCos, fSin, 0);
02036 NLMISC::CVector J(-fSin, fCos, 0);
02037 dest.setRot(scale.x * I, scale.y * J, NLMISC::CVector::K);
02038 NLMISC::CVector center(-0.5f, -0.5f, 0.f);
02039 NLMISC::CVector t(pos.x, pos.y, 0);
02040 dest.setPos(t + dest.mulVector(center) - center);
02041 }
02042
02043
02044 void CPSConstraintMesh::setGlobalTexAnim(uint stage, const CGlobalTexAnim &properties)
02045 {
02046 nlassert(_GlobalAnimationEnabled != 0);
02047 nlassert(stage < IDRV_MAT_MAXTEXTURES);
02048 nlassert(_GlobalTexAnims.get());
02049 _GlobalTexAnims->Anims[stage] = properties;
02050 }
02051
02052
02053 const CPSConstraintMesh::CGlobalTexAnim &CPSConstraintMesh::getGlobalTexAnim(uint stage) const
02054 {
02055 nlassert(_GlobalAnimationEnabled != 0);
02056 nlassert(stage < IDRV_MAT_MAXTEXTURES);
02057 nlassert(_GlobalTexAnims.get());
02058 return _GlobalTexAnims->Anims[stage];
02059 }
02060
02061
02062
02063 CPSConstraintMesh::TTexAnimType CPSConstraintMesh::getTexAnimType() const
02064 {
02065 return (TTexAnimType) (_GlobalAnimationEnabled != 0 ? GlobalAnim : NoAnim);
02066 }
02067
02068
02069 void CPSConstraintMesh::setTexAnimType(TTexAnimType type)
02070 {
02071 nlassert(type < Last);
02072 if (type == getTexAnimType()) return;
02073 switch (type)
02074 {
02075 case NoAnim:
02076 _GlobalTexAnims.reset();
02077 restoreMaterials();
02078 _GlobalAnimationEnabled = 0;
02079 break;
02080 case GlobalAnim:
02081 {
02082 PGlobalTexAnims newPtr(new CGlobalTexAnims);
02083 std::swap(_GlobalTexAnims, newPtr);
02084 _GlobalAnimationEnabled = 1;
02085 }
02086 break;
02087 default: break;
02088 }
02089 }
02090
02091
02092 void CPSConstraintMesh::CGlobalTexAnims::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02093 {
02094 f.serialVersion(0);
02095 for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
02096 {
02097 f.serial(Anims[k]);
02098 }
02099 }
02100
02101
02102 void CPSConstraintMesh::restoreMaterials()
02103 {
02104 update();
02105 CMesh &mesh = * NLMISC::safe_cast<CMesh *>((IShape *) _Shapes[0]);
02106 const CVertexBuffer &modelVb = mesh.getVertexBuffer();
02107 CMeshDisplay &md= _MeshDisplayShare.getMeshDisplay(_Shapes[0], modelVb.getVertexFormat()
02108 | (_ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
02109
02110 TRdrPassSet rdrPasses = md.RdrPasses;
02111
02112 for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin()
02113 ; rdrPassIt != rdrPasses.end(); ++rdrPassIt)
02114 {
02115 rdrPassIt->Mat = rdrPassIt->SourceMat;
02116 }
02117 }
02118
02119 }