part_buf.cpp 113 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***************************************************************************
  21. * *
  22. * Project Name : G *
  23. * *
  24. * $Archive:: /VSS_Sync/ww3d2/part_buf.cpp $*
  25. * *
  26. * $Author:: Vss_sync $*
  27. * *
  28. * $Modtime:: 10/26/01 2:56p $*
  29. * *
  30. * $Revision:: 21 $*
  31. * *
  32. *-------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "part_buf.h"
  36. #include "part_emt.h"
  37. #include "ww3d.h"
  38. #include "rinfo.h"
  39. #include "scene.h"
  40. #include "camera.h"
  41. #include "predlod.h"
  42. #include "pot.h"
  43. #include "bound.h"
  44. #include "simplevec.h"
  45. #include "sphere.h"
  46. #include "wwprofile.h"
  47. #include <limits.h>
  48. #include "vp.h"
  49. #include "texture.h"
  50. #include "dx8wrapper.h"
  51. #include "vector3.h"
  52. // A random permutation of the numbers 0 to 15 - used for LOD particle decimation.
  53. // It was generated by the amazingly high-tech method of pulling numbers out of a hat.
  54. const unsigned int ParticleBufferClass::PermutationArray[16] = {
  55. 11, 3, 7, 14, 0, 13, 1, 2, 5, 12, 15, 6, 9, 8, 4, 10
  56. };
  57. // Maximum size of randomizer tables
  58. const static unsigned int MAX_RANDOM_ENTRIES = 32; // MUST be power of two!
  59. // Total Active Particle Buffer Count
  60. unsigned int ParticleBufferClass::TotalActiveCount = 0;
  61. // Static array of screen-size clamps for the 17 possible LOD levels a particle buffer can have.
  62. // We can change these from being global to being per-buffer later if we wish. Default is
  63. // NO_MAX_SCREEN_SIZE.
  64. float ParticleBufferClass::LODMaxScreenSizes[17] = {
  65. NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE,
  66. NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE,
  67. NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE,
  68. NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE, NO_MAX_SCREEN_SIZE,
  69. NO_MAX_SCREEN_SIZE
  70. };
  71. static Random4Class rand_gen;
  72. const float oo_intmax = 1.0f / (float)INT_MAX;
  73. // Default Line Emitter Properties
  74. static const W3dEmitterLinePropertiesStruct _DefaultLineEmitterProps=
  75. { 0,0,0.0f,1.5f,1.0f,0.0f,0.0f,0,0,0,0,0,0,0,0,0 };
  76. ParticleBufferClass::ParticleBufferClass
  77. (
  78. ParticleEmitterClass *emitter,
  79. unsigned int buffer_size,
  80. ParticlePropertyStruct<Vector3> &color,
  81. ParticlePropertyStruct<float> &opacity,
  82. ParticlePropertyStruct<float> &size,
  83. ParticlePropertyStruct<float> &rotation,
  84. float orient_rnd,
  85. ParticlePropertyStruct<float> &frame,
  86. ParticlePropertyStruct<float> &blurtime,
  87. Vector3 accel,
  88. float max_age,
  89. TextureClass *tex,
  90. ShaderClass shader,
  91. bool pingpong,
  92. int render_mode,
  93. int frame_mode,
  94. const W3dEmitterLinePropertiesStruct * line_props
  95. ) :
  96. NewParticleQueue(NULL),
  97. NewParticleQueueStart(0U),
  98. NewParticleQueueEnd(0U),
  99. NewParticleQueueCount(0U),
  100. RenderMode(render_mode),
  101. FrameMode(frame_mode),
  102. MaxAge(1000.0f * max_age),
  103. LastUpdateTime(WW3D::Get_Sync_Time()),
  104. IsEmitterDead(false),
  105. MaxSize(0.0f),
  106. MaxNum(buffer_size),
  107. Start(0U),
  108. End(0U),
  109. NewEnd(0U),
  110. NonNewNum(0),
  111. NewNum(0),
  112. BoundingBox(Vector3(0,0,0),Vector3(0,0,0)),
  113. BoundingBoxDirty(true),
  114. NumColorKeyFrames(0),
  115. ColorKeyFrameTimes(NULL),
  116. ColorKeyFrameValues(NULL),
  117. ColorKeyFrameDeltas(NULL),
  118. NumAlphaKeyFrames(0),
  119. AlphaKeyFrameTimes(NULL),
  120. AlphaKeyFrameValues(NULL),
  121. AlphaKeyFrameDeltas(NULL),
  122. NumSizeKeyFrames(0),
  123. SizeKeyFrameTimes(NULL),
  124. SizeKeyFrameValues(NULL),
  125. SizeKeyFrameDeltas(NULL),
  126. NumRotationKeyFrames(0),
  127. RotationKeyFrameTimes(NULL),
  128. RotationKeyFrameValues(NULL),
  129. HalfRotationKeyFrameDeltas(NULL),
  130. OrientationKeyFrameValues(NULL),
  131. NumFrameKeyFrames(0),
  132. FrameKeyFrameTimes(NULL),
  133. FrameKeyFrameValues(NULL),
  134. FrameKeyFrameDeltas(NULL),
  135. NumBlurTimeKeyFrames(0),
  136. BlurTimeKeyFrameTimes(NULL),
  137. BlurTimeKeyFrameValues(NULL),
  138. BlurTimeKeyFrameDeltas(NULL),
  139. NumRandomColorEntriesMinus1(0),
  140. RandomColorEntries(NULL),
  141. NumRandomAlphaEntriesMinus1(0),
  142. RandomAlphaEntries(NULL),
  143. NumRandomSizeEntriesMinus1(0),
  144. RandomSizeEntries(NULL),
  145. ColorRandom(0, 0, 0),
  146. OpacityRandom(0),
  147. SizeRandom(0),
  148. RotationRandom(0),
  149. FrameRandom(0),
  150. InitialOrientationRandom(0),
  151. NumRandomRotationEntriesMinus1(0),
  152. RandomRotationEntries(NULL),
  153. NumRandomOrientationEntriesMinus1(0),
  154. RandomOrientationEntries(NULL),
  155. NumRandomFrameEntriesMinus1(0),
  156. RandomFrameEntries(NULL),
  157. NumRandomBlurTimeEntriesMinus1(0),
  158. RandomBlurTimeEntries(NULL),
  159. PointGroup(NULL),
  160. LineRenderer(NULL),
  161. LineGroup(NULL),
  162. Diffuse(NULL),
  163. TailDiffuse(NULL),
  164. Color(NULL),
  165. Alpha(NULL),
  166. Size(NULL),
  167. Orientation(NULL),
  168. Frame(NULL),
  169. UCoord(NULL),
  170. TailPosition(NULL),
  171. APT(NULL),
  172. PingPongPosition(pingpong),
  173. Velocity(NULL),
  174. TimeStamp(NULL),
  175. Emitter(emitter),
  176. DecimationThreshold(0U),
  177. ProjectedArea(0.0f),
  178. DefaultTailDiffuse(0,0,0,0)
  179. {
  180. LodCount = 17;
  181. LodBias = 1.0f;
  182. Position[0] = NULL;
  183. Position[1] = NULL;
  184. // Create color array, keyframes and randomizer table (if needed)
  185. Reset_Colors(color);
  186. // Create alpha array, keyframes and randomizer table (if needed)
  187. Reset_Opacity(opacity);
  188. // Create size array, keyframes and randomizer table (if needed)
  189. Reset_Size(size);
  190. // Create the rotation array, keyframes, and randomizer table (if needed)
  191. Reset_Rotations(rotation, orient_rnd);
  192. // Create the frame array, keyframes, and randomizer table (if needed)
  193. Reset_Frames(frame);
  194. // Create the blur time array, keyframes, and randomizer table if needed
  195. Reset_Blur_Times(blurtime);
  196. // We do not add a ref for the emitter (see DTor for detailed explanation)
  197. // if (Emitter) Emitter->Add_Ref();
  198. // Set up new particle queue:
  199. NewParticleQueue = new NewParticleStruct[MaxNum];
  200. // These inputs don't need to be range-checked (emitter did that).
  201. Accel = accel;
  202. HasAccel = (accel.X != 0.0f) || (accel.Y != 0.0f) || (accel.Z != 0.0f);
  203. shader.Enable_Fog ("ParticleBufferClass");
  204. switch (RenderMode)
  205. {
  206. case W3D_EMITTER_RENDER_MODE_TRI_PARTICLES:
  207. {
  208. // Set up worldspace point group
  209. PointGroup = new PointGroupClass();
  210. PointGroup->Set_Flag(PointGroupClass::TRANSFORM, true);
  211. PointGroup->Set_Texture(tex);
  212. PointGroup->Set_Shader(shader);
  213. PointGroup->Set_Frame_Row_Column_Count_Log2(frame_mode);
  214. PointGroup->Set_Point_Mode(PointGroupClass::TRIS);
  215. }
  216. break;
  217. case W3D_EMITTER_RENDER_MODE_QUAD_PARTICLES:
  218. {
  219. // Set up worldspace point group
  220. PointGroup = new PointGroupClass();
  221. PointGroup->Set_Flag(PointGroupClass::TRANSFORM, true);
  222. PointGroup->Set_Texture(tex);
  223. PointGroup->Set_Shader(shader);
  224. PointGroup->Set_Frame_Row_Column_Count_Log2(frame_mode);
  225. PointGroup->Set_Point_Mode(PointGroupClass::QUADS);
  226. }
  227. break;
  228. case W3D_EMITTER_RENDER_MODE_LINE:
  229. {
  230. LineRenderer = new SegLineRendererClass;
  231. LineRenderer->Init(*line_props);
  232. LineRenderer->Set_Texture(tex);
  233. LineRenderer->Set_Shader(shader);
  234. LineRenderer->Set_Width(Get_Particle_Size());
  235. if (line_props != NULL) {
  236. LineRenderer->Init(*line_props);
  237. } else {
  238. // This code should not be run, but if it does,
  239. // set line emitters to some reasonable value so
  240. // it doesn't crash
  241. WWASSERT(0);
  242. LineRenderer->Init(_DefaultLineEmitterProps);
  243. }
  244. }
  245. break;
  246. case W3D_EMITTER_RENDER_MODE_LINEGRP_TETRA:
  247. {
  248. LineGroup=new LineGroupClass();
  249. LineGroup->Set_Flag(LineGroupClass::TRANSFORM, true);
  250. LineGroup->Set_Texture(tex);
  251. LineGroup->Set_Shader(shader);
  252. LineGroup->Set_Line_Mode(LineGroupClass::TETRAHEDRON);
  253. TailPosition = NEW_REF( ShareBufferClass<Vector3> , (MaxNum) );
  254. // TODO: Change TailPosition to Kinematic state and add
  255. // tail positions to bounding box
  256. Set_Force_Visible(1);
  257. }
  258. break;
  259. case W3D_EMITTER_RENDER_MODE_LINEGRP_PRISM:
  260. {
  261. LineGroup=new LineGroupClass();
  262. LineGroup->Set_Flag(LineGroupClass::TRANSFORM, true);
  263. LineGroup->Set_Texture(tex);
  264. LineGroup->Set_Shader(shader);
  265. LineGroup->Set_Line_Mode(LineGroupClass::PRISM);
  266. TailPosition = NEW_REF( ShareBufferClass<Vector3> , (MaxNum) );
  267. // TODO: Change TailPosition to Kinematic state and add
  268. // tail positions to bounding box
  269. Set_Force_Visible(1);
  270. }
  271. break;
  272. default:
  273. WWASSERT(0);
  274. break;
  275. }
  276. // Set up circular buffer. Contents are not initialized because the
  277. // start/end indices currently indicate the buffer is empty.
  278. Position[0] = NEW_REF( ShareBufferClass<Vector3> , (MaxNum) );
  279. if (PingPongPosition) {
  280. Position[1] = NEW_REF( ShareBufferClass<Vector3> , (MaxNum) );
  281. }
  282. APT = NEW_REF( ShareBufferClass<unsigned int> , (MaxNum) );
  283. Velocity = new Vector3[MaxNum];
  284. TimeStamp = new unsigned int[MaxNum];
  285. // So that the object is ready for use after construction, we will
  286. // complete its initialization by initializing its cost and value arrays
  287. // according to a screen area of 1.
  288. int minlod = Calculate_Cost_Value_Arrays(1.0f, Value, Cost);
  289. // Ensure lod is no less than minimum allowed
  290. if (Get_LOD_Level() < minlod) Set_LOD_Level(minlod);
  291. // Update Global Count
  292. TotalActiveCount++;
  293. }
  294. ParticleBufferClass::ParticleBufferClass(const ParticleBufferClass & src) :
  295. RenderObjClass(src),
  296. NewParticleQueue(NULL),
  297. NewParticleQueueStart(0U),
  298. NewParticleQueueEnd(0U),
  299. NewParticleQueueCount(0U),
  300. RenderMode(src.RenderMode),
  301. FrameMode(src.FrameMode),
  302. MaxAge(src.MaxAge),
  303. LastUpdateTime(WW3D::Get_Sync_Time()),
  304. IsEmitterDead(false),
  305. MaxSize(src.MaxSize),
  306. MaxNum(src.MaxNum),
  307. Start(0U),
  308. End(0U),
  309. NewEnd(0U),
  310. NonNewNum(0),
  311. NewNum(0),
  312. BoundingBox(Vector3(0,0,0),Vector3(0,0,0)),
  313. BoundingBoxDirty(true),
  314. NumColorKeyFrames(src.NumColorKeyFrames),
  315. ColorKeyFrameTimes(NULL),
  316. ColorKeyFrameValues(NULL),
  317. ColorKeyFrameDeltas(NULL),
  318. NumAlphaKeyFrames(src.NumAlphaKeyFrames),
  319. AlphaKeyFrameTimes(NULL),
  320. AlphaKeyFrameValues(NULL),
  321. AlphaKeyFrameDeltas(NULL),
  322. NumSizeKeyFrames(src.NumSizeKeyFrames),
  323. SizeKeyFrameTimes(NULL),
  324. SizeKeyFrameValues(NULL),
  325. SizeKeyFrameDeltas(NULL),
  326. NumRotationKeyFrames(src.NumRotationKeyFrames),
  327. RotationKeyFrameTimes(NULL),
  328. RotationKeyFrameValues(NULL),
  329. HalfRotationKeyFrameDeltas(NULL),
  330. OrientationKeyFrameValues(NULL),
  331. NumFrameKeyFrames(src.NumFrameKeyFrames),
  332. FrameKeyFrameTimes(NULL),
  333. FrameKeyFrameValues(NULL),
  334. FrameKeyFrameDeltas(NULL),
  335. NumBlurTimeKeyFrames(src.NumBlurTimeKeyFrames),
  336. BlurTimeKeyFrameTimes(NULL),
  337. BlurTimeKeyFrameValues(NULL),
  338. BlurTimeKeyFrameDeltas(NULL),
  339. RandomColorEntries(NULL),
  340. RandomAlphaEntries(NULL),
  341. RandomSizeEntries(NULL),
  342. ColorRandom(src.ColorRandom),
  343. OpacityRandom(src.OpacityRandom),
  344. SizeRandom(src.SizeRandom),
  345. RotationRandom(src.RotationRandom),
  346. FrameRandom(src.FrameRandom),
  347. InitialOrientationRandom(src.InitialOrientationRandom),
  348. NumRandomRotationEntriesMinus1(0),
  349. RandomRotationEntries(NULL),
  350. NumRandomOrientationEntriesMinus1(0),
  351. RandomOrientationEntries(NULL),
  352. NumRandomFrameEntriesMinus1(0),
  353. RandomFrameEntries(NULL),
  354. NumRandomBlurTimeEntriesMinus1(0),
  355. RandomBlurTimeEntries(NULL),
  356. PointGroup(NULL),
  357. LineRenderer(NULL),
  358. LineGroup(NULL),
  359. Diffuse(NULL),
  360. TailDiffuse(NULL),
  361. Color(NULL),
  362. Alpha(NULL),
  363. Size(NULL),
  364. Orientation(NULL),
  365. Frame(NULL),
  366. UCoord(NULL),
  367. TailPosition(NULL),
  368. APT(NULL),
  369. PingPongPosition(src.PingPongPosition),
  370. Velocity(NULL),
  371. TimeStamp(NULL),
  372. Emitter(src.Emitter),
  373. DecimationThreshold(src.DecimationThreshold),
  374. ProjectedArea(0.0f),
  375. DefaultTailDiffuse(src.DefaultTailDiffuse)
  376. {
  377. Position[0] = NULL;
  378. Position[1] = NULL;
  379. unsigned int i;
  380. LodCount = MIN(MaxNum, 17);
  381. LodBias = src.LodBias;
  382. /*
  383. ** Create visual state arrays, copy keyframes and randomizer tables.
  384. */
  385. NumRandomColorEntriesMinus1 = src.NumRandomColorEntriesMinus1;
  386. if (src.Color) {
  387. // Create color array
  388. Color = NEW_REF( ShareBufferClass<Vector3> , (MaxNum) );
  389. // Copy color keyframes
  390. ColorKeyFrameTimes = new unsigned int [NumColorKeyFrames];
  391. ColorKeyFrameValues = new Vector3 [NumColorKeyFrames];
  392. ColorKeyFrameDeltas = new Vector3 [NumColorKeyFrames];
  393. for (i = 0; i < NumColorKeyFrames; i++) {
  394. ColorKeyFrameTimes[i] = src.ColorKeyFrameTimes[i];
  395. ColorKeyFrameValues[i] = src.ColorKeyFrameValues[i];
  396. ColorKeyFrameDeltas[i] = src.ColorKeyFrameDeltas[i];
  397. }
  398. // Copy color randomizer table
  399. if (src.RandomColorEntries) {
  400. RandomColorEntries = new Vector3 [NumRandomColorEntriesMinus1 + 1];
  401. for (unsigned int j = 0; j <= NumRandomColorEntriesMinus1; j++) {
  402. RandomColorEntries[j] = src.RandomColorEntries[j];
  403. }
  404. }
  405. } else {
  406. ColorKeyFrameValues = new Vector3 [1];
  407. ColorKeyFrameValues[0] = src.ColorKeyFrameValues[0];
  408. }
  409. NumRandomAlphaEntriesMinus1 = src.NumRandomAlphaEntriesMinus1;
  410. if (src.Alpha) {
  411. // Create alpha array
  412. Alpha = NEW_REF( ShareBufferClass<float> , (MaxNum) );
  413. // Copy alpha keyframes
  414. AlphaKeyFrameTimes = new unsigned int [NumAlphaKeyFrames];
  415. AlphaKeyFrameValues = new float [NumAlphaKeyFrames];
  416. AlphaKeyFrameDeltas = new float [NumAlphaKeyFrames];
  417. for (i = 0; i < NumAlphaKeyFrames; i++) {
  418. AlphaKeyFrameTimes[i] = src.AlphaKeyFrameTimes[i];
  419. AlphaKeyFrameValues[i] = src.AlphaKeyFrameValues[i];
  420. AlphaKeyFrameDeltas[i] = src.AlphaKeyFrameDeltas[i];
  421. }
  422. // Copy alpha randomizer table
  423. if (src.RandomAlphaEntries) {
  424. RandomAlphaEntries = new float [NumRandomAlphaEntriesMinus1 + 1];
  425. for (unsigned int j = 0; j <= NumRandomAlphaEntriesMinus1; j++) {
  426. RandomAlphaEntries[j] = src.RandomAlphaEntries[j];
  427. }
  428. }
  429. } else {
  430. AlphaKeyFrameValues = new float [1];
  431. AlphaKeyFrameValues[0] = src.AlphaKeyFrameValues[0];
  432. }
  433. NumRandomSizeEntriesMinus1 = src.NumRandomSizeEntriesMinus1;
  434. if (src.Size) {
  435. // Create size array
  436. Size = NEW_REF( ShareBufferClass<float> , (MaxNum) );
  437. // Copy size keyframes
  438. SizeKeyFrameTimes = new unsigned int [NumSizeKeyFrames];
  439. SizeKeyFrameValues = new float [NumSizeKeyFrames];
  440. SizeKeyFrameDeltas = new float [NumSizeKeyFrames];
  441. for (i = 0; i < NumSizeKeyFrames; i++) {
  442. SizeKeyFrameTimes[i] = src.SizeKeyFrameTimes[i];
  443. SizeKeyFrameValues[i] = src.SizeKeyFrameValues[i];
  444. SizeKeyFrameDeltas[i] = src.SizeKeyFrameDeltas[i];
  445. }
  446. // Copy size randomizer table
  447. if (src.RandomSizeEntries) {
  448. RandomSizeEntries = new float [NumRandomSizeEntriesMinus1 + 1];
  449. for (unsigned int j = 0; j <= NumRandomSizeEntriesMinus1; j++) {
  450. RandomSizeEntries[j] = src.RandomSizeEntries[j];
  451. }
  452. }
  453. } else {
  454. SizeKeyFrameValues = new float [1];
  455. SizeKeyFrameValues[0] = src.SizeKeyFrameValues[0];
  456. }
  457. // Set up the rotation / orientation keyframes
  458. NumRandomRotationEntriesMinus1 = src.NumRandomRotationEntriesMinus1;
  459. NumRandomOrientationEntriesMinus1 = src.NumRandomOrientationEntriesMinus1;
  460. if (src.Orientation) {
  461. // Create orientation array
  462. Orientation = NEW_REF( ShareBufferClass<uint8> , (MaxNum) );
  463. // Copy rotation / orientation keyframes
  464. RotationKeyFrameTimes = new unsigned int [NumRotationKeyFrames];
  465. RotationKeyFrameValues = new float [NumRotationKeyFrames];
  466. HalfRotationKeyFrameDeltas = new float [NumRotationKeyFrames];
  467. OrientationKeyFrameValues = new float [NumRotationKeyFrames];
  468. for (i = 0; i < NumRotationKeyFrames; i++) {
  469. RotationKeyFrameTimes[i] = src.RotationKeyFrameTimes[i];
  470. RotationKeyFrameValues[i] = src.RotationKeyFrameValues[i];
  471. HalfRotationKeyFrameDeltas[i] = src.HalfRotationKeyFrameDeltas[i];
  472. OrientationKeyFrameValues[i] = src.OrientationKeyFrameValues[i];
  473. }
  474. // Copy rotation randomizer table
  475. if (src.RandomRotationEntries) {
  476. RandomRotationEntries = new float [NumRandomRotationEntriesMinus1 + 1];
  477. for (unsigned int j = 0; j <= NumRandomRotationEntriesMinus1; j++) {
  478. RandomRotationEntries[j] = src.RandomRotationEntries[j];
  479. }
  480. }
  481. // Copy starting orientation randomizer table
  482. if (src.RandomOrientationEntries) {
  483. RandomOrientationEntries = new float [NumRandomOrientationEntriesMinus1 + 1];
  484. for (unsigned int j = 0; j <= NumRandomOrientationEntriesMinus1; j++) {
  485. RandomOrientationEntries[j] = src.RandomOrientationEntries[j];
  486. }
  487. }
  488. } else {
  489. // Unlike other properties, if there is no Orientation array then all the arrays are NULL
  490. // (including the Values array) - there is an implicit starting value of 0.
  491. }
  492. // Set up the frame keyframes
  493. // Frame and UCoord both use Frame Key Frames for the source data
  494. NumRandomFrameEntriesMinus1 = src.NumRandomFrameEntriesMinus1;
  495. if (src.Frame || src.UCoord) {
  496. // Create frame array
  497. if (src.Frame) {
  498. Frame = NEW_REF( ShareBufferClass<uint8> , (MaxNum) );
  499. } else {
  500. UCoord = NEW_REF( ShareBufferClass<float>, (MaxNum) );
  501. }
  502. // Copy frame keyframes
  503. FrameKeyFrameTimes = new unsigned int [NumFrameKeyFrames];
  504. FrameKeyFrameValues = new float [NumFrameKeyFrames];
  505. FrameKeyFrameDeltas = new float [NumFrameKeyFrames];
  506. for (i = 0; i < NumFrameKeyFrames; i++) {
  507. FrameKeyFrameTimes[i] = src.FrameKeyFrameTimes[i];
  508. FrameKeyFrameValues[i] = src.FrameKeyFrameValues[i];
  509. FrameKeyFrameDeltas[i] = src.FrameKeyFrameDeltas[i];
  510. }
  511. // Copy frame randomizer table
  512. if (src.RandomFrameEntries) {
  513. RandomFrameEntries = new float [NumRandomFrameEntriesMinus1 + 1];
  514. for (unsigned int j = 0; j <= NumRandomFrameEntriesMinus1; j++) {
  515. RandomFrameEntries[j] = src.RandomFrameEntries[j];
  516. }
  517. }
  518. } else {
  519. FrameKeyFrameValues = new float [1];
  520. FrameKeyFrameValues[0] = src.FrameKeyFrameValues[0];
  521. }
  522. // Set up the blur times keyframes
  523. NumRandomBlurTimeEntriesMinus1 = src.NumRandomBlurTimeEntriesMinus1;
  524. if (NumBlurTimeKeyFrames > 0) {
  525. // Copy blur time keyframes
  526. BlurTimeKeyFrameTimes = new unsigned int [NumBlurTimeKeyFrames];
  527. BlurTimeKeyFrameValues = new float [NumBlurTimeKeyFrames];
  528. BlurTimeKeyFrameDeltas = new float [NumBlurTimeKeyFrames];
  529. for (i = 0; i < NumBlurTimeKeyFrames; i++) {
  530. BlurTimeKeyFrameTimes[i] = src.BlurTimeKeyFrameTimes[i];
  531. BlurTimeKeyFrameValues[i] = src.BlurTimeKeyFrameValues[i];
  532. BlurTimeKeyFrameDeltas[i] = src.BlurTimeKeyFrameDeltas[i];
  533. }
  534. // Copy blur time randomizer table
  535. if (src.RandomBlurTimeEntries) {
  536. RandomBlurTimeEntries = new float [NumRandomBlurTimeEntriesMinus1 + 1];
  537. for (unsigned int j = 0; j <= NumRandomBlurTimeEntriesMinus1; j++) {
  538. RandomBlurTimeEntries[j] = src.RandomBlurTimeEntries[j];
  539. }
  540. }
  541. } else {
  542. BlurTimeKeyFrameValues = new float [1];
  543. BlurTimeKeyFrameValues[0] = src.BlurTimeKeyFrameValues[0];
  544. }
  545. // We do not add a ref for the emitter (see DTor for detailed explanation)
  546. // if (Emitter) Emitter->Add_Ref();
  547. // Set up new particle queue:
  548. NewParticleQueue = new NewParticleStruct[MaxNum];
  549. // Inputs don't need to be range-checked (emitter did that).
  550. Accel = src.Accel;
  551. HasAccel = src.HasAccel;
  552. switch (RenderMode)
  553. {
  554. case W3D_EMITTER_RENDER_MODE_TRI_PARTICLES:
  555. {
  556. // Set up worldspace point group
  557. WWASSERT(src.PointGroup);
  558. PointGroup = new PointGroupClass();
  559. PointGroup->Set_Flag(PointGroupClass::TRANSFORM, true);
  560. PointGroup->Set_Texture(src.PointGroup->Peek_Texture());
  561. PointGroup->Set_Shader(src.PointGroup->Get_Shader());
  562. PointGroup->Set_Point_Mode(PointGroupClass::TRIS);
  563. PointGroup->Set_Frame_Row_Column_Count_Log2(src.PointGroup->Get_Frame_Row_Column_Count_Log2());
  564. }
  565. break;
  566. case W3D_EMITTER_RENDER_MODE_QUAD_PARTICLES:
  567. {
  568. // Set up worldspace point group
  569. WWASSERT(src.PointGroup);
  570. PointGroup = new PointGroupClass();
  571. PointGroup->Set_Flag(PointGroupClass::TRANSFORM, true);
  572. PointGroup->Set_Texture(src.PointGroup->Peek_Texture());
  573. PointGroup->Set_Shader(src.PointGroup->Get_Shader());
  574. PointGroup->Set_Point_Mode(PointGroupClass::QUADS);
  575. PointGroup->Set_Frame_Row_Column_Count_Log2(src.PointGroup->Get_Frame_Row_Column_Count_Log2());
  576. }
  577. break;
  578. case W3D_EMITTER_RENDER_MODE_LINE:
  579. {
  580. WWASSERT(src.LineRenderer);
  581. LineRenderer = new SegLineRendererClass(*src.LineRenderer);
  582. }
  583. break;
  584. case W3D_EMITTER_RENDER_MODE_LINEGRP_TETRA:
  585. {
  586. WWASSERT(src.LineGroup);
  587. LineGroup=new LineGroupClass();
  588. LineGroup->Set_Flag(LineGroupClass::TRANSFORM, true);
  589. LineGroup->Set_Texture(src.LineGroup->Peek_Texture());
  590. LineGroup->Set_Shader(src.LineGroup->Get_Shader());
  591. LineGroup->Set_Line_Mode(LineGroupClass::TETRAHEDRON);
  592. TailPosition = NEW_REF( ShareBufferClass<Vector3> , (MaxNum) );
  593. // TODO: Change TailPosition to Kinematic state and add
  594. // tail positions to bounding box
  595. Set_Force_Visible(1);
  596. }
  597. break;
  598. case W3D_EMITTER_RENDER_MODE_LINEGRP_PRISM:
  599. {
  600. WWASSERT(src.LineGroup);
  601. LineGroup=new LineGroupClass();
  602. LineGroup->Set_Flag(LineGroupClass::TRANSFORM, true);
  603. LineGroup->Set_Texture(src.LineGroup->Peek_Texture());
  604. LineGroup->Set_Shader(src.LineGroup->Get_Shader());
  605. LineGroup->Set_Line_Mode(LineGroupClass::PRISM);
  606. TailPosition = NEW_REF( ShareBufferClass<Vector3> , (MaxNum) );
  607. // TODO: Change TailPosition to Kinematic state and add
  608. // tail positions to bounding box
  609. Set_Force_Visible(1);
  610. }
  611. break;
  612. default:
  613. WWASSERT(0);
  614. break;
  615. }
  616. // Set up circular buffer. Contents are not initialized because the
  617. // start/end indices currently indicate the buffer is empty.
  618. Position[0] = NEW_REF( ShareBufferClass<Vector3> , (MaxNum) );
  619. if (PingPongPosition) {
  620. Position[1] = NEW_REF( ShareBufferClass<Vector3> , (MaxNum) );
  621. }
  622. APT = NEW_REF( ShareBufferClass<unsigned int> , (MaxNum) );
  623. Velocity = new Vector3[MaxNum];
  624. TimeStamp = new unsigned int[MaxNum];
  625. // So that the object is ready for use after construction, we will
  626. // complete its initialization by initializing its cost and value arrays
  627. // according to a screen area of 1.
  628. int minlod = Calculate_Cost_Value_Arrays(1.0f, Value, Cost);
  629. // Ensure lod is no less than minimum allowed
  630. if (Get_LOD_Level() < minlod) Set_LOD_Level(minlod);
  631. // Update Global Count
  632. TotalActiveCount++;
  633. }
  634. ParticleBufferClass & ParticleBufferClass::operator = (const ParticleBufferClass & that)
  635. {
  636. RenderObjClass::operator = (that);
  637. if (this != &that) {
  638. assert(0); // TODO: if you hit this assert, please implement me !!!;-)
  639. }
  640. return * this;
  641. }
  642. ParticleBufferClass::~ParticleBufferClass(void)
  643. {
  644. if (NewParticleQueue) delete [] NewParticleQueue;
  645. if (ColorKeyFrameTimes) delete [] ColorKeyFrameTimes;
  646. if (ColorKeyFrameValues) delete [] ColorKeyFrameValues;
  647. if (ColorKeyFrameDeltas) delete [] ColorKeyFrameDeltas;
  648. if (AlphaKeyFrameTimes) delete [] AlphaKeyFrameTimes;
  649. if (AlphaKeyFrameValues) delete [] AlphaKeyFrameValues;
  650. if (AlphaKeyFrameDeltas) delete [] AlphaKeyFrameDeltas;
  651. if (SizeKeyFrameTimes) delete [] SizeKeyFrameTimes;
  652. if (SizeKeyFrameValues) delete [] SizeKeyFrameValues;
  653. if (SizeKeyFrameDeltas) delete [] SizeKeyFrameDeltas;
  654. if (RotationKeyFrameTimes) delete [] RotationKeyFrameTimes;
  655. if (RotationKeyFrameValues) delete [] RotationKeyFrameValues;
  656. if (HalfRotationKeyFrameDeltas) delete [] HalfRotationKeyFrameDeltas;
  657. if (OrientationKeyFrameValues) delete [] OrientationKeyFrameValues;
  658. if (FrameKeyFrameTimes) delete [] FrameKeyFrameTimes;
  659. if (FrameKeyFrameValues) delete [] FrameKeyFrameValues;
  660. if (FrameKeyFrameDeltas) delete [] FrameKeyFrameDeltas;
  661. if (BlurTimeKeyFrameTimes) delete [] BlurTimeKeyFrameTimes;
  662. if (BlurTimeKeyFrameValues) delete [] BlurTimeKeyFrameValues;
  663. if (BlurTimeKeyFrameDeltas) delete [] BlurTimeKeyFrameDeltas;
  664. if (RandomColorEntries) delete [] RandomColorEntries;
  665. if (RandomAlphaEntries) delete [] RandomAlphaEntries;
  666. if (RandomSizeEntries) delete [] RandomSizeEntries;
  667. if (RandomRotationEntries) delete [] RandomRotationEntries;
  668. if (RandomOrientationEntries) delete [] RandomOrientationEntries;
  669. if (RandomFrameEntries) delete [] RandomFrameEntries;
  670. if (RandomBlurTimeEntries) delete [] RandomBlurTimeEntries;
  671. if (PointGroup) delete PointGroup;
  672. if (LineRenderer) delete LineRenderer;
  673. if (LineGroup) delete LineGroup;
  674. REF_PTR_RELEASE(Position[0]);
  675. REF_PTR_RELEASE(Position[1]);
  676. REF_PTR_RELEASE(Diffuse);
  677. REF_PTR_RELEASE(TailDiffuse);
  678. REF_PTR_RELEASE(Color);
  679. REF_PTR_RELEASE(Alpha);
  680. REF_PTR_RELEASE(Size);
  681. REF_PTR_RELEASE(Orientation);
  682. REF_PTR_RELEASE(Frame);
  683. REF_PTR_RELEASE(UCoord);
  684. REF_PTR_RELEASE(TailPosition);
  685. REF_PTR_RELEASE(APT);
  686. if (Velocity) delete [] Velocity;
  687. if (TimeStamp) delete [] TimeStamp;
  688. if (Emitter) {
  689. // We should not have an emitter at this point, since the emitter
  690. // should still have a live ref to us if it still exists which would
  691. // prevent us from getting killed.
  692. assert(0);
  693. // We do not release-ref the emitter pointer because we did not add a
  694. // ref for it to begin with; the ref is not needed (if the emitter gets
  695. // deleted it will tell us to clear our emitter pointer) and actually
  696. // harmful (if emitter and buffer each have refcounted pointers to the
  697. // other neither would ever get deleted).
  698. // Emitter->Release_Ref();
  699. Emitter = NULL;
  700. }
  701. // Update Global Count
  702. TotalActiveCount--;
  703. }
  704. RenderObjClass * ParticleBufferClass::Clone(void) const
  705. {
  706. return new ParticleBufferClass(*this);
  707. }
  708. int ParticleBufferClass::Get_Num_Polys(void) const
  709. {
  710. // Currently in particle buffers, the cost happens to be equal to thwe polygon count.
  711. return (int)Get_Cost();
  712. }
  713. int ParticleBufferClass::Get_Particle_Count(void) const
  714. {
  715. return NonNewNum + NewNum;
  716. }
  717. void ParticleBufferClass::Render(RenderInfoClass & rinfo)
  718. {
  719. WWPROFILE("ParticleBuffer::Render");
  720. unsigned int sort_level = SORT_LEVEL_NONE;
  721. if (!WW3D::Is_Sorting_Enabled())
  722. sort_level=Get_Shader().Guess_Sort_Level();
  723. if (WW3D::Are_Static_Sort_Lists_Enabled() && sort_level!=SORT_LEVEL_NONE) {
  724. WW3D::Add_To_Static_Sort_List(this, sort_level);
  725. } else {
  726. // Ensure particles' kinematic state is updated
  727. Update_Kinematic_Particle_State();
  728. // Since we are rendering the particles, visual state needs to be updated (but not if the
  729. // entire particle buffer is decimated away)
  730. if (DecimationThreshold < LodCount - 1) {
  731. Update_Visual_Particle_State();
  732. }
  733. switch( RenderMode )
  734. {
  735. case W3D_EMITTER_RENDER_MODE_TRI_PARTICLES:
  736. case W3D_EMITTER_RENDER_MODE_QUAD_PARTICLES:
  737. Render_Particles(rinfo);
  738. break;
  739. case W3D_EMITTER_RENDER_MODE_LINE:
  740. Render_Line(rinfo);
  741. break;
  742. case W3D_EMITTER_RENDER_MODE_LINEGRP_TETRA:
  743. case W3D_EMITTER_RENDER_MODE_LINEGRP_PRISM:
  744. Render_Line_Group(rinfo);
  745. break;
  746. }
  747. }
  748. }
  749. void ParticleBufferClass::Generate_APT(ShareBufferClass <unsigned int> **apt,unsigned int &active_point_count)
  750. {
  751. if (NonNewNum < (int)MaxNum || DecimationThreshold > 0) {
  752. // In the general case, a range in a circular buffer can be composed of up
  753. // to two subranges. Find the Start - End subranges.
  754. // This differs from other similar code segments because we want to access
  755. // the subranges in memory order (rather than in queue order) this time.
  756. unsigned int sub1_start; // Start of subrange 1.
  757. unsigned int sub1_end; // End of subrange 1.
  758. unsigned int sub2_start; // Start of subrange 2.
  759. unsigned int sub2_end; // End of subrange 2.
  760. unsigned int i; // Loop index.
  761. if ((Start < End) || ((Start == End) && NonNewNum == 0)) {
  762. sub1_start = Start;
  763. sub1_end = End;
  764. sub2_start = End;
  765. sub2_end = End;
  766. } else {
  767. sub1_start = 0;
  768. sub1_end = End;
  769. sub2_start = Start;
  770. sub2_end = MaxNum;
  771. }
  772. // Generate APT:
  773. unsigned int *apt_ptr = APT->Get_Array();
  774. for (i = sub1_start; i < sub1_end; i++) {
  775. if (PermutationArray[i & 0xF] >= DecimationThreshold) {
  776. apt_ptr[active_point_count++] = i;
  777. }
  778. }
  779. for (i = sub2_start; i < sub2_end; i++) {
  780. if (PermutationArray[i & 0xF] >= DecimationThreshold) {
  781. apt_ptr[active_point_count++] = i;
  782. }
  783. }
  784. *apt = APT;
  785. } else {
  786. active_point_count = NonNewNum;
  787. }
  788. }
  789. void ParticleBufferClass::Combine_Color_And_Alpha()
  790. {
  791. // Temporary array copying to combine diffuse and alpha to one array.
  792. if (Color || Alpha) {
  793. unsigned cnt=MaxNum;
  794. if (!Diffuse) {
  795. Diffuse = NEW_REF( ShareBufferClass<Vector4> , (MaxNum) );
  796. }
  797. if (Color && Alpha) {
  798. VectorProcessorClass::Copy(
  799. Diffuse->Get_Array(),
  800. Color->Get_Array(),
  801. Alpha->Get_Array(),
  802. cnt);
  803. }
  804. else if (Color) {
  805. VectorProcessorClass::Copy(
  806. Diffuse->Get_Array(),
  807. Color->Get_Array(),
  808. 1.0f,
  809. cnt);
  810. }
  811. else {
  812. VectorProcessorClass::Copy(
  813. Diffuse->Get_Array(),
  814. Vector3(1.0f,1.0f,1.0f),
  815. Alpha->Get_Array(),
  816. cnt);
  817. }
  818. VectorProcessorClass::Clamp(
  819. Diffuse->Get_Array(),
  820. Diffuse->Get_Array(),
  821. 0.0f,
  822. 1.0f,
  823. cnt);
  824. }
  825. else if (Diffuse) {
  826. Diffuse->Release_Ref();
  827. Diffuse=NULL;
  828. }
  829. }
  830. void ParticleBufferClass::Render_Particles(RenderInfoClass & rinfo)
  831. {
  832. // If the number of active points is less than the maximum or we need to decimate particles
  833. // (for LOD purposes), build the active point table:
  834. ShareBufferClass<unsigned int> *apt = NULL;
  835. unsigned int active_point_count = 0;
  836. Generate_APT(&apt,active_point_count);
  837. // Set color, alpha, size defaults if array not present:
  838. if (!Color) {
  839. PointGroup->Set_Point_Color(ColorKeyFrameValues[0]);
  840. }
  841. if (!Alpha) {
  842. PointGroup->Set_Point_Alpha(AlphaKeyFrameValues[0]);
  843. }
  844. if (!Size) {
  845. PointGroup->Set_Point_Size(SizeKeyFrameValues[0]);
  846. }
  847. if (!Orientation) {
  848. // The rotation keyframes are used to derive the orientation indirectly, as well as the
  849. // starting orientation randomizer. If there is no Orientation array that means both are
  850. // absent so the orientation should just be set to 0.
  851. PointGroup->Set_Point_Orientation(0);
  852. }
  853. if (!Frame) {
  854. PointGroup->Set_Point_Frame(((int)(FrameKeyFrameValues[0])) & 0xFF);
  855. }
  856. // Pass the point buffer to the point group and render it.
  857. // If we are using pingpong position buffers pass the right one
  858. int pingpong = 0;
  859. if (PingPongPosition) {
  860. pingpong = WW3D::Get_Frame_Count() & 0x1;
  861. }
  862. Combine_Color_And_Alpha();
  863. PointGroup->Set_Arrays(Position[pingpong], Diffuse, apt, Size, Orientation, Frame, active_point_count);
  864. Update_Bounding_Box();
  865. PointGroup->Render(rinfo);
  866. }
  867. void ParticleBufferClass::Render_Line(RenderInfoClass & rinfo)
  868. {
  869. // Look up the array to use
  870. int pingpong = 0;
  871. if (PingPongPosition) {
  872. pingpong = WW3D::Get_Frame_Count() & 0x1;
  873. }
  874. // Unroll the circular buffer while skipping LOD'd particles
  875. static SimpleDynVecClass<Vector3> tmp_points;
  876. Vector3 * positions = Position[pingpong]->Get_Array();
  877. unsigned int sub1_end; // End of subrange 1.
  878. unsigned int sub2_start; // Start of subrange 2.
  879. unsigned int i; // Loop index.
  880. if ((Start < End) || ((Start == End) && NonNewNum ==0)) {
  881. sub1_end = End;
  882. sub2_start = End;
  883. } else {
  884. sub1_end = MaxNum;
  885. sub2_start = 0;
  886. }
  887. tmp_points.Delete_All(false);
  888. for (i = Start; i < sub1_end; i++) {
  889. if (PermutationArray[i & 0xF] >= DecimationThreshold) {
  890. tmp_points.Add(positions[i]);
  891. }
  892. }
  893. for (i = sub2_start; i < End; i++) {
  894. if (PermutationArray[i & 0xF] >= DecimationThreshold) {
  895. tmp_points.Add(positions[i]);
  896. }
  897. }
  898. // If we got any points, render them
  899. if (tmp_points.Count() > 0) {
  900. SphereClass bounding_sphere;
  901. Get_Obj_Space_Bounding_Sphere(bounding_sphere);
  902. LineRenderer->Render(rinfo,
  903. Transform,
  904. tmp_points.Count(),
  905. &(tmp_points[0]),
  906. bounding_sphere);
  907. }
  908. }
  909. void ParticleBufferClass::Render_Line_Group(RenderInfoClass & rinfo)
  910. {
  911. // If the number of active points is less than the maximum or we need to decimate particles
  912. // (for LOD purposes), build the active point table:
  913. ShareBufferClass<unsigned int> *apt = NULL;
  914. unsigned int active_point_count = 0;
  915. Generate_APT(&apt,active_point_count);
  916. // Set color, alpha, size defaults if array not present:
  917. if (!Color) {
  918. LineGroup->Set_Line_Color(ColorKeyFrameValues[0]);
  919. }
  920. if (!Alpha) {
  921. LineGroup->Set_Line_Alpha(AlphaKeyFrameValues[0]);
  922. }
  923. if (!Size) {
  924. LineGroup->Set_Line_Size(SizeKeyFrameValues[0]);
  925. }
  926. if (!Frame) {
  927. LineGroup->Set_Line_UCoord(FrameKeyFrameValues[0]);
  928. }
  929. // Pass the point buffer to the line group and render it.
  930. // If we are using pingpong position buffers pass the right one
  931. int pingpong = 0;
  932. if (PingPongPosition) {
  933. pingpong = WW3D::Get_Frame_Count() & 0x1;
  934. }
  935. Combine_Color_And_Alpha();
  936. TailDiffuseTypeEnum tailtype=Determine_Tail_Diffuse();
  937. switch (tailtype)
  938. {
  939. case BLACK:
  940. REF_PTR_RELEASE(TailDiffuse);
  941. DefaultTailDiffuse.Set(0,0,0,0);
  942. break;
  943. case WHITE:
  944. REF_PTR_RELEASE(TailDiffuse);
  945. DefaultTailDiffuse.Set(1,1,1,1);
  946. break;
  947. case SAME_AS_HEAD_ALPHA_ZERO:
  948. // if head is all one color, set tail the same way
  949. if (!Diffuse) {
  950. REF_PTR_RELEASE(TailDiffuse);
  951. DefaultTailDiffuse.Set(ColorKeyFrameValues[0].X,ColorKeyFrameValues[0].Y,ColorKeyFrameValues[0].Z,0);
  952. } else {
  953. // otherwise allocate and copy tail diffuse
  954. if (!TailDiffuse) TailDiffuse=NEW_REF(ShareBufferClass<Vector4>,(MaxNum));
  955. for (unsigned int i=0; i<MaxNum; i++) {
  956. Vector4 elt=Diffuse->Get_Element(i);
  957. elt.W=0;
  958. TailDiffuse->Set_Element(i,elt);
  959. }
  960. }
  961. break;
  962. case SAME_AS_HEAD:
  963. // if head is all one color, set tail the same way
  964. if (!Diffuse) {
  965. REF_PTR_RELEASE(TailDiffuse);
  966. DefaultTailDiffuse.Set(ColorKeyFrameValues[0].X,ColorKeyFrameValues[0].Y,ColorKeyFrameValues[0].Z,AlphaKeyFrameValues[0]);
  967. } else {
  968. // otherwise allocate and copy tail diffuse
  969. if (!TailDiffuse) TailDiffuse=NEW_REF(ShareBufferClass<Vector4>,(MaxNum));
  970. VectorProcessorClass::Copy(TailDiffuse->Get_Array(),Diffuse->Get_Array(),MaxNum);
  971. }
  972. break;
  973. default:
  974. WWASSERT(0);
  975. break;
  976. }
  977. if (!TailDiffuse)
  978. LineGroup->Set_Tail_Diffuse(DefaultTailDiffuse);
  979. LineGroup->Set_Arrays(Position[pingpong], TailPosition,Diffuse,TailDiffuse, apt, Size, UCoord, active_point_count);
  980. Update_Bounding_Box();
  981. LineGroup->Render(rinfo);
  982. }
  983. // Scales the size of the individual particles but doesn't affect their
  984. // position (and therefore the size of the particle system as a whole)
  985. void ParticleBufferClass::Scale(float scale)
  986. {
  987. // Scale all size keyframes, keyframe deltas, random size entries,
  988. // MaxSize and SizeRandom.
  989. unsigned int i;
  990. for (i = 0; i < NumSizeKeyFrames; i++) {
  991. SizeKeyFrameValues[i] *= scale;
  992. SizeKeyFrameDeltas[i] *= scale;
  993. }
  994. if (RandomSizeEntries) {
  995. for (i = 0; i <= NumRandomSizeEntriesMinus1; i++) {
  996. RandomSizeEntries[i] *= scale;
  997. }
  998. }
  999. MaxSize *= scale;
  1000. SizeRandom *= scale;
  1001. }
  1002. // The particle buffer never receives a Set_Transform/Position call,
  1003. // evem though its bounding volume changes. Since bounding volume
  1004. // invalidations ordinarily occur when these functions are called,
  1005. // the cached bounding volumes will not be invalidated unless we do
  1006. // it elsewhere (such as here). We also need to call the particle
  1007. // emitter's Emit() function (done here to avoid order dependence).
  1008. void ParticleBufferClass::On_Frame_Update(void)
  1009. {
  1010. Invalidate_Cached_Bounding_Volumes();
  1011. if (Emitter) {
  1012. Emitter->Emit();
  1013. }
  1014. if (Is_Complete()) {
  1015. WWASSERT(Scene);
  1016. Scene->Register(this,SceneClass::RELEASE);
  1017. }
  1018. }
  1019. void ParticleBufferClass::Notify_Added(SceneClass * scene)
  1020. {
  1021. RenderObjClass::Notify_Added(scene);
  1022. scene->Register(this,SceneClass::ON_FRAME_UPDATE);
  1023. }
  1024. void ParticleBufferClass::Notify_Removed(SceneClass * scene)
  1025. {
  1026. scene->Unregister(this,SceneClass::ON_FRAME_UPDATE);
  1027. RenderObjClass::Notify_Removed(scene);
  1028. }
  1029. void ParticleBufferClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
  1030. {
  1031. // This ugly cast is done because the alternative is to make everything
  1032. // in the class mutable, which does not seem like a good solution
  1033. // (Update_Bounding_Box can potentially update the particle state)
  1034. ((ParticleBufferClass *)this)->Update_Bounding_Box();
  1035. // The particle buffer's transform is always identity, so
  1036. // objspace == worldspace.
  1037. // Wrap sphere outside bounding box:
  1038. sphere.Center = BoundingBox.Center;
  1039. sphere.Radius = BoundingBox.Extent.Length();
  1040. }
  1041. void ParticleBufferClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
  1042. {
  1043. // This ugly cast is done because the alternative is to make everything
  1044. // in the class mutable, which does not seem like a good solution
  1045. // (Update_Bounding_Box can potentially update the particle state).
  1046. ((ParticleBufferClass *)this)->Update_Bounding_Box();
  1047. // The particle buffer's transform is always identity, so
  1048. // objspace == worldspace.
  1049. box = BoundingBox;
  1050. }
  1051. void ParticleBufferClass::Prepare_LOD(CameraClass &camera)
  1052. {
  1053. if (Is_Not_Hidden_At_All() == false) {
  1054. return;
  1055. }
  1056. // Estimate the screen area of the particle buffer. We shall take the lesser of two
  1057. // metrics: the standard bounding-sphere projection (which for many particle systems may
  1058. // grossly overestimate the actual screen area), and a measurement based on the screen area of
  1059. // individual particles times the maximum number of particles (in the case of densely
  1060. // overlapping particles this metric can also give numbers which are too high, which is why we
  1061. // use the bounding sphere as backup). Note - to find the area of individual particles we
  1062. // treat them as all being the maximum size and being in the center of the bounding sphere).
  1063. Vector3 cam = camera.Get_Position();
  1064. ViewportClass viewport = camera.Get_Viewport();
  1065. Vector2 vpr_min, vpr_max;
  1066. camera.Get_View_Plane(vpr_min, vpr_max);
  1067. float width_factor = viewport.Width() / (vpr_max.X - vpr_min.X);
  1068. float height_factor = viewport.Height() / (vpr_max.Y - vpr_min.Y);
  1069. const SphereClass & sphere = Get_Bounding_Sphere();
  1070. float dist = (sphere.Center - cam).Length();
  1071. float bounding_sphere_projected_radius = 0.0f;
  1072. float particle_projected_radius = 0.0f;
  1073. if (dist) {
  1074. float oo_dist = 1.0f / dist;
  1075. bounding_sphere_projected_radius = sphere.Radius * oo_dist;
  1076. particle_projected_radius = MaxSize * oo_dist;
  1077. }
  1078. float bs_rad_sq = bounding_sphere_projected_radius * bounding_sphere_projected_radius;
  1079. float p_rad_sq = particle_projected_radius * particle_projected_radius * MaxNum;
  1080. float proj_area = WWMATH_PI * MIN(bs_rad_sq, p_rad_sq) * width_factor * height_factor;
  1081. // Filter the area over time so we don't get as many pops in the LOD algorithm
  1082. ProjectedArea = 0.9f * ProjectedArea + 0.1f * proj_area;
  1083. int minlod = Calculate_Cost_Value_Arrays(ProjectedArea, Value, Cost);
  1084. // Ensure lod is no less than minimum allowed
  1085. if (Get_LOD_Level() < minlod) Set_LOD_Level(minlod);
  1086. PredictiveLODOptimizerClass::Add_Object(this);
  1087. }
  1088. void ParticleBufferClass::Increment_LOD(void)
  1089. {
  1090. if (DecimationThreshold > 0) DecimationThreshold--;
  1091. }
  1092. void ParticleBufferClass::Decrement_LOD(void)
  1093. {
  1094. if (DecimationThreshold < LodCount) DecimationThreshold++;
  1095. }
  1096. float ParticleBufferClass::Get_Cost(void) const
  1097. {
  1098. return(Cost[(LodCount - 1) - DecimationThreshold]);
  1099. }
  1100. float ParticleBufferClass::Get_Value(void) const
  1101. {
  1102. return(Value[(LodCount - 1) - DecimationThreshold]);
  1103. }
  1104. float ParticleBufferClass::Get_Post_Increment_Value(void) const
  1105. {
  1106. return(Value[LodCount - DecimationThreshold]);
  1107. }
  1108. void ParticleBufferClass::Set_LOD_Level(int lod)
  1109. {
  1110. lod = Bound(lod, 0, (int)LodCount);
  1111. DecimationThreshold = (LodCount - 1) - lod;
  1112. }
  1113. int ParticleBufferClass::Get_LOD_Level(void) const
  1114. {
  1115. return((LodCount - 1) - DecimationThreshold);
  1116. }
  1117. int ParticleBufferClass::Get_LOD_Count(void) const
  1118. {
  1119. return LodCount;
  1120. }
  1121. int ParticleBufferClass::Calculate_Cost_Value_Arrays(float screen_area, float *values, float *costs) const
  1122. {
  1123. unsigned int lod = 0;
  1124. // Calculate Cost heuristic for each LOD (we currently ignore pixel costs for particle systems)
  1125. // The cost factor is later multiplied by the LOD level. The LOD level is the numerator of the
  1126. // fraction of particles rendered, where 16 is the denominator. For this reason the cost factor
  1127. // is based on a 1/16 (0.0625) of the total.
  1128. float cost_factor=0.0f;
  1129. switch (RenderMode)
  1130. {
  1131. case W3D_EMITTER_RENDER_MODE_TRI_PARTICLES:
  1132. cost_factor = (float)MaxNum * 0.0625f;
  1133. break;
  1134. case W3D_EMITTER_RENDER_MODE_QUAD_PARTICLES:
  1135. cost_factor = (float)MaxNum * 2.0f * 0.0625f;
  1136. break;
  1137. case W3D_EMITTER_RENDER_MODE_LINE:
  1138. cost_factor = (float) (2*MaxNum-1) * 0.0625f;
  1139. break;
  1140. case W3D_EMITTER_RENDER_MODE_LINEGRP_TETRA:
  1141. cost_factor = (float)MaxNum * 4.0f * 0.0625f;
  1142. break;
  1143. case W3D_EMITTER_RENDER_MODE_LINEGRP_PRISM:
  1144. cost_factor = (float)MaxNum * 8.0f * 0.0625f;
  1145. break;
  1146. }
  1147. for (lod = 0; lod < LodCount; lod++) {
  1148. costs[lod] = cost_factor * (float)lod;
  1149. // If cost is zero set it to a small nonzero amount to avoid divisions by zero.
  1150. costs[lod] = (costs[lod] != 0) ? costs[lod] : 0.000001f;
  1151. }
  1152. // Calculate Value heuristic. First, all LOD levels for which
  1153. // MaxScreenSize is smaller than screen_area have their Value set to
  1154. // AT_MIN_LOD, as well as the first LOD after that (unless there are no
  1155. // other LODs):
  1156. for (lod = 0; lod < LodCount && LODMaxScreenSizes[lod] < screen_area; lod++) {
  1157. values[lod] = AT_MIN_LOD;
  1158. }
  1159. if (lod >= LodCount) {
  1160. lod = LodCount - 1;
  1161. } else {
  1162. values[lod] = AT_MIN_LOD;
  1163. }
  1164. // Now lod is the lowest allowed - return this value.
  1165. int minlod = lod;
  1166. // Calculate Value heuristic for any remaining LODs based on normalized screen area:
  1167. lod++;
  1168. for (; lod < LodCount; lod++) {
  1169. // Currently the cost happens to be equal to the poly count. We use a floating-
  1170. // point poly count since costs[] contains an approximation to the true polycount which may
  1171. // be less than one in some cases (we want to avoid 0 polycounts except for true null LODs)
  1172. float polycount = costs[lod];
  1173. float benefit_factor = (polycount > WWMATH_EPSILON) ? (1 - (0.5f / (polycount * polycount))) : 0.0f;
  1174. values[lod] = (benefit_factor * screen_area * LodBias) / costs[lod];
  1175. }
  1176. values[LodCount] = AT_MAX_LOD; // Post-inc value will flag max LOD.
  1177. return minlod;
  1178. }
  1179. void ParticleBufferClass::Reset_Colors(ParticlePropertyStruct<Vector3> &new_props)
  1180. {
  1181. unsigned int i; // Used in loops
  1182. unsigned int ui_previous_key_time = 0;
  1183. unsigned int ui_current_key_time = 0;
  1184. ColorRandom = new_props.Rand;
  1185. // If the randomizer is effectively zero and there are no keyframes, then we just create a
  1186. // values array with one entry and store the starting value in it (the keyframes and random
  1187. // table will not be used in this case).
  1188. static const float eps_byte = 0.0038f; // Epsilon value - less than 1/255
  1189. bool color_rand_zero = (fabs(new_props.Rand.X) < eps_byte && fabs(new_props.Rand.Y) < eps_byte && fabs(new_props.Rand.Z) < eps_byte);
  1190. if (color_rand_zero && new_props.NumKeyFrames == 0) {
  1191. // Release Color, ColorKeyFrameTimes and ColorKeyFrameDeltas if present. Reuse
  1192. // ColorKeyFrameValues if the right size, otherwise release and reallocate.
  1193. if (Color) {
  1194. Color->Release_Ref();
  1195. Color = NULL;
  1196. }
  1197. if (ColorKeyFrameTimes) {
  1198. delete [] ColorKeyFrameTimes;
  1199. ColorKeyFrameTimes = NULL;
  1200. }
  1201. if (ColorKeyFrameDeltas) {
  1202. delete [] ColorKeyFrameDeltas;
  1203. ColorKeyFrameDeltas = NULL;
  1204. }
  1205. if (ColorKeyFrameValues) {
  1206. if (NumColorKeyFrames > 1) {
  1207. delete [] ColorKeyFrameValues;
  1208. ColorKeyFrameValues = new Vector3 [1];
  1209. }
  1210. } else {
  1211. ColorKeyFrameValues = new Vector3 [1];
  1212. }
  1213. NumColorKeyFrames = 0;
  1214. NumRandomColorEntriesMinus1 = 0;
  1215. ColorKeyFrameValues[0] = new_props.Start;
  1216. } else {
  1217. // Create the color array if not present
  1218. if (!Color) {
  1219. Color = NEW_REF( ShareBufferClass<Vector3> , (MaxNum) );
  1220. }
  1221. // Check times of color keyframes (each keytime must be larger than the
  1222. // previous one by at least a millisecond, and we stop at the first
  1223. // keytime of MaxAge or larger. (If all keyframes below MaxAge, color is
  1224. // constant during the last segment between last keyframe and MaxAge).
  1225. ui_previous_key_time = 0;
  1226. for (unsigned int ckey = 0; ckey < new_props.NumKeyFrames; ckey++) {
  1227. ui_current_key_time = (unsigned int)(new_props.KeyTimes[ckey] * 1000.0f);
  1228. WWASSERT(ui_current_key_time > ui_previous_key_time);
  1229. if (ui_current_key_time >= MaxAge) break;
  1230. ui_previous_key_time = ui_current_key_time;
  1231. }
  1232. bool color_constant_at_end = (ckey == new_props.NumKeyFrames);
  1233. // Reuse ColorKeyFrameValues, ColorKeyFrameTimes and ColorKeyFrameDeltas if the right size,
  1234. // otherwise release and reallocate.
  1235. unsigned int new_num_color_key_frames = ckey + 1;// Includes start keyframe (keytime == 0).
  1236. if (new_num_color_key_frames != NumColorKeyFrames) {
  1237. if (ColorKeyFrameTimes) {
  1238. delete [] ColorKeyFrameTimes;
  1239. ColorKeyFrameTimes = NULL;
  1240. }
  1241. if (ColorKeyFrameValues) {
  1242. delete [] ColorKeyFrameValues;
  1243. ColorKeyFrameValues = NULL;
  1244. }
  1245. if (ColorKeyFrameDeltas) {
  1246. delete [] ColorKeyFrameDeltas;
  1247. ColorKeyFrameDeltas = NULL;
  1248. }
  1249. NumColorKeyFrames = new_num_color_key_frames;
  1250. ColorKeyFrameTimes = new unsigned int [NumColorKeyFrames];
  1251. ColorKeyFrameValues = new Vector3 [NumColorKeyFrames];
  1252. ColorKeyFrameDeltas = new Vector3 [NumColorKeyFrames];
  1253. }
  1254. // Set color keyframes (deltas will be set later)
  1255. ColorKeyFrameTimes[0] = 0;
  1256. ColorKeyFrameValues[0] = new_props.Start;
  1257. for (i = 1; i < NumColorKeyFrames; i++) {
  1258. unsigned int im1 = i - 1;
  1259. ColorKeyFrameTimes[i] = (unsigned int)(new_props.KeyTimes[im1] * 1000.0f);
  1260. ColorKeyFrameValues[i] = new_props.Values[im1];
  1261. }
  1262. // Do deltas for all color keyframes except last
  1263. for (i = 0; i < NumColorKeyFrames - 1; i++) {
  1264. ColorKeyFrameDeltas[i] = (ColorKeyFrameValues[i + 1] - ColorKeyFrameValues[i]) /
  1265. (float)(ColorKeyFrameTimes[i + 1] - ColorKeyFrameTimes[i]);
  1266. }
  1267. // Do delta for last color keyframe (i is NumColorKeyFrames - 1)
  1268. if (color_constant_at_end) {
  1269. ColorKeyFrameDeltas[i].Set(0.0, 0.0, 0.0);
  1270. } else {
  1271. // This is OK because if color_constant_at_end is false, NumColorKeyFrames is equal or
  1272. // smaller than color.NumKeyFrames so color.Values[NumColorKeyFrames - 1] and
  1273. // color.KeyTimes[NumColorKeyFrames - 1] exist.
  1274. ColorKeyFrameDeltas[i] = (new_props.Values[i] - ColorKeyFrameValues[i]) /
  1275. (new_props.KeyTimes[i] * 1000.0f - (float)ColorKeyFrameTimes[i]);
  1276. }
  1277. // Set up color randomizer table
  1278. if (color_rand_zero) {
  1279. if (RandomColorEntries) {
  1280. // Reuse RandomColorEntries if the right size, otherwise release and reallocate.
  1281. if (NumRandomColorEntriesMinus1 != 0) {
  1282. delete [] RandomColorEntries;
  1283. RandomColorEntries = new Vector3 [1];
  1284. }
  1285. } else {
  1286. RandomColorEntries = new Vector3 [1];
  1287. }
  1288. NumRandomColorEntriesMinus1 = 0;
  1289. RandomColorEntries[0].X = 0.0f;
  1290. RandomColorEntries[0].Y = 0.0f;
  1291. RandomColorEntries[0].Z = 0.0f;
  1292. } else {
  1293. // Default size of randomizer tables (tables for non-zero randomizers will be this size)
  1294. unsigned int pot_num = Find_POT(MaxNum);
  1295. unsigned int default_randomizer_entries = MIN(pot_num, MAX_RANDOM_ENTRIES);
  1296. if (RandomColorEntries) {
  1297. // Reuse RandomColorEntries if the right size, otherwise release and reallocate.
  1298. if (NumRandomColorEntriesMinus1 != (default_randomizer_entries - 1)) {
  1299. delete [] RandomColorEntries;
  1300. RandomColorEntries = new Vector3 [default_randomizer_entries];
  1301. }
  1302. } else {
  1303. RandomColorEntries = new Vector3 [default_randomizer_entries];
  1304. }
  1305. NumRandomColorEntriesMinus1 = default_randomizer_entries - 1;
  1306. float rscale = new_props.Rand.X * oo_intmax;
  1307. float gscale = new_props.Rand.Y * oo_intmax;
  1308. float bscale = new_props.Rand.Z * oo_intmax;
  1309. for (unsigned int j = 0; j <= NumRandomColorEntriesMinus1; j++) {
  1310. RandomColorEntries[j] = Vector3(rand_gen * rscale, rand_gen * gscale, rand_gen * bscale);
  1311. }
  1312. }
  1313. }
  1314. }
  1315. void ParticleBufferClass::Reset_Opacity(ParticlePropertyStruct<float> &new_props)
  1316. {
  1317. unsigned int i; // Used in loops
  1318. unsigned int ui_previous_key_time = 0;
  1319. unsigned int ui_current_key_time = 0;
  1320. OpacityRandom = new_props.Rand;
  1321. // If the randomizer is effectively zero and there are no keyframes, then we just create a
  1322. // values array with one entry and store the starting value in it (the keyframes and random
  1323. // table will not be used in this case).
  1324. static const float eps_byte = 0.0038f; // Epsilon value - less than 1/255
  1325. bool alpha_rand_zero = (fabs(new_props.Rand) < eps_byte);
  1326. if (alpha_rand_zero && new_props.NumKeyFrames == 0) {
  1327. // Release Alpha, AlphaKeyFrameTimes and AlphaKeyFrameDeltas if present. Reuse
  1328. // AlphaKeyFrameValues if the right size, otherwise release and reallocate.
  1329. if (Alpha) {
  1330. Alpha->Release_Ref();
  1331. Alpha = NULL;
  1332. }
  1333. if (AlphaKeyFrameTimes) {
  1334. delete [] AlphaKeyFrameTimes;
  1335. AlphaKeyFrameTimes = NULL;
  1336. }
  1337. if (AlphaKeyFrameDeltas) {
  1338. delete [] AlphaKeyFrameDeltas;
  1339. AlphaKeyFrameDeltas = NULL;
  1340. }
  1341. if (AlphaKeyFrameValues) {
  1342. if (NumAlphaKeyFrames > 1) {
  1343. delete [] AlphaKeyFrameValues;
  1344. AlphaKeyFrameValues = new float [1];
  1345. }
  1346. } else {
  1347. AlphaKeyFrameValues = new float [1];
  1348. }
  1349. NumAlphaKeyFrames = 0;
  1350. NumRandomAlphaEntriesMinus1 = 0;
  1351. AlphaKeyFrameValues[0] = new_props.Start;
  1352. } else {
  1353. // Create the alpha array if not present
  1354. if (!Alpha) {
  1355. Alpha = NEW_REF( ShareBufferClass<float> , (MaxNum) );
  1356. }
  1357. // Check times of opacity keyframes (each keytime must be larger than the
  1358. // previous one by at least a millisecond, and we stop at the first
  1359. // keytime of MaxAge or larger. (If all keyframes below MaxAge, alpha is
  1360. // constant during the last segment between last keyframe and MaxAge).
  1361. ui_previous_key_time = 0;
  1362. for (unsigned int akey = 0; akey < new_props.NumKeyFrames; akey++) {
  1363. ui_current_key_time = (unsigned int)(new_props.KeyTimes[akey] * 1000.0f);
  1364. WWASSERT(ui_current_key_time > ui_previous_key_time);
  1365. if (ui_current_key_time >= MaxAge) break;
  1366. ui_previous_key_time = ui_current_key_time;
  1367. }
  1368. bool alpha_constant_at_end = (akey == new_props.NumKeyFrames);
  1369. // Reuse AlphaKeyFrameValues, AlphaKeyFrameTimes and AlphaKeyFrameDeltas if the right size,
  1370. // otherwise release and reallocate.
  1371. unsigned int new_num_alpha_key_frames = akey + 1;// Includes start keyframe (keytime == 0).
  1372. if (new_num_alpha_key_frames != NumAlphaKeyFrames) {
  1373. if (AlphaKeyFrameTimes) {
  1374. delete [] AlphaKeyFrameTimes;
  1375. AlphaKeyFrameTimes = NULL;
  1376. }
  1377. if (AlphaKeyFrameValues) {
  1378. delete [] AlphaKeyFrameValues;
  1379. AlphaKeyFrameValues = NULL;
  1380. }
  1381. if (AlphaKeyFrameDeltas) {
  1382. delete [] AlphaKeyFrameDeltas;
  1383. AlphaKeyFrameDeltas = NULL;
  1384. }
  1385. NumAlphaKeyFrames = new_num_alpha_key_frames;
  1386. AlphaKeyFrameTimes = new unsigned int [NumAlphaKeyFrames];
  1387. AlphaKeyFrameValues = new float [NumAlphaKeyFrames];
  1388. AlphaKeyFrameDeltas = new float [NumAlphaKeyFrames];
  1389. }
  1390. // Set alpha keyframes (deltas will be set later)
  1391. AlphaKeyFrameTimes[0] = 0;
  1392. AlphaKeyFrameValues[0] = new_props.Start;
  1393. for (i = 1; i < NumAlphaKeyFrames; i++) {
  1394. unsigned int im1 = i - 1;
  1395. AlphaKeyFrameTimes[i] = (unsigned int)(new_props.KeyTimes[im1] * 1000.0f);
  1396. AlphaKeyFrameValues[i] = new_props.Values[im1];
  1397. }
  1398. // Do deltas for all alpha keyframes except last
  1399. for (i = 0; i < NumAlphaKeyFrames - 1; i++) {
  1400. AlphaKeyFrameDeltas[i] = (AlphaKeyFrameValues[i + 1] - AlphaKeyFrameValues[i]) /
  1401. (float)(AlphaKeyFrameTimes[i + 1] - AlphaKeyFrameTimes[i]);
  1402. }
  1403. // Do delta for last alpha keyframe (i is NumAlphaKeyFrames - 1)
  1404. if (alpha_constant_at_end) {
  1405. AlphaKeyFrameDeltas[i] = 0.0f;
  1406. } else {
  1407. // This is OK because if alpha_constant_at_end is false, NumAlphaKeyFrames is equal or
  1408. // smaller than opacity.NumKeyFrames so opacity.Values[NumAlphaKeyFrames - 1] and
  1409. // opacity.KeyTimes[NumAlphaKeyFrames - 1] exist.
  1410. AlphaKeyFrameDeltas[i] = (new_props.Values[i] - AlphaKeyFrameValues[i]) /
  1411. (new_props.KeyTimes[i] * 1000.0f - (float)AlphaKeyFrameTimes[i]);
  1412. }
  1413. // Set up alpha randomizer table
  1414. if (alpha_rand_zero) {
  1415. if (RandomAlphaEntries) {
  1416. // Reuse RandomAlphaEntries if the right size, otherwise release and reallocate.
  1417. if (NumRandomAlphaEntriesMinus1 != 0) {
  1418. delete [] RandomAlphaEntries;
  1419. RandomAlphaEntries = new float [1];
  1420. }
  1421. } else {
  1422. RandomAlphaEntries = new float [1];
  1423. }
  1424. NumRandomAlphaEntriesMinus1 = 0;
  1425. RandomAlphaEntries[0] = 0.0f;
  1426. } else {
  1427. // Default size of randomizer tables (tables for non-zero randomizers will be this size)
  1428. unsigned int pot_num = Find_POT(MaxNum);
  1429. unsigned int default_randomizer_entries = MIN(pot_num, MAX_RANDOM_ENTRIES);
  1430. if (RandomAlphaEntries) {
  1431. // Reuse RandomAlphaEntries if the right size, otherwise release and reallocate.
  1432. if (NumRandomAlphaEntriesMinus1 != (default_randomizer_entries - 1)) {
  1433. delete [] RandomAlphaEntries;
  1434. RandomAlphaEntries = new float [default_randomizer_entries];
  1435. }
  1436. } else {
  1437. RandomAlphaEntries = new float [default_randomizer_entries];
  1438. }
  1439. NumRandomAlphaEntriesMinus1 = default_randomizer_entries - 1;
  1440. float ascale = new_props.Rand * oo_intmax;
  1441. for (unsigned int j = 0; j <= NumRandomAlphaEntriesMinus1; j++) {
  1442. RandomAlphaEntries[j] = rand_gen * ascale;
  1443. }
  1444. }
  1445. }
  1446. }
  1447. void ParticleBufferClass::Reset_Size(ParticlePropertyStruct<float> &new_props)
  1448. {
  1449. unsigned int i; // Used in loops
  1450. unsigned int ui_previous_key_time = 0;
  1451. unsigned int ui_current_key_time = 0;
  1452. SizeRandom = new_props.Rand;
  1453. // If the randomizer is effectively zero and there are no keyframes, then we just create a
  1454. // values array with one entry and store the starting value in it (the keyframes and random
  1455. // table will not be used in this case).
  1456. static const float eps_size = 1.0e-12f; // Size scale unknown so must use very small epsilon
  1457. bool size_rand_zero = (fabs(new_props.Rand) < eps_size);
  1458. if (size_rand_zero && new_props.NumKeyFrames == 0) {
  1459. // Release Size, SizeKeyFrameTimes and SizeaKeyFrameDeltas if present. Reuse
  1460. // SizeKeyFrameValues if the right size, otherwise release and reallocate.
  1461. if (Size) {
  1462. Size->Release_Ref();
  1463. Size = NULL;
  1464. }
  1465. if (SizeKeyFrameTimes) {
  1466. delete [] SizeKeyFrameTimes;
  1467. SizeKeyFrameTimes = NULL;
  1468. }
  1469. if (SizeKeyFrameDeltas) {
  1470. delete [] SizeKeyFrameDeltas;
  1471. SizeKeyFrameDeltas = NULL;
  1472. }
  1473. if (SizeKeyFrameValues) {
  1474. if (NumSizeKeyFrames > 1) {
  1475. delete [] SizeKeyFrameValues;
  1476. SizeKeyFrameValues = new float [1];
  1477. }
  1478. } else {
  1479. SizeKeyFrameValues = new float [1];
  1480. }
  1481. NumSizeKeyFrames = 0;
  1482. NumRandomSizeEntriesMinus1 = 0;
  1483. SizeKeyFrameValues[0] = new_props.Start;
  1484. MaxSize = SizeKeyFrameValues[0];
  1485. } else {
  1486. // Create the size array if not present
  1487. if (!Size) {
  1488. Size = NEW_REF( ShareBufferClass<float> , (MaxNum) );
  1489. }
  1490. // Check times of size keyframes (each keytime must be larger than the
  1491. // previous one by at least a millisecond, and we stop at the first
  1492. // keytime of MaxAge or larger. (If all keyframes below MaxAge, size is
  1493. // constant during the last segment between last keyframe and MaxAge).
  1494. ui_previous_key_time = 0;
  1495. for (unsigned int skey = 0; skey < new_props.NumKeyFrames; skey++) {
  1496. ui_current_key_time = (unsigned int)(new_props.KeyTimes[skey] * 1000.0f);
  1497. WWASSERT(ui_current_key_time > ui_previous_key_time);
  1498. if (ui_current_key_time >= MaxAge) break;
  1499. ui_previous_key_time = ui_current_key_time;
  1500. }
  1501. bool size_constant_at_end = (skey == new_props.NumKeyFrames);
  1502. // Reuse SizeKeyFrameValues, SizeKeyFrameTimes and SizeKeyFrameDeltas if the right size,
  1503. // otherwise release and reallocate.
  1504. unsigned int new_num_size_key_frames = skey + 1;// Includes start keyframe (keytime == 0).
  1505. if (new_num_size_key_frames != NumSizeKeyFrames) {
  1506. if (SizeKeyFrameTimes) {
  1507. delete [] SizeKeyFrameTimes;
  1508. SizeKeyFrameTimes = NULL;
  1509. }
  1510. if (SizeKeyFrameValues) {
  1511. delete [] SizeKeyFrameValues;
  1512. SizeKeyFrameValues = NULL;
  1513. }
  1514. if (SizeKeyFrameDeltas) {
  1515. delete [] SizeKeyFrameDeltas;
  1516. SizeKeyFrameDeltas = NULL;
  1517. }
  1518. NumSizeKeyFrames = new_num_size_key_frames;
  1519. SizeKeyFrameTimes = new unsigned int [NumSizeKeyFrames];
  1520. SizeKeyFrameValues = new float [NumSizeKeyFrames];
  1521. SizeKeyFrameDeltas = new float [NumSizeKeyFrames];
  1522. }
  1523. // Set size keyframes (deltas will be set later)
  1524. SizeKeyFrameTimes[0] = 0;
  1525. SizeKeyFrameValues[0] = new_props.Start;
  1526. for (i = 1; i < NumSizeKeyFrames; i++) {
  1527. unsigned int im1 = i - 1;
  1528. SizeKeyFrameTimes[i] = (unsigned int)(new_props.KeyTimes[im1] * 1000.0f);
  1529. SizeKeyFrameValues[i] = new_props.Values[im1];
  1530. }
  1531. // Do deltas for all size keyframes except last
  1532. for (i = 0; i < NumSizeKeyFrames - 1; i++) {
  1533. SizeKeyFrameDeltas[i] = (SizeKeyFrameValues[i + 1] - SizeKeyFrameValues[i]) /
  1534. (float)(SizeKeyFrameTimes[i + 1] - SizeKeyFrameTimes[i]);
  1535. }
  1536. // Do delta for last size keyframe (i is NumSizeKeyFrames - 1)
  1537. if (size_constant_at_end) {
  1538. SizeKeyFrameDeltas[i] = 0.0f;
  1539. } else {
  1540. // This is OK because if size_constant_at_end is false, NumSizeKeyFrames is equal or
  1541. // smaller than new_props.NumKeyFrames so new_props.Values[NumSizeKeyFrames - 1] and
  1542. // new_props.KeyTimes[NumSizeKeyFrames - 1] exist.
  1543. SizeKeyFrameDeltas[i] = (new_props.Values[i] - SizeKeyFrameValues[i]) /
  1544. (new_props.KeyTimes[i] * 1000.0f - (float)SizeKeyFrameTimes[i]);
  1545. }
  1546. // Find maximum size (for BBox updates)
  1547. MaxSize = SizeKeyFrameValues[0];
  1548. for (i = 1; i < NumSizeKeyFrames; i++) {
  1549. MaxSize = MAX(MaxSize, SizeKeyFrameValues[i]);
  1550. }
  1551. // If last delta is positive, there may be a larger size keyframe:
  1552. float last_size = SizeKeyFrameValues[NumSizeKeyFrames - 1] + SizeKeyFrameDeltas[NumSizeKeyFrames - 1] *
  1553. (float)(MaxAge - SizeKeyFrameTimes[NumSizeKeyFrames - 1]);
  1554. MaxSize = MAX(MaxSize, last_size);
  1555. MaxSize += fabs(new_props.Rand);
  1556. // Set up size randomizer table
  1557. if (size_rand_zero) {
  1558. if (RandomSizeEntries) {
  1559. // Reuse RandomSizeEntries if the right size, otherwise release and reallocate.
  1560. if (NumRandomSizeEntriesMinus1 != 0) {
  1561. delete [] RandomSizeEntries;
  1562. RandomSizeEntries = new float [1];
  1563. }
  1564. } else {
  1565. RandomSizeEntries = new float [1];
  1566. }
  1567. NumRandomSizeEntriesMinus1 = 0;
  1568. RandomSizeEntries[0] = 0.0f;
  1569. } else {
  1570. // Default size of randomizer tables (tables for non-zero randomizers will be this size)
  1571. unsigned int pot_num = Find_POT(MaxNum);
  1572. unsigned int default_randomizer_entries = MIN(pot_num, MAX_RANDOM_ENTRIES);
  1573. if (RandomSizeEntries) {
  1574. // Reuse RandomSizeEntries if the right size, otherwise release and reallocate.
  1575. if (NumRandomSizeEntriesMinus1 != (default_randomizer_entries - 1)) {
  1576. delete [] RandomSizeEntries;
  1577. RandomSizeEntries = new float [default_randomizer_entries];
  1578. }
  1579. } else {
  1580. RandomSizeEntries = new float [default_randomizer_entries];
  1581. }
  1582. NumRandomSizeEntriesMinus1 = default_randomizer_entries - 1;
  1583. float sscale = new_props.Rand * oo_intmax;
  1584. for (unsigned int j = 0; j <= NumRandomSizeEntriesMinus1; j++) {
  1585. RandomSizeEntries[j] = rand_gen * sscale;
  1586. }
  1587. }
  1588. }
  1589. }
  1590. void ParticleBufferClass::Reset_Rotations(ParticlePropertyStruct<float> &new_props, float orient_rnd)
  1591. {
  1592. unsigned int i; // Used in loops
  1593. float oo_intmax = 1.0f / (float)INT_MAX;
  1594. unsigned int ui_previous_key_time = 0;
  1595. unsigned int ui_current_key_time = 0;
  1596. /*
  1597. ** NOTE: Input rotations are in rotations per second. These will be converted to rotations per millisecond.
  1598. */
  1599. RotationRandom = new_props.Rand * 0.001f;
  1600. InitialOrientationRandom = orient_rnd;
  1601. // If both randomizers are effectively zero and rotation is constant zero, then all arrays are NULL.
  1602. static const float eps_orientation = 2.77777778e-4f; // Epsilon is equivalent to 0.1 degree
  1603. static const float eps_rotation = 2.77777778e-4f; // Epsilon is equivalent to one rotation per hour (in rotations / second)
  1604. bool orientation_rand_zero = fabs(orient_rnd) < eps_orientation;
  1605. bool rotation_rand_zero = fabs(new_props.Rand) < eps_rotation;
  1606. if (orientation_rand_zero && rotation_rand_zero && new_props.NumKeyFrames == 0 && fabs(new_props.Start) < eps_rotation) {
  1607. // Release Arrays,
  1608. REF_PTR_RELEASE(Orientation);
  1609. if (RotationKeyFrameTimes) {
  1610. delete [] RotationKeyFrameTimes;
  1611. RotationKeyFrameTimes = NULL;
  1612. }
  1613. if (HalfRotationKeyFrameDeltas) {
  1614. delete [] HalfRotationKeyFrameDeltas;
  1615. HalfRotationKeyFrameDeltas = NULL;
  1616. }
  1617. if (RotationKeyFrameValues) {
  1618. delete [] RotationKeyFrameValues;
  1619. RotationKeyFrameValues = NULL;
  1620. }
  1621. if (OrientationKeyFrameValues) {
  1622. delete [] OrientationKeyFrameValues;
  1623. OrientationKeyFrameValues = NULL;
  1624. }
  1625. NumRotationKeyFrames = 0;
  1626. NumRandomRotationEntriesMinus1 = 0;
  1627. NumRandomOrientationEntriesMinus1 = 0;
  1628. } else {
  1629. // Create the array if not present
  1630. if (!Orientation) {
  1631. Orientation = NEW_REF( ShareBufferClass<uint8> , (MaxNum) );
  1632. }
  1633. // Check times of the keyframes (each keytime must be larger than the
  1634. // previous one by at least a millisecond, and we stop at the first
  1635. // keytime of MaxAge or larger. (If all keyframes below MaxAge, the value is
  1636. // constant during the last segment between last keyframe and MaxAge).
  1637. ui_previous_key_time = 0;
  1638. for (unsigned int key = 0; key < new_props.NumKeyFrames; key++) {
  1639. ui_current_key_time = (unsigned int)(new_props.KeyTimes[key] * 1000.0f);
  1640. WWASSERT(ui_current_key_time > ui_previous_key_time);
  1641. if (ui_current_key_time >= MaxAge) break;
  1642. ui_previous_key_time = ui_current_key_time;
  1643. }
  1644. bool rotation_constant_at_end = (key == new_props.NumKeyFrames);
  1645. // Reuse RotationKeyFrameValues, RotationKeyFrameTimes, RotationKeyFrameDeltas and
  1646. // OrientationKeyFrameValues if the right size, otherwise release and reallocate.
  1647. unsigned int new_num_key_frames = key + 1;// Includes start keyframe (keytime == 0).
  1648. if (new_num_key_frames != NumRotationKeyFrames) {
  1649. if (RotationKeyFrameTimes) {
  1650. delete [] RotationKeyFrameTimes;
  1651. RotationKeyFrameTimes = NULL;
  1652. }
  1653. if (RotationKeyFrameValues) {
  1654. delete [] RotationKeyFrameValues;
  1655. RotationKeyFrameValues = NULL;
  1656. }
  1657. if (HalfRotationKeyFrameDeltas) {
  1658. delete [] HalfRotationKeyFrameDeltas;
  1659. HalfRotationKeyFrameDeltas = NULL;
  1660. }
  1661. if (OrientationKeyFrameValues) {
  1662. delete [] OrientationKeyFrameValues;
  1663. OrientationKeyFrameValues = NULL;
  1664. }
  1665. NumRotationKeyFrames = new_num_key_frames;
  1666. RotationKeyFrameTimes = new unsigned int [NumRotationKeyFrames];
  1667. RotationKeyFrameValues = new float [NumRotationKeyFrames];
  1668. HalfRotationKeyFrameDeltas = new float [NumRotationKeyFrames];
  1669. OrientationKeyFrameValues = new float [NumRotationKeyFrames];
  1670. }
  1671. // Set rotation keyframes (deltas will be set later)
  1672. RotationKeyFrameTimes[0] = 0;
  1673. RotationKeyFrameValues[0] = new_props.Start * 0.001f;
  1674. for (i = 1; i < NumRotationKeyFrames; i++) {
  1675. unsigned int im1 = i - 1;
  1676. RotationKeyFrameTimes[i] = (unsigned int)(new_props.KeyTimes[im1] * 1000.0f);
  1677. RotationKeyFrameValues[i] = new_props.Values[im1] * 0.001f;
  1678. }
  1679. // Do deltas for all rotation keyframes except last
  1680. for (i = 0; i < NumRotationKeyFrames - 1; i++) {
  1681. HalfRotationKeyFrameDeltas[i] = 0.5f * ( (RotationKeyFrameValues[i + 1] - RotationKeyFrameValues[i]) /
  1682. (float)(RotationKeyFrameTimes[i + 1] - RotationKeyFrameTimes[i]) );
  1683. }
  1684. // Do delta for last rotation keyframe (i is NumRotationKeyFrames - 1)
  1685. if (rotation_constant_at_end) {
  1686. HalfRotationKeyFrameDeltas[i] = 0.0f;
  1687. } else {
  1688. // This is OK because if rotation_constant_at_end is false, NumRotationKeyFrames is equal or
  1689. // smaller than new_props.NumKeyFrames so new_props.Values[NumRotationKeyFrames - 1] and
  1690. // new_props.KeyTimes[NumRotationKeyFrames - 1] exist.
  1691. HalfRotationKeyFrameDeltas[i] = 0.5f * (new_props.Values[i] * 0.001f - RotationKeyFrameValues[i]) /
  1692. (new_props.KeyTimes[i] * 1000.0f - (float)RotationKeyFrameTimes[i]);
  1693. }
  1694. // Calculate orientation keyframes by integrating the rotation at each keyframe
  1695. OrientationKeyFrameValues[0] = 0.0f;
  1696. for (i = 1; i < NumRotationKeyFrames; i++) {
  1697. float delta_t = (float)(RotationKeyFrameTimes[i] - RotationKeyFrameTimes[i - 1]);
  1698. OrientationKeyFrameValues[i] = OrientationKeyFrameValues[i - 1] + delta_t *
  1699. (RotationKeyFrameValues[i - 1] + HalfRotationKeyFrameDeltas[i - 1] * delta_t);
  1700. }
  1701. // Set up rotation randomizer table
  1702. if (rotation_rand_zero) {
  1703. if (RandomRotationEntries) {
  1704. // Reuse RandomRotationEntries if the right size, otherwise release and reallocate.
  1705. if (NumRandomRotationEntriesMinus1 != 0) {
  1706. delete [] RandomRotationEntries;
  1707. RandomRotationEntries = new float [1];
  1708. }
  1709. } else {
  1710. RandomRotationEntries = new float [1];
  1711. }
  1712. NumRandomRotationEntriesMinus1 = 0;
  1713. RandomRotationEntries[0] = 0.0f;
  1714. } else {
  1715. // Default size of randomizer tables (tables for non-zero randomizers will be this size)
  1716. unsigned int pot_num = Find_POT(MaxNum);
  1717. unsigned int default_randomizer_entries = MIN(pot_num, MAX_RANDOM_ENTRIES);
  1718. if (RandomRotationEntries) {
  1719. // Reuse RandomRotationEntries if the right size, otherwise release and reallocate.
  1720. if (NumRandomRotationEntriesMinus1 != (default_randomizer_entries - 1)) {
  1721. delete [] RandomRotationEntries;
  1722. RandomRotationEntries = new float [default_randomizer_entries];
  1723. }
  1724. } else {
  1725. RandomRotationEntries = new float [default_randomizer_entries];
  1726. }
  1727. NumRandomRotationEntriesMinus1 = default_randomizer_entries - 1;
  1728. float scale = new_props.Rand * 0.001f * oo_intmax;
  1729. for (unsigned int j = 0; j <= NumRandomRotationEntriesMinus1; j++) {
  1730. RandomRotationEntries[j] = rand_gen * scale;
  1731. }
  1732. }
  1733. // Set up orientation randomizer table
  1734. if (orientation_rand_zero) {
  1735. if (RandomOrientationEntries) {
  1736. // Reuse RandomOrientationEntries if the right size, otherwise release and reallocate.
  1737. if (NumRandomOrientationEntriesMinus1 != 0) {
  1738. delete [] RandomOrientationEntries;
  1739. RandomOrientationEntries = new float [1];
  1740. }
  1741. } else {
  1742. RandomOrientationEntries = new float [1];
  1743. }
  1744. NumRandomOrientationEntriesMinus1 = 0;
  1745. RandomOrientationEntries[0] = 0.0f;
  1746. } else {
  1747. // Default size of randomizer tables (tables for non-zero randomizers will be this size)
  1748. unsigned int pot_num = Find_POT(MaxNum);
  1749. unsigned int default_randomizer_entries = MIN(pot_num, MAX_RANDOM_ENTRIES);
  1750. if (RandomOrientationEntries) {
  1751. // Reuse RandomOrientationEntries if the right size, otherwise release and reallocate.
  1752. if (NumRandomOrientationEntriesMinus1 != (default_randomizer_entries - 1)) {
  1753. delete [] RandomOrientationEntries;
  1754. RandomOrientationEntries = new float [default_randomizer_entries];
  1755. }
  1756. } else {
  1757. RandomOrientationEntries = new float [default_randomizer_entries];
  1758. }
  1759. NumRandomOrientationEntriesMinus1 = default_randomizer_entries - 1;
  1760. float scale = orient_rnd * oo_intmax;
  1761. for (unsigned int j = 0; j <= NumRandomOrientationEntriesMinus1; j++) {
  1762. RandomOrientationEntries[j] = rand_gen * scale;
  1763. }
  1764. }
  1765. }
  1766. }
  1767. void ParticleBufferClass::Reset_Frames(ParticlePropertyStruct<float> &new_props)
  1768. {
  1769. unsigned int i; // Used in loops
  1770. float oo_intmax = 1.0f / (float)INT_MAX;
  1771. unsigned int ui_previous_key_time = 0;
  1772. unsigned int ui_current_key_time = 0;
  1773. FrameRandom = new_props.Rand;
  1774. // If the randomizer is effectively zero and there are no keyframes, then we just create a
  1775. // values array with one entry and store the starting value in it (the keyframes and random
  1776. // table will not be used in this case).
  1777. static const float eps_frame = 0.1f; // Epsilon is equivalent to 0.1 frame
  1778. bool frame_rand_zero = (fabs(new_props.Rand) < eps_frame);
  1779. if (frame_rand_zero && new_props.NumKeyFrames == 0) {
  1780. // Release Arrays, Reuse KeyFrameValues if the right size,
  1781. // otherwise release and reallocate.
  1782. REF_PTR_RELEASE(Frame);
  1783. REF_PTR_RELEASE(UCoord);
  1784. if (FrameKeyFrameTimes) {
  1785. delete [] FrameKeyFrameTimes;
  1786. FrameKeyFrameTimes = NULL;
  1787. }
  1788. if (FrameKeyFrameDeltas) {
  1789. delete [] FrameKeyFrameDeltas;
  1790. FrameKeyFrameDeltas = NULL;
  1791. }
  1792. if (FrameKeyFrameValues) {
  1793. if (NumFrameKeyFrames > 1) {
  1794. delete [] FrameKeyFrameValues;
  1795. FrameKeyFrameValues = new float [1];
  1796. }
  1797. } else {
  1798. FrameKeyFrameValues = new float [1];
  1799. }
  1800. NumFrameKeyFrames = 0;
  1801. NumRandomFrameEntriesMinus1 = 0;
  1802. FrameKeyFrameValues[0] = new_props.Start;
  1803. } else {
  1804. // Create the array if not present
  1805. if ((RenderMode==W3D_EMITTER_RENDER_MODE_LINEGRP_TETRA) ||
  1806. (RenderMode==W3D_EMITTER_RENDER_MODE_LINEGRP_PRISM)) {
  1807. if (!UCoord) {
  1808. UCoord = NEW_REF( ShareBufferClass<float>, (MaxNum) );
  1809. }
  1810. } else {
  1811. if (!Frame) {
  1812. Frame = NEW_REF( ShareBufferClass<uint8> , (MaxNum) );
  1813. }
  1814. }
  1815. // Check times of the keyframes (each keytime must be larger than the
  1816. // previous one by at least a millisecond, and we stop at the first
  1817. // keytime of MaxAge or larger. (If all keyframes below MaxAge, the value is
  1818. // constant during the last segment between last keyframe and MaxAge).
  1819. ui_previous_key_time = 0;
  1820. for (unsigned int key = 0; key < new_props.NumKeyFrames; key++) {
  1821. ui_current_key_time = (unsigned int)(new_props.KeyTimes[key] * 1000.0f);
  1822. WWASSERT(ui_current_key_time > ui_previous_key_time);
  1823. if (ui_current_key_time >= MaxAge) break;
  1824. ui_previous_key_time = ui_current_key_time;
  1825. }
  1826. bool frame_constant_at_end = (key == new_props.NumKeyFrames);
  1827. // Reuse FrameKeyFrameValues, FrameKeyFrameTimes and FrameKeyFrameDeltas if the right size,
  1828. // otherwise release and reallocate.
  1829. unsigned int new_num_key_frames = key + 1;// Includes start keyframe (keytime == 0).
  1830. if (new_num_key_frames != NumFrameKeyFrames) {
  1831. if (FrameKeyFrameTimes) {
  1832. delete [] FrameKeyFrameTimes;
  1833. FrameKeyFrameTimes = NULL;
  1834. }
  1835. if (FrameKeyFrameValues) {
  1836. delete [] FrameKeyFrameValues;
  1837. FrameKeyFrameValues = NULL;
  1838. }
  1839. if (FrameKeyFrameDeltas) {
  1840. delete [] FrameKeyFrameDeltas;
  1841. FrameKeyFrameDeltas = NULL;
  1842. }
  1843. NumFrameKeyFrames = new_num_key_frames;
  1844. FrameKeyFrameTimes = new unsigned int [NumFrameKeyFrames];
  1845. FrameKeyFrameValues = new float [NumFrameKeyFrames];
  1846. FrameKeyFrameDeltas = new float [NumFrameKeyFrames];
  1847. }
  1848. // Set keyframes (deltas will be set later)
  1849. FrameKeyFrameTimes[0] = 0;
  1850. FrameKeyFrameValues[0] = new_props.Start;
  1851. for (i = 1; i < NumFrameKeyFrames; i++) {
  1852. unsigned int im1 = i - 1;
  1853. FrameKeyFrameTimes[i] = (unsigned int)(new_props.KeyTimes[im1] * 1000.0f);
  1854. FrameKeyFrameValues[i] = new_props.Values[im1];
  1855. }
  1856. // Do deltas for all frame keyframes except last
  1857. for (i = 0; i < NumFrameKeyFrames - 1; i++) {
  1858. FrameKeyFrameDeltas[i] = (FrameKeyFrameValues[i + 1] - FrameKeyFrameValues[i]) /
  1859. (float)(FrameKeyFrameTimes[i + 1] - FrameKeyFrameTimes[i]);
  1860. }
  1861. // Do delta for last frame keyframe (i is NumFrameKeyFrames - 1)
  1862. if (frame_constant_at_end) {
  1863. FrameKeyFrameDeltas[i] = 0.0f;
  1864. } else {
  1865. // This is OK because if frame_constant_at_end is false, NumFrameKeyFrames is equal or
  1866. // smaller than new_props.NumKeyFrames so new_props.Values[NumFrameKeyFrames - 1] and
  1867. // new_props.KeyTimes[NumFrameKeyFrames - 1] exist.
  1868. FrameKeyFrameDeltas[i] = (new_props.Values[i] - FrameKeyFrameValues[i]) /
  1869. (new_props.KeyTimes[i] * 1000.0f - (float)FrameKeyFrameTimes[i]);
  1870. }
  1871. // Set up frame randomizer table
  1872. if (frame_rand_zero) {
  1873. if (RandomFrameEntries) {
  1874. // Reuse RandomFrameEntries if the right size, otherwise release and reallocate.
  1875. if (NumRandomFrameEntriesMinus1 != 0) {
  1876. delete [] RandomFrameEntries;
  1877. RandomFrameEntries = new float [1];
  1878. }
  1879. } else {
  1880. RandomFrameEntries = new float [1];
  1881. }
  1882. NumRandomFrameEntriesMinus1 = 0;
  1883. RandomFrameEntries[0] = 0.0f;
  1884. } else {
  1885. // Default size of randomizer tables (tables for non-zero randomizers will be this size)
  1886. unsigned int pot_num = Find_POT(MaxNum);
  1887. unsigned int default_randomizer_entries = MIN(pot_num, MAX_RANDOM_ENTRIES);
  1888. if (RandomFrameEntries) {
  1889. // Reuse RandomFrameEntries if the right size, otherwise release and reallocate.
  1890. if (NumRandomFrameEntriesMinus1 != (default_randomizer_entries - 1)) {
  1891. delete [] RandomFrameEntries;
  1892. RandomFrameEntries = new float [default_randomizer_entries];
  1893. }
  1894. } else {
  1895. RandomFrameEntries = new float [default_randomizer_entries];
  1896. }
  1897. NumRandomFrameEntriesMinus1 = default_randomizer_entries - 1;
  1898. float scale = new_props.Rand * oo_intmax;
  1899. for (unsigned int j = 0; j <= NumRandomFrameEntriesMinus1; j++) {
  1900. RandomFrameEntries[j] = rand_gen * scale;
  1901. }
  1902. }
  1903. }
  1904. }
  1905. void ParticleBufferClass::Reset_Blur_Times(ParticlePropertyStruct<float> &new_blur_times)
  1906. {
  1907. unsigned int i; // Used in loops
  1908. float oo_intmax = 1.0f / (float)INT_MAX;
  1909. unsigned int ui_previous_key_time = 0;
  1910. unsigned int ui_current_key_time = 0;
  1911. BlurTimeRandom = new_blur_times.Rand;
  1912. // If the randomizer is effectively zero and there are no keyframes, then we just create a
  1913. // values array with one entry and store the starting value in it (the keyframes and random
  1914. // table will not be used in this case).
  1915. static const float eps_blur = 1e-5f; // Epsilon is equivalent to 1e-5 units per second
  1916. bool blurtime_rand_zero = (fabs(new_blur_times.Rand) < eps_blur);
  1917. if (blurtime_rand_zero && new_blur_times.NumKeyFrames == 0) {
  1918. // Release Arrays, Reuse KeyFrameValues if the right size,
  1919. // otherwise release and reallocate.
  1920. if (BlurTimeKeyFrameTimes) {
  1921. delete [] BlurTimeKeyFrameTimes;
  1922. BlurTimeKeyFrameTimes = NULL;
  1923. }
  1924. if (BlurTimeKeyFrameDeltas) {
  1925. delete [] BlurTimeKeyFrameDeltas;
  1926. BlurTimeKeyFrameDeltas = NULL;
  1927. }
  1928. if (BlurTimeKeyFrameValues) {
  1929. if (NumBlurTimeKeyFrames > 1) {
  1930. delete [] BlurTimeKeyFrameValues;
  1931. BlurTimeKeyFrameValues = new float [1];
  1932. }
  1933. } else {
  1934. BlurTimeKeyFrameValues = new float [1];
  1935. }
  1936. NumBlurTimeKeyFrames = 0;
  1937. NumRandomBlurTimeEntriesMinus1 = 0;
  1938. BlurTimeKeyFrameValues[0] = new_blur_times.Start;
  1939. } else {
  1940. // Check times of the keyframes (each keytime must be larger than the
  1941. // previous one by at least a millisecond, and we stop at the first
  1942. // keytime of MaxAge or larger. (If all keyframes below MaxAge, the value is
  1943. // constant during the last segment between last keyframe and MaxAge).
  1944. ui_previous_key_time = 0;
  1945. for (unsigned int key = 0; key < new_blur_times.NumKeyFrames; key++) {
  1946. ui_current_key_time = (unsigned int)(new_blur_times.KeyTimes[key] * 1000.0f);
  1947. WWASSERT(ui_current_key_time > ui_previous_key_time);
  1948. if (ui_current_key_time >= MaxAge) break;
  1949. ui_previous_key_time = ui_current_key_time;
  1950. }
  1951. bool blurtime_constant_at_end = (key == new_blur_times.NumKeyFrames);
  1952. // Reuse BlurTimeKeyFrameValues, BlurTimeKeyFrameTimes and BlurTimeKeyFrameDeltas if the right size,
  1953. // otherwise release and reallocate.
  1954. unsigned int new_num_key_frames = key + 1;// Includes start keyframe (keytime == 0).
  1955. if (new_num_key_frames != NumBlurTimeKeyFrames) {
  1956. if (BlurTimeKeyFrameTimes) {
  1957. delete [] BlurTimeKeyFrameTimes;
  1958. BlurTimeKeyFrameTimes = NULL;
  1959. }
  1960. if (BlurTimeKeyFrameValues) {
  1961. delete [] BlurTimeKeyFrameValues;
  1962. BlurTimeKeyFrameValues = NULL;
  1963. }
  1964. if (BlurTimeKeyFrameDeltas) {
  1965. delete [] BlurTimeKeyFrameDeltas;
  1966. BlurTimeKeyFrameDeltas = NULL;
  1967. }
  1968. NumBlurTimeKeyFrames = new_num_key_frames;
  1969. BlurTimeKeyFrameTimes = new unsigned int [NumBlurTimeKeyFrames];
  1970. BlurTimeKeyFrameValues = new float [NumBlurTimeKeyFrames];
  1971. BlurTimeKeyFrameDeltas = new float [NumBlurTimeKeyFrames];
  1972. }
  1973. // Set keyframes (deltas will be set later)
  1974. BlurTimeKeyFrameTimes[0] = 0;
  1975. BlurTimeKeyFrameValues[0] = new_blur_times.Start;
  1976. for (i = 1; i < NumBlurTimeKeyFrames; i++) {
  1977. unsigned int im1 = i - 1;
  1978. BlurTimeKeyFrameTimes[i] = (unsigned int)(new_blur_times.KeyTimes[im1] * 1000.0f);
  1979. BlurTimeKeyFrameValues[i] = new_blur_times.Values[im1];
  1980. }
  1981. // Do deltas for all frame keyframes except last
  1982. for (i = 0; i < NumBlurTimeKeyFrames - 1; i++) {
  1983. BlurTimeKeyFrameDeltas[i] = (BlurTimeKeyFrameValues[i + 1] - BlurTimeKeyFrameValues[i]) /
  1984. (float)(BlurTimeKeyFrameTimes[i + 1] - BlurTimeKeyFrameTimes[i]);
  1985. }
  1986. // Do delta for last frame keyframe (i is NumBlurTimeKeyFrames - 1)
  1987. if (blurtime_constant_at_end) {
  1988. BlurTimeKeyFrameDeltas[i] = 0.0f;
  1989. } else {
  1990. // This is OK because if frame_constant_at_end is false, NumBlurTimeKeyFrames is equal or
  1991. // smaller than new_props.NumKeyFrames so new_props.Values[NumBlurTimeKeyFrames - 1] and
  1992. // new_props.KeyTimes[NumBlurTimeKeyFrames - 1] exist.
  1993. BlurTimeKeyFrameDeltas[i] = (new_blur_times.Values[i] - BlurTimeKeyFrameValues[i]) /
  1994. (new_blur_times.KeyTimes[i] * 1000.0f - (float)BlurTimeKeyFrameTimes[i]);
  1995. }
  1996. // Set up frame randomizer table
  1997. if (blurtime_rand_zero) {
  1998. if (RandomBlurTimeEntries) {
  1999. // Reuse RandomBlurTimeEntries if the right size, otherwise release and reallocate.
  2000. if (NumRandomBlurTimeEntriesMinus1 != 0) {
  2001. delete [] RandomBlurTimeEntries;
  2002. RandomBlurTimeEntries = new float [1];
  2003. }
  2004. } else {
  2005. RandomBlurTimeEntries = new float [1];
  2006. }
  2007. NumRandomBlurTimeEntriesMinus1 = 0;
  2008. RandomBlurTimeEntries[0] = 0.0f;
  2009. } else {
  2010. // Default size of randomizer tables (tables for non-zero randomizers will be this size)
  2011. unsigned int pot_num = Find_POT(MaxNum);
  2012. unsigned int default_randomizer_entries = MIN(pot_num, MAX_RANDOM_ENTRIES);
  2013. if (RandomBlurTimeEntries) {
  2014. // Reuse RandomBlurTimeEntries if the right size, otherwise release and reallocate.
  2015. if (NumRandomBlurTimeEntriesMinus1 != (default_randomizer_entries - 1)) {
  2016. delete [] RandomBlurTimeEntries;
  2017. RandomBlurTimeEntries = new float [default_randomizer_entries];
  2018. }
  2019. } else {
  2020. RandomBlurTimeEntries = new float [default_randomizer_entries];
  2021. }
  2022. NumRandomBlurTimeEntriesMinus1 = default_randomizer_entries - 1;
  2023. float scale = new_blur_times.Rand * oo_intmax;
  2024. for (unsigned int j = 0; j <= NumRandomBlurTimeEntriesMinus1; j++) {
  2025. RandomBlurTimeEntries[j] = rand_gen * scale;
  2026. }
  2027. }
  2028. }
  2029. }
  2030. // This informs the buffer that the emitter is dead, so it can release
  2031. // its pointer to it and be removed itself after all its particles dies
  2032. // out.
  2033. void ParticleBufferClass::Emitter_Is_Dead(void)
  2034. {
  2035. IsEmitterDead = true;
  2036. // We do not have a ref for the emitter (see DTor for detailed explanation)
  2037. // Emitter->Release_Ref();
  2038. Emitter = NULL;
  2039. }
  2040. // This set's the buffer's current emitter - this should usually be
  2041. // called only by the emitter's copy constructor after it clones a
  2042. // buffer.
  2043. void ParticleBufferClass::Set_Emitter(ParticleEmitterClass *emitter)
  2044. {
  2045. if (Emitter) {
  2046. // We do not have a ref for the emitter (see DTor for detailed explanation)
  2047. // Emitter->Release_Ref();
  2048. Emitter = NULL;
  2049. }
  2050. Emitter = emitter;
  2051. if (Emitter) {
  2052. // We do not add a ref for the emitter (see DTor for detailed explanation)
  2053. // Emitter->Add_Ref();
  2054. }
  2055. }
  2056. NewParticleStruct * ParticleBufferClass::Add_Uninitialized_New_Particle(void)
  2057. {
  2058. // Note that this function does not initialize the new particle - it
  2059. // returns its address to a different function which performs the actual
  2060. // initialization.
  2061. // Push new particle on new particle queue. If it overflows, just adjust
  2062. // queue to remove oldest member (which is the one which was overwritten).
  2063. NewParticleStruct *ptr = &(NewParticleQueue[NewParticleQueueEnd]);
  2064. if (++NewParticleQueueEnd == MaxNum) NewParticleQueueEnd = 0;
  2065. if (++NewParticleQueueCount == (signed)(MaxNum + 1)) {
  2066. // Overflow - advance queue start:
  2067. if (++NewParticleQueueStart == MaxNum) NewParticleQueueStart = 0;
  2068. NewParticleQueueCount--;
  2069. }
  2070. return ptr;
  2071. }
  2072. void ParticleBufferClass::Update_Cached_Bounding_Volumes(void) const
  2073. {
  2074. // This ugly cast is done because the alternative is to make everything
  2075. // in the class mutable, which does not seem like a good solution
  2076. // (Update_Bounding_Box can potentially update the particle state).
  2077. ((ParticleBufferClass *)this)->Update_Bounding_Box();
  2078. // Update cached bounding box and sphere according to the bounding box:
  2079. CachedBoundingSphere.Init(BoundingBox.Center, BoundingBox.Extent.Length());
  2080. CachedBoundingBox = BoundingBox;
  2081. Validate_Cached_Bounding_Volumes();
  2082. }
  2083. void ParticleBufferClass::Update_Kinematic_Particle_State(void)
  2084. {
  2085. // Note: elapsed may be very large indeed the first time the object is
  2086. // updated, but this doesn't matter, since it is actually only used in
  2087. // Update_Non_New_Particles(), which is never called on the first update.
  2088. unsigned int elapsed = WW3D::Get_Sync_Time() - LastUpdateTime;
  2089. if (elapsed == 0U) return;
  2090. // Get new particles from the input buffer and write them into the circular
  2091. // particle buffer, possibly overwriting older particles. Update each
  2092. // according to its age.
  2093. Get_New_Particles();
  2094. // Kill all remaining particles which will pass their max age this update.
  2095. Kill_Old_Particles();
  2096. // Update all living, non-new particles by a uniform time interval.
  2097. if (NonNewNum > 0) Update_Non_New_Particles(elapsed);
  2098. // Mark all new particles as non-new.
  2099. End = NewEnd;
  2100. NonNewNum += NewNum;
  2101. NewNum = 0;
  2102. LastUpdateTime = WW3D::Get_Sync_Time();
  2103. BoundingBoxDirty = true;
  2104. }
  2105. void ParticleBufferClass::Update_Visual_Particle_State(void)
  2106. {
  2107. // NOTE: The visual state (color/alpha/size) is "stateless" in that each time it is calculated
  2108. // without referring to what it was before. This is important for when we optimize the particle
  2109. // systems/pointgroups in the future to chunk triangles into reusable small buffers.
  2110. // If all visual state is constant do nothing.
  2111. // Linegroup modes have a visual state that always have to be updated though
  2112. bool is_linegroup=( (RenderMode==W3D_EMITTER_RENDER_MODE_LINEGRP_TETRA) ||
  2113. (RenderMode==W3D_EMITTER_RENDER_MODE_LINEGRP_PRISM));
  2114. if (!Color && !Alpha && !Size && !Orientation && !Frame && !UCoord && !is_linegroup) return;
  2115. // In the general case, a range in a circular buffer can be composed of up
  2116. // to two subranges. Find the Start - End subranges.
  2117. unsigned int sub1_end; // End of subrange 1.
  2118. unsigned int sub2_start; // Start of subrange 2.
  2119. if ((Start < End) || ((Start == End) && NonNewNum ==0)) {
  2120. sub1_end = End;
  2121. sub2_start = End;
  2122. } else {
  2123. sub1_end = MaxNum;
  2124. sub2_start = 0;
  2125. }
  2126. unsigned int current_time = WW3D::Get_Sync_Time();
  2127. // The following back-to-back pair of "for" loops traverses the circular
  2128. // buffer subranges in proper order.
  2129. unsigned int ckey = NumColorKeyFrames - 1;
  2130. unsigned int akey = NumAlphaKeyFrames - 1;
  2131. unsigned int skey = NumSizeKeyFrames - 1;
  2132. unsigned int rkey = NumRotationKeyFrames - 1;
  2133. unsigned int fkey = NumFrameKeyFrames - 1;
  2134. unsigned int bkey = NumBlurTimeKeyFrames -1;
  2135. unsigned int part;
  2136. Vector3 *color = Color ? Color->Get_Array(): NULL;
  2137. float *alpha = Alpha ? Alpha->Get_Array(): NULL;
  2138. float *size = Size ? Size->Get_Array(): NULL;
  2139. uint8 *orientation = Orientation ? Orientation->Get_Array(): NULL;
  2140. uint8 *frame = Frame ? Frame->Get_Array(): NULL;
  2141. float *ucoord = UCoord ? UCoord->Get_Array() : NULL;
  2142. Vector3 *tailposition = TailPosition ? TailPosition->Get_Array() : NULL;
  2143. Vector3 *position=NULL;
  2144. if (PingPongPosition) {
  2145. int pingpong = WW3D::Get_Frame_Count() & 0x1;
  2146. position = Position[pingpong]->Get_Array();
  2147. } else {
  2148. position = Position[0]->Get_Array();
  2149. }
  2150. for (part = Start; part < sub1_end; part++) {
  2151. unsigned int part_age = current_time - TimeStamp[part];
  2152. // Ensure the current color keyframe is correct, and calculate color state
  2153. if (color) {
  2154. // We go from older to younger particles, so we go backwards from the last keyframe until
  2155. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2156. for (; part_age < ColorKeyFrameTimes[ckey]; ckey--);
  2157. color[part] = ColorKeyFrameValues[ckey] +
  2158. ColorKeyFrameDeltas[ckey] * (float)(part_age - ColorKeyFrameTimes[ckey]) +
  2159. RandomColorEntries[part & NumRandomColorEntriesMinus1];
  2160. }
  2161. // Ensure the current alpha keyframe is correct, and calculate alpha state
  2162. if (alpha) {
  2163. // We go from older to younger particles, so we go backwards from the last keyframe until
  2164. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2165. for (; part_age < AlphaKeyFrameTimes[akey]; akey--);
  2166. alpha[part] = AlphaKeyFrameValues[akey] +
  2167. AlphaKeyFrameDeltas[akey] * (float)(part_age - AlphaKeyFrameTimes[akey]) +
  2168. RandomAlphaEntries[part & NumRandomAlphaEntriesMinus1];
  2169. }
  2170. // Ensure the current size keyframe is correct, and calculate size state
  2171. if (size) {
  2172. // We go from older to younger particles, so we go backwards from the last keyframe until
  2173. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2174. for (; part_age < SizeKeyFrameTimes[skey]; skey--);
  2175. size[part] = SizeKeyFrameValues[skey] +
  2176. SizeKeyFrameDeltas[skey] * (float)(part_age - SizeKeyFrameTimes[skey]) +
  2177. RandomSizeEntries[part & NumRandomSizeEntriesMinus1];
  2178. // Size (unlike color and alpha) isn't clamped in the engine, so we need to clamp
  2179. // negative values to zero here:
  2180. size[part] = (size[part] >= 0.0f) ? size[part] : 0.0f;
  2181. }
  2182. // Ensure the current rotation keyframe is correct, and calculate orientation state
  2183. if (orientation) {
  2184. // We go from older to younger particles, so we go backwards from the last keyframe until
  2185. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2186. for (; part_age < RotationKeyFrameTimes[rkey]; rkey--);
  2187. float f_delta_t = (float)(part_age - RotationKeyFrameTimes[rkey]);
  2188. float tmp_orient = OrientationKeyFrameValues[rkey] +
  2189. (RotationKeyFrameValues[rkey] + HalfRotationKeyFrameDeltas[rkey] * f_delta_t) * f_delta_t +
  2190. RandomRotationEntries[part & NumRandomRotationEntriesMinus1] * (float)part_age +
  2191. RandomOrientationEntries[part & NumRandomOrientationEntriesMinus1];
  2192. orientation[part] = (uint)(((int)(tmp_orient * 256.0f)) & 0xFF);
  2193. }
  2194. // Ensure the current frame keyframe is correct, and calculate frame state
  2195. if (frame) {
  2196. // Frame and ucoord are mutually exclusive
  2197. WWASSERT(ucoord==NULL);
  2198. // We go from older to younger particles, so we go backwards from the last keyframe until
  2199. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2200. for (; part_age < FrameKeyFrameTimes[fkey]; fkey--);
  2201. float tmp_frame = FrameKeyFrameValues[fkey] +
  2202. FrameKeyFrameDeltas[fkey] * (float)(part_age - FrameKeyFrameTimes[fkey]) +
  2203. RandomFrameEntries[part & NumRandomFrameEntriesMinus1];
  2204. frame[part] = (uint)(((int)(tmp_frame)) & 0xFF);
  2205. }
  2206. // Ensure the current frame keyframe is correct, and calculate frame state
  2207. // ucoord is the same as frame but in float
  2208. if (ucoord) {
  2209. // Frame and ucoord are mutually exclusive
  2210. WWASSERT(frame==NULL);
  2211. // We go from older to younger particles, so we go backwards from the last keyframe until
  2212. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2213. for (; part_age < FrameKeyFrameTimes[fkey]; fkey--);
  2214. ucoord[part] = FrameKeyFrameValues[fkey] +
  2215. FrameKeyFrameDeltas[fkey] * (float)(part_age - FrameKeyFrameTimes[fkey]) +
  2216. RandomFrameEntries[part & NumRandomFrameEntriesMinus1];
  2217. }
  2218. if (tailposition) {
  2219. // We go from older to younger particles, so we go backwards from the last keyframe until
  2220. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2221. float blur_time = BlurTimeKeyFrameValues[0];
  2222. if (BlurTimeKeyFrameTimes) {
  2223. for (; part_age < BlurTimeKeyFrameTimes[bkey]; bkey--);
  2224. blur_time = BlurTimeKeyFrameValues[bkey] +
  2225. BlurTimeKeyFrameDeltas[bkey] * (float)(part_age - BlurTimeKeyFrameTimes[bkey]) +
  2226. RandomBlurTimeEntries[part & NumRandomBlurTimeEntriesMinus1];
  2227. }
  2228. tailposition[part]=position[part]-Velocity[part]*blur_time*1000;
  2229. }
  2230. }
  2231. for (part = sub2_start; part < End; part++) {
  2232. unsigned int part_age = current_time - TimeStamp[part];
  2233. // Ensure the current color keyframe is correct, and calculate color state
  2234. if (color) {
  2235. // We go from older to younger particles, so we go backwards from the last keyframe until
  2236. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2237. for (; part_age < ColorKeyFrameTimes[ckey]; ckey--);
  2238. color[part] =
  2239. ColorKeyFrameValues[ckey] +
  2240. ColorKeyFrameDeltas[ckey] * (float)(part_age - ColorKeyFrameTimes[ckey]) +
  2241. RandomColorEntries[part & NumRandomColorEntriesMinus1];
  2242. }
  2243. // Ensure the current alpha keyframe is correct, and calculate alpha state
  2244. if (alpha) {
  2245. // We go from older to younger particles, so we go backwards from the last keyframe until
  2246. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2247. for (; part_age < AlphaKeyFrameTimes[akey]; akey--);
  2248. alpha[part] = AlphaKeyFrameValues[akey] +
  2249. AlphaKeyFrameDeltas[akey] * (float)(part_age - AlphaKeyFrameTimes[akey]) +
  2250. RandomAlphaEntries[part & NumRandomAlphaEntriesMinus1];
  2251. }
  2252. // Ensure the current size keyframe is correct, and calculate size state
  2253. if (size) {
  2254. // We go from older to younger particles, so we go backwards from the last keyframe until
  2255. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2256. for (; part_age < SizeKeyFrameTimes[skey]; skey--);
  2257. size[part] = SizeKeyFrameValues[skey] +
  2258. SizeKeyFrameDeltas[skey] * (float)(part_age - SizeKeyFrameTimes[skey]) +
  2259. RandomSizeEntries[part & NumRandomSizeEntriesMinus1];
  2260. // Size (unlike color) isn't clamped in the engine, so we need to
  2261. // clamp negative values to zero here:
  2262. size[part] = (size[part] >= 0.0f) ? size[part] : 0.0f;
  2263. }
  2264. // Ensure the current rotation keyframe is correct, and calculate orientation state
  2265. if (orientation) {
  2266. // We go from older to younger particles, so we go backwards from the last keyframe until
  2267. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2268. for (; part_age < RotationKeyFrameTimes[rkey]; rkey--);
  2269. float f_delta_t = (float)(part_age - RotationKeyFrameTimes[rkey]);
  2270. float tmp_orient = OrientationKeyFrameValues[rkey] +
  2271. (RotationKeyFrameValues[rkey] + HalfRotationKeyFrameDeltas[rkey] * f_delta_t) * f_delta_t +
  2272. RandomRotationEntries[part & NumRandomRotationEntriesMinus1] * (float)part_age +
  2273. RandomOrientationEntries[part & NumRandomOrientationEntriesMinus1];
  2274. orientation[part] = (uint)(((int)(tmp_orient * 256.0f)) & 0xFF);
  2275. }
  2276. // Ensure the current frame keyframe is correct, and calculate frame state
  2277. if (frame) {
  2278. // Frame and ucoord are mutually exclusive
  2279. WWASSERT(ucoord==NULL);
  2280. // We go from older to younger particles, so we go backwards from the last keyframe until
  2281. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2282. for (; part_age < FrameKeyFrameTimes[fkey]; fkey--);
  2283. float tmp_frame = FrameKeyFrameValues[fkey] +
  2284. FrameKeyFrameDeltas[fkey] * (float)(part_age - FrameKeyFrameTimes[fkey]) +
  2285. RandomFrameEntries[part & NumRandomFrameEntriesMinus1];
  2286. frame[part] = (uint)(((int)(tmp_frame)) & 0xFF);
  2287. }
  2288. // Ensure the current frame keyframe is correct, and calculate frame state
  2289. // ucoord is the same as frame but in float
  2290. if (ucoord) {
  2291. // Frame and ucoord are mutually exclusive
  2292. WWASSERT(frame==NULL);
  2293. // We go from older to younger particles, so we go backwards from the last keyframe until
  2294. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2295. for (; part_age < FrameKeyFrameTimes[fkey]; fkey--);
  2296. ucoord[part] = FrameKeyFrameValues[fkey] +
  2297. FrameKeyFrameDeltas[fkey] * (float)(part_age - FrameKeyFrameTimes[fkey]) +
  2298. RandomFrameEntries[part & NumRandomFrameEntriesMinus1];
  2299. }
  2300. if (tailposition) {
  2301. // We go from older to younger particles, so we go backwards from the last keyframe until
  2302. // age >= keytime. This loop must terminate because the 0th keytime is 0.
  2303. float blur_time = BlurTimeKeyFrameValues[0];
  2304. if (BlurTimeKeyFrameTimes) {
  2305. for (; part_age < BlurTimeKeyFrameTimes[bkey]; bkey--);
  2306. blur_time = BlurTimeKeyFrameValues[bkey] +
  2307. BlurTimeKeyFrameDeltas[bkey] * (float)(part_age - BlurTimeKeyFrameTimes[bkey]) +
  2308. RandomBlurTimeEntries[part & NumRandomBlurTimeEntriesMinus1];
  2309. }
  2310. tailposition[part]=position[part]-Velocity[part]*blur_time*1000;
  2311. }
  2312. }
  2313. }
  2314. void ParticleBufferClass::Update_Bounding_Box(void)
  2315. {
  2316. // Ensure all particle positions are updated. If bounding box still not
  2317. // dirty, return.
  2318. Update_Kinematic_Particle_State();
  2319. if (!BoundingBoxDirty) return;
  2320. // If there are no particles, generate a dummy bounding box:
  2321. if (NonNewNum == 0U) {
  2322. BoundingBox.Init(Vector3(0.0, 0.0, 0.0), Vector3(0.0, 0.0, 0.0));
  2323. BoundingBoxDirty = false;
  2324. return;
  2325. }
  2326. // Find min/max coord values for all points:
  2327. int pingpong = 0;
  2328. if (PingPongPosition) {
  2329. pingpong = WW3D::Get_Frame_Count() & 0x1;
  2330. }
  2331. Vector3 *position = Position[pingpong]->Get_Array();
  2332. Vector3 max_coords = position[Start];
  2333. Vector3 min_coords = position[Start];
  2334. // In the general case, a range in a circular buffer can be composed of up
  2335. // to two subranges. Find the Start - End subranges.
  2336. unsigned int sub1_end; // End of subrange 1.
  2337. unsigned int sub2_start; // Start of subrange 2.
  2338. unsigned int i; // Loop index.
  2339. if ((Start < End) || ((Start == End) && NonNewNum ==0)) {
  2340. sub1_end = End;
  2341. sub2_start = End;
  2342. } else {
  2343. sub1_end = MaxNum;
  2344. sub2_start = 0;
  2345. }
  2346. for (i = Start; i < sub1_end; i++) {
  2347. max_coords.X = max_coords.X >= position[i].X ? max_coords.X : position[i].X;
  2348. max_coords.Y = max_coords.Y >= position[i].Y ? max_coords.Y : position[i].Y;
  2349. max_coords.Z = max_coords.Z >= position[i].Z ? max_coords.Z : position[i].Z;
  2350. min_coords.X = min_coords.X <= position[i].X ? min_coords.X : position[i].X;
  2351. min_coords.Y = min_coords.Y <= position[i].Y ? min_coords.Y : position[i].Y;
  2352. min_coords.Z = min_coords.Z <= position[i].Z ? min_coords.Z : position[i].Z;
  2353. }
  2354. for (i = sub2_start; i < End; i++) {
  2355. max_coords.X = max_coords.X >= position[i].X ? max_coords.X : position[i].X;
  2356. max_coords.Y = max_coords.Y >= position[i].Y ? max_coords.Y : position[i].Y;
  2357. max_coords.Z = max_coords.Z >= position[i].Z ? max_coords.Z : position[i].Z;
  2358. min_coords.X = min_coords.X <= position[i].X ? min_coords.X : position[i].X;
  2359. min_coords.Y = min_coords.Y <= position[i].Y ? min_coords.Y : position[i].Y;
  2360. min_coords.Z = min_coords.Z <= position[i].Z ? min_coords.Z : position[i].Z;
  2361. }
  2362. // Extend by maximum possible particle size:
  2363. Vector3 size(MaxSize, MaxSize, MaxSize);
  2364. max_coords += size;
  2365. min_coords -= size;
  2366. // Update bounding box:
  2367. BoundingBox.Init(MinMaxAABoxClass(min_coords,max_coords));
  2368. BoundingBoxDirty = false;
  2369. }
  2370. // NOTE: typically, the number of new particles created in a frame is small
  2371. // relative to the total number of particles, so this is not the most
  2372. // performance-critical particle function. New particles are copied from the
  2373. // new particle vector into the circular buffer, overwriting any older
  2374. // particles (including possibly other new particles) so that the newest
  2375. // particles are preserved. The particles are initialized to their state at
  2376. // the end of the current interval.
  2377. void ParticleBufferClass::Get_New_Particles(void)
  2378. {
  2379. unsigned int current_time = WW3D::Get_Sync_Time();
  2380. // position is the current frame position, prev_pos is the previous frames position (only if
  2381. // we have enabled pingpong position buffers)
  2382. Vector3 *position;
  2383. Vector3 *prev_pos;
  2384. if (PingPongPosition) {
  2385. int pingpong = WW3D::Get_Frame_Count() & 0x1;
  2386. position = Position[pingpong]->Get_Array();
  2387. prev_pos = Position[pingpong ^ 0x1]->Get_Array();
  2388. } else {
  2389. position = Position[0]->Get_Array();
  2390. prev_pos = NULL;
  2391. }
  2392. for (; NewParticleQueueCount;) {
  2393. // Get particle off new particle queue:
  2394. NewParticleStruct &new_particle = NewParticleQueue[NewParticleQueueStart];
  2395. if (++NewParticleQueueStart == MaxNum) NewParticleQueueStart = 0U;
  2396. NewParticleQueueCount--;
  2397. // Get particle birth time stamp, calculate age. If not under maxage
  2398. // skip this particle.
  2399. TimeStamp[NewEnd] = new_particle.TimeStamp;
  2400. unsigned int age = current_time - TimeStamp[NewEnd];
  2401. if (age >= MaxAge) continue;
  2402. float fp_age = (float)age;
  2403. // Apply velocity and acceleration if present. Otherwise, just apply
  2404. // velocity.
  2405. if (HasAccel) {
  2406. position[NewEnd] = new_particle.Position +
  2407. (new_particle.Velocity + 0.5f * Accel * fp_age) * fp_age;
  2408. Velocity[NewEnd] = new_particle.Velocity + (Accel * fp_age);
  2409. } else {
  2410. position[NewEnd] =new_particle.Position +
  2411. (new_particle.Velocity * fp_age);
  2412. Velocity[NewEnd] = new_particle.Velocity;
  2413. }
  2414. // If pingpong enabled, store starting position in prev_pos[].
  2415. if (PingPongPosition) {
  2416. prev_pos[NewEnd] = new_particle.Position;
  2417. }
  2418. // Advance the 'end of new particles' index.
  2419. NewEnd++;
  2420. if (NewEnd == MaxNum) NewEnd = 0;
  2421. // Update the new particles count.
  2422. NewNum++;
  2423. // If we have just overflowed the total buffer, advance Start.
  2424. if ((NewNum + NonNewNum) == (signed)(MaxNum + 1)) {
  2425. Start++;
  2426. if (Start == MaxNum) Start = 0;
  2427. NonNewNum--;
  2428. // If this underflows the 'non-new' buffer, advance End.
  2429. if (NonNewNum == -1) {
  2430. End++;
  2431. if (End == MaxNum) End = 0;
  2432. NonNewNum = 0;
  2433. NewNum--;
  2434. }
  2435. }
  2436. }
  2437. }
  2438. void ParticleBufferClass::Kill_Old_Particles(void)
  2439. {
  2440. // Scan from Start and find the first particle which has an age less than
  2441. // MaxAge - set Start to that position.
  2442. // In the general case, a range in a circular buffer can be composed of up
  2443. // to two subranges. Find the Start - End subranges.
  2444. unsigned int sub1_end; // End of subrange 1.
  2445. unsigned int sub2_start; // Start of subrange 2.
  2446. unsigned int i; // Loop index.
  2447. if ((Start < End) || ((Start == End) && NonNewNum ==0)) {
  2448. sub1_end = End;
  2449. sub2_start = End;
  2450. } else {
  2451. sub1_end = MaxNum;
  2452. sub2_start = 0;
  2453. }
  2454. unsigned int current_time = WW3D::Get_Sync_Time();
  2455. // Stop when the current particle is young enough to be alive.
  2456. bool broke = false;
  2457. for (i = Start; i < sub1_end; i++) {
  2458. if ((current_time - TimeStamp[i]) < MaxAge) {
  2459. broke = true;
  2460. break;
  2461. }
  2462. NonNewNum--;
  2463. }
  2464. if (!broke) {
  2465. for (i = sub2_start; i < End; i++) {
  2466. if ((current_time - TimeStamp[i]) < MaxAge) break;
  2467. NonNewNum--;
  2468. }
  2469. }
  2470. Start = i;
  2471. // NOTE: we do not scan the new particles, because they have been already
  2472. // preculled to be under MaxAge.
  2473. }
  2474. void ParticleBufferClass::Update_Non_New_Particles(unsigned int elapsed)
  2475. {
  2476. // In the general case, a range in a circular buffer can be composed of up
  2477. // to two subranges. Find the Start - End subranges.
  2478. unsigned int sub1_end; // End of subrange 1.
  2479. unsigned int sub2_start; // Start of subrange 2.
  2480. unsigned int i; // Loop index.
  2481. if ((Start < End) || ((Start == End) && NonNewNum ==0)) {
  2482. sub1_end = End;
  2483. sub2_start = End;
  2484. } else {
  2485. sub1_end = MaxNum;
  2486. sub2_start = 0;
  2487. }
  2488. float fp_elapsed_time = (float)elapsed;
  2489. // Update position and velocity for all particles.
  2490. if (PingPongPosition) {
  2491. int pingpong = WW3D::Get_Frame_Count() & 0x1;
  2492. Vector3 *position = Position[pingpong]->Get_Array();
  2493. Vector3 *prev_pos = Position[pingpong ^ 0x1]->Get_Array();
  2494. if (HasAccel) {
  2495. Vector3 delta_v = Accel * fp_elapsed_time;
  2496. Vector3 accel_p = Accel * (0.5f * fp_elapsed_time * fp_elapsed_time);
  2497. for (i = Start; i < sub1_end; i++) {
  2498. position[i] = prev_pos[i] + Velocity[i] * fp_elapsed_time + accel_p;
  2499. Velocity[i] += delta_v;
  2500. }
  2501. for (i = sub2_start; i < End; i++) {
  2502. position[i] = prev_pos[i] + Velocity[i] * fp_elapsed_time + accel_p;
  2503. Velocity[i] += delta_v;
  2504. }
  2505. } else {
  2506. for (i = Start; i < sub1_end; i++) {
  2507. position[i] += Velocity[i] * fp_elapsed_time;
  2508. }
  2509. for (i = sub2_start; i < End; i++) {
  2510. position[i] += Velocity[i] * fp_elapsed_time;
  2511. }
  2512. }
  2513. } else {
  2514. Vector3 *position = Position[0]->Get_Array();
  2515. if (HasAccel) {
  2516. Vector3 delta_v = Accel * fp_elapsed_time;
  2517. Vector3 accel_p = Accel * (0.5f * fp_elapsed_time * fp_elapsed_time);
  2518. for (i = Start; i < sub1_end; i++) {
  2519. position[i] += Velocity[i] * fp_elapsed_time + accel_p;
  2520. Velocity[i] += delta_v;
  2521. }
  2522. for (i = sub2_start; i < End; i++) {
  2523. position[i] += Velocity[i] * fp_elapsed_time + accel_p;
  2524. Velocity[i] += delta_v;
  2525. }
  2526. } else {
  2527. for (i = Start; i < sub1_end; i++) {
  2528. position[i] += Velocity[i] * fp_elapsed_time;
  2529. }
  2530. for (i = sub2_start; i < End; i++) {
  2531. position[i] += Velocity[i] * fp_elapsed_time;
  2532. }
  2533. }
  2534. }
  2535. }
  2536. void ParticleBufferClass::Get_Color_Key_Frames (ParticlePropertyStruct<Vector3> &colors) const
  2537. {
  2538. int real_keyframe_count = (NumColorKeyFrames > 0) ? (NumColorKeyFrames - 1) : 0;
  2539. bool create_last_keyframe = false;
  2540. //
  2541. // Determine if there is a keyframe at the very end of the particle's lifetime
  2542. //
  2543. if ((ColorKeyFrameDeltas != NULL) &&
  2544. ((ColorKeyFrameDeltas[NumColorKeyFrames - 1].X != 0) ||
  2545. (ColorKeyFrameDeltas[NumColorKeyFrames - 1].Y != 0) ||
  2546. (ColorKeyFrameDeltas[NumColorKeyFrames - 1].Z != 0))) {
  2547. real_keyframe_count ++;
  2548. create_last_keyframe = true;
  2549. }
  2550. colors.Start = ColorKeyFrameValues[0];
  2551. colors.Rand = ColorRandom;
  2552. colors.NumKeyFrames = real_keyframe_count;
  2553. colors.KeyTimes = NULL;
  2554. colors.Values = NULL;
  2555. //
  2556. // If we have more than just the start color, build
  2557. // an array of key times and color vatues
  2558. //
  2559. if (real_keyframe_count > 0) {
  2560. colors.KeyTimes = new float[real_keyframe_count];
  2561. colors.Values = new Vector3[real_keyframe_count];
  2562. //
  2563. // Copy the keytimes and color values
  2564. //
  2565. unsigned int index;
  2566. for (index = 1; index < NumColorKeyFrames; index ++) {
  2567. colors.KeyTimes[index - 1] = ((float)ColorKeyFrameTimes[index]) / 1000;
  2568. colors.Values[index - 1] = ColorKeyFrameValues[index];
  2569. }
  2570. //
  2571. // Add a keyframe at the very end of the timeline if necessary
  2572. //
  2573. if (create_last_keyframe) {
  2574. colors.KeyTimes[index - 1] = ((float)MaxAge / 1000);
  2575. //
  2576. // Determine what the value of the last keyframe should be
  2577. //
  2578. Vector3 start_color = ColorKeyFrameValues[index - 1];
  2579. Vector3 &delta = ColorKeyFrameDeltas[NumColorKeyFrames - 1];
  2580. float time_delta = MaxAge - ColorKeyFrameTimes[index - 1];
  2581. colors.Values[index - 1] = start_color + (delta * time_delta);
  2582. }
  2583. }
  2584. return ;
  2585. }
  2586. void ParticleBufferClass::Get_Opacity_Key_Frames (ParticlePropertyStruct<float> &opacities) const
  2587. {
  2588. int real_keyframe_count = (NumAlphaKeyFrames > 0) ? (NumAlphaKeyFrames - 1) : 0;
  2589. bool create_last_keyframe = false;
  2590. //
  2591. // Determine if there is a keyframe at the very end of the particle's lifetime
  2592. //
  2593. if ((AlphaKeyFrameDeltas != NULL) &&
  2594. (AlphaKeyFrameDeltas[NumAlphaKeyFrames - 1] != 0)) {
  2595. real_keyframe_count ++;
  2596. create_last_keyframe = true;
  2597. }
  2598. opacities.Start = AlphaKeyFrameValues[0];
  2599. opacities.Rand = OpacityRandom;
  2600. opacities.NumKeyFrames = real_keyframe_count;
  2601. opacities.KeyTimes = NULL;
  2602. opacities.Values = NULL;
  2603. //
  2604. // If we have more than just the start opacity, build
  2605. // an array of key times and opacity values
  2606. //
  2607. if (real_keyframe_count > 0) {
  2608. opacities.KeyTimes = new float[real_keyframe_count];
  2609. opacities.Values = new float[real_keyframe_count];
  2610. //
  2611. // Copy the keytimes and opacity values
  2612. //
  2613. unsigned int index;
  2614. for (index = 1; index < NumAlphaKeyFrames; index ++) {
  2615. opacities.KeyTimes[index - 1] = ((float)AlphaKeyFrameTimes[index]) / 1000;
  2616. opacities.Values[index - 1] = AlphaKeyFrameValues[index];
  2617. }
  2618. //
  2619. // Add a keyframe at the very end of the timeline if necessary
  2620. //
  2621. if (create_last_keyframe) {
  2622. opacities.KeyTimes[index - 1] = ((float)MaxAge / 1000);
  2623. //
  2624. // Determine what the value of the last keyframe should be
  2625. //
  2626. float start_alpha = AlphaKeyFrameValues[index - 1];
  2627. float &delta = AlphaKeyFrameDeltas[NumAlphaKeyFrames - 1];
  2628. float time_delta = MaxAge - AlphaKeyFrameTimes[index - 1];
  2629. opacities.Values[index - 1] = start_alpha + (delta * time_delta);
  2630. }
  2631. }
  2632. return ;
  2633. }
  2634. void ParticleBufferClass::Get_Size_Key_Frames (ParticlePropertyStruct<float> &sizes) const
  2635. {
  2636. int real_keyframe_count = (NumSizeKeyFrames > 0) ? (NumSizeKeyFrames - 1) : 0;
  2637. bool create_last_keyframe = false;
  2638. //
  2639. // Determine if there is a keyframe at the very end of the particle's lifetime
  2640. //
  2641. if ((SizeKeyFrameDeltas != NULL) &&
  2642. (SizeKeyFrameDeltas[NumSizeKeyFrames - 1] != 0)) {
  2643. real_keyframe_count ++;
  2644. create_last_keyframe = true;
  2645. }
  2646. sizes.Start = SizeKeyFrameValues[0];
  2647. sizes.Rand = SizeRandom;
  2648. sizes.NumKeyFrames = real_keyframe_count;
  2649. sizes.KeyTimes = NULL;
  2650. sizes.Values = NULL;
  2651. //
  2652. // If we have more than just the start opacity, build
  2653. // an array of key times and opacity values
  2654. //
  2655. if (real_keyframe_count > 0) {
  2656. sizes.KeyTimes = new float[real_keyframe_count];
  2657. sizes.Values = new float[real_keyframe_count];
  2658. //
  2659. // Copy the keytimes and size values
  2660. //
  2661. unsigned int index;
  2662. for (index = 1; index < NumSizeKeyFrames; index ++) {
  2663. sizes.KeyTimes[index - 1] = ((float)SizeKeyFrameTimes[index]) / 1000;
  2664. sizes.Values[index - 1] = SizeKeyFrameValues[index];
  2665. }
  2666. //
  2667. // Add a keyframe at the very end of the timeline if necessary
  2668. //
  2669. if (create_last_keyframe) {
  2670. sizes.KeyTimes[index - 1] = ((float)MaxAge / 1000);
  2671. //
  2672. // Determine what the value of the last keyframe should be
  2673. //
  2674. float start_size = SizeKeyFrameValues[index - 1];
  2675. float &delta = SizeKeyFrameDeltas[NumSizeKeyFrames - 1];
  2676. float time_delta = MaxAge - SizeKeyFrameTimes[index - 1];
  2677. sizes.Values[index - 1] = start_size + (delta * time_delta);
  2678. }
  2679. }
  2680. return ;
  2681. }
  2682. void ParticleBufferClass::Get_Rotation_Key_Frames (ParticlePropertyStruct<float> &rotations) const
  2683. {
  2684. int real_keyframe_count = (NumRotationKeyFrames > 0) ? (NumRotationKeyFrames - 1) : 0;
  2685. bool create_last_keyframe = false;
  2686. /*
  2687. ** NOTE: Rotations are stored internally in rotations per millisecond. These will be converted to rotations per second.
  2688. */
  2689. //
  2690. // Determine if there is a keyframe at the very end of the particle's lifetime
  2691. //
  2692. if ((HalfRotationKeyFrameDeltas != NULL) &&
  2693. (HalfRotationKeyFrameDeltas[NumRotationKeyFrames - 1] != 0)) {
  2694. real_keyframe_count ++;
  2695. create_last_keyframe = true;
  2696. }
  2697. // Convert the rotation values from rotations per millisecond to rotations per second.
  2698. rotations.Start = RotationKeyFrameValues ? RotationKeyFrameValues[0] * 1000.0f : 0;
  2699. rotations.Rand = RotationRandom * 1000.0f;
  2700. rotations.NumKeyFrames = real_keyframe_count;
  2701. rotations.KeyTimes = NULL;
  2702. rotations.Values = NULL;
  2703. //
  2704. // If we have more than just the start rotation, build
  2705. // an array of key times and rotation values
  2706. //
  2707. if (real_keyframe_count > 0) {
  2708. rotations.KeyTimes = new float[real_keyframe_count];
  2709. rotations.Values = new float[real_keyframe_count];
  2710. //
  2711. // Copy the keytimes and rotation values
  2712. //
  2713. unsigned int index;
  2714. for (index = 1; index < NumRotationKeyFrames; index ++) {
  2715. rotations.KeyTimes[index - 1] = ((float)RotationKeyFrameTimes[index]) / 1000;
  2716. rotations.Values[index - 1] = RotationKeyFrameValues[index] * 1000.0f;
  2717. }
  2718. //
  2719. // Add a keyframe at the very end of the timeline if necessary
  2720. //
  2721. if (create_last_keyframe) {
  2722. rotations.KeyTimes[index - 1] = ((float)MaxAge / 1000);
  2723. //
  2724. // Determine what the value of the last keyframe should be
  2725. //
  2726. float start_rotation = RotationKeyFrameValues[index - 1];
  2727. float delta = 2.0f * HalfRotationKeyFrameDeltas[NumRotationKeyFrames - 1];
  2728. float time_delta = MaxAge - RotationKeyFrameTimes[index - 1];
  2729. rotations.Values[index - 1] = (start_rotation + (delta * time_delta)) * 1000.0f;
  2730. }
  2731. }
  2732. return ;
  2733. }
  2734. void ParticleBufferClass::Get_Frame_Key_Frames (ParticlePropertyStruct<float> &frames) const
  2735. {
  2736. int real_keyframe_count = (NumFrameKeyFrames > 0) ? (NumFrameKeyFrames - 1) : 0;
  2737. bool create_last_keyframe = false;
  2738. //
  2739. // Determine if there is a keyframe at the very end of the particle's lifetime
  2740. //
  2741. if ((FrameKeyFrameDeltas != NULL) &&
  2742. (FrameKeyFrameDeltas[NumFrameKeyFrames - 1] != 0)) {
  2743. real_keyframe_count ++;
  2744. create_last_keyframe = true;
  2745. }
  2746. frames.Start = FrameKeyFrameValues[0];
  2747. frames.Rand = FrameRandom;
  2748. frames.NumKeyFrames = real_keyframe_count;
  2749. frames.KeyTimes = NULL;
  2750. frames.Values = NULL;
  2751. //
  2752. // If we have more than just the start rotation, build
  2753. // an array of key times and frame values
  2754. //
  2755. if (real_keyframe_count > 0) {
  2756. frames.KeyTimes = new float[real_keyframe_count];
  2757. frames.Values = new float[real_keyframe_count];
  2758. //
  2759. // Copy the keytimes and frame values
  2760. //
  2761. unsigned int index;
  2762. for (index = 1; index < NumFrameKeyFrames; index ++) {
  2763. frames.KeyTimes[index - 1] = ((float)FrameKeyFrameTimes[index]) / 1000;
  2764. frames.Values[index - 1] = FrameKeyFrameValues[index];
  2765. }
  2766. //
  2767. // Add a keyframe at the very end of the timeline if necessary
  2768. //
  2769. if (create_last_keyframe) {
  2770. frames.KeyTimes[index - 1] = ((float)MaxAge / 1000);
  2771. //
  2772. // Determine what the value of the last keyframe should be
  2773. //
  2774. float start_frame = FrameKeyFrameValues[index - 1];
  2775. float &delta = FrameKeyFrameDeltas[NumFrameKeyFrames - 1];
  2776. float time_delta = MaxAge - FrameKeyFrameTimes[index - 1];
  2777. frames.Values[index - 1] = start_frame + (delta * time_delta);
  2778. }
  2779. }
  2780. return ;
  2781. }
  2782. void ParticleBufferClass::Get_Blur_Time_Key_Frames (ParticlePropertyStruct<float> &blurtimes) const
  2783. {
  2784. int real_keyframe_count = (NumBlurTimeKeyFrames > 0) ? (NumBlurTimeKeyFrames - 1) : 0;
  2785. bool create_last_keyframe = false;
  2786. //
  2787. // Determine if there is a keyframe at the very end of the particle's lifetime
  2788. //
  2789. if ((BlurTimeKeyFrameDeltas != NULL) &&
  2790. (BlurTimeKeyFrameDeltas[NumBlurTimeKeyFrames - 1] != 0)) {
  2791. real_keyframe_count ++;
  2792. create_last_keyframe = true;
  2793. }
  2794. blurtimes.Start = BlurTimeKeyFrameValues[0];
  2795. blurtimes.Rand = BlurTimeRandom;
  2796. blurtimes.NumKeyFrames = real_keyframe_count;
  2797. blurtimes.KeyTimes = NULL;
  2798. blurtimes.Values = NULL;
  2799. //
  2800. // If we have more than just the start rotation, build
  2801. // an array of key times and blur time values
  2802. //
  2803. if (real_keyframe_count > 0) {
  2804. blurtimes.KeyTimes = new float[real_keyframe_count];
  2805. blurtimes.Values = new float[real_keyframe_count];
  2806. //
  2807. // Copy the keytimes and frame values
  2808. //
  2809. unsigned int index;
  2810. for (index = 1; index < NumBlurTimeKeyFrames; index ++) {
  2811. blurtimes.KeyTimes[index - 1] = ((float)BlurTimeKeyFrameTimes[index]) / 1000;
  2812. blurtimes.Values[index - 1] = BlurTimeKeyFrameValues[index];
  2813. }
  2814. //
  2815. // Add a keyframe at the very end of the timeline if necessary
  2816. //
  2817. if (create_last_keyframe) {
  2818. blurtimes.KeyTimes[index - 1] = ((float)MaxAge / 1000);
  2819. //
  2820. // Determine what the value of the last keyframe should be
  2821. //
  2822. float start_blurtime = BlurTimeKeyFrameValues[index - 1];
  2823. float &delta = BlurTimeKeyFrameDeltas[NumBlurTimeKeyFrames - 1];
  2824. float time_delta = MaxAge - BlurTimeKeyFrameTimes[index - 1];
  2825. blurtimes.Values[index - 1] = start_blurtime + (delta * time_delta);
  2826. }
  2827. }
  2828. return ;
  2829. }
  2830. void ParticleBufferClass::Set_LOD_Max_Screen_Size(int lod_level,float max_screen_size)
  2831. {
  2832. if ((lod_level <0) || (lod_level > 17)) {
  2833. return;
  2834. }
  2835. LODMaxScreenSizes[lod_level] = max_screen_size;
  2836. }
  2837. float ParticleBufferClass::Get_LOD_Max_Screen_Size(int lod_level)
  2838. {
  2839. if ((lod_level <0) || (lod_level > 17)) {
  2840. return NO_MAX_SCREEN_SIZE;
  2841. }
  2842. return LODMaxScreenSizes[lod_level];
  2843. }
  2844. int ParticleBufferClass::Get_Line_Texture_Mapping_Mode(void) const
  2845. {
  2846. if (LineRenderer != NULL) {
  2847. return LineRenderer->Get_Texture_Mapping_Mode();
  2848. }
  2849. return SegLineRendererClass::UNIFORM_WIDTH_TEXTURE_MAP;
  2850. }
  2851. int ParticleBufferClass::Is_Merge_Intersections(void) const
  2852. {
  2853. if (LineRenderer != NULL) {
  2854. return LineRenderer->Is_Merge_Intersections();
  2855. }
  2856. return false;
  2857. }
  2858. int ParticleBufferClass::Is_Freeze_Random(void) const
  2859. {
  2860. if (LineRenderer != NULL) {
  2861. return LineRenderer->Is_Freeze_Random();
  2862. }
  2863. return false;
  2864. }
  2865. int ParticleBufferClass::Is_Sorting_Disabled(void) const
  2866. {
  2867. if (LineRenderer != NULL) {
  2868. return LineRenderer->Is_Sorting_Disabled();
  2869. }
  2870. return false;
  2871. }
  2872. int ParticleBufferClass::Are_End_Caps_Enabled(void) const
  2873. {
  2874. if (LineRenderer != NULL) {
  2875. return LineRenderer->Are_End_Caps_Enabled();
  2876. }
  2877. return false;
  2878. }
  2879. int ParticleBufferClass::Get_Subdivision_Level(void) const
  2880. {
  2881. if (LineRenderer != NULL) {
  2882. return LineRenderer->Get_Current_Subdivision_Level();
  2883. }
  2884. return 0;
  2885. }
  2886. float ParticleBufferClass::Get_Noise_Amplitude(void) const
  2887. {
  2888. if (LineRenderer != NULL) {
  2889. return LineRenderer->Get_Noise_Amplitude();
  2890. }
  2891. return 0.0f;
  2892. }
  2893. float ParticleBufferClass::Get_Merge_Abort_Factor(void) const
  2894. {
  2895. if (LineRenderer != NULL) {
  2896. return LineRenderer->Get_Merge_Abort_Factor();
  2897. }
  2898. return 0.0f;
  2899. }
  2900. float ParticleBufferClass::Get_Texture_Tile_Factor(void) const
  2901. {
  2902. if (LineRenderer != NULL) {
  2903. return LineRenderer->Get_Texture_Tile_Factor();
  2904. }
  2905. return 1.0f;
  2906. }
  2907. Vector2 ParticleBufferClass::Get_UV_Offset_Rate(void) const
  2908. {
  2909. if (LineRenderer != NULL) {
  2910. return LineRenderer->Get_UV_Offset_Rate();
  2911. }
  2912. return Vector2(0.0f,0.0f);
  2913. }
  2914. ParticleBufferClass::TailDiffuseTypeEnum ParticleBufferClass::Determine_Tail_Diffuse()
  2915. {
  2916. // if there is a texture, the assumption is that the artist
  2917. // is controlling the fadeoff ramp using the texture
  2918. // thus, the ARGB of the tail should be the same as the head
  2919. TextureClass *tex=Get_Texture();
  2920. if (tex)
  2921. {
  2922. REF_PTR_RELEASE(tex);
  2923. return SAME_AS_HEAD;
  2924. }
  2925. ShaderClass shader=Get_Shader();
  2926. //Multiplicative RGB is white (A is don't care)
  2927. //Additive RGB is Black (A is don't care)
  2928. //Screen RGB is Black (A is don't care)
  2929. //Alpha Same RGB as head but A is 0
  2930. //Alpha test blend Same ARGB as head but A is 0
  2931. //Alpha test Same ARGB as head
  2932. //Opaque Same ARGB as head
  2933. // Multiplicative
  2934. if (shader.Get_Dst_Blend_Func()==ShaderClass::DSTBLEND_SRC_COLOR) return WHITE;
  2935. // Additive
  2936. else if ((shader.Get_Src_Blend_Func()==ShaderClass::SRCBLEND_ONE) && (shader.Get_Dst_Blend_Func()==ShaderClass::DSTBLEND_ONE)) return BLACK;
  2937. // Screen
  2938. else if ((shader.Get_Src_Blend_Func()==ShaderClass::SRCBLEND_ONE) && (shader.Get_Dst_Blend_Func()==ShaderClass::DSTBLEND_ONE_MINUS_SRC_COLOR)) return BLACK;
  2939. // Alpha
  2940. else if ((shader.Get_Src_Blend_Func()==ShaderClass::SRCBLEND_SRC_ALPHA) && (shader.Get_Dst_Blend_Func()==ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA)) return SAME_AS_HEAD_ALPHA_ZERO;
  2941. // Alpha test
  2942. else if (shader.Get_Alpha_Test()==ShaderClass::ALPHATEST_ENABLE) return SAME_AS_HEAD_ALPHA_ZERO;
  2943. return SAME_AS_HEAD;
  2944. }
  2945. TextureClass * ParticleBufferClass::Get_Texture (void) const
  2946. {
  2947. if (PointGroup) return PointGroup->Get_Texture();
  2948. else if (LineGroup) return LineGroup->Get_Texture();
  2949. else if (LineRenderer) return LineRenderer->Get_Texture();
  2950. return NULL;
  2951. }
  2952. void ParticleBufferClass::Set_Texture (TextureClass *tex)
  2953. {
  2954. if (PointGroup) PointGroup->Set_Texture(tex);
  2955. else if (LineGroup) LineGroup->Set_Texture(tex);
  2956. else if (LineRenderer) LineRenderer->Set_Texture(tex);
  2957. }
  2958. ShaderClass ParticleBufferClass::Get_Shader (void) const
  2959. {
  2960. if (PointGroup) return PointGroup->Get_Shader();
  2961. else if (LineGroup) return LineGroup->Get_Shader();
  2962. else if (LineRenderer) return LineRenderer->Get_Shader();
  2963. WWASSERT(0);
  2964. return ShaderClass::_PresetOpaqueShader;
  2965. }