// // Copyright (c) 2008-2014 the Urho3D project. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // #include "Precompiled.h" #include "Camera.h" #include "Context.h" #include "Drawable2D.h" #include "DrawableProxy2D.h" #include "Geometry.h" #include "Log.h" #include "Material.h" #include "MaterialCache2D.h" #include "Node.h" #include "ResourceCache.h" #include "Scene.h" #include "Sprite2D.h" #include "SpriteSheet2D.h" #include "Technique.h" #include "Texture2D.h" #include "VertexBuffer.h" #include "DebugNew.h" namespace Urho3D { const float PIXEL_SIZE = 0.01f; extern const char* blendModeNames[]; Drawable2D::Drawable2D(Context* context) : Drawable(context, DRAWABLE_GEOMETRY), layer_(0), orderInLayer_(0), blendMode_(BLEND_ALPHA), verticesDirty_(true), materialUpdatePending_(false), visibility_(true) { } Drawable2D::~Drawable2D() { if (drawableProxy_) drawableProxy_->RemoveDrawable(this); } void Drawable2D::RegisterObject(Context* context) { ACCESSOR_ATTRIBUTE("Layer", GetLayer, SetLayer, int, 0, AM_DEFAULT); ACCESSOR_ATTRIBUTE("Order in Layer", GetOrderInLayer, SetOrderInLayer, int, 0, AM_DEFAULT); MIXED_ACCESSOR_ATTRIBUTE("Sprite", GetSpriteAttr, SetSpriteAttr, ResourceRef, ResourceRef(Sprite2D::GetTypeStatic()), AM_DEFAULT); ENUM_ACCESSOR_ATTRIBUTE("Blend Mode", GetBlendMode, SetBlendModeAttr, BlendMode, blendModeNames, BLEND_ALPHA, AM_DEFAULT); MIXED_ACCESSOR_ATTRIBUTE("Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT); COPY_BASE_ATTRIBUTES(Drawable); } void Drawable2D::ApplyAttributes() { if (materialUpdatePending_) { materialUpdatePending_ = false; UpdateDefaultMaterial(); } } void Drawable2D::OnSetEnabled() { if (!drawableProxy_) return; if (IsEnabledEffective()) drawableProxy_->AddDrawable(this); else drawableProxy_->RemoveDrawable(this); } void Drawable2D::SetLayer(int layer) { if (layer == layer_) return; layer_ = layer; if (drawableProxy_) drawableProxy_->MarkOrderDirty(); MarkNetworkUpdate(); } void Drawable2D::SetOrderInLayer(int orderInLayer) { if (orderInLayer == orderInLayer_) return; orderInLayer_ = orderInLayer; if (drawableProxy_) drawableProxy_->MarkOrderDirty(); MarkNetworkUpdate(); } void Drawable2D::SetSprite(Sprite2D* sprite) { if (sprite == sprite_) return; sprite_ = sprite; verticesDirty_ = true; OnMarkedDirty(node_); UpdateDefaultMaterial(); MarkNetworkUpdate(); } void Drawable2D::SetBlendMode(BlendMode blendMode) { if (blendMode == blendMode_) return; blendMode_ = blendMode; UpdateDefaultMaterial(); MarkNetworkUpdate(); } void Drawable2D::SetMaterial(Material* material) { if (material == material_) return; material_ = material; if (drawableProxy_) drawableProxy_->MarkOrderDirty(); MarkNetworkUpdate(); } Material* Drawable2D::GetMaterial() const { return material_; } Material* Drawable2D::GetUsedMaterial() const { return material_ ? material_ : defaultMaterial_; } const Vector& Drawable2D::GetVertices() { if (verticesDirty_) UpdateVertices(); return vertices_; } void Drawable2D::SetSpriteAttr(const ResourceRef& value) { // Delay applying material update materialUpdatePending_ = true; ResourceCache* cache = GetSubsystem(); if (value.type_ == Sprite2D::GetTypeStatic()) { SetSprite(cache->GetResource(value.name_)); return; } if (value.type_ == SpriteSheet2D::GetTypeStatic()) { // value.name_ include sprite speet name and sprite name. Vector names = value.name_.Split('@'); if (names.Size() != 2) return; const String& spriteSheetName = names[0]; const String& spriteName = names[1]; SpriteSheet2D* spriteSheet = cache->GetResource(spriteSheetName); if (!spriteSheet) return; SetSprite(spriteSheet->GetSprite(spriteName)); } } ResourceRef Drawable2D::GetSpriteAttr() const { SpriteSheet2D* spriteSheet = 0; if (sprite_) spriteSheet = sprite_->GetSpriteSheet(); if (!spriteSheet) return GetResourceRef(sprite_, Sprite2D::GetTypeStatic()); // Combine sprite sheet name and sprite name as resource name. return ResourceRef(spriteSheet->GetType(), spriteSheet->GetName() + "@" + sprite_->GetName()); } void Drawable2D::SetBlendModeAttr(BlendMode mode) { // Delay applying material update materialUpdatePending_ = true; SetBlendMode(mode); } void Drawable2D::SetMaterialAttr(const ResourceRef& value) { // Delay applying material update materialUpdatePending_ = true; ResourceCache* cache = GetSubsystem(); SetMaterial(cache->GetResource(value.name_)); } ResourceRef Drawable2D::GetMaterialAttr() const { return GetResourceRef(material_, Material::GetTypeStatic()); } void Drawable2D::OnNodeSet(Node* node) { Drawable::OnNodeSet(node); if (node) { Scene* scene = GetScene(); if (scene) { materialCache_ = scene->GetOrCreateComponent(); drawableProxy_ = scene->GetOrCreateComponent(); if (IsEnabledEffective()) drawableProxy_->AddDrawable(this); } } } void Drawable2D::OnMarkedDirty(Node* node) { Drawable::OnMarkedDirty(node); verticesDirty_ = true; } void Drawable2D::UpdateDefaultMaterial() { // Delay the material update if (materialUpdatePending_) return; defaultMaterial_ = materialCache_->GetMaterial(GetTexture(), blendMode_); if (drawableProxy_) drawableProxy_->MarkOrderDirty(); } }