1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ParticleUtil.cpp
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: 31311 $
16  *---------------------------------------------------------------------------*/
17 
18 #include "precompiled.h"
19 
20 #include <nw/gfx/gfx_ParticleUtil.h>
21 
22 namespace nw
23 {
24 namespace gfx
25 {
26 
27 // パーティクルセットを探します。
28 ParticleSet*
FindParticleSet(const char * name,ut::MoveArray<SceneNode * > * sceneNodeArray)29 FindParticleSet(
30     const char* name,
31     ut::MoveArray<SceneNode*>* sceneNodeArray
32 )
33 {
34     for (ut::MoveArray<SceneNode*>::iterator i = sceneNodeArray->Begin();
35         i != sceneNodeArray->End();
36         ++i)
37     {
38         ParticleModel* particleModel = ut::DynamicCast<ParticleModel*>(*i);
39         if (!particleModel) { continue; }
40 
41         for (int j = 0; j < (int)particleModel->GetParticleSetsCount(); ++j)
42         {
43             ParticleSet* itParticleSet = particleModel->GetParticleSets(j);
44             NW_NULL_ASSERT(itParticleSet);
45 
46             const char* itParticleSetName= itParticleSet->GetResParticleSet().GetName();
47 
48             if (std::strcmp(itParticleSetName, name) == 0)
49             {
50                 return itParticleSet;
51             }
52         }
53     }
54 
55     return NULL;
56 }
57 
58 void
SetupParticleObject(ut::MoveArray<SceneNode * > * sceneNodeArray,ParticleContext * particleContext)59 ParticleUtil::SetupParticleObject(
60     ut::MoveArray<SceneNode*>* sceneNodeArray,
61     ParticleContext* particleContext
62 )
63 {
64     NW_NULL_ASSERT(sceneNodeArray);
65     NW_NULL_ASSERT(particleContext);
66 
67     ResolveParticleObject(sceneNodeArray);
68 
69     NW_FOREACH(SceneNode* node, *sceneNodeArray)
70     {
71         ResSceneNode resSceneNode = node->GetResSceneNode();
72         NW_ASSERT(resSceneNode.IsValid());
73 
74         switch (resSceneNode.ptr()->typeInfo)
75         {
76         case ResParticleModel::TYPE_INFO:
77             {
78                 ParticleModel* model = static_cast<ParticleModel*>(node);
79                 NW_NULL_ASSERT(model);
80 
81                 for (u32 i = 0; i < model->GetParticleSetsCount(); ++i)
82                 {
83                     ParticleSet* particleSet = model->GetParticleSets(i);
84                     NW_NULL_ASSERT(particleSet);
85 
86                     particleSet->Srand(particleContext->GetRandom());
87                 }
88             }
89             break;
90         case ResParticleEmitter::TYPE_INFO:
91             {
92                 ParticleEmitter* emitter = static_cast<ParticleEmitter*>(node);
93                 NW_NULL_ASSERT(emitter);
94 
95                 emitter->Srand(particleContext->GetRandom());
96             }
97         }
98     }
99 }
100 
101 void
ResolveParticleObject(ut::MoveArray<SceneNode * > * sceneNodeArray)102 ParticleUtil::ResolveParticleObject(
103     ut::MoveArray<SceneNode*>* sceneNodeArray
104 )
105 {
106     NW_NULL_ASSERT(sceneNodeArray);
107 
108     NW_FOREACH(SceneNode* node, *sceneNodeArray)
109     {
110         ResSceneNode resSceneNode = node->GetResSceneNode();
111         NW_ASSERT(resSceneNode.IsValid());
112 
113         switch (resSceneNode.ptr()->typeInfo)
114         {
115         case ResParticleModel::TYPE_INFO:
116             {
117                 ParticleModel* model = static_cast<ParticleModel*>(node);
118                 NW_NULL_ASSERT(model);
119 
120                 for (u32 i = 0; i < model->GetParticleSetsCount(); ++i)
121                 {
122                     ParticleSet* particleSet = model->GetParticleSets(i);
123                     NW_NULL_ASSERT(particleSet);
124 
125                     ut::MoveArray<ParticleSet::Updater>* updaters =
126                         particleSet->GetUpdaters();
127                     NW_NULL_ASSERT(updaters);
128 
129                     ut::MoveArray<ParticleSet::Updater>::iterator endIter = updaters->end();
130                     for (ut::MoveArray<ParticleSet::Updater>::iterator iter = updaters->begin();
131                         iter != endIter;)
132                     {
133                         ParticleSet::Updater& updater = *iter++;
134 
135                         ResParticleUpdater resUpdater(updater.resource);
136                         NW_ASSERT(resUpdater.IsValid());
137 
138                         if (resUpdater.GetTypeInfo() == ResParticleChildUpdater::TYPE_INFO)
139                         {
140                             ResParticleChildUpdater childUpdater =
141                                 ResDynamicCast<ResParticleChildUpdater>(resUpdater);
142 
143                             const char* particleSetPath = childUpdater.GetParticleSetPath();
144 
145                             ParticleSet* childParticleSet =
146                                 FindParticleSet(particleSetPath, sceneNodeArray);
147                             if (childParticleSet != NULL)
148                             {
149                                 updater.work = (u32)childParticleSet;
150                             }
151                         }
152                     }
153                 }
154             }
155             break;
156         case ResParticleEmitter::TYPE_INFO:
157             {
158                 ParticleEmitter* emitter = static_cast<ParticleEmitter*>(node);
159                 NW_NULL_ASSERT(emitter);
160 
161                 ResParticleEmitter resource = emitter->GetResParticleEmitter();
162                 if (resource.IsValid())
163                 {
164                     ParticleSet* particleSet =
165                         FindParticleSet(resource.GetParticleSetPath(), sceneNodeArray);
166 
167                     emitter->SetParticleSet(particleSet);
168                 }
169             }
170             break;
171         }
172     }
173 }
174 
175 bool
operator ()(const ParticleSet * lhs,const ParticleSet * rhs)176 ParticleSetCompare::operator() (
177         const ParticleSet* lhs,
178         const ParticleSet* rhs)
179 {
180     if (rhs == NULL)
181     {
182         return true;
183     }
184 
185     if (lhs == NULL)
186     {
187         return false;
188     }
189 
190     const ResParticleSet& lhsResource = lhs->GetResParticleSet();
191     const ResParticleSet& rhsResource = rhs->GetResParticleSet();
192     return lhsResource.GetParticleSetPriority() < rhsResource.GetParticleSetPriority();
193 }
194 
195 void
GetMemorySizeForDuplicateResParticleInitializerInternal(os::MemorySizeCalculator * pSize,const ResParticleInitializer * src)196 ParticleUtil::GetMemorySizeForDuplicateResParticleInitializerInternal(
197     os::MemorySizeCalculator* pSize,
198     const ResParticleInitializer* src)
199 {
200     os::MemorySizeCalculator& size = *pSize;
201 
202     int baseSize = 0;
203 
204     switch (src->GetTypeInfo())
205     {
206     case ResParticleInitializer::TYPE_INFO:
207         baseSize += sizeof(ResParticleInitializerData);
208         break;
209     case ResParticleDirectionalVelocityInitializer::TYPE_INFO:
210         baseSize += sizeof(ResParticleDirectionalVelocityInitializerData);
211         break;
212     case ResParticleRandomDirectionalVelocityInitializer::TYPE_INFO:
213         baseSize += sizeof(ResParticleRandomDirectionalVelocityInitializerData);
214         break;
215     case ResParticleOriginVelocityInitializer::TYPE_INFO:
216         baseSize += sizeof(ResParticleOriginVelocityInitializerData);
217         break;
218     case ResParticleRandomVelocityInitializer::TYPE_INFO:
219         baseSize += sizeof(ResParticleRandomVelocityInitializerData);
220         break;
221     case ResParticleYAxisVelocityInitializer::TYPE_INFO:
222         baseSize += sizeof(ResParticleYAxisVelocityInitializerData);
223         break;
224     case ResParticleVector3ImmediateInitializer::TYPE_INFO:
225         baseSize += sizeof(ResParticleVector3ImmediateInitializerData);
226         break;
227     case ResParticleFloatRandomInitializer::TYPE_INFO:
228         baseSize += sizeof(ResParticleFloatRandomInitializerData);
229         break;
230     case ResParticleFloatRangeRandomInitializer::TYPE_INFO:
231         baseSize += sizeof(ResParticleFloatRangeRandomInitializerData);
232         break;
233     case ResParticleFloatImmediateInitializer::TYPE_INFO:
234         baseSize += sizeof(ResParticleFloatImmediateInitializerData);
235         break;
236     case ResParticleVector2ImmediateInitializer::TYPE_INFO:
237         baseSize += sizeof(ResParticleVector2ImmediateInitializerData);
238         break;
239     case ResParticleVector3Random1Initializer::TYPE_INFO:
240         baseSize += sizeof(ResParticleVector3Random1InitializerData);
241         break;
242     case ResParticleVector3Random3Initializer::TYPE_INFO:
243         baseSize += sizeof(ResParticleVector3Random3InitializerData);
244         break;
245     case ResParticleVector3MultRandomInitializer::TYPE_INFO:
246         baseSize += sizeof(ResParticleVector3MultRandomInitializerData);
247         break;
248     default:
249         NW_FATAL_ERROR("unknown initializer type");
250     }
251 
252     size.Add(baseSize, 4);
253 }
254 
255 ResParticleInitializerData*
DuplicateResParticleInitializer(const ResParticleInitializer * src,os::IAllocator * allocator)256 ParticleUtil::DuplicateResParticleInitializer(
257     const ResParticleInitializer* src,
258     os::IAllocator* allocator
259 )
260 {
261     NW_NULL_ASSERT(src);
262     NW_NULL_ASSERT(allocator);
263 
264     int baseSize = 0;
265     int size = 0;
266 
267     switch (src->GetTypeInfo())
268     {
269     case ResParticleInitializer::TYPE_INFO:
270         baseSize += sizeof(ResParticleInitializerData);
271         break;
272     case ResParticleDirectionalVelocityInitializer::TYPE_INFO:
273         baseSize += sizeof(ResParticleDirectionalVelocityInitializerData);
274         break;
275     case ResParticleRandomDirectionalVelocityInitializer::TYPE_INFO:
276         baseSize += sizeof(ResParticleRandomDirectionalVelocityInitializerData);
277         break;
278     case ResParticleOriginVelocityInitializer::TYPE_INFO:
279         baseSize += sizeof(ResParticleOriginVelocityInitializerData);
280         break;
281     case ResParticleRandomVelocityInitializer::TYPE_INFO:
282         baseSize += sizeof(ResParticleRandomVelocityInitializerData);
283         break;
284     case ResParticleYAxisVelocityInitializer::TYPE_INFO:
285         baseSize += sizeof(ResParticleYAxisVelocityInitializerData);
286         break;
287     case ResParticleVector3ImmediateInitializer::TYPE_INFO:
288         baseSize += sizeof(ResParticleVector3ImmediateInitializerData);
289         break;
290     case ResParticleFloatRandomInitializer::TYPE_INFO:
291         baseSize += sizeof(ResParticleFloatRandomInitializerData);
292         break;
293     case ResParticleFloatRangeRandomInitializer::TYPE_INFO:
294         baseSize += sizeof(ResParticleFloatRangeRandomInitializerData);
295         break;
296     case ResParticleFloatImmediateInitializer::TYPE_INFO:
297         baseSize += sizeof(ResParticleFloatImmediateInitializerData);
298         break;
299     case ResParticleVector2ImmediateInitializer::TYPE_INFO:
300         baseSize += sizeof(ResParticleVector2ImmediateInitializerData);
301         break;
302     case ResParticleVector3Random1Initializer::TYPE_INFO:
303         baseSize += sizeof(ResParticleVector3Random1InitializerData);
304         break;
305     case ResParticleVector3Random3Initializer::TYPE_INFO:
306         baseSize += sizeof(ResParticleVector3Random3InitializerData);
307         break;
308     case ResParticleVector3MultRandomInitializer::TYPE_INFO:
309         baseSize += sizeof(ResParticleVector3MultRandomInitializerData);
310         break;
311     default:
312         NW_FATAL_ERROR("unknown initializer type");
313     }
314 
315     size += ut::RoundUp(baseSize, 4);
316 
317     void* memory = allocator->Alloc(size, 4);
318     if (memory == NULL)
319     {
320         return NULL;
321     }
322 
323     {
324         u8* dstPtr = (u8*)memory;
325 
326         ResParticleInitializerData* dstData =
327             reinterpret_cast<ResParticleInitializerData*>(dstPtr);
328         const ResParticleInitializerData* srcData = src->ptr();
329 
330         ::nw::os::MemCpy(dstPtr, srcData, baseSize);
331         dstPtr += ut::RoundUp(baseSize, 4);
332     }
333 
334     switch (src->GetTypeInfo())
335     {
336     case ResParticleInitializer::TYPE_INFO:
337     case ResParticleDirectionalVelocityInitializer::TYPE_INFO:
338     case ResParticleRandomDirectionalVelocityInitializer::TYPE_INFO:
339     case ResParticleOriginVelocityInitializer::TYPE_INFO:
340     case ResParticleRandomVelocityInitializer::TYPE_INFO:
341     case ResParticleYAxisVelocityInitializer::TYPE_INFO:
342     case ResParticleVector3ImmediateInitializer::TYPE_INFO:
343     case ResParticleFloatRandomInitializer::TYPE_INFO:
344     case ResParticleFloatRangeRandomInitializer::TYPE_INFO:
345     case ResParticleFloatImmediateInitializer::TYPE_INFO:
346     case ResParticleVector2ImmediateInitializer::TYPE_INFO:
347     case ResParticleVector3Random1Initializer::TYPE_INFO:
348     case ResParticleVector3Random3Initializer::TYPE_INFO:
349     case ResParticleVector3MultRandomInitializer::TYPE_INFO:
350         // PRIMITIVEしかないので何もしなくてよい
351         break;
352     default:
353         NW_FATAL_ERROR("unknown initializer type");
354     }
355 
356     return reinterpret_cast<ResParticleInitializerData*>(memory);
357 }
358 
359 void
GetMemorySizeForDuplicateResParticleUpdaterInternal(os::MemorySizeCalculator * pSize,const ResParticleUpdater * src)360 ParticleUtil::GetMemorySizeForDuplicateResParticleUpdaterInternal(
361     os::MemorySizeCalculator* pSize,
362     const ResParticleUpdater* src)
363 {
364     int baseSize = 0;
365     os::MemorySizeCalculator& size = *pSize;
366     int childStrSize = 0;
367     int childFormSize = 0;
368     int childOptionSize  = 0;
369 
370     switch (src->GetTypeInfo())
371     {
372     case ResParticleUpdater::TYPE_INFO:
373         baseSize = sizeof(ResParticleUpdaterData);
374         break;
375     case ResParticleAccelarationUpdater::TYPE_INFO:
376         baseSize = sizeof(ResParticleAccelarationUpdaterData);
377         break;
378     case ResParticleGeneralUpdater::TYPE_INFO:
379         baseSize = sizeof(ResParticleGeneralUpdaterData);
380         break;
381     case ResParticleGravityUpdater::TYPE_INFO:
382         baseSize = sizeof(ResParticleGravityUpdaterData);
383         break;
384     case ResParticleSpinUpdater::TYPE_INFO:
385         baseSize = sizeof(ResParticleSpinUpdaterData);
386         break;
387     case ResParticleRandomUpdater::TYPE_INFO:
388         baseSize = sizeof(ResParticleRandomUpdaterData);
389         break;
390     case ResParticleChildUpdater::TYPE_INFO:
391         baseSize = sizeof(ResParticleChildUpdaterData);
392         {
393             const ResParticleChildUpdater& child = ResDynamicCast<ResParticleChildUpdater>(*src);
394             NW_ASSERT(child.IsValid());
395 
396             childStrSize = strlen(child.GetParticleSetPath()) + 1;
397 
398             const ResParticleForm& form = child.GetParticleForm();
399             const ResParticleChildUpdaterOption& option = child.GetTiming();
400 
401             if (form.IsValid())
402             {
403                 switch (form.GetTypeInfo())
404                 {
405                 case ResParticleForm::TYPE_INFO:
406                     childFormSize = sizeof(ResParticleFormData);
407                     break;
408                 case ResParticleCubeForm::TYPE_INFO:
409                     childFormSize = sizeof(ResParticleCubeFormData);
410                     break;
411                 case ResParticleCylinderForm::TYPE_INFO:
412                     childFormSize = sizeof(ResParticleCylinderFormData);
413                     break;
414                 case ResParticleDiscForm::TYPE_INFO:
415                     childFormSize = sizeof(ResParticleDiscFormData);
416                     break;
417                 case ResParticlePointForm::TYPE_INFO:
418                     childFormSize = sizeof(ResParticlePointFormData);
419                     break;
420                 case ResParticleRectangleForm::TYPE_INFO:
421                     childFormSize = sizeof(ResParticleRectangleFormData);
422                     break;
423                 case ResParticleSphereForm::TYPE_INFO:
424                     childFormSize = sizeof(ResParticleSphereFormData);
425                     break;
426                 default:
427                     NW_FATAL_ERROR("unknown form type");
428                 }
429             }
430 
431             if (option.IsValid())
432             {
433                 switch (option.GetTypeInfo())
434                 {
435                 case ResParticleChildUpdaterFinalUpdateOption::TYPE_INFO:
436                     childOptionSize = sizeof(ResParticleChildUpdaterFinalUpdateOptionData);
437                     break;
438                 case ResParticleChildUpdaterFirstUpdateOption::TYPE_INFO:
439                     childOptionSize = sizeof(ResParticleChildUpdaterFirstUpdateOptionData);
440                     break;
441                 case ResParticleChildUpdaterIntervalOption::TYPE_INFO:
442                     childOptionSize = sizeof(ResParticleChildUpdaterIntervalOptionData);
443                     break;
444                 default:
445                     NW_FATAL_ERROR("unknown updateOption type");
446                 }
447             }
448         }
449         break;
450     case ResParticleUserUpdater::TYPE_INFO:
451         baseSize = sizeof(ResParticleUserUpdaterData);
452         break;
453     case ResParticleVector2ImmediateUpdater::TYPE_INFO:
454         baseSize = sizeof(ResParticleVector2ImmediateUpdaterData);
455         break;
456     case ResParticleVector3Updater::TYPE_INFO:
457         baseSize = sizeof(ResParticleVector3UpdaterData);
458         break;
459     case ResParticleFloatUpdater::TYPE_INFO:
460         baseSize = sizeof(ResParticleFloatUpdaterData);
461         break;
462     case ResParticleRotateUpVectorUpdater::TYPE_INFO:
463         baseSize = sizeof(ResParticleRotateUpVectorUpdaterData);
464         break;
465     case ResParticleTexturePatternUpdater::TYPE_INFO:
466         baseSize = sizeof(ResParticleTexturePatternUpdaterData);
467         break;
468     case ResParticleVector3ImmediateUpdater::TYPE_INFO:
469         baseSize = sizeof(ResParticleVector3ImmediateUpdaterData);
470         break;
471     case ResParticleVector3AdditiveUpdater::TYPE_INFO:
472         baseSize = sizeof(ResParticleVector3AdditiveUpdaterData);
473         break;
474     case ResParticleVector3RandomAdditiveUpdater::TYPE_INFO:
475         baseSize = sizeof(ResParticleVector3RandomAdditiveUpdaterData);
476         break;
477     case ResParticleFloatImmediateUpdater::TYPE_INFO:
478         baseSize = sizeof(ResParticleFloatImmediateUpdaterData);
479         break;
480     default:
481         NW_FATAL_ERROR("unknown updater type");
482         break;
483     }
484 
485     // アニメーションのサイズ計算
486     int animationSize = 0;
487     int enabledSize = 0;
488     int dataSize = 0;
489     int animationOptionSize = 0;
490     {
491         const ResParticleAnimation& resAnimation = src->GetParticleAnimation();
492         if (resAnimation.IsValid())
493         {
494             animationSize += sizeof(ResParticleAnimationData);
495 
496             enabledSize = resAnimation.GetAnimationEnabledCount() * sizeof(bool);
497             dataSize = resAnimation.GetAnimationDataCount() * sizeof(s32);
498 
499             const ResParticleAnimationOption& option =
500                 resAnimation.GetParticleAnimationOption();
501             if (option.IsValid())
502             {
503                 switch (option.GetTypeInfo())
504                 {
505                 case ResParticleAnimationOption::TYPE_INFO:
506                     animationOptionSize = sizeof(ResParticleAnimationOptionData);
507                     break;
508                 case ResParticleFittingAnimationOption::TYPE_INFO:
509                     animationOptionSize = sizeof(ResParticleFittingAnimationOptionData);
510                     break;
511                 case ResParticleFrameLoopAnimationOption::TYPE_INFO:
512                     animationOptionSize = sizeof(ResParticleFrameLoopAnimationOptionData);
513                     break;
514                 case ResParticleRandomAnimationOption::TYPE_INFO:
515                     animationOptionSize = sizeof(ResParticleRandomAnimationOptionData);
516                     break;
517                 default:
518                     NW_FATAL_ERROR("unknown animationOption type");
519                 }
520             }
521 
522             animationSize +=
523                 resAnimation.GetAnimationEnabledCount() * sizeof(u32);
524             animationSize +=
525                 resAnimation.GetAnimationDataCount() * sizeof(u32);
526         }
527     }
528 
529     size.Add(baseSize, 4);
530     size.Add(animationSize, 4);
531     size.Add(enabledSize, 4);
532     size.Add(dataSize, 4);
533     size.Add(animationOptionSize, 4);
534     size.Add(childStrSize, 4);
535     size.Add(childFormSize, 4);
536     size.Add(childOptionSize, 4);
537 }
538 
539 ResParticleUpdaterData*
DuplicateResParticleUpdater(const ResParticleUpdater * src,os::IAllocator * allocator)540 ParticleUtil::DuplicateResParticleUpdater(
541     const ResParticleUpdater* src,
542     os::IAllocator* allocator
543 )
544 {
545     NW_NULL_ASSERT(src);
546     NW_NULL_ASSERT(allocator);
547 
548     int baseSize = 0;
549     int size = 0;
550     int childStrSize = 0;
551     int childFormSize = 0;
552     int childOptionSize  = 0;
553 
554     switch (src->GetTypeInfo())
555     {
556     case ResParticleUpdater::TYPE_INFO:
557         baseSize = sizeof(ResParticleUpdaterData);
558         break;
559     case ResParticleAccelarationUpdater::TYPE_INFO:
560         baseSize = sizeof(ResParticleAccelarationUpdaterData);
561         break;
562     case ResParticleGeneralUpdater::TYPE_INFO:
563         baseSize = sizeof(ResParticleGeneralUpdaterData);
564         break;
565     case ResParticleGravityUpdater::TYPE_INFO:
566         baseSize = sizeof(ResParticleGravityUpdaterData);
567         break;
568     case ResParticleSpinUpdater::TYPE_INFO:
569         baseSize = sizeof(ResParticleSpinUpdaterData);
570         break;
571     case ResParticleRandomUpdater::TYPE_INFO:
572         baseSize = sizeof(ResParticleRandomUpdaterData);
573         break;
574     case ResParticleChildUpdater::TYPE_INFO:
575         baseSize = sizeof(ResParticleChildUpdaterData);
576         {
577             const ResParticleChildUpdater& child = ResDynamicCast<ResParticleChildUpdater>(*src);
578             NW_ASSERT(child.IsValid());
579 
580             childStrSize = strlen(child.GetParticleSetPath()) + 1;
581 
582             const ResParticleForm& form = child.GetParticleForm();
583             const ResParticleChildUpdaterOption& option = child.GetTiming();
584 
585             if (form.IsValid())
586             {
587                 switch (form.GetTypeInfo())
588                 {
589                 case ResParticleForm::TYPE_INFO:
590                     childFormSize = sizeof(ResParticleFormData);
591                     break;
592                 case ResParticleCubeForm::TYPE_INFO:
593                     childFormSize = sizeof(ResParticleCubeFormData);
594                     break;
595                 case ResParticleCylinderForm::TYPE_INFO:
596                     childFormSize = sizeof(ResParticleCylinderFormData);
597                     break;
598                 case ResParticleDiscForm::TYPE_INFO:
599                     childFormSize = sizeof(ResParticleDiscFormData);
600                     break;
601                 case ResParticlePointForm::TYPE_INFO:
602                     childFormSize = sizeof(ResParticlePointFormData);
603                     break;
604                 case ResParticleRectangleForm::TYPE_INFO:
605                     childFormSize = sizeof(ResParticleRectangleFormData);
606                     break;
607                 case ResParticleSphereForm::TYPE_INFO:
608                     childFormSize = sizeof(ResParticleSphereFormData);
609                     break;
610                 default:
611                     NW_FATAL_ERROR("unknown form type");
612                 }
613             }
614 
615             if (option.IsValid())
616             {
617                 switch (option.GetTypeInfo())
618                 {
619                 case ResParticleChildUpdaterFinalUpdateOption::TYPE_INFO:
620                     childOptionSize = sizeof(ResParticleChildUpdaterFinalUpdateOptionData);
621                     break;
622                 case ResParticleChildUpdaterFirstUpdateOption::TYPE_INFO:
623                     childOptionSize = sizeof(ResParticleChildUpdaterFirstUpdateOptionData);
624                     break;
625                 case ResParticleChildUpdaterIntervalOption::TYPE_INFO:
626                     childOptionSize = sizeof(ResParticleChildUpdaterIntervalOptionData);
627                     break;
628                 default:
629                     NW_FATAL_ERROR("unknown updateOption type");
630                 }
631             }
632         }
633         break;
634     case ResParticleUserUpdater::TYPE_INFO:
635         baseSize = sizeof(ResParticleUserUpdaterData);
636         break;
637     case ResParticleVector2ImmediateUpdater::TYPE_INFO:
638         baseSize = sizeof(ResParticleVector2ImmediateUpdaterData);
639         break;
640     case ResParticleVector3Updater::TYPE_INFO:
641         baseSize = sizeof(ResParticleVector3UpdaterData);
642         break;
643     case ResParticleFloatUpdater::TYPE_INFO:
644         baseSize = sizeof(ResParticleFloatUpdaterData);
645         break;
646     case ResParticleRotateUpVectorUpdater::TYPE_INFO:
647         baseSize = sizeof(ResParticleRotateUpVectorUpdaterData);
648         break;
649     case ResParticleTexturePatternUpdater::TYPE_INFO:
650         baseSize = sizeof(ResParticleTexturePatternUpdaterData);
651         break;
652     case ResParticleVector3ImmediateUpdater::TYPE_INFO:
653         baseSize = sizeof(ResParticleVector3ImmediateUpdaterData);
654         break;
655     case ResParticleVector3AdditiveUpdater::TYPE_INFO:
656         baseSize = sizeof(ResParticleVector3AdditiveUpdaterData);
657         break;
658     case ResParticleVector3RandomAdditiveUpdater::TYPE_INFO:
659         baseSize = sizeof(ResParticleVector3RandomAdditiveUpdaterData);
660         break;
661     case ResParticleFloatImmediateUpdater::TYPE_INFO:
662         baseSize = sizeof(ResParticleFloatImmediateUpdaterData);
663         break;
664     default:
665         NW_FATAL_ERROR("unknown updater type");
666         break;
667     }
668 
669     // アニメーションのサイズ計算
670     int animationSize = 0;
671     int enabledSize = 0;
672     int dataSize = 0;
673     int animationOptionSize = 0;
674     {
675         const ResParticleAnimation& resAnimation = src->GetParticleAnimation();
676         if (resAnimation.IsValid())
677         {
678             animationSize += sizeof(ResParticleAnimationData);
679 
680             enabledSize = resAnimation.GetAnimationEnabledCount() * sizeof(bool);
681             dataSize = resAnimation.GetAnimationDataCount() * sizeof(s32);
682 
683             const ResParticleAnimationOption& option =
684                 resAnimation.GetParticleAnimationOption();
685             if (option.IsValid())
686             {
687                 switch (option.GetTypeInfo())
688                 {
689                 case ResParticleAnimationOption::TYPE_INFO:
690                     animationOptionSize = sizeof(ResParticleAnimationOptionData);
691                     break;
692                 case ResParticleFittingAnimationOption::TYPE_INFO:
693                     animationOptionSize = sizeof(ResParticleFittingAnimationOptionData);
694                     break;
695                 case ResParticleFrameLoopAnimationOption::TYPE_INFO:
696                     animationOptionSize = sizeof(ResParticleFrameLoopAnimationOptionData);
697                     break;
698                 case ResParticleRandomAnimationOption::TYPE_INFO:
699                     animationOptionSize = sizeof(ResParticleRandomAnimationOptionData);
700                     break;
701                 default:
702                     NW_FATAL_ERROR("unknown animationOption type");
703                 }
704             }
705 
706             animationSize +=
707                 resAnimation.GetAnimationEnabledCount() * sizeof(u32);
708             animationSize +=
709                 resAnimation.GetAnimationDataCount() * sizeof(u32);
710         }
711     }
712 
713     size += ut::RoundUp(baseSize, 4);
714     size += ut::RoundUp(animationSize, 4);
715     size += ut::RoundUp(enabledSize, 4);
716     size += ut::RoundUp(dataSize, 4);
717     size += ut::RoundUp(animationOptionSize, 4);
718     size += ut::RoundUp(childStrSize, 4);
719     size += ut::RoundUp(childFormSize, 4);
720     size += ut::RoundUp(childOptionSize, 4);
721 
722     void* memory = allocator->Alloc(size, 4);
723     if (memory == NULL)
724     {
725         return NULL;
726     }
727 
728     u8* dstPtr = (u8*)memory;
729 
730     ResParticleUpdaterData* dstData =
731         reinterpret_cast<ResParticleUpdaterData*>(dstPtr);
732 
733     {
734         const ResParticleUpdaterData* srcData = src->ptr();
735         ::nw::os::MemCpy(dstPtr, srcData, baseSize);
736         dstPtr += ut::RoundUp(baseSize, 4);
737     }
738 
739     if (animationSize != 0)
740     {
741         const ResParticleAnimation& animation = src->GetParticleAnimation();
742 
743         ResParticleAnimationData* dstAnimation =
744             reinterpret_cast<ResParticleAnimationData*>(dstPtr);
745 
746         ::nw::os::MemCpy(
747             dstPtr,
748             animation.ptr(),
749             animationSize);
750         dstData->toParticleAnimation.set_ptr(dstPtr);
751         dstPtr += ut::RoundUp(animationSize, 4);
752 
753         if (enabledSize > 0)
754         {
755             ::nw::os::MemCpy(
756                 dstPtr,
757                 animation.GetAnimationEnabled(),
758                 enabledSize);
759             dstAnimation->toAnimationEnabledTable.set_ptr(dstPtr);
760             dstPtr += ut::RoundUp(enabledSize, 4);
761         }
762 
763         if (dataSize > 0)
764         {
765             ::nw::os::MemCpy(
766                 dstPtr,
767                 animation.GetAnimationData(),
768                 dataSize);
769             dstAnimation->toAnimationDataTable.set_ptr(dstPtr);
770             dstPtr += ut::RoundUp(dataSize, 4);
771         }
772 
773         if (animationOptionSize != 0)
774         {
775             const ResParticleAnimationOption& option = animation.GetParticleAnimationOption();
776 
777             ::nw::os::MemCpy(
778                 dstPtr,
779                 option.ptr(),
780                 animationOptionSize);
781             dstAnimation->toParticleAnimationOption.set_ptr(dstPtr);
782             dstPtr += ut::RoundUp(animationOptionSize, 4);
783         }
784     }
785 
786     switch (src->GetTypeInfo())
787     {
788     case ResParticleChildUpdater::TYPE_INFO:
789         {
790             ResParticleChildUpdaterData* childData =
791                 reinterpret_cast<ResParticleChildUpdaterData*>(memory);
792 
793             const ResParticleChildUpdater& child = ResDynamicCast<ResParticleChildUpdater>(*src);
794 
795             if (childStrSize > 0)
796             {
797                 const char* str = child.GetParticleSetPath();
798 
799                 ::nw::os::MemCpy(
800                     dstPtr,
801                     str,
802                     childStrSize);
803                 childData->toParticleSetPath.set_ptr((const char*)dstPtr);
804                 dstPtr += ut::RoundUp(childStrSize, 4);
805             }
806 
807             if (childFormSize > 0)
808             {
809                 const ResParticleForm& form = child.GetParticleForm();
810 
811                 ::nw::os::MemCpy(
812                     dstPtr,
813                     form.ptr(),
814                     childFormSize);
815                 childData->toParticleForm.set_ptr(dstPtr);
816                 dstPtr += ut::RoundUp(childFormSize, 4);
817             }
818 
819             if (childOptionSize > 0)
820             {
821                 const ResParticleChildUpdaterOption& option = child.GetTiming();
822 
823                 ::nw::os::MemCpy(
824                     dstPtr,
825                     option.ptr(),
826                     childOptionSize);
827                 childData->toTiming.set_ptr(dstPtr);
828                 dstPtr += ut::RoundUp(childOptionSize, 4);
829             }
830         }
831         break;
832     }
833 
834     return reinterpret_cast<ResParticleUpdaterData*>(memory);
835 }
836 
837 } // namespace gfx
838 } // namespace nw
839