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