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