1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_MeshRenderer.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: 25742 $
14  *---------------------------------------------------------------------------*/
15 
16 // パーティクルのストリームに不正値が含まれていないかを調べる定義です。
17 // ストリーム内の全要素を調べるため、デバッグ時のみ有効にしてあります。
18 #ifdef NW_DEBUG
19 #define NW_GFX_CHECK_PARTICLE_STREAMS
20 #endif
21 
22 #include "precompiled.h"
23 
24 #include <nw/gfx/gfx_Common.h>
25 #include <nw/gfx/res/gfx_ResMesh.h>
26 #include <nw/gfx/res/gfx_ResParticleShape.h>
27 #include <nw/gfx/gfx_SceneObject.h>
28 #include <nw/gfx/gfx_MeshRenderer.h>
29 #include <nw/gfx/gfx_RenderContext.h>
30 #include <nw/gfx/gfx_ShaderProgram.h>
31 #include <nw/gfx/gfx_SkeletalModel.h>
32 #include <nw/gfx/gfx_Skeleton.h>
33 #include <nw/gfx/gfx_ParticleModel.h>
34 #include <nw/gfx/gfx_ParticleShape.h>
35 #include <nw/os/os_Memory.h>
36 #include <nw/types.h>
37 #include <nw/ut/ut_Inlines.h>
38 #include <nw/ut/ut_ResUtil.h>
39 #include <nw/ut/ut_ResDictionary.h>
40 #include <nw/ut/ut_Foreach.h>
41 #include <nw/dev.h>
42 #include <nw/gfx/gfx_CommandUtil.h>
43 #include <nw/gfx/gfx_ActivateCommand.h>
44 
45 #include <GLES2/gl2.h>
46 #include <GLES2/gl2ext.h>
47 
48 #include <cmath>
49 
50 namespace nw
51 {
52 namespace gfx
53 {
54 
55 namespace internal
56 {
57 
58 //! @brief 頂点シェーダーのレジスタが上書きされていないか確認します。
TestRegisterOverride(int matrixpaletteCount,bool isNonuniformScalable,RenderContext * renderContext)59 bool TestRegisterOverride(int matrixpaletteCount, bool isNonuniformScalable, RenderContext* renderContext)
60 {
61     NW_ASSERT(renderContext->GetShaderProgram()->GetActiveDescription().IsValid());
62 
63     int vertexLightEndUniform = renderContext->GetShaderProgram()->GetActiveDescription().GetVertexLightEndUniform();
64     int vertexLightCount = renderContext->GetSceneEnvironment().GetVertexLightCount();
65     const int UNIT_COUNT = 3;
66     const int VERTEX_LIGHT_REGISTER_COUNT = 6;
67     int usedMatrixpaletteCount = 0;
68     if (isNonuniformScalable)
69     {
70         usedMatrixpaletteCount = UNIT_COUNT * matrixpaletteCount * 2 + vertexLightCount * VERTEX_LIGHT_REGISTER_COUNT;
71     }
72     else
73     {
74         usedMatrixpaletteCount = UNIT_COUNT * matrixpaletteCount + vertexLightCount * VERTEX_LIGHT_REGISTER_COUNT;
75     }
76 
77     return (usedMatrixpaletteCount <= vertexLightEndUniform);
78 }
79 
80 }
81 
82 //----------------------------------------
83 MeshRenderer*
Create(nw::os::IAllocator * pAllocator)84 MeshRenderer::Create(nw::os::IAllocator* pAllocator)
85 {
86     NW_NULL_ASSERT(pAllocator);
87 
88     size_t size = sizeof(MeshRenderer);
89 
90     void* buf = pAllocator->Alloc(size);
91 
92     return new(buf) MeshRenderer(pAllocator);
93 }
94 
95 //----------------------------------------
96 void
RenderMesh(ResMesh mesh,Model * model)97 MeshRenderer::RenderMesh(ResMesh mesh, Model* model)
98 {
99     NW_ASSERT(mesh.IsValid());
100 
101     // Mesh の頂点設定を有効化。
102     ResShape shape = model->GetResModel().GetShapes(mesh.GetShapeIndex());
103 
104     switch ( shape.ref().typeInfo )
105     {
106     case ResSeparateDataShape::TYPE_INFO:
107         {
108             m_RenderContext->SetMaterial(model->GetMaterial(mesh.GetMaterialIndex()));
109 
110             // コンテキストを有効化します
111             m_RenderContext->ActivateContext();
112 
113             if (m_RenderContext->GetModelCache() != model)
114             {
115                 m_RenderContext->SetModelMatrix(model);
116             }
117 
118             m_RenderContext->ActivateVertexAttribute( mesh );
119 
120             RenderSeparateDataShape(
121                 model,
122                 ResStaticCast<ResSeparateDataShape>(shape),
123                 mesh.GetCurrentPrimitiveIndex());
124 
125             m_RenderContext->DeactivateVertexAttribute( mesh );
126         }
127         break;
128     case ResParticleShape::TYPE_INFO:
129         {
130             ParticleModel* particleModel = static_cast<ParticleModel*>(model);
131             NW_NULL_ASSERT(particleModel);
132 
133             ParticleSet* particleSet = particleModel->GetParticleSets(mesh.GetShapeIndex());
134             if (particleSet->GetParticleCollection()->GetCount() == 0)
135             {
136                 return;
137             }
138 
139             m_RenderContext->SetMaterial(model->GetMaterial(mesh.GetMaterialIndex()));
140 
141             // コンテキストを有効化します
142             m_RenderContext->ActivateParticleContext();
143 
144             RenderParticleShape(
145                 model,
146                 ResStaticCast<ResParticleShape>(shape),
147                 mesh.GetShapeIndex());
148         }
149         break;
150     default:
151         {
152             NW_FATAL_ERROR("Unsupported data shape type.");
153         }
154     }
155 }
156 
157 //----------------------------------------
158 void
RenderSeparateDataShape(Model * model,ResSeparateDataShape shape,s32 currentPrimitiveIndex)159 MeshRenderer::RenderSeparateDataShape(
160     Model* model,
161     ResSeparateDataShape shape,
162     s32 currentPrimitiveIndex
163 )
164 {
165     NW_NULL_ASSERT(m_RenderContext);
166     if (!shape.IsValid()) { return; }
167 
168     const ShaderProgram* shaderProgram = m_RenderContext->GetShaderProgram();
169 
170     internal::NWSetVertexUniform3fv( VERTEX_SHADER_UNIFORM_POSOFFS_INDEX, 1, shape.GetPositionOffset() );
171 
172     SkeletalModel* skeletalModel = ut::DynamicCast<SkeletalModel*>(model);
173 
174     ResPrimitiveSetArray primitiveSets = shape.GetPrimitiveSets();
175     ResPrimitiveSetArray::iterator primitiveSetEnd = primitiveSets.end();
176 
177     for (ResPrimitiveSetArray::iterator primitiveSet = primitiveSets.begin();
178         primitiveSet != primitiveSetEnd; ++primitiveSet)
179     {
180         NW_ASSERT((*primitiveSet).IsValid());
181         NW_ASSERT(0 <= currentPrimitiveIndex &&
182                   currentPrimitiveIndex < (*primitiveSet).GetPrimitivesCount());
183 
184         s32 boneIndexCount = (*primitiveSet).GetBoneIndexTableCount();
185 
186         NW_ASSERTMSG(
187             internal::TestRegisterOverride(
188                 boneIndexCount,
189                 model->GetResModel().IsNonuniformScalable(),
190                 m_RenderContext
191              ),
192             "Vertex-lights or user-registers might be overridden by bone matrices.%s", model->GetResModel().GetName()
193         );
194 
195         if (skeletalModel && boneIndexCount != 0)
196         {
197             this->SetMatrixPalette(
198                 skeletalModel,
199                 *primitiveSet,
200                 boneIndexCount
201             );
202         }
203         else
204         {
205             shaderProgram->SetVertexUniformBool(NW_GFX_VERTEX_UNIFORM(ISSMOSK), false);
206             shaderProgram->SetVertexUniformBool(NW_GFX_VERTEX_UNIFORM(ISRGDSK), false);
207 
208             m_RenderContext->SetMatrixPaletteCount(1);
209 #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED
210             math::MTX34 worldMatrix(model->WorldMatrix());
211             MTX34MultTranslate(&worldMatrix, m_RenderContext->ModelTranslateOffset(), worldMatrix);
212             shaderProgram->SetUniversal(0, worldMatrix);
213 #else
214             shaderProgram->SetUniversal(0, model->WorldMatrix());
215 #endif
216         }
217 
218         m_RenderContext->RenderPrimitive((*primitiveSet).GetPrimitives(currentPrimitiveIndex));
219     }
220 }
221 
222 //----------------------------------------
223 namespace internal
224 {
225 static bool
isIllegal(f32 val)226 isIllegal(f32 val)
227 {
228 //    return isnan(val);
229     return !isfinite(val);
230 }
231 
232 static bool
isIllegal(const math::VEC3 & vec)233 isIllegal(const math::VEC3& vec)
234 {
235     return isIllegal(vec.x) || isIllegal(vec.y) || isIllegal(vec.z);
236 }
237 
238 static bool
isIllegal(const math::MTX34 & mtx)239 isIllegal(const math::MTX34& mtx)
240 {
241     return
242         isIllegal(mtx._00) || isIllegal(mtx._01) || isIllegal(mtx._02) || isIllegal(mtx._03) ||
243         isIllegal(mtx._10) || isIllegal(mtx._11) || isIllegal(mtx._12) || isIllegal(mtx._13) ||
244         isIllegal(mtx._20) || isIllegal(mtx._21) || isIllegal(mtx._22) || isIllegal(mtx._23);
245 }
246 }
247 
248 //----------------------------------------
249 void
RenderParticleShape(Model * model,ResParticleShape resource,int shapeIndex)250 MeshRenderer::RenderParticleShape(
251     Model* model,
252     ResParticleShape resource,
253     int shapeIndex
254 )
255 {
256     NW_NULL_ASSERT(m_RenderContext);
257     if (!resource.IsValid()) { return; }
258 
259     ParticleModel* particleModel = static_cast<ParticleModel*>(model);
260     NW_NULL_ASSERT(particleModel);
261 
262     ParticleSet* particleSet = particleModel->GetParticleSets(shapeIndex);
263 
264     const ResParticleSet& resParticleSet = particleSet->GetResParticleSet();
265 
266     ParticleShape* particleShape = particleModel->GetParticleShapes(shapeIndex);
267     NW_NULL_ASSERT(particleShape);
268 
269     NW_ASSERT(particleShape->GetResParticleShape().ptr() == resource.ptr());
270 
271     if (particleSet->GetParticleCollection()->GetCount() == 0)
272     {
273         return;
274     }
275 
276     if (resParticleSet.GetIsBufferFlushEnabled())
277     {
278         particleShape->FlushBuffer();
279     }
280 
281     int bufferSide = particleShape->GetBufferSide();
282     internal::NWUseCmdlist(particleShape->m_CommandCache[bufferSide], particleShape->m_CommandCacheSize[bufferSide]);
283 
284     enum
285     {
286         REG_UNIFORM_FLOAT_INDEX = 0x2c0,
287         REG_VS_FLOAT_DATA1      = 0x2c1,
288         REG_INDEX_STREAM_OFFSET = 0x227,
289         REG_INDEX_STREAM_COUNT      = 0x228
290     };
291 
292     // c6-c7
293     u32* command = (u32*)internal::NWGetCurrentCmdBuffer();
294     int commandIndex = 0;
295 
296     command[commandIndex++] = 0x80000000 | VERTEX_SHADER_UNIFORM_POSOFFS_INDEX;
297     command[commandIndex++] = internal::MakeCommandHeader(REG_UNIFORM_FLOAT_INDEX, 1 + 4, true, 0xF);
298     command[commandIndex++] = 0;
299     command[commandIndex++] = *(u32*)&resource.GetPositionOffset().z;
300     command[commandIndex++] = *(u32*)&resource.GetPositionOffset().y;
301     command[commandIndex++] = *(u32*)&resource.GetPositionOffset().x;
302     NW_ASSERT(!internal::isIllegal(resource.GetPositionOffset()));
303 
304     // universal
305     Camera* camera = m_RenderContext->GetActiveCamera();
306     NW_NULL_ASSERT(camera);
307 
308     const u32 HEADER_UNIFORM_FLOAT_INDEX = internal::MakeCommandHeader(REG_UNIFORM_FLOAT_INDEX, 1, false, 0xF);
309 
310     command[commandIndex++] = 0x80000000 | VERTEX_SHADER_UNIFORM_UNIVREG_INDEX;
311     command[commandIndex++] = HEADER_UNIFORM_FLOAT_INDEX;
312 
313     const int universalNum = 15;
314 
315     if (particleSet->GetResParticleSet().GetIsForceWorld())
316     {
317         // modelを強制的に単位行列とする
318 
319         // view . model = view . I = view
320         NW_ASSERT(!internal::isIllegal(camera->ViewMatrix()));
321         internal::NWCopyMtx34WithHeader(
322             (f32*)&command[commandIndex],
323             (f32*)&camera->ViewMatrix(),
324             internal::MakeCommandHeader(REG_VS_FLOAT_DATA1, 4 * universalNum, false, 0xF));
325         commandIndex += 12 + 1;
326 
327         // Inv(view . model) = Inv(view . I) = Inv(view)
328         NW_ASSERT(!internal::isIllegal(camera->InverseViewMatrix()));
329         internal::NWCopyMtx34Reverse(
330             (f32*)&command[commandIndex],
331             (f32*)&camera->InverseViewMatrix());
332         commandIndex += 12;
333 
334         // Inv(model)
335         command[commandIndex++] = 0;
336         command[commandIndex++] = 0;
337         command[commandIndex++] = 0;
338         command[commandIndex++] = 0x3f800000;
339 
340         command[commandIndex++] = 0;
341         command[commandIndex++] = 0;
342         command[commandIndex++] = 0x3f800000;
343         command[commandIndex++] = 0;
344 
345         command[commandIndex++] = 0;
346         command[commandIndex++] = 0x3f800000;
347         command[commandIndex++] = 0;
348         command[commandIndex++] = 0;
349 
350         // model
351         command[commandIndex++] = 0;
352         command[commandIndex++] = 0;
353         command[commandIndex++] = 0;
354         command[commandIndex++] = 0x3f800000;
355 
356         command[commandIndex++] = 0;
357         command[commandIndex++] = 0;
358         command[commandIndex++] = 0x3f800000;
359         command[commandIndex++] = 0;
360 
361         command[commandIndex++] = 0;
362         command[commandIndex++] = 0x3f800000;
363         command[commandIndex++] = 0;
364         command[commandIndex++] = 0;
365     }
366     else
367     {
368         nw::math::MTX34* worldMatrix;
369 
370 #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED
371         math::MTX34 offsetMatrix(model->WorldMatrix());
372         worldMatrix = &offsetMatrix;
373         MTX34MultTranslate(worldMatrix, m_RenderContext->ModelTranslateOffset(), *worldMatrix);
374 #else
375         worldMatrix = &model->WorldMatrix();
376 #endif
377 
378         nw::math::MTX34 modelView;
379         nw::math::MTX34Mult(&modelView, camera->ViewMatrix(), *worldMatrix);
380         NW_ASSERT(!internal::isIllegal(modelView));
381         internal::NWCopyMtx34WithHeader(
382             (f32*)&command[commandIndex],
383             (f32*)&modelView,
384             internal::MakeCommandHeader(REG_VS_FLOAT_DATA1, 4 * universalNum, false, 0xF));
385         commandIndex += 12 + 1;
386 
387         // Inv(view . model) = Inv(model) . Inv(view)
388         nw::math::MTX34 invModelView;
389 
390 #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED
391         MTX34MultTranslate(&invModelView, -m_RenderContext->ModelTranslateOffset(), model->InverseWorldMatrix());
392         nw::math::MTX34Mult(&invModelView, invModelView, camera->InverseViewMatrix());
393 #else
394         nw::math::MTX34Mult(&invModelView, model->InverseWorldMatrix(), camera->InverseViewMatrix());
395 #endif
396 
397         NW_ASSERT(!internal::isIllegal(invModelView));
398         internal::NWCopyMtx34Reverse(
399             (f32*)&command[commandIndex],
400             (f32*)&invModelView);
401         commandIndex += 12;
402 
403         // Inv(model)
404         NW_ASSERT(!internal::isIllegal(model->InverseWorldMatrix()));
405         internal::NWCopyMtx34Reverse(
406             (f32*)&command[commandIndex],
407             (f32*)&model->InverseWorldMatrix());
408         commandIndex += 12;
409 
410         // model
411         NW_ASSERT(!internal::isIllegal(model->WorldMatrix()));
412         internal::NWCopyMtx34Reverse(
413             (f32*)&command[commandIndex],
414             (f32*)worldMatrix);
415         commandIndex += 12;
416     }
417 
418     math::VEC3 offset(0.0f, 0.0f, 0.0f);
419     const ResParticleShapeBuilder& resShapeBuilder = resParticleSet.GetParticleShapeBuilder();
420     if (resShapeBuilder.IsValid())
421     {
422         offset = resShapeBuilder.GetDrawOffset();
423     }
424 
425     NW_ASSERT(!internal::isIllegal(offset));
426     internal::NWCopyVec3Reverse(
427         (f32*)&command[commandIndex],
428         (f32*)&offset);
429     commandIndex += 4;
430 
431     NW_ASSERT(!internal::isIllegal(particleSet->GetScaleOffset()));
432     internal::NWCopyVec3Reverse(
433         (f32*)&command[commandIndex],
434         (f32*)&particleSet->GetScaleOffset());
435     commandIndex += 4;
436 
437     NW_ASSERT(!internal::isIllegal(particleSet->GetRotateOffset()));
438     internal::NWCopyVec3Reverse(
439         (f32*)&command[commandIndex],
440         (f32*)&particleSet->GetRotateOffset());
441     commandIndex += 4;
442 
443     if ((commandIndex & 1) == 1)
444     {
445         command[commandIndex++] = 0; // padding
446     }
447 
448     const u32 HEADER_INDEX_STREAM_COUNT = internal::MakeCommandHeader(REG_INDEX_STREAM_COUNT, 1, false, 0xF);
449 
450     command[commandIndex++] = particleSet->GetParticleCollection()->GetCount();
451     command[commandIndex++] = HEADER_INDEX_STREAM_COUNT;
452 
453     u32 streamOffset = particleShape->GetPrimitiveStreamOffset(PARTICLE_BUFFER_FRONT);
454 
455     const bool isAscendingOrder = (resShapeBuilder.IsValid())? resShapeBuilder.IsAscendingOrder() : true;
456     if (!isAscendingOrder)
457     {
458         ParticleCollection* collection = particleSet->GetParticleCollection();
459         streamOffset += sizeof(u16) * (collection->GetCapacity() - collection->GetCount());
460     }
461 
462     const u32 HEADER_INDEX_STREAM_OFFSET = internal::MakeCommandHeader(REG_INDEX_STREAM_OFFSET, 1, false, 0xF);
463 
464     command[commandIndex++] = 0x80000000 | streamOffset;
465     command[commandIndex++] = HEADER_INDEX_STREAM_OFFSET;
466 
467     internal::NWForwardCurrentCmdBuffer(sizeof(u32) * commandIndex);
468 
469 #ifdef NW_GFX_CHECK_PARTICLE_STREAMS
470     for (int index = 0; index < particleShape->GetVertexAttributesCount(); ++index)
471     {
472         int format = particleShape->GetVertexAttributeFormatType(index);
473         if (format != GL_FLOAT)
474         {
475             continue;
476         }
477 
478         if (particleShape->IsVertexStream(index))
479         {
480             // stream
481             int count = particleShape->GetVertexCapacity();
482             count *= particleShape->GetVertexAttributeDimension(index);
483 
484             const f32* ptr = reinterpret_cast<const f32*>(
485                 particleShape->GetVertexStreamPtr(index, PARTICLE_BUFFER_FRONT));
486             for (int i = 0; i < count; ++i)
487             {
488                 NW_ASSERT(!internal::isIllegal(ptr[i]));
489             }
490         }
491         else
492         {
493             // param
494             int count = 1;
495             count *= particleShape->GetVertexAttributeDimension(index);
496 
497             const f32* ptr = particleShape->GetVertexParameter(index);
498             for (int i = 0; i < count; ++i)
499             {
500                 NW_ASSERT(!internal::isIllegal(ptr[i]));
501             }
502         }
503     }
504 #endif
505 
506     internal::NWUseCmdlist(
507         particleShape->m_PrimitiveCommandCache,
508         particleShape->m_PrimitiveCommandCacheSize);
509 
510     internal::NWUseCmdlist(
511         particleShape->m_DeactivateVertexCommandCache,
512         particleShape->m_DeactivateVertexCommandCacheSize);
513 }
514 
515 //----------------------------------------
516 void
SetMatrixPalette(SkeletalModel * skeletalModel,ResPrimitiveSet primitiveSet,s32 boneIndexCount)517 MeshRenderer::SetMatrixPalette(
518     SkeletalModel* skeletalModel,
519     ResPrimitiveSet primitiveSet,
520     s32 boneIndexCount)
521 {
522     NW_NULL_ASSERT(m_RenderContext);
523     NW_ASSERT(primitiveSet.IsValid());
524 
525     bool useNormalMatrix = false;
526     const int UNIT_COUNT = 3;
527 
528     //----------------------------------------
529     // マトリクスパレットに関する設定用レジスタをシェーダに設定します。
530     const ShaderProgram* shaderProgram = m_RenderContext->GetShaderProgram();
531 
532     //bool isRigid = boneIndexCount == 1 || primitiveSet.GetSkinningMode() != ResPrimitiveSet::SKINNING_MODE_SMOOTH;
533     bool isRigid = primitiveSet.GetSkinningMode() != ResPrimitiveSet::SKINNING_MODE_SMOOTH;
534     shaderProgram->SetVertexUniformBool(NW_GFX_VERTEX_UNIFORM(ISSMOSK), !isRigid);
535     shaderProgram->SetVertexUniformBool(NW_GFX_VERTEX_UNIFORM(ISRGDSK), isRigid);
536 
537     m_RenderContext->SetMatrixPaletteCount(boneIndexCount);
538 
539     //----------------------------------------
540     // ボーンの種類に合わせたマトリクスを取得し、シェーダに設定します。
541     Skeleton* skeleton = skeletalModel->GetSkeleton();
542     ResSkeleton resSkeleton = skeleton->GetResSkeleton();
543     Skeleton::MatrixPose& matrixPose = skeleton->WorldMatrixPose();
544     Skeleton::MatrixPose& skiningPose = skeleton->SkiningMatrixPose();
545 
546     const int normalMatrixOffset = boneIndexCount * UNIT_COUNT;
547 
548 #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED
549     const bool isModelCoordinate =
550         ut::CheckFlag(resSkeleton.GetFlags(), ResSkeletonData::FLAG_MODEL_COORDINATE);
551 #endif
552 
553     for (int count = 0; count < boneIndexCount; ++count)
554     {
555         s32 boneIndex = primitiveSet.GetBoneIndexTable(count);
556 
557         // マトリクスを取得してきます。
558         ResBone bone = resSkeleton.GetBones(boneIndex);
559         bool hasSkinningMatrix = (bone.GetFlags() & ResBoneData::FLAG_HAS_SKINNING_MATRIX) != 0;
560         Skeleton::MatrixPose* pose =
561             (!isRigid && hasSkinningMatrix) ? &skiningPose : &matrixPose;
562 
563         math::MTX34* matrix;
564 
565 #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED
566         math::MTX34 offsetMatrix;
567         if (isModelCoordinate)
568         {
569             matrix = pose->GetMatrix(boneIndex);
570         }
571         else
572         {
573             offsetMatrix = *pose->GetMatrix(boneIndex);
574             matrix = &offsetMatrix;
575             MTX34MultTranslate(matrix, m_RenderContext->ModelTranslateOffset(), *matrix);
576         }
577 #else
578         matrix = pose->GetMatrix(boneIndex);
579 #endif
580 
581         // マトリクスを設定します。
582         int index = count * UNIT_COUNT;
583 
584         if (count == 0)
585         {
586             internal::NWSetVertexUniform4fvBegin(
587                 VERTEX_SHADER_UNIFORM_UNIVREG_INDEX + index,
588                 boneIndexCount * UNIT_COUNT,
589                 UNIT_COUNT,
590                 *matrix);
591         }
592         else
593         {
594             internal::NWSetVertexUniform4fvContinuous(UNIT_COUNT, *matrix);
595         }
596 
597         if (useNormalMatrix)
598         {
599             // TODO: 現状ではここには到達しない。
600             math::MTX34 normalMatrix(*pose->GetMatrix(boneIndex));
601             math::MTX34Inverse(&normalMatrix, normalMatrix);
602             math::MTX34Transpose(&normalMatrix, normalMatrix);
603             shaderProgram->SetUniversal(
604                 normalMatrixOffset + index, normalMatrix);
605         }
606     }
607 
608     internal::NWSetVertexUniform4fvEnd();
609 }
610 
611 } // namespace gfx
612 } // namespace nw
613 
614