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