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