void ProcessedShaderMaterial::_initMaterialParameters() { // Cleanup anything left first. SAFE_DELETE( mDefaultParameters ); for ( U32 i = 0; i < mParameterHandles.size(); i++ ) SAFE_DELETE( mParameterHandles[i] ); // Gather the shaders as they all need to be // passed to the ShaderMaterialParameterHandles. Vector<GFXShader*> shaders; shaders.setSize( mPasses.size() ); for ( U32 i = 0; i < mPasses.size(); i++ ) shaders[i] = _getRPD(i)->shader; // Run through each shader and prepare its constants. for ( U32 i = 0; i < mPasses.size(); i++ ) { const Vector<GFXShaderConstDesc>& desc = shaders[i]->getShaderConstDesc(); Vector<GFXShaderConstDesc>::const_iterator p = desc.begin(); for ( ; p != desc.end(); p++ ) { // Add this to our list of shader constants GFXShaderConstDesc d(*p); mShaderConstDesc.push_back(d); ShaderMaterialParameterHandle* smph = new ShaderMaterialParameterHandle(d.name, shaders); mParameterHandles.push_back(smph); } } }
ShaderConstHandles* ProcessedShaderMaterial::_getShaderConstHandles(const U32 pass) { if (pass < mPasses.size()) { return &_getRPD(pass)->shaderHandles; } return NULL; }
MaterialParameters* ProcessedShaderMaterial::allocMaterialParameters() { ShaderMaterialParameters* smp = new ShaderMaterialParameters(); Vector<GFXShaderConstBufferRef> buffers( __FILE__, __LINE__ ); buffers.setSize(mPasses.size()); for (U32 i = 0; i < mPasses.size(); i++) buffers[i] = _getRPD(i)->shader->allocConstBuffer(); // smp now owns these buffers. smp->setBuffers(mShaderConstDesc, buffers); return smp; }
void ProcessedShaderMaterial::dumpMaterialInfo() { for ( U32 i = 0; i < getNumPasses(); i++ ) { const ShaderRenderPassData *passData = _getRPD( i ); if ( passData == NULL ) continue; const GFXShader *shader = passData->shader; if ( shader == NULL ) Con::printf( " [%i] [NULL shader]", i ); else Con::printf( " [%i] %s", i, shader->describeSelf().c_str() ); } }
// // Runtime / rendering // bool ProcessedShaderMaterial::setupPass( SceneRenderState *state, const SceneData &sgData, U32 pass ) { PROFILE_SCOPE( ProcessedShaderMaterial_SetupPass ); // Make sure we have the pass if(pass >= mPasses.size()) { // If we were rendering instanced data tell // the device to reset that vb stream. if ( mInstancingState ) GFX->setVertexBuffer( NULL, 1 ); return false; } _setRenderState( state, sgData, pass ); // Set shaders ShaderRenderPassData* rpd = _getRPD(pass); if( rpd->shader ) { GFX->setShader( rpd->shader ); GFX->setShaderConstBuffer(_getShaderConstBuffer(pass)); _setShaderConstants(state, sgData, pass); // If we're instancing then do the initial step to get // set the vb pointer to the const buffer. if ( mInstancingState ) stepInstance(); } else { GFX->disableShaders(); GFX->setShaderConstBuffer(NULL); } // Set our textures setTextureStages( state, sgData, pass ); _setTextureTransforms(pass); return true; }
MaterialParameterHandle* ProcessedShaderMaterial::getMaterialParameterHandle(const String& name) { // Search our list for (U32 i = 0; i < mParameterHandles.size(); i++) { if (mParameterHandles[i]->getName().equal(name)) return mParameterHandles[i]; } // If we didn't find it, we have to add it to support shader reloading. Vector<GFXShader*> shaders; shaders.setSize(mPasses.size()); for (U32 i = 0; i < mPasses.size(); i++) shaders[i] = _getRPD(i)->shader; ShaderMaterialParameterHandle* smph = new ShaderMaterialParameterHandle( name, shaders ); mParameterHandles.push_back(smph); return smph; }
void ProcessedShaderMaterial::setSceneInfo(SceneRenderState * state, const SceneData& sgData, U32 pass) { PROFILE_SCOPE( ProcessedShaderMaterial_setSceneInfo ); GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass); ShaderConstHandles* handles = _getShaderConstHandles(pass); // Set cubemap stuff here (it's convenient!) const Point3F &eyePosWorld = state->getCameraPosition(); if ( handles->mCubeEyePosSC->isValid() ) { if(_hasCubemap(pass) || mMaterial->mDynamicCubemap) { Point3F cubeEyePos = eyePosWorld - sgData.objTrans->getPosition(); shaderConsts->set(handles->mCubeEyePosSC, cubeEyePos); } } shaderConsts->setSafe(handles->mVisiblitySC, sgData.visibility); shaderConsts->setSafe(handles->mEyePosWorldSC, eyePosWorld); if ( handles->mEyePosSC->isValid() ) { MatrixF tempMat( *sgData.objTrans ); tempMat.inverse(); Point3F eyepos; tempMat.mulP( eyePosWorld, &eyepos ); shaderConsts->set(handles->mEyePosSC, eyepos); } shaderConsts->setSafe(handles->mEyeMatSC, state->getCameraTransform()); ShaderRenderPassData *rpd = _getRPD( pass ); for ( U32 i=0; i < rpd->featureShaderHandles.size(); i++ ) rpd->featureShaderHandles[i]->setConsts( state, sgData, shaderConsts ); LIGHTMGR->setLightInfo( this, mMaterial, sgData, state, pass, shaderConsts ); }
bool ProcessedCustomMaterial::setupPass( SceneRenderState *state, const SceneData& sgData, U32 pass ) { PROFILE_SCOPE( ProcessedCustomMaterial_SetupPass ); // Make sure we have a pass. if ( pass >= mPasses.size() ) return false; ShaderRenderPassData* rpd = _getRPD( pass ); U32 currState = _getRenderStateIndex( state, sgData ); GFX->setStateBlock(rpd->mRenderStates[currState]); // activate shader if ( rpd->shader ) GFX->setShader( rpd->shader ); else GFX->disableShaders(); // Set our textures setTextureStages( state, sgData, pass ); GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass); GFX->setShaderConstBuffer(shaderConsts); // Set our shader constants. _setTextureTransforms(pass); _setShaderConstants(state, sgData, pass); LightManager* lm = state ? LIGHTMGR : NULL; if (lm) lm->setLightInfo(this, NULL, sgData, state, pass, shaderConsts); shaderConsts->setSafe(rpd->shaderHandles.mAccumTimeSC, MATMGR->getTotalTime()); return true; }
void ProcessedCustomMaterial::_setStageData() { // Only do this once if ( mHasSetStageData ) return; mHasSetStageData = true; ShaderRenderPassData* rpd = _getRPD(0); mConditionerMacros.clear(); // Loop through all the possible textures, set the right flags, and load them if needed for(U32 i=0; i<CustomMaterial::MAX_TEX_PER_PASS; i++ ) { rpd->mTexType[i] = Material::NoTexture; // Set none as the default in case none of the cases below catch it. String filename = mCustomMaterial->mTexFilename[i]; if(filename.isEmpty()) continue; if(filename.equal(String("$dynamiclight"), String::NoCase)) { rpd->mTexType[i] = Material::DynamicLight; mMaxTex = i+1; continue; } if(filename.equal(String("$dynamiclightmask"), String::NoCase)) { rpd->mTexType[i] = Material::DynamicLightMask; mMaxTex = i+1; continue; } if(filename.equal(String("$lightmap"), String::NoCase)) { rpd->mTexType[i] = Material::Lightmap; mMaxTex = i+1; continue; } if(filename.equal(String("$cubemap"), String::NoCase)) { if( mCustomMaterial->mCubemapData ) { rpd->mTexType[i] = Material::Cube; mMaxTex = i+1; } else { mCustomMaterial->logError( "Could not find CubemapData - %s", mCustomMaterial->mCubemapName.c_str()); } continue; } if(filename.equal(String("$dynamicCubemap"), String::NoCase)) { rpd->mTexType[i] = Material::SGCube; mMaxTex = i+1; continue; } if(filename.equal(String("$backbuff"), String::NoCase)) { rpd->mTexType[i] = Material::BackBuff; mMaxTex = i+1; continue; } if(filename.equal(String("$reflectbuff"), String::NoCase)) { rpd->mTexType[i] = Material::ReflectBuff; mMaxTex = i+1; continue; } if(filename.equal(String("$miscbuff"), String::NoCase)) { rpd->mTexType[i] = Material::Misc; mMaxTex = i+1; continue; } // Check for a RenderTexTargetBin assignment if (filename.substr( 0, 1 ).equal("#")) { String texTargetBufferName = filename.substr(1, filename.length() - 1); NamedTexTarget *texTarget = NamedTexTarget::find( texTargetBufferName ); rpd->mTexSlot[i].texTarget = texTarget; // Get the conditioner macros. if ( texTarget ) texTarget->getShaderMacros( &mConditionerMacros ); rpd->mTexType[i] = Material::TexTarget; mMaxTex = i+1; continue; } rpd->mTexSlot[i].texObject = _createTexture( filename, &GFXDefaultStaticDiffuseProfile ); if ( !rpd->mTexSlot[i].texObject ) { mMaterial->logError("Failed to load texture %s", _getTexturePath(filename).c_str()); continue; } rpd->mTexType[i] = Material::Standard; mMaxTex = i+1; } // We only get one cubemap if( mCustomMaterial->mCubemapData ) { mCustomMaterial->mCubemapData->createMap(); rpd->mCubeMap = mMaterial->mCubemapData->mCubemap; // BTRTODO ? if ( !rpd->mCubeMap ) mMaterial->logError("Failed to load cubemap"); } // If this has a output target defined, it may be writing // to a tex target bin with a conditioner, so search for // one and add its macros. if ( mCustomMaterial->mOutputTarget.isNotEmpty() ) { NamedTexTarget *texTarget = NamedTexTarget::find( mCustomMaterial->mOutputTarget ); if ( texTarget ) texTarget->getShaderMacros( &mConditionerMacros ); } // Copy the glow state over. mHasGlow = mCustomMaterial->mGlow[0]; }
void ProcessedCustomMaterial::setTextureStages( SceneRenderState *state, const SceneData &sgData, U32 pass ) { LightManager* lm = state ? LIGHTMGR : NULL; ShaderRenderPassData* rpd = _getRPD(pass); ShaderConstHandles* handles = _getShaderConstHandles(pass); GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass); const NamedTexTarget *texTarget; GFXTextureObject *texObject; for( U32 i=0; i<mMaxTex; i++ ) { U32 currTexFlag = rpd->mTexType[i]; if ( !lm || !lm->setTextureStage(sgData, currTexFlag, i, shaderConsts, handles ) ) { GFXShaderConstHandle* handle = handles->mTexHandlesSC[i]; if ( !handle->isValid() ) continue; S32 samplerRegister = handle->getSamplerRegister(); switch( currTexFlag ) { case 0: default: break; case Material::Mask: case Material::Standard: case Material::Bump: case Material::Detail: { GFX->setTexture( samplerRegister, rpd->mTexSlot[i].texObject ); break; } case Material::Lightmap: { GFX->setTexture( samplerRegister, sgData.lightmap ); break; } case Material::Cube: { GFX->setCubeTexture( samplerRegister, rpd->mCubeMap ); break; } case Material::SGCube: { GFX->setCubeTexture( samplerRegister, sgData.cubemap ); break; } case Material::BackBuff: { GFX->setTexture( samplerRegister, sgData.backBuffTex ); //if ( sgData.reflectTex ) // GFX->setTexture( samplerRegister, sgData.reflectTex ); //else //{ // GFXTextureObject *refractTex = REFLECTMGR->getRefractTex( true ); // GFX->setTexture( samplerRegister, refractTex ); //} break; } case Material::ReflectBuff: { GFX->setTexture( samplerRegister, sgData.reflectTex ); break; } case Material::Misc: { GFX->setTexture( samplerRegister, sgData.miscTex ); break; } case Material::TexTarget: { texTarget = rpd->mTexSlot[i].texTarget; if ( !texTarget ) { GFX->setTexture( samplerRegister, NULL ); break; } texObject = texTarget->getTexture(); // If no texture is available then map the default 2x2 // black texture to it. This at least will ensure that // we get consistant behavior across GPUs and platforms. if ( !texObject ) texObject = GFXTexHandle::ZERO; if ( handles->mRTParamsSC[samplerRegister]->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); } GFX->setTexture( samplerRegister, texObject ); break; } } } } }
void ProcessedCustomMaterial::_initPassStateBlocks() { AssertFatal(mHasSetStageData, "State data must be set before initializing state block!"); ShaderRenderPassData* rpd = _getRPD(0); _initRenderStateStateBlocks( rpd ); }
// // Material init // bool ProcessedShaderMaterial::init( const FeatureSet &features, const GFXVertexFormat *vertexFormat, const MatFeaturesDelegate &featuresDelegate ) { // Load our textures _setStageData(); // Determine how many stages we use mMaxStages = getNumStages(); mVertexFormat = vertexFormat; mFeatures.clear(); mStateHint.clear(); SAFE_DELETE(mInstancingState); for( U32 i=0; i<mMaxStages; i++ ) { MaterialFeatureData fd; // Determine the features of this stage _determineFeatures( i, fd, features ); // Let the delegate poke at the features. if ( featuresDelegate ) featuresDelegate( this, i, fd, features ); // Create the passes for this stage if ( fd.features.isNotEmpty() ) if( !_createPasses( fd, i, features ) ) return false; } _initRenderPassDataStateBlocks(); _initMaterialParameters(); mDefaultParameters = allocMaterialParameters(); setMaterialParameters( mDefaultParameters, 0 ); mStateHint.init( this ); // Enable instancing if we have it. if ( mFeatures.hasFeature( MFT_UseInstancing ) ) { mInstancingState = new InstancingState(); mInstancingState->setFormat( &_getRPD( 0 )->shader->mInstancingFormat, mVertexFormat ); } // Check for a RenderTexTargetBin assignment // *IMPORTANT NOTE* // This is a temporary solution for getting diffuse mapping working with tex targets for standard materials // It should be removed once this is done properly, at that time the sAllowTextureTargetAssignment should also be removed // from Material (it is necessary for catching shadow maps/post effect this shouldn't be applied to) if (Material::sAllowTextureTargetAssignment) if (mMaterial && mMaterial->mDiffuseMapFilename[0].isNotEmpty() && mMaterial->mDiffuseMapFilename[0].substr( 0, 1 ).equal("#")) { String texTargetBufferName = mMaterial->mDiffuseMapFilename[0].substr(1, mMaterial->mDiffuseMapFilename[0].length() - 1); NamedTexTarget *texTarget = NamedTexTarget::find( texTargetBufferName ); RenderPassData* rpd = getPass(0); if (rpd) { rpd->mTexSlot[0].texTarget = texTarget; rpd->mTexType[0] = Material::TexTarget; } } return true; }