/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_SimpleMaterialActivator.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 26943 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include // このマクロを定義するとハッシュと利用します。 #define MATERIAL_HASH_ENABLED namespace nw { namespace gfx { NW_UT_RUNTIME_TYPEINFO_DEFINITION(SimpleMaterialActivator, IMaterialActivator); //---------------------------------------- IMaterialActivator* SimpleMaterialActivator::Create(os::IAllocator* allocator) { void* memory = allocator->Alloc(sizeof(SimpleMaterialActivator)); if (memory == NULL) { return NULL; } else { return new(memory) SimpleMaterialActivator(allocator); } } //---------------------------------------- void SimpleMaterialActivator::Activate(RenderContext* renderContext, const Material* material) { NW_NULL_ASSERT(renderContext); const SceneEnvironment& sceneEnvironment = renderContext->GetSceneEnvironment(); bool areFragmentLightsDirty = sceneEnvironment.IsFragmentLightsDirty() || sceneEnvironment.IsAmbientLightDirty(); bool areVertexLightsDirty = sceneEnvironment.IsVertexLightsDirty() || sceneEnvironment.IsHemiSphereLightDirty(); // SimpleMaterialActivator の場合はリソースの比較を行います。 // 直前に設定したマテリアルがバッファを使っている場合はスキップできません。 const Material* cacheMaterial = renderContext->GetMaterialCache(); if ( ( cacheMaterial != NULL) && ( cacheMaterial->GetBufferCount() == 0) && ( cacheMaterial->GetOriginal() == material->GetOriginal() ) && ( !areFragmentLightsDirty ) && ( !areVertexLightsDirty ) ) { return; } const ShaderProgram* shaderProgram = renderContext->GetShaderProgram(); NW_NULL_ASSERT(shaderProgram); ResMaterial original = material->GetOriginal(); const Model* owner = material->GetOwnerModel(); NW_NULL_ASSERT(owner); #if defined(MATERIAL_HASH_ENABLED) RenderContext::MaterialHash materialHash = renderContext->GetMaterialHash(); ResMaterial resShaderParameterMaterial = original; u32 shaderParametersHash = resShaderParameterMaterial.GetShaderParametersHash(); bool isShaderParametersEnabled = (shaderParametersHash == 0x0) || (shaderParametersHash != materialHash.shaderParameter) || renderContext->IsShaderProgramDirty(); if (isShaderParametersEnabled) { internal::MaterialState::ActivateShaderParameter(shaderProgram, resShaderParameterMaterial); materialHash.shaderParameter = shaderParametersHash; } ResMaterial resShadingParametersMaterial = original; // FragmentLightEnabled は必ず設定します。 internal::MaterialState::ActivateFragmentLightParameters(sceneEnvironment, shaderProgram, resShadingParametersMaterial); u32 shadingParametersHash = resShadingParametersMaterial.GetShadingParameterHash(); bool isShadingParametersEnabled = (shadingParametersHash == 0x0) || (shadingParametersHash != materialHash.shadingParameter) || areVertexLightsDirty; if (isShadingParametersEnabled) { internal::MaterialState::ActivateShadingParameters(sceneEnvironment, shaderProgram, resShadingParametersMaterial); materialHash.shadingParameter = shadingParametersHash; } ResRasterization resRasterization = original.GetRasterization(); u32 rasterizationHash = original.GetRasterizationHash(); bool isRasterizationEnabled = (rasterizationHash == 0x0) || (rasterizationHash != materialHash.rasterization); if (isRasterizationEnabled) { internal::MaterialState::ActivateRasterization(resRasterization); materialHash.rasterization = rasterizationHash; } ResMaterial resTextureCoordinatorsMaterial = original; u32 textureCoordinatorHash = resTextureCoordinatorsMaterial.GetTextureCoordinatorsHash(); bool isTextureCoordinatorEnabled = (textureCoordinatorHash == 0x0) || (textureCoordinatorHash != materialHash.textureCoordinator); if (isTextureCoordinatorEnabled) { internal::MaterialState::ActivateTextureCoordinators(renderContext, shaderProgram, resTextureCoordinatorsMaterial); materialHash.textureCoordinator = textureCoordinatorHash; } ResMaterial resTextureMappersMaterial = original; u32 textureMappersHash = resTextureMappersMaterial.GetTextureMappersHash(); bool isTextureMappersEnabled = (textureMappersHash == 0x0) || (textureMappersHash != materialHash.textureMapper); if (isTextureMappersEnabled) { internal::MaterialState::ActivateTextureMappers(resTextureMappersMaterial); materialHash.textureMapper = textureMappersHash; } #if 0 // プロシージャルテクスチャは未対応 ResMaterial resProceduralTextureMapperMaterial = original; internal::MaterialState::ActivateProceduralTextureMapper(renderContext, shaderProgram, resProceduralTextureMapperMaterial); #endif bool reflectionEnabled = false; bool lightEnabled = ut::CheckFlag(original.GetFlags(), ResMaterialData::FLAG_FRAGMENTLIGHT_ENABLED); if (lightEnabled) { ResFragmentLighting resFragmentLighting =original.GetFragmentShader().GetFragmentLighting(); reflectionEnabled = ut::CheckFlag(resFragmentLighting.GetFlags(), ResFragmentLightingData::FLAG_REFLECTION_ENABLED); u32 fragmentLightingHash = original.GetFragmentLightingHash(); bool isFragmentLightingEnabled = (fragmentLightingHash == 0x0) || (fragmentLightingHash != materialHash.fragmentLighting) || areFragmentLightsDirty; if (isFragmentLightingEnabled) { internal::MaterialState::ActivateFragmentLighting(sceneEnvironment, resFragmentLighting); materialHash.fragmentLighting = fragmentLightingHash; } ResFragmentLightingTable resFragmentLightingTable =original.GetFragmentShader().GetFragmentLightingTable(); u32 fragmentLightingTableHash = original.GetFragmentLightingTableHash(); bool isFragmentLightingTableEnabled = (fragmentLightingTableHash == 0x0) || (fragmentLightingTableHash != materialHash.fragmentLightingTable); if (isFragmentLightingTableEnabled) { internal::MaterialState::ActivateFragmentLightingTable(resFragmentLighting, resFragmentLightingTable); materialHash.fragmentLightingTable = fragmentLightingTableHash; } } ResMaterialColor resMaterialColor = original.GetMaterialColor(); u32 materialColorHash = original.GetMaterialColorHash(); bool isMaterialColorEnabled = (materialColorHash == 0x0) || (materialColorHash != materialHash.materialColor) || areFragmentLightsDirty; if (!isMaterialColorEnabled && cacheMaterial != NULL) { // マテリアルカラーは reflectionEnabled が変化したときに再設定する必要があるために前回に設定したマテリアルを参照します。 bool isPreReflectionEnabled = ut::CheckFlag(cacheMaterial->GetOriginal().GetFragmentShader().GetFragmentLighting().GetFlags(), ResFragmentLightingData::FLAG_REFLECTION_ENABLED); isMaterialColorEnabled = (reflectionEnabled != isPreReflectionEnabled); } if (isMaterialColorEnabled) { internal::MaterialState::ActivateMaterialColor(sceneEnvironment, shaderProgram, resMaterialColor, reflectionEnabled); materialHash.materialColor = materialColorHash; } ResFragmentShader resTextureCombinerFragmentShader = original.GetFragmentShader(); u32 textureCombinersHash = original.GetTextureCombinersHash(); bool isTextureCombinersEnabled = (textureCombinersHash == 0x0) || (textureCombinersHash != materialHash.textureCombiner); if (isTextureCombinersEnabled || isMaterialColorEnabled) { internal::MaterialState::ActivateTextureCombiners(resTextureCombinerFragmentShader, resMaterialColor); materialHash.textureCombiner = textureCombinersHash; } ResAlphaTest resAlphaTest = original.GetFragmentShader().GetAlphaTest(); u32 alphaTestHash = original.GetAlphaTestHash(); bool isAlphaTestEnabled = (alphaTestHash == 0x0) || (alphaTestHash != materialHash.alphaTest); if (isAlphaTestEnabled) { internal::MaterialState::ActivateAlphaTest(resAlphaTest); materialHash.alphaTest = alphaTestHash; } ResFragmentOperation resFragmentOperation = original.GetFragmentOperation(); u32 fragmentOperationHash = original.GetFragmentOperationHash(); bool isFragmentOperationEnabled = (fragmentOperationHash == 0x0) || (fragmentOperationHash != materialHash.fragmentOperation); if (isFragmentOperationEnabled) { internal::MaterialState::ActivateFragmentOperation(resFragmentOperation); materialHash.fragmentOperation = fragmentOperationHash; } renderContext->SetMaterialHash(materialHash); #else internal::MaterialState::ActivateShaderParameter(shaderProgram, original); internal::MaterialState::ActivateShadingParameters(sceneEnvironment, shaderProgram, original); internal::MaterialState::ActivateRasterization(original.GetRasterization()); internal::MaterialState::ActivateTextureCoordinators(sceneEnvironment, shaderProgram, original); internal::MaterialState::ActivateTextureMappers(original); ResFragmentShader resFragmentShader = original.GetFragmentShader(); bool lightEnabled = ut::CheckFlag(original.GetFlags(), ResMaterialData::FLAG_FRAGMENTLIGHT_ENABLED); bool reflectionEnabled = false; if (lightEnabled) { reflectionEnabled = ut::CheckFlag(resFragmentShader.GetFragmentLighting().GetFlags(), ResFragmentLightingData::FLAG_REFLECTION_ENABLED); internal::MaterialState::ActivateFragmentLighting(sceneEnvironment, resFragmentShader.GetFragmentLighting()); internal::MaterialState::ActivateFragmentLightingTable(resFragmentShader.GetFragmentLighting(), resFragmentShader.GetFragmentLightingTable()); } ResMaterialColor resMaterialColor = original.GetMaterialColor(); internal::MaterialState::ActivateMaterialColor(sceneEnvironment, shaderProgram, resMaterialColor, reflectionEnabled); internal::MaterialState::ActivateTextureCombiners(resFragmentShader, resMaterialColor); internal::MaterialState::ActivateAlphaTest(resFragmentShader.GetAlphaTest()); ResFragmentOperation resFragmentOperation = original.GetFragmentOperation(); internal::MaterialState::ActivateFragmentOperation(resFragmentOperation); #endif } //---------------------------------------- SimpleMaterialActivator::SimpleMaterialActivator(os::IAllocator* allocator) : IMaterialActivator(allocator) { } //---------------------------------------- SimpleMaterialActivator::~SimpleMaterialActivator() { } } // namespace gfx } // namespace nw