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