ea::shared_ptr<Technique> Technique::Clone(const ea::string& cloneName) const { ea::shared_ptr<Technique> ret(context_->CreateObject<Technique>()); ret->SetIsDesktop(isDesktop_); ret->SetName(cloneName); // Deep copy passes for (auto i = passes_.begin(); i != passes_.end(); ++i) { Pass* srcPass = i->get(); if (!srcPass) continue; Pass* newPass = ret->CreatePass(srcPass->GetName()); newPass->SetBlendMode(srcPass->GetBlendMode()); newPass->SetDepthTestMode(srcPass->GetDepthTestMode()); newPass->SetLightingMode(srcPass->GetLightingMode()); newPass->SetDepthWrite(srcPass->GetDepthWrite()); newPass->SetAlphaToCoverage(srcPass->GetAlphaToCoverage()); newPass->SetIsDesktop(srcPass->IsDesktop()); newPass->SetVertexShader(srcPass->GetVertexShader()); newPass->SetPixelShader(srcPass->GetPixelShader()); newPass->SetVertexShaderDefines(srcPass->GetVertexShaderDefines()); newPass->SetPixelShaderDefines(srcPass->GetPixelShaderDefines()); newPass->SetVertexShaderDefineExcludes(srcPass->GetVertexShaderDefineExcludes()); newPass->SetPixelShaderDefineExcludes(srcPass->GetPixelShaderDefineExcludes()); } return ret; }
ea::shared_ptr<Technique> Technique::CloneWithDefines(const ea::string& vsDefines, const ea::string& psDefines) { // Return self if no actual defines if (vsDefines.empty() && psDefines.empty()) return ea::shared_ptr<Technique>(this); ea::pair<StringHash, StringHash> key = ea::make_pair(StringHash(vsDefines), StringHash(psDefines)); // Return existing if possible auto i = cloneTechniques_.find(key); if (i != cloneTechniques_.end()) return i->second; // Set same name as the original for the clones to ensure proper serialization of the material. This should not be a problem // since the clones are never stored to the resource cache i = cloneTechniques_.insert(ea::make_pair(key, Clone(GetName()))).first; for (auto j = i->second->passes_.begin(); j != i->second->passes_.end(); ++j) { Pass* pass = (*j); if (!pass) continue; if (!vsDefines.empty()) pass->SetVertexShaderDefines(pass->GetVertexShaderDefines() + " " + vsDefines); if (!psDefines.empty()) pass->SetPixelShaderDefines(pass->GetPixelShaderDefines() + " " + psDefines); } return i->second; }
SharedPtr<Technique> Technique::CloneWithDefines(const String& vsDefines, const String& psDefines) { // Return self if no actual defines if (vsDefines.Empty() && psDefines.Empty()) return SharedPtr<Technique>(this); Pair<StringHash, StringHash> key = MakePair(StringHash(vsDefines), StringHash(psDefines)); // Return existing if possible HashMap<Pair<StringHash, StringHash>, SharedPtr<Technique> >::Iterator i = cloneTechniques_.Find(key); if (i != cloneTechniques_.End()) return i->second_; // Set same name as the original for the clones to ensure proper serialization of the material. This should not be a problem // since the clones are never stored to the resource cache i = cloneTechniques_.Insert(MakePair(key, Clone(GetName()))); for (Vector<SharedPtr<Pass> >::ConstIterator j = i->second_->passes_.Begin(); j != i->second_->passes_.End(); ++j) { Pass* pass = (*j); if (!pass) continue; if (!vsDefines.Empty()) pass->SetVertexShaderDefines(pass->GetVertexShaderDefines() + " " + vsDefines); if (!psDefines.Empty()) pass->SetPixelShaderDefines(pass->GetPixelShaderDefines() + " " + psDefines); } return i->second_; }
SharedPtr<Technique> Technique::Clone(const String& cloneName) const { SharedPtr<Technique> ret(new Technique(context_)); ret->SetIsDesktop(isDesktop_); ret->SetName(cloneName); // Deep copy passes for (Vector<SharedPtr<Pass> >::ConstIterator i = passes_.Begin(); i != passes_.End(); ++i) { Pass* srcPass = i->Get(); if (!srcPass) continue; Pass* newPass = ret->CreatePass(srcPass->GetName()); newPass->SetBlendMode(srcPass->GetBlendMode()); newPass->SetDepthTestMode(srcPass->GetDepthTestMode()); newPass->SetLightingMode(srcPass->GetLightingMode()); newPass->SetDepthWrite(srcPass->GetDepthWrite()); newPass->SetAlphaToCoverage(srcPass->GetAlphaToCoverage()); newPass->SetIsDesktop(srcPass->IsDesktop()); newPass->SetVertexShader(srcPass->GetVertexShader()); newPass->SetPixelShader(srcPass->GetPixelShader()); newPass->SetVertexShaderDefines(srcPass->GetVertexShaderDefines()); newPass->SetPixelShaderDefines(srcPass->GetPixelShaderDefines()); newPass->SetVertexShaderDefineExcludes(srcPass->GetVertexShaderDefineExcludes()); newPass->SetPixelShaderDefineExcludes(srcPass->GetPixelShaderDefineExcludes()); } return ret; }
Material* MaterialCache2D::CreateMaterial(Texture2D* texture, BlendMode blendMode) { Material* material = new Material(context_); if (texture) material->SetName(texture->GetName() + "_" + blendModeNames[blendMode]); else material->SetName(blendModeNames[blendMode]); Technique* tech = new Technique(context_); Pass* pass = tech->CreatePass(PASS_ALPHA); pass->SetBlendMode(blendMode); pass->SetVertexShader("Basic"); pass->SetVertexShaderDefines("DIFFMAP VERTEXCOLOR"); pass->SetPixelShader("Basic"); pass->SetPixelShaderDefines("DIFFMAP VERTEXCOLOR"); pass->SetDepthWrite(false); material->SetTechnique(0, tech); material->SetCullMode(CULL_NONE); material->SetTexture(TU_DIFFUSE, texture); return material; }
void Drawable2D::CreateDefaultMaterial() { SharedPtr<Material> material(new Material(context_)); Technique* tech = new Technique(context_); Pass* pass = tech->CreatePass(PASS_ALPHA); pass->SetVertexShader("Basic"); pass->SetVertexShaderDefines("DIFFMAP VERTEXCOLOR"); pass->SetPixelShader("Basic"); pass->SetPixelShaderDefines("DIFFMAP VERTEXCOLOR"); pass->SetDepthWrite(false); material->SetTechnique(0, tech); material->SetCullMode(CULL_NONE); batches_[0].material_ = material; }
void Text3D::UpdateTextMaterials(bool forceUpdate) { batches_.Resize(uiBatches_.Size()); geometries_.Resize(uiBatches_.Size()); for (unsigned i = 0; i < batches_.Size(); ++i) { if (!geometries_[i]) { Geometry* geometry = new Geometry(context_); geometry->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1); batches_[i].geometry_ = geometries_[i] = geometry; } if (!batches_[i].material_ || forceUpdate) { // If material not defined, create a reasonable default from scratch if (!material_) { Material* material = new Material(context_); Technique* tech = new Technique(context_); Pass* pass = tech->CreatePass(PASS_ALPHA); pass->SetVertexShader("Basic"); pass->SetVertexShaderDefines("DIFFMAP VERTEXCOLOR"); pass->SetPixelShader("Basic"); pass->SetPixelShaderDefines("ALPHAMAP VERTEXCOLOR"); pass->SetBlendMode(BLEND_ALPHA); pass->SetDepthWrite(false); material->SetTechnique(0, tech); material->SetCullMode(CULL_NONE); batches_[i].material_ = material; } else batches_[i].material_ = material_->Clone(); } Material* material = batches_[i].material_; material->SetTexture(TU_DIFFUSE, uiBatches_[i].texture_); } }
bool Technique::BeginLoad(Deserializer& source) { passes_.Clear(); SetMemoryUse(sizeof(Technique)); SharedPtr<XMLFile> xml(new XMLFile(context_)); if (!xml->Load(source)) return false; XMLElement rootElem = xml->GetRoot(); if (rootElem.HasAttribute("sm3")) isSM3_ = rootElem.GetBool("sm3"); String globalVS = rootElem.GetAttribute("vs"); String globalPS = rootElem.GetAttribute("ps"); String globalVSDefines = rootElem.GetAttribute("vsdefines"); String globalPSDefines = rootElem.GetAttribute("psdefines"); // End with space so that the pass-specific defines can be appended if (!globalVSDefines.Empty()) globalVSDefines += ' '; if (!globalPSDefines.Empty()) globalPSDefines += ' '; bool globalAlphaMask = false; if (rootElem.HasAttribute("alphamask")) globalAlphaMask = rootElem.GetBool("alphamask"); unsigned numPasses = 0; XMLElement passElem = rootElem.GetChild("pass"); while (passElem) { if (passElem.HasAttribute("name")) { StringHash nameHash(passElem.GetAttribute("name")); Pass* newPass = CreatePass(nameHash); ++numPasses; if (passElem.HasAttribute("sm3")) newPass->SetIsSM3(passElem.GetBool("sm3")); // Append global defines only when pass does not redefine the shader if (passElem.HasAttribute("vs")) { newPass->SetVertexShader(passElem.GetAttribute("vs")); newPass->SetVertexShaderDefines(passElem.GetAttribute("vsdefines")); } else { newPass->SetVertexShader(globalVS); newPass->SetVertexShaderDefines(globalVSDefines + passElem.GetAttribute("vsdefines")); } if (passElem.HasAttribute("ps")) { newPass->SetPixelShader(passElem.GetAttribute("ps")); newPass->SetPixelShaderDefines(passElem.GetAttribute("psdefines")); } else { newPass->SetPixelShader(globalPS); newPass->SetPixelShaderDefines(globalPSDefines + passElem.GetAttribute("psdefines")); } if (passElem.HasAttribute("lighting")) { String lighting = passElem.GetAttributeLower("lighting"); newPass->SetLightingMode((PassLightingMode)GetStringListIndex(lighting.CString(), lightingModeNames, LIGHTING_UNLIT)); } if (passElem.HasAttribute("blend")) { String blend = passElem.GetAttributeLower("blend"); newPass->SetBlendMode((BlendMode)GetStringListIndex(blend.CString(), blendModeNames, BLEND_REPLACE)); } if (passElem.HasAttribute("depthtest")) { String depthTest = passElem.GetAttributeLower("depthtest"); if (depthTest == "false") newPass->SetDepthTestMode(CMP_ALWAYS); else newPass->SetDepthTestMode((CompareMode)GetStringListIndex(depthTest.CString(), compareModeNames, CMP_LESS)); } if (passElem.HasAttribute("depthwrite")) newPass->SetDepthWrite(passElem.GetBool("depthwrite")); if (passElem.HasAttribute("alphamask")) newPass->SetAlphaMask(passElem.GetBool("alphamask")); else newPass->SetAlphaMask(globalAlphaMask); } else LOGERROR("Missing pass name"); passElem = passElem.GetNext("pass"); } // Calculate memory use now SetMemoryUse(sizeof(Technique) + numPasses * sizeof(Pass)); return true; }
bool Technique::BeginLoad(Deserializer& source) { passes_.clear(); cloneTechniques_.clear(); SetMemoryUse(sizeof(Technique)); ea::shared_ptr<XMLFile> xml(context_->CreateObject<XMLFile>()); if (!xml->Load(source)) return false; XMLElement rootElem = xml->GetRoot(); if (rootElem.HasAttribute("desktop")) isDesktop_ = rootElem.GetBool("desktop"); ea::string globalVS = rootElem.GetAttribute("vs"); ea::string globalPS = rootElem.GetAttribute("ps"); ea::string globalVSDefines = rootElem.GetAttribute("vsdefines"); ea::string globalPSDefines = rootElem.GetAttribute("psdefines"); // End with space so that the pass-specific defines can be appended if (!globalVSDefines.empty()) globalVSDefines += ' '; if (!globalPSDefines.empty()) globalPSDefines += ' '; XMLElement passElem = rootElem.GetChild("pass"); while (passElem) { if (passElem.HasAttribute("name")) { Pass* newPass = CreatePass(passElem.GetAttribute("name")); if (passElem.HasAttribute("desktop")) newPass->SetIsDesktop(passElem.GetBool("desktop")); // Append global defines only when pass does not redefine the shader if (passElem.HasAttribute("vs")) { newPass->SetVertexShader(passElem.GetAttribute("vs")); newPass->SetVertexShaderDefines(passElem.GetAttribute("vsdefines")); } else { newPass->SetVertexShader(globalVS); newPass->SetVertexShaderDefines(globalVSDefines + passElem.GetAttribute("vsdefines")); } if (passElem.HasAttribute("ps")) { newPass->SetPixelShader(passElem.GetAttribute("ps")); newPass->SetPixelShaderDefines(passElem.GetAttribute("psdefines")); } else { newPass->SetPixelShader(globalPS); newPass->SetPixelShaderDefines(globalPSDefines + passElem.GetAttribute("psdefines")); } newPass->SetVertexShaderDefineExcludes(passElem.GetAttribute("vsexcludes")); newPass->SetPixelShaderDefineExcludes(passElem.GetAttribute("psexcludes")); if (passElem.HasAttribute("lighting")) { ea::string lighting = passElem.GetAttributeLower("lighting"); newPass->SetLightingMode((PassLightingMode)GetStringListIndex(lighting.c_str(), lightingModeNames, LIGHTING_UNLIT)); } if (passElem.HasAttribute("blend")) { ea::string blend = passElem.GetAttributeLower("blend"); newPass->SetBlendMode((BlendMode)GetStringListIndex(blend.c_str(), blendModeNames, BLEND_REPLACE)); } if (passElem.HasAttribute("cull")) { ea::string cull = passElem.GetAttributeLower("cull"); newPass->SetCullMode((CullMode)GetStringListIndex(cull.c_str(), cullModeNames, MAX_CULLMODES)); } if (passElem.HasAttribute("depthtest")) { ea::string depthTest = passElem.GetAttributeLower("depthtest"); if (depthTest == "false") newPass->SetDepthTestMode(CMP_ALWAYS); else newPass->SetDepthTestMode((CompareMode)GetStringListIndex(depthTest.c_str(), compareModeNames, CMP_LESS)); } if (passElem.HasAttribute("depthwrite")) newPass->SetDepthWrite(passElem.GetBool("depthwrite")); if (passElem.HasAttribute("alphatocoverage")) newPass->SetAlphaToCoverage(passElem.GetBool("alphatocoverage")); } else URHO3D_LOGERROR("Missing pass name"); passElem = passElem.GetNext("pass"); } return true; }
void Text3D::UpdateTextMaterials(bool forceUpdate) { batches_.Resize(uiBatches_.Size()); geometries_.Resize(uiBatches_.Size()); for (unsigned i = 0; i < batches_.Size(); ++i) { if (!geometries_[i]) { Geometry* geometry = new Geometry(context_); geometry->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1); batches_[i].geometry_ = geometries_[i] = geometry; } if (!batches_[i].material_ || forceUpdate) { // If material not defined, create a reasonable default from scratch if (!material_) { Material* material = new Material(context_); Technique* tech = new Technique(context_); Pass* pass = tech->CreatePass(PASS_ALPHA); pass->SetVertexShader("Text"); pass->SetPixelShader("Text"); if (GetFont()->IsSDFFont()) { switch (GetTextEffect()) { case TE_NONE: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD"); break; case TE_SHADOW: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD TEXT_EFFECT_SHADOW"); break; case TE_STROKE: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD TEXT_EFFECT_STROKE"); break; } } pass->SetBlendMode(BLEND_ALPHA); pass->SetDepthWrite(false); material->SetTechnique(0, tech); material->SetCullMode(CULL_NONE); batches_[i].material_ = material; } else batches_[i].material_ = material_->Clone(); } Material* material = batches_[i].material_; Texture* texture = uiBatches_[i].texture_; material->SetTexture(TU_DIFFUSE, texture); if (GetFont()->IsSDFFont()) { switch (GetTextEffect()) { case TE_SHADOW: if (texture) { Vector2 shadowOffset(0.5f / texture->GetWidth(), 0.5f / texture->GetHeight()); material->SetShaderParameter("ShadowOffset", shadowOffset); } material->SetShaderParameter("ShadowColor", GetEffectColor()); break; case TE_STROKE: material->SetShaderParameter("StrokeColor", GetEffectColor()); break; default: break; } } } }
void Text3D::UpdateTextMaterials(bool forceUpdate) { Font* font = GetFont(); bool isSDFFont = font ? font->IsSDFFont() : false; batches_.Resize(uiBatches_.Size()); geometries_.Resize(uiBatches_.Size()); for (unsigned i = 0; i < batches_.Size(); ++i) { if (!geometries_[i]) { Geometry* geometry = new Geometry(context_); geometry->SetVertexBuffer(0, vertexBuffer_); batches_[i].geometry_ = geometries_[i] = geometry; } if (!batches_[i].material_ || forceUpdate || isSDFFont != usingSDFShader_) { // If material not defined, create a reasonable default from scratch if (!material_) { Material* material = new Material(context_); Technique* tech = new Technique(context_); Pass* pass = tech->CreatePass("alpha"); pass->SetVertexShader("Text"); pass->SetPixelShader("Text"); if (isSDFFont) { switch (GetTextEffect()) { case TE_NONE: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD"); break; case TE_SHADOW: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD TEXT_EFFECT_SHADOW"); break; case TE_STROKE: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD TEXT_EFFECT_STROKE"); break; } } pass->SetBlendMode(BLEND_ALPHA); pass->SetDepthWrite(false); material->SetTechnique(0, tech); material->SetCullMode(CULL_NONE); batches_[i].material_ = material; } else batches_[i].material_ = material_->Clone(); // Note: custom material is assumed to use the right kind of shader; it is not modified to define SIGNED_DISTANCE_FIELD usingSDFShader_ = isSDFFont; } Material* material = batches_[i].material_; Texture* texture = uiBatches_[i].texture_; material->SetTexture(TU_DIFFUSE, texture); if (isSDFFont) { switch (GetTextEffect()) { case TE_SHADOW: if (texture) { Vector2 shadowOffset(0.5f / texture->GetWidth(), 0.5f / texture->GetHeight()); material->SetShaderParameter("ShadowOffset", shadowOffset); } material->SetShaderParameter("ShadowColor", GetEffectColor()); break; case TE_STROKE: material->SetShaderParameter("StrokeColor", GetEffectColor()); break; default: break; } } } }