Browse Source

Convert MaterialCache2D to a component. [ci skip]

aster2013 11 years ago
parent
commit
43147fbe1d

+ 0 - 6
Source/Engine/Engine/Engine.cpp

@@ -32,7 +32,6 @@
 #include "Input.h"
 #include "InputEvents.h"
 #include "Log.h"
-#include "MaterialCache2D.h"
 #include "NavigationMesh.h"
 #include "Network.h"
 #include "PackageFile.h"
@@ -149,7 +148,6 @@ bool Engine::Initialize(const VariantMap& parameters)
     }
 
     // 2D graphics library is dependent on 3D graphics library
-    context_->RegisterSubsystem(new MaterialCache2D(context_));
     RegisterUrho2DLibrary(context_);
 
     // Start logging
@@ -761,10 +759,6 @@ void Engine::HandleExitRequested(StringHash eventType, VariantMap& eventData)
 
 void Engine::DoExit()
 {
-    MaterialCache2D* materialCache = GetSubsystem<MaterialCache2D>();
-    if (materialCache)
-        materialCache->ReleaseAllMaterials();
-
     Graphics* graphics = GetSubsystem<Graphics>();
     if (graphics)
         graphics->Close();

+ 17 - 2
Source/Engine/Urho2D/Drawable2D.cpp

@@ -274,6 +274,22 @@ ResourceRef Drawable2D::GetMaterialAttr() const
     return GetResourceRef(material_, Material::GetTypeStatic());
 }
 
+void Drawable2D::OnNodeSet(Node* node)
+{
+    Drawable::OnNodeSet(node);
+
+    if (node)
+    {
+        node->AddListener(this);
+
+        Scene* scene = GetScene();
+        if (scene)
+        {
+            materialCache_ = scene->GetOrCreateComponent<MaterialCache2D>();
+        }
+    }
+}
+
 void Drawable2D::OnWorldBoundingBoxUpdate()
 {
     if (verticesDirty_)
@@ -298,8 +314,7 @@ void Drawable2D::UpdateMaterial()
         batches_[0].material_ = material_;
     else
     {
-        MaterialCache2D* materialCache = GetSubsystem<MaterialCache2D>();
-        defaultMaterial_ = materialCache->GetMaterial(GetTexture(), blendMode_);
+        defaultMaterial_ = materialCache_->GetMaterial(GetTexture(), blendMode_);
         batches_[0].material_ = defaultMaterial_;
     }
 }

+ 9 - 0
Source/Engine/Urho2D/Drawable2D.h

@@ -28,6 +28,8 @@
 namespace Urho3D
 {
 
+class DrawableProxy2D;
+class MaterialCache2D;
 class VertexBuffer;
 
 /// Pixel size (equal 0.01f).
@@ -98,6 +100,8 @@ public:
     ResourceRef GetMaterialAttr() const;
 
 protected:
+    /// Handle node being assigned.
+    virtual void OnNodeSet(Node* node);
     /// Recalculate the world-space bounding box.
     virtual void OnWorldBoundingBoxUpdate();
     /// Update vertices.
@@ -128,7 +132,12 @@ protected:
     bool geometryDirty_;
     /// Material update pending flag.
     bool materialUpdatePending_;
+    /// Default material.
     SharedPtr<Material> defaultMaterial_;
+    /// Material cache.
+    WeakPtr<MaterialCache2D> materialCache_;
+    /// Drawable proxy.
+    WeakPtr<DrawableProxy2D> drawableProxy_;
 };
 
 inline bool CompareDrawable2Ds(Drawable2D* lhs, Drawable2D* rhs)

+ 193 - 0
Source/Engine/Urho2D/DrawableProxy2D.cpp

@@ -0,0 +1,193 @@
+//
+// 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 "Node.h"
+#include "VertexBuffer.h"
+#include "Sort.h"
+
+#include "DebugNew.h"
+
+namespace Urho3D
+{
+
+DrawableProxy2D::DrawableProxy2D(Context* context) :
+    Drawable(context, DRAWABLE_GEOMETRY),
+    vertexBuffer_(new VertexBuffer(context_)),
+    orderDirty_(true)
+{
+}
+
+DrawableProxy2D::~DrawableProxy2D()
+{
+}
+
+void DrawableProxy2D::RegisterObject(Context* context)
+{
+    context->RegisterFactory<DrawableProxy2D>();
+}
+
+void DrawableProxy2D::UpdateBatches(const FrameInfo& frame)
+{
+    unsigned count = materials_.Size();
+    batches_.Resize(count);
+
+    for (unsigned i = 0; i < count; ++i)
+    {
+        batches_[i].distance_ = 10.0f + (count - i) * 0.001f;
+        batches_[i].material_ = materials_[i];
+        batches_[i].geometry_ = geometries_[i];
+        batches_[i].worldTransform_ = &Matrix3x4::IDENTITY;
+    }
+}
+
+void DrawableProxy2D::UpdateGeometry(const FrameInfo& frame)
+{
+    materials_.Clear();
+
+    if (orderDirty_)
+    {
+        Sort(drawables_.Begin(), drawables_.End(), CompareDrawable2Ds);
+        orderDirty_ = false;
+    }
+
+    float timeStep = frame.timeStep_;
+
+    unsigned vertexCount = 0;
+    for (unsigned i = 0; i < drawables_.Size(); ++i)
+        vertexCount += drawables_[i]->GetVertices().Size();
+
+    if (vertexCount == 0)
+        return;
+
+    vertexCount = vertexCount / 4 * 6;
+
+    vertexBuffer_->SetSize(vertexCount, MASK_VERTEX2D);
+    Vertex2D* dest = reinterpret_cast<Vertex2D*>(vertexBuffer_->Lock(0, vertexCount, true));
+    if (dest)
+    {
+        unsigned start = 0;
+        unsigned count = 0;
+        Material* material = 0;
+
+        for (unsigned d = 0; d < drawables_.Size(); ++d)
+        {
+            Material* currMaterial = drawables_[d]->GetUsedMaterial();
+            if (material != currMaterial)
+            {
+                if (material)
+                {
+                    AddBatch(material, start, count);
+                    start += count;
+                    count = 0;
+                }
+
+                material = currMaterial;
+            }
+
+            const Vector<Vertex2D>& vertices = drawables_[d]->GetVertices();
+            for (unsigned i = 0; i < vertices.Size(); i += 4)
+            {
+                dest[0] = vertices[i + 0];
+                dest[1] = vertices[i + 1];
+                dest[2] = vertices[i + 2];
+
+                dest[3] = vertices[i + 0];
+                dest[4] = vertices[i + 2];
+                dest[5] = vertices[i + 3];
+                dest += 6;
+            }
+
+            count += vertices.Size() / 4 * 6;
+        }
+
+        if (material)
+            AddBatch(material, start, count);
+
+        vertexBuffer_->Unlock();
+    }
+    else
+        LOGERROR("Failed to lock vertex buffer");
+}
+
+UpdateGeometryType DrawableProxy2D::GetUpdateGeometryType()
+{
+    return UPDATE_WORKER_THREAD;
+}
+
+void DrawableProxy2D::AddDrawable(Drawable2D* drawable)
+{
+    if (!drawable)
+        return;
+
+    if (drawables_.Contains(drawable))
+        return;
+
+    drawables_.Push(drawable);
+    orderDirty_ = true;
+}
+
+void DrawableProxy2D::RemoveDrawable(Drawable2D* drawable)
+{
+    if (!drawable)
+        return;
+
+    drawables_.Remove(drawable);
+    orderDirty_ = true;
+}
+
+void DrawableProxy2D::OnWorldBoundingBoxUpdate()
+{
+    boundingBox_.Clear();
+
+    for (unsigned i = 0; i < drawables_.Size(); ++i)
+        boundingBox_.Merge(drawables_[i]->GetWorldBoundingBox());
+
+    worldBoundingBox_ = boundingBox_;
+}
+
+void DrawableProxy2D::AddBatch(Material* material, unsigned vertexStart, unsigned vertexCount)
+{
+    if (!material)
+        return;
+
+    materials_.Push(SharedPtr<Material>(material));
+
+    unsigned batchSize = materials_.Size();
+    if (geometries_.Size() < batchSize)
+    {
+        SharedPtr<Geometry> geometry(new Geometry(context_));
+        geometry->SetVertexBuffer(0, vertexBuffer_, MASK_VERTEX2D);
+        geometries_.Push(geometry);
+    }
+
+    geometries_[batchSize - 1]->SetDrawRange(TRIANGLE_LIST, 0, 0, vertexStart, vertexCount);
+}
+
+}

+ 78 - 0
Source/Engine/Urho2D/DrawableProxy2D.h

@@ -0,0 +1,78 @@
+//
+// 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.
+//
+
+#pragma once
+
+#include "Drawable.h"
+
+namespace Urho3D
+{
+
+class Drawable2D;
+class VertexBuffer;
+
+/// Proxy for 2D visible components.
+class URHO3D_API DrawableProxy2D : public Drawable
+{
+    OBJECT(DrawableProxy2D);
+
+public:
+    /// Construct.
+    DrawableProxy2D(Context* context);
+    /// Destruct.
+    ~DrawableProxy2D();
+    /// Register object factory.
+    static void RegisterObject(Context* context);
+
+    /// Calculate distance and prepare batches for rendering. May be called from worker thread(s), possibly re-entrantly.
+    virtual void UpdateBatches(const FrameInfo& frame);
+    /// Prepare geometry for rendering. Called from a worker thread if possible (no GPU update.)
+    virtual void UpdateGeometry(const FrameInfo& frame);
+    /// Return whether a geometry update is necessary, and if it can happen in a worker thread.
+    virtual UpdateGeometryType GetUpdateGeometryType();
+
+    /// Add drawable.
+    void AddDrawable(Drawable2D* drawable);
+    /// Remove drawable.
+    void RemoveDrawable(Drawable2D* drawable);
+    /// Mark order dirty.
+    void MarkOrderDirty() { orderDirty_ = true; }
+
+protected:
+    /// Recalculate the world-space bounding box.
+    virtual void OnWorldBoundingBoxUpdate();
+    /// Add batch.
+    void AddBatch(Material* material, unsigned vertexStart, unsigned vertexCount);
+
+    /// Vertex buffer.
+    SharedPtr<VertexBuffer> vertexBuffer_;
+    /// Materials.
+    Vector<SharedPtr<Material> > materials_;
+    /// Geometries.
+    Vector<SharedPtr<Geometry> > geometries_;
+    /// Drawables.
+    PODVector<Drawable2D* > drawables_;
+    /// Order dirty.
+    bool orderDirty_;
+};
+
+}

+ 5 - 17
Source/Engine/Urho2D/MaterialCache2D.cpp

@@ -33,7 +33,7 @@ namespace Urho3D
 {
 
 MaterialCache2D::MaterialCache2D(Context* context) :
-    Object(context)
+    Component(context)
 {
 }
 
@@ -41,21 +41,9 @@ MaterialCache2D::~MaterialCache2D()
 {
 }
 
-void MaterialCache2D::ReleaseAllMaterials()
+void MaterialCache2D::RegisterObject(Context* context)
 {
-    materials_.Clear();
-}
-
-void MaterialCache2D::ReleaseMaterial(Texture2D* texture)
-{
-    materials_.Erase(texture);
-}
-
-void MaterialCache2D::ReleaseMaterial(Texture2D* texture, BlendMode blendMode)
-{
-    HashMap<Texture2D*, HashMap<int, SharedPtr<Material> > >::Iterator i = materials_.Find(texture);
-    if (i != materials_.End())
-        i->second_.Erase(blendMode);
+    context->RegisterFactory<MaterialCache2D>();
 }
 
 Material* MaterialCache2D::GetMaterial(Texture2D* texture, BlendMode blendMode)
@@ -82,7 +70,7 @@ Material* MaterialCache2D::GetMaterial(Texture2D* texture, BlendMode blendMode)
 Material* MaterialCache2D::CreateMaterial(Texture2D* texture, BlendMode blendMode)
 {
     Material* material = new Material(context_);
-    
+
     Technique* tech = new Technique(context_);
     Pass* pass = tech->CreatePass(PASS_ALPHA);
     pass->SetBlendMode(blendMode);
@@ -92,7 +80,7 @@ Material* MaterialCache2D::CreateMaterial(Texture2D* texture, BlendMode blendMod
 
     pass->SetPixelShader("Basic");
     pass->SetPixelShaderDefines("DIFFMAP VERTEXCOLOR");
-    
+
     pass->SetDepthWrite(false);
 
     material->SetTechnique(0, tech);

+ 4 - 9
Source/Engine/Urho2D/MaterialCache2D.h

@@ -22,7 +22,7 @@
 
 #pragma once
 
-#include "Object.h"
+#include "Component.h"
 #include "GraphicsDefs.h"
 
 namespace Urho3D
@@ -32,7 +32,7 @@ class Texture2D;
 class Material;
 
 /// Material cache for 2D.
-class URHO3D_API MaterialCache2D : public Object
+class URHO3D_API MaterialCache2D : public Component
 {
     OBJECT(MaterialCache2D);
 
@@ -41,13 +41,8 @@ public:
     MaterialCache2D(Context* context);
     /// Destruct.
     virtual ~MaterialCache2D();
-    
-    /// Release all materials.
-    void ReleaseAllMaterials();
-    /// Release material by texture.
-    void ReleaseMaterial(Texture2D* texture);
-    /// Release material by texture and blend mode.
-    void ReleaseMaterial(Texture2D* texture, BlendMode blendMode);
+    /// Register object factory.
+    static void RegisterObject(Context* context);
 
     /// Return material by texture and blend mode.
     Material* GetMaterial(Texture2D* texture, BlendMode blendMode);

+ 5 - 0
Source/Engine/Urho2D/Urho2D.cpp

@@ -43,6 +43,8 @@
 #include "ConstraintWheel2D.h"
 #include "Context.h"
 #include "Drawable2D.h"
+#include "DrawableProxy2D.h"
+#include "MaterialCache2D.h"
 #include "ParticleEffect2D.h"
 #include "ParticleEmitter2D.h"
 #include "PhysicsWorld2D.h"
@@ -60,6 +62,9 @@ const char* URHO2D_CATEGORY = "Urho2D";
 
 void RegisterUrho2DLibrary(Context* context)
 {
+    MaterialCache2D::RegisterObject(context);
+    DrawableProxy2D::RegisterObject(context);
+
     // Must register objects from base to derived order
     Drawable2D::RegisterObject(context);
     StaticSprite2D::RegisterObject(context);