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