1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_SimpleMaterialActivator.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: 26943 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/gfx/gfx_SimpleMaterialActivator.h>
19 #include <nw/gfx/gfx_MaterialState.h>
20 #include <nw/gfx/gfx_Model.h>
21 #include <nn/gx.h>
22 #include <nw/dev.h>
23 
24 // このマクロを定義するとハッシュと利用します。
25 #define MATERIAL_HASH_ENABLED
26 
27 namespace nw
28 {
29 namespace gfx
30 {
31 
32 NW_UT_RUNTIME_TYPEINFO_DEFINITION(SimpleMaterialActivator, IMaterialActivator);
33 
34 //----------------------------------------
35 IMaterialActivator*
Create(os::IAllocator * allocator)36 SimpleMaterialActivator::Create(os::IAllocator* allocator)
37 {
38     void* memory = allocator->Alloc(sizeof(SimpleMaterialActivator));
39 
40     if (memory == NULL)
41     {
42         return NULL;
43     }
44     else
45     {
46         return new(memory) SimpleMaterialActivator(allocator);
47     }
48 }
49 
50 //----------------------------------------
51 void
Activate(RenderContext * renderContext,const Material * material)52 SimpleMaterialActivator::Activate(RenderContext* renderContext, const Material* material)
53 {
54     NW_NULL_ASSERT(renderContext);
55 
56     const SceneEnvironment& sceneEnvironment = renderContext->GetSceneEnvironment();
57     bool areFragmentLightsDirty = sceneEnvironment.IsFragmentLightsDirty() || sceneEnvironment.IsAmbientLightDirty();
58     bool areVertexLightsDirty = sceneEnvironment.IsVertexLightsDirty() || sceneEnvironment.IsHemiSphereLightDirty();
59 
60     // SimpleMaterialActivator の場合はリソースの比較を行います。
61     // 直前に設定したマテリアルがバッファを使っている場合はスキップできません。
62     const Material* cacheMaterial = renderContext->GetMaterialCache();
63     if ( ( cacheMaterial != NULL) &&
64          ( cacheMaterial->GetBufferCount() == 0) &&
65          ( cacheMaterial->GetOriginal() == material->GetOriginal() ) &&
66          ( !areFragmentLightsDirty ) &&
67          ( !areVertexLightsDirty ) )
68     {
69         return;
70     }
71 
72     const ShaderProgram* shaderProgram = renderContext->GetShaderProgram();
73     NW_NULL_ASSERT(shaderProgram);
74 
75     ResMaterial original = material->GetOriginal();
76     const Model* owner = material->GetOwnerModel();
77     NW_NULL_ASSERT(owner);
78 
79 #if defined(MATERIAL_HASH_ENABLED)
80     RenderContext::MaterialHash materialHash = renderContext->GetMaterialHash();
81 
82     ResMaterial resShaderParameterMaterial = original;
83     u32 shaderParametersHash = resShaderParameterMaterial.GetShaderParametersHash();
84     bool isShaderParametersEnabled =
85         (shaderParametersHash == 0x0) ||
86         (shaderParametersHash != materialHash.shaderParameter) ||
87         renderContext->IsShaderProgramDirty();
88     if (isShaderParametersEnabled)
89     {
90         internal::MaterialState::ActivateShaderParameter(shaderProgram, resShaderParameterMaterial);
91         materialHash.shaderParameter = shaderParametersHash;
92     }
93 
94     ResMaterial resShadingParametersMaterial = original;
95 
96     // FragmentLightEnabled は必ず設定します。
97     internal::MaterialState::ActivateFragmentLightParameters(sceneEnvironment, shaderProgram, resShadingParametersMaterial);
98 
99     u32 shadingParametersHash = resShadingParametersMaterial.GetShadingParameterHash();
100     bool isShadingParametersEnabled =
101         (shadingParametersHash == 0x0) || (shadingParametersHash != materialHash.shadingParameter) || areVertexLightsDirty;
102     if (isShadingParametersEnabled)
103     {
104         internal::MaterialState::ActivateShadingParameters(sceneEnvironment, shaderProgram, resShadingParametersMaterial);
105         materialHash.shadingParameter = shadingParametersHash;
106     }
107 
108     ResRasterization resRasterization = original.GetRasterization();
109     u32 rasterizationHash = original.GetRasterizationHash();
110     bool isRasterizationEnabled = (rasterizationHash == 0x0) || (rasterizationHash != materialHash.rasterization);
111     if (isRasterizationEnabled)
112     {
113         internal::MaterialState::ActivateRasterization(resRasterization);
114         materialHash.rasterization = rasterizationHash;
115     }
116 
117     ResMaterial resTextureCoordinatorsMaterial = original;
118     u32 textureCoordinatorHash = resTextureCoordinatorsMaterial.GetTextureCoordinatorsHash();
119     bool isTextureCoordinatorEnabled = (textureCoordinatorHash == 0x0) || (textureCoordinatorHash != materialHash.textureCoordinator);
120     if (isTextureCoordinatorEnabled)
121     {
122         internal::MaterialState::ActivateTextureCoordinators(renderContext, shaderProgram, resTextureCoordinatorsMaterial);
123         materialHash.textureCoordinator = textureCoordinatorHash;
124     }
125 
126     ResMaterial resTextureMappersMaterial = original;
127     u32 textureMappersHash = resTextureMappersMaterial.GetTextureMappersHash();
128     bool isTextureMappersEnabled = (textureMappersHash == 0x0) || (textureMappersHash != materialHash.textureMapper);
129     if (isTextureMappersEnabled)
130     {
131         internal::MaterialState::ActivateTextureMappers(resTextureMappersMaterial);
132         materialHash.textureMapper = textureMappersHash;
133     }
134 
135 #if 0 // プロシージャルテクスチャは未対応
136     ResMaterial resProceduralTextureMapperMaterial = original;
137     internal::MaterialState::ActivateProceduralTextureMapper(renderContext, shaderProgram, resProceduralTextureMapperMaterial);
138 #endif
139 
140     bool reflectionEnabled = false;
141     bool lightEnabled = ut::CheckFlag(original.GetFlags(), ResMaterialData::FLAG_FRAGMENTLIGHT_ENABLED);
142     if (lightEnabled)
143     {
144         ResFragmentLighting resFragmentLighting =original.GetFragmentShader().GetFragmentLighting();
145         reflectionEnabled = ut::CheckFlag(resFragmentLighting.GetFlags(), ResFragmentLightingData::FLAG_REFLECTION_ENABLED);
146         u32 fragmentLightingHash = original.GetFragmentLightingHash();
147         bool isFragmentLightingEnabled = (fragmentLightingHash == 0x0) ||
148                                          (fragmentLightingHash != materialHash.fragmentLighting) ||
149                                          areFragmentLightsDirty;
150         if (isFragmentLightingEnabled)
151         {
152             internal::MaterialState::ActivateFragmentLighting(sceneEnvironment, resFragmentLighting);
153             materialHash.fragmentLighting = fragmentLightingHash;
154         }
155 
156         ResFragmentLightingTable resFragmentLightingTable =original.GetFragmentShader().GetFragmentLightingTable();
157         u32 fragmentLightingTableHash = original.GetFragmentLightingTableHash();
158         bool isFragmentLightingTableEnabled = (fragmentLightingTableHash == 0x0) || (fragmentLightingTableHash != materialHash.fragmentLightingTable);
159         if (isFragmentLightingTableEnabled)
160         {
161             internal::MaterialState::ActivateFragmentLightingTable(resFragmentLighting, resFragmentLightingTable);
162             materialHash.fragmentLightingTable = fragmentLightingTableHash;
163         }
164     }
165 
166     ResMaterialColor resMaterialColor =  original.GetMaterialColor();
167     u32 materialColorHash = original.GetMaterialColorHash();
168     bool isMaterialColorEnabled = (materialColorHash == 0x0) || (materialColorHash != materialHash.materialColor) || areFragmentLightsDirty;
169     if (!isMaterialColorEnabled && cacheMaterial != NULL)
170     {
171         // マテリアルカラーは reflectionEnabled が変化したときに再設定する必要があるために前回に設定したマテリアルを参照します。
172         bool isPreReflectionEnabled = ut::CheckFlag(cacheMaterial->GetOriginal().GetFragmentShader().GetFragmentLighting().GetFlags(), ResFragmentLightingData::FLAG_REFLECTION_ENABLED);
173         isMaterialColorEnabled = (reflectionEnabled != isPreReflectionEnabled);
174     }
175     if (isMaterialColorEnabled)
176     {
177         internal::MaterialState::ActivateMaterialColor(sceneEnvironment, shaderProgram, resMaterialColor, reflectionEnabled);
178         materialHash.materialColor = materialColorHash;
179     }
180 
181     ResFragmentShader resTextureCombinerFragmentShader = original.GetFragmentShader();
182     u32 textureCombinersHash = original.GetTextureCombinersHash();
183     bool isTextureCombinersEnabled = (textureCombinersHash == 0x0) || (textureCombinersHash != materialHash.textureCombiner);
184     if (isTextureCombinersEnabled || isMaterialColorEnabled)
185     {
186         internal::MaterialState::ActivateTextureCombiners(resTextureCombinerFragmentShader, resMaterialColor);
187         materialHash.textureCombiner = textureCombinersHash;
188     }
189 
190     ResAlphaTest resAlphaTest = original.GetFragmentShader().GetAlphaTest();
191     u32 alphaTestHash = original.GetAlphaTestHash();
192     bool isAlphaTestEnabled = (alphaTestHash == 0x0) || (alphaTestHash != materialHash.alphaTest);
193     if (isAlphaTestEnabled)
194     {
195         internal::MaterialState::ActivateAlphaTest(resAlphaTest);
196         materialHash.alphaTest = alphaTestHash;
197     }
198 
199     ResFragmentOperation resFragmentOperation = original.GetFragmentOperation();
200     u32 fragmentOperationHash = original.GetFragmentOperationHash();
201     bool isFragmentOperationEnabled = (fragmentOperationHash == 0x0) || (fragmentOperationHash != materialHash.fragmentOperation);
202     if (isFragmentOperationEnabled)
203     {
204         internal::MaterialState::ActivateFragmentOperation(resFragmentOperation);
205         materialHash.fragmentOperation = fragmentOperationHash;
206     }
207 
208     renderContext->SetMaterialHash(materialHash);
209 #else
210     internal::MaterialState::ActivateShaderParameter(shaderProgram, original);
211     internal::MaterialState::ActivateShadingParameters(sceneEnvironment, shaderProgram, original);
212     internal::MaterialState::ActivateRasterization(original.GetRasterization());
213     internal::MaterialState::ActivateTextureCoordinators(sceneEnvironment, shaderProgram, original);
214     internal::MaterialState::ActivateTextureMappers(original);
215 
216     ResFragmentShader resFragmentShader = original.GetFragmentShader();
217     bool lightEnabled = ut::CheckFlag(original.GetFlags(), ResMaterialData::FLAG_FRAGMENTLIGHT_ENABLED);
218     bool reflectionEnabled = false;
219     if (lightEnabled)
220     {
221         reflectionEnabled = ut::CheckFlag(resFragmentShader.GetFragmentLighting().GetFlags(), ResFragmentLightingData::FLAG_REFLECTION_ENABLED);
222         internal::MaterialState::ActivateFragmentLighting(sceneEnvironment, resFragmentShader.GetFragmentLighting());
223 
224         internal::MaterialState::ActivateFragmentLightingTable(resFragmentShader.GetFragmentLighting(), resFragmentShader.GetFragmentLightingTable());
225     }
226 
227     ResMaterialColor resMaterialColor =  original.GetMaterialColor();
228     internal::MaterialState::ActivateMaterialColor(sceneEnvironment, shaderProgram, resMaterialColor, reflectionEnabled);
229     internal::MaterialState::ActivateTextureCombiners(resFragmentShader, resMaterialColor);
230 
231     internal::MaterialState::ActivateAlphaTest(resFragmentShader.GetAlphaTest());
232 
233     ResFragmentOperation resFragmentOperation = original.GetFragmentOperation();
234     internal::MaterialState::ActivateFragmentOperation(resFragmentOperation);
235 #endif
236 }
237 
238 //----------------------------------------
SimpleMaterialActivator(os::IAllocator * allocator)239 SimpleMaterialActivator::SimpleMaterialActivator(os::IAllocator* allocator)
240     : IMaterialActivator(allocator)
241 {
242 }
243 
244 //----------------------------------------
~SimpleMaterialActivator()245 SimpleMaterialActivator::~SimpleMaterialActivator()
246 {
247 }
248 
249 } // namespace gfx
250 } // namespace nw
251