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