From 1ac8fab8840c64aff09a5e6040b289bece36d03b Mon Sep 17 00:00:00 2001 From: LuisAntonRebollo Date: Sat, 8 Nov 2014 01:57:28 +0100 Subject: [PATCH] Changes for get necesary sampler names for OpenGL shaders. --- .../hlsl/advancedLightingFeaturesHLSL.cpp | 5 +- .../materials/customMaterialDefinition.cpp | 19 ++++++- .../materials/processedCustomMaterial.cpp | 28 ++++++++- .../materials/processedShaderMaterial.cpp | 57 ++++++++++++++++++- Engine/source/shaderGen/HLSL/bumpHLSL.cpp | 3 + .../source/shaderGen/HLSL/pixSpecularHLSL.cpp | 1 + .../shaderGen/HLSL/shaderFeatureHLSL.cpp | 25 ++++++-- Engine/source/shaderGen/shaderGen.cpp | 4 +- Engine/source/shaderGen/shaderGen.h | 2 +- Engine/source/terrain/terrCellMaterial.cpp | 32 ++++++++--- Engine/source/terrain/terrCellMaterial.h | 2 + 11 files changed, 155 insertions(+), 23 deletions(-) diff --git a/Engine/source/lighting/advanced/hlsl/advancedLightingFeaturesHLSL.cpp b/Engine/source/lighting/advanced/hlsl/advancedLightingFeaturesHLSL.cpp index 9e04f3f76..661530bf3 100644 --- a/Engine/source/lighting/advanced/hlsl/advancedLightingFeaturesHLSL.cpp +++ b/Engine/source/lighting/advanced/hlsl/advancedLightingFeaturesHLSL.cpp @@ -98,7 +98,7 @@ void DeferredRTLightingFeatHLSL::processPix( Vector &component uvScene->setName( "uvScene" ); LangElement *uvSceneDecl = new DecOp( uvScene ); - String rtParamName = String::ToString( "rtParams%d", mLastTexIndex ); + String rtParamName = String::ToString( "rtParams%s", "lightInfoBuffer" ); Var *rtParams = (Var*) LangElement::find( rtParamName ); if( !rtParams ) { @@ -207,6 +207,7 @@ void DeferredRTLightingFeatHLSL::setTexData( Material::StageData &stageDat, mLastTexIndex = texIndex; passData.mTexType[ texIndex ] = Material::TexTarget; + passData.mSamplerNames[ texIndex ]= "lightInfoBuffer"; passData.mTexSlot[ texIndex++ ].texTarget = texTarget; } } @@ -402,12 +403,14 @@ void DeferredBumpFeatHLSL::setTexData( Material::StageData &stageDat, fd.features[MFT_PixSpecular] ) ) { passData.mTexType[ texIndex ] = Material::Bump; + passData.mSamplerNames[ texIndex ] = "bumpMap"; passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_NormalMap ); if ( fd.features[MFT_PrePassConditioner] && fd.features.hasFeature( MFT_DetailNormalMap ) ) { passData.mTexType[ texIndex ] = Material::DetailBump; + passData.mSamplerNames[ texIndex ] = "detailBumpMap"; passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_DetailNormalMap ); } } diff --git a/Engine/source/materials/customMaterialDefinition.cpp b/Engine/source/materials/customMaterialDefinition.cpp index c61a10a34..8e61a018f 100644 --- a/Engine/source/materials/customMaterialDefinition.cpp +++ b/Engine/source/materials/customMaterialDefinition.cpp @@ -138,9 +138,22 @@ bool CustomMaterial::onAdd() return false; } - mSamplerNames[i] = entry->slotName + dStrlen(samplerDecl); - mSamplerNames[i].insert(0, '$'); - mTexFilename[i] = entry->value; + // Assert sampler names are defined on ShaderData + S32 pos = -1; + String samplerName = entry->slotName + dStrlen(samplerDecl); + samplerName.insert(0, '$'); + mShaderData->hasSamplerDef(samplerName, pos); + + if(pos == -1) + { + const char *error = (avar("CustomMaterial(%s) bind sampler[%s] and is not present on ShaderData(%s)", + getName(), samplerName.c_str(), mShaderDataName.c_str() )); + Con::errorf(error); + GFXAssertFatal(0, error); + continue; + } + mSamplerNames[pos] = samplerName; + mTexFilename[pos] = entry->value; ++i; } } diff --git a/Engine/source/materials/processedCustomMaterial.cpp b/Engine/source/materials/processedCustomMaterial.cpp index 513ead314..c3c59d1b6 100644 --- a/Engine/source/materials/processedCustomMaterial.cpp +++ b/Engine/source/materials/processedCustomMaterial.cpp @@ -79,6 +79,7 @@ void ProcessedCustomMaterial::_setStageData() if(filename.equal(String("$dynamiclight"), String::NoCase)) { rpd->mTexType[i] = Material::DynamicLight; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; mMaxTex = i+1; continue; } @@ -86,6 +87,7 @@ void ProcessedCustomMaterial::_setStageData() if(filename.equal(String("$dynamiclightmask"), String::NoCase)) { rpd->mTexType[i] = Material::DynamicLightMask; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; mMaxTex = i+1; continue; } @@ -93,6 +95,7 @@ void ProcessedCustomMaterial::_setStageData() if(filename.equal(String("$lightmap"), String::NoCase)) { rpd->mTexType[i] = Material::Lightmap; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; mMaxTex = i+1; continue; } @@ -102,6 +105,7 @@ void ProcessedCustomMaterial::_setStageData() if( mCustomMaterial->mCubemapData ) { rpd->mTexType[i] = Material::Cube; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; mMaxTex = i+1; } else @@ -114,6 +118,7 @@ void ProcessedCustomMaterial::_setStageData() if(filename.equal(String("$dynamicCubemap"), String::NoCase)) { rpd->mTexType[i] = Material::SGCube; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; mMaxTex = i+1; continue; } @@ -121,6 +126,7 @@ void ProcessedCustomMaterial::_setStageData() if(filename.equal(String("$backbuff"), String::NoCase)) { rpd->mTexType[i] = Material::BackBuff; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; mMaxTex = i+1; continue; } @@ -128,6 +134,7 @@ void ProcessedCustomMaterial::_setStageData() if(filename.equal(String("$reflectbuff"), String::NoCase)) { rpd->mTexType[i] = Material::ReflectBuff; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; mMaxTex = i+1; continue; } @@ -135,6 +142,7 @@ void ProcessedCustomMaterial::_setStageData() if(filename.equal(String("$miscbuff"), String::NoCase)) { rpd->mTexType[i] = Material::Misc; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; mMaxTex = i+1; continue; } @@ -151,6 +159,7 @@ void ProcessedCustomMaterial::_setStageData() texTarget->getShaderMacros( &mConditionerMacros ); rpd->mTexType[i] = Material::TexTarget; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; mMaxTex = i+1; continue; } @@ -162,6 +171,7 @@ void ProcessedCustomMaterial::_setStageData() continue; } rpd->mTexType[i] = Material::Standard; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; mMaxTex = i+1; } @@ -232,6 +242,20 @@ bool ProcessedCustomMaterial::init( const FeatureSet &features, setMaterialParameters( mDefaultParameters, 0 ); mStateHint.init( this ); + for(int i = 0; i < mMaxTex; i++) + { + ShaderConstHandles *handles = _getShaderConstHandles( mPasses.size()-1 ); + AssertFatal(handles,""); + + if(rpd->mSamplerNames[i].isEmpty()) + continue; + + String samplerName = rpd->mSamplerNames[i].startsWith("$") ? rpd->mSamplerNames[i] : String("$") + rpd->mSamplerNames[i]; + GFXShaderConstHandle *handle = rpd->shader->getShaderConstHandle( samplerName ); + AssertFatal(handle,""); + handles->mTexHandlesSC[i] = handle; + } + return true; } @@ -384,14 +408,14 @@ void ProcessedCustomMaterial::setTextureStages( SceneRenderState *state, const S if ( !texObject ) texObject = GFXTexHandle::ZERO; - if ( handles->mRTParamsSC[samplerRegister]->isValid() && texObject ) + if ( handles->mRTParamsSC[i]->isValid() && texObject ) { const Point3I &targetSz = texObject->getSize(); const RectI &targetVp = texTarget->getViewport(); Point4F rtParams; ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams); - shaderConsts->set(handles->mRTParamsSC[samplerRegister], rtParams); + shaderConsts->set(handles->mRTParamsSC[i], rtParams); } GFX->setTexture( samplerRegister, texObject ); diff --git a/Engine/source/materials/processedShaderMaterial.cpp b/Engine/source/materials/processedShaderMaterial.cpp index 1b17c17ce..81094e9b2 100644 --- a/Engine/source/materials/processedShaderMaterial.cpp +++ b/Engine/source/materials/processedShaderMaterial.cpp @@ -221,6 +221,7 @@ bool ProcessedShaderMaterial::init( const FeatureSet &features, { rpd->mTexSlot[0].texTarget = texTarget; rpd->mTexType[0] = Material::TexTarget; + rpd->mSamplerNames[0] = "diffuseMap"; } } @@ -516,8 +517,23 @@ bool ProcessedShaderMaterial::_createPasses( MaterialFeatureData &stageFeatures, passData.mNumTexReg += numTexReg; passData.mFeatureData.features.addFeature( *info.type ); + +#if defined(TORQUE_DEBUG) && defined( TORQUE_OPENGL) + U32 oldTexNumber = texIndex; +#endif + info.feature->setTexData( mStages[stageNum], stageFeatures, passData, texIndex ); +#if defined(TORQUE_DEBUG) && defined( TORQUE_OPENGL) + if(oldTexNumber != texIndex) + { + for(int i = oldTexNumber; i < texIndex; i++) + { + AssertFatal(passData.mSamplerNames[ oldTexNumber ].isNotEmpty(), avar( "ERROR: ShaderGen feature %s don't set used sampler name", info.feature->getName().c_str()) ); + } + } +#endif + // Add pass if tex units are maxed out if( texIndex > GFX->getNumSamplers() ) { @@ -527,6 +543,13 @@ bool ProcessedShaderMaterial::_createPasses( MaterialFeatureData &stageFeatures, } } +#if defined(TORQUE_DEBUG) && defined( TORQUE_OPENGL) + for(int i = 0; i < texIndex; i++) + { + AssertFatal(passData.mSamplerNames[ i ].isNotEmpty(),""); + } +#endif + const FeatureSet &passFeatures = passData.mFeatureData.codify(); if ( passFeatures.isNotEmpty() ) { @@ -587,9 +610,16 @@ bool ProcessedShaderMaterial::_addPass( ShaderRenderPassData &rpd, // Copy over features rpd.mFeatureData.materialFeatures = fd.features; + Vector samplers; + samplers.setSize(Material::MAX_TEX_PER_PASS); + for(int i = 0; i < Material::MAX_TEX_PER_PASS; ++i) + { + samplers[i] = (rpd.mSamplerNames[i].isEmpty() || rpd.mSamplerNames[i][0] == '$') ? rpd.mSamplerNames[i] : "$" + rpd.mSamplerNames[i]; + } + // Generate shader GFXShader::setLogging( true, true ); - rpd.shader = SHADERGEN->getShader( rpd.mFeatureData, mVertexFormat, &mUserMacros ); + rpd.shader = SHADERGEN->getShader( rpd.mFeatureData, mVertexFormat, &mUserMacros, samplers ); if( !rpd.shader ) return false; rpd.shaderHandles.init( rpd.shader ); @@ -601,6 +631,30 @@ bool ProcessedShaderMaterial::_addPass( ShaderRenderPassData &rpd, ShaderRenderPassData *newPass = new ShaderRenderPassData( rpd ); mPasses.push_back( newPass ); + //initSamplerHandles + ShaderConstHandles *handles = _getShaderConstHandles( mPasses.size()-1 ); + AssertFatal(handles,""); + for(int i = 0; i < rpd.mNumTex; i++) + { + if(rpd.mSamplerNames[i].isEmpty()) + { + handles->mTexHandlesSC[i] = newPass->shader->getShaderConstHandle( String::EmptyString ); + handles->mRTParamsSC[i] = newPass->shader->getShaderConstHandle( String::EmptyString ); + continue; + } + + String samplerName = rpd.mSamplerNames[i]; + if( !samplerName.startsWith("$")) + samplerName.insert(0, "$"); + + GFXShaderConstHandle *handle = newPass->shader->getShaderConstHandle( samplerName ); + + handles->mTexHandlesSC[i] = handle; + handles->mRTParamsSC[i] = newPass->shader->getShaderConstHandle( String::ToString( "$rtParams%s", samplerName.c_str()+1 ) ); + + AssertFatal( handle,""); + } + // Give each active feature a chance to create specialized shader consts. for( U32 i=0; i < FEATUREMGR->getFeatureCount(); i++ ) { @@ -705,6 +759,7 @@ void ProcessedShaderMaterial::setTextureStages( SceneRenderState *state, const S PROFILE_SCOPE( ProcessedShaderMaterial_SetTextureStages ); ShaderConstHandles *handles = _getShaderConstHandles(pass); + AssertFatal(handles,""); // Set all of the textures we need to render the give pass. #ifdef TORQUE_DEBUG diff --git a/Engine/source/shaderGen/HLSL/bumpHLSL.cpp b/Engine/source/shaderGen/HLSL/bumpHLSL.cpp index 2d6dc8464..c54f9a7f3 100644 --- a/Engine/source/shaderGen/HLSL/bumpHLSL.cpp +++ b/Engine/source/shaderGen/HLSL/bumpHLSL.cpp @@ -222,12 +222,14 @@ void BumpFeatHLSL::setTexData( Material::StageData &stageDat, if ( fd.features[MFT_NormalMap] ) { passData.mTexType[ texIndex ] = Material::Bump; + passData.mSamplerNames[ texIndex ] = "bumpMap"; passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_NormalMap ); } if ( fd.features[ MFT_DetailNormalMap ] ) { passData.mTexType[ texIndex ] = Material::DetailBump; + passData.mSamplerNames[ texIndex ] = "detailBumpMap"; passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_DetailNormalMap ); } } @@ -382,6 +384,7 @@ void ParallaxFeatHLSL::setTexData( Material::StageData &stageDat, GFXTextureObject *tex = stageDat.getTex( MFT_NormalMap ); if ( tex ) { + passData.mSamplerNames[ texIndex ] = "bumpMap"; passData.mTexType[ texIndex ] = Material::Bump; passData.mTexSlot[ texIndex++ ].texObject = tex; } diff --git a/Engine/source/shaderGen/HLSL/pixSpecularHLSL.cpp b/Engine/source/shaderGen/HLSL/pixSpecularHLSL.cpp index 930e702c8..97485dbd6 100644 --- a/Engine/source/shaderGen/HLSL/pixSpecularHLSL.cpp +++ b/Engine/source/shaderGen/HLSL/pixSpecularHLSL.cpp @@ -147,6 +147,7 @@ void SpecularMapHLSL::setTexData( Material::StageData &stageDat, if ( tex ) { passData.mTexType[ texIndex ] = Material::Standard; + passData.mSamplerNames[ texIndex ] = "specularMap"; passData.mTexSlot[ texIndex++ ].texObject = tex; } } \ No newline at end of file diff --git a/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp b/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp index 586978eec..b0fb3ad0f 100644 --- a/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp +++ b/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp @@ -985,7 +985,10 @@ void DiffuseMapFeatHLSL::setTexData( Material::StageData &stageDat, { GFXTextureObject *tex = stageDat.getTex( MFT_DiffuseMap ); if ( tex ) + { + passData.mSamplerNames[ texIndex ] = "diffuseMap"; passData.mTexSlot[ texIndex++ ].texObject = tex; + } } @@ -1069,7 +1072,10 @@ void OverlayTexFeatHLSL::setTexData( Material::StageData &stageDat, { GFXTextureObject *tex = stageDat.getTex( MFT_OverlayMap ); if ( tex ) + { + passData.mSamplerNames[texIndex] = "overlayMap"; passData.mTexSlot[ texIndex++ ].texObject = tex; + } } @@ -1257,6 +1263,7 @@ void LightmapFeatHLSL::setTexData( Material::StageData &stageDat, U32 &texIndex ) { GFXTextureObject *tex = stageDat.getTex( MFT_LightMap ); + passData.mSamplerNames[ texIndex ] = "lightMap"; if ( tex ) passData.mTexSlot[ texIndex++ ].texObject = tex; else @@ -1386,6 +1393,7 @@ void TonemapFeatHLSL::setTexData( Material::StageData &stageDat, if ( tex ) { passData.mTexType[ texIndex ] = Material::ToneMapTex; + passData.mSamplerNames[ texIndex ] = "toneMap"; passData.mTexSlot[ texIndex++ ].texObject = tex; } } @@ -1576,7 +1584,10 @@ void DetailFeatHLSL::setTexData( Material::StageData &stageDat, { GFXTextureObject *tex = stageDat.getTex( MFT_DetailMap ); if ( tex ) + { + passData.mSamplerNames[texIndex] = "detailMap"; passData.mTexSlot[ texIndex++ ].texObject = tex; + } } @@ -1846,22 +1857,27 @@ void ReflectCubeFeatHLSL::setTexData( Material::StageData &stageDat, !passData.mFeatureData.features[MFT_NormalMap] ) { GFXTextureObject *tex = stageDat.getTex( MFT_DetailMap ); - if ( tex && - stageFeatures.features[MFT_DiffuseMap] ) + if ( tex && stageFeatures.features[MFT_DiffuseMap] ) + { + passData.mSamplerNames[ texIndex ] = "diffuseMap"; passData.mTexSlot[ texIndex++ ].texObject = tex; + } else { tex = stageDat.getTex( MFT_NormalMap ); - if ( tex && - stageFeatures.features[ MFT_NormalMap ] ) + if ( tex && stageFeatures.features[ MFT_NormalMap ] ) + { + passData.mSamplerNames[ texIndex ] = "bumpMap"; passData.mTexSlot[ texIndex++ ].texObject = tex; } } + } if( stageDat.getCubemap() ) { passData.mCubeMap = stageDat.getCubemap(); + passData.mSamplerNames[texIndex] = "cubeMap"; passData.mTexType[texIndex++] = Material::Cube; } else @@ -1869,6 +1885,7 @@ void ReflectCubeFeatHLSL::setTexData( Material::StageData &stageDat, if( stageFeatures.features[MFT_CubeMap] ) { // assuming here that it is a scenegraph cubemap + passData.mSamplerNames[texIndex] = "cubeMap"; passData.mTexType[texIndex++] = Material::SGCube; } } diff --git a/Engine/source/shaderGen/shaderGen.cpp b/Engine/source/shaderGen/shaderGen.cpp index 5cd18f10c..ada454296 100644 --- a/Engine/source/shaderGen/shaderGen.cpp +++ b/Engine/source/shaderGen/shaderGen.cpp @@ -443,7 +443,7 @@ void ShaderGen::_printPixShader( Stream &stream ) mPrinter->printPixelShaderCloser(stream); } -GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const GFXVertexFormat *vertexFormat, const Vector *macros ) +GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const GFXVertexFormat *vertexFormat, const Vector *macros, const Vector &samplers ) { PROFILE_SCOPE( ShaderGen_GetShader ); @@ -488,7 +488,7 @@ GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const G GFXShader *shader = GFX->createShader(); shader->mInstancingFormat.copy( mInstancingFormat ); // TODO: Move to init() below! - if ( !shader->init( vertFile, pixFile, pixVersion, shaderMacros ) ) + if ( !shader->init( vertFile, pixFile, pixVersion, shaderMacros, samplers ) ) { delete shader; return NULL; diff --git a/Engine/source/shaderGen/shaderGen.h b/Engine/source/shaderGen/shaderGen.h index dab3a29e2..016159559 100644 --- a/Engine/source/shaderGen/shaderGen.h +++ b/Engine/source/shaderGen/shaderGen.h @@ -155,7 +155,7 @@ public: Vector ¯os ); // Returns a shader that implements the features listed by dat. - GFXShader* getShader( const MaterialFeatureData &dat, const GFXVertexFormat *vertexFormat, const Vector *macros ); + GFXShader* getShader( const MaterialFeatureData &dat, const GFXVertexFormat *vertexFormat, const Vector *macros, const Vector &samplers ); // This will delete all of the procedural shaders that we have. Used to regenerate shaders when // the ShaderFeatures have changed (due to lighting system change, or new plugin) diff --git a/Engine/source/terrain/terrCellMaterial.cpp b/Engine/source/terrain/terrCellMaterial.cpp index 63f03a188..dadb6d4a8 100644 --- a/Engine/source/terrain/terrCellMaterial.cpp +++ b/Engine/source/terrain/terrCellMaterial.cpp @@ -46,6 +46,27 @@ AFTER_MODULE_INIT( MaterialManager ) Vector TerrainCellMaterial::smAllMaterials; +Vector _initSamplerNames() +{ + Vector samplerNames; + samplerNames.push_back("$baseTexMap"); + samplerNames.push_back("$layerTex"); + samplerNames.push_back("$macrolayerTex"); + samplerNames.push_back("$lightMapTex"); + samplerNames.push_back("$lightInfoBuffer"); + for(int i = 0; i < 3; ++i) + { + samplerNames.push_back(avar("$normalMap%d",i)); + samplerNames.push_back(avar("$detailMap%d",i)); + samplerNames.push_back(avar("$macroMap%d",i)); + } + + return samplerNames; +} + + +const Vector TerrainCellMaterial::mSamplerNames = _initSamplerNames(); + TerrainCellMaterial::TerrainCellMaterial() : mCurrPass( 0 ), mTerrain( NULL ), @@ -460,7 +481,7 @@ bool TerrainCellMaterial::_createPass( Vector *materials, const bool logErrors = matCount == 1; GFXShader::setLogging( logErrors, true ); - pass->shader = SHADERGEN->getShader( featureData, getGFXVertexFormat(), NULL ); + pass->shader = SHADERGEN->getShader( featureData, getGFXVertexFormat(), NULL, mSamplerNames ); } // If we got a shader then we can continue. @@ -499,14 +520,7 @@ bool TerrainCellMaterial::_createPass( Vector *materials, pass->oneOverTerrainSize = pass->shader->getShaderConstHandle( "$oneOverTerrainSize" ); pass->squareSize = pass->shader->getShaderConstHandle( "$squareSize" ); - // NOTE: We're assuming rtParams0 here as we know its the only - // render target we currently get in a terrain material and the - // DeferredRTLightingFeatHLSL will always use 0. - // - // This could change in the future and we would need to fix - // the ShaderFeature API to allow us to do this right. - // - pass->lightParamsConst = pass->shader->getShaderConstHandle( "$rtParams0" ); + pass->lightParamsConst = pass->shader->getShaderConstHandle( "$rtParamslightInfoBuffer" ); // Now prepare the basic stateblock. GFXStateBlockDesc desc; diff --git a/Engine/source/terrain/terrCellMaterial.h b/Engine/source/terrain/terrCellMaterial.h index b7acaf16e..0784bc192 100644 --- a/Engine/source/terrain/terrCellMaterial.h +++ b/Engine/source/terrain/terrCellMaterial.h @@ -144,6 +144,8 @@ protected: U32 mCurrPass; + static const Vector mSamplerNames; + GFXTexHandle mBaseMapTexture; GFXTexHandle mLayerMapTexture;