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