Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / 3d / ps_face_look_at.cpp
blob000db78e6b12cc575bd85eda1882c41205eeef5b
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/3d/ps_face_look_at.h"
20 #include "nel/3d/ps_macro.h"
21 #include "nel/3d/driver.h"
22 #include "nel/3d/ps_iterator.h"
23 #include "nel/3d/particle_system.h"
24 #include "nel/3d/debug_vb.h"
26 #include "nel/misc/fast_floor.h"
28 #ifdef DEBUG_NEW
29 #define new DEBUG_NEW
30 #endif
32 namespace NL3D
36 /** vector giving the orientation of look at
38 struct CLookAtAlign
40 CVector I;
41 CVector K;
45 uint64 PSLookAtRenderTime = 0;
48 //////////////////////////////////
49 // CPSFaceLookAt implementation //
50 //////////////////////////////////
53 /** Well, we could have put a method template in CPSFaceLookAt, but some compilers
54 * want the definition of the methods in the header, and some compilers
55 * don't want friend with function template, so we use a static method template of a friend class instead,
56 * which gives us the same result :)
58 class CPSFaceLookAtHelper
60 public:
61 /** compute orientation vectors depending on speed
63 template <class T>
64 static void computeOrientationVectors(T speedIt, const CVector &I, const CVector &K, CLookAtAlign *dest, uint size)
66 NL_PS_FUNC(CPSFaceLookAtHelper_computeOrientationVectors)
67 nlassert(size > 0);
68 const CLookAtAlign *endDest = dest + size;
71 // tmp unoptimized slow version
72 CVector normedSpeed = (*speedIt).normed();
73 float iProj = normedSpeed * I;
74 float kProj = normedSpeed * K;
75 dest->I = iProj * I + kProj * K;
76 dest->K = (- kProj * I + iProj * K).normed();
77 ++ speedIt;
78 ++ dest;
80 while(dest != endDest);
83 /** Draw look at and align them on motion
85 template <class T>
86 static void drawLookAtAlignOnMotion(T it, T speedIt, CPSFaceLookAt &la, uint size, uint32 srcStep)
88 PARTICLES_CHECK_MEM;
89 nlassert(la._Owner);
90 IDriver *driver = la.getDriver();
92 if (la._ColorScheme)
94 la._ColorScheme->setColorType(driver->getVertexColorFormat());
97 CVertexBuffer &vb = la.getNeededVB(*driver);
98 la.updateMatBeforeRendering(driver, vb);
100 la._Owner->incrementNbDrawnParticles(size); // for benchmark purpose
101 la.setupDriverModelMatrix();
102 //driver->activeVertexBuffer(vb);
103 const CVector I = la.computeI();
104 const CVector K = la.computeK();
105 const float *rotTable = CPSRotated2DParticle::getRotTable();
106 // for each the particle can be constantly rotated or have an independant rotation for each particle
107 // number of face left, and number of face to process at once
108 uint32 leftToDo = size, toProcess;
109 float pSizes[CPSQuad::quadBufSize]; // the sizes to use
110 float pSecondSizes[CPSQuad::quadBufSize]; // the second sizes to use
111 uint8 laAlignRaw[sizeof(CLookAtAlign) * CPSQuad::quadBufSize]; // orientation computed from motion for each particle
112 CLookAtAlign *laAlign = (CLookAtAlign *) laAlignRaw; // cast to avoid unilined ctor calls
113 float *currentSize;
114 uint32 currentSizeStep = la._SizeScheme ? 1 : 0;
115 // point the vector part in the current vertex
116 uint8 *ptPos;
117 // strides to go from one vertex to another one
118 const uint32 stride = vb.getVertexSize();
119 if (!la._Angle2DScheme)
121 // constant rotation case
124 toProcess = leftToDo <= (uint32) CPSQuad::quadBufSize ? leftToDo : (uint32) CPSQuad::quadBufSize;
125 vb.setNumVertices(4 * toProcess);
126 // restart at the beginning of the vertex buffer
127 CVertexBufferReadWrite vba;
128 vb.lock (vba);
129 ptPos = (uint8 *) vba.getVertexCoordPointer();
130 if (la._SizeScheme)
132 currentSize = (float *) la._SizeScheme->make(la._Owner, size- leftToDo, pSizes, sizeof(float), toProcess, true, srcStep);
134 else
136 currentSize = &la._ParticleSize;
138 computeOrientationVectors(speedIt, I, K, laAlign, toProcess);
139 speedIt = speedIt + toProcess;
140 const CLookAtAlign *currAlign = laAlign;
142 la.updateVbColNUVForRender(vb, size - leftToDo, toProcess, srcStep, *driver);
143 T endIt = it + toProcess;
144 if (!la._IndependantSizes)
146 const uint32 tabIndex = (((uint32) la._Angle2D) & 0xff) << 2;
147 CVector v1;
148 CVector v2;
149 // TODO : optimize if necessary
150 while (it != endIt)
152 v1 = rotTable[tabIndex] * currAlign->I + rotTable[tabIndex + 1] * currAlign->K;
153 v2 = rotTable[tabIndex + 2] * currAlign->I + rotTable[tabIndex + 3] * currAlign->K;
154 CHECK_VERTEX_BUFFER(vb, ptPos);
155 ((CVector *) ptPos)->x = (*it).x + *currentSize * v1.x;
156 ((CVector *) ptPos)->y = (*it).y + *currentSize * v1.y;
157 ((CVector *) ptPos)->z = (*it).z + *currentSize * v1.z;
158 ptPos += stride;
160 CHECK_VERTEX_BUFFER(vb, ptPos);
161 ((CVector *) ptPos)->x = (*it).x + *currentSize * v2.x;
162 ((CVector *) ptPos)->y = (*it).y + *currentSize * v2.y;
163 ((CVector *) ptPos)->z = (*it).z + *currentSize * v2.z;
164 ptPos += stride;
166 CHECK_VERTEX_BUFFER(vb, ptPos);
167 ((CVector *) ptPos)->x = (*it).x - *currentSize * v1.x;
168 ((CVector *) ptPos)->y = (*it).y - *currentSize * v1.y;
169 ((CVector *) ptPos)->z = (*it).z - *currentSize * v1.z;
170 ptPos += stride;
172 CHECK_VERTEX_BUFFER(vb, ptPos);
173 ((CVector *) ptPos)->x = (*it).x - *currentSize * v2.x;
174 ((CVector *) ptPos)->y = (*it).y - *currentSize * v2.y;
175 ((CVector *) ptPos)->z = (*it).z - *currentSize * v2.z;
176 ptPos += stride;
178 ++it;
179 ++currAlign;
180 currentSize += currentSizeStep;
183 else // independant sizes
185 float *currentSize2;
186 float secondSize;
187 uint32 currentSizeStep2;
188 if (la._SecondSize.getSizeScheme())
190 currentSize2 = (float *) la._SecondSize.getSizeScheme()->make(la._Owner, size- leftToDo, pSecondSizes, sizeof(float), toProcess, true, srcStep);
191 currentSizeStep2 = 1;
193 else
195 secondSize = la._SecondSize.getSize();
196 currentSize2 = &secondSize;
197 currentSizeStep2 = 0;
199 CVector v1;
200 CVector v2;
201 // TODO : optimize if necessary
202 while (it != endIt)
204 v1 = CPSUtil::getCos((sint32) la._Angle2D) * currAlign->I + CPSUtil::getSin((sint32) la._Angle2D) * currAlign->K;
205 v2 = - CPSUtil::getSin((sint32) la._Angle2D) * currAlign->I + CPSUtil::getCos((sint32) la._Angle2D) * currAlign->K;
206 CHECK_VERTEX_BUFFER(vb, ptPos);
207 ((CVector *) ptPos)->x = (*it).x - *currentSize * v1.x + *currentSize2 * v2.x;
208 ((CVector *) ptPos)->y = (*it).y - *currentSize * v1.y + *currentSize2 * v2.y;
209 ((CVector *) ptPos)->z = (*it).z - *currentSize * v1.z + *currentSize2 * v2.z;
210 ptPos += stride;
212 CHECK_VERTEX_BUFFER(vb, ptPos);
213 ((CVector *) ptPos)->x = (*it).x + *currentSize * v1.x + *currentSize2 * v2.x;
214 ((CVector *) ptPos)->y = (*it).y + *currentSize * v1.y + *currentSize2 * v2.y;
215 ((CVector *) ptPos)->z = (*it).z + *currentSize * v1.z + *currentSize2 * v2.z;
216 ptPos += stride;
218 CHECK_VERTEX_BUFFER(vb, ptPos);
219 ((CVector *) ptPos)->x = (*it).x + *currentSize * v1.x - *currentSize2 * v2.x;
220 ((CVector *) ptPos)->y = (*it).y + *currentSize * v1.y - *currentSize2 * v2.y;
221 ((CVector *) ptPos)->z = (*it).z + *currentSize * v1.z - *currentSize2 * v2.z;
222 ptPos += stride;
224 CHECK_VERTEX_BUFFER(vb, ptPos);
225 ((CVector *) ptPos)->x = (*it).x - *currentSize * v1.x - *currentSize2 * v2.x;
226 ((CVector *) ptPos)->y = (*it).y - *currentSize * v1.y - *currentSize2 * v2.y;
227 ((CVector *) ptPos)->z = (*it).z - *currentSize * v1.z - *currentSize2 * v2.z;
228 ptPos += stride;
229 ++it;
230 ++currAlign;
231 currentSize += currentSizeStep;
232 currentSize2 += currentSizeStep2;
235 // uint64 startTick = NLMISC::CTime::getPerformanceTime();
236 vba.unlock();
237 driver->activeVertexBuffer(vb);
238 driver->renderRawQuads(la._Mat, 0, toProcess);
239 // PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;
240 leftToDo -= toProcess;
242 while (leftToDo);
244 else
246 float pAngles[CPSQuad::quadBufSize]; // the angles to use
247 float *currentAngle;
250 toProcess = leftToDo <= (uint32) CPSQuad::quadBufSize ? leftToDo : (uint32) CPSQuad::quadBufSize;
251 vb.setNumVertices(4 * toProcess);
252 // restart at the beginning of the vertex buffer
253 CVertexBufferReadWrite vba;
254 vb.lock (vba);
255 ptPos = (uint8 *) vba.getVertexCoordPointer();
256 if (la._SizeScheme)
258 currentSize = (float *) la._SizeScheme->make(la._Owner, size - leftToDo, pSizes, sizeof(float), toProcess, true, srcStep);
260 else
262 currentSize = &la._ParticleSize;
264 computeOrientationVectors(speedIt, I, K, laAlign, toProcess);
265 speedIt = speedIt + toProcess;
266 const CLookAtAlign *currAlign = laAlign;
267 currentAngle = (float *) la._Angle2DScheme->make(la._Owner, size - leftToDo, pAngles, sizeof(float), toProcess, true, srcStep);
268 la.updateVbColNUVForRender(vb, size - leftToDo, toProcess, srcStep, *driver);
269 T endIt = it + toProcess;
270 CVector v1, v2;
271 NLMISC::OptFastFloorBegin();
272 if (!la._IndependantSizes)
274 while (it != endIt)
276 const uint32 tabIndex = ((NLMISC::OptFastFloor(*currentAngle)) & 0xff) << 2;
277 // lets avoid some ctor calls
278 v1.x = *currentSize * (rotTable[tabIndex] * currAlign->I.x + rotTable[tabIndex + 1] * currAlign->K.x);
279 v1.y = *currentSize * (rotTable[tabIndex] * currAlign->I.y + rotTable[tabIndex + 1] * currAlign->K.y);
280 v1.z = *currentSize * (rotTable[tabIndex] * currAlign->I.z + rotTable[tabIndex + 1] * currAlign->K.z);
282 v2.x = *currentSize * (rotTable[tabIndex + 2] * currAlign->I.x + rotTable[tabIndex + 3] * currAlign->K.x);
283 v2.y = *currentSize * (rotTable[tabIndex + 2] * currAlign->I.y + rotTable[tabIndex + 3] * currAlign->K.y);
284 v2.z = *currentSize * (rotTable[tabIndex + 2] * currAlign->I.z + rotTable[tabIndex + 3] * currAlign->K.z);
286 CHECK_VERTEX_BUFFER(vb, ptPos);
287 CHECK_VERTEX_BUFFER(vb, ptPos + stride);
288 CHECK_VERTEX_BUFFER(vb, ptPos + stride2);
289 CHECK_VERTEX_BUFFER(vb, ptPos + stride3);
291 ((CVector *) ptPos)->x = (*it).x + v1.x;
292 ((CVector *) ptPos)->y = (*it).y + v1.y;
293 ((CVector *) ptPos)->z = (*it).z + v1.z;
294 ptPos += stride;
296 ((CVector *) ptPos)->x = (*it).x + v2.x;
297 ((CVector *) ptPos)->y = (*it).y + v2.y;
298 ((CVector *) ptPos)->z = (*it).z + v2.z;
299 ptPos += stride;
301 ((CVector *) ptPos)->x = (*it).x - v1.x;
302 ((CVector *) ptPos)->y = (*it).y - v1.y;
303 ((CVector *) ptPos)->z = (*it).z - v1.z;
304 ptPos += stride;
306 ((CVector *) ptPos)->x = (*it).x - v2.x;
307 ((CVector *) ptPos)->y = (*it).y - v2.y;
308 ((CVector *) ptPos)->z = (*it).z - v2.z;
309 ptPos += stride;
311 ++it;
312 ++ currAlign;
313 currentSize += currentSizeStep;
314 ++currentAngle;
317 else // independant size, and non-constant rotation
320 float *currentSize2;
321 float secondSize;
322 uint32 currentSizeStep2;
323 if (la._SecondSize.getSizeScheme())
325 currentSize2 = (float *) la._SecondSize.getSizeScheme()->make(la._Owner, size- leftToDo, pSecondSizes, sizeof(float), toProcess, true, srcStep);
326 currentSizeStep2 = 1;
328 else
330 secondSize = la._SecondSize.getSize();
331 currentSize2 = &secondSize;
332 currentSizeStep2 = 0;
335 float cosAngle, sinAngle;
336 while (it != endIt)
338 cosAngle = CPSUtil::getCos((sint32) *currentAngle);
339 sinAngle = CPSUtil::getSin((sint32) *currentAngle);
340 v1 = cosAngle * currAlign->I + sinAngle * currAlign->K;
341 v2 = - sinAngle * currAlign->I + cosAngle * currAlign->K;
343 CHECK_VERTEX_BUFFER(vb, ptPos);
344 ((CVector *) ptPos)->x = (*it).x - *currentSize * v1.x + *currentSize2 * v2.x;
345 ((CVector *) ptPos)->y = (*it).y - *currentSize * v1.y + *currentSize2 * v2.y;
346 ((CVector *) ptPos)->z = (*it).z - *currentSize * v1.z + *currentSize2 * v2.z;
347 ptPos += stride;
349 CHECK_VERTEX_BUFFER(vb, ptPos);
350 ((CVector *) ptPos)->x = (*it).x + *currentSize * v1.x + *currentSize2 * v2.x;
351 ((CVector *) ptPos)->y = (*it).y + *currentSize * v1.y + *currentSize2 * v2.y;
352 ((CVector *) ptPos)->z = (*it).z + *currentSize * v1.z + *currentSize2 * v2.z;
353 ptPos += stride;
355 CHECK_VERTEX_BUFFER(vb, ptPos);
356 ((CVector *) ptPos)->x = (*it).x + *currentSize * v1.x - *currentSize2 * v2.x;
357 ((CVector *) ptPos)->y = (*it).y + *currentSize * v1.y - *currentSize2 * v2.y;
358 ((CVector *) ptPos)->z = (*it).z + *currentSize * v1.z - *currentSize2 * v2.z;
359 ptPos += stride;
361 CHECK_VERTEX_BUFFER(vb, ptPos);
362 ((CVector *) ptPos)->x = (*it).x - *currentSize * v1.x - *currentSize2 * v2.x;
363 ((CVector *) ptPos)->y = (*it).y - *currentSize * v1.y - *currentSize2 * v2.y;
364 ((CVector *) ptPos)->z = (*it).z - *currentSize * v1.z - *currentSize2 * v2.z;
365 ptPos += stride;
366 ++it;
367 ++currentAngle;
368 ++ currAlign;
369 currentSize += currentSizeStep;
370 currentSize2 += currentSizeStep2;
373 NLMISC::OptFastFloorEnd();
374 //tmp
375 // uint64 startTick = NLMISC::CTime::getPerformanceTime();
376 vba.unlock();
377 driver->activeVertexBuffer(vb);
378 driver->renderRawQuads(la._Mat, 0, toProcess);
379 // PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;
380 leftToDo -= toProcess;
382 while (leftToDo);
384 PARTICLES_CHECK_MEM;
387 /** render look at, but dont align on motion
389 template <class T>
390 static void drawLookAt(T it, T speedIt, CPSFaceLookAt &la, uint size, uint32 srcStep)
392 //uint64 startTick = NLMISC::CTime::getPerformanceTime();
393 PARTICLES_CHECK_MEM;
394 nlassert(la._Owner);
395 IDriver *driver = la.getDriver();
397 if (la._ColorScheme)
399 la._ColorScheme->setColorType(driver->getVertexColorFormat());
402 CVertexBuffer &vb = la.getNeededVB(*driver);
403 la.updateMatBeforeRendering(driver, vb);
405 la._Owner->incrementNbDrawnParticles(size); // for benchmark purpose
406 la.setupDriverModelMatrix();
407 //driver->activeVertexBuffer(vb);
408 CVector I;
409 CVector J;
410 CVector K;
411 if (!la._AlignOnZAxis)
413 I = la.computeI();
414 J = la.computeJ();
415 K = la.computeK();
417 else
419 I = la.computeIWithZAxisAligned();
420 K = la.computeKWithZAxisAligned();
421 J = K ^ I;
423 const float *rotTable = CPSRotated2DParticle::getRotTable();
424 // for each the particle can be constantly rotated or have an independant rotation for each particle
425 // number of face left, and number of face to process at once
426 uint32 leftToDo = size, toProcess;
427 float pSizes[CPSQuad::quadBufSize]; // the sizes to use
428 float pSecondSizes[CPSQuad::quadBufSize]; // the second sizes to use
429 float *currentSize;
430 uint32 currentSizeStep = la._SizeScheme ? 1 : 0;
431 // point the vector part in the current vertex
432 uint8 *ptPos;
433 // strides to go from one vertex to another one
434 const uint32 stride = vb.getVertexSize(), stride2 = stride << 1, stride3 = stride + stride2, stride4 = stride << 2;
435 //PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;
436 if (!la._Angle2DScheme)
438 // constant rotation case
441 toProcess = leftToDo <= (uint32) CPSQuad::quadBufSize ? leftToDo : (uint32) CPSQuad::quadBufSize;
442 vb.setNumVertices(4 * toProcess);
443 // restart at the beginning of the vertex buffer
444 CVertexBufferReadWrite vba;
445 vb.lock (vba);
446 ptPos = (uint8 *) vba.getVertexCoordPointer();
447 if (la._SizeScheme)
449 currentSize = (float *) la._SizeScheme->make(la._Owner, size- leftToDo, pSizes, sizeof(float), toProcess, true, srcStep);
451 else
453 currentSize = &la._ParticleSize;
456 la.updateVbColNUVForRender(vb, size - leftToDo, toProcess, srcStep, *driver);
457 T endIt = it + toProcess;
458 if (la._MotionBlurCoeff == 0.f)
460 if (!la._IndependantSizes)
462 const uint32 tabIndex = (((uint32) la._Angle2D) & 0xff) << 2;
463 const CVector v1 = rotTable[tabIndex] * I + rotTable[tabIndex + 1] * K;
464 const CVector v2 = rotTable[tabIndex + 2] * I + rotTable[tabIndex + 3] * K;
465 if (currentSizeStep)
467 while (it != endIt)
469 CHECK_VERTEX_BUFFER(vb, ptPos);
470 ((CVector *) ptPos)->x = (*it).x + *currentSize * v1.x;
471 ((CVector *) ptPos)->y = (*it).y + *currentSize * v1.y;
472 ((CVector *) ptPos)->z = (*it).z + *currentSize * v1.z;
473 ptPos += stride;
475 CHECK_VERTEX_BUFFER(vb, ptPos);
476 ((CVector *) ptPos)->x = (*it).x + *currentSize * v2.x;
477 ((CVector *) ptPos)->y = (*it).y + *currentSize * v2.y;
478 ((CVector *) ptPos)->z = (*it).z + *currentSize * v2.z;
479 ptPos += stride;
481 CHECK_VERTEX_BUFFER(vb, ptPos);
482 ((CVector *) ptPos)->x = (*it).x - *currentSize * v1.x;
483 ((CVector *) ptPos)->y = (*it).y - *currentSize * v1.y;
484 ((CVector *) ptPos)->z = (*it).z - *currentSize * v1.z;
485 ptPos += stride;
487 CHECK_VERTEX_BUFFER(vb, ptPos);
488 ((CVector *) ptPos)->x = (*it).x - *currentSize * v2.x;
489 ((CVector *) ptPos)->y = (*it).y - *currentSize * v2.y;
490 ((CVector *) ptPos)->z = (*it).z - *currentSize * v2.z;
491 ptPos += stride;
493 ++it;
494 currentSize += currentSizeStep;
497 else
499 // constant size
500 const CVector myV1 = *currentSize * v1;
501 const CVector myV2 = *currentSize * v2;
503 while (it != endIt)
505 CHECK_VERTEX_BUFFER(vb, ptPos);
506 ((CVector *) ptPos)->x = (*it).x + myV1.x;
507 ((CVector *) ptPos)->y = (*it).y + myV1.y;
508 ((CVector *) ptPos)->z = (*it).z + myV1.z;
509 ptPos += stride;
511 CHECK_VERTEX_BUFFER(vb, ptPos);
512 ((CVector *) ptPos)->x = (*it).x + myV2.x;
513 ((CVector *) ptPos)->y = (*it).y + myV2.y;
514 ((CVector *) ptPos)->z = (*it).z + myV2.z;
515 ptPos += stride;
517 CHECK_VERTEX_BUFFER(vb, ptPos);
518 ((CVector *) ptPos)->x = (*it).x - myV1.x;
519 ((CVector *) ptPos)->y = (*it).y - myV1.y;
520 ((CVector *) ptPos)->z = (*it).z - myV1.z;
521 ptPos += stride;
523 CHECK_VERTEX_BUFFER(vb, ptPos);
524 ((CVector *) ptPos)->x = (*it).x - myV2.x;
525 ((CVector *) ptPos)->y = (*it).y - myV2.y;
526 ((CVector *) ptPos)->z = (*it).z - myV2.z;
527 ptPos += stride;
528 ++it;
532 else // independant sizes
534 const CVector v1 = CPSUtil::getCos((sint32) la._Angle2D) * I + CPSUtil::getSin((sint32) la._Angle2D) * K;
535 const CVector v2 = - CPSUtil::getSin((sint32) la._Angle2D) * I + CPSUtil::getCos((sint32) la._Angle2D) * K;
537 float *currentSize2;
538 float secondSize;
539 uint32 currentSizeStep2;
540 if (la._SecondSize.getSizeScheme())
542 currentSize2 = (float *) la._SecondSize.getSizeScheme()->make(la._Owner, size- leftToDo, pSecondSizes, sizeof(float), toProcess, true, srcStep);
543 currentSizeStep2 = 1;
545 else
547 secondSize = la._SecondSize.getSize();
548 currentSize2 = &secondSize;
549 currentSizeStep2 = 0;
553 while (it != endIt)
555 CHECK_VERTEX_BUFFER(vb, ptPos);
556 ((CVector *) ptPos)->x = (*it).x - *currentSize * v1.x + *currentSize2 * v2.x;
557 ((CVector *) ptPos)->y = (*it).y - *currentSize * v1.y + *currentSize2 * v2.y;
558 ((CVector *) ptPos)->z = (*it).z - *currentSize * v1.z + *currentSize2 * v2.z;
559 ptPos += stride;
561 CHECK_VERTEX_BUFFER(vb, ptPos);
562 ((CVector *) ptPos)->x = (*it).x + *currentSize * v1.x + *currentSize2 * v2.x;
563 ((CVector *) ptPos)->y = (*it).y + *currentSize * v1.y + *currentSize2 * v2.y;
564 ((CVector *) ptPos)->z = (*it).z + *currentSize * v1.z + *currentSize2 * v2.z;
565 ptPos += stride;
567 CHECK_VERTEX_BUFFER(vb, ptPos);
568 ((CVector *) ptPos)->x = (*it).x + *currentSize * v1.x - *currentSize2 * v2.x;
569 ((CVector *) ptPos)->y = (*it).y + *currentSize * v1.y - *currentSize2 * v2.y;
570 ((CVector *) ptPos)->z = (*it).z + *currentSize * v1.z - *currentSize2 * v2.z;
571 ptPos += stride;
573 CHECK_VERTEX_BUFFER(vb, ptPos);
574 ((CVector *) ptPos)->x = (*it).x - *currentSize * v1.x - *currentSize2 * v2.x;
575 ((CVector *) ptPos)->y = (*it).y - *currentSize * v1.y - *currentSize2 * v2.y;
576 ((CVector *) ptPos)->z = (*it).z - *currentSize * v1.z - *currentSize2 * v2.z;
577 ptPos += stride;
578 ++it;
579 currentSize += currentSizeStep;
580 currentSize2 += currentSizeStep2;
583 //tmp
584 //uint64 startTick = NLMISC::CTime::getPerformanceTime();
585 vba.unlock();
586 driver->activeVertexBuffer(vb);
587 driver->renderRawQuads(la._Mat, 0, toProcess);
588 //PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;
590 else
592 // perform motion, blur, we need an iterator on speed
593 // independant sizes and rotation not supported for now with motion blur
594 const CVector v1 = I + K;
595 const CVector v2 = K - I;
596 CVector startV, endV, mbv1, mbv1n, mbv12, mbv2;
597 // norme of the v1 vect
598 float n;
599 const float epsilon = 10E-5f;
600 const float normEpsilon = 10E-6f;
602 CMatrix tMat = la.getViewMat() * la._Owner->getLocalToWorldMatrix();
604 while (it != endIt)
606 // project the speed in the projection plane
607 // this give us the v1 vect
608 startV = tMat * *it ;
609 endV = tMat * (*it + *speedIt);
610 if (startV.y > epsilon || endV.y > epsilon)
612 if (startV.y < epsilon)
614 if (fabsf(endV.y - startV.y) > normEpsilon)
616 startV = endV + (endV.y - epsilon) / (endV.y - startV.y) * (startV - endV);
618 startV.y = epsilon;
620 else if (endV.y < epsilon)
622 if (fabsf(endV.y - startV.y) > normEpsilon)
624 endV = startV + (startV.y - epsilon) / (startV.y - endV.y) * (endV - startV);
626 endV.y = epsilon;
629 mbv1 = (startV.x / startV.y - endV.x / endV.y) * I
630 + (startV.z / startV.y - endV.z / endV.y) * K ;
632 n = mbv1.norm();
633 if (n > la._Threshold)
635 mbv1 *= la._Threshold / n;
636 n = la._Threshold;
638 if (n > normEpsilon)
640 mbv1n = mbv1 / n;
641 mbv2 = *currentSize * (J ^ mbv1n);
642 mbv12 = -*currentSize * mbv1n;
643 mbv1 *= *currentSize * (1 + la._MotionBlurCoeff * n * n) / n;
645 *(CVector *) ptPos = *it - mbv2;
646 *(CVector *) (ptPos + stride) = *it + mbv1;
647 *(CVector *) (ptPos + stride2) = *it + mbv2;
648 *(CVector *) (ptPos + stride3) = *it + mbv12;
651 CHECK_VERTEX_BUFFER(vb, ptPos);
652 ((CVector *) ptPos)->x = (*it).x - mbv2.x;
653 ((CVector *) ptPos)->y = (*it).y - mbv2.y;
654 ((CVector *) ptPos)->z = (*it).z - mbv2.z;
656 CHECK_VERTEX_BUFFER(vb, ptPos + stride);
657 ((CVector *) (ptPos + stride))->x = (*it).x + mbv1.x;
658 ((CVector *) (ptPos + stride))->y = (*it).y + mbv1.y;
659 ((CVector *) (ptPos + stride))->z = (*it).z + mbv1.z;
661 CHECK_VERTEX_BUFFER(vb, ptPos + stride2);
662 ((CVector *) (ptPos + stride2))->x = (*it).x + mbv2.x;
663 ((CVector *) (ptPos + stride2))->y = (*it).y + mbv2.y;
664 ((CVector *) (ptPos + stride2))->z = (*it).z + mbv2.z;
667 CHECK_VERTEX_BUFFER(vb, ptPos + stride3);
668 ((CVector *) (ptPos + stride3))->x = (*it).x + mbv12.x;
669 ((CVector *) (ptPos + stride3))->y = (*it).y + mbv12.y;
670 ((CVector *) (ptPos + stride3))->z = (*it).z + mbv12.z;
673 else // speed too small, we must avoid imprecision
675 CHECK_VERTEX_BUFFER(vb, ptPos);
676 ((CVector *) ptPos)->x = (*it).x - *currentSize * v2.x;
677 ((CVector *) ptPos)->y = (*it).y - *currentSize * v2.y;
678 ((CVector *) ptPos)->z = (*it).z - *currentSize * v2.z;
680 CHECK_VERTEX_BUFFER(vb, ptPos + stride);
681 ((CVector *) (ptPos + stride))->x = (*it).x + *currentSize * v1.x;
682 ((CVector *) (ptPos + stride))->y = (*it).y + *currentSize * v1.y;
683 ((CVector *) (ptPos + stride))->z = (*it).z + *currentSize * v1.z;
685 CHECK_VERTEX_BUFFER(vb, ptPos + stride2);
686 ((CVector *) (ptPos + stride2))->x = (*it).x + *currentSize * v2.x;
687 ((CVector *) (ptPos + stride2))->y = (*it).y + *currentSize * v2.y;
688 ((CVector *) (ptPos + stride2))->z = (*it).z + *currentSize * v2.z;
691 CHECK_VERTEX_BUFFER(vb, ptPos + stride3);
692 ((CVector *) (ptPos + stride3))->x = (*it).x - *currentSize * v1.x;
693 ((CVector *) (ptPos + stride3))->y = (*it).y - *currentSize * v1.y;
694 ((CVector *) (ptPos + stride3))->z = (*it).z - *currentSize * v1.z;
697 else
700 CHECK_VERTEX_BUFFER(vb, ptPos);
701 ((CVector *) ptPos)->x = (*it).x - *currentSize * v2.x;
702 ((CVector *) ptPos)->y = (*it).y - *currentSize * v2.y;
703 ((CVector *) ptPos)->z = (*it).z - *currentSize * v2.z;
705 CHECK_VERTEX_BUFFER(vb, ptPos + stride);
706 ((CVector *) (ptPos + stride))->x = (*it).x + *currentSize * v1.x;
707 ((CVector *) (ptPos + stride))->y = (*it).y + *currentSize * v1.y;
708 ((CVector *) (ptPos + stride))->z = (*it).z + *currentSize * v1.z;
710 CHECK_VERTEX_BUFFER(vb, ptPos + stride2);
711 ((CVector *) (ptPos + stride2))->x = (*it).x + *currentSize * v2.x;
712 ((CVector *) (ptPos + stride2))->y = (*it).y + *currentSize * v2.y;
713 ((CVector *) (ptPos + stride2))->z = (*it).z + *currentSize * v2.z;
716 CHECK_VERTEX_BUFFER(vb, ptPos + stride3);
717 ((CVector *) (ptPos + stride3))->x = (*it).x - *currentSize * v1.x;
718 ((CVector *) (ptPos + stride3))->y = (*it).y - *currentSize * v1.y;
719 ((CVector *) (ptPos + stride3))->z = (*it).z - *currentSize * v1.z;
722 ptPos += stride4;
723 ++it;
724 ++speedIt;
725 currentSize += currentSizeStep;
727 //uint64 startTick = NLMISC::CTime::getPerformanceTime();
728 vba.unlock();
729 driver->activeVertexBuffer(vb);
730 driver->renderRawQuads(la._Mat, 0, toProcess);
731 //PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;
733 leftToDo -= toProcess;
735 while (leftToDo);
737 else
739 float pAngles[CPSQuad::quadBufSize]; // the angles to use
740 float *currentAngle;
743 toProcess = leftToDo <= (uint32) CPSQuad::quadBufSize ? leftToDo : (uint32) CPSQuad::quadBufSize;
744 vb.setNumVertices(4 * toProcess);
745 // restart at the beginning of the vertex buffer
746 CVertexBufferReadWrite vba;
747 vb.lock (vba);
748 ptPos = (uint8 *) vba.getVertexCoordPointer();
749 if (la._SizeScheme)
751 currentSize = (float *) la._SizeScheme->make(la._Owner, size - leftToDo, pSizes, sizeof(float), toProcess, true, srcStep);
753 else
755 currentSize = &la._ParticleSize;
757 currentAngle = (float *) la._Angle2DScheme->make(la._Owner, size - leftToDo, pAngles, sizeof(float), toProcess, true, srcStep);
758 la.updateVbColNUVForRender(vb, size - leftToDo, toProcess, srcStep, *driver);
760 static bool fakeColors = false;
761 if (fakeColors)
763 uint8 *col = (uint8 *) vba.getColorPointer();
764 uint left = toProcess;
765 while(left--)
767 * (CRGBA *) col = CRGBA::Red;
768 col += stride;
769 * (CRGBA *) col = CRGBA::Red;
770 col += stride;
771 * (CRGBA *) col = CRGBA::Red;
772 col += stride;
773 * (CRGBA *) col = CRGBA::Red;
774 col += stride;
778 //nlinfo("======= %s", la._Name.c_str());
779 T endIt = it + toProcess;
780 CVector v1, v2;
781 NLMISC::OptFastFloorBegin();
782 if (!la._IndependantSizes)
784 while (it != endIt)
786 const uint32 tabIndex = ((NLMISC::OptFastFloor(*currentAngle)) & 0xff) << 2;
787 // lets avoid some ctor calls
788 v1.x = *currentSize * (rotTable[tabIndex] * I.x + rotTable[tabIndex + 1] * K.x);
789 v1.y = *currentSize * (rotTable[tabIndex] * I.y + rotTable[tabIndex + 1] * K.y);
790 v1.z = *currentSize * (rotTable[tabIndex] * I.z + rotTable[tabIndex + 1] * K.z);
792 v2.x = *currentSize * (rotTable[tabIndex + 2] * I.x + rotTable[tabIndex + 3] * K.x);
793 v2.y = *currentSize * (rotTable[tabIndex + 2] * I.y + rotTable[tabIndex + 3] * K.y);
794 v2.z = *currentSize * (rotTable[tabIndex + 2] * I.z + rotTable[tabIndex + 3] * K.z);
796 CHECK_VERTEX_BUFFER(vb, ptPos);
797 CHECK_VERTEX_BUFFER(vb, ptPos + stride);
798 CHECK_VERTEX_BUFFER(vb, ptPos + stride2);
799 CHECK_VERTEX_BUFFER(vb, ptPos + stride3);
801 ((CVector *) ptPos)->x = (*it).x + v1.x;
802 ((CVector *) ptPos)->y = (*it).y + v1.y;
803 ((CVector *) ptPos)->z = (*it).z + v1.z;
804 //nlinfo("** %f, %f, %f", ((CVector *) ptPos)->x, ((CVector *) ptPos)->y, ((CVector *) ptPos)->z);
805 ptPos += stride;
809 ((CVector *) ptPos)->x = (*it).x + v2.x;
810 ((CVector *) ptPos)->y = (*it).y + v2.y;
811 ((CVector *) ptPos)->z = (*it).z + v2.z;
812 //nlinfo("%f, %f, %f", ((CVector *) ptPos)->x, ((CVector *) ptPos)->y, ((CVector *) ptPos)->z);
813 ptPos += stride;
815 ((CVector *) ptPos)->x = (*it).x - v1.x;
816 ((CVector *) ptPos)->y = (*it).y - v1.y;
817 ((CVector *) ptPos)->z = (*it).z - v1.z;
818 //nlinfo("%f, %f, %f", ((CVector *) ptPos)->x, ((CVector *) ptPos)->y, ((CVector *) ptPos)->z);
819 ptPos += stride;
821 ((CVector *) ptPos)->x = (*it).x - v2.x;
822 ((CVector *) ptPos)->y = (*it).y - v2.y;
823 ((CVector *) ptPos)->z = (*it).z - v2.z;
824 //nlinfo("%f, %f, %f", ((CVector *) ptPos)->x, ((CVector *) ptPos)->y, ((CVector *) ptPos)->z);
825 ptPos += stride;
827 ++it;
828 currentSize += currentSizeStep;
829 ++currentAngle;
832 else // independant size, and non-constant rotation
835 float *currentSize2;
836 float secondSize;
837 uint32 currentSizeStep2;
838 if (la._SecondSize.getSizeScheme())
840 currentSize2 = (float *) la._SecondSize.getSizeScheme()->make(la._Owner, size- leftToDo, pSecondSizes, sizeof(float), toProcess, true, srcStep);
841 currentSizeStep2 = 1;
843 else
845 secondSize = la._SecondSize.getSize();
846 currentSize2 = &secondSize;
847 currentSizeStep2 = 0;
850 float cosAngle, sinAngle;
851 while (it != endIt)
853 cosAngle = CPSUtil::getCos((sint32) *currentAngle);
854 sinAngle = CPSUtil::getSin((sint32) *currentAngle);
855 v1 = cosAngle * I + sinAngle * K;
856 v2 = - sinAngle * I + cosAngle * K;
858 CHECK_VERTEX_BUFFER(vb, ptPos);
859 ((CVector *) ptPos)->x = (*it).x - *currentSize * v1.x + *currentSize2 * v2.x;
860 ((CVector *) ptPos)->y = (*it).y - *currentSize * v1.y + *currentSize2 * v2.y;
861 ((CVector *) ptPos)->z = (*it).z - *currentSize * v1.z + *currentSize2 * v2.z;
862 ptPos += stride;
864 CHECK_VERTEX_BUFFER(vb, ptPos);
865 ((CVector *) ptPos)->x = (*it).x + *currentSize * v1.x + *currentSize2 * v2.x;
866 ((CVector *) ptPos)->y = (*it).y + *currentSize * v1.y + *currentSize2 * v2.y;
867 ((CVector *) ptPos)->z = (*it).z + *currentSize * v1.z + *currentSize2 * v2.z;
868 ptPos += stride;
870 CHECK_VERTEX_BUFFER(vb, ptPos);
871 ((CVector *) ptPos)->x = (*it).x + *currentSize * v1.x - *currentSize2 * v2.x;
872 ((CVector *) ptPos)->y = (*it).y + *currentSize * v1.y - *currentSize2 * v2.y;
873 ((CVector *) ptPos)->z = (*it).z + *currentSize * v1.z - *currentSize2 * v2.z;
874 ptPos += stride;
876 CHECK_VERTEX_BUFFER(vb, ptPos);
877 ((CVector *) ptPos)->x = (*it).x - *currentSize * v1.x - *currentSize2 * v2.x;
878 ((CVector *) ptPos)->y = (*it).y - *currentSize * v1.y - *currentSize2 * v2.y;
879 ((CVector *) ptPos)->z = (*it).z - *currentSize * v1.z - *currentSize2 * v2.z;
880 ptPos += stride;
881 ++it;
882 ++currentAngle;
883 currentSize += currentSizeStep;
884 currentSize2 += currentSizeStep2;
887 NLMISC::OptFastFloorEnd();
888 //tmp
889 // uint64 startTick = NLMISC::CTime::getPerformanceTime();
890 vba.unlock();
891 driver->activeVertexBuffer(vb);
892 driver->renderRawQuads(la._Mat, 0, toProcess);
893 //PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;*/
894 leftToDo -= toProcess;
896 while (leftToDo);
898 PARTICLES_CHECK_MEM;
902 ///===========================================================================================
903 void CPSFaceLookAt::draw(bool opaque)
905 // if (!FilterPS[2]) return;
906 NL_PS_FUNC(CPSFaceLookAt_draw)
907 PARTICLES_CHECK_MEM;
908 if (!_Owner->getSize()) return;
909 uint32 step;
910 uint numToProcess;
911 computeSrcStep(step, numToProcess);
912 if (!numToProcess) return;
914 if (step == (1 << 16))
916 if (!_AlignOnMotion)
918 CPSFaceLookAtHelper::drawLookAt(_Owner->getPos().begin(),
919 _Owner->getSpeed().begin(),
920 *this,
921 numToProcess,
922 step
925 else
927 CPSFaceLookAtHelper::drawLookAtAlignOnMotion(_Owner->getPos().begin(),
928 _Owner->getSpeed().begin(),
929 *this,
930 numToProcess,
931 step
935 else
937 if (!_AlignOnMotion)
939 CPSFaceLookAtHelper::drawLookAt(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
940 TIteratorVectStep1616(_Owner->getSpeed().begin(), 0, step),
941 *this,
942 numToProcess,
943 step
946 else
948 CPSFaceLookAtHelper::drawLookAtAlignOnMotion(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
949 TIteratorVectStep1616(_Owner->getSpeed().begin(), 0, step),
950 *this,
951 numToProcess,
952 step
956 PARTICLES_CHECK_MEM;
959 ///===========================================================================================
960 CPSFaceLookAt::CPSFaceLookAt(CSmartPtr<ITexture> tex) : CPSQuad(tex),
961 _MotionBlurCoeff(0.f),
962 _Threshold(0.5f),
963 _IndependantSizes(false),
964 _AlignOnMotion(false),
965 _AlignOnZAxis(false)
967 NL_PS_FUNC(CPSFaceLookAt_CPSFaceLookAt)
968 _SecondSize.Owner = this;
969 if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("LookAt");
972 ///===========================================================================================
973 void CPSFaceLookAt::newElement(const CPSEmitterInfo &info)
975 NL_PS_FUNC(CPSFaceLookAt_newElement)
976 CPSQuad::newElement(info);
977 newAngle2DElement(info);
980 ///===========================================================================================
981 void CPSFaceLookAt::deleteElement(uint32 index)
983 NL_PS_FUNC(CPSFaceLookAt_deleteElement)
984 CPSQuad::deleteElement(index);
985 deleteAngle2DElement(index);
988 ///===========================================================================================
989 void CPSFaceLookAt::resize(uint32 capacity)
991 NL_PS_FUNC(CPSFaceLookAt_resize)
992 nlassert(capacity < (1 << 16));
993 CPSQuad::resize(capacity);
994 resizeAngle2D(capacity);
998 ///===========================================================================================
999 void CPSFaceLookAt::serial(NLMISC::IStream &f)
1001 NL_PS_FUNC(CPSFaceLookAt_serial)
1002 // version 4 : added 'align on z-axis' flag
1003 // version 3 : added 'align on motion' flag
1004 sint ver = f.serialVersion(4);
1005 CPSQuad::serial(f);
1006 CPSRotated2DParticle::serialAngle2DScheme(f);
1007 f.serial(_MotionBlurCoeff);
1008 if (_MotionBlurCoeff != 0)
1010 f.serial(_Threshold);
1012 if (ver > 1)
1014 f.serial(_IndependantSizes);
1015 if (_IndependantSizes)
1017 _SecondSize.serialSizeScheme(f);
1020 if (ver >= 3)
1022 f.serial(_AlignOnMotion);
1024 if (ver >= 4)
1026 f.serial(_AlignOnZAxis);
1028 if (f.isReading())
1030 init();
1034 } // NL3D