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