1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ParticleCollection.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: 26419 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/gfx/gfx_ParticleCollection.h>
19 #include <nw/gfx/gfx_ISceneVisitor.h>
20 
21 #include <nw/ut/ut_ResUtil.h>
22 #include <nw/ut/ut_ResDictionary.h>
23 
24 namespace nw
25 {
26 namespace gfx
27 {
28 
29 NW_UT_RUNTIME_TYPEINFO_DEFINITION(ParticleCollection, SceneObject);
30 
31 //----------------------------------------
32 template <typename T>
33 static int
ParticleStreamCreateSize(int capacity,int prevSize)34 ParticleStreamCreateSize(
35     int capacity,
36     int prevSize
37 )
38 {
39     NW_ASSERT(capacity > 0);
40 
41     prevSize = ut::RoundUp(prevSize, 8);
42 
43     // サイズをショートベクタ演算の処理単位に切り上げる
44     const int size =
45         ut::RoundUp(capacity, internal::PARTICLE_SIMD_WIDTH_MAX) * sizeof(T) +
46         internal::PARTICLE_SIMD_WIDTH_MAX;
47 
48     return prevSize + size;
49 }
50 
51 template <typename T>
52 static bool
ParticleStreamCreate(ParticleCollection::ParticleAttribute * storage,ParticleUsage usage,int capacity,u8 ** buffer)53 ParticleStreamCreate(
54     ParticleCollection::ParticleAttribute* storage,
55     ParticleUsage usage,
56     int capacity,
57     u8** buffer
58 )
59 {
60     NW_ASSERT(capacity > 0);
61     NW_NULL_ASSERT(buffer);
62 
63     // サイズをショートベクタ演算の処理単位に切り上げる
64     const int size =
65         ut::RoundUp(capacity, internal::PARTICLE_SIMD_WIDTH_MAX) * sizeof(T) +
66         internal::PARTICLE_SIMD_WIDTH_MAX;
67 
68     // VFPは64bitバスを持つので、8byteアラインメントしたほうが高速
69     *buffer = reinterpret_cast<u8*>(ut::RoundUp(*buffer, 8));
70     void* memory = *buffer;
71     *buffer += size;
72 
73     std::memset(memory, 0, size);
74 
75     storage->m_Usage = static_cast<s32>(usage);
76     storage->m_IsStream = true;
77     storage->m_Stream = reinterpret_cast<f32*>(memory);
78 
79     return memory != NULL;
80 }
81 
82 //----------------------------------------
83 template <typename T>
84 static int
ParticleParameterAttributeCreateSize(int prevSize)85 ParticleParameterAttributeCreateSize(
86     int prevSize
87 )
88 {
89     prevSize = ut::RoundUp(prevSize, 4);
90 
91     const int size = sizeof(T);
92 
93     return prevSize + size;
94 }
95 
96 template <typename T>
97 static bool
ParticleParameterAttributeCreate(ParticleCollection::ParticleAttribute * storage,ParticleUsage usage,const ResParticleParameterAttribute & resource,u8 ** buffer)98 ParticleParameterAttributeCreate(
99     ParticleCollection::ParticleAttribute* storage,
100     ParticleUsage usage,
101     const ResParticleParameterAttribute& resource,
102     u8** buffer
103 )
104 {
105     NW_NULL_ASSERT(buffer);
106 
107     const int size = sizeof(T);
108 
109     *buffer = reinterpret_cast<u8*>(ut::RoundUp(*buffer, 4));
110     void* memory = *buffer;
111     *buffer += size;
112 
113     nw::os::MemCpy(memory, resource.GetData(), size);
114 
115     storage->m_Usage = static_cast<s32>(usage);
116     storage->m_IsStream = false;
117     storage->m_Stream = reinterpret_cast<f32*>(memory);
118 
119     return memory != NULL;
120 }
121 
122 //----------------------------------------
123 void
GetMemorySizeInternal(os::MemorySizeCalculator * pSize,ResParticleCollection resNode)124 ParticleCollection::GetMemorySizeInternal(
125     os::MemorySizeCalculator* pSize,
126     ResParticleCollection resNode)
127 {
128     os::MemorySizeCalculator& size = *pSize;
129 
130     const int capacity = resNode.GetCapacity();
131 
132     int collectionMemorySize = sizeof(ParticleCollection);
133     collectionMemorySize = ut::RoundUp(collectionMemorySize, 4);
134 
135     bool hasAttribute[PARTICLEUSAGE_COUNT];
136     for (int i = 0; i < PARTICLEUSAGE_COUNT; ++i)
137     {
138         hasAttribute[i] = false;
139     }
140 
141     // 使用するメモリの総量の確認
142     {
143         // 生まれた順でアクティブなインデックスが格納されている
144         // ここではメモリ確保しない
145         {
146             ParticleUsage usage = PARTICLEUSAGE_ACTIVEINDEX;
147             hasAttribute[usage] = true;
148         }
149 
150         // 使用可能なインデックスが前詰めで格納されている
151         {
152             ParticleUsage usage = PARTICLEUSAGE_FREEINDEX;
153 
154             collectionMemorySize =
155                 ParticleStreamCreateSize<u16>(capacity, collectionMemorySize);
156             collectionMemorySize = ut::RoundUp(collectionMemorySize, 4);
157 
158             hasAttribute[usage] = true;
159         }
160 
161 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
162         // 消滅する時刻(高速化のため)
163         {
164             ParticleUsage usage = PARTICLEUSAGE_NEG_TIMELIMIT;
165 
166             collectionMemorySize =
167                 ParticleStreamCreateSize<f32>(capacity, collectionMemorySize);
168 
169             hasAttribute[usage] = true;
170         }
171 #endif
172 
173         ResParticleAttributeArray attributes = resNode.GetAttributes();
174         ResParticleAttributeArray::iterator attributeEnd = attributes.end();
175         for (ResParticleAttributeArray::iterator it = attributes.begin();
176             it != attributeEnd;
177             ++it)
178         {
179             ParticleUsage usage = (ParticleUsage)(*it).GetUsage();
180 
181             if ((*it).GetTypeInfo() == ResParticleParameterAttribute::TYPE_INFO)
182             {
183                 ResParticleParameterAttribute resParam((*it).ptr());
184 
185                 switch (usage)
186                 {
187                 case PARTICLEUSAGE_BIRTH:
188                 case PARTICLEUSAGE_LIFE:
189                     collectionMemorySize =
190                         ParticleParameterAttributeCreateSize<f32>(collectionMemorySize);
191                     break;
192                 case PARTICLEUSAGE_VELOCITY:
193                     NW_FATAL_ERROR("PARTICLEUSAGE_VELOCITY must not be ParameterAttribute");
194                     break;
195                 case PARTICLEUSAGE_ALPHA:
196                 case PARTICLEUSAGE_TEXTUREROTATE0:
197                     collectionMemorySize =
198                         ParticleShape::AddVertexParamSize(GL_FLOAT, 1, collectionMemorySize);
199                     break;
200                 case PARTICLEUSAGE_TRANSLATE:
201                 case PARTICLEUSAGE_SCALE:
202                 case PARTICLEUSAGE_ROTATE:
203                 case PARTICLEUSAGE_COLOR:
204                 case PARTICLEUSAGE_SCALE_EXT:
205                     collectionMemorySize =
206                         ParticleShape::AddVertexParamSize(GL_FLOAT, 3, collectionMemorySize);
207                     break;
208                 case PARTICLEUSAGE_TEXTURETRANSLATE0:
209                 case PARTICLEUSAGE_TEXTURESCALE0:
210                     collectionMemorySize =
211                         ParticleShape::AddVertexParamSize(GL_FLOAT, 2, collectionMemorySize);
212                     break;
213                 }
214 
215                 hasAttribute[usage] = true;
216             }
217             else
218             {
219                 switch (usage)
220                 {
221                 case PARTICLEUSAGE_BIRTH:
222                 case PARTICLEUSAGE_LIFE:
223                     collectionMemorySize =
224                         ParticleStreamCreateSize<f32>(capacity, collectionMemorySize);
225                     break;
226                 case PARTICLEUSAGE_VELOCITY:
227                     collectionMemorySize =
228                         ParticleStreamCreateSize<nw::math::VEC3>(capacity, collectionMemorySize);
229                     break;
230                 case PARTICLEUSAGE_ALPHA:
231                 case PARTICLEUSAGE_TEXTUREROTATE0:
232                 case PARTICLEUSAGE_TRANSLATE:
233                 case PARTICLEUSAGE_SCALE:
234                 case PARTICLEUSAGE_ROTATE:
235                 case PARTICLEUSAGE_COLOR:
236                 case PARTICLEUSAGE_SCALE_EXT:
237                 case PARTICLEUSAGE_TEXTURETRANSLATE0:
238                 case PARTICLEUSAGE_TEXTURESCALE0:
239                     break;
240                 }
241 
242                 hasAttribute[usage] = true;
243             }
244         }
245 
246         for (int usage = 0; usage < PARTICLEUSAGE_COUNT; ++usage)
247         {
248             if (!hasAttribute[usage])
249             {
250                 switch (usage)
251                 {
252                 case PARTICLEUSAGE_BIRTH:
253                 case PARTICLEUSAGE_LIFE:
254                 case PARTICLEUSAGE_VELOCITY:
255                     NW_FATAL_ERROR("PARTICLEUSAGE_BIRTH/LIFE/VELOCITY must not be ParameterAttribute");
256                     break;
257                 case PARTICLEUSAGE_ALPHA:
258                     collectionMemorySize =
259                         ParticleShape::AddVertexParamSize(GL_FLOAT, 1, collectionMemorySize);
260                     break;
261                 case PARTICLEUSAGE_TEXTUREROTATE0:
262                     collectionMemorySize =
263                         ParticleShape::AddVertexParamSize(GL_FLOAT, 1, collectionMemorySize);
264                     break;
265                 case PARTICLEUSAGE_TRANSLATE:
266                 case PARTICLEUSAGE_ROTATE:
267                     collectionMemorySize =
268                         ParticleShape::AddVertexParamSize(GL_FLOAT, 3, collectionMemorySize);
269                     break;
270                 case PARTICLEUSAGE_COLOR:
271                 case PARTICLEUSAGE_SCALE:
272                 case PARTICLEUSAGE_SCALE_EXT:
273                     collectionMemorySize =
274                         ParticleShape::AddVertexParamSize(GL_FLOAT, 3, collectionMemorySize);
275                     break;
276                 case PARTICLEUSAGE_TEXTURETRANSLATE0:
277                     collectionMemorySize =
278                         ParticleShape::AddVertexParamSize(GL_FLOAT, 2, collectionMemorySize);
279                     break;
280                 case PARTICLEUSAGE_TEXTURESCALE0:
281                     collectionMemorySize =
282                         ParticleShape::AddVertexParamSize(GL_FLOAT, 2, collectionMemorySize);
283                     break;
284                 }
285 
286                 // 実際の確保のために初期化
287                 hasAttribute[usage] = false;
288             }
289         }
290     }
291 
292     size.Add(collectionMemorySize, 32);
293 }
294 
295 //----------------------------------------
296 void
GetDeviceMemorySizeInternal(os::MemorySizeCalculator * pSize,ResParticleCollection resNode)297 ParticleCollection::GetDeviceMemorySizeInternal(
298     os::MemorySizeCalculator* pSize,
299     ResParticleCollection resNode)
300 {
301     os::MemorySizeCalculator& size = *pSize;
302 
303     const int capacity = resNode.GetCapacity();
304 
305     int deviceMemorySize = 0;
306 
307     // 使用するメモリの総量の確認
308     {
309         ResParticleAttributeArray attributes = resNode.GetAttributes();
310         ResParticleAttributeArray::iterator attributeEnd = attributes.end();
311         for (ResParticleAttributeArray::iterator it = attributes.begin();
312             it != attributeEnd;
313             ++it)
314         {
315             ParticleUsage usage = (ParticleUsage)(*it).GetUsage();
316 
317             if ((*it).GetTypeInfo() != ResParticleParameterAttribute::TYPE_INFO)
318             {
319                 switch (usage)
320                 {
321                 case PARTICLEUSAGE_BIRTH:
322                 case PARTICLEUSAGE_LIFE:
323                 case PARTICLEUSAGE_VELOCITY:
324                     break;
325                 case PARTICLEUSAGE_ALPHA:
326                 case PARTICLEUSAGE_TEXTUREROTATE0:
327                     deviceMemorySize =
328                         ParticleShape::AddVertexStreamSize(GL_FLOAT, 1, capacity, deviceMemorySize);
329                     break;
330                 case PARTICLEUSAGE_TRANSLATE:
331                 case PARTICLEUSAGE_SCALE:
332                 case PARTICLEUSAGE_ROTATE:
333                 case PARTICLEUSAGE_COLOR:
334                 case PARTICLEUSAGE_SCALE_EXT:
335                     deviceMemorySize =
336                         ParticleShape::AddVertexStreamSize(GL_FLOAT, 3, capacity, deviceMemorySize);
337                     break;
338                 case PARTICLEUSAGE_TEXTURETRANSLATE0:
339                 case PARTICLEUSAGE_TEXTURESCALE0:
340                     deviceMemorySize =
341                         ParticleShape::AddVertexStreamSize(GL_FLOAT, 2, capacity, deviceMemorySize);
342                     break;
343                 }
344             }
345         }
346     }
347 
348     size.Add(deviceMemorySize, 32);
349 }
350 
351 //----------------------------------------
352 ParticleCollection*
Create(ParticleSet * parent,ResParticleCollection resNode,os::IAllocator * mainAllocator,os::IAllocator * deviceAllocator,ParticleShape * shape)353 ParticleCollection::Create(
354     ParticleSet* parent,
355     ResParticleCollection resNode,
356     os::IAllocator* mainAllocator,
357     os::IAllocator* deviceAllocator,
358     ParticleShape* shape
359 )
360 {
361     NW_NULL_ASSERT(mainAllocator);
362     NW_NULL_ASSERT(deviceAllocator);
363     NW_NULL_ASSERT(shape);
364 
365     NW_ASSERT(resNode.IsValid());
366 
367     const int capacity = resNode.GetCapacity();
368 
369     int collectionMemorySize = sizeof(ParticleCollection);
370     collectionMemorySize = ut::RoundUp(collectionMemorySize, 4);
371 
372     int deviceMemorySize = 0;
373 
374     bool hasAttribute[PARTICLEUSAGE_COUNT];
375     for (int i = 0; i < PARTICLEUSAGE_COUNT; ++i)
376     {
377         hasAttribute[i] = false;
378     }
379 
380     // 使用するメモリの総量の確認
381     {
382         // 生まれた順でアクティブなインデックスが格納されている
383         // ここではメモリ確保しない
384         {
385             ParticleUsage usage = PARTICLEUSAGE_ACTIVEINDEX;
386             hasAttribute[usage] = true;
387         }
388 
389         // 使用可能なインデックスが前詰めで格納されている
390         {
391             ParticleUsage usage = PARTICLEUSAGE_FREEINDEX;
392 
393             collectionMemorySize =
394                 ParticleStreamCreateSize<u16>(capacity, collectionMemorySize);
395             collectionMemorySize = ut::RoundUp(collectionMemorySize, 4);
396 
397             hasAttribute[usage] = true;
398         }
399 
400 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
401         // 消滅する時刻(高速化のため)
402         {
403             ParticleUsage usage = PARTICLEUSAGE_NEG_TIMELIMIT;
404 
405             collectionMemorySize =
406                 ParticleStreamCreateSize<f32>(capacity, collectionMemorySize);
407 
408             hasAttribute[usage] = true;
409         }
410 #endif
411 
412         ResParticleAttributeArray attributes = resNode.GetAttributes();
413         ResParticleAttributeArray::iterator attributeEnd = attributes.end();
414         for (ResParticleAttributeArray::iterator it = attributes.begin();
415             it != attributeEnd;
416             ++it)
417         {
418             ParticleUsage usage = (ParticleUsage)(*it).GetUsage();
419 
420             if ((*it).GetTypeInfo() == ResParticleParameterAttribute::TYPE_INFO)
421             {
422                 ResParticleParameterAttribute resParam((*it).ptr());
423 
424                 switch (usage)
425                 {
426                 case PARTICLEUSAGE_BIRTH:
427                 case PARTICLEUSAGE_LIFE:
428                     collectionMemorySize =
429                         ParticleParameterAttributeCreateSize<f32>(collectionMemorySize);
430                     break;
431                 case PARTICLEUSAGE_VELOCITY:
432                     NW_FATAL_ERROR("PARTICLEUSAGE_VELOCITY must not be ParameterAttribute");
433                     break;
434                 case PARTICLEUSAGE_ALPHA:
435                 case PARTICLEUSAGE_TEXTUREROTATE0:
436                     collectionMemorySize =
437                         shape->AddVertexParamSize(GL_FLOAT, 1, collectionMemorySize);
438                     break;
439                 case PARTICLEUSAGE_TRANSLATE:
440                 case PARTICLEUSAGE_SCALE:
441                 case PARTICLEUSAGE_ROTATE:
442                 case PARTICLEUSAGE_COLOR:
443                 case PARTICLEUSAGE_SCALE_EXT:
444                     collectionMemorySize =
445                         shape->AddVertexParamSize(GL_FLOAT, 3, collectionMemorySize);
446                     break;
447                 case PARTICLEUSAGE_TEXTURETRANSLATE0:
448                 case PARTICLEUSAGE_TEXTURESCALE0:
449                     collectionMemorySize =
450                         shape->AddVertexParamSize(GL_FLOAT, 2, collectionMemorySize);
451                     break;
452                 }
453 
454                 hasAttribute[usage] = true;
455             }
456             else
457             {
458                 switch (usage)
459                 {
460                 case PARTICLEUSAGE_BIRTH:
461                 case PARTICLEUSAGE_LIFE:
462                     collectionMemorySize =
463                         ParticleStreamCreateSize<f32>(capacity, collectionMemorySize);
464                     break;
465                 case PARTICLEUSAGE_VELOCITY:
466                     collectionMemorySize =
467                         ParticleStreamCreateSize<nw::math::VEC3>(capacity, collectionMemorySize);
468                     break;
469                 case PARTICLEUSAGE_ALPHA:
470                 case PARTICLEUSAGE_TEXTUREROTATE0:
471                     deviceMemorySize =
472                         shape->AddVertexStreamSize(GL_FLOAT, 1, capacity, deviceMemorySize);
473                     break;
474                 case PARTICLEUSAGE_TRANSLATE:
475                 case PARTICLEUSAGE_SCALE:
476                 case PARTICLEUSAGE_ROTATE:
477                 case PARTICLEUSAGE_COLOR:
478                 case PARTICLEUSAGE_SCALE_EXT:
479                     deviceMemorySize =
480                         shape->AddVertexStreamSize(GL_FLOAT, 3, capacity, deviceMemorySize);
481                     break;
482                 case PARTICLEUSAGE_TEXTURETRANSLATE0:
483                 case PARTICLEUSAGE_TEXTURESCALE0:
484                     deviceMemorySize =
485                         shape->AddVertexStreamSize(GL_FLOAT, 2, capacity, deviceMemorySize);
486                     break;
487                 }
488 
489                 hasAttribute[usage] = true;
490             }
491         }
492 
493         for (int usage = 0; usage < PARTICLEUSAGE_COUNT; ++usage)
494         {
495             if (!hasAttribute[usage])
496             {
497                 switch (usage)
498                 {
499                 case PARTICLEUSAGE_BIRTH:
500                 case PARTICLEUSAGE_LIFE:
501                 case PARTICLEUSAGE_VELOCITY:
502                     NW_FATAL_ERROR("PARTICLEUSAGE_BIRTH/LIFE/VELOCITY must not be ParameterAttribute");
503                     break;
504                 case PARTICLEUSAGE_ALPHA:
505                     collectionMemorySize =
506                         shape->AddVertexParamSize(GL_FLOAT, 1, collectionMemorySize);
507                     break;
508                 case PARTICLEUSAGE_TEXTUREROTATE0:
509                     collectionMemorySize =
510                         shape->AddVertexParamSize(GL_FLOAT, 1, collectionMemorySize);
511                     break;
512                 case PARTICLEUSAGE_TRANSLATE:
513                 case PARTICLEUSAGE_ROTATE:
514                     collectionMemorySize =
515                         shape->AddVertexParamSize(GL_FLOAT, 3, collectionMemorySize);
516                     break;
517                 case PARTICLEUSAGE_COLOR:
518                 case PARTICLEUSAGE_SCALE:
519                 case PARTICLEUSAGE_SCALE_EXT:
520                     collectionMemorySize =
521                         shape->AddVertexParamSize(GL_FLOAT, 3, collectionMemorySize);
522                     break;
523                 case PARTICLEUSAGE_TEXTURETRANSLATE0:
524                     collectionMemorySize =
525                         shape->AddVertexParamSize(GL_FLOAT, 2, collectionMemorySize);
526                     break;
527                 case PARTICLEUSAGE_TEXTURESCALE0:
528                     collectionMemorySize =
529                         shape->AddVertexParamSize(GL_FLOAT, 2, collectionMemorySize);
530                     break;
531                 }
532 
533                 // 実際の確保のために初期化
534                 hasAttribute[usage] = false;
535             }
536         }
537     }
538 
539     u8* deviceMemory = NULL;
540     if (deviceMemorySize > 0)
541     {
542         deviceMemory = reinterpret_cast<u8*>(deviceAllocator->Alloc(deviceMemorySize, 32));
543         if (deviceMemory == NULL)
544         {
545             return NULL;
546         }
547     }
548 
549     u8* nodeMemory = reinterpret_cast<u8*>(mainAllocator->Alloc(collectionMemorySize, 32));
550     if (nodeMemory == NULL)
551     {
552         if (deviceMemory != NULL)
553         {
554             deviceAllocator->Free(deviceMemory);
555         }
556 
557         return NULL;
558     }
559 
560     ParticleCollection* node = new(nodeMemory) ParticleCollection(
561         mainAllocator,
562         deviceAllocator,
563         deviceMemory,
564         resNode);
565     nodeMemory += sizeof(ParticleCollection);
566     nodeMemory = reinterpret_cast<u8*>(ut::RoundUp(nodeMemory, 4));
567 
568     node->m_Capacity = capacity;
569 
570     node->m_ParticleShape = shape;
571 
572     {
573         // 生まれた順でアクティブなインデックスが格納されている
574         {
575             ParticleUsage usage = PARTICLEUSAGE_ACTIVEINDEX;
576 
577             node->m_IsStream[usage] = true;
578             for (int i = 0; i < 2; ++i)
579             {
580                 node->m_StreamPtr[usage][i] = shape->GetPrimitiveStreamPtr((ParticleBuffer)i);
581                 node->m_StreamStride[usage] = 2;
582             }
583 
584             hasAttribute[usage] = true;
585         }
586 
587         // 使用可能なインデックスが前詰めで格納されている
588         {
589             ParticleUsage usage = PARTICLEUSAGE_FREEINDEX;
590 
591             ParticleStreamCreate<u16>(
592                 &node->m_ParticleAttribute[usage], static_cast<ParticleUsage>(usage), capacity, &nodeMemory);
593 
594             node->m_IsStream[usage] = true;
595             for (int i = 0; i < 2; ++i)
596             {
597                 node->m_StreamPtr[usage][i] = node->m_ParticleAttribute[usage].m_Stream;
598                 node->m_StreamStride[usage] = 2;
599             }
600 
601             hasAttribute[usage] = true;
602         }
603 
604 #ifdef NW_GFX_PARTICLE_COMPAT_1_1
605         // 消滅する時刻(高速化のため)
606         {
607             ParticleUsage usage = PARTICLEUSAGE_NEG_TIMELIMIT;
608 
609             ParticleStreamCreate<f32>(
610                 &node->m_ParticleAttribute[usage], static_cast<ParticleUsage>(usage), capacity, &nodeMemory);
611 
612             node->m_IsStream[usage] = true;
613             for (int i = 0; i < 2; ++i)
614             {
615                 node->m_StreamPtr[usage][i] = node->m_ParticleAttribute[usage].m_Stream;
616                 node->m_StreamStride[usage] = 2;
617             }
618 
619             hasAttribute[usage] = true;
620         }
621 #endif
622 
623         ResParticleAttributeArray attributes = resNode.GetAttributes();
624         ResParticleAttributeArray::iterator attributeEnd = attributes.end();
625         for (ResParticleAttributeArray::iterator it = attributes.begin();
626             it != attributeEnd;
627             ++it)
628         {
629             ParticleUsage usage = (ParticleUsage)(*it).GetUsage();
630 
631             void* ptr0 = NULL;
632             void* ptr1 = NULL;
633 
634             if ((*it).GetTypeInfo() == ResParticleParameterAttribute::TYPE_INFO)
635             {
636                 ResParticleParameterAttribute resParam((*it).ptr());
637 
638                 void* ptr = NULL;
639 
640                 switch (usage)
641                 {
642                 case PARTICLEUSAGE_BIRTH:
643                 case PARTICLEUSAGE_LIFE:
644                     ParticleParameterAttributeCreate<ParticleTime>(
645                         &node->m_ParticleAttribute[usage], usage, resParam, &nodeMemory);
646                     ptr = node->m_ParticleAttribute[usage].m_Stream;
647                     {
648                         *(ParticleTime*)ptr =  *resParam.GetData();
649                     }
650                     break;
651                 case PARTICLEUSAGE_VELOCITY:
652                     NW_FATAL_ERROR("PARTICLEUSAGE_VELOCITY must not be ParameterAttribute");
653                     break;
654                 case PARTICLEUSAGE_ALPHA:
655                 case PARTICLEUSAGE_TEXTUREROTATE0:
656                     {
657                         ParticleShape::VertexAttribute* data =
658                             shape->AddVertexParam(usage, GL_FLOAT, 1, resParam.GetData(), &nodeMemory);
659                         ptr = data->m_Stream[0];
660                     }
661                     break;
662                 case PARTICLEUSAGE_TRANSLATE:
663                 case PARTICLEUSAGE_SCALE:
664                 case PARTICLEUSAGE_ROTATE:
665                 case PARTICLEUSAGE_COLOR:
666                 case PARTICLEUSAGE_SCALE_EXT:
667                     {
668                         ParticleShape::VertexAttribute* data =
669                             shape->AddVertexParam(usage, GL_FLOAT, 3, resParam.GetData(), &nodeMemory);
670                         ptr = data->m_Stream[0];
671                     }
672                     break;
673                 case PARTICLEUSAGE_TEXTURETRANSLATE0:
674                 case PARTICLEUSAGE_TEXTURESCALE0:
675                     {
676                         ParticleShape::VertexAttribute* data =
677                             shape->AddVertexParam(usage, GL_FLOAT, 2, resParam.GetData(), &nodeMemory);
678                         ptr = data->m_Stream[0];
679                     }
680                     break;
681                 }
682 
683                 hasAttribute[usage] = true;
684                 node->m_IsStream[usage] = false;
685                 node->m_StreamPtr[usage][0] = ptr;
686                 node->m_StreamPtr[usage][1] = ptr;
687                 node->m_StreamStride[usage] = 0;
688             }
689             else
690             {
691                 switch (usage)
692                 {
693                 case PARTICLEUSAGE_BIRTH:
694                 case PARTICLEUSAGE_LIFE:
695                     ParticleStreamCreate<ParticleTime>(
696                         &node->m_ParticleAttribute[usage], static_cast<ParticleUsage>(usage), capacity, &nodeMemory);
697                     node->m_StreamPtr[usage][0] = node->m_ParticleAttribute[usage].m_Stream;
698                     node->m_StreamPtr[usage][1] = node->m_ParticleAttribute[usage].m_Stream;
699                     node->m_StreamStride[usage] = 4;
700                     break;
701                 case PARTICLEUSAGE_VELOCITY:
702                     ParticleStreamCreate<nw::math::VEC3>(
703                         &node->m_ParticleAttribute[usage], static_cast<ParticleUsage>(usage), capacity, &nodeMemory);
704                     node->m_StreamPtr[usage][0] = node->m_ParticleAttribute[usage].m_Stream;
705                     node->m_StreamPtr[usage][1] = node->m_ParticleAttribute[usage].m_Stream;
706                     node->m_StreamStride[usage] = 12;
707                     break;
708                 case PARTICLEUSAGE_ALPHA:
709                 case PARTICLEUSAGE_TEXTUREROTATE0:
710                     {
711                         ParticleShape::VertexAttribute* datas = shape->AddVertexStream(usage, GL_FLOAT, 1, capacity, &deviceMemory);
712                         node->m_StreamPtr[usage][0] = datas->m_Stream[0];
713                         node->m_StreamPtr[usage][1] = datas->m_Stream[1];
714                         node->m_StreamStride[usage] = 4;
715                     }
716                     break;
717                 case PARTICLEUSAGE_TRANSLATE:
718                 case PARTICLEUSAGE_SCALE:
719                 case PARTICLEUSAGE_ROTATE:
720                 case PARTICLEUSAGE_COLOR:
721                 case PARTICLEUSAGE_SCALE_EXT:
722                     {
723                         ParticleShape::VertexAttribute* datas = shape->AddVertexStream(usage, GL_FLOAT, 3, capacity, &deviceMemory);
724                         node->m_StreamPtr[usage][0] = datas->m_Stream[0];
725                         node->m_StreamPtr[usage][1] = datas->m_Stream[1];
726                         node->m_StreamStride[usage] = 12;
727                     }
728                     break;
729                 case PARTICLEUSAGE_TEXTURETRANSLATE0:
730                 case PARTICLEUSAGE_TEXTURESCALE0:
731                     {
732                         ParticleShape::VertexAttribute* datas = shape->AddVertexStream(usage, GL_FLOAT, 2, capacity, &deviceMemory);
733                         node->m_StreamPtr[usage][0] = datas->m_Stream[0];
734                         node->m_StreamPtr[usage][1] = datas->m_Stream[1];
735                         node->m_StreamStride[usage] = 8;
736                     }
737                     break;
738                 }
739 
740                 node->m_IsStream[usage] = true;
741                 hasAttribute[usage] = true;
742             }
743         }
744 
745         for (int usage = 0; usage < PARTICLEUSAGE_COUNT; ++usage)
746         {
747             if (!hasAttribute[usage])
748             {
749                 float paramZero[] = {0.0f, 0.0f, 0.0f, 0.0f};
750                 float paramOne[] = {1.0f, 1.0f, 1.0f, 1.0f};
751 
752                 void* ptr = NULL;
753 
754                 switch (usage)
755                 {
756                 case PARTICLEUSAGE_BIRTH:
757                 case PARTICLEUSAGE_LIFE:
758                 case PARTICLEUSAGE_VELOCITY:
759                     NW_FATAL_ERROR("PARTICLEUSAGE_BIRTH/LIFE/VELOCITY must not be ParameterAttribute");
760                     break;
761                 case PARTICLEUSAGE_ALPHA:
762                     {
763                         ParticleShape::VertexAttribute* data =
764                             shape->AddVertexParam(usage, GL_FLOAT, 1, paramOne, &nodeMemory);
765                         ptr = data->m_Stream[0];
766                     }
767                     break;
768                 case PARTICLEUSAGE_TEXTUREROTATE0:
769                     {
770                         ParticleShape::VertexAttribute* data =
771                             shape->AddVertexParam(usage, GL_FLOAT, 1, paramZero, &nodeMemory);
772                         ptr = data->m_Stream[0];
773                     }
774                     break;
775                 case PARTICLEUSAGE_TRANSLATE:
776                 case PARTICLEUSAGE_ROTATE:
777                     {
778                         ParticleShape::VertexAttribute* data =
779                             shape->AddVertexParam(usage, GL_FLOAT, 3, paramZero, &nodeMemory);
780                         ptr = data->m_Stream[0];
781                     }
782                     break;
783                 case PARTICLEUSAGE_COLOR:
784                 case PARTICLEUSAGE_SCALE:
785                 case PARTICLEUSAGE_SCALE_EXT:
786                     {
787                         ParticleShape::VertexAttribute* data =
788                             shape->AddVertexParam(usage, GL_FLOAT, 3, paramOne, &nodeMemory);
789                         ptr = data->m_Stream[0];
790                     }
791                     break;
792                 case PARTICLEUSAGE_TEXTURETRANSLATE0:
793                     {
794                         ParticleShape::VertexAttribute* data =
795                             shape->AddVertexParam(usage, GL_FLOAT, 2, paramZero, &nodeMemory);
796                         ptr = data->m_Stream[0];
797                     }
798                     break;
799                 case PARTICLEUSAGE_TEXTURESCALE0:
800                     {
801                         ParticleShape::VertexAttribute* data =
802                             shape->AddVertexParam(usage, GL_FLOAT, 2, paramOne, &nodeMemory);
803                         ptr = data->m_Stream[0];
804                     }
805                     break;
806                 }
807 
808                 hasAttribute[usage] = true;
809                 node->m_IsStream[usage] = false;
810                 node->m_StreamPtr[usage][0] = ptr;
811                 node->m_StreamPtr[usage][1] = ptr;
812                 node->m_StreamStride[usage] = 0;
813             }
814         }
815     }
816 
817     node->Clear();
818 
819     if (parent)
820     {
821         bool result = parent->AttachParticleCollection(node);
822         NW_ASSERT(result);
823 
824         node->m_ParticleSet = parent;
825     }
826 
827     return node;
828 }
829 
830 //----------------------------------------
ParticleCollection(os::IAllocator * allocator,os::IAllocator * deviceAllocator,void * deviceMemory,ResParticleCollection resObj)831 ParticleCollection::ParticleCollection(
832     os::IAllocator* allocator,
833     os::IAllocator* deviceAllocator,
834     void* deviceMemory,
835     ResParticleCollection resObj
836 )
837 : GfxObject(allocator),
838   m_BufferSide(false),
839   m_MinActiveIndex(0),
840   m_MaxActiveIndex(0),
841   m_ResParticleCollection(resObj),
842   m_ParticleShape(NULL),
843   m_ParticleSet(NULL),
844   m_DeviceAllocator(deviceAllocator),
845   m_DeviceMemory(deviceMemory)
846 {
847     NW_UNUSED_VARIABLE(resObj)
848 
849     for (int i = 0; i < PARTICLEUSAGE_COUNT; ++i)
850     {
851         this->m_ParticleAttribute[i].m_Stream = NULL;
852         this->m_StreamStride[i] = 0;
853 
854         this->m_IsStream[i] = false;
855         for (int j = 0; j < 2; ++j)
856         {
857             this->m_StreamPtr[i][j] = NULL;
858         }
859     }
860 }
861 
862 //----------------------------------------
~ParticleCollection()863 ParticleCollection::~ParticleCollection()
864 {
865     if (m_DeviceMemory != NULL)
866     {
867         m_DeviceAllocator->Free(m_DeviceMemory);
868     }
869 
870     for (int i = 0; i < PARTICLEUSAGE_COUNT; ++i)
871     {
872         if (this->m_ParticleAttribute[i].m_Stream != NULL)
873         {
874             this->m_ParticleAttribute[i].m_Stream = NULL;
875         }
876 
877         for (int j = 0; j < 2; ++j)
878         {
879             this->m_StreamPtr[i][j] = NULL;
880         }
881     }
882 }
883 
884 //----------------------------------------
885 void
Clear()886 ParticleCollection::Clear()
887 {
888     const int capacity = this->GetCapacity();
889 
890     this->SetCount(0);
891     this->SetMinActiveIndex(0xffff);
892     this->SetMaxActiveIndex(0);
893 
894     // 生まれた順でアクティブなインデックスが格納されている
895     for (int j = 0; j < 2; ++j)
896     {
897         u16* ptr = (u16*)this->GetStreamPtr(PARTICLEUSAGE_ACTIVEINDEX, (ParticleBuffer)j);
898         std::memset(ptr, 0xff, sizeof(u16) * capacity);
899     }
900 
901     // 使用可能なインデックスが前詰めで格納されている
902     {
903         u16* ptr = (u16*)this->GetStreamPtr(PARTICLEUSAGE_FREEINDEX, PARTICLE_BUFFER_FRONT);
904         for (int i = capacity - 1; i >= 0; --i)
905         {
906             *ptr++ = i;
907         }
908     }
909 
910 #if 0
911     // 消滅する時刻(高速化のため)
912     {
913         f32* ptr = (f32*)this->GetStreamPtr(PARTICLEUSAGE_NEG_TIMELIMIT, PARTICLE_BUFFER_FRONT);
914         std::memset(ptr, 0xff, sizeof(f32) * capacity);
915     }
916 #endif
917 }
918 
919 //----------------------------------------
920 void
SetParameter(ParticleUsage usage,ParticleBuffer side,const f32 * ptr)921 ParticleCollection::SetParameter(
922     ParticleUsage usage,
923     ParticleBuffer side,
924     const f32* ptr
925 )
926 {
927     NW_ASSERT(usage >= 0 && usage < PARTICLEUSAGE_COUNT);
928 
929     if (this->m_IsStream[usage])
930     {
931         return;
932     }
933 
934     // 非VBOから検索
935     for (int i = 0; i < PARTICLEUSAGE_COUNT; ++i)
936     {
937         if (this->m_ParticleAttribute[i].m_Usage == usage)
938         {
939             nw::os::MemCpy(
940                 this->m_ParticleAttribute[i].m_Stream,
941                 ptr,
942                 sizeof(ParticleTime)); // TBD:LIFEしかないはずなので固定
943             return; // 見つかったので終了する
944         }
945     }
946 
947     // VBO
948     for (int i = 0; i < this->m_ParticleShape->GetVertexAttributesCount(); ++i)
949     {
950         if (this->m_ParticleShape->GetVertexAttributeUsage(i) == usage)
951         {
952             this->m_ParticleShape->SetVertexParameter(i, side, ptr);
953             return;
954         }
955     }
956 }
957 
958 } // namespace gfx
959 } // namespace nw
960