1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_RenderContext.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: 29284 $
14 *---------------------------------------------------------------------------*/
15
16 #include "precompiled.h"
17
18 #include <nw/math.h>
19 #include <nw/types.h>
20 #include <nw/gfx/gfx_ShaderProgram.h>
21 #include <nw/gfx/gfx_SceneObject.h>
22 #include <nw/gfx/gfx_Camera.h>
23 #include <nw/gfx/gfx_Fog.h>
24 #include <nw/gfx/gfx_FragmentLight.h>
25 #include <nw/gfx/gfx_VertexLight.h>
26 #include <nw/gfx/gfx_AmbientLight.h>
27 #include <nw/gfx/gfx_HemiSphereLight.h>
28 #include <nw/gfx/gfx_Material.h>
29 #include <nw/gfx/gfx_ParticleMaterialActivator.h>
30 #include <nw/gfx/gfx_RenderContext.h>
31 #include <nw/gfx/gfx_GraphicsDevice.h>
32 #include <nw/gfx/gfx_IRenderTarget.h>
33 #include <nw/gfx/gfx_OnScreenBuffer.h>
34 #include <nw/gfx/res/gfx_ResLookupTable.h>
35 #include <nw/gfx/gfx_Common.h>
36 #include <nw/gfx/res/gfx_ResGraphicsFile.h>
37 #include <nw/gfx/res/gfx_ResLight.h>
38 #include <nw/gfx/res/gfx_ResFog.h>
39 #include <nw/gfx/gfx_ShaderUniforms.h>
40 #include <nw/gfx/gfx_ActivateCommand.h>
41 #include <nw/ut/ut_Inlines.h>
42 #include <nw/ut/ut_ResUtil.h>
43 #include <nw/ut/ut_ResDictionary.h>
44 #include <nw/ut/ut_RuntimeTypeInfo.h>
45 #include <nw/ut/ut_Foreach.h>
46 #include <nw/gfx/gfx_CommandUtil.h>
47
48 #include <GLES2/gl2.h>
49 #include <GLES2/gl2ext.h>
50 #include <nw/dev.h>
51
52 #include <nn.h>
53
54
55 namespace
56 {
GetTranslate(const nw::math::MTX34 & transform)57 nw::math::VEC4 GetTranslate(const nw::math::MTX34& transform)
58 {
59 nw::math::VEC3 translate = transform.GetColumn(3);
60 return nw::math::VEC4(translate);
61 }
62 }
63
64 namespace nw
65 {
66 namespace gfx
67 {
68
69 const ut::FloatColor RenderContext::NULL_AMBIENT = ut::FloatColor();
70
71 //----------------------------------------
72 RenderContext*
Create(os::IAllocator * allocator)73 RenderContext::Builder::Create(
74 os::IAllocator* allocator
75 )
76 {
77 NW_NULL_ASSERT(allocator);
78
79 void* renderContextMemory = allocator->Alloc(sizeof(RenderContext));
80 NW_NULL_ASSERT(renderContextMemory);
81 void* shaderProgramMemory = allocator->Alloc(sizeof(ShaderProgram));
82 NW_NULL_ASSERT(shaderProgramMemory);
83
84 if (!renderContextMemory)
85 {
86 NW_WARNING(false, "Allocation failed\n");
87 return NULL;
88 }
89
90 GfxPtr<ShaderProgram> shaderProgram(new(shaderProgramMemory) ShaderProgram(allocator));
91
92 // パーティクル用アクティベータが存在しない場合は自動的に生成します。
93 if (m_ParticleMaterialActivator == NULL)
94 {
95 m_ParticleMaterialActivator = ParticleMaterialActivator::Create(allocator);
96 }
97
98 GfxPtr<IMaterialActivator> particleMaterialActivator(m_ParticleMaterialActivator);
99
100 SceneEnvironment::Description description;
101 description.vertexLights = VertexLightArray(m_MaxVertexLights, allocator);
102 description.cameras = CameraArray(m_MaxCameras, allocator);
103 description.fogs = FogArray(m_MaxFogs, allocator);
104 description.lightSets = LightSetArray(m_MaxLightSets, allocator);
105
106 return new(renderContextMemory) RenderContext(
107 allocator,
108 shaderProgram,
109 particleMaterialActivator,
110 description);
111 }
112
113 //----------------------------------------
RenderContext(os::IAllocator * allocator,GfxPtr<ShaderProgram> shaderProgram,GfxPtr<IMaterialActivator> particleMaterialActivator,const SceneEnvironment::Description & description)114 RenderContext::RenderContext(
115 os::IAllocator* allocator,
116 GfxPtr<ShaderProgram> shaderProgram,
117 GfxPtr<IMaterialActivator> particleMaterialActivator,
118 const SceneEnvironment::Description& description)
119 : GfxObject(allocator),
120 m_ShaderProgram(shaderProgram),
121 m_MatrixPaletteCount(0),
122 m_IsVertexAlphaEnabled(false),
123 m_IsBoneWeightWEnabled(false),
124 m_IsVertexAttributeDirty(true),
125 m_IsShaderProgramDirty(true),
126 m_RenderMode(RENDERMODE_DEFAULT),
127 m_RenderTarget(NULL),
128 m_ModelCache(NULL),
129 m_Material(NULL),
130 m_MaterialCache(NULL),
131 m_CameraCache(NULL),
132 m_SceneEnvironment(description),
133 m_ParticleMaterialActivator(particleMaterialActivator)
134 #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED
135 , m_ModelTranslateOffset(0.0f, 0.0f, 0.0f)
136 #endif
137 {
138 }
139
140 //----------------------------------------
141 void
SetRenderTarget(IRenderTarget * renderTarget,const Viewport & viewport)142 RenderContext::SetRenderTarget(
143 IRenderTarget* renderTarget,
144 const Viewport& viewport
145 )
146 {
147 this->m_RenderTarget = renderTarget;
148
149 if (this->m_RenderTarget)
150 {
151 const FrameBufferObject& fbo = this->m_RenderTarget->GetBufferObject();
152 fbo.ActivateBuffer();
153
154 GraphicsDevice::SetRenderBufferSize(
155 this->m_RenderTarget->GetDescription().width,
156 this->m_RenderTarget->GetDescription().height);
157
158 GraphicsDevice::ActivateViewport(viewport);
159 GraphicsDevice::SetDepthRange(viewport.GetDepthNear(), viewport.GetDepthFar());
160 GraphicsDevice::SetDepthFormat(this->m_RenderTarget->GetDescription().depthFormat);
161 }
162 }
163
164 //----------------------------------------
165 void
SetRenderTarget(IRenderTarget * renderTarget)166 RenderContext::SetRenderTarget(
167 IRenderTarget* renderTarget
168 )
169 {
170 f32 width = 0.0f;
171 f32 height = 0.0f;
172 if (renderTarget)
173 {
174 width = static_cast<f32>(renderTarget->GetDescription().width);
175 height = static_cast<f32>(renderTarget->GetDescription().height);
176 }
177
178 const float x = 0.0f;
179 const float y = 0.0f;
180 const float near = 0.0f;
181 const float far = 1.0f;
182 this->SetRenderTarget(renderTarget, Viewport(x, y, width, height, near, far));
183 }
184
185 //----------------------------------------
186 void
ResetState()187 RenderContext::ResetState()
188 {
189 m_ModelCache = NULL;
190 m_Material = NULL;
191 m_MaterialCache = NULL;
192 m_CameraCache = NULL;
193 m_SceneEnvironment.Reset();
194
195 m_IsVertexAttributeDirty = true;
196
197 m_ShaderProgram.Get()->DeactivateDescription();
198 GraphicsDevice::InvalidateAllLookupTables();
199 m_MaterialHash.ResetMaterialHash(Model::MULTI_FLAG_BUFFER_MATERIAL);
200 }
201
202 //----------------------------------------
203 // こちらの実装を修正した場合 ResetState(u32 resetStateMode) も修正する必要があります。
204 void
ResetState(s32 hashMask)205 RenderContext::ResetState(s32 hashMask)
206 {
207 m_ModelCache = NULL;
208 m_Material = NULL;
209 m_MaterialCache = NULL;
210 m_CameraCache = NULL;
211 m_SceneEnvironment.Reset();
212
213 m_IsVertexAttributeDirty = true;
214
215 m_ShaderProgram.Get()->DeactivateDescription();
216 GraphicsDevice::InvalidateAllLookupTables();
217 m_MaterialHash.ResetMaterialHash(hashMask);
218 }
219
220 //----------------------------------------
221 void
ResetState(s32 resetStateMode,s32 hashMask)222 RenderContext::ResetState(s32 resetStateMode, s32 hashMask)
223 {
224 if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_MODEL_CACHE))
225 {
226 m_ModelCache = NULL;
227 }
228
229 if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_MATERIAL))
230 {
231 m_Material = NULL;
232 }
233
234 if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_MATERIAL_CACHE))
235 {
236 m_MaterialCache = NULL;
237 }
238
239 if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_CAMERA_CACHE))
240 {
241 m_CameraCache = NULL;
242 }
243
244 if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_SCENE_ENVIRONMENT))
245 {
246 m_SceneEnvironment.Reset();
247 }
248
249 if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_SHADER_PROGRAM))
250 {
251 m_ShaderProgram.Get()->DeactivateDescription();
252 m_IsShaderProgramDirty = true;
253 }
254
255 if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_LOOK_UP_TABLE))
256 {
257 GraphicsDevice::InvalidateAllLookupTables();
258 }
259
260 if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_HASH))
261 {
262 m_MaterialHash.ResetMaterialHash(hashMask);
263 }
264
265 if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_VERTEX_ATTRIBUTE))
266 {
267 m_IsVertexAttributeDirty = true;
268 }
269 }
270
271 //----------------------------------------
272 void
ClearBuffer(GLbitfield mask,const ut::FloatColor & color,f32 depth)273 RenderContext::ClearBuffer(
274 GLbitfield mask,
275 const ut::FloatColor& color,
276 f32 depth
277 )
278 {
279 const FrameBufferObject& fbo = this->m_RenderTarget->GetBufferObject();
280
281 #if 0
282 if ( fbo.GetFboID() != 0 )
283 {
284 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
285 glDepthMask(true);
286 glClearColor(color.r, color.g, color.b, color.a);
287 glClearDepthf(depth);
288 glClearStencil(0);
289 glClear(mask);
290 }
291 else
292 #endif
293 {
294 fbo.ClearBuffer( mask, color, depth, 0 );
295 }
296 }
297
298 //----------------------------------------
299 // コンテキスト設定関係
300
301
302 //----------------------------------------
303 void
SetCameraMatrix(Camera * camera,bool isForce)304 RenderContext::SetCameraMatrix(Camera* camera, bool isForce)
305 {
306 if (m_CameraCache != camera || isForce)
307 {
308 m_CameraCache = camera;
309
310 internal::NWSetVertexUniform4fv(
311 VERTEX_SHADER_UNIFORM_VIEWMTX_INDEX, 3, camera->ViewMatrix());
312 internal::NWSetVertexUniform4fv(
313 VERTEX_SHADER_UNIFORM_PROJMTX_INDEX, 4, camera->ProjectionMatrix());
314
315 internal::NWSetGeometryUniform4fv(
316 VERTEX_SHADER_UNIFORM_VIEWMTX_INDEX, 3, camera->ViewMatrix());
317 internal::NWSetGeometryUniform4fv(
318 VERTEX_SHADER_UNIFORM_PROJMTX_INDEX, 4, camera->ProjectionMatrix());
319
320 NW_GL_ASSERT();
321 }
322 }
323
324 //----------------------------------------
325 void
SetModelMatrix(Model * model)326 RenderContext::SetModelMatrix(Model* model)
327 {
328 if (model == NULL)
329 {
330 this->m_ModelCache = NULL;
331 return;
332 }
333
334 NW_NULL_ASSERT(this->m_ShaderProgram);
335
336 SkeletalModel* skeletalModel = ut::DynamicCast<SkeletalModel*>(model);
337 if (skeletalModel)
338 {
339 Skeleton* skeleton = skeletalModel->GetSkeleton();
340 NW_NULL_ASSERT(skeleton);
341 ResSkeleton resSkeleton = skeleton->GetResSkeleton();
342 NW_ASSERT(resSkeleton.IsValid());
343 if (ut::CheckFlag(resSkeleton.GetFlags(), ResSkeletonData::FLAG_MODEL_COORDINATE))
344 {
345 #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED
346 math::MTX34 worldMatrix(model->WorldMatrix());
347 MTX34MultTranslate(&worldMatrix, m_ModelTranslateOffset, worldMatrix);
348 this->m_ShaderProgram->SetWorldMatrix(worldMatrix);
349 #else
350 this->m_ShaderProgram->SetWorldMatrix(model->WorldMatrix());
351 #endif
352 }
353 else
354 {
355 this->m_ShaderProgram->SetWorldMatrix(math::Matrix34::Identity());
356 }
357 }
358 else
359 {
360 this->m_ShaderProgram->SetWorldMatrix(math::Matrix34::Identity());
361 }
362
363 this->m_ShaderProgram->SetModelNormalMatrix(model->NormalMatrix());
364
365 bool useNormalMatrix = false;
366 this->m_ShaderProgram->SetUseBoneNormalMatrix(useNormalMatrix);
367
368 this->m_ModelCache = model;
369 }
370
371 //----------------------------------------
372 // アクティベート関係
373
374
375 //---------------------------------------------------------------------------
376 void
ActivateContext()377 RenderContext::ActivateContext()
378 {
379 if (m_MaterialCache == m_Material)
380 {
381 return;
382 }
383
384 this->ActivateShaderProgram();
385 this->ActivateSceneEnvironment();
386 this->ActivateMaterial();
387 this->m_SceneEnvironment.SetAllFlagsDirty(false);
388
389 m_MaterialCache = m_Material;
390 NW_GL_ASSERT();
391 }
392
393 //---------------------------------------------------------------------------
394 void
ActivateParticleContext()395 RenderContext::ActivateParticleContext()
396 {
397 if (this->m_IsVertexAttributeDirty)
398 {
399 internal::ClearVertexAttribute();
400 m_IsVertexAttributeDirty = false;
401 }
402
403 if (m_MaterialCache == m_Material)
404 {
405 return;
406 }
407
408 bool isParticleMaterialEnabled = false;
409 if (m_MaterialCache != NULL)
410 {
411 isParticleMaterialEnabled =
412 ut::CheckFlag(m_MaterialCache->GetOriginal().GetFlags(), ResMaterialData::FLAG_PARTICLE_MATERIAL_ENABLED) &&
413 ut::CheckFlag(m_Material->GetOriginal().GetFlags(), ResMaterialData::FLAG_PARTICLE_MATERIAL_ENABLED);
414 }
415
416 if (isParticleMaterialEnabled)
417 {
418 // シェーダープログラムが変更されていないことを表します。
419 m_IsShaderProgramDirty = false;
420 this->ActivateParticleMaterial();
421 }
422 else
423 {
424 this->ActivateContext();
425 }
426
427 NW_GL_ASSERT();
428 m_MaterialCache = m_Material;
429 }
430
431 //---------------------------------------------------------------------------
432 void
ActivateVertexAttribute(ResMesh mesh)433 RenderContext::ActivateVertexAttribute( ResMesh mesh )
434 {
435 NW_NULL_ASSERT( mesh.ref().m_ActivateCommandCache );
436
437 if (m_IsVertexAttributeDirty)
438 {
439 internal::ClearVertexAttribute();
440 m_IsVertexAttributeDirty = false;
441 }
442
443 internal::NWUseCmdlist( mesh.ref().m_ActivateCommandCache, mesh.ref().m_ActivateCommandCacheSize );
444 internal::NWUseCmdlist( mesh.ref().m_IrScaleCommand, sizeof(mesh.ref().m_IrScaleCommand) );
445
446 ShaderProgram* shaderProgram = this->GetShaderProgram();
447
448 const bool hasVertexAlpha = (mesh.ref().m_Flags & ResMesh::FLAG_HAS_VERTEX_ALPHA) ? true : false;
449 const bool hasBoneWeightW = (mesh.ref().m_Flags & ResMesh::FLAG_HAS_BONE_WEIGHT_W) ? true : false;
450
451 shaderProgram->SetVertexUniformBool(NW_GFX_VERTEX_UNIFORM(ISVERTA), hasVertexAlpha);
452 shaderProgram->SetVertexUniformBool(NW_GFX_VERTEX_UNIFORM(ISBONEW), hasBoneWeightW);
453 }
454
455 //----------------------------------------
456 void
ActivateShaderProgram()457 RenderContext::ActivateShaderProgram()
458 {
459 ResShaderProgramDescription description = this->m_Material->GetDescription();
460
461 NW_ASSERT(description.IsValid());
462
463 ResShaderProgramDescription previousDescription =
464 this->m_ShaderProgram.Get()->GetActiveDescription();
465
466 if ( previousDescription != description )
467 {
468 // ジオメトリシェーダ使用後はクリア処理が必要。
469 if ( previousDescription.IsValid() &&
470 previousDescription.GetGeometryShaderIndex() >= 0 &&
471 description.GetGeometryShaderIndex() < 0 )
472 {
473 this->m_IsVertexAttributeDirty = true;
474
475 const s32 hashMask = Model::FLAG_BUFFER_SHADER_PARAMETER |
476 Model::FLAG_BUFFER_MATERIAL_COLOR |
477 Model::FLAG_BUFFER_TEXTURE_COORDINATOR |
478 Model::FLAG_BUFFER_SCENE_ENVIRONMENT;
479 m_MaterialHash.ResetMaterialHash( hashMask );
480
481 m_SceneEnvironment.SetAllFlagsDirty( true );
482 }
483
484 m_ShaderProgram.Get()->ActivateDescription(description);
485
486 m_IsShaderProgramDirty = true;
487 }
488 else
489 {
490 m_IsShaderProgramDirty = false;
491 }
492 }
493
494 //----------------------------------------
495 void
ActivateSceneEnvironment()496 RenderContext::ActivateSceneEnvironment()
497 {
498 NW_NULL_ASSERT(this->m_Material);
499 const Model* owner = this->m_Material->GetOwnerModel();
500 NW_NULL_ASSERT(owner);
501
502 ResMaterial resMaterial = this->m_Material->GetSceneEnvironmentResMaterial();
503
504 this->m_SceneEnvironment.SetActiveLightSet(resMaterial.GetLightSetIndex());
505
506 if (this->m_SceneEnvironment.IsFragmentLightsDirty())
507 {
508 this->ActivateFragmentLights();
509 }
510
511 if (this->m_SceneEnvironment.IsHemiSphereLightDirty())
512 {
513 this->ActivateHemiSphereLight();
514 }
515 #if defined(NW_GFX_VERTEX_LIGHT_ENABLED)
516 if (this->m_SceneEnvironment.IsVertexLightsDirty())
517 {
518 this->ActivateVertexLights();
519 }
520 #endif
521 this->m_SceneEnvironment.SetActiveFog(resMaterial.GetFogIndex());
522
523 if (this->m_SceneEnvironment.IsFogDirty())
524 {
525 this->ActivateFog();
526 }
527 }
528
529 //----------------------------------------
530 void
ActivateFog()531 RenderContext::ActivateFog()
532 {
533 if (this->m_SceneEnvironment.GetActiveFog() != NULL &&
534 this->m_SceneEnvironment.GetActiveFog()->GetResFog().IsValid() &&
535 this->m_SceneEnvironment.GetActiveFog()->GetResFog().GetFogSampler().IsValid())
536 {
537 ResFog resFog = m_SceneEnvironment.GetActiveFog()->GetResFog();
538
539 ResImageLookupTable lut = resFog.GetFogSampler();
540
541 enum
542 {
543 REG_FOG_ZFLIP = 0xe0,
544 REG_FOG_COLOR = 0xe1,
545 REG_FOG_ZFLIP_SHIFT = 16
546 };
547
548 ut::Color8 color8 = resFog.GetColor();
549
550 const u32 HEADER_FOG_ZFLIP = internal::MakeCommandHeader(REG_FOG_ZFLIP, 1, false, 0x4);
551 const u32 HEADER_FOG_COLOR = internal::MakeCommandHeader(REG_FOG_COLOR, 1, false, 0xf);
552
553 // TODO: ZFLIP の設定が逆だが、FogUpdater で逆順の LUT を生成しているので辻褄が合っている。
554 // 両方の足並みを揃えて修正する。
555 u32 FOG_COMMAND[] =
556 {
557 (resFog.IsZFlip() ? (0x1 << REG_FOG_ZFLIP_SHIFT) : 0x0),
558 HEADER_FOG_ZFLIP,
559 color8.r | color8.g << 8 | color8.b << 16,
560 HEADER_FOG_COLOR
561 };
562
563 internal::NWUseCmdlist<sizeof(FOG_COMMAND)>(&FOG_COMMAND[0]);
564
565 GraphicsDevice::ActivateLookupTable(lut, GraphicsDevice::LUT_TARGET_FOG);
566 }
567 }
568
569 //----------------------------------------
570 void
ActivateHemiSphereLight()571 RenderContext::ActivateHemiSphereLight()
572 {
573 const ShaderProgram* shaderProgram = this->GetShaderProgram();
574
575 if (m_SceneEnvironment.GetHemiSphereLight() &&
576 shaderProgram &&
577 ut::CheckFlag(
578 shaderProgram->GetActiveDescription().GetFlags(),
579 ResShaderProgramDescription::FLAG_IS_SUPPORTING_HEMISPHERE_LIGHTING))
580 {
581 ResHemiSphereLight resLight = m_SceneEnvironment.GetHemiSphereLight()->GetResHemiSphereLight();
582 NW_ASSERT(resLight.IsValid());
583
584 internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_HSLGCOL_INDEX, 1, resLight.GetGroundColor());
585 internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_HSLSCOL_INDEX, 1, resLight.GetSkyColor());
586
587 math::VEC3 direction(resLight.GetDirection());
588 if (ut::CheckFlag(resLight.GetFlags(), ResHemiSphereLightData::FLAG_IS_INHERITING_DIRECTION_ROTATE) &&
589 m_SceneEnvironment.GetHemiSphereLight()->GetParent() != NULL)
590 {
591 math::VEC3TransformNormal(
592 &direction, &m_SceneEnvironment.GetHemiSphereLight()->TrackbackWorldMatrix(), &resLight.GetDirection());
593 }
594
595 const Camera* camera = this->GetActiveCamera();
596 NW_NULL_ASSERT(camera);
597
598 const math::MTX34& viewMatrix = camera->ViewMatrix();
599
600 math::VEC3TransformNormal(&direction, &viewMatrix, &direction);
601 math::VEC4 directionAndLerp(direction.x, direction.y, direction.z, resLight.GetLerpFactor());
602
603 internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_HSLSDIR_INDEX, 1, directionAndLerp);
604
605 }
606 }
607
608 //----------------------------------------
609 void
ActivateFragmentLights()610 RenderContext::ActivateFragmentLights()
611 {
612 GraphicsDevice::ResetFragmentLightEnabled();
613 int lightCount = this->m_SceneEnvironment.GetFragmentLightCount();
614
615 for (int i = 0; i < lightCount; ++i)
616 {
617 const FragmentLight* light = this->m_SceneEnvironment.GetFragmentLight(i);
618
619 this->ActivateFragmentLight(i, light);
620 }
621
622 GraphicsDevice::ActivateFragmentLightEnabled();
623 }
624
625 //----------------------------------------
626 void
ActivateFragmentLight(int index,const FragmentLight * light)627 RenderContext::ActivateFragmentLight(int index, const FragmentLight* light)
628 {
629 ResFragmentLight resLight = light->GetResFragmentLight();
630 NW_ASSERT(resLight.IsValid());
631
632 s32 lightKind = resLight.GetLightKind();
633 NW_ASSERT(lightKind < ResFragmentLight::KIND_COUNT);
634
635 Camera* camera = this->GetActiveCamera();
636 NW_NULL_ASSERT(camera);
637
638 const math::MTX34& viewMatrix = camera->ViewMatrix();
639
640 if ( lightKind == ResFragmentLight::KIND_DIRECTIONAL )
641 {
642 nw::math::VEC4 direction(light->Direction());
643 direction.w = 0.0f;
644
645 this->TransformToViewCoordinate(&direction, &viewMatrix, &direction);
646
647 // 平行光源はポジションの逆方向のベクトルをディレクションとします。
648 GraphicsDevice::ActivateFragmentLightPosition(index, -direction);
649 GraphicsDevice::SetFragmentLightPositionW(index, (direction.w == 0.0f));
650
651 GraphicsDevice::SetFragmentLightSpotEnabled(index, false);
652 GraphicsDevice::SetFragmentLightDistanceAttnEnabled(index, false);
653 }
654 else if ( lightKind == ResFragmentLight::KIND_POINT )
655 {
656 GraphicsDevice::SetFragmentLightSpotEnabled(index, false);
657
658 if ( ut::CheckFlag(resLight.GetFlags(), ResFragmentLightData::FLAG_DISTANCE_ATTENUATION_ENABLED)
659 && resLight.GetDistanceSampler().IsValid() )
660 {
661 GraphicsDevice::SetFragmentLightDistanceAttnEnabled(index, true);
662 GraphicsDevice::ActivateFragmentLightDistanceAttnTable(index, resLight.GetDistanceSampler().Dereference());
663
664 GraphicsDevice::ActivateFragmentLightDistanceAttnScaleBias(
665 index,
666 resLight.ref().m_DistanceAttenuationScale,
667 resLight.ref().m_DistanceAttenuationBias );
668 }
669 else
670 {
671 GraphicsDevice::SetFragmentLightDistanceAttnEnabled(index, false);
672 }
673
674 nw::math::VEC4 position = GetTranslate(light->WorldMatrix());
675 position.w = 1.0f;
676 this->TransformToViewCoordinate(&position, &viewMatrix, &position);
677
678 GraphicsDevice::ActivateFragmentLightPosition(index, position);
679 GraphicsDevice::SetFragmentLightPositionW(index, (position.w == 0.0f));
680 }
681 else if ( lightKind == ResFragmentLight::KIND_SPOT )
682 {
683 NW_ASSERT(resLight.GetAngleSampler().IsValid());
684 NW_ASSERT(resLight.GetAngleSampler().GetSampler().IsValid());
685
686 GraphicsDevice::SetFragmentLightSpotEnabled(index, true);
687 GraphicsDevice::ActivateFragmentLightSpotTable(index, resLight.GetAngleSampler().GetSampler().Dereference());
688 GraphicsDevice::SetLutIsAbs( GraphicsDevice::LUT_TARGET_SP, resLight.GetAngleSampler().GetSampler().Dereference().IsAbs() );
689 GraphicsDevice::SetLutInput( GraphicsDevice::LUT_TARGET_SP, resLight.GetAngleSampler().GetInput() );
690 GraphicsDevice::SetLutScale( GraphicsDevice::LUT_TARGET_SP, resLight.GetAngleSampler().GetScale() );
691
692 if ( ut::CheckFlag(resLight.GetFlags(), ResFragmentLightData::FLAG_DISTANCE_ATTENUATION_ENABLED )
693 && resLight.GetDistanceSampler().IsValid())
694 {
695 GraphicsDevice::SetFragmentLightDistanceAttnEnabled(index, true);
696 GraphicsDevice::ActivateFragmentLightDistanceAttnTable(index, resLight.GetDistanceSampler().Dereference());
697
698 GraphicsDevice::ActivateFragmentLightDistanceAttnScaleBias(
699 index,
700 resLight.ref().m_DistanceAttenuationScale,
701 resLight.ref().m_DistanceAttenuationBias );
702 }
703 else
704 {
705 GraphicsDevice::SetFragmentLightDistanceAttnEnabled(index, false);
706 }
707
708 nw::math::VEC4 direction(light->Direction());
709 direction.w = 0.0f;
710
711 this->TransformToViewCoordinate(&direction, &viewMatrix, &direction);
712
713 nw::math::VEC4 position = GetTranslate(light->WorldMatrix());
714 position.w = 1.0f;
715 this->TransformToViewCoordinate(&position, &viewMatrix, &position);
716
717 math::VEC3 spotDirection(direction);
718 GraphicsDevice::ActivateFragmentLightPosition(index, position, spotDirection);
719 GraphicsDevice::SetFragmentLightPositionW(index, (position.w == 0.0f));
720 }
721 }
722
723 #if defined(NW_GFX_VERTEX_LIGHT_ENABLED)
724 //----------------------------------------
725 void
ActivateVertexLights()726 RenderContext::ActivateVertexLights()
727 {
728 int size = this->m_SceneEnvironment.GetVertexLightCount();
729 if (size > 0)
730 {
731 const ShaderProgram* shaderProgram = this->GetShaderProgram();
732
733 // 整数レジスタにループカウンタとして頂点ライトの数をセットする。
734 // ただし、頂点シェーダーでは整数レジスタ+1回のループを行うために頂点ライト数-1を設定する。
735 // 頂点ライトが0の場合はIsVertLを用いてループを行わないようにしている。
736 if(shaderProgram->GetActiveDescription().GetMaxVertexLightCount() > 0)
737 {
738 shaderProgram->SetVertexUniformInt(
739 NW_GFX_VERTEX_UNIFORM(LIGHTCT),
740 ut::Max<s32>(size - 1, 0),
741 0,
742 1);
743 }
744
745 for (int i = 0; i < size; i++)
746 {
747 this->ActivateVertexLight(i, m_SceneEnvironment.GetVertexLight(i));
748 }
749 }
750 }
751
752 //----------------------------------------
753 void
ActivateVertexLight(int index,const VertexLight * light)754 RenderContext::ActivateVertexLight(int index, const VertexLight* light)
755 {
756 const ShaderProgram* shaderProgram = this->GetShaderProgram();
757
758 if (shaderProgram->GetActiveDescription().GetMaxVertexLightCount() > index)
759 {
760 const float LIGHT_INFINITY = 0.0f;
761 const float LIGHT_FINITY = 1.0f;
762
763 s32 endUniform = shaderProgram->GetActiveDescription().GetVertexLightEndUniform();
764 ResVertexLight resLight = light->GetResVertexLight();
765 NW_ASSERT(resLight.IsValid());
766
767 Camera* camera = this->GetActiveCamera();
768 NW_NULL_ASSERT(camera);
769
770 const math::MTX34& viewMatrix = camera->ViewMatrix();
771
772 shaderProgram->SetUniversal(
773 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_AMBIENT,
774 resLight.GetAmbient());
775
776 shaderProgram->SetUniversal(
777 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_DIFFUSE,
778 resLight.GetDiffuse());
779
780 if (resLight.GetLightKind() == ResVertexLight::KIND_DIRECTIONAL)
781 {
782 // OpenGLではライトを無限遠に置くことで平行光源を実現しています。
783 // デフォルトシェーダーも同様の仕様となります。
784 math::VEC4 position(light->Direction());
785 position.w = LIGHT_INFINITY;
786
787 this->TransformToViewCoordinate(&position, &viewMatrix, &position);
788 shaderProgram->SetUniversal(
789 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_POSITION,
790 -position);
791 }
792 else
793 {
794 math::VEC4 position = GetTranslate(light->WorldMatrix());
795 position.w = LIGHT_FINITY;
796
797 this->TransformToViewCoordinate(&position, &viewMatrix, &position);
798 shaderProgram->SetUniversal(
799 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_POSITION,
800 position);
801
802 // 距離減衰パラメータを設定します。
803 shaderProgram->SetUniversal(
804 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_DISTANCE_ATTENUATION,
805 resLight.GetDistanceAttenuationAndEnabled());
806
807 if (resLight.GetLightKind() == ResVertexLight::KIND_SPOT)
808 {
809 // スポットパラメータを設定します。
810 math::VEC4 spotDirection(light->Direction());
811 spotDirection.w = 0.0f;
812
813 this->TransformToViewCoordinate(&spotDirection, &viewMatrix, &spotDirection);
814
815 math::VEC4 spotFactor(resLight.GetSpotFactor().x, resLight.GetSpotFactor().y, 0.0f, 0.0f);
816 if (resLight.GetSpotFactor().y > 0.0f && resLight.GetSpotFactor().y < math::F_PI)
817 {
818 spotFactor.y = nw::math::CosRad(resLight.GetSpotFactor().y);
819 spotDirection.w = 1.0f;
820 }
821 else if (resLight.GetSpotFactor().y == 0.0f)
822 {
823 const float EPSILON = 1e-5f;
824 const float GREATER_THAN_ONE = 1.0f + EPSILON;
825 spotFactor.y = GREATER_THAN_ONE;
826 spotDirection.w = 1.0f;
827 }
828 else
829 {
830 spotDirection.w = 0.0f;
831 }
832
833 shaderProgram->SetUniversal(
834 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_SPOT_DIRECTION,
835 spotDirection);
836
837 shaderProgram->SetUniversal(
838 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_SPOT_FACTOR,
839 spotFactor);
840 }
841 else
842 {
843 shaderProgram->SetUniversal(
844 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_SPOT_DIRECTION,
845 math::VEC4::Zero());
846 }
847 }
848 }
849 }
850 #endif
851
852 //----------------------------------------
853 void
TransformToViewCoordinate(math::VEC4 * out,const math::MTX34 * __restrict view,const math::VEC4 * v)854 RenderContext::TransformToViewCoordinate(
855 math::VEC4* out,
856 const math::MTX34* __restrict view,
857 const math::VEC4* v)
858 {
859 f32 vx = v->x;
860 f32 vy = v->y;
861 f32 vz = v->z;
862 f32 vw = v->w;
863
864 out->x = view->f._00 * vx + view->f._01 * vy + view->f._02 * vz + view->f._03 * vw;
865 out->y = view->f._10 * vx + view->f._11 * vy + view->f._12 * vz + view->f._13 * vw;
866 out->z = view->f._20 * vx + view->f._21 * vy + view->f._22 * vz + view->f._23 * vw;
867 out->w = vw;
868 }
869
870
871 //----------------------------------------
872 void
RenderPrimitive(ResPrimitive primitive)873 RenderContext::RenderPrimitive(
874 ResPrimitive primitive
875 )
876 {
877 NW_ASSERT(primitive.IsValid());
878
879 ResIndexStreamArray indexStreams = primitive.GetIndexStreams();
880 GLuint* bufferObjects = reinterpret_cast<GLuint*>(primitive.GetBufferObjects());
881
882 const ShaderProgram* shaderProgram = this->GetShaderProgram();
883 shaderProgram->FlushUniform();
884
885 math::VEC4 float4(
886 1.0f,
887 1.0f,
888 static_cast<f32>(m_MatrixPaletteCount),
889 1.0f);
890
891 internal::NWSetVertexUniform4fv( VERTEX_SHADER_UNIFORM_IRSCALE_INDEX + 2, 1, float4 );
892
893 //NW_FOREACH(ResIndexStream indexStream, indexStreams)
894 ResIndexStreamArray::iterator end = indexStreams.end();
895 for (ResIndexStreamArray::iterator stream = indexStreams.begin(); stream != end; ++stream)
896 {
897 ResIndexStream indexStream = *stream;
898 GLuint bufferObject = *bufferObjects;
899 ++bufferObjects;
900
901 if (!indexStream.IsVisible()) { continue; }
902
903 if (indexStream.ref().m_CommandCache)
904 {
905 NW_ASSERT(indexStream.ref().m_CommandCacheSize > 0);
906 internal::NWUseCmdlist(indexStream.ref().m_CommandCache, indexStream.ref().m_CommandCacheSize);
907 }
908 else
909 {
910 // TODO: 初期化場所を初回 Draw 時から Setup 後に変更する。
911 enum
912 {
913 REG_INDEX_STREAM_OFFSET = 0x227,
914 REG_INDEX_STREAM_COUNT = 0x228,
915 REG_ELEMENTS_MODE = 0x229, // [23:16]にはバイトイネーブルでアクセスしてはいけない。
916 REG_ELEMENTS_MODE_2 = 0x253, // [31:16]にはバイトイネーブルでアクセスしてはいけない。
917 REG_ELEMENTS_MODE_3 = 0x25e, // [31:16]にはバイトイネーブルでアクセスしてはいけない。
918 REG_TRIANGLE_INDEX_RESET = 0x25f,
919 REG_DRAW_READY = 0x245,
920 REG_DRAW_KICK = 0x22f,
921 REG_VERTEX_CACHE_CLEAR = 0x231,
922 REG_COLOR_DEPTH_CACHE_CLEAR = 0x110,
923 REG_COLOR_DEPTH_CACHE_FLUSH = 0x111
924 };
925
926 ResShaderProgramDescription description = shaderProgram->GetActiveDescription();
927
928 GLuint mode = ToPrimitiveModeGL(
929 indexStream.GetPrimitiveMode(),
930 description.GetGeometryShaderObject() > 0);
931
932 internal::CommandCacheBuilder builder;
933
934 builder.Begin();
935
936 const size_t commandCount = 26;
937 u32* command = reinterpret_cast<u32*>(internal::NWGetCurrentCmdBuffer());
938 std::memset(command, 0, sizeof(u32) * commandCount);
939
940 u32 baseAddr = nngxGetPhysicalAddr(nn::gx::GetVramStartAddr(nn::gx::MEM_VRAMA));
941 u32 bufferAddr = nngxGetPhysicalAddr( indexStream.GetImageAddress() );
942
943 NW_ASSERT((bufferAddr - baseAddr) < 0x10000000);
944
945 const u32 HEADER_INDEX_STREAM_OFFSET = internal::MakeCommandHeader(REG_INDEX_STREAM_OFFSET, 1, false, 0xF);
946 const u32 HEADER_INDEX_STREAM_COUNT = internal::MakeCommandHeader(REG_INDEX_STREAM_COUNT, 1, false, 0xF);
947
948 command[0] = (bufferAddr - baseAddr);
949 command[1] = HEADER_INDEX_STREAM_OFFSET;
950 command[2] = indexStream.GetStreamCount();
951 command[3] = HEADER_INDEX_STREAM_COUNT;
952
953 // CTR では GL_UNSIGNED_INT は未対応です。
954 if (indexStream.GetFormatType() == GL_UNSIGNED_SHORT)
955 {
956 command[0] |= 0x80000000;
957 command[2] /= 2;
958 }
959
960 const u32 HEADER_ELEMENTS_MODE = internal::MakeCommandHeader(REG_ELEMENTS_MODE, 1, false, 0x2);
961 const u32 HEADER_ELEMENTS_MODE_2 = internal::MakeCommandHeader(REG_ELEMENTS_MODE_2, 1, false, 0x2);
962
963 if (mode == GL_TRIANGLES)
964 {
965 command[4] = 1 << 8;
966 command[5] = HEADER_ELEMENTS_MODE;
967 command[6] = 1 << 8;
968 command[7] = HEADER_ELEMENTS_MODE_2;
969 }
970 else
971 {
972 command[4] = 0;
973 command[5] = HEADER_ELEMENTS_MODE;
974 command[6] = 0;
975 command[7] = HEADER_ELEMENTS_MODE_2;
976 }
977
978 switch (mode)
979 {
980 case GL_TRIANGLES: command[8] = 3 << 8; break;
981 case GL_TRIANGLE_STRIP: command[8] = 1 << 8; break;
982 case GL_TRIANGLE_FAN: command[8] = 2 << 8; break;
983 case GL_GEOMETRY_PRIMITIVE_DMP: command[8] = 3 << 8; break;
984 }
985
986 u32 commandIndex = 9;
987
988 command[commandIndex++] = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x2);
989 command[commandIndex++] = 0;
990 command[commandIndex++] = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x4);
991 command[commandIndex++] = 1;
992 command[commandIndex++] = internal::MakeCommandHeader(REG_TRIANGLE_INDEX_RESET, 1, false, 0xF);
993 command[commandIndex++] = 0;
994 command[commandIndex++] = internal::MakeCommandHeader(REG_DRAW_READY, 1, false, 0xF);
995 command[commandIndex++] = 1;
996 command[commandIndex++] = internal::MakeCommandHeader(REG_DRAW_KICK, 1, false, 0xF);
997 command[commandIndex++] = 1;
998 command[commandIndex++] = internal::MakeCommandHeader(REG_DRAW_READY, 1, false, 0xF);
999 command[commandIndex++] = 1;
1000 command[commandIndex++] = internal::MakeCommandHeader(REG_VERTEX_CACHE_CLEAR, 1, false, 0xF);
1001 command[commandIndex++] = 0;
1002 command[commandIndex++] = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x8);
1003 command[commandIndex++] = 0;
1004 command[commandIndex++] = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x8);
1005 command[commandIndex++] = 1;
1006 command[commandIndex++] = internal::MakeCommandHeader(REG_COLOR_DEPTH_CACHE_FLUSH, 1, false, 0xF);
1007 command[commandIndex++] = 1;
1008 command[commandIndex++] = internal::MakeCommandHeader(REG_COLOR_DEPTH_CACHE_CLEAR, 1, false, 0xF);
1009
1010 internal::NWForwardCurrentCmdBuffer(sizeof(u32) * commandIndex);
1011
1012 builder.End();
1013
1014 indexStream.ref().m_CommandCache = builder.AllocAndCopy();
1015 indexStream.ref().m_CommandCacheSize = builder.GetSize();
1016 }
1017 }
1018 NW_GL_ASSERT();
1019 }
1020
1021 } // namespace gfx
1022 } // namespace nw
1023
1024