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: 29432 $
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 
82     if (!renderContextMemory)
83     {
84         NW_WARNING(false, "Allocation failed\n");
85         return NULL;
86     }
87 
88     void* shaderProgramMemory = allocator->Alloc(sizeof(ShaderProgram));
89     NW_NULL_ASSERT(shaderProgramMemory);
90 
91     if (!shaderProgramMemory)
92     {
93         NW_WARNING(false, "Allocation failed\n");
94         return NULL;
95     }
96 
97     GfxPtr<ShaderProgram> shaderProgram(new(shaderProgramMemory) ShaderProgram(allocator));
98 
99     // パーティクル用アクティベータが存在しない場合は自動的に生成します。
100     if (m_ParticleMaterialActivator == NULL)
101     {
102         m_ParticleMaterialActivator = ParticleMaterialActivator::Create(allocator);
103     }
104 
105     GfxPtr<IMaterialActivator> particleMaterialActivator(m_ParticleMaterialActivator);
106 
107     SceneEnvironment::Description description;
108     description.vertexLights = VertexLightArray(m_MaxVertexLights, allocator);
109     description.cameras = CameraArray(m_MaxCameras, allocator);
110     description.fogs = FogArray(m_MaxFogs, allocator);
111     description.lightSets = LightSetArray(m_MaxLightSets, allocator);
112 
113     return new(renderContextMemory) RenderContext(
114         allocator,
115         shaderProgram,
116         particleMaterialActivator,
117         description);
118 }
119 
120 //----------------------------------------
RenderContext(os::IAllocator * allocator,GfxPtr<ShaderProgram> shaderProgram,GfxPtr<IMaterialActivator> particleMaterialActivator,const SceneEnvironment::Description & description)121 RenderContext::RenderContext(
122     os::IAllocator* allocator,
123     GfxPtr<ShaderProgram> shaderProgram,
124     GfxPtr<IMaterialActivator> particleMaterialActivator,
125     const SceneEnvironment::Description& description)
126 : GfxObject(allocator),
127   m_ShaderProgram(shaderProgram),
128   m_IsVertexAlphaEnabled(false),
129   m_IsBoneWeightWEnabled(false),
130   m_IsVertexAttributeDirty(true),
131   m_IsShaderProgramDirty(true),
132   m_RenderMode(RENDERMODE_DEFAULT),
133   m_RenderTarget(NULL),
134   m_ModelCache(NULL),
135   m_Material(NULL),
136   m_MaterialCache(NULL),
137   m_CameraCache(NULL),
138   m_SceneEnvironment(description),
139   m_ParticleMaterialActivator(particleMaterialActivator)
140 #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED
141   , m_ModelTranslateOffset(0.0f, 0.0f, 0.0f)
142 #endif
143 {
144 }
145 
146 //----------------------------------------
147 void
SetRenderTarget(IRenderTarget * renderTarget,const Viewport & viewport)148 RenderContext::SetRenderTarget(
149     IRenderTarget* renderTarget,
150     const Viewport& viewport
151 )
152 {
153     this->m_RenderTarget = renderTarget;
154 
155     if (this->m_RenderTarget)
156     {
157         const FrameBufferObject& fbo = this->m_RenderTarget->GetBufferObject();
158         fbo.ActivateBuffer();
159 
160         GraphicsDevice::SetRenderBufferSize(
161             this->m_RenderTarget->GetDescription().width,
162             this->m_RenderTarget->GetDescription().height);
163 
164         GraphicsDevice::ActivateViewport(viewport);
165         GraphicsDevice::SetDepthRange(viewport.GetDepthNear(), viewport.GetDepthFar());
166         GraphicsDevice::SetDepthFormat(this->m_RenderTarget->GetDescription().depthFormat);
167     }
168 }
169 
170 //----------------------------------------
171 void
SetRenderTarget(IRenderTarget * renderTarget)172 RenderContext::SetRenderTarget(
173     IRenderTarget* renderTarget
174 )
175 {
176     f32 width = 0.0f;
177     f32 height = 0.0f;
178     if (renderTarget)
179     {
180         width = static_cast<f32>(renderTarget->GetDescription().width);
181         height = static_cast<f32>(renderTarget->GetDescription().height);
182     }
183 
184     const float x = 0.0f;
185     const float y = 0.0f;
186     const float near = 0.0f;
187     const float far = 1.0f;
188     this->SetRenderTarget(renderTarget, Viewport(x, y, width, height, near, far));
189 }
190 
191 //----------------------------------------
192 void
ResetState()193 RenderContext::ResetState()
194 {
195     m_ModelCache = NULL;
196     m_Material = NULL;
197     m_MaterialCache = NULL;
198     m_CameraCache = NULL;
199     m_SceneEnvironment.Reset();
200 
201     m_IsVertexAttributeDirty = true;
202 
203     m_ShaderProgram.Get()->DeactivateDescription();
204     GraphicsDevice::InvalidateAllLookupTables();
205     m_MaterialHash.ResetMaterialHash(Model::MULTI_FLAG_BUFFER_MATERIAL);
206 }
207 
208 //----------------------------------------
209 void
ResetState(s32 resetStateMode,s32 hashMask)210 RenderContext::ResetState(s32 resetStateMode, s32 hashMask)
211 {
212     if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_MODEL_CACHE))
213     {
214         m_ModelCache = NULL;
215     }
216 
217     if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_MATERIAL))
218     {
219         m_Material = NULL;
220     }
221 
222     if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_MATERIAL_CACHE))
223     {
224         m_MaterialCache = NULL;
225     }
226 
227     if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_ACTIVE_CAMERA))
228     {
229         m_SceneEnvironment.m_Camera = NULL;
230         m_SceneEnvironment.m_CameraIndex = -1;
231     }
232 
233     if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_CAMERA_CACHE))
234     {
235         m_CameraCache = NULL;
236     }
237 
238     if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_SCENE_ENVIRONMENT))
239     {
240         m_SceneEnvironment.Reset();
241     }
242 
243     if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_SHADER_PROGRAM))
244     {
245         m_ShaderProgram.Get()->DeactivateDescription();
246         m_IsShaderProgramDirty = true;
247     }
248 
249     if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_LOOK_UP_TABLE))
250     {
251         GraphicsDevice::InvalidateAllLookupTables();
252     }
253 
254     if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_HASH))
255     {
256         m_MaterialHash.ResetMaterialHash(hashMask);
257     }
258 
259     if (ut::CheckFlag(resetStateMode, RenderContext::RESETSTATEMODE_VERTEX_ATTRIBUTE))
260     {
261         m_IsVertexAttributeDirty = true;
262     }
263 }
264 
265 //----------------------------------------
266 void
ClearBuffer(GLbitfield mask,const ut::FloatColor & color,f32 depth)267 RenderContext::ClearBuffer(
268     GLbitfield mask,
269     const ut::FloatColor& color,
270     f32 depth
271 )
272 {
273     const FrameBufferObject& fbo = this->m_RenderTarget->GetBufferObject();
274 
275 #if 0
276     if ( fbo.GetFboID() != 0 )
277     {
278         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
279         glDepthMask(true);
280         glClearColor(color.r, color.g, color.b, color.a);
281         glClearDepthf(depth);
282         glClearStencil(0);
283         glClear(mask);
284     }
285     else
286 #endif
287     {
288         fbo.ClearBuffer( mask, color, depth, 0 );
289     }
290 }
291 
292 //----------------------------------------
293 // コンテキスト設定関係
294 
295 
296 //----------------------------------------
297 void
SetCameraMatrix(Camera * camera,bool isForce)298 RenderContext::SetCameraMatrix(Camera* camera, bool isForce)
299 {
300     if (m_CameraCache != camera || isForce)
301     {
302         m_CameraCache = camera;
303 
304         internal::NWSetVertexUniform4fv(
305             VERTEX_SHADER_UNIFORM_VIEWMTX_INDEX, 3, camera->ViewMatrix());
306         internal::NWSetVertexUniform4fv(
307             VERTEX_SHADER_UNIFORM_PROJMTX_INDEX, 4, camera->ProjectionMatrix());
308 
309         internal::NWSetGeometryUniform4fv(
310             VERTEX_SHADER_UNIFORM_VIEWMTX_INDEX, 3, camera->ViewMatrix());
311         internal::NWSetGeometryUniform4fv(
312             VERTEX_SHADER_UNIFORM_PROJMTX_INDEX, 4, camera->ProjectionMatrix());
313     }
314 }
315 
316 //---------------------------------------------------------------------------
317 void
SetModelMatrixForModel(Model * model)318 RenderContext::SetModelMatrixForModel(Model* model)
319 {
320     NW_NULL_ASSERT(model);
321     NW_NULL_ASSERT(this->m_ShaderProgram);
322 
323     this->m_ShaderProgram->SetWorldMatrix(math::Matrix34::Identity());
324     this->m_ShaderProgram->SetModelNormalMatrix(model->NormalMatrix());
325 
326     this->m_ModelCache = model;
327 }
328 
329 //---------------------------------------------------------------------------
330 void
SetModelMatrixForSkeletalModel(SkeletalModel * skeletalModel)331 RenderContext::SetModelMatrixForSkeletalModel(SkeletalModel* skeletalModel)
332 {
333     NW_NULL_ASSERT(skeletalModel);
334     NW_NULL_ASSERT(this->m_ShaderProgram);
335 
336     Skeleton* skeleton = skeletalModel->GetSkeleton();
337     NW_NULL_ASSERT(skeleton);
338     ResSkeleton resSkeleton = skeleton->GetResSkeleton();
339     NW_ASSERT(resSkeleton.IsValid());
340     if (ut::CheckFlag(resSkeleton.GetFlags(), ResSkeletonData::FLAG_MODEL_COORDINATE))
341     {
342 #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED
343         math::MTX34 worldMatrix(skeletalModel->WorldMatrix());
344         MTX34MultTranslate(&worldMatrix, m_ModelTranslateOffset, worldMatrix);
345         this->m_ShaderProgram->SetWorldMatrix(worldMatrix);
346 #else
347         this->m_ShaderProgram->SetWorldMatrix(skeletalModel->WorldMatrix());
348 #endif
349     }
350     else
351     {
352         this->m_ShaderProgram->SetWorldMatrix(math::Matrix34::Identity());
353     }
354 
355     this->m_ShaderProgram->SetModelNormalMatrix(skeletalModel->NormalMatrix());
356 
357     this->m_ModelCache = skeletalModel;
358 }
359 
360 //----------------------------------------
361 // アクティベート関係
362 
363 
364 //---------------------------------------------------------------------------
365 void
ActivateContext(IMaterialActivator * userMaterialActivator)366 RenderContext::ActivateContext(IMaterialActivator* userMaterialActivator)
367 {
368     if (m_MaterialCache ==  m_Material)
369     {
370         return;
371     }
372 
373     this->ActivateShaderProgram();
374     this->ActivateSceneEnvironment();
375     this->ActivateMaterial(userMaterialActivator);
376 
377     m_MaterialCache = m_Material;
378 }
379 
380 //---------------------------------------------------------------------------
381 void
ActivateParticleContext()382 RenderContext::ActivateParticleContext()
383 {
384     if (this->m_IsVertexAttributeDirty)
385     {
386         internal::ClearVertexAttribute();
387         m_IsVertexAttributeDirty = false;
388     }
389 
390     if (m_MaterialCache ==  m_Material)
391     {
392         return;
393     }
394 
395     bool isParticleMaterialEnabled = false;
396     if (m_MaterialCache != NULL)
397     {
398         isParticleMaterialEnabled =
399             ut::CheckFlag(m_MaterialCache->GetOriginal().GetFlags(), ResMaterialData::FLAG_PARTICLE_MATERIAL_ENABLED) &&
400             ut::CheckFlag(m_Material->GetOriginal().GetFlags(), ResMaterialData::FLAG_PARTICLE_MATERIAL_ENABLED);
401     }
402 
403     if (isParticleMaterialEnabled)
404     {
405         // シェーダープログラムが変更されていないことを表します。
406         m_IsShaderProgramDirty = false;
407         this->ActivateParticleMaterial();
408     }
409     else
410     {
411         this->ActivateContext();
412     }
413 
414     m_MaterialCache = m_Material;
415 }
416 
417 //---------------------------------------------------------------------------
418 void
ActivateVertexAttribute(ResMesh mesh)419 RenderContext::ActivateVertexAttribute( ResMesh mesh )
420 {
421     NW_NULL_ASSERT( mesh.ref().m_ActivateCommandCache );
422 
423     if (m_IsVertexAttributeDirty)
424     {
425         internal::ClearVertexAttribute();
426         m_IsVertexAttributeDirty = false;
427     }
428 
429     internal::NWUseCmdlist( mesh.ref().m_ActivateCommandCache, mesh.ref().m_ActivateCommandCacheSize );
430     internal::NWUseCmdlist( mesh.ref().m_IrScaleCommand, sizeof(mesh.ref().m_IrScaleCommand) );
431 
432     const bool hasVertexAlpha = (mesh.ref().m_Flags & ResMesh::FLAG_HAS_VERTEX_ALPHA) ? true : false;
433     const bool hasBoneWeightW = (mesh.ref().m_Flags & ResMesh::FLAG_HAS_BONE_WEIGHT_W) ? true : false;
434 
435     this->m_ShaderProgram->SetVertexUniformBool(NW_GFX_VERTEX_UNIFORM(ISVERTA), hasVertexAlpha);
436     this->m_ShaderProgram->SetVertexUniformBool(NW_GFX_VERTEX_UNIFORM(ISBONEW), hasBoneWeightW);
437 }
438 
439 //----------------------------------------
440 void
ActivateShaderProgram()441 RenderContext::ActivateShaderProgram()
442 {
443     if (!ut::CheckFlag(m_RenderMode, RenderContext::RENDERMODE_IGNORE_SHADER))
444     {
445         ResShaderProgramDescription description = this->m_Material->GetDescription();
446 
447         NW_ASSERT(description.IsValid());
448 
449         ResShaderProgramDescription previousDescription =
450             this->m_ShaderProgram->GetActiveDescription();
451 
452         if ( previousDescription != description )
453         {
454             // ジオメトリシェーダ使用後はクリア処理が必要。
455             if ( previousDescription.IsValid() &&
456                  previousDescription.GetGeometryShaderIndex() >= 0 &&
457                  description.GetGeometryShaderIndex() < 0 )
458             {
459                 this->m_IsVertexAttributeDirty = true;
460 
461                 const s32 hashMask = Model::FLAG_BUFFER_SHADER_PARAMETER    |
462                                      Model::FLAG_BUFFER_MATERIAL_COLOR      |
463                                      Model::FLAG_BUFFER_TEXTURE_COORDINATOR |
464                                      Model::FLAG_BUFFER_SCENE_ENVIRONMENT;
465                 m_MaterialHash.ResetMaterialHash(hashMask );
466 
467                 this->m_SceneEnvironment.SetAllFlagsDirty( true );
468             }
469 
470             m_ShaderProgram.Get()->ActivateDescription(description);
471 
472             m_IsShaderProgramDirty = true;
473         }
474         else
475         {
476             m_IsShaderProgramDirty = false;
477         }
478     }
479 }
480 
481 //----------------------------------------
482 void
ActivateSceneEnvironment()483 RenderContext::ActivateSceneEnvironment()
484 {
485     if (!ut::CheckFlag(m_RenderMode, RenderContext::RENDERMODE_IGNORE_SCENEENVIRONMENT))
486     {
487         NW_NULL_ASSERT(this->m_Material);
488         const Model* owner = this->m_Material->GetOwnerModel();
489         NW_NULL_ASSERT(owner);
490 
491         ResMaterial resMaterial = this->m_Material->GetSceneEnvironmentResMaterial();
492 
493         this->m_SceneEnvironment.SetActiveLightSet(resMaterial.GetLightSetIndex());
494 
495         if (this->m_SceneEnvironment.IsFragmentLightsDirty())
496         {
497             this->ActivateFragmentLights();
498         }
499 
500         if (this->m_SceneEnvironment.IsHemiSphereLightDirty())
501         {
502             this->ActivateHemiSphereLight();
503         }
504     #if defined(NW_GFX_VERTEX_LIGHT_ENABLED)
505         if (this->m_SceneEnvironment.IsVertexLightsDirty())
506         {
507             this->ActivateVertexLights();
508         }
509     #endif
510         this->m_SceneEnvironment.SetActiveFog(resMaterial.GetFogIndex());
511 
512         if (this->m_SceneEnvironment.IsFogDirty())
513         {
514             this->ActivateFog();
515         }
516 
517         this->m_SceneEnvironment.SetAllFlagsDirty(false);
518     }
519 }
520 
521 //----------------------------------------
522 void
ActivateFog()523 RenderContext::ActivateFog()
524 {
525     if (this->m_SceneEnvironment.GetActiveFog() != NULL)
526     {
527         NW_ASSERT(this->m_SceneEnvironment.GetActiveFog()->GetResFog().IsValid());
528         NW_ASSERT(this->m_SceneEnvironment.GetActiveFog()->GetResFog().GetFogSampler().IsValid());
529 
530         ResFog resFog = m_SceneEnvironment.GetActiveFog()->GetResFog();
531 
532         ResImageLookupTable lut = resFog.GetFogSampler();
533 
534         enum
535         {
536             REG_FOG_ZFLIP = 0xe0,
537             REG_FOG_COLOR = 0xe1,
538             REG_FOG_ZFLIP_SHIFT = 16
539         };
540 
541         ut::Color8 color8 = resFog.GetColor();
542 
543         const u32 HEADER_FOG_ZFLIP = internal::MakeCommandHeader(REG_FOG_ZFLIP, 1, false, 0x4);
544         const u32 HEADER_FOG_COLOR = internal::MakeCommandHeader(REG_FOG_COLOR, 1, false, 0xf);
545 
546         // TODO: ZFLIP の設定が逆だが、FogUpdater で逆順の LUT を生成しているので辻褄が合っている。
547         //       両方の足並みを揃えて修正する。
548         u32 FOG_COMMAND[] =
549         {
550             (resFog.IsZFlip() ? (0x1 << REG_FOG_ZFLIP_SHIFT) : 0x0),
551             HEADER_FOG_ZFLIP,
552             color8.r | color8.g << 8 | color8.b << 16,
553             HEADER_FOG_COLOR
554         };
555 
556         internal::NWUseCmdlist<sizeof(FOG_COMMAND)>(&FOG_COMMAND[0]);
557 
558         GraphicsDevice::ActivateLookupTable(lut, GraphicsDevice::LUT_TARGET_FOG);
559     }
560 }
561 
562 //----------------------------------------
563 void
ActivateHemiSphereLight()564 RenderContext::ActivateHemiSphereLight()
565 {
566     const HemiSphereLight* hemiSphereLight = m_SceneEnvironment.GetHemiSphereLight();
567     if (hemiSphereLight &&
568         ut::CheckFlag(
569             m_ShaderProgram->GetActiveDescription().GetFlags(),
570             ResShaderProgramDescription::FLAG_IS_SUPPORTING_HEMISPHERE_LIGHTING))
571     {
572             ResHemiSphereLight resLight = hemiSphereLight->GetResHemiSphereLight();
573             NW_ASSERT(resLight.IsValid());
574 
575             internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_HSLGCOL_INDEX, 1, resLight.GetGroundColor());
576             internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_HSLSCOL_INDEX, 1, resLight.GetSkyColor());
577 
578             math::VEC3 direction(resLight.GetDirection());
579             if (ut::CheckFlag(resLight.GetFlags(), ResHemiSphereLightData::FLAG_IS_INHERITING_DIRECTION_ROTATE) &&
580                 hemiSphereLight->GetParent() != NULL)
581             {
582                 math::VEC3TransformNormal(
583                     &direction, &hemiSphereLight->TrackbackWorldMatrix(), &resLight.GetDirection());
584             }
585 
586             const Camera* camera = this->GetActiveCamera();
587             NW_NULL_ASSERT(camera);
588 
589             const math::MTX34& viewMatrix = camera->ViewMatrix();
590 
591             math::VEC3TransformNormal(&direction, &viewMatrix, &direction);
592             math::VEC4 directionAndLerp(direction.x, direction.y, direction.z, resLight.GetLerpFactor());
593 
594             internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_HSLSDIR_INDEX, 1, directionAndLerp);
595 
596     }
597 }
598 
599 //----------------------------------------
600 void
ActivateFragmentLights()601 RenderContext::ActivateFragmentLights()
602 {
603     GraphicsDevice::ResetFragmentLightEnabled();
604     int lightCount = this->m_SceneEnvironment.GetFragmentLightCount();
605 
606     for (int i = 0; i < lightCount; ++i)
607     {
608         const FragmentLight* light = this->m_SceneEnvironment.GetFragmentLight(i);
609 
610         this->ActivateFragmentLight(i, light);
611     }
612 
613     GraphicsDevice::ActivateFragmentLightEnabled();
614 }
615 
616 //----------------------------------------
617 void
ActivateFragmentLight(int index,const FragmentLight * light)618 RenderContext::ActivateFragmentLight(int index, const FragmentLight* light)
619 {
620     ResFragmentLight resLight = light->GetResFragmentLight();
621     NW_ASSERT(resLight.IsValid());
622 
623     s32 lightKind = resLight.GetLightKind();
624     NW_ASSERT(lightKind < ResFragmentLight::KIND_COUNT);
625 
626     Camera* camera = this->GetActiveCamera();
627     NW_NULL_ASSERT(camera);
628 
629     const math::MTX34& viewMatrix = camera->ViewMatrix();
630 
631     if ( lightKind == ResFragmentLight::KIND_DIRECTIONAL )
632     {
633         nw::math::VEC4 direction(light->Direction());
634         direction.w = 0.0f;
635 
636         this->TransformToViewCoordinate(&direction, &viewMatrix, &direction);
637 
638         // 平行光源はポジションの逆方向のベクトルをディレクションとします。
639         GraphicsDevice::ActivateFragmentLightPosition(index, -direction);
640         GraphicsDevice::SetFragmentLightPositionW(index, (direction.w == 0.0f));
641 
642         GraphicsDevice::SetFragmentLightSpotEnabled(index, false);
643         GraphicsDevice::SetFragmentLightDistanceAttnEnabled(index, false);
644     }
645     else if ( lightKind == ResFragmentLight::KIND_POINT )
646     {
647         GraphicsDevice::SetFragmentLightSpotEnabled(index, false);
648 
649         if ( ut::CheckFlag(resLight.GetFlags(), ResFragmentLightData::FLAG_DISTANCE_ATTENUATION_ENABLED)
650             && resLight.GetDistanceSampler().IsValid() )
651         {
652             GraphicsDevice::SetFragmentLightDistanceAttnEnabled(index, true);
653             GraphicsDevice::ActivateFragmentLightDistanceAttnTable(index, resLight.GetDistanceSampler().Dereference());
654 
655             GraphicsDevice::ActivateFragmentLightDistanceAttnScaleBias(
656                 index,
657                 resLight.ref().m_DistanceAttenuationScale,
658                 resLight.ref().m_DistanceAttenuationBias );
659         }
660         else
661         {
662             GraphicsDevice::SetFragmentLightDistanceAttnEnabled(index, false);
663         }
664 
665         nw::math::VEC4 position = GetTranslate(light->WorldMatrix());
666         position.w = 1.0f;
667         this->TransformToViewCoordinate(&position, &viewMatrix, &position);
668 
669         GraphicsDevice::ActivateFragmentLightPosition(index, position);
670         GraphicsDevice::SetFragmentLightPositionW(index, (position.w == 0.0f));
671     }
672     else if ( lightKind == ResFragmentLight::KIND_SPOT )
673     {
674         NW_ASSERTMSG(resLight.GetAngleSampler().IsValid(), "The spot light must contain angle sampler(lookuptable).");
675         NW_ASSERTMSG(resLight.GetAngleSampler().GetSampler().IsValid(), "The spot light must contain angle sampler(lookuptable).");
676 
677         if (resLight.GetAngleSampler().IsValid())
678         {
679             GraphicsDevice::SetFragmentLightSpotEnabled(index, true);
680             GraphicsDevice::ActivateFragmentLightSpotTable(index, resLight.GetAngleSampler().GetSampler().Dereference());
681             GraphicsDevice::SetLutIsAbs( GraphicsDevice::LUT_TARGET_SP, resLight.GetAngleSampler().GetSampler().Dereference().IsAbs() );
682             GraphicsDevice::SetLutInput( GraphicsDevice::LUT_TARGET_SP, resLight.GetAngleSampler().GetInput() );
683             GraphicsDevice::SetLutScale( GraphicsDevice::LUT_TARGET_SP, resLight.GetAngleSampler().GetScale() );
684         }
685 
686         if ( ut::CheckFlag(resLight.GetFlags(), ResFragmentLightData::FLAG_DISTANCE_ATTENUATION_ENABLED )
687             && resLight.GetDistanceSampler().IsValid())
688         {
689             GraphicsDevice::SetFragmentLightDistanceAttnEnabled(index, true);
690             GraphicsDevice::ActivateFragmentLightDistanceAttnTable(index, resLight.GetDistanceSampler().Dereference());
691 
692             GraphicsDevice::ActivateFragmentLightDistanceAttnScaleBias(
693                 index,
694                 resLight.ref().m_DistanceAttenuationScale,
695                 resLight.ref().m_DistanceAttenuationBias );
696         }
697         else
698         {
699             GraphicsDevice::SetFragmentLightDistanceAttnEnabled(index, false);
700         }
701 
702         nw::math::VEC4 direction(light->Direction());
703         direction.w = 0.0f;
704 
705         this->TransformToViewCoordinate(&direction, &viewMatrix, &direction);
706 
707         nw::math::VEC4 position = GetTranslate(light->WorldMatrix());
708         position.w = 1.0f;
709         this->TransformToViewCoordinate(&position, &viewMatrix, &position);
710 
711         math::VEC3 spotDirection(direction);
712         GraphicsDevice::ActivateFragmentLightPosition(index, position, spotDirection);
713         GraphicsDevice::SetFragmentLightPositionW(index, (position.w == 0.0f));
714     }
715 }
716 
717 #if defined(NW_GFX_VERTEX_LIGHT_ENABLED)
718 //----------------------------------------
719 void
ActivateVertexLights()720 RenderContext::ActivateVertexLights()
721 {
722     int size = this->m_SceneEnvironment.GetVertexLightCount();
723     if (size > 0)
724     {
725         const ShaderProgram* shaderProgram = this->GetShaderProgram();
726 
727         // 整数レジスタにループカウンタとして頂点ライトの数をセットする。
728         // ただし、頂点シェーダーでは整数レジスタ+1回のループを行うために頂点ライト数-1を設定する。
729         // 頂点ライトが0の場合はIsVertLを用いてループを行わないようにしている。
730         if(shaderProgram->GetActiveDescription().GetMaxVertexLightCount() > 0)
731         {
732             shaderProgram->SetVertexUniformInt(
733                 NW_GFX_VERTEX_UNIFORM(LIGHTCT),
734                 ut::Max<s32>(size - 1, 0),
735                 0,
736                 1);
737         }
738 
739         for (int i = 0; i < size; i++)
740         {
741             this->ActivateVertexLight(i, m_SceneEnvironment.GetVertexLight(i));
742         }
743     }
744 }
745 
746 //----------------------------------------
747 void
ActivateVertexLight(int index,const VertexLight * light)748 RenderContext::ActivateVertexLight(int index, const VertexLight* light)
749 {
750     if (m_ShaderProgram->GetActiveDescription().GetMaxVertexLightCount() > index)
751     {
752         const float LIGHT_INFINITY = 0.0f;
753         const float LIGHT_FINITY = 1.0f;
754 
755         s32 endUniform = m_ShaderProgram->GetActiveDescription().GetVertexLightEndUniform();
756         ResVertexLight resLight = light->GetResVertexLight();
757         NW_ASSERT(resLight.IsValid());
758 
759         Camera* camera = this->GetActiveCamera();
760         NW_NULL_ASSERT(camera);
761 
762         const math::MTX34& viewMatrix = camera->ViewMatrix();
763 
764         m_ShaderProgram->SetUniversal(
765             endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_AMBIENT,
766             resLight.GetAmbient());
767 
768         m_ShaderProgram->SetUniversal(
769             endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_DIFFUSE,
770             resLight.GetDiffuse());
771 
772         if (resLight.GetLightKind() == ResVertexLight::KIND_DIRECTIONAL)
773         {
774             // OpenGLではライトを無限遠に置くことで平行光源を実現しています。
775             // デフォルトシェーダーも同様の仕様となります。
776             math::VEC4 position(light->Direction());
777             position.w = LIGHT_INFINITY;
778 
779             this->TransformToViewCoordinate(&position, &viewMatrix, &position);
780             m_ShaderProgram->SetUniversal(
781                 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_POSITION,
782                 -position);
783         }
784         else
785         {
786             math::VEC4 position = GetTranslate(light->WorldMatrix());
787             position.w = LIGHT_FINITY;
788 
789             this->TransformToViewCoordinate(&position, &viewMatrix, &position);
790             m_ShaderProgram->SetUniversal(
791                 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_POSITION,
792                 position);
793 
794             // 距離減衰パラメータを設定します。
795             m_ShaderProgram->SetUniversal(
796                 endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_DISTANCE_ATTENUATION,
797                 resLight.GetDistanceAttenuationAndEnabled());
798 
799             if (resLight.GetLightKind() == ResVertexLight::KIND_SPOT)
800             {
801                 // スポットパラメータを設定します。
802                 math::VEC4 spotDirection(light->Direction());
803                 spotDirection.w = 0.0f;
804 
805                 this->TransformToViewCoordinate(&spotDirection, &viewMatrix, &spotDirection);
806 
807                 math::VEC4 spotFactor(resLight.GetSpotFactor().x, resLight.GetSpotFactor().y, 0.0f, 0.0f);
808                 if (resLight.GetSpotFactor().y > 0.0f && resLight.GetSpotFactor().y < math::F_PI)
809                 {
810                     spotFactor.y = nw::math::CosRad(resLight.GetSpotFactor().y);
811                     spotDirection.w = 1.0f;
812                 }
813                 else if (resLight.GetSpotFactor().y == 0.0f)
814                 {
815                     const float EPSILON = 1e-5f;
816                     const float GREATER_THAN_ONE = 1.0f + EPSILON;
817                     spotFactor.y = GREATER_THAN_ONE;
818                     spotDirection.w = 1.0f;
819                 }
820                 else
821                 {
822                     spotDirection.w = 0.0f;
823                 }
824 
825                 m_ShaderProgram->SetUniversal(
826                     endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_SPOT_DIRECTION,
827                     spotDirection);
828 
829                 m_ShaderProgram->SetUniversal(
830                     endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_SPOT_FACTOR,
831                     spotFactor);
832             }
833             else
834             {
835                 m_ShaderProgram->SetUniversal(
836                     endUniform - (index + 1) * VERTEX_LIGHT_SET_COUNT + VERTEX_LIGHT_SPOT_DIRECTION,
837                     math::VEC4::Zero());
838             }
839         }
840     }
841 }
842 #endif
843 
844 //----------------------------------------
845 void
TransformToViewCoordinate(math::VEC4 * out,const math::MTX34 * __restrict view,const math::VEC4 * v)846 RenderContext::TransformToViewCoordinate(
847     math::VEC4* out,
848     const math::MTX34* __restrict view,
849     const math::VEC4* v)
850 {
851     f32 vx = v->x;
852     f32 vy = v->y;
853     f32 vz = v->z;
854     f32 vw = v->w;
855 
856     out->x = view->f._00 * vx + view->f._01 * vy + view->f._02 * vz + view->f._03 * vw;
857     out->y = view->f._10 * vx + view->f._11 * vy + view->f._12 * vz + view->f._13 * vw;
858     out->z = view->f._20 * vx + view->f._21 * vy + view->f._22 * vz + view->f._23 * vw;
859     out->w = vw;
860 }
861 
862 
863 //----------------------------------------
864 void
RenderPrimitive(ResPrimitive primitive)865 RenderContext::RenderPrimitive(
866     ResPrimitive primitive
867 )
868 {
869     NW_ASSERT(primitive.IsValid());
870 
871     this->m_ShaderProgram->FlushUniform();
872 
873 #if defined(NW_GFX_USE_BONE_INDEX_SCALE)
874     const math::VEC4 float4(1.0f, 1.0f, 1.0f, 1.0f);
875 
876     internal::NWSetVertexUniform4fv( VERTEX_SHADER_UNIFORM_IRSCALE_INDEX + 2, 1, float4 );
877 #endif
878 
879     // コマンドがまだ未構築の場合はコマンドキャッシュを生成する。
880     // バッファは、Setup で確保済み。
881     if ((primitive.GetFlags() & ResPrimitive::FLAG_COMMAND_HAS_BEEN_SETUP) == 0)
882     {
883         ResShaderProgramDescription description = this->m_ShaderProgram->GetActiveDescription();
884         bool hasGeometryShader = (description.GetGeometryShaderObject() > 0);
885 
886         primitive.SetupDrawCommand(hasGeometryShader);
887     }
888 
889     // 描画コマンドの送信。
890     ResIndexStreamArray indexStreams = primitive.GetIndexStreams();
891     ResIndexStreamArray::iterator end = indexStreams.end();
892     // NW_FOREACH(ResIndexStream indexStream, indexStreams)
893     for (ResIndexStreamArray::iterator stream = indexStreams.begin(); stream != end; ++stream)
894     {
895         ResIndexStream indexStream = *stream;
896 
897         if (!indexStream.IsVisible()) { continue; }
898 
899         NW_NULL_ASSERT(indexStream.ref().m_CommandCache);
900         NW_ASSERT(indexStream.ref().m_CommandCacheSize > 0);
901         internal::NWUseCmdlist(indexStream.ref().m_CommandCache, indexStream.ref().m_CommandCacheSize);
902     }
903 }
904 
905 } // namespace gfx
906 } // namespace nw
907 
908