1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ParticleSet.cpp
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 28126 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/gfx/gfx_ParticleContext.h>
19 #include <nw/gfx/gfx_ParticleSet.h>
20 #include <nw/gfx/gfx_ParticleModel.h>
21 #include <nw/gfx/gfx_ParticleEmitter.h>
22 #include <nw/gfx/gfx_ParticleTime.h>
23 #include <nw/gfx/gfx_ISceneVisitor.h>
24 
25 #include <nw/dev/dev_ParticleProfile.h>
26 
27 #include <nw/ut/ut_ResUtil.h>
28 #include <nw/ut/ut_ResDictionary.h>
29 
30 namespace nw
31 {
32 namespace gfx
33 {
34 
35 namespace internal
36 {
37 #if 0
38 static const f32 acosTable[] =
39 {
40 3.141593f,3.067040f,3.036135f,3.012403f,2.992383f,2.974733f,2.958764f,2.944069f,2.930382f,2.917517f,2.905342f,2.893752f,
41 2.882671f,2.872035f,2.861794f,2.851906f,2.842335f,2.833052f,2.824032f,2.815253f,2.806697f,2.798345f,2.790184f,2.782202f,
42 2.774385f,2.766724f,2.759209f,2.751832f,2.744585f,2.737462f,2.730455f,2.723559f,2.716768f,2.710078f,2.703484f,2.696981f,
43 2.690566f,2.684235f,2.677984f,2.671810f,2.665710f,2.659682f,2.653723f,2.647830f,2.642000f,2.636232f,2.630524f,2.624873f,
44 2.619278f,2.613737f,2.608248f,2.602809f,2.597420f,2.592077f,2.586782f,2.581531f,2.576324f,2.571159f,2.566035f,2.560952f,
45 2.555907f,2.550901f,2.545932f,2.540999f,2.536101f,2.531238f,2.526408f,2.521611f,2.516846f,2.512112f,2.507409f,2.502736f,
46 2.498092f,2.493476f,2.488889f,2.484329f,2.479795f,2.475288f,2.470807f,2.466351f,2.461919f,2.457511f,2.453128f,2.448767f,
47 2.444430f,2.440114f,2.435821f,2.431549f,2.427298f,2.423068f,2.418859f,2.414669f,2.410499f,2.406348f,2.402216f,2.398103f,
48 2.394008f,2.389932f,2.385872f,2.381831f,2.377806f,2.373798f,2.369807f,2.365833f,2.361874f,2.357931f,2.354003f,2.350091f,
49 2.346194f,2.342312f,2.338444f,2.334590f,2.330751f,2.326926f,2.323115f,2.319317f,2.315532f,2.311761f,2.308003f,2.304257f,
50 2.300524f,2.296803f,2.293095f,2.289399f,2.285714f,2.282042f,2.278381f,2.274731f,2.271093f,2.267466f,2.263849f,2.260244f,
51 2.256649f,2.253065f,2.249491f,2.245928f,2.242375f,2.238831f,2.235298f,2.231774f,2.228260f,2.224755f,2.221260f,2.217774f,
52 2.214298f,2.210830f,2.207371f,2.203921f,2.200480f,2.197047f,2.193623f,2.190207f,2.186800f,2.183401f,2.180009f,2.176626f,
53 2.173251f,2.169884f,2.166524f,2.163172f,2.159827f,2.156490f,2.153161f,2.149838f,2.146523f,2.143215f,2.139914f,2.136620f,
54 2.133333f,2.130052f,2.126779f,2.123511f,2.120251f,2.116997f,2.113750f,2.110508f,2.107273f,2.104045f,2.100822f,2.097606f,
55 2.094395f,2.091191f,2.087992f,2.084799f,2.081612f,2.078431f,2.075255f,2.072084f,2.068920f,2.065760f,2.062606f,2.059458f,
56 2.056314f,2.053176f,2.050043f,2.046916f,2.043792f,2.040675f,2.037562f,2.034454f,2.031350f,2.028252f,2.025158f,2.022069f,
57 2.018985f,2.015904f,2.012829f,2.009758f,2.006692f,2.003630f,2.000572f,1.997518f,1.994469f,1.991424f,1.988383f,1.985346f,
58 1.982313f,1.979284f,1.976260f,1.973239f,1.970222f,1.967208f,1.964199f,1.961193f,1.958191f,1.955193f,1.952199f,1.949207f,
59 1.946220f,1.943236f,1.940256f,1.937278f,1.934305f,1.931334f,1.928367f,1.925404f,1.922443f,1.919486f,1.916532f,1.913581f,
60 1.910633f,1.907688f,1.904747f,1.901808f,1.898872f,1.895939f,1.893010f,1.890083f,1.887158f,1.884237f,1.881318f,1.878402f,
61 1.875489f,1.872578f,1.869671f,1.866765f,1.863862f,1.860962f,1.858064f,1.855169f,1.852276f,1.849386f,1.846498f,1.843612f,
62 1.840729f,1.837848f,1.834969f,1.832093f,1.829219f,1.826347f,1.823477f,1.820609f,1.817743f,1.814879f,1.812018f,1.809158f,
63 1.806301f,1.803445f,1.800591f,1.797739f,1.794889f,1.792041f,1.789195f,1.786351f,1.783508f,1.780667f,1.777828f,1.774990f,
64 1.772154f,1.769320f,1.766487f,1.763656f,1.760827f,1.757999f,1.755172f,1.752348f,1.749524f,1.746702f,1.743881f,1.741062f,
65 1.738244f,1.735428f,1.732613f,1.729799f,1.726986f,1.724175f,1.721365f,1.718556f,1.715748f,1.712941f,1.710136f,1.707331f,
66 1.704528f,1.701726f,1.698924f,1.696124f,1.693325f,1.690527f,1.687729f,1.684933f,1.682137f,1.679343f,1.676549f,1.673756f,
67 1.670964f,1.668172f,1.665382f,1.662592f,1.659803f,1.657014f,1.654226f,1.651439f,1.648653f,1.645867f,1.643081f,1.640297f,
68 1.637512f,1.634729f,1.631945f,1.629163f,1.626380f,1.623599f,1.620817f,1.618036f,1.615255f,1.612475f,1.609695f,1.606915f,
69 1.604136f,1.601357f,1.598578f,1.595799f,1.593020f,1.590242f,1.587464f,1.584686f,1.581908f,1.579130f,1.576352f,1.573574f,
70 1.570796f,1.568019f,1.565241f,1.562463f,1.559685f,1.556907f,1.554129f,1.551351f,1.548572f,1.545794f,1.543015f,1.540236f,
71 1.537457f,1.534677f,1.531898f,1.529118f,1.526337f,1.523557f,1.520775f,1.517994f,1.515212f,1.512430f,1.509647f,1.506864f,
72 1.504080f,1.501296f,1.498511f,1.495726f,1.492940f,1.490153f,1.487366f,1.484578f,1.481790f,1.479001f,1.476211f,1.473420f,
73 1.470629f,1.467837f,1.465044f,1.462250f,1.459455f,1.456660f,1.453863f,1.451066f,1.448268f,1.445469f,1.442668f,1.439867f,
74 1.437065f,1.434261f,1.431457f,1.428651f,1.425845f,1.423037f,1.420228f,1.417418f,1.414606f,1.411794f,1.408980f,1.406165f,
75 1.403348f,1.400530f,1.397711f,1.394891f,1.392069f,1.389245f,1.386420f,1.383594f,1.380766f,1.377936f,1.375105f,1.372273f,
76 1.369438f,1.366603f,1.363765f,1.360926f,1.358085f,1.355242f,1.352398f,1.349551f,1.346703f,1.343853f,1.341002f,1.338148f,
77 1.335292f,1.332434f,1.329575f,1.326713f,1.323850f,1.320984f,1.318116f,1.315246f,1.312374f,1.309500f,1.306623f,1.303745f,
78 1.300864f,1.297980f,1.295095f,1.292207f,1.289316f,1.286423f,1.283528f,1.280631f,1.277730f,1.274827f,1.271922f,1.269014f,
79 1.266104f,1.263190f,1.260275f,1.257356f,1.254434f,1.251510f,1.248583f,1.245653f,1.242720f,1.239785f,1.236846f,1.233904f,
80 1.230959f,1.228012f,1.225061f,1.222107f,1.219149f,1.216189f,1.213225f,1.210258f,1.207288f,1.204314f,1.201337f,1.198357f,
81 1.195373f,1.192385f,1.189394f,1.186400f,1.183401f,1.180399f,1.177394f,1.174384f,1.171371f,1.168354f,1.165333f,1.162308f,
82 1.159279f,1.156247f,1.153210f,1.150169f,1.147124f,1.144074f,1.141021f,1.137963f,1.134901f,1.131835f,1.128763f,1.125688f,
83 1.122608f,1.119524f,1.116435f,1.113341f,1.110242f,1.107139f,1.104031f,1.100918f,1.097800f,1.094677f,1.091549f,1.088416f,
84 1.085278f,1.082135f,1.078986f,1.075832f,1.072673f,1.069508f,1.066338f,1.063162f,1.059981f,1.056794f,1.053601f,1.050402f,
85 1.047198f,1.043987f,1.040771f,1.037548f,1.034319f,1.031084f,1.027843f,1.024596f,1.021342f,1.018081f,1.014814f,1.011541f,
86 1.008260f,1.004973f,1.001679f,0.998378f,0.995070f,0.991754f,0.988432f,0.985102f,0.981765f,0.978421f,0.975069f,0.971709f,
87 0.968342f,0.964966f,0.961583f,0.958192f,0.954793f,0.951385f,0.947970f,0.944546f,0.941113f,0.937672f,0.934222f,0.930763f,
88 0.927295f,0.923818f,0.920332f,0.916837f,0.913333f,0.909819f,0.906295f,0.902762f,0.899218f,0.895665f,0.892101f,0.888527f,
89 0.884943f,0.881349f,0.877743f,0.874127f,0.870500f,0.866862f,0.863212f,0.859551f,0.855878f,0.852194f,0.848498f,0.844789f,
90 0.841069f,0.837336f,0.833590f,0.829832f,0.826060f,0.822276f,0.818478f,0.814666f,0.810841f,0.807002f,0.803149f,0.799281f,
91 0.795399f,0.791502f,0.787590f,0.783662f,0.779719f,0.775760f,0.771785f,0.767794f,0.763786f,0.759762f,0.755720f,0.751661f,
92 0.747584f,0.743490f,0.739376f,0.735245f,0.731094f,0.726924f,0.722734f,0.718525f,0.714295f,0.710044f,0.705772f,0.701478f,
93 0.697163f,0.692825f,0.688465f,0.684081f,0.679674f,0.675242f,0.670786f,0.666305f,0.661797f,0.657264f,0.652704f,0.648116f,
94 0.643501f,0.638857f,0.634184f,0.629481f,0.624747f,0.619982f,0.615185f,0.610355f,0.605492f,0.600594f,0.595661f,0.590692f,
95 0.585685f,0.580641f,0.575558f,0.570434f,0.565269f,0.560062f,0.554811f,0.549515f,0.544173f,0.538784f,0.533345f,0.527856f,
96 0.522315f,0.516720f,0.511069f,0.505360f,0.499593f,0.493763f,0.487870f,0.481910f,0.475882f,0.469783f,0.463609f,0.457358f,
97 0.451027f,0.444612f,0.438109f,0.431514f,0.424824f,0.418034f,0.411138f,0.404131f,0.397007f,0.389761f,0.382384f,0.374869f,
98 0.367208f,0.359391f,0.351408f,0.343248f,0.334896f,0.326339f,0.317560f,0.308540f,0.299258f,0.289687f,0.279798f,0.269557f,
99 0.258921f,0.247840f,0.236251f,0.224075f,0.211211f,0.197523f,0.182829f,0.166860f,0.149209f,0.129189f,0.105458f,0.074553f,
100 0.000000f,
101 };
102 
103 // ArcCosのテーブル引き関数です。
104 inline f32
105 AcosTableRad(f32 x)
106 {
107     // 0~720へ変換
108     u32 index = x * 360 + 360;
109     if (index < sizeof(acosTable))
110     {
111         return acosTable[index];
112     }
113     else
114     {
115         return 0.0f;
116     }
117 }
118 #endif
119 
120 inline bool
VEC3Normalize(nn::math::VEC3 * pIn)121 VEC3Normalize(nn::math::VEC3* pIn)
122 {
123     NN_NULL_ASSERT(pIn);
124 
125     f32 mag = (pIn->x * pIn->x) + (pIn->y * pIn->y) + (pIn->z * pIn->z);
126 
127     if (mag == 0)
128     {
129         return false;
130     }
131 
132     mag = 1.0f / ::std::sqrtf(mag);
133 
134     pIn->x = pIn->x * mag;
135     pIn->y = pIn->y * mag;
136     pIn->z = pIn->z * mag;
137 
138     return true;
139 }
140 
141 
142 #include <nn/hw/ARM/code32.h>
143 #include <nn/hw/ARM/VFPv2_reg.h>
144 
145 // ベクタ長4 バージョン
146 asm void
VEC3ArrayAddScalar(nw::math::VEC3 *,nw::math::VEC3 *,u32)147 VEC3ArrayAddScalar(nw::math::VEC3* /*array*/, nw::math::VEC3* /*scalar*/, u32 /*countDiv12*/)
148 {
149     // レジスタの保存
150     VPUSH       {d8-d11}
151 
152     ADD         r2, #3
153     ASR         r2, #2
154 
155     // 端数処理を省けるよう、VEC3を4個ずつ一度に処理
156     VLDMIA      r1, {s20-s22}
157     MOV         r3, r0
158 
159 VEC3ArrayAddScalarLoop
160     VLDMIA      r0!, {s8-s11}
161     VLDMIA      r0!, {s12-s15}
162 
163     // [s8 .. s10] += [s20 .. s22]
164     // [s11 .. s13] += [s20 .. s22]
165     // [s14 .. s16] += [s20 .. s22]
166     // [s17 .. s19] += [s20 .. s22]
167     VADD.F32    s8, s8, s20
168     VADD.F32    s9, s9, s21
169     VADD.F32    s10, s10, s22
170     VADD.F32    s11, s11, s20
171 
172     VLDMIA      r0!, {s16-s19}
173 
174     VADD.F32    s12, s12, s21
175     VADD.F32    s13, s13, s22
176     VADD.F32    s14, s14, s20
177     VADD.F32    s15, s15, s21
178 
179     VSTMIA      r3!, {s8-s11}
180 
181     VADD.F32    s16, s16, s22
182     VADD.F32    s17, s17, s20
183     VADD.F32    s18, s18, s21
184     VADD.F32    s19, s19, s22
185 
186     VSTMIA      r3!, {s12-s19}
187 
188     SUBS        r2, r2, #1
189     BNE         VEC3ArrayAddScalarLoop
190 
191     // レジスタの復帰
192     VPOP        {d8-d11}
193 
194     // 戻る
195     BX          lr
196 }
197 
198 asm void
VEC3ArrayAddVEC3Array(nw::math::VEC3 *,nw::math::VEC3 *,f32,u32)199 VEC3ArrayAddVEC3Array(
200     nw::math::VEC3* /*arrayTarget*/, // r0
201     nw::math::VEC3* /*arrayAdd*/, // r1
202     f32 /*scalar*/, // s0
203     u32 /*countDiv12*/ // r2
204 )
205 {
206     // レジスタの保存
207     VPUSH       {d8-d15}
208 
209     ADD         r2, #3
210     ASR         r2, #2
211 
212     MOV         r3, r0
213 
214     // 端数処理を省けるよう、VEC3を4個ずつ一度に処理
215 VEC3ArrayAddVEC3ArrayLoop
216     VLDMIA      r0!, {s8-s11}
217     VLDMIA      r1!, {s20-s23}
218     VLDMIA      r0!, {s12-s15}
219 
220     // [s8 .. s11] += [s20 .. s23] * s0
221     VMLA.F32    s8, s20, s0
222     VMLA.F32    s9, s21, s0
223     VMLA.F32    s10, s22, s0
224     VMLA.F32    s11, s23, s0
225 
226     VLDMIA      r1!, {s24-s27}
227     VSTMIA      r3!, {s8-s11}
228 
229     // [s12 .. s15] += [s24 .. s27] * s0
230     VMLA.F32    s12, s24, s0
231     VMLA.F32    s13, s25, s0
232 
233     VLDMIA      r0!, {s16-s19}
234 
235     VMLA.F32    s14, s26, s0
236     VMLA.F32    s15, s27, s0
237 
238     VLDMIA      r1!, {s28-s31}
239     VSTMIA      r3!, {s12-s15}
240 
241     // [s16 .. s19] += [s28 .. s31] * s0
242     VMLA.F32    s16, s28, s0
243     VMLA.F32    s17, s29, s0
244     VMLA.F32    s18, s30, s0
245     VMLA.F32    s19, s31, s0
246 
247     VSTMIA      r3!, {s16-s19}
248 
249     SUBS        r2, r2, #1
250     BNE         VEC3ArrayAddVEC3ArrayLoop
251 
252     // レジスタの復帰
253     VPOP        {d8-d15}
254 
255     // 戻る
256     BX          lr
257 }
258 
259 asm void
CalcRemainFrame(f32 *,f32 *,f32,int)260 CalcRemainFrame(
261     f32* /*output*/, // r0
262     f32* /*limitArray*/, // r1
263     f32 /*time*/, // s0
264     int /*count*/ // r2
265 )
266 {
267     ADD         r2, #7
268     ASR         r2, #3
269 
270 CalcRemainFrameLoop
271     VLDMIA      r1!, {s8-s15}
272 
273     // [s8 .. s15] = [s8 .. s15] + s0
274     VADD.F32    s8, s8, s0
275     VADD.F32    s9, s9, s0
276     VADD.F32    s10, s10, s0
277     VADD.F32    s11, s11, s0
278     VADD.F32    s12, s12, s0
279     VADD.F32    s13, s13, s0
280     VADD.F32    s14, s14, s0
281     VADD.F32    s15, s15, s0
282 
283     VSTMIA      r0!, {s8-s15}
284 
285     SUBS        r2, r2, #1
286     BNE         CalcRemainFrameLoop
287 
288     // 戻る
289     BX          lr
290 }
291 
292 #include <nn/hw/ARM/codereset.h>
293 
294 }
295 
296 NW_UT_RUNTIME_TYPEINFO_DEFINITION(ParticleSet, SceneNode);
297 
298 void
GetMemorySizeInternal(os::MemorySizeCalculator * pSize,ResParticleSet resNode,const ParticleSet::Description & description)299 ParticleSet::GetMemorySizeInternal(
300     os::MemorySizeCalculator* pSize,
301     ResParticleSet resNode,
302     const ParticleSet::Description& description)
303 {
304     int initializerCapacity = description.maxInitializers;
305     if (initializerCapacity < resNode.GetParticleInitializersCount())
306     {
307         initializerCapacity = resNode.GetParticleInitializersCount();
308     }
309 
310     int updaterCapacity = description.maxUpdaters;
311     if (updaterCapacity < resNode.GetParticleUpdatersCount())
312     {
313         updaterCapacity = resNode.GetParticleUpdatersCount();
314     }
315 
316     os::MemorySizeCalculator& size = *pSize;
317 
318     size.Add(sizeof(ParticleSet), 4);
319     size.Add(sizeof(Initializer) * initializerCapacity, 4);
320     size.Add(sizeof(Updater) * updaterCapacity, 4);
321 
322     {
323         ResParticleInitializerArray resInitializers =
324             resNode.GetParticleInitializers();
325         ResParticleInitializerArrayIterator initializerEnd =
326             resInitializers.end();
327         for (ResParticleInitializerArrayIterator i = resInitializers.begin(); i != initializerEnd;)
328         {
329             const ResParticleInitializer resInitializer = *i++;
330 
331             if (resInitializer.GetIsResourceCopyEnabled())
332             {
333                 ParticleUtil::GetMemorySizeForDuplicateResParticleInitializerInternal(
334                     pSize,&resInitializer);
335             }
336         }
337     }
338 
339     {
340         ResParticleUpdaterArray resUpdaters = resNode.GetParticleUpdaters();
341         ResParticleUpdaterArrayIterator updaterEnd =
342             resUpdaters.end();
343         for (ResParticleUpdaterArrayIterator i = resUpdaters.begin(); i != updaterEnd;)
344         {
345             const ResParticleUpdater resUpdater = *i++;
346 
347             if (resUpdater.GetIsResourceCopyEnabled())
348             {
349                 ParticleUtil::GetMemorySizeForDuplicateResParticleUpdaterInternal(
350                     pSize, &resUpdater);
351             }
352         }
353     }
354 
355     SceneNode::GetMemorySizeForInitialize(pSize, resNode, description);
356 
357     nw::gfx::ResParticleCollection resParticleCollection =
358         resNode.GetParticleCollection();
359 
360     NW_ASSERT(resParticleCollection.IsValid());
361 
362     ParticleCollection::GetMemorySizeInternal(pSize, resParticleCollection);
363 }
364 
365 //----------------------------------------
366 void
GetDeviceMemorySizeInternal(os::MemorySizeCalculator * pSize,ResParticleSet resNode)367 ParticleSet::GetDeviceMemorySizeInternal(
368     os::MemorySizeCalculator* pSize,
369     ResParticleSet resNode)
370 {
371     nw::gfx::ResParticleCollection resParticleCollection =
372         resNode.GetParticleCollection();
373 
374     ParticleCollection::GetDeviceMemorySizeInternal(pSize, resParticleCollection);
375 }
376 
377 //----------------------------------------
378 ParticleSet*
Create(SceneNode * parent,ResSceneObject resource,const ParticleSet::Description & description,os::IAllocator * mainAllocator,os::IAllocator * deviceAllocator,ParticleShape * shape)379 ParticleSet::Create(
380     SceneNode* parent,
381     ResSceneObject resource,
382     const ParticleSet::Description& description,
383     os::IAllocator* mainAllocator,
384     os::IAllocator* deviceAllocator,
385     ParticleShape* shape
386 )
387 {
388     NW_NULL_ASSERT(mainAllocator);
389     NW_NULL_ASSERT(deviceAllocator);
390 
391     ResParticleSet resNode = ResDynamicCast<ResParticleSet>(resource);
392     NW_ASSERT(resNode.IsValid());
393 
394     int initializerCapacity = description.maxInitializers;
395     if (initializerCapacity < resNode.GetParticleInitializersCount())
396     {
397         initializerCapacity = resNode.GetParticleInitializersCount();
398     }
399 
400     int updaterCapacity = description.maxUpdaters;
401     if (updaterCapacity < resNode.GetParticleUpdatersCount())
402     {
403         updaterCapacity = resNode.GetParticleUpdatersCount();
404     }
405 
406     int memorySize = sizeof(ParticleSet);
407     memorySize = ut::RoundUp(memorySize, 4);
408     memorySize += sizeof(Initializer) * initializerCapacity;
409     memorySize = ut::RoundUp(memorySize, 4);
410     memorySize += sizeof(Updater) * updaterCapacity;
411 
412     u8* memory = reinterpret_cast<u8*>(mainAllocator->Alloc(memorySize));
413     if (memory == NULL)
414     {
415         return NULL;
416     }
417 
418     ParticleSet* node = new(memory) ParticleSet(
419         mainAllocator,
420         resNode,
421         description);
422     memory += sizeof(ParticleSet);
423 
424     {
425         Result result = node->Initialize(mainAllocator);
426         if (!result.IsSuccess())
427         {
428             SafeDestroy(node);
429             return NULL;
430         }
431     }
432 
433     if (parent)
434     {
435         bool result = parent->AttachChild(node);
436         NW_ASSERT(result);
437     }
438 
439     bool isSuccess = true;
440 
441     {
442         memory = reinterpret_cast<u8*>(ut::RoundUp(memory, 4));
443         node->m_Initializers = ut::MoveArray<Initializer>(memory, initializerCapacity);
444         memory += sizeof(Initializer) * initializerCapacity;
445 
446         ResParticleInitializerArray resInitializers =
447             resNode.GetParticleInitializers();
448         ResParticleInitializerArrayIterator initializerEnd =
449             resInitializers.end();
450         for (ResParticleInitializerArrayIterator i = resInitializers.begin(); i != initializerEnd;)
451         {
452             const ResParticleInitializer resInitializer = *i++;
453 
454             Initializer initializer;
455 
456             if (resInitializer.GetIsResourceCopyEnabled())
457             {
458                 initializer.m_IsCopied = true;
459                 initializer.resource = ParticleUtil::DuplicateResParticleInitializer(
460                     &resInitializer,
461                     mainAllocator);
462                 if (initializer.resource == NULL)
463                 {
464                     isSuccess = false;
465                 }
466             }
467             else
468             {
469                 initializer.m_IsCopied = false;
470                 initializer.resource = resInitializer.ptr();
471             }
472 
473             initializer.work = 0;
474 
475             nw::ut::ResTypeInfo resType = resInitializer.GetTypeInfo();
476             initializer.m_Type = resType;
477 
478             node->m_Initializers.push_back(initializer);
479         }
480     }
481 
482     {
483         memory = reinterpret_cast<u8*>(ut::RoundUp(memory, 4));
484         node->m_Updaters = ut::MoveArray<Updater>(memory, updaterCapacity);
485         memory += sizeof(Updater) * updaterCapacity;
486 
487         ResParticleUpdaterArray resUpdaters = resNode.GetParticleUpdaters();
488         ResParticleUpdaterArrayIterator updaterEnd =
489             resUpdaters.end();
490         for (ResParticleUpdaterArrayIterator i = resUpdaters.begin(); i != updaterEnd;)
491         {
492             const ResParticleUpdater resUpdater = *i++;
493 
494             Updater updater;
495 
496             if (resUpdater.GetIsResourceCopyEnabled())
497             {
498                 updater.m_IsCopied = true;
499                 updater.resource = ParticleUtil::DuplicateResParticleUpdater(
500                     &resUpdater,
501                     mainAllocator);
502                 if (updater.resource == NULL)
503                 {
504                     isSuccess = false;
505                 }
506             }
507             else
508             {
509                 updater.m_IsCopied = false;
510                 updater.resource = resUpdater.ptr();
511             }
512 
513             updater.work = 0;
514             updater.m_Flags = 0;
515 
516             nw::ut::ResTypeInfo resType = resUpdater.GetTypeInfo();
517             updater.m_Type = resType;
518 
519             // アニメーション系のアップデータであれば、
520             // カーブデータがあるかこの時点で判断する。
521             if ((resType == ResParticleVector3AdditiveUpdater::TYPE_INFO) ||
522                 (resType == ResParticleVector3ImmediateUpdater::TYPE_INFO) ||
523                 (resType == ResParticleVector3RandomAdditiveUpdater::TYPE_INFO))
524             {
525                 ResParticleVector3Updater vec3Updater(resUpdater.ptr());
526                 NW_ASSERT(vec3Updater.IsValid());
527                 ResParticleAnimation animation = vec3Updater.GetParticleAnimation();
528                 if (animation.IsValid())
529                 {
530                     if (animation.GetAnimationData())
531                     {
532                         updater.EnableFlags(Updater::FLAG_IS_HAS_CURVE_ANIM);
533                     }
534                 }
535             }
536 
537             node->m_Updaters.push_back(updater);
538         }
539     }
540 
541     if (isSuccess == false)
542     {
543         SafeDestroy(node);
544         return NULL;
545     }
546 
547     nw::gfx::ResParticleCollection resParticleCollection =
548         resNode.GetParticleCollection();
549 
550     NW_ASSERT(resParticleCollection.IsValid());
551 
552     ParticleCollection* collectionNode = ParticleCollection::Create(
553         node,
554         resParticleCollection,
555         mainAllocator,
556         deviceAllocator,
557         shape);
558 
559     if (collectionNode  == NULL)
560     {
561         SafeDestroy(node);
562         return NULL;
563     }
564 
565     shape->CreateCommandCache(node);
566 
567     // 高速化のためのストリームのポインタのキャッシュ
568     {
569         ut::MoveArray<Initializer>::iterator endIter = node->m_Initializers.end();
570         for (ut::MoveArray<Initializer>::iterator iter = node->m_Initializers.begin(); iter != endIter;)
571         {
572             Initializer& initializer = *iter++;
573 
574             const ResParticleInitializer resInitializer(initializer.resource);
575 
576             ParticleUsage target = resInitializer.GetTargetStream();
577 
578             if (target >= 0)
579             {
580                 if (collectionNode->GetBufferSide())
581                 {
582                     initializer.m_TargetStreams[1] = collectionNode->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
583                     initializer.m_TargetStreams[0] = collectionNode->GetStreamPtr(target, PARTICLE_BUFFER_BACK);
584                 }
585                 else
586                 {
587                     initializer.m_TargetStreams[0] = collectionNode->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
588                     initializer.m_TargetStreams[1] = collectionNode->GetStreamPtr(target, PARTICLE_BUFFER_BACK);
589                 }
590             }
591             else
592             {
593                 initializer.m_TargetStreams[0] = NULL;
594                 initializer.m_TargetStreams[1] = NULL;
595             }
596         }
597     }
598 
599     {
600         ut::MoveArray<Updater>::iterator endIter = node->m_Updaters.end();
601         for (ut::MoveArray<Updater>::iterator iter = node->m_Updaters.begin(); iter != endIter;)
602         {
603             Updater& updater = *iter++;
604 
605             const ResParticleUpdater resUpdater(updater.resource);
606 
607             ParticleUsage target = resUpdater.GetTargetStream();
608 
609             if (target >= 0)
610             {
611                 if (collectionNode->GetBufferSide())
612                 {
613                     updater.m_TargetStreams[1] = collectionNode->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
614                     updater.m_TargetStreams[0] = collectionNode->GetStreamPtr(target, PARTICLE_BUFFER_BACK);
615                 }
616                 else
617                 {
618                     updater.m_TargetStreams[0] = collectionNode->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
619                     updater.m_TargetStreams[1] = collectionNode->GetStreamPtr(target, PARTICLE_BUFFER_BACK);
620                 }
621             }
622             else
623             {
624                     updater.m_TargetStreams[0] = NULL;
625                     updater.m_TargetStreams[1] = NULL;
626             }
627         }
628     }
629 
630     return node;
631 }
632 
633 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
634 // CALC_OPT:inline 指定へ。
635 /*static*/ inline void
SetDefaultValues(ParticleCollection * collection,const nw::math::VEC3 * positions,int particleCount,f32 time,bool isAscendingOrder)636 SetDefaultValues(
637     ParticleCollection* collection,
638     const nw::math::VEC3* positions,
639     int particleCount,
640     f32 time,
641     bool isAscendingOrder
642 )
643 {
644     ParticleTime lifeParam = 1;
645     if (!collection->IsStream(PARTICLEUSAGE_LIFE))
646     {
647         lifeParam = *(ParticleTime*)collection->GetParameterPtr(PARTICLEUSAGE_LIFE);
648     }
649 
650     u16* activeIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_FRONT);
651     NW_NULL_ASSERT(activeIndex);
652 
653     const int startIndex = (isAscendingOrder)? collection->GetCount() : collection->GetCapacity() - collection->GetCount() - 1;
654     const int incrIndex = (isAscendingOrder)? 1 : -1;
655 
656     u16* pFreeIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_FREEINDEX, PARTICLE_BUFFER_FRONT);
657     NW_NULL_ASSERT(pFreeIndex);
658     pFreeIndex += collection->GetCapacity() - collection->GetCount() - 1;
659 
660     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
661     NW_NULL_ASSERT(birth);
662 
663     nw::math::VEC3* translate = (nw::math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_FRONT);
664     NW_NULL_ASSERT(translate);
665 
666     nw::math::VEC3* velocity = (nw::math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_VELOCITY, PARTICLE_BUFFER_FRONT);
667     NW_NULL_ASSERT(velocity);
668 
669     ParticleTime* limit = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_NEG_TIMELIMIT, PARTICLE_BUFFER_FRONT);
670     NW_NULL_ASSERT(limit);
671 
672     int minIndex = collection->GetMinActiveIndex();
673     int maxIndex = collection->GetMaxActiveIndex();
674     {
675         f32 limitDefault = -(time + lifeParam);
676 
677         u16* pActiveIndex = activeIndex + startIndex;
678         for (int i = particleCount; i != 0; --i)
679         {
680             int nextIndex = *pFreeIndex;
681             --pFreeIndex;
682 
683             *pActiveIndex = nextIndex;
684             pActiveIndex += incrIndex;
685 
686             if (minIndex > nextIndex)
687             {
688                 minIndex = nextIndex;
689             }
690 
691             if (maxIndex < nextIndex)
692             {
693                 maxIndex = nextIndex;
694             }
695 
696             birth[nextIndex] = time;
697             translate[nextIndex] = *positions++;
698             velocity[nextIndex].x = 0.0f;
699             velocity[nextIndex].y = 0.0f;
700             velocity[nextIndex].z = 0.0f;
701             limit[nextIndex] = limitDefault;
702         }
703     }
704 
705     collection->SetMinActiveIndex(minIndex);
706     collection->SetMaxActiveIndex(maxIndex);
707 }
708 
709 //----------------------------------------
710 void
AddParticles(const nw::math::MTX34 & emitterMatrix,const nw::math::VEC3 * const positions,ParticleSet * parentParticleSet,const u16 * const parentIndices,int positionsCount)711 ParticleSet::AddParticles(
712     const nw::math::MTX34& emitterMatrix,
713     const nw::math::VEC3* const positions,
714     ParticleSet* parentParticleSet,
715     const u16* const parentIndices,
716     int positionsCount
717 )
718 {
719     NW_NULL_ASSERT(positions);
720 
721     ParticleCollection* collection = this->GetParticleCollection();
722 
723     const int collectionCount = collection->GetCount();
724     const int collectionCapacity = collection->GetCapacity();
725 
726     int freeSize = collectionCapacity - collectionCount;
727     if (freeSize <= 0)
728     {
729         return;
730     }
731 
732     int particleCount = positionsCount;
733     if (particleCount > freeSize)
734     {
735         particleCount = freeSize;
736     }
737 
738     if (particleCount <= 0)
739     {
740         return;
741     }
742 
743     const bool isAscendingOrder = this->IsAscendingOrder();
744 
745     const int startIndex = (isAscendingOrder)? collectionCount : collectionCapacity - collectionCount - 1;
746     const int incrIndex = (isAscendingOrder)? 1 : -1;
747 
748     ParticleModel* model = static_cast<ParticleModel*>(this->GetParent());
749     NW_NULL_ASSERT(model);
750     f32 time = model->ParticleAnimFrameController().GetFrame();
751 
752     SetDefaultValues(collection, positions, particleCount, time, isAscendingOrder);
753 
754     this->InitializeParticles(startIndex, particleCount, incrIndex, time);
755 
756     collection->SetCount(collectionCount + particleCount);
757 
758     bool useTransform = false;
759     if (this->WorldMatrix() != emitterMatrix)
760     {
761         useTransform = true;
762     }
763 
764     if (parentIndices == NULL)
765     {
766         if (useTransform)
767         {
768             nw::math::MTX34 transformMatrix;
769             nw::math::MTX34Mult(&transformMatrix, this->InverseWorldMatrix(), emitterMatrix);
770 
771             u16* activeIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_FRONT);
772 
773             math::VEC3* translate =
774                 (math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_FRONT);
775 
776             math::VEC3* velocity =
777                 (math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_VELOCITY, PARTICLE_BUFFER_FRONT);
778 
779             u16* pActiveIndex = activeIndex + startIndex;
780             for (int i = 0; i < particleCount; ++i)
781             {
782                 int dstIndex = *pActiveIndex;
783                 pActiveIndex += incrIndex;
784 
785                 nw::math::VEC3Transform(&translate[dstIndex], transformMatrix, translate[dstIndex]);
786                 nw::math::VEC3TransformNormal(&velocity[dstIndex], transformMatrix, velocity[dstIndex]);
787             }
788         }
789     }
790     else
791     {
792         math::VEC3* parentTranslate =
793             (math::VEC3*)parentParticleSet->GetParticleCollection()->GetStreamPtr(
794             PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_FRONT);
795 
796         u16* activeIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_FRONT);
797 
798         math::VEC3* translate =
799             (math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_FRONT);
800 
801         math::VEC3* velocity =
802             (math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_VELOCITY, PARTICLE_BUFFER_FRONT);
803 
804         u16* pActiveIndex = activeIndex + startIndex;
805 
806         // 親の速度
807         bool isInheritParentVelocity = this->GetResParticleSet().GetIsInheritParentVelocity();
808 
809         math::VEC3* parentVelocity = NULL;
810         if (isInheritParentVelocity)
811         {
812             parentVelocity = (math::VEC3*)parentParticleSet->GetParticleCollection()->GetStreamPtr(
813                                     PARTICLEUSAGE_VELOCITY, PARTICLE_BUFFER_FRONT);
814         }
815 
816         if (useTransform)
817         {
818             for (int i = 0; i < particleCount; ++i)
819             {
820                 int dstIndex = *pActiveIndex;
821                 int parentIndex = parentIndices[i];
822                 pActiveIndex += incrIndex;
823 
824                 nw::math::VEC3  parentTransformedVelocity;
825                 nw::math::MTX34 workMatrix;
826 
827                 nw::math::MTX34 particleMatrix;
828                 nw::math::MTX34Identity(&particleMatrix);
829 
830                 nw::math::MTX34Translate(&particleMatrix, parentTranslate[parentIndex]);
831                 ////nw::math::MTX34RotXYZRad(&workMatrix, rotate[index].x, rotate[index].y, rotate[index].z);
832                 ////nw::math::MTX34Mult(&particleMatrix, particleMatrix, workMatrix);
833                 ////nw::math::MTX34Scale(&workMatrix, scale[index]);
834                 ////nw::math::MTX34Mult(&particleMatrix, particleMatrix, workMatrix);
835 
836                 nw::math::MTX34 transformMatrix;
837                 nw::math::MTX34Mult(&transformMatrix, this->InverseWorldMatrix(), emitterMatrix);
838                 nw::math::MTX34Mult(&workMatrix, transformMatrix, particleMatrix);
839 
840                 nw::math::VEC3Transform(&translate[dstIndex], workMatrix, translate[dstIndex]);
841 
842                 // 親からの継承処理
843                 if (isInheritParentVelocity)
844                 {
845                     // 速度の継承
846                     velocity[dstIndex] += parentVelocity[parentIndex];
847                     nw::math::VEC3TransformNormal(&velocity[dstIndex], workMatrix, velocity[dstIndex]);
848 
849                     // NW4R相当の機能では、速度以外にスケール・ローテート・アルファ・カラーがあります。
850                 }
851                 else
852                 {
853                     nw::math::VEC3TransformNormal(&velocity[dstIndex], workMatrix, velocity[dstIndex]);
854                 }
855             }
856         }
857         else
858         {
859             for (int i = 0; i < particleCount; ++i)
860             {
861                 int dstIndex = *pActiveIndex;
862                 int parentIndex = parentIndices[i];
863                 pActiveIndex += incrIndex;
864 
865                 translate[dstIndex] += parentTranslate[parentIndex];
866 
867                 // 親からの継承処理
868                 if (isInheritParentVelocity)
869                 {
870                     // 速度の継承
871                     velocity[dstIndex] += parentVelocity[parentIndex];
872 
873                     // NW4R相当の機能では、速度以外にスケール・ローテート・アルファ・カラーがあります。
874                 }
875             }
876         }
877     }
878 }
879 #else
880 //----------------------------------------
881 int
AddParticles(int particleCount)882 ParticleSet::AddParticles(
883     int particleCount
884 )
885 {
886     ParticleCollection* collection = this->GetParticleCollection();
887 
888     const int collectionCount = collection->GetCount();
889     const int collectionCapacity = collection->GetCapacity();
890 
891     int freeSize = collectionCapacity - collectionCount;
892     if (particleCount > freeSize)
893     {
894         particleCount = freeSize;
895     }
896 
897     if (particleCount <= 0)
898     {
899         return 0;
900     }
901 
902     const bool isAscendingOrder = this->IsAscendingOrder();
903 
904     ParticleModel* model = static_cast<ParticleModel*>(this->GetParent());
905     NW_NULL_ASSERT(model);
906     ParticleTime time = model->ParticleAnimFrameController().GetFrame();
907 
908     u16* activeIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_FRONT);
909     NW_NULL_ASSERT(activeIndex);
910 
911     const int startIndex = (isAscendingOrder)? collection->GetCount() : collection->GetCapacity() - collection->GetCount() - 1;
912     const int incrIndex = (isAscendingOrder)? 1 : -1;
913 
914     u16* pFreeIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_FREEINDEX, PARTICLE_BUFFER_FRONT);
915     NW_NULL_ASSERT(pFreeIndex);
916     pFreeIndex += collection->GetCapacity() - collection->GetCount() - 1;
917 
918     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
919     NW_NULL_ASSERT(birth);
920 
921     nw::math::VEC3* velocity = (nw::math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_VELOCITY, PARTICLE_BUFFER_FRONT);
922     NW_NULL_ASSERT(velocity);
923 
924     int minIndex = collection->GetMinActiveIndex();
925     int maxIndex = collection->GetMaxActiveIndex();
926 
927     u16* pActiveIndex = activeIndex + startIndex;
928     for (int i = particleCount; i != 0; --i)
929     {
930         int nextIndex = *pFreeIndex;
931         --pFreeIndex;
932 
933         *pActiveIndex = nextIndex;
934         pActiveIndex += incrIndex;
935 
936         if (minIndex > nextIndex)
937         {
938             minIndex = nextIndex;
939         }
940 
941         if (maxIndex < nextIndex)
942         {
943             maxIndex = nextIndex;
944         }
945 
946         birth[nextIndex] = time;
947         velocity[nextIndex].x = 0.0f;
948         velocity[nextIndex].y = 0.0f;
949         velocity[nextIndex].z = 0.0f;
950     }
951 
952     collection->SetMinActiveIndex(minIndex);
953     collection->SetMaxActiveIndex(maxIndex);
954 
955     collection->SetCount(collectionCount + particleCount);
956 
957     return particleCount;
958 }
959 #endif
960 
961 //----------------------------------------
962 void
InitializeParticles(int startIndex,int count,int incrIndex,ParticleTime time)963 ParticleSet::InitializeParticles(
964     int startIndex,
965     int count,
966     int incrIndex,
967     ParticleTime time
968 )
969 {
970     ParticleCollection* collection = this->GetParticleCollection();
971 
972     u16* activeIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_FRONT);
973     activeIndex += startIndex;
974 
975     ut::MoveArray<Initializer>::iterator endIter = this->m_Initializers.end();
976     for (ut::MoveArray<Initializer>::iterator iter = this->m_Initializers.begin(); iter != endIter;)
977     {
978         Initializer& workInitializer = *iter++;
979         if (workInitializer.resource == NULL)
980         {
981             continue;
982         }
983 
984         const ResParticleInitializer initializer(workInitializer.resource);
985 
986         if (!initializer.GetInitializerEnabled())
987         {
988             continue;
989         }
990 
991         void* targetStream;
992         if (collection->GetBufferSide())
993         {
994             targetStream = workInitializer.m_TargetStreams[1];
995         }
996         else
997         {
998             targetStream = workInitializer.m_TargetStreams[0];
999         }
1000 
1001         switch (workInitializer.m_Type)
1002         {
1003         case ResParticleFloatImmediateInitializer::TYPE_INFO:
1004             {
1005                 NW_PARTICLE_PROFILE_START("ParticleFloatImmediateInitializer");
1006 
1007                 ResParticleFloatImmediateInitializer floatInitializer(initializer.ptr());
1008                 NW_ASSERT(floatInitializer.IsValid());
1009 
1010                 f32* storagePtr = (f32*)targetStream;
1011 
1012                 const f32 value = floatInitializer.GetImmediateValue();
1013 
1014                 u16* pActiveIndex = activeIndex;
1015                 for (int j = count; j != 0; --j)
1016                 {
1017                     int index = *pActiveIndex;
1018                     pActiveIndex += incrIndex;
1019 
1020                     storagePtr[index] = value;
1021                 }
1022 
1023                 NW_PARTICLE_PROFILE_STOP();
1024             }
1025             break;
1026         case ResParticleVector2ImmediateInitializer::TYPE_INFO:
1027             {
1028                 NW_PARTICLE_PROFILE_START("ParticleVector2ImmediateInitializer");
1029 
1030                 ResParticleVector2ImmediateInitializer vec2Initializer(initializer.ptr());
1031                 NW_ASSERT(vec2Initializer.IsValid());
1032 
1033                 nw::math::VEC2* storagePtr = (nw::math::VEC2*)targetStream;
1034 
1035                 const nw::math::VEC2 value = vec2Initializer.GetImmediateValue();
1036 
1037                 u16* pActiveIndex = activeIndex;
1038                 for (int j = count; j != 0; --j)
1039                 {
1040                     int index = *pActiveIndex;
1041                     pActiveIndex += incrIndex;
1042 
1043                     storagePtr[index] = value;
1044                 }
1045 
1046                 NW_PARTICLE_PROFILE_STOP();
1047             }
1048 
1049             break;
1050         case ResParticleVector3ImmediateInitializer::TYPE_INFO:
1051             {
1052                 NW_PARTICLE_PROFILE_START("ParticleVector3ImmediateInitializer");
1053 
1054                 ResParticleVector3ImmediateInitializer vec3Initializer(initializer.ptr());
1055                 NW_ASSERT(vec3Initializer.IsValid());
1056 
1057                 nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
1058                 NW_NULL_ASSERT(storagePtr);
1059 
1060                 const nw::math::VEC3 value = vec3Initializer.GetImmediateValue();
1061 
1062                 u16* pActiveIndex = activeIndex;
1063                 for (int j = count; j != 0; --j)
1064                 {
1065                     int index = *pActiveIndex;
1066                     pActiveIndex += incrIndex;
1067 
1068                     storagePtr[index] = value;
1069                 }
1070 
1071                 NW_PARTICLE_PROFILE_STOP();
1072             }
1073             break;
1074         case ResParticleFloatRandomInitializer::TYPE_INFO:
1075             {
1076                 NW_PARTICLE_PROFILE_START("ParticleFloatRandomInitializer");
1077 
1078                 ResParticleFloatRandomInitializer floatInitializer(initializer.ptr());
1079                 NW_ASSERT(floatInitializer.IsValid());
1080 
1081                 f32* storagePtr = (f32*)targetStream;
1082                 NW_NULL_ASSERT(storagePtr);
1083 
1084                 const f32 baseValue = floatInitializer.GetBaseValue();
1085                 const f32 random = floatInitializer.GetRandom();
1086 
1087                 u16* pActiveIndex = activeIndex;
1088                 for (int j = count; j != 0; --j)
1089                 {
1090                     int index = *pActiveIndex;
1091                     pActiveIndex += incrIndex;
1092 
1093                     f32 value = baseValue;
1094 
1095                     if (random != 0.0f)
1096                     {
1097                         value += value * this->m_ParticleRandom.NextFloatSignedOne() * random;
1098                     }
1099 
1100                     storagePtr[index] = value;
1101                 }
1102 
1103                 NW_PARTICLE_PROFILE_STOP();
1104             }
1105             break;
1106         case ResParticleDirectionalVelocityInitializer::TYPE_INFO:
1107             {
1108                 NW_PARTICLE_PROFILE_START("ParticleDirectionalVelocityInitializer");
1109 
1110                 ResParticleDirectionalVelocityInitializer velInitializer(initializer.ptr());
1111                 NW_ASSERT(velInitializer.IsValid());
1112 
1113                 nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
1114                 NW_NULL_ASSERT(storagePtr);
1115 
1116                 const nw::math::VEC3 direction = velInitializer.GetDirection();
1117                 const f32 power = velInitializer.GetPower();
1118 
1119                 nw::math::VEC3 velocity = direction;
1120                 velocity *= power;
1121 
1122                 u16* pActiveIndex = activeIndex;
1123                 for (int j = count; j != 0; --j)
1124                 {
1125                     int index = *pActiveIndex;
1126                     pActiveIndex += incrIndex;
1127 
1128                     storagePtr[index] += velocity;
1129                 }
1130 
1131                 NW_PARTICLE_PROFILE_STOP();
1132             }
1133             break;
1134         case ResParticleRandomDirectionalVelocityInitializer::TYPE_INFO:
1135             {
1136                 #define PARTICLE_CUSTUM_EPSILON   0.0001f
1137 
1138                 NW_PARTICLE_PROFILE_START("ParticleRandomDirectionalVelocityInitializer");
1139 
1140                 ResParticleRandomDirectionalVelocityInitializer velInitializer(initializer.ptr());
1141                 NW_ASSERT(velInitializer.IsValid());
1142 
1143                 nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
1144                 NW_NULL_ASSERT(storagePtr);
1145 
1146                 nw::math::VEC3 direction = velInitializer.GetDirection();
1147                 // direction が不正な場合は処理を行わない
1148                 if (direction.x == 0.f && direction.y == 0.f && direction.z == 0.f )
1149                 {
1150                     break;
1151                 }
1152 
1153                 const f32 power = velInitializer.GetPower();
1154                 const f32 angle = velInitializer.GetAngle();
1155                 f32 sin, cos;
1156 
1157                 // 変換行列のパラメータを計算
1158                 f32 sx = direction.z;
1159                 NW_ASSERT(sx <= 1.0f);
1160 
1161                 f32 cx = 1.0f - sx * sx;
1162                 f32 divcx;
1163                 if (cx >= PARTICLE_CUSTUM_EPSILON)
1164                 {
1165                     divcx = math::FrSqrt(cx);
1166                 }
1167                 else
1168                 {
1169                     // 誤差等の対策
1170                     divcx = 0.0f;
1171                 }
1172                 cx = cx * divcx;
1173 
1174                 f32 sz;
1175                 f32 cz;
1176 
1177                 if (cx == 0.0f)
1178                 {
1179                     sz = 0.0f;
1180                     cz = 1.0f;
1181                 }
1182                 else
1183                 {
1184                     sz = direction.x * -divcx;
1185                     cz = direction.y * divcx;
1186                 }
1187 
1188                 f32 sxsz = sx * sz;
1189                 f32 msxcz = -sx * cz;
1190 
1191                 // (0,1,0)を基準にランダムを適用した円錐状ベクトルを生成する
1192                 nw::math::VEC3 velocity;
1193 
1194                 u16* pActiveIndex = activeIndex;
1195 
1196                 for (int j = count; j != 0; --j)
1197                 {
1198                     nn::math::SinCosRad(&sin, &cos, nw::math::F_PI/2.f - (angle * this->m_ParticleRandom.NextFloatSignedOne()));
1199                     velocity.x = cos;
1200                     velocity.y = sin;
1201                     velocity.z = 0.0f;
1202 
1203                     f32 rad = velocity.x;
1204                     nn::math::SinCosRad(&sin, &cos, 2.0f * nw::math::F_PI * this->m_ParticleRandom.NextFloatSignedOne());
1205                     velocity.x = rad * cos;
1206                     velocity.z = rad * sin;
1207 
1208                     nw::math::VEC3 tempv;
1209 
1210                     tempv.x =
1211                         velocity.x * cz +
1212                         velocity.y * direction.x +
1213                         velocity.z * sxsz;
1214 
1215                     tempv.y =
1216                         velocity.x * sz +
1217                         velocity.y * direction.y +
1218                         velocity.z * msxcz;
1219 
1220                     tempv.z =
1221                         velocity.y * direction.z +
1222                         velocity.z * cx;
1223 
1224                     velocity = tempv * power;
1225 
1226                     int index = *pActiveIndex;
1227                     pActiveIndex += incrIndex;
1228 
1229                     storagePtr[index] += velocity;
1230                 }
1231 
1232                 NW_PARTICLE_PROFILE_STOP();
1233             }
1234             break;
1235         case ResParticleOriginVelocityInitializer::TYPE_INFO:
1236             {
1237                 NW_PARTICLE_PROFILE_START("ParticleOriginVelocityInitializer");
1238 
1239                 ResParticleOriginVelocityInitializer velInitializer(initializer.ptr());
1240                 NW_ASSERT(velInitializer.IsValid());
1241 
1242                 nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
1243                 NW_NULL_ASSERT(storagePtr);
1244 
1245                 nw::math::VEC3* trans = (nw::math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_FRONT);
1246                 NW_NULL_ASSERT(trans);
1247 
1248                 const f32 power = velInitializer.GetPower();
1249 
1250                 u16* pActiveIndex = activeIndex;
1251                 for (int j = count; j != 0; --j)
1252                 {
1253                     int index = *pActiveIndex;
1254                     pActiveIndex += incrIndex;
1255 
1256                     nw::math::VEC3 velocity = trans[index];
1257                     velocity.SafeNormalize(nw::math::VEC3(0, 0, 0));
1258                     velocity *= power;
1259 
1260                     storagePtr[index] += velocity;
1261                 }
1262 
1263                 NW_PARTICLE_PROFILE_STOP();
1264             }
1265             break;
1266         case ResParticleRandomVelocityInitializer::TYPE_INFO:
1267             {
1268                 NW_PARTICLE_PROFILE_START("ParticleRandomVelocityInitializer");
1269 
1270                 ResParticleRandomVelocityInitializer velInitializer(initializer.ptr());
1271                 NW_ASSERT(velInitializer.IsValid());
1272 
1273                 nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
1274                 NW_NULL_ASSERT(storagePtr);
1275 
1276                 const f32 power = velInitializer.GetPower();
1277 
1278                 u16* pActiveIndex = activeIndex;
1279                 for (int j = count; j != 0; --j)
1280                 {
1281                     int index = *pActiveIndex;
1282                     pActiveIndex += incrIndex;
1283 
1284                     nw::math::VEC3 velocity(0.0f, 0.0f, 0.0f);
1285 
1286                     f32 yaw = this->m_ParticleRandom.NextFloat() * 2.0f * nw::math::F_PI;
1287                     f32 pitch = this->m_ParticleRandom.NextFloatSignedHalf() * nw::math::F_PI;
1288 
1289                     f32 sinYaw = 0.0f;
1290                     f32 cosYaw = 1.0f;
1291                     if (yaw != 0.0f)
1292                     {
1293                         nw::math::SinCosRad(&sinYaw, &cosYaw, yaw);
1294                     }
1295 
1296                     f32 sinPitch = 0.0f;
1297                     f32 cosPitch = 1.0f;
1298                     if (pitch != 0.0f)
1299                     {
1300                         nw::math::SinCosRad(&sinPitch, &cosPitch, pitch);
1301                     }
1302 
1303                     velocity.x = sinYaw * -cosPitch;
1304                     velocity.y = -sinPitch;
1305                     velocity.z = cosYaw * cosPitch;
1306 
1307                     velocity *= power;
1308 
1309                     storagePtr[index] += velocity;
1310                 }
1311 
1312                 NW_PARTICLE_PROFILE_STOP();
1313             }
1314             break;
1315         case ResParticleYAxisVelocityInitializer::TYPE_INFO:
1316             {
1317                 NW_PARTICLE_PROFILE_START("ParticleYAxisVelocityInitializer");
1318 
1319                 ResParticleYAxisVelocityInitializer velInitializer(initializer.ptr());
1320                 NW_ASSERT(velInitializer.IsValid());
1321 
1322                 nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
1323                 NW_NULL_ASSERT(storagePtr);
1324 
1325                 nw::math::VEC3* trans = (nw::math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_FRONT);
1326 
1327                 const f32 power = velInitializer.GetPower();
1328 
1329                 u16* pActiveIndex = activeIndex;
1330                 for (int j = count; j != 0; --j)
1331                 {
1332                     int index = *pActiveIndex;
1333                     pActiveIndex += incrIndex;
1334 
1335                     nw::math::VEC3 velocity(trans[index].x, 0.0f, trans[index].z);
1336                     velocity.SafeNormalize(nw::math::VEC3(0, 0, 0));
1337                     velocity *= power;
1338 
1339                     storagePtr[index] += velocity;
1340                 }
1341 
1342                 NW_PARTICLE_PROFILE_STOP();
1343             }
1344             break;
1345         case ResParticleVector3Random1Initializer::TYPE_INFO:
1346             {
1347                 NW_PARTICLE_PROFILE_START("ParticleVector3Random1Initializer");
1348 
1349                 ResParticleVector3Random1Initializer vec3Initializer(initializer.ptr());
1350                 NW_ASSERT(vec3Initializer.IsValid());
1351 
1352                 nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
1353                 NW_NULL_ASSERT(storagePtr);
1354 
1355                 const nw::math::VEC3 baseValue = vec3Initializer.GetBaseValue();
1356                 const f32 random = vec3Initializer.GetRandom();
1357 
1358                 u16* pActiveIndex = activeIndex;
1359                 for (int j = count; j != 0; --j)
1360                 {
1361                     int index = *pActiveIndex;
1362                     pActiveIndex += incrIndex;
1363 
1364                     nw::math::VEC3 value(baseValue);
1365 
1366                     if (random != 0.0f)
1367                     {
1368                         f32 floatRandom = this->m_ParticleRandom.NextFloatSignedOne();
1369                         floatRandom *= random;
1370 
1371                         value.x += value.x * floatRandom;
1372                         value.y += value.y * floatRandom;
1373                         value.z += value.z * floatRandom;
1374                     }
1375 
1376                     storagePtr[index] = value;
1377                 }
1378 
1379                 NW_PARTICLE_PROFILE_STOP();
1380             }
1381             break;
1382         case ResParticleVector3Random3Initializer::TYPE_INFO:
1383             {
1384                 NW_PARTICLE_PROFILE_START("ParticleVector3Random3Initializer");
1385 
1386                 ResParticleVector3Random3Initializer vec3Initializer(initializer.ptr());
1387                 NW_ASSERT(vec3Initializer.IsValid());
1388 
1389                 nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
1390                 NW_NULL_ASSERT(storagePtr);
1391 
1392                 const nw::math::VEC3 baseValue = vec3Initializer.GetBaseValue();
1393                 const nw::math::VEC3 random = vec3Initializer.GetRandom();
1394 
1395                 u16* pActiveIndex = activeIndex;
1396                 for (int j = count; j != 0; --j)
1397                 {
1398                     int index = *pActiveIndex;
1399                     pActiveIndex += incrIndex;
1400 
1401                     nw::math::VEC3 value(baseValue);
1402 
1403                     if (random.x != 0.0f)
1404                     {
1405                         f32 floatRandom = this->m_ParticleRandom.NextFloatSignedOne();
1406                         floatRandom *= random.x;
1407                         value.x += value.x * floatRandom;
1408                     }
1409 
1410                     if (random.y != 0.0f)
1411                     {
1412                         f32 floatRandom = this->m_ParticleRandom.NextFloatSignedOne();
1413                         floatRandom *= random.y;
1414                         value.y += value.y * floatRandom;
1415                     }
1416 
1417                     if (random.z != 0.0f)
1418                     {
1419                         f32 floatRandom = this->m_ParticleRandom.NextFloatSignedOne();
1420                         floatRandom *= random.z;
1421                         value.z += value.z * floatRandom;
1422                     }
1423 
1424                     storagePtr[index] = value;
1425                 }
1426 
1427                 NW_PARTICLE_PROFILE_STOP();
1428             }
1429             break;
1430         case ResParticleVector3MultRandomInitializer::TYPE_INFO:
1431             {
1432                 NW_PARTICLE_PROFILE_START("ParticleVector3MultRandomInitializer");
1433 
1434                 ResParticleVector3MultRandomInitializer vec3Initializer(initializer.ptr());
1435                 NW_ASSERT(vec3Initializer.IsValid());
1436 
1437                 nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
1438                 NW_NULL_ASSERT(storagePtr);
1439 
1440                 const f32 random = vec3Initializer.GetRandom();
1441 
1442                 u16* pActiveIndex = activeIndex;
1443                 for (int j = count; j != 0; --j)
1444                 {
1445                     int index = *pActiveIndex;
1446                     pActiveIndex += incrIndex;
1447 
1448                     f32 floatRandom = this->m_ParticleRandom.NextFloatSignedOne();
1449                     floatRandom = 1.0f + (floatRandom * random);
1450 
1451                     storagePtr[index].x *= floatRandom;
1452                     storagePtr[index].y *= floatRandom;
1453                     storagePtr[index].z *= floatRandom;
1454                 }
1455 
1456                 NW_PARTICLE_PROFILE_STOP();
1457             }
1458             break;
1459         case ResParticleFloatRangeRandomInitializer::TYPE_INFO:
1460             {
1461                 NW_PARTICLE_PROFILE_START("ParticleFloatRangeRandomInitializer");
1462 
1463                 ResParticleFloatRangeRandomInitializer floatInitializer(initializer.ptr());
1464                 NW_ASSERT(floatInitializer.IsValid());
1465 
1466 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1467                 ParticleTime* limit = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_NEG_TIMELIMIT, PARTICLE_BUFFER_FRONT);
1468 #endif
1469 
1470                 ParticleTime* storagePtr = (ParticleTime*)targetStream;
1471                 NW_NULL_ASSERT(storagePtr);
1472 
1473                 f32 minValue = floatInitializer.GetMinValue();
1474                 f32 maxValue = floatInitializer.GetMaxValue();
1475 
1476 #if 1
1477                 NW_ASSERT(minValue <= maxValue);
1478 #else
1479                 if (minValue > maxValue)
1480                 {
1481                     f32 swap = minValue;
1482                     minValue = maxValue;
1483                     maxValue = swap;
1484                 }
1485 #endif
1486 
1487                 f32 diff = maxValue - minValue;
1488 
1489                 u16* pActiveIndex = activeIndex;
1490                 for (int j = count; j != 0; --j)
1491                 {
1492                     int index = *pActiveIndex;
1493                     pActiveIndex += incrIndex;
1494 
1495                     f32 value = minValue + this->m_ParticleRandom.Next((int)(diff + 1));
1496 
1497                     storagePtr[index] = value;
1498 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1499                     limit[index] = -(time + value);
1500 #endif
1501                 }
1502 
1503                 NW_PARTICLE_PROFILE_STOP();
1504             }
1505             break;
1506         }
1507     }
1508 
1509 }
1510 
1511 
1512 //----------------------------------------
1513 //! @brief        アニメーションで参照すべきテーブルの位置を計算します。
1514 //! @details :private
1515 //!
1516 //! @param[in]    animationOption アニメーションオプションです。
1517 //! @param[in]    id パーティクルのIDです。
1518 //! @param[in]    birth パーティクルの生まれた時刻です。
1519 //! @param[in]    life パーティクルの寿命です。
1520 //! @param[in]    time 現在の時刻です。
1521 //! @param[in]    animationLength アニメーションの長さです。
1522 //! @param[out]   interp 次のキーと補間すべきかのフラグです。
1523 //! @param[out]   interpFactor 次のキーと補間する際の係数です。0で補間なしです。
1524 //! @param[out]   updaterIndex アップデータのインデックス番号です。
1525 //!
1526 // CALC_OPT:inline 指定へ。
1527 /*static*/inline int
CalcAnimationDataIndex(const ResParticleAnimationOption & animationOption,u32 id,ParticleTime birth,ParticleTime life,ParticleTime time,int animationLength,bool * interp,f32 * interpFactor,int updaterIndex)1528 CalcAnimationDataIndex(
1529     const ResParticleAnimationOption& animationOption,
1530     u32 id,
1531     ParticleTime birth,
1532     ParticleTime life,
1533     ParticleTime time,
1534     int animationLength,
1535     bool* interp,
1536     f32* interpFactor,
1537     int updaterIndex
1538 )
1539 {
1540     NW_NULL_ASSERT(interp);
1541     NW_NULL_ASSERT(interpFactor);
1542 
1543     ParticleTime ptclTime = animationOption.EvaluateAnimationFrame(id, birth, life, time, updaterIndex);
1544 
1545 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1546     if (ptclTime < 0)
1547 #else
1548     if (ptclTime.GetParticleTimeValue() < 0)
1549 #endif
1550     {
1551         ptclTime = 0;
1552     }
1553 
1554     if (ptclTime >= animationLength)
1555     {
1556         ptclTime = (f32)animationLength - 1;
1557     }
1558 
1559 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1560     int index = (int)ptclTime;
1561     *interpFactor = ptclTime - index;
1562 #else
1563     int index = ptclTime.GetIntegralParts();
1564     *interpFactor = ptclTime.GetFractionalParts();
1565 #endif
1566 
1567     if (*interpFactor != 0.0f)
1568     {
1569         *interp = true;
1570     }
1571     else
1572     {
1573         *interp = false;
1574     }
1575 
1576     return index;
1577 }
1578 
ParticleAccelarationUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,f32 diffTime)1579 void ParticleAccelarationUpdater(
1580     const ResParticleUpdaterData* updater,
1581     ParticleCollection* collection,
1582     f32 diffTime
1583 )
1584 {
1585     NW_PARTICLE_PROFILE_START("ParticleAccelarationUpdater");
1586 
1587     ResParticleAccelarationUpdater accelUpdater(updater);
1588     NW_ASSERT(accelUpdater.IsValid());
1589 
1590     ParticleUsage target = accelUpdater.GetTargetStream();
1591     nw::math::VEC3* storagePtr = (nw::math::VEC3*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
1592     NW_NULL_ASSERT(storagePtr);
1593 
1594     // factor = 1 - a として
1595     // 1 - difftime * a と近似します(粗めです)。
1596     f32 factor = 1.0f - diffTime * (1.0f - accelUpdater.GetFactor());
1597 
1598     const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
1599     for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
1600     {
1601         storagePtr[index] *= factor;
1602     }
1603 
1604     NW_PARTICLE_PROFILE_STOP();
1605 }
1606 
ParticleFloatImmediateUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,ParticleTime time,int updaterIndex)1607 void ParticleFloatImmediateUpdater(
1608     const ResParticleUpdaterData* updater,
1609     ParticleCollection* collection,
1610     ParticleTime time,
1611     int updaterIndex
1612 )
1613 {
1614     NW_PARTICLE_PROFILE_START("ParticleFloatImmediateUpdater");
1615 
1616     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
1617 
1618     ParticleTime* life;
1619     ParticleTime lifeParam = 1.0f;
1620     collection->GetStreamOrParameter(PARTICLEUSAGE_LIFE, &life, &lifeParam, PARTICLE_BUFFER_FRONT);
1621 
1622     int animationLength = 0;
1623     //int animationDimension = 0;
1624     //int animationStride = 0;
1625     bool* animationEnable = NULL;
1626     f32* animationData = NULL;
1627 
1628     ResParticleFloatImmediateUpdater floatUpdater(updater);
1629     NW_ASSERT(floatUpdater.IsValid());
1630 
1631     ParticleUsage target = floatUpdater.GetTargetStream();
1632     f32* storagePtr = (f32*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
1633     NW_NULL_ASSERT(storagePtr);
1634 
1635     ResParticleAnimation animation = floatUpdater.GetParticleAnimation();
1636     if (animation.IsValid())
1637     {
1638         animationLength = animation.GetAnimationLength();
1639         //animationDimension = animation.GetAnimationDimension();
1640         //animationStride = animation.GetAnimationStride();
1641         animationEnable = animation.GetAnimationEnabled();
1642         animationData = animation.GetAnimationData();
1643     }
1644 
1645     if (animationData == NULL || !animationEnable[0])
1646     {
1647         const f32 baseValue = floatUpdater.GetDefaultValue();
1648 
1649         const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
1650         for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
1651         {
1652             storagePtr[index] = baseValue;
1653         }
1654     }
1655     else
1656     {
1657         const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
1658         for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
1659         {
1660             bool interp;
1661             f32 interpFactor;
1662             int animationDataIndex;
1663 
1664             ResParticleAnimationOption animationOption = animation.GetParticleAnimationOption();
1665 
1666             animationDataIndex = CalcAnimationDataIndex(
1667                 animationOption,
1668                 index,
1669                 birth[index],
1670                 (life == NULL) ? lifeParam : life[index],
1671                 time,
1672                 animationLength,
1673                 &interp,
1674                 &interpFactor,
1675                 updaterIndex);
1676             //animationDataIndex *= animationStride;
1677 
1678             f32 value = animationData[animationDataIndex++];
1679 
1680             if (interp)
1681             {
1682                 f32 nextValue = animationData[animationDataIndex++];
1683                 value = value + (nextValue - value) * interpFactor;
1684             }
1685 
1686             storagePtr[index] = value;
1687         }
1688     }
1689 
1690     NW_PARTICLE_PROFILE_STOP();
1691 }
1692 
ParticleFloatImmediate4KeyUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,ParticleTime time)1693 void ParticleFloatImmediate4KeyUpdater(
1694     const ResParticleUpdaterData* updater,
1695     ParticleCollection* collection,
1696     ParticleTime time
1697 )
1698 {
1699     NW_PARTICLE_PROFILE_START("ParticleFloatImmediate4KeyUpdater");
1700 
1701     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
1702 
1703     ParticleTime* life;
1704     ParticleTime lifeParam = 1.0f;
1705     collection->GetStreamOrParameter(PARTICLEUSAGE_LIFE, &life, &lifeParam, PARTICLE_BUFFER_FRONT);
1706 
1707     ResParticleFloatImmediate4KeyUpdater fkeyUpdater(updater);
1708     NW_ASSERT(fkeyUpdater.IsValid());
1709 
1710     ParticleUsage target = fkeyUpdater.GetTargetStream();
1711     f32* storagePtr = (f32*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
1712     NW_NULL_ASSERT(storagePtr);
1713 
1714     register u32 inTime = fkeyUpdater.GetInTime();
1715     register u32 outTime = fkeyUpdater.GetOutTime();
1716     register s32 value0 = fkeyUpdater.GetValue0();
1717     register s32 value1 = fkeyUpdater.GetValue1();
1718     register s32 value2 = fkeyUpdater.GetValue2();
1719     register s32 value3 = fkeyUpdater.GetValue3();
1720     register s32 value4 = fkeyUpdater.GetValue4();
1721 
1722     if (life == NULL)
1723     {
1724         const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
1725         for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
1726         {
1727             ParticleTime difftime  = time - birth[index];
1728             ParticleTime ftime     = (ParticleTime)(difftime / lifeParam);
1729 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1730             u32 utime     = (u32)(ftime * 0x10000);
1731 #else
1732             u32 utime     = (u32)(ftime.GetS32Value() * 0x10000);
1733 #endif
1734 
1735             u32 value;
1736 
1737             if (utime < inTime)
1738             {
1739 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1740                 value = value2 * difftime / lifeParam + value0;
1741 #else
1742                 value = value2 * ftime.GetFloat32Value() + value0;
1743 #endif
1744             }
1745             else if (utime < outTime)
1746             {
1747                 value = value1;
1748             }
1749             else
1750             {
1751 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1752                 value = value3 * ftime + value4;
1753 #else
1754                 value = value3 * ftime.GetFloat32Value() + value4;
1755 #endif
1756             }
1757 
1758             storagePtr[index] = (f32)value / 65535.f;
1759         }
1760     }
1761     else
1762     {
1763         const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
1764         for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
1765         {
1766             ParticleTime difftime  = time - birth[index];
1767             ParticleTime ftime     = (ParticleTime)(difftime / life[index]);
1768 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1769             u32 utime     = (u32)(ftime * 0x10000);
1770 #else
1771             u32 utime     = (u32)(ftime.GetS32Value() * 0x10000);
1772 #endif
1773 
1774             u32 value;
1775 
1776             if (utime < inTime)
1777             {
1778 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1779                 value = value2 * difftime / life[index] + value0;
1780 #else
1781                 value = value2 * ftime.GetFloat32Value() + value0;
1782 #endif
1783             }
1784             else if (utime < outTime)
1785             {
1786                 value = value1;
1787             }
1788             else
1789             {
1790 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1791                 value = value3 * ftime + value4;
1792 #else
1793                 value = value3 * ftime.GetFloat32Value() + value4;
1794 #endif
1795             }
1796 
1797             storagePtr[index] = (f32)value / 65535.f;
1798         }
1799     }
1800 
1801     NW_PARTICLE_PROFILE_STOP();
1802 }
1803 
ParticleVector3Immediate4KeyUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,ParticleTime time)1804 void ParticleVector3Immediate4KeyUpdater(
1805     const ResParticleUpdaterData* updater,
1806     ParticleCollection* collection,
1807     ParticleTime time
1808 )
1809 {
1810     NW_PARTICLE_PROFILE_START("ParticleVector3Immediate4KeyUpdater");
1811 
1812     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
1813 
1814     ParticleTime* life;
1815     ParticleTime lifeParam = 1.0f;
1816     collection->GetStreamOrParameter(PARTICLEUSAGE_LIFE, &life, &lifeParam, PARTICLE_BUFFER_FRONT);
1817 
1818     ResParticleVector3Immediate4KeyUpdater fkeyUpdater(updater);
1819     NW_ASSERT(fkeyUpdater.IsValid());
1820 
1821     ParticleUsage target = fkeyUpdater.GetTargetStream();
1822     math::VEC3* storagePtr = (math::VEC3*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
1823     NW_NULL_ASSERT(storagePtr);
1824 
1825     register u32 inTime = fkeyUpdater.GetInTime();
1826     register u32 outTime = fkeyUpdater.GetOutTime();
1827     math::VEC3 value0 = fkeyUpdater.GetValue0();
1828     math::VEC3 value1 = fkeyUpdater.GetValue1();
1829     math::VEC3 value2 = fkeyUpdater.GetValue2();
1830     math::VEC3 value3 = fkeyUpdater.GetValue3();
1831     math::VEC3 value4 = fkeyUpdater.GetValue4();
1832 
1833     if (life == NULL)
1834     {
1835         const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
1836         for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
1837         {
1838             ParticleTime difftime  = time - birth[index];
1839             ParticleTime ftime     = (ParticleTime)(difftime / lifeParam);
1840 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1841             u32 utime     = (u32)(ftime * 0x10000);
1842 #else
1843             u32 utime     = (u32)(ftime.GetFloat32Value() * 0x10000);
1844 #endif
1845 
1846             math::VEC3 value;
1847 
1848             if (utime < inTime)
1849             {
1850 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1851                 value = value2 * difftime / lifeParam + value0;
1852 #else
1853                 value = value2 * ftime.GetFloat32Value() + value0;
1854 #endif
1855             }
1856             else if (utime < outTime)
1857             {
1858                 value = value1;
1859             }
1860             else
1861             {
1862 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1863                 value = value3 * ftime + value4;
1864 #else
1865                 value = value3 * ftime.GetFloat32Value() + value4;
1866 #endif
1867             }
1868 
1869             storagePtr[index] = value;
1870         }
1871     }
1872     else
1873     {
1874         const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
1875         for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
1876         {
1877             ParticleTime difftime  = time - birth[index];
1878             ParticleTime ftime     = (ParticleTime)(difftime / life[index]);
1879 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1880 
1881             u32 utime     = (u32)(ftime * 0x10000);
1882 #else
1883             u32 utime     = (u32)(ftime.GetFloat32Value() * 0x10000);
1884 #endif
1885 
1886             math::VEC3 value;
1887 
1888             if (utime < inTime)
1889             {
1890 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1891                 value = value2 * difftime / life[index] + value0;
1892 #else
1893                 value = value2 * ftime.GetFloat32Value() + value0;
1894 #endif
1895             }
1896             else if (utime < outTime)
1897             {
1898                 value = value1;
1899             }
1900             else
1901             {
1902 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1903                 value = value3 * ftime + value4;
1904 #else
1905                 value = value3 * ftime.GetFloat32Value() + value4;
1906 #endif
1907             }
1908 
1909             storagePtr[index] = value;
1910         }
1911     }
1912 
1913     NW_PARTICLE_PROFILE_STOP();
1914 }
1915 
ParticleGravityUpdater(nw::math::VEC3 * storagePtr,const ResParticleUpdaterData * updater,ParticleCollection * collection,f32 diffTime)1916 void ParticleGravityUpdater(
1917     nw::math::VEC3* storagePtr,
1918     const ResParticleUpdaterData* updater,
1919     ParticleCollection* collection,
1920     f32 diffTime
1921 )
1922 {
1923     NW_PARTICLE_PROFILE_START("ParticleGravityUpdater");
1924 
1925     NW_NULL_ASSERT(storagePtr);
1926 
1927     ResParticleGravityUpdater gravUpdater(updater);
1928     NW_ASSERT(gravUpdater.IsValid());
1929 
1930     nw::math::VEC3 velocity = gravUpdater.GetDirection();
1931     const f32 power = gravUpdater.GetPower() * diffTime;
1932 
1933 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
1934     velocity.SafeNormalize(nw::math::VEC3(0, -1, 0));
1935 #endif
1936     velocity *= power;
1937 
1938     // 存在しないパーティクルもかまわず処理することで、スループットを上げる
1939     storagePtr += collection->GetMinActiveIndex();
1940     const int count = collection->GetMaxActiveIndex() - collection->GetMinActiveIndex() + 1;
1941     internal::VEC3ArrayAddScalar(storagePtr, &velocity, count);
1942 
1943     NW_PARTICLE_PROFILE_STOP();
1944 }
1945 
ParticleSpinUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,f32 diffTime)1946 void ParticleSpinUpdater(
1947     const ResParticleUpdaterData* updater,
1948     ParticleCollection* collection,
1949     f32 diffTime
1950 )
1951 {
1952     NW_PARTICLE_PROFILE_START("ParticleSpinUpdater");
1953 
1954     ResParticleSpinUpdater spinUpdater(updater);
1955     NW_ASSERT(spinUpdater.IsValid());
1956 
1957     ParticleUsage target = spinUpdater.GetTargetStream();
1958     nw::math::VEC3* storagePtr = (nw::math::VEC3*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
1959     NW_NULL_ASSERT(storagePtr);
1960 
1961     const nw::math::VEC3 axis = spinUpdater.GetAxis();
1962     const f32 power = spinUpdater.GetPower() * diffTime;
1963 
1964     if (power != 0.0f && !axis.IsZero())
1965     {
1966         nw::math::MTX34 matrix;
1967         nw::math::MTX34RotAxisRad(&matrix, &axis, power);
1968 
1969         nw::math::VEC3 value;
1970 
1971         const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
1972         for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
1973         {
1974             nw::math::VEC3TransformNormal(&value, matrix, storagePtr[index]);
1975             // CALC_OPT:展開することで、valueが確定する前からコピーが始まる。
1976 //            storagePtr[index] = value;
1977             storagePtr[index].x = value.x;
1978             storagePtr[index].y = value.y;
1979             storagePtr[index].z = value.z;
1980         }
1981     }
1982 
1983     NW_PARTICLE_PROFILE_STOP();
1984 }
1985 
ParticleRandomUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,ParticleTime time,ParticleTime prevTime,ParticleRandom & random)1986 void ParticleRandomUpdater(
1987     const ResParticleUpdaterData* updater,
1988     ParticleCollection* collection,
1989     ParticleTime time,
1990     ParticleTime prevTime,
1991     ParticleRandom& random
1992 )
1993 {
1994     NW_PARTICLE_PROFILE_START("ParticleRandomUpdater");
1995 
1996     // 時間経過が無ければ処理をしない。
1997     if (time == prevTime) return;
1998 
1999     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
2000 
2001     ParticleTime* life;
2002     ParticleTime lifeParam = 1.0f;
2003     collection->GetStreamOrParameter(PARTICLEUSAGE_LIFE, &life, &lifeParam, PARTICLE_BUFFER_FRONT);
2004 
2005     ResParticleRandomUpdater randomUpdater(updater);
2006     NW_ASSERT(randomUpdater.IsValid());
2007 
2008     ParticleUsage target = randomUpdater.GetTargetStream();
2009     nw::math::VEC3* storagePtr = (nw::math::VEC3*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
2010     NW_NULL_ASSERT(storagePtr);
2011 
2012 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2013     f32 processCount = math::FFloor(time) - math::FCeil(prevTime) + 1;
2014 #else
2015     f32 processCount = time.Floor() - prevTime.Ceil() + 1;
2016 #endif
2017     if (processCount > 0) // 整数を跨いでいないならいずれにしろ実行することはない
2018     {
2019         const s32 interval = randomUpdater.GetInterval();
2020         if (interval <= 1) // 毎フレーム
2021         {
2022             const nw::math::VEC3 power = randomUpdater.GetPower() * processCount;
2023 
2024             const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
2025             for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
2026             {
2027                 storagePtr[index].x += power.x * random.NextFloatSignedOne();
2028                 storagePtr[index].y += power.y * random.NextFloatSignedOne();
2029                 storagePtr[index].z += power.z * random.NextFloatSignedOne();
2030             }
2031         }
2032         else // インターバルあり
2033         {
2034             const nw::math::VEC3 power = randomUpdater.GetPower() * processCount;
2035 
2036             nw::math::VEC3 value;
2037 
2038             const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
2039             for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
2040             {
2041                 // 粒子ごとに再計算
2042 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2043                 processCount =
2044                     math::FFloor((time - birth[index]) / interval)
2045                     - math::FCeil((prevTime - birth[index]) / interval)
2046                     + 1;
2047 #else
2048                 ParticleTime time_birth = time - birth[index];
2049                 ParticleTime prev_birth = prevTime - birth[index];
2050                 processCount =
2051                     math::FFloor(time_birth.GetFloat32Value() / interval)
2052                     - math::FCeil(prev_birth.GetFloat32Value() / interval)
2053                     + 1;
2054 #endif
2055 
2056                 if (processCount > 0)
2057                 {
2058                     storagePtr[index].x += power.x * random.NextFloatSignedOne() * processCount;
2059                     storagePtr[index].y += power.y * random.NextFloatSignedOne() * processCount;
2060                     storagePtr[index].z += power.z * random.NextFloatSignedOne() * processCount;
2061                 }
2062             }
2063         }
2064     }
2065 
2066     NW_PARTICLE_PROFILE_STOP();
2067 }
2068 
ParticleVector2ImmediateUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,ParticleTime time,int updaterIndex)2069 void ParticleVector2ImmediateUpdater(
2070     const ResParticleUpdaterData* updater,
2071     ParticleCollection* collection,
2072     ParticleTime time,
2073     int updaterIndex
2074 )
2075 {
2076     NW_PARTICLE_PROFILE_START("ParticleVector2ImmediateUpdater");
2077 
2078     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
2079 
2080     ParticleTime* life;
2081     ParticleTime lifeParam = 1.0f;
2082     collection->GetStreamOrParameter(PARTICLEUSAGE_LIFE, &life, &lifeParam, PARTICLE_BUFFER_FRONT);
2083 
2084     int animationLength = 0;
2085     //int animationDimension = 0;
2086     int animationStride = 0;
2087     bool* animationEnable = NULL;
2088     f32* animationData = NULL;
2089 
2090     ResParticleVector2ImmediateUpdater vec2Updater(updater);
2091     NW_ASSERT(vec2Updater.IsValid());
2092 
2093     ResParticleAnimation animation = vec2Updater.GetParticleAnimation();
2094     if (animation.IsValid())
2095     {
2096         animationLength = animation.GetAnimationLength();
2097         //animationDimension = animation.GetAnimationDimension();
2098         animationStride = animation.GetAnimationStride();
2099         animationEnable = animation.GetAnimationEnabled();
2100         animationData = animation.GetAnimationData();
2101     }
2102 
2103     ParticleUsage target = vec2Updater.GetTargetStream();
2104     nw::math::VEC2* storagePtr = (nw::math::VEC2*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
2105     NW_NULL_ASSERT(storagePtr);
2106 
2107     const nw::math::VEC2 defaultValue = vec2Updater.GetDefaultValue();
2108 
2109     const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
2110     for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
2111     {
2112         nw::math::VEC2 value = defaultValue;
2113 
2114         bool interp;
2115         f32 interpFactor;
2116         int animationDataIndex;
2117 
2118         if (animationData != NULL)
2119         {
2120             ResParticleAnimationOption animationOption = animation.GetParticleAnimationOption();
2121 
2122             animationDataIndex = CalcAnimationDataIndex(
2123                 animationOption,
2124                 index,
2125                 birth[index],
2126                 (life == NULL) ? lifeParam : life[index],
2127                 time,
2128                 animationLength,
2129                 &interp,
2130                 &interpFactor,
2131                 updaterIndex);
2132             animationDataIndex *= animationStride;
2133 
2134             if (animationEnable[0])
2135             {
2136                 value.x = animationData[animationDataIndex++];
2137             }
2138 
2139             if (animationEnable[1])
2140             {
2141                 value.y = animationData[animationDataIndex++];
2142             }
2143 
2144             if (interp)
2145             {
2146                 if (animationEnable[0])
2147                 {
2148                     f32 nextValue = animationData[animationDataIndex++];
2149                     value.x = value.x + (nextValue - value.x) * interpFactor;
2150                 }
2151 
2152                 if (animationEnable[1])
2153                 {
2154                     f32 nextValue = animationData[animationDataIndex++];
2155                     value.y = value.y + (nextValue - value.y) * interpFactor;
2156                 }
2157             }
2158         }
2159 
2160         storagePtr[index] = value;
2161     }
2162 
2163     NW_PARTICLE_PROFILE_STOP();
2164 }
2165 
ParticleVector3AdditiveUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,ParticleTime time,f32 diffTime,int updaterIndex)2166 void ParticleVector3AdditiveUpdater(
2167     const ResParticleUpdaterData* updater,
2168     ParticleCollection* collection,
2169     ParticleTime time,
2170     f32 diffTime,
2171     int updaterIndex
2172 )
2173 {
2174     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
2175 
2176     ParticleTime* life;
2177     ParticleTime lifeParam = 1.0f;
2178     collection->GetStreamOrParameter(PARTICLEUSAGE_LIFE, &life, &lifeParam, PARTICLE_BUFFER_FRONT);
2179 
2180     int animationLength = 0;
2181     //int animationDimension = 0;
2182     int animationStride = 0;
2183     bool* animationEnable = NULL;
2184     f32* animationData = NULL;
2185 
2186     ResParticleVector3AdditiveUpdater vec3Updater(updater);
2187     NW_ASSERT(vec3Updater.IsValid());
2188 
2189     ParticleUsage target = vec3Updater.GetTargetStream();
2190     nw::math::VEC3* storagePtr = (nw::math::VEC3*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
2191     NW_NULL_ASSERT(storagePtr);
2192 
2193     const nw::math::VEC3 defaultValue = vec3Updater.GetDefaultValue();
2194 
2195     ResParticleAnimation animation = vec3Updater.GetParticleAnimation();
2196     if (animation.IsValid())
2197     {
2198         animationLength = animation.GetAnimationLength();
2199         //animationDimension = animation.GetAnimationDimension();
2200         animationStride = animation.GetAnimationStride();
2201         animationEnable = animation.GetAnimationEnabled();
2202         animationData = animation.GetAnimationData();
2203     }
2204 
2205     const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
2206     for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
2207     {
2208         // CALC_OPT:コピーをわけることで、適切なタイミングでコピーが実行される模様。
2209         register nw::math::VEC3 value;
2210         value.x = defaultValue.x;
2211         value.y = defaultValue.y;
2212         value.z = defaultValue.z;
2213 
2214         bool interp;
2215         f32 interpFactor;
2216         int animationDataIndex;
2217 
2218         // CALC_OPT:カーブ無しデータはここまで処理がこない。
2219 //        if (animationData != NULL)
2220         {
2221             ResParticleAnimationOption animationOption = animation.GetParticleAnimationOption();
2222 
2223             animationDataIndex = CalcAnimationDataIndex(
2224                 animationOption,
2225                 index,
2226                 birth[index],
2227                 (life == NULL) ? lifeParam : life[index],
2228                 time,
2229                 animationLength,
2230                 &interp,
2231                 &interpFactor,
2232                 updaterIndex);
2233             animationDataIndex *= animationStride;
2234 
2235             if (animationEnable[0])
2236             {
2237                 value.x = animationData[animationDataIndex++];
2238             }
2239 
2240             if (animationEnable[1])
2241             {
2242                 value.y = animationData[animationDataIndex++];
2243             }
2244 
2245             if (animationEnable[2])
2246             {
2247                 value.z = animationData[animationDataIndex++];
2248             }
2249 
2250             if (interp)
2251             {
2252                 if (animationEnable[0])
2253                 {
2254                     f32 nextValue = animationData[animationDataIndex++];
2255                     value.x = value.x + (nextValue - value.x) * interpFactor;
2256                 }
2257 
2258                 if (animationEnable[1])
2259                 {
2260                     f32 nextValue = animationData[animationDataIndex++];
2261                     value.y = value.y + (nextValue - value.y) * interpFactor;
2262                 }
2263 
2264                 if (animationEnable[2])
2265                 {
2266                     f32 nextValue = animationData[animationDataIndex++];
2267                     value.z = value.z + (nextValue - value.z) * interpFactor;
2268                 }
2269             }
2270         }
2271 
2272         storagePtr[index].x += value.x * diffTime;
2273         storagePtr[index].y += value.y * diffTime;
2274         storagePtr[index].z += value.z * diffTime;
2275     }
2276 }
2277 
2278 
ParticleVector3ImmediateUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,ParticleTime time,int updaterIndex)2279 void ParticleVector3ImmediateUpdater(
2280     const ResParticleUpdaterData* updater,
2281     ParticleCollection* collection,
2282     ParticleTime time,
2283     int updaterIndex
2284 )
2285 {
2286     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
2287 
2288     ParticleTime* life;
2289     ParticleTime lifeParam = 1.0f;
2290     collection->GetStreamOrParameter(PARTICLEUSAGE_LIFE, &life, &lifeParam, PARTICLE_BUFFER_FRONT);
2291 
2292     int animationLength = 0;
2293     //int animationDimension = 0;
2294     int animationStride = 0;
2295     bool* animationEnable = NULL;
2296     f32* animationData = NULL;
2297 
2298     ResParticleVector3ImmediateUpdater vec3Updater(updater);
2299     NW_ASSERT(vec3Updater.IsValid());
2300 
2301     ResParticleAnimation animation = vec3Updater.GetParticleAnimation();
2302     if (animation.IsValid())
2303     {
2304         animationLength = animation.GetAnimationLength();
2305         //animationDimension = animation.GetAnimationDimension();
2306         animationStride = animation.GetAnimationStride();
2307         animationEnable = animation.GetAnimationEnabled();
2308         animationData = animation.GetAnimationData();
2309     }
2310 
2311     ParticleUsage target = vec3Updater.GetTargetStream();
2312     nw::math::VEC3* storagePtr = (nw::math::VEC3*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
2313     NW_NULL_ASSERT(storagePtr);
2314 
2315     const nw::math::VEC3 defaultValue = vec3Updater.GetDefaultValue();
2316 
2317     const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
2318     for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
2319     {
2320         nw::math::VEC3 value = defaultValue;
2321 
2322         bool interp;
2323         f32 interpFactor;
2324         int animationDataIndex;
2325 
2326         // CALC_OPT:カーブ無しデータはここまで処理がこない。
2327 //        if (animationData != NULL)
2328         {
2329             ResParticleAnimationOption animationOption = animation.GetParticleAnimationOption();
2330 
2331             animationDataIndex = CalcAnimationDataIndex(
2332                 animationOption,
2333                 index,
2334                 birth[index],
2335                 (life == NULL) ? lifeParam : life[index],
2336                 time,
2337                 animationLength,
2338                 &interp,
2339                 &interpFactor,
2340                 updaterIndex);
2341             animationDataIndex *= animationStride;
2342 
2343             if (animationEnable[0])
2344             {
2345                 value.x = animationData[animationDataIndex++];
2346             }
2347 
2348             if (animationEnable[1])
2349             {
2350                 value.y = animationData[animationDataIndex++];
2351             }
2352 
2353             if (animationEnable[2])
2354             {
2355                 value.z = animationData[animationDataIndex++];
2356             }
2357 
2358             if (interp)
2359             {
2360                 if (animationEnable[0])
2361                 {
2362                     f32 nextValue = animationData[animationDataIndex++];
2363                     value.x = value.x + (nextValue - value.x) * interpFactor;
2364                 }
2365 
2366                 if (animationEnable[1])
2367                 {
2368                     f32 nextValue = animationData[animationDataIndex++];
2369                     value.y = value.y + (nextValue - value.y) * interpFactor;
2370                 }
2371 
2372                 if (animationEnable[2])
2373                 {
2374                     f32 nextValue = animationData[animationDataIndex++];
2375                     value.z = value.z + (nextValue - value.z) * interpFactor;
2376                 }
2377             }
2378         }
2379 
2380         storagePtr[index] = value;
2381     }
2382 }
2383 
ParticleVector3RandomAdditiveUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,ParticleTime time,f32 diffTime,int updaterIndex)2384 void ParticleVector3RandomAdditiveUpdater(
2385     const ResParticleUpdaterData* updater,
2386     ParticleCollection* collection,
2387     ParticleTime time,
2388     f32 diffTime,
2389     int updaterIndex
2390 )
2391 {
2392     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
2393 
2394     ParticleTime* life;
2395     ParticleTime lifeParam = 1.0f;
2396     collection->GetStreamOrParameter(PARTICLEUSAGE_LIFE, &life, &lifeParam, PARTICLE_BUFFER_FRONT);
2397 
2398     int animationLength = 0;
2399     //int animationDimension = 0;
2400     int animationStride = 0;
2401     bool* animationEnable = NULL;
2402     f32* animationData = NULL;
2403 
2404     ResParticleVector3RandomAdditiveUpdater vec3Updater(updater);
2405     NW_ASSERT(vec3Updater.IsValid());
2406 
2407     ResParticleAnimation animation = vec3Updater.GetParticleAnimation();
2408     if (animation.IsValid())
2409     {
2410         animationLength = animation.GetAnimationLength();
2411         //animationDimension = animation.GetAnimationDimension();
2412         animationStride = animation.GetAnimationStride();
2413         animationEnable = animation.GetAnimationEnabled();
2414         animationData = animation.GetAnimationData();
2415     }
2416 
2417     ParticleUsage target = vec3Updater.GetTargetStream();
2418     nw::math::VEC3* storagePtr = (nw::math::VEC3*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
2419     NW_NULL_ASSERT(storagePtr);
2420 
2421     const nw::math::VEC3 defaultValue = vec3Updater.GetDefaultValue();
2422 
2423     const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
2424     for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
2425     {
2426         nw::math::VEC3 value = defaultValue;
2427 
2428         bool interp;
2429         f32 interpFactor;
2430         int animationDataIndex;
2431 
2432         // CALC_OPT:カーブ無しデータはここまで処理がこない。
2433 //        if (animationData != NULL)
2434         {
2435             ResParticleAnimationOption animationOption = animation.GetParticleAnimationOption();
2436 
2437             animationDataIndex = CalcAnimationDataIndex(
2438                 animationOption,
2439                 index,
2440                 birth[index],
2441                 (life == NULL) ? lifeParam : life[index],
2442                 time,
2443                 animationLength,
2444                 &interp,
2445                 &interpFactor,
2446                 updaterIndex);
2447             animationDataIndex *= animationStride;
2448 
2449             if (animationEnable[0])
2450             {
2451                 value.x = animationData[animationDataIndex++];
2452             }
2453 
2454             if (animationEnable[1])
2455             {
2456                 value.y = animationData[animationDataIndex++];
2457             }
2458 
2459             if (animationEnable[2])
2460             {
2461                 value.z = animationData[animationDataIndex++];
2462             }
2463 
2464             if (interp)
2465             {
2466                 if (animationEnable[0])
2467                 {
2468                     f32 nextValue = animationData[animationDataIndex++];
2469                     value.x = value.x + (nextValue - value.x) * interpFactor;
2470                 }
2471 
2472                 if (animationEnable[1])
2473                 {
2474                     f32 nextValue = animationData[animationDataIndex++];
2475                     value.y = value.y + (nextValue - value.y) * interpFactor;
2476                 }
2477 
2478                 if (animationEnable[2])
2479                 {
2480                     f32 nextValue = animationData[animationDataIndex++];
2481                     value.z = value.z + (nextValue - value.z) * interpFactor;
2482                 }
2483             }
2484         }
2485 
2486         storagePtr[index] = value * diffTime;
2487     }
2488 }
2489 
ParticleRotateUpVectorUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection)2490 void ParticleRotateUpVectorUpdater(
2491     const ResParticleUpdaterData* updater,
2492     ParticleCollection* collection
2493 )
2494 {
2495     NW_PARTICLE_PROFILE_START("ParticleRotateUpVectorUpdater");
2496 
2497     ResParticleRotateUpVectorUpdater vec3Updater(updater);
2498     NW_ASSERT(vec3Updater.IsValid());
2499 
2500     NW_ASSERT(vec3Updater.GetTargetStream() == PARTICLEUSAGE_ROTATE);
2501     nw::math::VEC3* storagePtr =
2502         (nw::math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_ROTATE, PARTICLE_BUFFER_FRONT);
2503     NW_NULL_ASSERT(storagePtr);
2504 
2505     ResParticleRotateUpVectorUpdater::ParticleRotateUpVectorSource source =
2506         vec3Updater.GetSource();
2507     switch (source)
2508     {
2509     case ResParticleRotateUpVectorUpdater::SOURCE_VELOCITY:
2510         {
2511             nw::math::VEC3* srcStoragePtr =
2512                 (nw::math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_VELOCITY, PARTICLE_BUFFER_FRONT);
2513 
2514             const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
2515             for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
2516             {
2517                 nw::math::VEC3 ySrcAxis = srcStoragePtr[index];
2518 
2519                 if (internal::VEC3Normalize(&ySrcAxis))
2520                 {
2521                     // CALC_OPT:acosをテーブル引きに。
2522                     // 2010/09/27 一旦、精度上の問題で戻しました。
2523                     storagePtr[index].x = nw::math::AcosRad(ySrcAxis.y);
2524                     //        storagePtr[index].x = internal::AcosTableRad(ySrcAxis.y);
2525 
2526                     // nw::math::Atan2Rad よりも std::atan2fの方が速い(SDK0.13)
2527                     storagePtr[index].y = ::std::atan2f(ySrcAxis.x, ySrcAxis.z);
2528 
2529                     storagePtr[index].z = 0;
2530                 }
2531             }
2532         }
2533         break;
2534     case ResParticleRotateUpVectorUpdater::SOURCE_DISTANCE:
2535         {
2536             nw::math::VEC3* srcStoragePtr =
2537                 (nw::math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_FRONT);
2538             nw::math::VEC3* optionStoragePtr =
2539                 (nw::math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_BACK);
2540 
2541             const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
2542             for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
2543             {
2544                 nw::math::VEC3 ySrcAxis = srcStoragePtr[index];
2545                 ySrcAxis -= optionStoragePtr[index];
2546 
2547                 if (internal::VEC3Normalize(&ySrcAxis))
2548                 {
2549                     // CALC_OPT:acosをテーブル引きに。
2550                     // 2010/09/27 一旦、精度上の問題で戻しました。
2551                     storagePtr[index].x = nw::math::AcosRad(ySrcAxis.y);
2552                     //        storagePtr[index].x = internal::AcosTableRad(ySrcAxis.y);
2553 
2554                     // nw::math::Atan2Rad よりも std::atan2fの方が速い(SDK0.13)
2555                     storagePtr[index].y = ::std::atan2f(ySrcAxis.x, ySrcAxis.z);
2556 
2557                     storagePtr[index].z = 0;
2558                 }
2559             }
2560         }
2561         break;
2562     }
2563 
2564     NW_PARTICLE_PROFILE_STOP();
2565 }
2566 
ParticleTexturePatternUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,ParticleTime time,int updaterIndex)2567 void ParticleTexturePatternUpdater(
2568     const ResParticleUpdaterData* updater,
2569     ParticleCollection* collection,
2570     ParticleTime time,
2571     int updaterIndex
2572 )
2573 {
2574     NW_PARTICLE_PROFILE_START("ParticleTexturePatternUpdater");
2575 
2576     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
2577 
2578     ParticleTime* life;
2579     ParticleTime lifeParam = 1.0f;
2580     collection->GetStreamOrParameter(PARTICLEUSAGE_LIFE, &life, &lifeParam, PARTICLE_BUFFER_FRONT);
2581 
2582     int animationLength = 0;
2583     //int animationDimension = 0;
2584     int animationStride = 0;
2585     bool* animationEnable = NULL;
2586     f32* animationData = NULL;
2587 
2588     ResParticleTexturePatternUpdater texUpdater(updater);
2589     NW_ASSERT(texUpdater.IsValid());
2590 
2591     ResParticleAnimation animation = texUpdater.GetParticleAnimation();
2592     if (animation.IsValid())
2593     {
2594         animationLength = animation.GetAnimationLength();
2595         //animationDimension = animation.GetAnimationDimension();
2596         animationStride = animation.GetAnimationStride();
2597         animationEnable = animation.GetAnimationEnabled();
2598         animationData = animation.GetAnimationData();
2599     }
2600 
2601     ParticleUsage target = texUpdater.GetTargetStream();
2602     nw::math::VEC2* storagePtr = (nw::math::VEC2*)collection->GetStreamPtr(target, PARTICLE_BUFFER_FRONT);
2603     NW_NULL_ASSERT(storagePtr);
2604 
2605     const int divisionX = (int)texUpdater.GetDivisionX();
2606     const int divisionY = (int)texUpdater.GetDivisionY();
2607 
2608     const f32 halfDivisionX = (int)texUpdater.GetDivisionX() * 0.5f;
2609     const f32 halfDivisionY = (int)texUpdater.GetDivisionY() * 0.5f;
2610 
2611     const int textureIndexMax = divisionX * divisionY - 1;
2612 
2613     const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
2614     for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
2615     {
2616         int value = texUpdater.GetTextureIndex();
2617 
2618         if (animationData != NULL)
2619         {
2620             ResParticleAnimationOption animationOption = animation.GetParticleAnimationOption();
2621 
2622             ParticleTime ptclTime = animationOption.EvaluateAnimationFrame(
2623                 index,
2624                 birth[index],
2625                 (life == NULL) ? lifeParam : life[index],
2626                 time,
2627                 updaterIndex);
2628 
2629 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2630             if (ptclTime < 0)
2631             {
2632                 ptclTime = 0;
2633             }
2634             if (ptclTime >= animationLength)
2635             {
2636                 ptclTime = (f32)animationLength - 1;
2637             }
2638 
2639             int animationDataPos = (int)ptclTime * animationStride;
2640 #else
2641             if (ptclTime.GetParticleTimeValue() < 0)
2642             {
2643                 ptclTime = 0;
2644             }
2645             if (ptclTime >= ParticleTime(animationLength))
2646             {
2647                 ptclTime = animationLength - 1;
2648             }
2649 
2650             int animationDataPos = ptclTime.GetS32Value() * animationStride;
2651 #endif
2652 
2653             if (animationEnable[0])
2654             {
2655                 value = (int)animationData[animationDataPos++];
2656             }
2657 
2658             if (value < 0)
2659             {
2660                 value = 0;
2661             }
2662 
2663             if (value > textureIndexMax)
2664             {
2665                 value = textureIndexMax;
2666             }
2667         }
2668 
2669         storagePtr[index].x = -0.5f + (halfDivisionX) - (value % divisionX);
2670         storagePtr[index].y = 0.5f - (halfDivisionY) + (divisionY - (value / divisionX) - 1);
2671         //storagePtr[index].y = -0.5f + (halfDivisionY) - (divisionY - (value / divisionX) - 1);
2672     }
2673 
2674     NW_PARTICLE_PROFILE_STOP();
2675 }
2676 
ParticleChildUpdater(const ResParticleUpdaterData * updater,ParticleCollection * collection,u16 * activeIndex,int startIndex,int incrIndex,int count,ParticleTime time,ParticleTime prevTime,u32 work,ParticleSet * parent,ParticleContext * particleContext,ParticleRandom * random)2677 void ParticleChildUpdater(
2678     const ResParticleUpdaterData* updater,
2679     ParticleCollection* collection,
2680     u16* activeIndex,
2681     int startIndex,
2682     int incrIndex,
2683     int count,
2684     ParticleTime time,
2685     ParticleTime prevTime,
2686     u32 work,
2687     ParticleSet* parent,
2688 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2689     ParticleContext* particleContext,
2690 #endif
2691     ParticleRandom* random
2692 )
2693 {
2694     NW_PARTICLE_PROFILE_START("ParticleChildUpdater");
2695 
2696     ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
2697 
2698     ParticleTime* life;
2699     ParticleTime lifeParam = 1.0f;
2700     collection->GetStreamOrParameter(PARTICLEUSAGE_LIFE, &life, &lifeParam, PARTICLE_BUFFER_FRONT);
2701 
2702     ResParticleChildUpdater childUpdater(updater);
2703     NW_ASSERT(childUpdater.IsValid());
2704 
2705     const ResParticleForm resForm = childUpdater.GetParticleForm();
2706 
2707     ParticleSet* particleSet = reinterpret_cast<ParticleSet*>(work);
2708     if (particleSet != NULL && resForm.IsValid())
2709     {
2710         const nw::math::MTX34 modelMtx = parent->WorldMatrix();
2711 
2712         nw::math::VEC3* translate =
2713             (nw::math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_FRONT);
2714 #if 0
2715         nw::math::VEC3* rotate;
2716         nw::math::VEC3 rotateParam;
2717         collection->GetStreamOrParameter(PARTICLEUSAGE_ROTATE, &rotate, &rotateParam, PARTICLE_BUFFER_FRONT);
2718 
2719         nw::math::VEC3* scale;
2720         nw::math::VEC3 scaleParam;
2721         collection->GetStreamOrParameter(PARTICLEUSAGE_SCALE, &scale, &scaleParam, PARTICLE_BUFFER_FRONT);
2722 #endif
2723 
2724         int emissionCount = childUpdater.GetEmissionRatio();
2725 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2726         int newParticleCount = 0;
2727         nw::math::VEC3* positionsHead = particleContext->GetEmissionPositionWork(emissionCount * count);
2728         u16* parentsHead = particleContext->GetEmissionParentWork(emissionCount * count);
2729 #endif
2730         ResParticleChildUpdaterOption updaterOption = childUpdater.GetTiming();
2731 
2732 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2733         ParticleTime* limit = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_NEG_TIMELIMIT, PARTICLE_BUFFER_FRONT);
2734 #endif
2735 
2736 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2737 #else
2738         // 格納先のポインタ等を集める
2739         ParticleCollection* targetCollection = particleSet->GetParticleCollection();
2740         bool targetIsAscendingOrder = particleSet->IsAscendingOrder();
2741 
2742         const int targetIncrIndex = targetIsAscendingOrder ? 1 : -1;
2743 
2744         nw::math::VEC3* targetTranslate = (nw::math::VEC3*)targetCollection->GetStreamPtr(PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_FRONT);
2745         NW_NULL_ASSERT(targetTranslate);
2746 
2747         bool useTransform = false;
2748         nw::math::VEC3* targetVelocity = (nw::math::VEC3*)targetCollection->GetStreamPtr(PARTICLEUSAGE_VELOCITY, PARTICLE_BUFFER_FRONT);
2749         nw::math::MTX34 transformMatrix;
2750         if (particleSet->WorldMatrix() != modelMtx)
2751         {
2752             useTransform = true;
2753             nw::math::MTX34Mult(&transformMatrix, particleSet->InverseWorldMatrix(), modelMtx);
2754         }
2755 
2756         u16* targetActiveIndex = (u16*)targetCollection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_FRONT);
2757         NW_NULL_ASSERT(targetActiveIndex);
2758         int targetStartIndex = targetIsAscendingOrder ? targetCollection->GetCount() : targetCollection->GetCapacity() - targetCollection->GetCount() - 1;
2759         targetActiveIndex += targetStartIndex;
2760 #endif
2761 
2762         u16* pActiveIndex = activeIndex + startIndex;
2763         for (int j = 0; j < count; ++j)
2764         {
2765             int index = *pActiveIndex;
2766             pActiveIndex += incrIndex;
2767 
2768             if (updaterOption.CheckTiming(
2769                 birth[index],
2770                 (life == NULL) ? lifeParam : life[index],
2771 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2772                 limit[index],
2773 #endif
2774                 prevTime,
2775                 time))
2776             {
2777 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2778                 nw::math::VEC3* newPositions = &positionsHead[newParticleCount];
2779                 if (emissionCount > particleContext->GetEmissionWorkCapacity() - newParticleCount)
2780                 {
2781                     emissionCount = particleContext->GetEmissionWorkCapacity() - newParticleCount;
2782                 }
2783 
2784                 for (int k = 0; k < emissionCount; ++k)
2785                 {
2786                     parentsHead[newParticleCount + k] = index;
2787                 }
2788 #else
2789                 emissionCount = particleSet->AddParticles(emissionCount);
2790                 if (emissionCount == 0)
2791                 {
2792                     break;
2793                 }
2794 #endif
2795 
2796                 const ResParticleCubeForm cubeForm = ResDynamicCast<ResParticleCubeForm>(resForm);
2797                 if (cubeForm.IsValid())
2798                 {
2799 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2800                     ParticleEmitter::CalcCubeForm(cubeForm, emissionCount, random, newPositions);
2801 #else
2802                     ParticleEmitter::CalcCubeForm(cubeForm, emissionCount, random,
2803                         targetActiveIndex, targetIncrIndex, targetTranslate);
2804 #endif
2805                 }
2806 
2807                 const ResParticleCylinderForm cylinderForm = ResDynamicCast<ResParticleCylinderForm>(resForm);
2808                 if (cylinderForm.IsValid())
2809                 {
2810 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2811                     ParticleEmitter::CalcCylinderForm(cylinderForm, emissionCount, random, newPositions);
2812 #else
2813                     ParticleEmitter::CalcCylinderForm(cylinderForm, emissionCount, random,
2814                         targetActiveIndex, targetIncrIndex, targetTranslate);
2815 #endif
2816                 }
2817 
2818                 const ResParticleDiscForm discForm = ResDynamicCast<ResParticleDiscForm>(resForm);
2819                 if (discForm.IsValid())
2820                 {
2821 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2822                     ParticleEmitter::CalcDiscForm(discForm, emissionCount, random, newPositions);
2823 #else
2824                     ParticleEmitter::CalcDiscForm(discForm, emissionCount, random,
2825                         targetActiveIndex, targetIncrIndex, targetTranslate);
2826 #endif
2827                 }
2828 
2829                 const ResParticlePointForm pointForm = ResDynamicCast<ResParticlePointForm>(resForm);
2830                 if (pointForm.IsValid())
2831                 {
2832 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2833                     ParticleEmitter::CalcPointForm(pointForm, emissionCount, random, newPositions);
2834 #else
2835                     ParticleEmitter::CalcPointForm(pointForm, emissionCount, random,
2836                         targetActiveIndex, targetIncrIndex, targetTranslate);
2837 #endif
2838                 }
2839 
2840                 const ResParticleSphereForm sphereForm = ResDynamicCast<ResParticleSphereForm>(resForm);
2841                 if (sphereForm.IsValid())
2842                 {
2843 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2844                     ParticleEmitter::CalcSphereForm(sphereForm, emissionCount, random, newPositions);
2845 #else
2846                     ParticleEmitter::CalcSphereForm(sphereForm, emissionCount, random,
2847                         targetActiveIndex, targetIncrIndex, targetTranslate);
2848 #endif
2849                 }
2850 
2851                 const ResParticleRectangleForm rectangleForm = ResDynamicCast<ResParticleRectangleForm>(resForm);
2852                 if (rectangleForm.IsValid())
2853                 {
2854 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2855                     ParticleEmitter::CalcRectangleForm(rectangleForm, emissionCount, random, newPositions);
2856 #else
2857                     ParticleEmitter::CalcRectangleForm(rectangleForm, emissionCount, random,
2858                         targetActiveIndex, targetIncrIndex, targetTranslate);
2859 #endif
2860                 }
2861 
2862 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2863                 newParticleCount += emissionCount;
2864 #else
2865                 {
2866                     ParticleModel* model = static_cast<ParticleModel*>(particleSet->GetParent());
2867                     NW_NULL_ASSERT(model);
2868                     ParticleTime targetTime = model->ParticleAnimFrameController().GetFrame();
2869 
2870                     particleSet->InitializeParticles(targetStartIndex, emissionCount, targetIncrIndex, targetTime);
2871                     targetStartIndex += targetIncrIndex * emissionCount;
2872                 }
2873 
2874                 // 親の速度
2875                 bool isInheritParentVelocity = particleSet->GetResParticleSet().GetIsInheritParentVelocity();
2876 
2877                 math::VEC3* parentVelocity = NULL;
2878                 if (isInheritParentVelocity)
2879                 {
2880                     parentVelocity = (math::VEC3*)parent->GetParticleCollection()->GetStreamPtr(
2881                         PARTICLEUSAGE_VELOCITY, PARTICLE_BUFFER_FRONT);
2882                 }
2883 
2884                 if (useTransform)
2885                 {
2886                     nw::math::MTX34 workMatrix;
2887 
2888                     nw::math::MTX34 particleMatrix;
2889                     nw::math::MTX34Identity(&particleMatrix);
2890 
2891 #if 0
2892                     nw::math::MTX34Translate(&particleMatrix, translate[index]);
2893                     ////nw::math::MTX34RotXYZRad(&workMatrix, rotate[index].x, rotate[index].y, rotate[index].z);
2894                     ////nw::math::MTX34Mult(&particleMatrix, particleMatrix, workMatrix);
2895                     ////nw::math::MTX34Scale(&workMatrix, scale[index]);
2896                     ////nw::math::MTX34Mult(&particleMatrix, particleMatrix, workMatrix);
2897 
2898                     nw::math::MTX34Mult(&workMatrix, transformMatrix, particleMatrix);
2899 
2900                     for (int i = 0; i < emissionCount; ++i)
2901                     {
2902                         int dstIndex = *targetActiveIndex;
2903                         targetActiveIndex += targetIncrIndex;
2904 
2905                         nw::math::VEC3Transform(&targetTranslate[dstIndex], workMatrix, targetTranslate[dstIndex]);
2906                         nw::math::VEC3TransformNormal(&targetVelocity[dstIndex], workMatrix, targetVelocity[dstIndex]);
2907                     }
2908 #else
2909                     for (int i = 0; i < emissionCount; ++i)
2910                     {
2911                         int dstIndex = *targetActiveIndex;
2912                         targetActiveIndex += targetIncrIndex;
2913 
2914                         targetTranslate[dstIndex] += translate[index];
2915 
2916                         nw::math::VEC3Transform(&targetTranslate[dstIndex], transformMatrix, targetTranslate[dstIndex]);
2917 
2918                         if (isInheritParentVelocity)
2919                         {
2920                             targetVelocity[dstIndex] += parentVelocity[index];
2921                         }
2922 
2923                         nw::math::VEC3TransformNormal(&targetVelocity[dstIndex], transformMatrix, targetVelocity[dstIndex]);
2924                     }
2925 #endif
2926                 }
2927                 else
2928                 {
2929                     for (int i = 0; i < emissionCount; ++i)
2930                     {
2931                         int dstIndex = *targetActiveIndex;
2932                         targetActiveIndex += targetIncrIndex;
2933 
2934                         targetTranslate[dstIndex] += translate[index];
2935 
2936                         if (isInheritParentVelocity)
2937                         {
2938                             targetVelocity[dstIndex] += parentVelocity[index];
2939                         }
2940                     }
2941                 }
2942 #endif
2943             }
2944         }
2945 
2946 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2947         if (newParticleCount > 0)
2948         {
2949             particleSet->AddParticles(
2950                 modelMtx,
2951                 positionsHead,
2952                 parent,
2953                 parentsHead,
2954                 newParticleCount);
2955         }
2956 #endif
2957     }
2958 
2959     NW_PARTICLE_PROFILE_STOP();
2960 }
2961 
2962 //----------------------------------------
2963 void
UpdateParticles(ParticleContext * particleContext)2964 ParticleSet::UpdateParticles(ParticleContext* particleContext)
2965 {
2966     NW_ASSERT(ut::IsTypeOf<ParticleModel>(this->GetParent()));
2967     ParticleModel* model = static_cast<ParticleModel*>(this->GetParent());
2968     NW_NULL_ASSERT(model);
2969 
2970     ParticleCollection* collection = this->GetParticleCollection();
2971     collection->SwapBuffer();
2972 
2973     const ParticleTime prevTime = model->ParticleAnimFrameController().GetAnimFrame().GetLastFrame();
2974     const ParticleTime time = model->ParticleAnimFrameController().GetFrame();
2975 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
2976     const f32 diffTime = time - prevTime;
2977     if (diffTime < 0)
2978     {
2979         return;
2980     }
2981 #else
2982     const ParticleTime diffTimePtcl = time - prevTime;
2983     if (diffTimePtcl < 0)
2984     {
2985         return;
2986     }
2987     const f32 diffTime = diffTimePtcl.GetFloat32Value();
2988 #endif
2989 
2990     const int collectionCapacity = collection->GetCapacity();
2991     const int count = collection->GetCount();
2992     if (count == 0)
2993     {
2994         return;
2995     }
2996 
2997     if (!m_Updaters.empty())
2998     {
2999         int updaterIndex = 0;
3000         ut::MoveArray<Updater>::iterator endIter = this->m_Updaters.end();
3001         for (ut::MoveArray<Updater>::iterator iter = this->m_Updaters.begin(); iter != endIter; ++updaterIndex)
3002         {
3003             Updater& workUpdater = *iter++;
3004             if (workUpdater.resource == NULL)
3005             {
3006                 continue;
3007             }
3008 
3009             const ResParticleUpdater updater(workUpdater.resource);
3010             if (!updater.GetUpdaterEnabled())
3011             {
3012                 continue;
3013             }
3014 
3015             void* targetStream;
3016             if (collection->GetBufferSide())
3017             {
3018                 targetStream = workUpdater.m_TargetStreams[1];
3019             }
3020             else
3021             {
3022                 targetStream = workUpdater.m_TargetStreams[0];
3023             }
3024 
3025             switch (workUpdater.m_Type)
3026             {
3027             case ResParticleAccelarationUpdater::TYPE_INFO:
3028                 ParticleAccelarationUpdater(updater.ptr(), collection, diffTime);
3029                 break;
3030             case ResParticleFloatImmediateUpdater::TYPE_INFO:
3031                 ParticleFloatImmediateUpdater(updater.ptr(), collection, time, updaterIndex);
3032                 break;
3033             case ResParticleFloatImmediate4KeyUpdater::TYPE_INFO:
3034                 ParticleFloatImmediate4KeyUpdater(updater.ptr(), collection, time);
3035                 break;
3036             case ResParticleVector3Immediate4KeyUpdater::TYPE_INFO:
3037                 ParticleVector3Immediate4KeyUpdater(updater.ptr(), collection, time);
3038                 break;
3039             case ResParticleGravityUpdater::TYPE_INFO:
3040                 ParticleGravityUpdater((nw::math::VEC3*)targetStream, updater.ptr(), collection, diffTime);
3041                 break;
3042             case ResParticleSpinUpdater::TYPE_INFO:
3043                 ParticleSpinUpdater(updater.ptr(), collection, diffTime);
3044                 break;
3045             case ResParticleRandomUpdater::TYPE_INFO:
3046                 ParticleRandomUpdater(updater.ptr(), collection, time, prevTime, this->m_ParticleRandom);
3047                 break;
3048             case ResParticleVector2ImmediateUpdater::TYPE_INFO:
3049                 ParticleVector2ImmediateUpdater(updater.ptr(), collection, time, updaterIndex);
3050                 break;
3051             case ResParticleVector3AdditiveUpdater::TYPE_INFO:
3052                 {
3053                     NW_PARTICLE_PROFILE_START("ParticleVector3AdditiveUpdater");
3054 
3055                     if (workUpdater.IsEnabledFlags(Updater::FLAG_IS_HAS_CURVE_ANIM))
3056                     {
3057                         ParticleVector3AdditiveUpdater(updater.ptr(), collection, time, diffTime, updaterIndex);
3058                     }
3059                     else
3060                     {
3061                         ResParticleVector3AdditiveUpdater vec3Updater(updater.ptr());
3062                         NW_ASSERT(vec3Updater.IsValid());
3063 
3064                         nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
3065                         NW_NULL_ASSERT(storagePtr);
3066 
3067                         nw::math::VEC3 defaultValue = vec3Updater.GetDefaultValue();
3068                         defaultValue *= diffTime;
3069 
3070                         storagePtr += collection->GetMinActiveIndex();
3071                         const int processCount = collection->GetMaxActiveIndex() - collection->GetMinActiveIndex() + 1;
3072                         internal::VEC3ArrayAddScalar(storagePtr, &defaultValue, processCount);
3073                     }
3074 
3075                     NW_PARTICLE_PROFILE_STOP();
3076                 }
3077                 break;
3078             case ResParticleVector3ImmediateUpdater::TYPE_INFO:
3079                 {
3080                     NW_PARTICLE_PROFILE_START("ParticleVector3ImmediateUpdater");
3081 
3082                     if (workUpdater.IsEnabledFlags(Updater::FLAG_IS_HAS_CURVE_ANIM))
3083                     {
3084                         ParticleVector3ImmediateUpdater(updater.ptr(), collection, time, updaterIndex);
3085                     }
3086                     else
3087                     {
3088                         ResParticleVector3ImmediateUpdater vec3Updater(updater.ptr());
3089                         NW_ASSERT(vec3Updater.IsValid());
3090                         const nw::math::VEC3 defaultValue = vec3Updater.GetDefaultValue();
3091 
3092                         nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
3093                         NW_NULL_ASSERT(storagePtr);
3094 
3095                         const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
3096                         for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
3097                         {
3098                             storagePtr[index] = defaultValue;
3099                         }
3100                     }
3101 
3102                     NW_PARTICLE_PROFILE_STOP();
3103                 }
3104                 break;
3105             case ResParticleVector3RandomAdditiveUpdater::TYPE_INFO:
3106                 {
3107                     NW_PARTICLE_PROFILE_START("ParticleVector3RandomAdditiveUpdater");
3108 
3109                     if (workUpdater.IsEnabledFlags(Updater::FLAG_IS_HAS_CURVE_ANIM))
3110                     {
3111                         ParticleVector3RandomAdditiveUpdater(updater.ptr(), collection, time, diffTime, updaterIndex);
3112                     }
3113                     else
3114                     {
3115                         ResParticleVector3RandomAdditiveUpdater vec3Updater(updater.ptr());
3116                         NW_ASSERT(vec3Updater.IsValid());
3117                         const nw::math::VEC3 defaultValue = vec3Updater.GetDefaultValue();
3118 
3119                         nw::math::VEC3* storagePtr = (nw::math::VEC3*)targetStream;
3120                         NW_NULL_ASSERT(storagePtr);
3121 
3122                         const u32 maxIndex = collection->GetMaxActiveIndex() + 1;
3123                         for (u32 index = collection->GetMinActiveIndex(); index < maxIndex; ++index)
3124                         {
3125                             storagePtr[index] = defaultValue * diffTime;
3126                         }
3127                     }
3128 
3129                     NW_PARTICLE_PROFILE_STOP();
3130                 }
3131                 break;
3132             case ResParticleRotateUpVectorUpdater::TYPE_INFO:
3133                 ParticleRotateUpVectorUpdater(updater.ptr(), collection);
3134                 break;
3135             case ResParticleTexturePatternUpdater::TYPE_INFO:
3136                 ParticleTexturePatternUpdater(updater.ptr(), collection, time, updaterIndex);
3137                 break;
3138             case ResParticleChildUpdater::TYPE_INFO:
3139                 {
3140                     u16* activeIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_BACK);
3141                     const bool isAscendingOrder = this->IsAscendingOrder();
3142                     const int startIndex = (isAscendingOrder) ? 0 : collectionCapacity - 1;
3143                     const int incrIndex = (isAscendingOrder) ? 1 : -1;
3144 
3145 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
3146                     ParticleChildUpdater(updater.ptr(), collection, activeIndex, startIndex, incrIndex, count, time, prevTime, workUpdater.work, this, particleContext, &this->m_ParticleRandom);
3147 #else
3148                     ParticleChildUpdater(updater.ptr(), collection, activeIndex, startIndex, incrIndex, count, time, prevTime, workUpdater.work, this, &this->m_ParticleRandom);
3149 #endif
3150                 }
3151                 break;
3152             case ResParticleUserUpdater::TYPE_INFO:
3153                 {
3154                     NW_PARTICLE_PROFILE_START("ParticleUserUpdater");
3155 
3156                     ResParticleUserUpdater userUpdater(updater.ptr());
3157                     NW_ASSERT(userUpdater.IsValid());
3158 
3159                     if (workUpdater.work != 0)
3160                     {
3161                         (*(ResParticleUserUpdater::UserFunctionType)workUpdater.work)(
3162                             particleContext,
3163                             this, // ParticleSet*
3164                             &userUpdater,
3165 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
3166                             prevTime,
3167                             time
3168 #else
3169                             prevTime.GetFloat32Value(),
3170                             time.GetFloat32Value()
3171 #endif
3172                         );
3173                     }
3174 
3175                     NW_PARTICLE_PROFILE_STOP();
3176                 }
3177                 break;
3178             case ResParticleGeneralUpdater::TYPE_INFO:
3179                 // 位置の更新
3180                 {
3181                     NW_PARTICLE_PROFILE_START("ParticleGeneralUpdater");
3182 
3183                     math::VEC3* trans =
3184                         (math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_TRANSLATE, PARTICLE_BUFFER_FRONT);
3185 
3186                     math::VEC3* velocity =
3187                         (math::VEC3*)collection->GetStreamPtr(PARTICLEUSAGE_VELOCITY, PARTICLE_BUFFER_FRONT);
3188 
3189                     trans += collection->GetMinActiveIndex();
3190                     velocity += collection->GetMinActiveIndex();
3191                     const int processCount = collection->GetMaxActiveIndex() - collection->GetMinActiveIndex() + 1;
3192                     internal::VEC3ArrayAddVEC3Array(trans, velocity, diffTime, processCount);
3193 
3194                     NW_PARTICLE_PROFILE_STOP();
3195                 }
3196                 break;
3197             }
3198         }
3199     }
3200 
3201     // 消滅処理
3202     {
3203 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
3204         int minActiveIndex = collection->GetMinActiveIndex();
3205         int maxActiveIndex = collection->GetMaxActiveIndex();
3206         u32* work = reinterpret_cast<u32*>(particleContext->GetEmissionPositionWork(
3207             (minActiveIndex + ut::RoundUp(maxActiveIndex - minActiveIndex + 1, 8) + 2) / 3)); // TBD
3208 
3209         if (minActiveIndex <= maxActiveIndex)
3210         {
3211             NW_ASSERT(particleContext->GetEmissionWorkCapacity() * 3 >=
3212                 minActiveIndex + ut::RoundUp(maxActiveIndex - minActiveIndex + 1, 8));
3213             f32* limit = (f32*)collection->GetStreamPtr(PARTICLEUSAGE_NEG_TIMELIMIT, PARTICLE_BUFFER_FRONT);
3214 
3215             internal::CalcRemainFrame(
3216                 reinterpret_cast<f32*>(&work[minActiveIndex]),
3217                 &limit[minActiveIndex],
3218                 time,
3219                 maxActiveIndex - minActiveIndex + 1);
3220         }
3221 
3222         int aliveCount = 0;
3223         int destroyCount = 0;
3224         const int prevCollectionCount = collection->GetCount();
3225 
3226         const bool isAscendingOrder = this->IsAscendingOrder();
3227         const int startIndex = (isAscendingOrder) ? 0 : collectionCapacity - 1;
3228         const int incrIndex = (isAscendingOrder) ? 1 : -1;
3229 
3230         u16* activeIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_BACK);
3231         u16* newActiveIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_FRONT);
3232         u16* freeIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_FREEINDEX, PARTICLE_BUFFER_FRONT);
3233 
3234         minActiveIndex = 0xffff;
3235         maxActiveIndex = 0;
3236         {
3237             u16* pActiveIndex = activeIndex + startIndex;
3238             u16* pAliveIndex = newActiveIndex + startIndex;
3239             u16* pDestroyIndex = freeIndex + collectionCapacity - prevCollectionCount;
3240 
3241             for (int i = prevCollectionCount; i != 0; --i)
3242             {
3243                 int index = *pActiveIndex;
3244                 pActiveIndex += incrIndex;
3245                 NW_ASSERT(index != 0xffff);
3246 
3247                 if ((work[index] & 0x80000000) == 0)
3248                 {
3249                     *pDestroyIndex++ = index;
3250                     ++destroyCount;
3251                 }
3252                 else
3253                 {
3254                     if (minActiveIndex > index)
3255                     {
3256                         minActiveIndex = index;
3257                     }
3258 
3259                     if (maxActiveIndex < index)
3260                     {
3261                         maxActiveIndex = index;
3262                     }
3263 
3264                     *pAliveIndex = index; // 別バッファにコピーしつつ整列していく
3265                     pAliveIndex += incrIndex;
3266                     ++aliveCount;
3267                 }
3268             }
3269         }
3270 #else
3271         ParticleTime* birth = (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_BIRTH, PARTICLE_BUFFER_FRONT);
3272 
3273         int aliveCount = 0;
3274         const int prevCollectionCount = collection->GetCount();
3275 
3276         const bool isAscendingOrder = this->IsAscendingOrder();
3277         const int startIndex = (isAscendingOrder) ? 0 : collectionCapacity - 1;
3278         const int incrIndex = (isAscendingOrder) ? 1 : -1;
3279 
3280         u16* pActiveIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_BACK);
3281         pActiveIndex += startIndex;
3282 
3283         u16* pAliveIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, PARTICLE_BUFFER_FRONT);
3284         pAliveIndex += startIndex;
3285 
3286         u16* pDestroyIndex = (u16*)collection->GetStreamPtr(PARTICLEUSAGE_FREEINDEX, PARTICLE_BUFFER_FRONT);
3287         pDestroyIndex += collectionCapacity - prevCollectionCount;
3288 
3289         int minActiveIndex = 0xffff;
3290         int maxActiveIndex = 0;
3291 
3292         if (collection->IsStream(PARTICLEUSAGE_LIFE))
3293         {
3294             ParticleTime* life =
3295                 (ParticleTime*)collection->GetStreamPtr(PARTICLEUSAGE_LIFE, PARTICLE_BUFFER_FRONT);
3296 
3297             for (int i = prevCollectionCount; i != 0; --i)
3298             {
3299                 int index = *pActiveIndex;
3300                 pActiveIndex += incrIndex;
3301                 NW_ASSERT(index != 0xffff);
3302 
3303                 if (birth[index].GetParticleTimeValue() + life[index].GetParticleTimeValue() <= time.GetParticleTimeValue())
3304                 {
3305                     *pDestroyIndex++ = index;
3306                 }
3307                 else
3308                 {
3309                     if (minActiveIndex > index)
3310                     {
3311                         minActiveIndex = index;
3312                     }
3313 
3314                     if (maxActiveIndex < index)
3315                     {
3316                         maxActiveIndex = index;
3317                     }
3318 
3319                     *pAliveIndex = index; // 別バッファにコピーしつつ整列していく
3320                     pAliveIndex += incrIndex;
3321                     ++aliveCount;
3322                 }
3323             }
3324         }
3325         else
3326         {
3327             ParticleTime* lifeParam =
3328                 (ParticleTime*)collection->GetParameterPtr(PARTICLEUSAGE_LIFE);
3329 
3330             ParticleTime limit = time - *lifeParam;
3331 
3332             for (int i = prevCollectionCount; i != 0; --i)
3333             {
3334                 int index = *pActiveIndex;
3335                 pActiveIndex += incrIndex;
3336                 NW_ASSERT(index != 0xffff);
3337 
3338                 if (birth[index].GetParticleTimeValue() <= limit.GetParticleTimeValue())
3339                 {
3340                     *pDestroyIndex++ = index;
3341                 }
3342                 else
3343                 {
3344                     if (minActiveIndex > index)
3345                     {
3346                         minActiveIndex = index;
3347                     }
3348 
3349                     if (maxActiveIndex < index)
3350                     {
3351                         maxActiveIndex = index;
3352                     }
3353 
3354                     *pAliveIndex = index; // 別バッファにコピーしつつ整列していく
3355                     pAliveIndex += incrIndex;
3356                     ++aliveCount;
3357                 }
3358             }
3359         }
3360 #endif
3361 
3362         collection->SetMinActiveIndex(minActiveIndex);
3363         collection->SetMaxActiveIndex(maxActiveIndex);
3364         collection->SetCount(aliveCount);
3365     }
3366 }
3367 
3368 //----------------------------------------
ParticleSet(os::IAllocator * allocator,ResParticleSet resObj,const ParticleSet::Description & description)3369 ParticleSet::ParticleSet(
3370     os::IAllocator* allocator,
3371     ResParticleSet resObj,
3372     const ParticleSet::Description& description)
3373     : SceneNode(allocator, resObj, description),
3374     m_ParticleCollection(NULL),
3375     m_ScaleOffset(1.0f, 1.0f, 1.0f),
3376     m_RotateOffset(0, 0, 0)
3377 {
3378 }
3379 
3380 //----------------------------------------
~ParticleSet()3381 ParticleSet::~ParticleSet()
3382 {
3383     {
3384         ut::MoveArray<Initializer>::iterator endIter = this->m_Initializers.end();
3385         for (ut::MoveArray<Initializer>::iterator iter = this->m_Initializers.begin(); iter != endIter; ++iter)
3386         {
3387             if ((*iter).m_IsCopied)
3388             {
3389                 ResParticleInitializerData* ptr = const_cast<ResParticleInitializerData*>((*iter).resource);
3390                 this->GetAllocator().Free(ptr);
3391                 (*iter).resource = NULL;
3392             }
3393         }
3394     }
3395 
3396     {
3397         ut::MoveArray<Updater>::iterator endIter = this->m_Updaters.end();
3398         for (ut::MoveArray<Updater>::iterator iter = this->m_Updaters.begin(); iter != endIter; ++iter)
3399         {
3400             if ((*iter).m_IsCopied)
3401             {
3402                 ResParticleUpdaterData* ptr = const_cast<ResParticleUpdaterData*>((*iter).resource);
3403                 this->GetAllocator().Free(ptr);
3404                 (*iter).resource = NULL;
3405             }
3406         }
3407     }
3408 
3409     SafeDestroy(m_ParticleCollection);
3410 }
3411 
3412 //----------------------------------------
3413 void
Accept(ISceneVisitor * visitor)3414 ParticleSet::Accept(
3415     ISceneVisitor* visitor
3416 )
3417 {
3418     visitor->VisitParticleSet(this);
3419     AcceptChildren(visitor);
3420 }
3421 
3422 //----------------------------------------
3423 void
ClearParticleCollection()3424 ParticleSet::ClearParticleCollection()
3425 {
3426     if (this->m_ParticleCollection == NULL)
3427     {
3428         return;
3429     }
3430 
3431     this->m_ParticleCollection->Clear();
3432 }
3433 
3434 //----------------------------------------
3435 bool
CheckTiming(ParticleTime birth,ParticleTime life,ParticleTime limit,ParticleTime prevTime,ParticleTime currentTime)3436 ResParticleChildUpdaterOption::CheckTiming(
3437     ParticleTime birth,
3438     ParticleTime life,
3439 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
3440     ParticleTime limit,
3441 #endif
3442     ParticleTime prevTime,
3443     ParticleTime currentTime)
3444 {
3445     switch (this->GetTypeInfo())
3446     {
3447     case ResParticleChildUpdaterFirstUpdateOption::TYPE_INFO:
3448         return birth == currentTime;
3449 
3450     case ResParticleChildUpdaterFinalUpdateOption::TYPE_INFO:
3451 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
3452         return limit + currentTime >= 0;
3453 #else
3454         return birth.GetParticleTimeValue() + life.GetParticleTimeValue() <= currentTime.GetParticleTimeValue();
3455 #endif
3456 
3457     case ResParticleChildUpdaterIntervalOption::TYPE_INFO:
3458         {
3459             ResParticleChildUpdaterIntervalOption resource(this->ptr());
3460 
3461             if (prevTime >= currentTime)
3462             {
3463                 return false;
3464             }
3465 
3466 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
3467             int end = (int)(resource.GetEnd() * life);
3468 
3469             int prevCount =(int)(prevTime - birth);
3470 #else
3471             int end = (int)(resource.GetEnd() * life.GetFloat32Value());
3472 
3473             ParticleTime prev_birth = prevTime - birth;
3474             int prevCount = prev_birth.GetIntegralParts();
3475 #endif
3476             if (prevCount >= end)
3477             {
3478                 return false;
3479             }
3480 
3481             int interval = resource.GetInterval();
3482             if (interval < 1)
3483             {
3484                 interval = 1;
3485             }
3486 
3487 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
3488             int start = (int)(resource.GetStart() * life);
3489             prevCount = (int)math::FFloor((float)(prevCount - start) / interval);
3490 
3491             int currentCount = (int)math::FFloor((currentTime - birth - start) / interval);
3492 #else
3493             int start = (int)(resource.GetStart() * life.GetFloat32Value());
3494             prevCount = (int)math::FFloor((float)(prevCount - start) / interval);
3495 
3496             ParticleTime current_birth =currentTime - birth;
3497             current_birth -= start;
3498             int currentCount = (int)math::FFloor(current_birth.GetFloat32Value() / interval);
3499 #endif
3500             if (currentCount < 0)
3501             {
3502                 return false;
3503             }
3504 
3505             return prevCount < currentCount;
3506         }
3507 
3508     case ResParticleChildUpdaterFrameOption::TYPE_INFO:
3509         {
3510             ResParticleChildUpdaterFrameOption resource(this->ptr());
3511 
3512             if (prevTime >= currentTime)
3513             {
3514                 return false;
3515             }
3516 
3517 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
3518             int prevCount =(int)(prevTime - birth);
3519 #else
3520             ParticleTime prev_birth = prevTime - birth;
3521             int prevCount = prev_birth.GetIntegralParts();
3522 #endif
3523             if (prevCount >= resource.GetEnd())
3524             {
3525                 return false;
3526             }
3527 
3528             int interval = resource.GetInterval();
3529             if (interval < 1)
3530             {
3531                 interval = 1;
3532             }
3533 
3534             prevCount = (int)math::FFloor((float)(prevCount - resource.GetStart()) / interval);
3535 
3536 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
3537             int currentCount = (int)math::FFloor((currentTime - birth - resource.GetStart()) / interval);
3538 #else
3539             ParticleTime current_birth =currentTime - birth;
3540             current_birth -= resource.GetStart();
3541             int currentCount = (int)math::FFloor(current_birth.GetFloat32Value() / interval);
3542 #endif
3543             if (currentCount < 0)
3544             {
3545                 return false;
3546             }
3547 
3548             return prevCount < currentCount;
3549         }
3550     }
3551 
3552     return false;
3553 }
3554 
3555 } // namespace gfx
3556 } // namespace nw
3557