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