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