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