1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_MeshRenderer.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: 31829 $
16 *---------------------------------------------------------------------------*/
17
18 // パーティクルのストリームに不正値が含まれていないかを調べる定義です。
19 // ストリーム内の全要素を調べるため、デバッグ時のみ有効にしてあります。
20 #ifdef NW_DEBUG
21 #define NW_GFX_CHECK_PARTICLE_STREAMS
22 #endif
23
24 #include "precompiled.h"
25
26 #include <nw/gfx/gfx_Common.h>
27 #include <nw/gfx/res/gfx_ResMesh.h>
28 #include <nw/gfx/res/gfx_ResParticleShape.h>
29 #include <nw/gfx/gfx_SceneObject.h>
30 #include <nw/gfx/gfx_MeshRenderer.h>
31 #include <nw/gfx/gfx_RenderContext.h>
32 #include <nw/gfx/gfx_ShaderProgram.h>
33 #include <nw/gfx/gfx_SkeletalModel.h>
34 #include <nw/gfx/gfx_Skeleton.h>
35 #include <nw/gfx/gfx_ParticleModel.h>
36 #include <nw/gfx/gfx_ParticleShape.h>
37 #include <nw/os/os_Memory.h>
38 #include <nw/types.h>
39 #include <nw/ut/ut_Inlines.h>
40 #include <nw/ut/ut_ResUtil.h>
41 #include <nw/ut/ut_ResDictionary.h>
42 #include <nw/ut/ut_Foreach.h>
43 #include <nw/dev.h>
44 #include <nw/gfx/gfx_CommandUtil.h>
45 #include <nw/gfx/gfx_ActivateCommand.h>
46
47 #include <GLES2/gl2.h>
48 #include <GLES2/gl2ext.h>
49
50 #include <cmath>
51
52 namespace nw
53 {
54 namespace gfx
55 {
56
57 namespace internal
58 {
59
60 //! @brief 頂点シェーダーのレジスタが上書きされていないか確認します。
TestRegisterOverride(int matrixpaletteCount,RenderContext * renderContext)61 bool TestRegisterOverride(int matrixpaletteCount, RenderContext* renderContext)
62 {
63 NW_ASSERT(renderContext->GetShaderProgram()->GetActiveDescription().IsValid());
64
65 int vertexLightEndUniform = renderContext->GetShaderProgram()->GetActiveDescription().GetVertexLightEndUniform();
66 int vertexLightCount = renderContext->GetSceneEnvironment().GetVertexLightCount();
67 const int UNIT_COUNT = 3;
68 const int VERTEX_LIGHT_REGISTER_COUNT = 6;
69 int usedMatrixpaletteCount = 0;
70 usedMatrixpaletteCount = UNIT_COUNT * matrixpaletteCount + vertexLightCount * VERTEX_LIGHT_REGISTER_COUNT;
71
72 return (usedMatrixpaletteCount <= vertexLightEndUniform);
73 }
74
75 }
76
77 //----------------------------------------
78 MeshRenderer*
Create(nw::os::IAllocator * pAllocator)79 MeshRenderer::Create(nw::os::IAllocator* pAllocator)
80 {
81 NW_NULL_ASSERT(pAllocator);
82
83 size_t size = sizeof(MeshRenderer);
84
85 void* buf = pAllocator->Alloc(size);
86
87 return new(buf) MeshRenderer(pAllocator);
88 }
89
90 //----------------------------------------
91 void
RenderMesh(ResMesh mesh,Model * model)92 MeshRenderer::RenderMesh(ResMesh mesh, Model* model)
93 {
94 NW_ASSERT(mesh.IsValid());
95
96 // Mesh の頂点設定を有効化。
97 ResShape shape = model->GetResModel().GetShapes(mesh.GetShapeIndex());
98
99 switch ( shape.ref().typeInfo )
100 {
101 case ResSeparateDataShape::TYPE_INFO:
102 {
103 m_RenderContext->SetMaterial(model->GetMaterial(mesh.GetMaterialIndex()));
104
105 // コンテキストを有効化します
106 m_RenderContext->ActivateContext();
107
108 m_RenderContext->ActivateVertexAttribute( mesh );
109
110 RenderSeparateDataShape(
111 model,
112 ResStaticCast<ResSeparateDataShape>(shape),
113 mesh.GetCurrentPrimitiveIndex());
114
115 m_RenderContext->DeactivateVertexAttribute( mesh );
116 }
117 break;
118 case ResParticleShape::TYPE_INFO:
119 {
120 ParticleModel* particleModel = static_cast<ParticleModel*>(model);
121 NW_NULL_ASSERT(particleModel);
122
123 ParticleSet* particleSet = particleModel->GetParticleSets(mesh.GetShapeIndex());
124 #ifdef NW_CHECK_PARTICLE_PROCESS
125 particleSet->BeginDraw();
126 #endif
127 if (particleSet->GetParticleCollection()->GetCount() == 0)
128 {
129 return;
130 }
131
132 m_RenderContext->SetMaterial(model->GetMaterial(mesh.GetMaterialIndex()));
133
134 // コンテキストを有効化します
135 m_RenderContext->ActivateParticleContext();
136
137 RenderParticleShape(
138 model,
139 ResStaticCast<ResParticleShape>(shape),
140 mesh.GetShapeIndex());
141 }
142 break;
143 default:
144 {
145 NW_FATAL_ERROR("Unsupported data shape type.");
146 }
147 }
148 }
149
150 //----------------------------------------
151 void
RenderSeparateDataShape(Model * model,ResSeparateDataShape shape,s32 currentPrimitiveIndex)152 MeshRenderer::RenderSeparateDataShape(
153 Model* model,
154 ResSeparateDataShape shape,
155 s32 currentPrimitiveIndex
156 )
157 {
158 NW_NULL_ASSERT(m_RenderContext);
159 if (!shape.IsValid()) { return; }
160
161 internal::NWSetVertexUniform3fv( VERTEX_SHADER_UNIFORM_POSOFFS_INDEX, 1, shape.GetPositionOffset() );
162
163 SkeletalModel* skeletalModel = ut::DynamicCast<SkeletalModel*>(model);
164
165 if (m_RenderContext->GetModelCache() != model)
166 {
167 if (skeletalModel)
168 {
169 m_RenderContext->SetModelMatrixForSkeletalModel(skeletalModel);
170 }
171 else
172 {
173 m_RenderContext->SetModelMatrixForModel(model);
174 }
175 }
176
177 ResPrimitiveSetArray primitiveSets = shape.GetPrimitiveSets();
178 ResPrimitiveSetArray::iterator primitiveSetEnd = primitiveSets.end();
179
180 for (ResPrimitiveSetArray::iterator primitiveSet = primitiveSets.begin();
181 primitiveSet != primitiveSetEnd; ++primitiveSet)
182 {
183 NW_ASSERT((*primitiveSet).IsValid());
184 NW_ASSERT(0 <= currentPrimitiveIndex &&
185 currentPrimitiveIndex < (*primitiveSet).GetPrimitivesCount());
186
187 s32 boneIndexCount = (*primitiveSet).GetBoneIndexTableCount();
188
189 NW_ASSERTMSG(
190 internal::TestRegisterOverride(
191 boneIndexCount,
192 m_RenderContext
193 ),
194 "Vertex-lights or user-registers might be overridden by bone matrices.%s", model->GetResModel().GetName()
195 );
196
197 if (skeletalModel == NULL || boneIndexCount == 0)
198 {
199 const ShaderProgram* shaderProgram = m_RenderContext->GetShaderProgram();
200
201 shaderProgram->SetVertexUniformBool(NW_GFX_VERTEX_UNIFORM(ISSMOSK), false);
202 shaderProgram->SetVertexUniformBool(NW_GFX_VERTEX_UNIFORM(ISRGDSK), false);
203
204 #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED
205 math::MTX34 worldMatrix(model->WorldMatrix());
206 MTX34MultTranslate(&worldMatrix, m_RenderContext->ModelTranslateOffset(), worldMatrix);
207 shaderProgram->SetUniversal(0, worldMatrix);
208 #else
209 shaderProgram->SetUniversal(0, model->WorldMatrix());
210 #endif
211 }
212 else
213 {
214 this->SetMatrixPalette(
215 skeletalModel,
216 *primitiveSet,
217 boneIndexCount
218 );
219 }
220
221 m_RenderContext->RenderPrimitive((*primitiveSet).GetPrimitives(currentPrimitiveIndex));
222 }
223 }
224
225 //----------------------------------------
226 namespace internal
227 {
228 static bool
isIllegal(f32 val)229 isIllegal(f32 val)
230 {
231 // return isnan(val);
232 return !isfinite(val);
233 }
234
235 static bool
isIllegal(const math::VEC3 & vec)236 isIllegal(const math::VEC3& vec)
237 {
238 return isIllegal(vec.x) || isIllegal(vec.y) || isIllegal(vec.z);
239 }
240
241 static bool
isIllegal(const math::MTX34 & mtx)242 isIllegal(const math::MTX34& mtx)
243 {
244 return
245 isIllegal(mtx._00) || isIllegal(mtx._01) || isIllegal(mtx._02) || isIllegal(mtx._03) ||
246 isIllegal(mtx._10) || isIllegal(mtx._11) || isIllegal(mtx._12) || isIllegal(mtx._13) ||
247 isIllegal(mtx._20) || isIllegal(mtx._21) || isIllegal(mtx._22) || isIllegal(mtx._23);
248 }
249 }
250
251 //----------------------------------------
252 void
RenderParticleShape(Model * model,ResParticleShape resource,int shapeIndex)253 MeshRenderer::RenderParticleShape(
254 Model* model,
255 ResParticleShape resource,
256 int shapeIndex
257 )
258 {
259 NW_NULL_ASSERT(m_RenderContext);
260 if (!resource.IsValid()) { return; }
261
262 ParticleModel* particleModel = static_cast<ParticleModel*>(model);
263 NW_NULL_ASSERT(particleModel);
264
265 ParticleSet* particleSet = particleModel->GetParticleSets(shapeIndex);
266
267 const ResParticleSet& resParticleSet = particleSet->GetResParticleSet();
268
269 ParticleShape* particleShape = particleModel->GetParticleShapes(shapeIndex);
270 NW_NULL_ASSERT(particleShape);
271
272 NW_ASSERT(particleShape->GetResParticleShape().ptr() == resource.ptr());
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