1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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"
36 /** vector giving the orientation of look at
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
61 /** compute orientation vectors depending on speed
64 static void computeOrientationVectors(T speedIt
, const CVector
&I
, const CVector
&K
, CLookAtAlign
*dest
, uint size
)
66 NL_PS_FUNC(CPSFaceLookAtHelper_computeOrientationVectors
)
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();
80 while(dest
!= endDest
);
83 /** Draw look at and align them on motion
86 static void drawLookAtAlignOnMotion(T it
, T speedIt
, CPSFaceLookAt
&la
, uint size
, uint32 srcStep
)
90 IDriver
*driver
= la
.getDriver();
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
114 uint32 currentSizeStep
= la
._SizeScheme
? 1 : 0;
115 // point the vector part in the current vertex
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
;
129 ptPos
= (uint8
*) vba
.getVertexCoordPointer();
132 currentSize
= (float *) la
._SizeScheme
->make(la
._Owner
, size
- leftToDo
, pSizes
, sizeof(float), toProcess
, true, srcStep
);
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;
149 // TODO : optimize if necessary
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
;
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
;
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
;
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
;
180 currentSize
+= currentSizeStep
;
183 else // independant sizes
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;
195 secondSize
= la
._SecondSize
.getSize();
196 currentSize2
= &secondSize
;
197 currentSizeStep2
= 0;
201 // TODO : optimize if necessary
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
;
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
;
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
;
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
;
231 currentSize
+= currentSizeStep
;
232 currentSize2
+= currentSizeStep2
;
235 // uint64 startTick = NLMISC::CTime::getPerformanceTime();
237 driver
->activeVertexBuffer(vb
);
238 driver
->renderRawQuads(la
._Mat
, 0, toProcess
);
239 // PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;
240 leftToDo
-= toProcess
;
246 float pAngles
[CPSQuad::quadBufSize
]; // the angles to use
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
;
255 ptPos
= (uint8
*) vba
.getVertexCoordPointer();
258 currentSize
= (float *) la
._SizeScheme
->make(la
._Owner
, size
- leftToDo
, pSizes
, sizeof(float), toProcess
, true, srcStep
);
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
;
271 NLMISC::OptFastFloorBegin();
272 if (!la
._IndependantSizes
)
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
;
296 ((CVector
*) ptPos
)->x
= (*it
).x
+ v2
.x
;
297 ((CVector
*) ptPos
)->y
= (*it
).y
+ v2
.y
;
298 ((CVector
*) ptPos
)->z
= (*it
).z
+ v2
.z
;
301 ((CVector
*) ptPos
)->x
= (*it
).x
- v1
.x
;
302 ((CVector
*) ptPos
)->y
= (*it
).y
- v1
.y
;
303 ((CVector
*) ptPos
)->z
= (*it
).z
- v1
.z
;
306 ((CVector
*) ptPos
)->x
= (*it
).x
- v2
.x
;
307 ((CVector
*) ptPos
)->y
= (*it
).y
- v2
.y
;
308 ((CVector
*) ptPos
)->z
= (*it
).z
- v2
.z
;
313 currentSize
+= currentSizeStep
;
317 else // independant size, and non-constant rotation
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;
330 secondSize
= la
._SecondSize
.getSize();
331 currentSize2
= &secondSize
;
332 currentSizeStep2
= 0;
335 float cosAngle
, sinAngle
;
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
;
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
;
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
;
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
;
369 currentSize
+= currentSizeStep
;
370 currentSize2
+= currentSizeStep2
;
373 NLMISC::OptFastFloorEnd();
375 // uint64 startTick = NLMISC::CTime::getPerformanceTime();
377 driver
->activeVertexBuffer(vb
);
378 driver
->renderRawQuads(la
._Mat
, 0, toProcess
);
379 // PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;
380 leftToDo
-= toProcess
;
387 /** render look at, but dont align on motion
390 static void drawLookAt(T it
, T speedIt
, CPSFaceLookAt
&la
, uint size
, uint32 srcStep
)
392 //uint64 startTick = NLMISC::CTime::getPerformanceTime();
395 IDriver
*driver
= la
.getDriver();
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);
411 if (!la
._AlignOnZAxis
)
419 I
= la
.computeIWithZAxisAligned();
420 K
= la
.computeKWithZAxisAligned();
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
430 uint32 currentSizeStep
= la
._SizeScheme
? 1 : 0;
431 // point the vector part in the current vertex
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
;
446 ptPos
= (uint8
*) vba
.getVertexCoordPointer();
449 currentSize
= (float *) la
._SizeScheme
->make(la
._Owner
, size
- leftToDo
, pSizes
, sizeof(float), toProcess
, true, srcStep
);
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
;
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
;
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
;
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
;
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
;
494 currentSize
+= currentSizeStep
;
500 const CVector myV1
= *currentSize
* v1
;
501 const CVector myV2
= *currentSize
* v2
;
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
;
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
;
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
;
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
;
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
;
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;
547 secondSize
= la
._SecondSize
.getSize();
548 currentSize2
= &secondSize
;
549 currentSizeStep2
= 0;
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
;
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
;
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
;
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
;
579 currentSize
+= currentSizeStep
;
580 currentSize2
+= currentSizeStep2
;
584 //uint64 startTick = NLMISC::CTime::getPerformanceTime();
586 driver
->activeVertexBuffer(vb
);
587 driver
->renderRawQuads(la
._Mat
, 0, toProcess
);
588 //PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;
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
599 const float epsilon
= 10E-5f
;
600 const float normEpsilon
= 10E-6f
;
602 CMatrix tMat
= la
.getViewMat() * la
._Owner
->getLocalToWorldMatrix();
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
);
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
);
629 mbv1
= (startV
.x
/ startV
.y
- endV
.x
/ endV
.y
) * I
630 + (startV
.z
/ startV
.y
- endV
.z
/ endV
.y
) * K
;
633 if (n
> la
._Threshold
)
635 mbv1
*= la
._Threshold
/ 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
;
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
;
725 currentSize
+= currentSizeStep
;
727 //uint64 startTick = NLMISC::CTime::getPerformanceTime();
729 driver
->activeVertexBuffer(vb
);
730 driver
->renderRawQuads(la
._Mat
, 0, toProcess
);
731 //PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;
733 leftToDo
-= toProcess
;
739 float pAngles
[CPSQuad::quadBufSize
]; // the angles to use
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
;
748 ptPos
= (uint8
*) vba
.getVertexCoordPointer();
751 currentSize
= (float *) la
._SizeScheme
->make(la
._Owner
, size
- leftToDo
, pSizes
, sizeof(float), toProcess
, true, srcStep
);
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;
763 uint8 *col = (uint8 *) vba.getColorPointer();
764 uint left = toProcess;
767 * (CRGBA *) col = CRGBA::Red;
769 * (CRGBA *) col = CRGBA::Red;
771 * (CRGBA *) col = CRGBA::Red;
773 * (CRGBA *) col = CRGBA::Red;
778 //nlinfo("======= %s", la._Name.c_str());
779 T endIt
= it
+ toProcess
;
781 NLMISC::OptFastFloorBegin();
782 if (!la
._IndependantSizes
)
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);
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);
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);
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);
828 currentSize
+= currentSizeStep
;
832 else // independant size, and non-constant rotation
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;
845 secondSize
= la
._SecondSize
.getSize();
846 currentSize2
= &secondSize
;
847 currentSizeStep2
= 0;
850 float cosAngle
, sinAngle
;
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
;
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
;
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
;
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
;
883 currentSize
+= currentSizeStep
;
884 currentSize2
+= currentSizeStep2
;
887 NLMISC::OptFastFloorEnd();
889 // uint64 startTick = NLMISC::CTime::getPerformanceTime();
891 driver
->activeVertexBuffer(vb
);
892 driver
->renderRawQuads(la
._Mat
, 0, toProcess
);
893 //PSLookAtRenderTime += NLMISC::CTime::getPerformanceTime() - startTick;*/
894 leftToDo
-= toProcess
;
902 ///===========================================================================================
903 void CPSFaceLookAt::draw(bool opaque
)
905 // if (!FilterPS[2]) return;
906 NL_PS_FUNC(CPSFaceLookAt_draw
)
908 if (!_Owner
->getSize()) return;
911 computeSrcStep(step
, numToProcess
);
912 if (!numToProcess
) return;
914 if (step
== (1 << 16))
918 CPSFaceLookAtHelper::drawLookAt(_Owner
->getPos().begin(),
919 _Owner
->getSpeed().begin(),
927 CPSFaceLookAtHelper::drawLookAtAlignOnMotion(_Owner
->getPos().begin(),
928 _Owner
->getSpeed().begin(),
939 CPSFaceLookAtHelper::drawLookAt(TIteratorVectStep1616(_Owner
->getPos().begin(), 0, step
),
940 TIteratorVectStep1616(_Owner
->getSpeed().begin(), 0, step
),
948 CPSFaceLookAtHelper::drawLookAtAlignOnMotion(TIteratorVectStep1616(_Owner
->getPos().begin(), 0, step
),
949 TIteratorVectStep1616(_Owner
->getSpeed().begin(), 0, step
),
959 ///===========================================================================================
960 CPSFaceLookAt::CPSFaceLookAt(CSmartPtr
<ITexture
> tex
) : CPSQuad(tex
),
961 _MotionBlurCoeff(0.f
),
963 _IndependantSizes(false),
964 _AlignOnMotion(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);
1006 CPSRotated2DParticle::serialAngle2DScheme(f
);
1007 f
.serial(_MotionBlurCoeff
);
1008 if (_MotionBlurCoeff
!= 0)
1010 f
.serial(_Threshold
);
1014 f
.serial(_IndependantSizes
);
1015 if (_IndependantSizes
)
1017 _SecondSize
.serialSizeScheme(f
);
1022 f
.serial(_AlignOnMotion
);
1026 f
.serial(_AlignOnZAxis
);