ShaderVariation* Shader::GetVariation(ShaderType type, const char* defines) { StringHash definesHash(defines); if (type == VS) { HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator i = vsVariations_.Find(definesHash); if (i == vsVariations_.End()) { // If shader not found, normalize the defines (to prevent duplicates) and check again. In that case make an alias // so that further queries are faster String normalizedDefines = NormalizeDefines(defines); StringHash normalizedHash(normalizedDefines); i = vsVariations_.Find(normalizedHash); if (i != vsVariations_.End()) vsVariations_.Insert(MakePair(definesHash, i->second_)); else { // No shader variation found. Create new i = vsVariations_.Insert(MakePair(normalizedHash, SharedPtr<ShaderVariation>(new ShaderVariation(this, VS)))); if (definesHash != normalizedHash) vsVariations_.Insert(MakePair(definesHash, i->second_)); i->second_->SetName(GetFileName(GetName())); i->second_->SetDefines(normalizedDefines); ++numVariations_; RefreshMemoryUse(); } } return i->second_; } else { HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator i = psVariations_.Find(definesHash); if (i == psVariations_.End()) { String normalizedDefines = NormalizeDefines(defines); StringHash normalizedHash(normalizedDefines); i = psVariations_.Find(normalizedHash); if (i != psVariations_.End()) psVariations_.Insert(MakePair(definesHash, i->second_)); else { i = psVariations_.Insert(MakePair(normalizedHash, SharedPtr<ShaderVariation>(new ShaderVariation(this, PS)))); if (definesHash != normalizedHash) psVariations_.Insert(MakePair(definesHash, i->second_)); i->second_->SetName(GetFileName(GetName())); i->second_->SetDefines(normalizedDefines); ++numVariations_; RefreshMemoryUse(); } } return i->second_; } }
bool Shader::BeginLoad(Deserializer& source) { Graphics* graphics = GetSubsystem<Graphics>(); if (!graphics) return false; // Load the shader source code and resolve any includes timeStamp_ = 0; String shaderCode; if (!ProcessSource(shaderCode, source)) return false; // Comment out the unneeded shader function vsSourceCode_ = shaderCode; psSourceCode_ = shaderCode; CommentOutFunction(vsSourceCode_, "void PS("); CommentOutFunction(psSourceCode_, "void VS("); // OpenGL: rename either VS() or PS() to main(), comment out vertex attributes in pixel shaders #ifdef URHO3D_OPENGL vsSourceCode_.Replace("void VS(", "void main("); psSourceCode_.Replace("void PS(", "void main("); psSourceCode_.Replace("attribute ", "// attribute "); #endif RefreshMemoryUse(); return true; }
void Material::ResetToDefaults() { // Needs to be a no-op when async loading, as this does a GetResource() which is not allowed from worker threads if (!Thread::IsMainThread()) return; SetNumTechniques(1); SetTechnique(0, GetSubsystem<ResourceCache>()->GetResource<Technique>("Techniques/NoTexture.xml")); textures_.Clear(); batchedParameterUpdate_ = true; shaderParameters_.Clear(); SetShaderParameter("UOffset", Vector4(1.0f, 0.0f, 0.0f, 0.0f)); SetShaderParameter("VOffset", Vector4(0.0f, 1.0f, 0.0f, 0.0f)); SetShaderParameter("MatDiffColor", Vector4::ONE); SetShaderParameter("MatEmissiveColor", Vector3::ZERO); SetShaderParameter("MatEnvMapColor", Vector3::ONE); SetShaderParameter("MatSpecColor", Vector4(0.0f, 0.0f, 0.0f, 1.0f)); batchedParameterUpdate_ = false; cullMode_ = CULL_CCW; shadowCullMode_ = CULL_CCW; fillMode_ = FILL_SOLID; depthBias_ = BiasParameters(0.0f, 0.0f); RefreshShaderParameterHash(); RefreshMemoryUse(); }
void Material::SetShaderParameter(const String& name, const Variant& value) { MaterialShaderParameter newParam; newParam.name_ = name; newParam.value_ = value; StringHash nameHash(name); shaderParameters_[nameHash] = newParam; if (nameHash == PSP_MATSPECCOLOR) { VariantType type = value.GetType(); if (type == VAR_VECTOR3) { const Vector3& vec = value.GetVector3(); specular_ = vec.x_ > 0.0f || vec.y_ > 0.0f || vec.z_ > 0.0f; } else if (type == VAR_VECTOR4) { const Vector4& vec = value.GetVector4(); specular_ = vec.x_ > 0.0f || vec.y_ > 0.0f || vec.z_ > 0.0f; } } if (!batchedParameterUpdate_) { RefreshShaderParameterHash(); RefreshMemoryUse(); } }
void Material::SetNumTechniques(unsigned num) { if (!num) return; techniques_.Resize(num); RefreshMemoryUse(); }
void Material::RemoveShaderParameter(const String& name) { StringHash nameHash(name); shaderParameters_.Erase(nameHash); if (nameHash == PSP_MATSPECCOLOR) specular_ = false; RefreshShaderParameterHash(); RefreshMemoryUse(); }
bool Shader::Load(Deserializer& source) { PROFILE(LoadShader); Graphics* graphics = GetSubsystem<Graphics>(); if (!graphics) return false; // Load the shader source code and resolve any includes timeStamp_ = 0; String shaderCode; if (!ProcessSource(shaderCode, source)) return false; // Comment out the unneeded shader function vsSourceCode_ = shaderCode; psSourceCode_ = shaderCode; CommentOutFunction(vsSourceCode_, "void PS("); CommentOutFunction(psSourceCode_, "void VS("); // OpenGL: rename either VS() or PS() to main(), comment out vertex attributes in pixel shaders #ifdef USE_OPENGL vsSourceCode_.Replace("void VS(", "void main("); psSourceCode_.Replace("void PS(", "void main("); psSourceCode_.Replace("attribute ", "// attribute "); #endif // If variations had already been created, release them and require recompile for (HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator i = vsVariations_.Begin(); i != vsVariations_.End(); ++i) i->second_->Release(); for (HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator i = psVariations_.Begin(); i != psVariations_.End(); ++i) i->second_->Release(); RefreshMemoryUse(); return true; }
Shader::Shader(Context* context) : Resource(context), timeStamp_(0) { RefreshMemoryUse(); }
bool Material::Load(const XMLElement& source) { ResetToDefaults(); if (source.IsNull()) { LOGERROR("Can not load material from null XML element"); return false; } ResourceCache* cache = GetSubsystem<ResourceCache>(); XMLElement techniqueElem = source.GetChild("technique"); techniques_.Clear(); while (techniqueElem) { Technique* tech = cache->GetResource<Technique>(techniqueElem.GetAttribute("name")); if (tech) { TechniqueEntry newTechnique; newTechnique.technique_ = tech; if (techniqueElem.HasAttribute("quality")) newTechnique.qualityLevel_ = techniqueElem.GetInt("quality"); if (techniqueElem.HasAttribute("loddistance")) newTechnique.lodDistance_ = techniqueElem.GetFloat("loddistance"); techniques_.Push(newTechnique); } techniqueElem = techniqueElem.GetNext("technique"); } SortTechniques(); XMLElement textureElem = source.GetChild("texture"); while (textureElem) { TextureUnit unit = TU_DIFFUSE; if (textureElem.HasAttribute("unit")) unit = ParseTextureUnitName(textureElem.GetAttribute("unit")); if (unit < MAX_TEXTURE_UNITS) { String name = textureElem.GetAttribute("name"); // Detect cube maps by file extension: they are defined by an XML file /// \todo Differentiate with 3D textures by actually reading the XML content if (GetExtension(name) == ".xml") { #ifdef DESKTOP_GRAPHICS if (unit == TU_VOLUMEMAP) SetTexture(unit, cache->GetResource<Texture3D>(name)); else #endif SetTexture(unit, cache->GetResource<TextureCube>(name)); } else SetTexture(unit, cache->GetResource<Texture2D>(name)); } textureElem = textureElem.GetNext("texture"); } batchedParameterUpdate_ = true; XMLElement parameterElem = source.GetChild("parameter"); while (parameterElem) { String name = parameterElem.GetAttribute("name"); SetShaderParameter(name, ParseShaderParameterValue(parameterElem.GetAttribute("value"))); parameterElem = parameterElem.GetNext("parameter"); } batchedParameterUpdate_ = false; XMLElement parameterAnimationElem = source.GetChild("parameteranimation"); while (parameterAnimationElem) { String name = parameterAnimationElem.GetAttribute("name"); SharedPtr<ValueAnimation> animation(new ValueAnimation(context_)); if (!animation->LoadXML(parameterAnimationElem)) { LOGERROR("Could not load parameter animation"); return false; } String wrapModeString = parameterAnimationElem.GetAttribute("wrapmode"); WrapMode wrapMode = WM_LOOP; for (int i = 0; i <= WM_CLAMP; ++i) { if (wrapModeString == wrapModeNames[i]) { wrapMode = (WrapMode)i; break; } } float speed = parameterAnimationElem.GetFloat("speed"); SetShaderParameterAnimation(name, animation, wrapMode, speed); parameterAnimationElem = parameterAnimationElem.GetNext("parameteranimation"); } XMLElement cullElem = source.GetChild("cull"); if (cullElem) SetCullMode((CullMode)GetStringListIndex(cullElem.GetAttribute("value").CString(), cullModeNames, CULL_CCW)); XMLElement shadowCullElem = source.GetChild("shadowcull"); if (shadowCullElem) SetShadowCullMode((CullMode)GetStringListIndex(shadowCullElem.GetAttribute("value").CString(), cullModeNames, CULL_CCW)); XMLElement fillElem = source.GetChild("fill"); if (fillElem) SetFillMode((FillMode)GetStringListIndex(fillElem.GetAttribute("value").CString(), fillModeNames, FILL_SOLID)); XMLElement depthBiasElem = source.GetChild("depthbias"); if (depthBiasElem) SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled"))); RefreshShaderParameterHash(); RefreshMemoryUse(); CheckOcclusion(); return true; }