//--------------------------------------------------------------------- bool Technique::checkHardwareSupport(bool autoManageTextureUnits, StringUtil::StrStreamType& compileErrors) { // Go through each pass, checking requirements Passes::iterator i; unsigned short passNum = 0; const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); unsigned short numTexUnits = caps->getNumTextureUnits(); for (i = mPasses.begin(); i != mPasses.end(); ++i, ++passNum) { Pass* currPass = *i; // Adjust pass index currPass->_notifyIndex(passNum); // Check for advanced blending operation support if((currPass->getSceneBlendingOperation() != SBO_ADD || currPass->getSceneBlendingOperationAlpha() != SBO_ADD) && !caps->hasCapability(RSC_ADVANCED_BLEND_OPERATIONS)) { return false; } // Check texture unit requirements size_t numTexUnitsRequested = currPass->getNumTextureUnitStates(); // Don't trust getNumTextureUnits for programmable if(!currPass->hasFragmentProgram()) { #if defined(OGRE_PRETEND_TEXTURE_UNITS) && OGRE_PRETEND_TEXTURE_UNITS > 0 if (numTexUnits > OGRE_PRETEND_TEXTURE_UNITS) numTexUnits = OGRE_PRETEND_TEXTURE_UNITS; #endif if (numTexUnitsRequested > numTexUnits) { if (!autoManageTextureUnits) { // The user disabled auto pass split compileErrors << "Pass " << passNum << ": Too many texture units for the current hardware and no splitting allowed." << std::endl; return false; } else if (currPass->hasVertexProgram()) { // Can't do this one, and can't split a programmable pass compileErrors << "Pass " << passNum << ": Too many texture units for the current hardware and " "cannot split programmable passes." << std::endl; return false; } } } if (currPass->hasVertexProgram()) { // Check vertex program version if (!currPass->getVertexProgram()->isSupported() ) { // Can't do this one compileErrors << "Pass " << passNum << ": Vertex program " << currPass->getVertexProgram()->getName() << " cannot be used - "; if (currPass->getVertexProgram()->hasCompileError()) compileErrors << "compile error."; else compileErrors << "not supported."; compileErrors << std::endl; return false; } } if (currPass->hasGeometryProgram()) { // Check geometry program version if (!currPass->getGeometryProgram()->isSupported() ) { // Can't do this one compileErrors << "Pass " << passNum << ": Geometry program " << currPass->getGeometryProgram()->getName() << " cannot be used - "; if (currPass->getGeometryProgram()->hasCompileError()) compileErrors << "compile error."; else compileErrors << "not supported."; compileErrors << std::endl; return false; } } if (currPass->hasFragmentProgram()) { // Check fragment program version if (!currPass->getFragmentProgram()->isSupported()) { // Can't do this one compileErrors << "Pass " << passNum << ": Fragment program " << currPass->getFragmentProgram()->getName() << " cannot be used - "; if (currPass->getFragmentProgram()->hasCompileError()) compileErrors << "compile error."; else compileErrors << "not supported."; compileErrors << std::endl; return false; } } else { // Check a few fixed-function options in texture layers Pass::TextureUnitStateIterator texi = currPass->getTextureUnitStateIterator(); size_t texUnit = 0; while (texi.hasMoreElements()) { TextureUnitState* tex = texi.getNext(); // Any Cube textures? NB we make the assumption that any // card capable of running fragment programs can support // cubic textures, which has to be true, surely? if (tex->is3D() && !caps->hasCapability(RSC_CUBEMAPPING)) { // Fail compileErrors << "Pass " << passNum << " Tex " << texUnit << ": Cube maps not supported by current environment." << std::endl; return false; } // Any 3D textures? NB we make the assumption that any // card capable of running fragment programs can support // 3D textures, which has to be true, surely? if (tex->getTextureType() == TEX_TYPE_3D && !caps->hasCapability(RSC_TEXTURE_3D)) { // Fail compileErrors << "Pass " << passNum << " Tex " << texUnit << ": Volume textures not supported by current environment." << std::endl; return false; } // Any Dot3 blending? if (tex->getColourBlendMode().operation == LBX_DOTPRODUCT && !caps->hasCapability(RSC_DOT3)) { // Fail compileErrors << "Pass " << passNum << " Tex " << texUnit << ": DOT3 blending not supported by current environment." << std::endl; return false; } ++texUnit; } // We're ok on operations, now we need to check # texture units if (!currPass->hasFragmentProgram()) { // Keep splitting this pass so long as units requested > gpu units while (numTexUnitsRequested > numTexUnits) { // chop this pass into many passes currPass = currPass->_split(numTexUnits); numTexUnitsRequested = currPass->getNumTextureUnitStates(); // Advance pass number ++passNum; // Reset iterator i = mPasses.begin() + passNum; // Move the new pass to the right place (will have been created // at the end, may be other passes in between) assert(mPasses.back() == currPass); std::copy_backward(i, (mPasses.end()-1), mPasses.end()); *i = currPass; // Adjust pass index currPass->_notifyIndex(passNum); } } } } // If we got this far, we're ok return true; }
//----------------------------------------------------------------------- void RenderSystem::_setTextureUnitSettings(size_t texUnit, TextureUnitState& tl) { // This method is only ever called to set a texture unit to valid details // The method _disableTextureUnit is called to turn a unit off const TexturePtr& tex = tl._getTexturePtr(); // Vertex texture binding? if (mCurrentCapabilities->hasCapability(RSC_VERTEX_TEXTURE_FETCH) && !mCurrentCapabilities->getVertexTextureUnitsShared()) { if (tl.getBindingType() == TextureUnitState::BT_VERTEX) { // Bind vertex texture _setVertexTexture(texUnit, tex); // bind nothing to fragment unit (hardware isn't shared but fragment // unit can't be using the same index _setTexture(texUnit, true, sNullTexPtr); } else { // vice versa _setVertexTexture(texUnit, sNullTexPtr); _setTexture(texUnit, true, tex); } } else { // Shared vertex / fragment textures or no vertex texture support // Bind texture (may be blank) _setTexture(texUnit, true, tex); } // Set texture coordinate set _setTextureCoordSet(texUnit, tl.getTextureCoordSet()); // Set texture layer filtering _setTextureUnitFiltering(texUnit, tl.getTextureFiltering(FT_MIN), tl.getTextureFiltering(FT_MAG), tl.getTextureFiltering(FT_MIP)); // Set texture layer filtering _setTextureLayerAnisotropy(texUnit, tl.getTextureAnisotropy()); // Set mipmap biasing _setTextureMipmapBias(texUnit, tl.getTextureMipmapBias()); // Set blend modes // Note, colour before alpha is important _setTextureBlendMode(texUnit, tl.getColourBlendMode()); _setTextureBlendMode(texUnit, tl.getAlphaBlendMode()); // Texture addressing mode const TextureUnitState::UVWAddressingMode& uvw = tl.getTextureAddressingMode(); _setTextureAddressingMode(texUnit, uvw); // Set texture border colour only if required if (uvw.u == TextureUnitState::TAM_BORDER || uvw.v == TextureUnitState::TAM_BORDER || uvw.w == TextureUnitState::TAM_BORDER) { _setTextureBorderColour(texUnit, tl.getTextureBorderColour()); } // Set texture effects TextureUnitState::EffectMap::iterator effi; // Iterate over new effects bool anyCalcs = false; for (effi = tl.mEffects.begin(); effi != tl.mEffects.end(); ++effi) { switch (effi->second.type) { case TextureUnitState::ET_ENVIRONMENT_MAP: if (effi->second.subtype == TextureUnitState::ENV_CURVED) { _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP); anyCalcs = true; } else if (effi->second.subtype == TextureUnitState::ENV_PLANAR) { _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP_PLANAR); anyCalcs = true; } else if (effi->second.subtype == TextureUnitState::ENV_REFLECTION) { _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP_REFLECTION); anyCalcs = true; } else if (effi->second.subtype == TextureUnitState::ENV_NORMAL) { _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP_NORMAL); anyCalcs = true; } break; case TextureUnitState::ET_UVSCROLL: case TextureUnitState::ET_USCROLL: case TextureUnitState::ET_VSCROLL: case TextureUnitState::ET_ROTATE: case TextureUnitState::ET_TRANSFORM: break; case TextureUnitState::ET_PROJECTIVE_TEXTURE: _setTextureCoordCalculation(texUnit, TEXCALC_PROJECTIVE_TEXTURE, effi->second.frustum); anyCalcs = true; break; } } // Ensure any previous texcoord calc settings are reset if there are now none if (!anyCalcs) { _setTextureCoordCalculation(texUnit, TEXCALC_NONE); } // Change tetxure matrix _setTextureMatrix(texUnit, tl.getTextureTransform()); }