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