Browse Source

Additional Updates

Josh Engebretson 10 năm trước cách đây
mục cha
commit
e195fa58da
100 tập tin đã thay đổi với 2644 bổ sung2078 xóa
  1. 1 1
      CMakeLists.txt
  2. 12 20
      Source/Atomic/Atomic2D/AnimatedSprite2D.cpp
  3. 3 5
      Source/Atomic/Atomic2D/AnimatedSprite2D.h
  4. 17 97
      Source/Atomic/Atomic2D/Drawable2D.cpp
  5. 26 40
      Source/Atomic/Atomic2D/Drawable2D.h
  6. 9 7
      Source/Atomic/Atomic2D/Light2D.cpp
  7. 7 1
      Source/Atomic/Atomic2D/Light2D.h
  8. 64 24
      Source/Atomic/Atomic2D/ParticleEmitter2D.cpp
  9. 13 3
      Source/Atomic/Atomic2D/ParticleEmitter2D.h
  10. 207 210
      Source/Atomic/Atomic2D/Renderer2D.cpp
  11. 41 29
      Source/Atomic/Atomic2D/Renderer2D.h
  12. 56 1
      Source/Atomic/Atomic2D/Sprite2D.cpp
  13. 8 1
      Source/Atomic/Atomic2D/Sprite2D.h
  14. 109 83
      Source/Atomic/Atomic2D/StaticSprite2D.cpp
  15. 23 3
      Source/Atomic/Atomic2D/StaticSprite2D.h
  16. 3 3
      Source/Atomic/Atomic3D/AnimatedModel.cpp
  17. 2 2
      Source/Atomic/Atomic3D/DecalSet.cpp
  18. 2 0
      Source/Atomic/Atomic3D/Model.h
  19. 2 2
      Source/Atomic/Atomic3D/ParticleEmitter.cpp
  20. 10 12
      Source/Atomic/Atomic3D/StaticModel.cpp
  21. 208 244
      Source/Atomic/Graphics/Batch.cpp
  22. 3 1
      Source/Atomic/Graphics/Batch.h
  23. 2 2
      Source/Atomic/Graphics/ConstantBuffer.h
  24. 27 3
      Source/Atomic/Graphics/DebugRenderer.cpp
  25. 5 1
      Source/Atomic/Graphics/DebugRenderer.h
  26. 26 20
      Source/Atomic/Graphics/Drawable.cpp
  27. 22 28
      Source/Atomic/Graphics/Drawable.h
  28. 4 2
      Source/Atomic/Graphics/GPUObject.h
  29. 4 2
      Source/Atomic/Graphics/Graphics.h
  30. 2 15
      Source/Atomic/Graphics/GraphicsDefs.cpp
  31. 25 29
      Source/Atomic/Graphics/GraphicsDefs.h
  32. 0 5
      Source/Atomic/Graphics/GraphicsEvents.h
  33. 4 2
      Source/Atomic/Graphics/GraphicsImpl.h
  34. 4 2
      Source/Atomic/Graphics/IndexBuffer.h
  35. 3 12
      Source/Atomic/Graphics/Light.cpp
  36. 65 24
      Source/Atomic/Graphics/Material.cpp
  37. 16 8
      Source/Atomic/Graphics/Material.h
  38. 1 1
      Source/Atomic/Graphics/OpenGL/OGLConstantBuffer.cpp
  39. 2 2
      Source/Atomic/Graphics/OpenGL/OGLConstantBuffer.h
  40. 322 316
      Source/Atomic/Graphics/OpenGL/OGLGraphics.cpp
  41. 61 42
      Source/Atomic/Graphics/OpenGL/OGLGraphics.h
  42. 5 3
      Source/Atomic/Graphics/OpenGL/OGLGraphicsImpl.cpp
  43. 12 4
      Source/Atomic/Graphics/OpenGL/OGLGraphicsImpl.h
  44. 4 8
      Source/Atomic/Graphics/OpenGL/OGLIndexBuffer.cpp
  45. 185 11
      Source/Atomic/Graphics/OpenGL/OGLShaderProgram.cpp
  46. 34 2
      Source/Atomic/Graphics/OpenGL/OGLShaderProgram.h
  47. 10 5
      Source/Atomic/Graphics/OpenGL/OGLShaderVariation.cpp
  48. 41 20
      Source/Atomic/Graphics/OpenGL/OGLTexture.cpp
  49. 4 4
      Source/Atomic/Graphics/OpenGL/OGLTexture.h
  50. 11 2
      Source/Atomic/Graphics/OpenGL/OGLTexture2D.cpp
  51. 12 3
      Source/Atomic/Graphics/OpenGL/OGLTexture3D.cpp
  52. 11 2
      Source/Atomic/Graphics/OpenGL/OGLTextureCube.cpp
  53. 5 4
      Source/Atomic/Graphics/OpenGL/OGLVertexBuffer.cpp
  54. 42 14
      Source/Atomic/Graphics/RenderPath.cpp
  55. 16 5
      Source/Atomic/Graphics/RenderPath.h
  56. 4 2
      Source/Atomic/Graphics/RenderSurface.h
  57. 54 56
      Source/Atomic/Graphics/Renderer.cpp
  58. 8 15
      Source/Atomic/Graphics/Renderer.h
  59. 6 2
      Source/Atomic/Graphics/ShaderProgram.h
  60. 4 2
      Source/Atomic/Graphics/ShaderVariation.h
  61. 120 57
      Source/Atomic/Graphics/Technique.cpp
  62. 53 40
      Source/Atomic/Graphics/Technique.h
  63. 4 2
      Source/Atomic/Graphics/Texture.h
  64. 4 2
      Source/Atomic/Graphics/Texture2D.h
  65. 4 2
      Source/Atomic/Graphics/Texture3D.h
  66. 4 2
      Source/Atomic/Graphics/TextureCube.h
  67. 4 2
      Source/Atomic/Graphics/VertexBuffer.h
  68. 4 2
      Source/Atomic/Graphics/VertexDeclaration.h
  69. 252 302
      Source/Atomic/Graphics/View.cpp
  70. 35 23
      Source/Atomic/Graphics/View.h
  71. 1 2
      Source/Atomic/Input/Input.cpp
  72. 5 5
      Source/Atomic/Navigation/CrowdAgent.cpp
  73. 2 2
      Source/Atomic/Navigation/CrowdAgent.h
  74. 3 3
      Source/Atomic/Navigation/DetourCrowdManager.cpp
  75. 2 2
      Source/Atomic/Navigation/DetourCrowdManager.h
  76. 8 8
      Source/Atomic/Navigation/DynamicNavigationMesh.cpp
  77. 2 2
      Source/Atomic/Navigation/DynamicNavigationMesh.h
  78. 1 1
      Source/Atomic/Navigation/NavArea.cpp
  79. 2 2
      Source/Atomic/Navigation/NavArea.h
  80. 7 7
      Source/Atomic/Navigation/NavBuildData.cpp
  81. 3 3
      Source/Atomic/Navigation/NavBuildData.h
  82. 1 1
      Source/Atomic/Navigation/NavigationEvents.h
  83. 1 0
      Source/Atomic/Navigation/NavigationMesh.h
  84. 1 1
      Source/Atomic/Navigation/Obstacle.cpp
  85. 2 2
      Source/Atomic/Navigation/Obstacle.h
  86. 54 37
      Source/Atomic/Network/Connection.cpp
  87. 7 0
      Source/Atomic/Network/Connection.h
  88. 9 1
      Source/Atomic/Scene/ReplicationState.h
  89. 11 1
      Source/Atomic/Scene/SceneEvents.h
  90. 117 10
      Source/Atomic/Scene/Serializable.cpp
  91. 14 8
      Source/Atomic/Scene/Serializable.h
  92. 3 4
      Source/Atomic/UI/UI.cpp
  93. 1 1
      Source/Atomic/UI/UI.h
  94. 2 0
      Source/ThirdParty/CMakeLists.txt
  95. 3 32
      Source/ThirdParty/DetourCrowd/CMakeLists.txt
  96. 2 2
      Source/ThirdParty/DetourCrowd/include/DetourCrowd.h
  97. 1 1
      Source/ThirdParty/DetourCrowd/include/DetourLocalBoundary.h
  98. 1 1
      Source/ThirdParty/DetourCrowd/include/DetourPathCorridor.h
  99. 2 2
      Source/ThirdParty/DetourCrowd/include/DetourPathQueue.h
  100. 3 34
      Source/ThirdParty/DetourTileCache/CMakeLists.txt

+ 1 - 1
CMakeLists.txt

@@ -26,7 +26,7 @@ endif()
 
 
 if (NOT EMSCRIPTEN)
 if (NOT EMSCRIPTEN)
     add_definitions( -DATOMIC_NETWORK)
     add_definitions( -DATOMIC_NETWORK)
-    set (ATOMIC_LINK_LIBRARIES ${ATOMIC_LINK_LIBRARIES} SDL Civetweb Recast Detour kNet )
+    set (ATOMIC_LINK_LIBRARIES ${ATOMIC_LINK_LIBRARIES} SDL Civetweb Recast Detour DetourCrowd DetourTileCache kNet )
 endif()
 endif()
 
 
 if (MSVC)
 if (MSVC)

+ 12 - 20
Source/Atomic/Atomic2D/AnimatedSprite2D.cpp

@@ -21,13 +21,13 @@
 //
 //
 
 
 #include "Precompiled.h"
 #include "Precompiled.h"
-#include "../Atomic2D/AnimatedSprite2D.h"
-#include "../Atomic2D/Animation2D.h"
-#include "../Atomic2D/AnimationSet2D.h"
 #include "../Core/Context.h"
 #include "../Core/Context.h"
 #include "../Resource/ResourceCache.h"
 #include "../Resource/ResourceCache.h"
 #include "../Scene/Scene.h"
 #include "../Scene/Scene.h"
 #include "../Scene/SceneEvents.h"
 #include "../Scene/SceneEvents.h"
+#include "../Atomic2D/AnimatedSprite2D.h"
+#include "../Atomic2D/Animation2D.h"
+#include "../Atomic2D/AnimationSet2D.h"
 #include "../Atomic2D/Sprite2D.h"
 #include "../Atomic2D/Sprite2D.h"
 #include "../Atomic2D/StaticSprite2D.h"
 #include "../Atomic2D/StaticSprite2D.h"
 
 
@@ -222,7 +222,7 @@ void AnimatedSprite2D::OnWorldBoundingBoxUpdate()
     boundingBox_ = worldBoundingBox_.Transformed(node_->GetWorldTransform().Inverse());
     boundingBox_ = worldBoundingBox_.Transformed(node_->GetWorldTransform().Inverse());
 }
 }
 
 
-void AnimatedSprite2D::OnLayerChanged()
+void AnimatedSprite2D::OnDrawOrderChanged()
 {
 {
     for (unsigned i = 0; i < numTracks_; ++i)
     for (unsigned i = 0; i < numTracks_; ++i)
     {
     {
@@ -235,18 +235,6 @@ void AnimatedSprite2D::OnLayerChanged()
     }
     }
 }
 }
 
 
-void AnimatedSprite2D::OnBlendModeChanged()
-{
-    for (unsigned i = 0; i < numTracks_; ++i)
-    {
-        if (!trackNodes_[i])
-            continue;
-
-        StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
-        staticSprite->SetBlendMode(blendMode_);
-    }
-}
-
 void AnimatedSprite2D::OnFlipChanged()
 void AnimatedSprite2D::OnFlipChanged()
 {
 {
     for (unsigned i = 0; i < numTracks_; ++i)
     for (unsigned i = 0; i < numTracks_; ++i)
@@ -255,16 +243,17 @@ void AnimatedSprite2D::OnFlipChanged()
             continue;
             continue;
 
 
         StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
         StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
-        staticSprite->SetFlip(flipX_, flipY_);
+        if (staticSprite)
+            staticSprite->SetFlip(flipX_, flipY_);
     }
     }
 
 
     // For editor paused mode
     // For editor paused mode
     UpdateAnimation(0.0f);
     UpdateAnimation(0.0f);
 }
 }
 
 
-void AnimatedSprite2D::UpdateVertices()
+void AnimatedSprite2D::UpdateSourceBatches()
 {
 {
-    verticesDirty_ = false;
+    sourceBatchesDirty_ = false;
 }
 }
 
 
 void AnimatedSprite2D::SetAnimation(Animation2D* animation, LoopMode2D loopMode)
 void AnimatedSprite2D::SetAnimation(Animation2D* animation, LoopMode2D loopMode)
@@ -376,7 +365,7 @@ void AnimatedSprite2D::UpdateAnimation(float timeStep)
     {
     {
         trackNodeInfos_[i].worldSpace = false;
         trackNodeInfos_[i].worldSpace = false;
         
         
-        const AnimationTrack2D& track = animation_->GetTrack(i);        
+        const AnimationTrack2D& track = animation_->GetTrack(i);
         const Vector<AnimationKeyFrame2D>& keyFrames = track.keyFrames_;
         const Vector<AnimationKeyFrame2D>& keyFrames = track.keyFrames_;
 
 
         // Time out of range
         // Time out of range
@@ -430,6 +419,9 @@ void AnimatedSprite2D::UpdateAnimation(float timeStep)
     for (unsigned i = 0; i < numTracks_; ++i)
     for (unsigned i = 0; i < numTracks_; ++i)
     {
     {
         Node* node = trackNodes_[i];
         Node* node = trackNodes_[i];
+        if (!node)
+            continue;
+
         TrackNodeInfo& nodeInfo = trackNodeInfos_[i];
         TrackNodeInfo& nodeInfo = trackNodeInfos_[i];
 
 
         if (!nodeInfo.value.enabled_)
         if (!nodeInfo.value.enabled_)

+ 3 - 5
Source/Atomic/Atomic2D/AnimatedSprite2D.h

@@ -91,12 +91,10 @@ protected:
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
     /// Recalculate the world-space bounding box.
     /// Recalculate the world-space bounding box.
     virtual void OnWorldBoundingBoxUpdate();
     virtual void OnWorldBoundingBoxUpdate();
-    /// Handle layer changed.
-    virtual void OnLayerChanged();
-    /// Handle blend mode changed.
-    virtual void OnBlendModeChanged();
+    /// Handle draw order changed.
+    virtual void OnDrawOrderChanged();
     /// Handle update vertices.
     /// Handle update vertices.
-    virtual void UpdateVertices();
+    virtual void UpdateSourceBatches();
     /// Handle flip changed.
     /// Handle flip changed.
     virtual void OnFlipChanged();
     virtual void OnFlipChanged();
     /// Set animation.
     /// Set animation.

+ 17 - 97
Source/Atomic/Atomic2D/Drawable2D.cpp

@@ -21,13 +21,13 @@
 //
 //
 
 
 #include "Precompiled.h"
 #include "Precompiled.h"
-#include "../Graphics/Camera.h"
 #include "../Core/Context.h"
 #include "../Core/Context.h"
-#include "../Atomic2D/Drawable2D.h"
+#include "../Graphics/Camera.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/Material.h"
-#include "../Atomic2D/Renderer2D.h"
-#include "../Scene/Scene.h"
 #include "../Graphics/Texture2D.h"
 #include "../Graphics/Texture2D.h"
+#include "../Scene/Scene.h"
+#include "../Atomic2D/Drawable2D.h"
+#include "../Atomic2D/Renderer2D.h"
 
 
 #include "../DebugNew.h"
 #include "../DebugNew.h"
 
 
@@ -35,14 +35,16 @@ namespace Atomic
 {
 {
 
 
 const float PIXEL_SIZE = 0.01f;
 const float PIXEL_SIZE = 0.01f;
-extern const char* blendModeNames[];
+
+SourceBatch2D::SourceBatch2D() : drawOrder_(0)
+{
+}
 
 
 Drawable2D::Drawable2D(Context* context) :
 Drawable2D::Drawable2D(Context* context) :
     Drawable(context, DRAWABLE_GEOMETRY2D),
     Drawable(context, DRAWABLE_GEOMETRY2D),
     layer_(0),
     layer_(0),
     orderInLayer_(0),
     orderInLayer_(0),
-    blendMode_(BLEND_ALPHA),
-    verticesDirty_(true)
+    sourceBatchesDirty_(true)
 {
 {
 }
 }
 
 
@@ -56,8 +58,6 @@ void Drawable2D::RegisterObject(Context* context)
 {
 {
     ACCESSOR_ATTRIBUTE("Layer", GetLayer, SetLayer, int, 0, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Layer", GetLayer, SetLayer, int, 0, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Order in Layer", GetOrderInLayer, SetOrderInLayer, int, 0, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Order in Layer", GetOrderInLayer, SetOrderInLayer, int, 0, AM_DEFAULT);
-    ENUM_ACCESSOR_ATTRIBUTE("Blend Mode", GetBlendMode, SetBlendMode, BlendMode, blendModeNames, BLEND_ALPHA, AM_DEFAULT);
-    COPY_BASE_ATTRIBUTES(Drawable);
 }
 }
 
 
 void Drawable2D::OnSetEnabled()
 void Drawable2D::OnSetEnabled()
@@ -77,11 +77,7 @@ void Drawable2D::SetLayer(int layer)
 
 
     layer_ = layer;
     layer_ = layer;
 
 
-    OnLayerChanged();
-
-    if (renderer_)
-        renderer_->MarkOrderDirty();
-
+    OnDrawOrderChanged();
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -92,96 +88,28 @@ void Drawable2D::SetOrderInLayer(int orderInLayer)
 
 
     orderInLayer_ = orderInLayer;
     orderInLayer_ = orderInLayer;
     
     
-    OnLayerChanged();
-
-    if (renderer_)
-        renderer_->MarkOrderDirty();
-
-    MarkNetworkUpdate();
-}
-
-void Drawable2D::SetTexture(Texture2D* texture)
-{
-    if (texture == texture_)
-        return;
-
-    texture_ = texture;
-
-    verticesDirty_ = true;
-    material_ = 0;
-    if (renderer_)
-        renderer_->MarkMaterialDirty(this);
-
-    OnMarkedDirty(node_);
-
+    OnDrawOrderChanged();
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
-void Drawable2D::SetBlendMode(BlendMode blendMode)
+const Vector<SourceBatch2D>& Drawable2D::GetSourceBatches()
 {
 {
-    if (blendMode == blendMode_)
-        return;
+    if (sourceBatchesDirty_)
+        UpdateSourceBatches();
 
 
-    blendMode_ = blendMode;
-    material_ = 0;
-    if (renderer_)
-        renderer_->MarkMaterialDirty(this);
-
-    OnBlendModeChanged();
-
-    MarkNetworkUpdate();
-}
-
-void Drawable2D::SetCustomMaterial(Material* customMaterial)
-{
-    if (customMaterial == customMaterial_)
-        return;
-
-    customMaterial_ = customMaterial;
-    material_ = 0;
-    if (renderer_)
-        renderer_->MarkMaterialDirty(this);
-
-    MarkNetworkUpdate();
-}
-
-Texture2D* Drawable2D::GetTexture() const
-{
-    return texture_;
-}
-
-Material* Drawable2D::GetCustomMaterial() const
-{
-    return customMaterial_;
-}
-
-void Drawable2D::SetMaterial(Material* material)
-{
-    material_ = material;
-}
-
-Material* Drawable2D::GetMaterial() const
-{
-    return customMaterial_ ? customMaterial_ : material_;
-}
-
-const Vector<Vertex2D>& Drawable2D::GetVertices()
-{
-    if (verticesDirty_)
-        UpdateVertices();
-    return vertices_;
+    return sourceBatches_;
 }
 }
 
 
 void Drawable2D::OnNodeSet(Node* node)
 void Drawable2D::OnNodeSet(Node* node)
 {
 {
     // Do not call Drawable::OnNodeSet(node)
     // Do not call Drawable::OnNodeSet(node)
-
     if (node)
     if (node)
     {
     {
         Scene* scene = GetScene();
         Scene* scene = GetScene();
         if (scene)
         if (scene)
         {
         {
             renderer_ = scene->GetOrCreateComponent<Renderer2D>();
             renderer_ = scene->GetOrCreateComponent<Renderer2D>();
+
             if (IsEnabledEffective())
             if (IsEnabledEffective())
                 renderer_->AddDrawable(this);
                 renderer_->AddDrawable(this);
         }
         }
@@ -199,15 +127,7 @@ void Drawable2D::OnMarkedDirty(Node* node)
 {
 {
     Drawable::OnMarkedDirty(node);
     Drawable::OnMarkedDirty(node);
 
 
-    verticesDirty_ = true;
-}
-
-void Drawable2D::OnLayerChanged()
-{
-}
-
-void Drawable2D::OnBlendModeChanged()
-{
+    sourceBatchesDirty_ = true;
 }
 }
 
 
 }
 }

+ 26 - 40
Source/Atomic/Atomic2D/Drawable2D.h

@@ -43,7 +43,19 @@ struct Vertex2D
     Vector2 uv_;
     Vector2 uv_;
 };
 };
 
 
-static const unsigned MASK_VERTEX2D = MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1;
+/// 2D source batch.
+struct SourceBatch2D
+{
+    /// Construct.
+    SourceBatch2D();
+
+    /// Draw order.
+    int drawOrder_;
+    /// Material.
+    SharedPtr<Material> material_;
+    /// Vertices.
+    Vector<Vertex2D> vertices_;
+};
 
 
 /// Pixel size (equal 0.01f).
 /// Pixel size (equal 0.01f).
 extern ATOMIC_API const float PIXEL_SIZE;
 extern ATOMIC_API const float PIXEL_SIZE;
@@ -68,61 +80,35 @@ public:
     void SetLayer(int layer);
     void SetLayer(int layer);
     /// Set order in layer.
     /// Set order in layer.
     void SetOrderInLayer(int orderInLayer);
     void SetOrderInLayer(int orderInLayer);
-    /// Set texture.
-    void SetTexture(Texture2D* texture);
-    /// Set blend mode.
-    void SetBlendMode(BlendMode mode);
-    /// Set custom material. 
-    void SetCustomMaterial(Material* customMaterial);
     
     
     /// Return layer.
     /// Return layer.
     int GetLayer() const { return layer_; }
     int GetLayer() const { return layer_; }
     /// Return order in layer.
     /// Return order in layer.
     int GetOrderInLayer() const { return orderInLayer_; }
     int GetOrderInLayer() const { return orderInLayer_; }
-    /// Return texture.
-    Texture2D* GetTexture() const;
-    /// Return blend mode.
-    BlendMode GetBlendMode() const { return blendMode_; }
-    /// Return custom material.
-    Material* GetCustomMaterial() const;
 
 
-    /// Set material (called by Renderer2D).
-    void SetMaterial(Material* material);
-    /// Return custom material or material (called by Renderer2D).
-    Material* GetMaterial() const;
-    /// Return all vertices (called by Renderer2D).
-    const Vector<Vertex2D>& GetVertices();
+    /// Return all source batches (called by Renderer2D).
+    const Vector<SourceBatch2D>& GetSourceBatches();
 
 
 protected:
 protected:
     /// Handle node being assigned.
     /// Handle node being assigned.
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
     /// Handle node transform being dirtied.
     /// Handle node transform being dirtied.
     virtual void OnMarkedDirty(Node* node);
     virtual void OnMarkedDirty(Node* node);
-    /// Handle layer changed.
-    virtual void OnLayerChanged();
-    /// Handle blend mode changed.
-    virtual void OnBlendModeChanged();
-    /// Update vertices.
-    virtual void UpdateVertices() = 0;
-    
-
+    /// Handle draw order changed.
+    virtual void OnDrawOrderChanged() = 0;
+    /// Update source batches.
+    virtual void UpdateSourceBatches() = 0;
+    /// Return draw order by layer and order in layer.
+    int GetDrawOrder() const { return (layer_ << 20) + (orderInLayer_ << 10); }
+  
     /// Layer.
     /// Layer.
     int layer_;
     int layer_;
     /// Order in layer.
     /// Order in layer.
     int orderInLayer_;
     int orderInLayer_;
-    /// Texture.
-    SharedPtr<Texture2D> texture_;
-    /// Blend mode.
-    BlendMode blendMode_;
-    /// Custom material.
-    SharedPtr<Material> customMaterial_;
-
-    /// Vertices.
-    Vector<Vertex2D> vertices_;
-    /// Vertices dirty flag.
-    bool verticesDirty_;
-    /// Material.
-    SharedPtr<Material> material_;
+    /// Source batches.
+    Vector<SourceBatch2D> sourceBatches_;
+    /// Source batches dirty flag.
+    bool sourceBatchesDirty_;
     /// Renderer2D.
     /// Renderer2D.
     WeakPtr<Renderer2D> renderer_;
     WeakPtr<Renderer2D> renderer_;
 };
 };

+ 9 - 7
Source/Atomic/Atomic2D/Light2D.cpp

@@ -452,7 +452,7 @@ void Light2DGroup::OnNodeSet(Node* node)
         if (renderer_.Null())
         if (renderer_.Null())
         {
         {
             renderer_ = node->GetOrCreateComponent<Renderer2D>();
             renderer_ = node->GetOrCreateComponent<Renderer2D>();
-            renderer_->SetUseTris(true);
+            //renderer_->SetUseTris(true);
         }
         }
 
 
         if (light2DMaterial_.Null())
         if (light2DMaterial_.Null())
@@ -527,7 +527,7 @@ void Light2DGroup::HandleBeginViewUpdate(StringHash eventType, VariantMap& event
 
 
 void Light2DGroup::HandleBeginRendering(StringHash eventType, VariantMap& eventData)
 void Light2DGroup::HandleBeginRendering(StringHash eventType, VariantMap& eventData)
 {
 {
-    verticesDirty_ = true;
+    //verticesDirty_ = true;
 }
 }
 
 
 void Light2DGroup::OnWorldBoundingBoxUpdate()
 void Light2DGroup::OnWorldBoundingBoxUpdate()
@@ -539,10 +539,10 @@ void Light2DGroup::OnWorldBoundingBoxUpdate()
 void Light2DGroup::UpdateVertices()
 void Light2DGroup::UpdateVertices()
 {
 {
     // This is the shadow map
     // This is the shadow map
-    if (!verticesDirty_)
-        return;
+    //if (!verticesDirty_)
+    //    return;
 
 
-    vertices_.Clear();
+    //vertices_.Clear();
 
 
     for (Vector<WeakPtr<Light2D> >::Iterator itr = lights_.Begin(); itr != lights_.End(); itr++)
     for (Vector<WeakPtr<Light2D> >::Iterator itr = lights_.Begin(); itr != lights_.End(); itr++)
     {
     {
@@ -550,10 +550,10 @@ void Light2DGroup::UpdateVertices()
         if (!light->IsEnabled())
         if (!light->IsEnabled())
             continue;
             continue;
         light->UpdateVertices();
         light->UpdateVertices();
-        light->AddVertices(vertices_);
+      //  light->AddVertices(vertices_);
     }
     }
 
 
-    verticesDirty_ = false;
+    //verticesDirty_ = false;
 
 
 }
 }
 
 
@@ -653,6 +653,7 @@ void Light2DGroup::CreateLight2DMaterial()
     light2DMaterial_ = new Material(context_);
     light2DMaterial_ = new Material(context_);
     light2DMaterial_->SetName("Light2DMaterial");
     light2DMaterial_->SetName("Light2DMaterial");
 
 
+    /*
     Technique* tech = new Technique(context_);
     Technique* tech = new Technique(context_);
     Pass* pass = tech->CreatePass(PASS_LIGHT2D);
     Pass* pass = tech->CreatePass(PASS_LIGHT2D);
     pass->SetBlendMode(BLEND_ADDALPHA);
     pass->SetBlendMode(BLEND_ADDALPHA);
@@ -667,6 +668,7 @@ void Light2DGroup::CreateLight2DMaterial()
     light2DMaterial_->SetCullMode(CULL_NONE);
     light2DMaterial_->SetCullMode(CULL_NONE);
 
 
     SetCustomMaterial(light2DMaterial_);
     SetCustomMaterial(light2DMaterial_);
+    */
 
 
 }
 }
 
 

+ 7 - 1
Source/Atomic/Atomic2D/Light2D.h

@@ -174,7 +174,7 @@ public:
     void AddLight(Light2D* light);
     void AddLight(Light2D* light);
     Vector<WeakPtr<Light2D> >& GetLights() { return lights_; }
     Vector<WeakPtr<Light2D> >& GetLights() { return lights_; }
 
 
-    void SetDirty() { verticesDirty_ = true; }
+    void SetDirty() { /*verticesDirty_ = true;*/ }
 
 
     void SetAmbientColor(const Color& color);
     void SetAmbientColor(const Color& color);
     const Color& GetAmbientColor() { return ambientColor_; }
     const Color& GetAmbientColor() { return ambientColor_; }
@@ -188,6 +188,12 @@ protected:
     void UpdateVertices();
     void UpdateVertices();
     void OnNodeSet(Node* node);
     void OnNodeSet(Node* node);
 
 
+    /// Handle draw order changed.
+    virtual void OnDrawOrderChanged(){}
+    /// Update source batches.
+    virtual void UpdateSourceBatches(){}
+
+
 private:
 private:
 
 
     Color ambientColor_;
     Color ambientColor_;

+ 64 - 24
Source/Atomic/Atomic2D/ParticleEmitter2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -21,13 +21,15 @@
 //
 //
 
 
 #include "Precompiled.h"
 #include "Precompiled.h"
-#include "../Graphics/Camera.h"
 #include "../Core/Context.h"
 #include "../Core/Context.h"
-#include "../Atomic2D/ParticleEffect2D.h"
-#include "../Atomic2D/ParticleEmitter2D.h"
+#include "../Graphics/Camera.h"
+#include "../Graphics/Material.h"
 #include "../Resource/ResourceCache.h"
 #include "../Resource/ResourceCache.h"
 #include "../Scene/Scene.h"
 #include "../Scene/Scene.h"
 #include "../Scene/SceneEvents.h"
 #include "../Scene/SceneEvents.h"
+#include "../Atomic2D/ParticleEffect2D.h"
+#include "../Atomic2D/ParticleEmitter2D.h"
+#include "../Atomic2D/Renderer2D.h"
 #include "../Atomic2D/Sprite2D.h"
 #include "../Atomic2D/Sprite2D.h"
 
 
 #include "../DebugNew.h"
 #include "../DebugNew.h"
@@ -36,15 +38,18 @@ namespace Atomic
 {
 {
 
 
 extern const char* ATOMIC2D_CATEGORY;
 extern const char* ATOMIC2D_CATEGORY;
+extern const char* blendModeNames[];
 
 
 ParticleEmitter2D::ParticleEmitter2D(Context* context) :
 ParticleEmitter2D::ParticleEmitter2D(Context* context) :
     Drawable2D(context),
     Drawable2D(context),
+    blendMode_(BLEND_ADDALPHA),
     numParticles_(0),
     numParticles_(0),
     emissionTime_(0.0f),
     emissionTime_(0.0f),
     emitParticleTime_(0.0f),
     emitParticleTime_(0.0f),
     boundingBoxMinPoint_(Vector3::ZERO),
     boundingBoxMinPoint_(Vector3::ZERO),
     boundingBoxMaxPoint_(Vector3::ZERO)
     boundingBoxMaxPoint_(Vector3::ZERO)
 {
 {
+    sourceBatches_.Resize(1);
 }
 }
 
 
 ParticleEmitter2D::~ParticleEmitter2D()
 ParticleEmitter2D::~ParticleEmitter2D()
@@ -56,9 +61,10 @@ void ParticleEmitter2D::RegisterObject(Context* context)
     context->RegisterFactory<ParticleEmitter2D>(ATOMIC2D_CATEGORY);
     context->RegisterFactory<ParticleEmitter2D>(ATOMIC2D_CATEGORY);
 
 
     ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
+    COPY_BASE_ATTRIBUTES(Drawable2D);
     MIXED_ACCESSOR_ATTRIBUTE("Particle Effect", GetParticleEffectAttr, SetParticleEffectAttr, ResourceRef, ResourceRef(ParticleEffect2D::GetTypeStatic()), AM_DEFAULT);
     MIXED_ACCESSOR_ATTRIBUTE("Particle Effect", GetParticleEffectAttr, SetParticleEffectAttr, ResourceRef, ResourceRef(ParticleEffect2D::GetTypeStatic()), AM_DEFAULT);
     MIXED_ACCESSOR_ATTRIBUTE("Sprite ", GetSpriteAttr, SetSpriteAttr, ResourceRef, ResourceRef(Sprite2D::GetTypeStatic()), AM_DEFAULT);
     MIXED_ACCESSOR_ATTRIBUTE("Sprite ", GetSpriteAttr, SetSpriteAttr, ResourceRef, ResourceRef(Sprite2D::GetTypeStatic()), AM_DEFAULT);
-    COPY_BASE_ATTRIBUTES(Drawable2D);
+    ENUM_ACCESSOR_ATTRIBUTE("Blend Mode", GetBlendMode, SetBlendMode, BlendMode, blendModeNames, BLEND_ALPHA, AM_DEFAULT);
 }
 }
 
 
 void ParticleEmitter2D::OnSetEnabled()
 void ParticleEmitter2D::OnSetEnabled()
@@ -100,8 +106,20 @@ void ParticleEmitter2D::SetSprite(Sprite2D* sprite)
         return;
         return;
 
 
     sprite_ = sprite;
     sprite_ = sprite;
+    UpdateMaterial();
 
 
-    SetTexture(sprite_ ? sprite_->GetTexture() : 0);
+    MarkNetworkUpdate();
+}
+
+void ParticleEmitter2D::SetBlendMode(BlendMode blendMode)
+{
+    if (blendMode == blendMode_)
+        return;
+
+    blendMode_ = blendMode;
+    UpdateMaterial();
+
+    MarkNetworkUpdate();
 }
 }
 
 
 void ParticleEmitter2D::SetMaxParticles(unsigned maxParticles)
 void ParticleEmitter2D::SetMaxParticles(unsigned maxParticles)
@@ -109,7 +127,7 @@ void ParticleEmitter2D::SetMaxParticles(unsigned maxParticles)
     maxParticles = Max(maxParticles, 1);
     maxParticles = Max(maxParticles, 1);
 
 
     particles_.Resize(maxParticles);
     particles_.Resize(maxParticles);
-    vertices_.Reserve(maxParticles * 4);
+    sourceBatches_[0].vertices_.Reserve(maxParticles * 4);
 
 
     numParticles_ = Min(maxParticles, numParticles_);
     numParticles_ = Min(maxParticles, numParticles_);
 }
 }
@@ -169,30 +187,44 @@ void ParticleEmitter2D::OnWorldBoundingBoxUpdate()
     worldBoundingBox_ = boundingBox_;
     worldBoundingBox_ = boundingBox_;
 }
 }
 
 
-void ParticleEmitter2D::UpdateVertices()
+void ParticleEmitter2D::OnDrawOrderChanged()
 {
 {
-    if (!verticesDirty_)
+    sourceBatches_[0].drawOrder_ = GetDrawOrder();
+}
+
+void ParticleEmitter2D::UpdateSourceBatches()
+{
+    if (!sourceBatchesDirty_)
         return;
         return;
 
 
-    vertices_.Clear();
+    Vector<Vertex2D>& vertices = sourceBatches_[0].vertices_;
+    vertices.Clear();
 
 
-    Texture2D* texture = GetTexture();
-    if (!texture)
+    if (!sprite_)
         return;
         return;
 
 
-    const IntRect& rectangle_ = sprite_->GetRectangle();
-    if (rectangle_.Width() == 0 || rectangle_.Height() == 0)
+    Rect textureRect;
+    if (!sprite_->GetTextureRectangle(textureRect))
         return;
         return;
 
 
+    /*
+    V1---------V2
+    |         / |
+    |       /   |
+    |     /     |
+    |   /       |
+    | /         |
+    V0---------V3
+    */
     Vertex2D vertex0;
     Vertex2D vertex0;
     Vertex2D vertex1;
     Vertex2D vertex1;
     Vertex2D vertex2;
     Vertex2D vertex2;
     Vertex2D vertex3;
     Vertex2D vertex3;
 
 
-    vertex0.uv_ = Vector2(0.0f, 1.0f);
-    vertex1.uv_ = Vector2(0.0f, 0.0f);
-    vertex2.uv_ = Vector2(1.0f, 0.0f);
-    vertex3.uv_ = Vector2(1.0f, 1.0f);
+    vertex0.uv_ = textureRect.min_;
+    vertex1.uv_ = Vector2(textureRect.min_.x_, textureRect.max_.y_);
+    vertex2.uv_ = textureRect.max_;
+    vertex3.uv_ = Vector2(textureRect.max_.x_, textureRect.min_.y_);
 
 
     for (int i = 0; i < numParticles_; ++i)
     for (int i = 0; i < numParticles_; ++i)
     {
     {
@@ -211,13 +243,21 @@ void ParticleEmitter2D::UpdateVertices()
 
 
         vertex0.color_ = vertex1.color_ = vertex2.color_  = vertex3.color_ = p.color_.ToUInt();
         vertex0.color_ = vertex1.color_ = vertex2.color_  = vertex3.color_ = p.color_.ToUInt();
 
 
-        vertices_.Push(vertex0);
-        vertices_.Push(vertex1);
-        vertices_.Push(vertex2);
-        vertices_.Push(vertex3);
+        vertices.Push(vertex0);
+        vertices.Push(vertex1);
+        vertices.Push(vertex2);
+        vertices.Push(vertex3);
     }
     }
 
 
-    verticesDirty_ = false;
+    sourceBatchesDirty_ = false;
+}
+
+void ParticleEmitter2D::UpdateMaterial()
+{
+    if (sprite_)
+        sourceBatches_[0].material_ = renderer_->GetMaterial(sprite_->GetTexture(), blendMode_);
+    else
+        sourceBatches_[0].material_ = 0;
 }
 }
 
 
 void ParticleEmitter2D::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
 void ParticleEmitter2D::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
@@ -274,7 +314,7 @@ void ParticleEmitter2D::Update(float timeStep)
             emissionTime_ = Max(0.0f, emissionTime_ - timeStep);
             emissionTime_ = Max(0.0f, emissionTime_ - timeStep);
     }
     }
 
 
-    verticesDirty_ = true;
+    sourceBatchesDirty_ = true;
 
 
     OnMarkedDirty(node_);
     OnMarkedDirty(node_);
 }
 }

+ 13 - 3
Source/Atomic/Atomic2D/ParticleEmitter2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -92,6 +92,8 @@ public:
     void SetEffect(ParticleEffect2D* effect);
     void SetEffect(ParticleEffect2D* effect);
     /// Set sprite.
     /// Set sprite.
     void SetSprite(Sprite2D* sprite);
     void SetSprite(Sprite2D* sprite);
+    /// Set blend mode.
+    void SetBlendMode(BlendMode blendMode);
     /// Set max particles.
     /// Set max particles.
     void SetMaxParticles(unsigned maxParticles);
     void SetMaxParticles(unsigned maxParticles);
 
 
@@ -99,6 +101,8 @@ public:
     ParticleEffect2D* GetEffect() const;
     ParticleEffect2D* GetEffect() const;
     /// Return sprite.
     /// Return sprite.
     Sprite2D* GetSprite() const;
     Sprite2D* GetSprite() const;
+    /// Return blend mode.
+    BlendMode GetBlendMode() const { return blendMode_; }
     /// Return max particles.
     /// Return max particles.
     unsigned GetMaxParticles() const { return particles_.Size(); }
     unsigned GetMaxParticles() const { return particles_.Size(); }
 
 
@@ -116,8 +120,12 @@ private:
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
     /// Recalculate the world-space bounding box.
     /// Recalculate the world-space bounding box.
     virtual void OnWorldBoundingBoxUpdate();
     virtual void OnWorldBoundingBoxUpdate();
-    /// Update vertices.
-    virtual void UpdateVertices();
+    /// Handle draw order changed.
+    virtual void OnDrawOrderChanged();
+    /// Update source batches.
+    virtual void UpdateSourceBatches();
+    /// Update material.
+    void UpdateMaterial();
     /// Handle scene post update.
     /// Handle scene post update.
     void HandleScenePostUpdate(StringHash eventType, VariantMap& eventData);
     void HandleScenePostUpdate(StringHash eventType, VariantMap& eventData);
     /// Update.
     /// Update.
@@ -131,6 +139,8 @@ private:
     SharedPtr<ParticleEffect2D> effect_;
     SharedPtr<ParticleEffect2D> effect_;
     /// Sprite.
     /// Sprite.
     SharedPtr<Sprite2D> sprite_;
     SharedPtr<Sprite2D> sprite_;
+    /// Blend mode.
+    BlendMode blendMode_;
     /// Num particles.
     /// Num particles.
     int numParticles_;
     int numParticles_;
     /// Emission time.
     /// Emission time.

+ 207 - 210
Source/Atomic/Atomic2D/Renderer2D.cpp

@@ -21,24 +21,25 @@
 //
 //
 
 
 #include "Precompiled.h"
 #include "Precompiled.h"
-#include "../Graphics/Camera.h"
+#include "../Container/Sort.h"
 #include "../Core/Context.h"
 #include "../Core/Context.h"
-#include "../Atomic2D/Drawable2D.h"
+#include "../Core/Profiler.h"
+#include "../Core/WorkQueue.h"
+#include "../Graphics/Camera.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/GraphicsEvents.h"
 #include "../Graphics/GraphicsEvents.h"
 #include "../Graphics/IndexBuffer.h"
 #include "../Graphics/IndexBuffer.h"
-#include "../IO/Log.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/Material.h"
-#include "../Scene/Node.h"
-#include "../Core/Profiler.h"
-#include "../Atomic2D/Renderer2D.h"
-#include "../Scene/Scene.h"
-#include "../Container/Sort.h"
+#include "../Graphics/OctreeQuery.h"
 #include "../Graphics/Technique.h"
 #include "../Graphics/Technique.h"
 #include "../Graphics/Texture2D.h"
 #include "../Graphics/Texture2D.h"
 #include "../Graphics/VertexBuffer.h"
 #include "../Graphics/VertexBuffer.h"
 #include "../Graphics/View.h"
 #include "../Graphics/View.h"
-#include "../Core/WorkQueue.h"
+#include "../IO/Log.h"
+#include "../Scene/Node.h"
+#include "../Scene/Scene.h"
+#include "../Atomic2D/Drawable2D.h"
+#include "../Atomic2D/Renderer2D.h"
 
 
 #include "../DebugNew.h"
 #include "../DebugNew.h"
 
 
@@ -47,15 +48,33 @@ namespace Atomic
 
 
 extern const char* blendModeNames[];
 extern const char* blendModeNames[];
 
 
+static const unsigned MASK_VERTEX2D = MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1;
+
+ViewBatchInfo2D::ViewBatchInfo2D() : vertexBufferUpdateFrameNumber_(0),
+    indexCount_(0),
+    vertexCount_(0),
+    batchUpdatedFrameNumber_(0), 
+    batchCount_(0)
+{
+}
+
 Renderer2D::Renderer2D(Context* context) :
 Renderer2D::Renderer2D(Context* context) :
     Drawable(context, DRAWABLE_GEOMETRY),
     Drawable(context, DRAWABLE_GEOMETRY),
+    material_(new Material(context)),
     indexBuffer_(new IndexBuffer(context_)),
     indexBuffer_(new IndexBuffer(context_)),
-    vertexBuffer_(new VertexBuffer(context_)),
-    orderDirty_(true),
-    frustum_(0),
-    useTris_(false),
-    geometryCount_(0)
+    frustum_(0)
 {
 {
+    material_->SetName("Atomic2D");
+
+    Technique* tech = new Technique(context_);
+    Pass* pass = tech->CreatePass("alpha");
+    pass->SetVertexShader("Atomic2D");
+    pass->SetPixelShader("Atomic2D");
+    pass->SetDepthWrite(false);
+
+    material_->SetTechnique(0, tech);
+    material_->SetCullMode(CULL_NONE);
+
     frame_.frameNumber_ = 0;
     frame_.frameNumber_ = 0;
     SubscribeToEvent(E_BEGINVIEWUPDATE, HANDLER(Renderer2D, HandleBeginViewUpdate));
     SubscribeToEvent(E_BEGINVIEWUPDATE, HANDLER(Renderer2D, HandleBeginViewUpdate));
 }
 }
@@ -69,37 +88,27 @@ void Renderer2D::RegisterObject(Context* context)
     context->RegisterFactory<Renderer2D>();
     context->RegisterFactory<Renderer2D>();
 }
 }
 
 
-static inline bool CompareDrawable2Ds(Drawable2D* lhs, Drawable2D* rhs)
+static inline bool CompareRayQueryResults(RayQueryResult& lr, RayQueryResult& rr)
 {
 {
+    Drawable2D* lhs = static_cast<Drawable2D*>(lr.drawable_);
+    Drawable2D* rhs = static_cast<Drawable2D*>(rr.drawable_);
     if (lhs->GetLayer() != rhs->GetLayer())
     if (lhs->GetLayer() != rhs->GetLayer())
-        return lhs->GetLayer() < rhs->GetLayer();
+        return lhs->GetLayer() > rhs->GetLayer();
 
 
     if (lhs->GetOrderInLayer() != rhs->GetOrderInLayer())
     if (lhs->GetOrderInLayer() != rhs->GetOrderInLayer())
-        return lhs->GetOrderInLayer() < rhs->GetOrderInLayer();
-
-    Material* lhsUsedMaterial = lhs->GetMaterial();
-    Material* rhsUsedMaterial = rhs->GetMaterial();
-    if (lhsUsedMaterial && rhsUsedMaterial && lhsUsedMaterial != rhsUsedMaterial)
-        return lhsUsedMaterial->GetNameHash() < rhsUsedMaterial->GetNameHash();
+        return lhs->GetOrderInLayer() > rhs->GetOrderInLayer();
 
 
-    return lhs->GetID() < rhs->GetID();
+    return lhs->GetID() > rhs->GetID();
 }
 }
 
 
 void Renderer2D::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 void Renderer2D::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
 {
-    if (orderDirty_)
-    {
-        Sort(drawables_.Begin(), drawables_.End(), CompareDrawable2Ds);
-        orderDirty_ = false;
-    }
-
     unsigned resultSize = results.Size();
     unsigned resultSize = results.Size();
-    for (unsigned i = drawables_.Size() - 1; i < drawables_.Size(); --i)
-    {
+    for (unsigned i = 0; i < drawables_.Size(); ++i)
         drawables_[i]->ProcessRayQuery(query, results);
         drawables_[i]->ProcessRayQuery(query, results);
-        if (results.Size() != resultSize)
-            return;
-    }
+
+    if (results.Size() != resultSize)
+        Sort(results.Begin() + resultSize, results.End(), CompareRayQueryResults);
 }
 }
 
 
 void Renderer2D::UpdateBatches(const FrameInfo& frame)
 void Renderer2D::UpdateBatches(const FrameInfo& frame)
@@ -116,36 +125,36 @@ void Renderer2D::UpdateBatches(const FrameInfo& frame)
 
 
 void Renderer2D::UpdateGeometry(const FrameInfo& frame)
 void Renderer2D::UpdateGeometry(const FrameInfo& frame)
 {
 {
-    unsigned& vertexCount = vertexCount_[frame.camera_];
-    unsigned& indexCount = indexCount_[frame.camera_];
+    unsigned indexCount = 0;
+    for (HashMap<Camera*, ViewBatchInfo2D>::ConstIterator i = viewBatchInfos_.Begin(); i != viewBatchInfos_.End(); ++i)
+    {
+        if (i->second_.batchUpdatedFrameNumber_ == frame_.frameNumber_)
+            indexCount = Max((int)indexCount, (int)i->second_.indexCount_);
+    }
 
 
     // Fill index buffer
     // Fill index buffer
     if (indexBuffer_->GetIndexCount() < indexCount || indexBuffer_->IsDataLost())
     if (indexBuffer_->GetIndexCount() < indexCount || indexBuffer_->IsDataLost())
     {
     {
-        bool largeIndices = vertexCount > 0xffff;
+        bool largeIndices = (indexCount * 4 / 6) > 0xffff;
         indexBuffer_->SetSize(indexCount, largeIndices);
         indexBuffer_->SetSize(indexCount, largeIndices);
+
         void* buffer = indexBuffer_->Lock(0, indexCount, true);
         void* buffer = indexBuffer_->Lock(0, indexCount, true);
         if (buffer)
         if (buffer)
         {
         {
-            unsigned quadCount =  useTris_ ? indexCount/3 : indexCount / 6;
+            unsigned quadCount = indexCount / 6;
             if (largeIndices)
             if (largeIndices)
             {
             {
                 unsigned* dest = reinterpret_cast<unsigned*>(buffer);
                 unsigned* dest = reinterpret_cast<unsigned*>(buffer);
                 for (unsigned i = 0; i < quadCount; ++i)
                 for (unsigned i = 0; i < quadCount; ++i)
                 {
                 {
-                    unsigned base = i * (useTris_ ? 3 : 4);
+                    unsigned base = i * 4;
                     dest[0] = base;
                     dest[0] = base;
                     dest[1] = base + 1;
                     dest[1] = base + 1;
                     dest[2] = base + 2;
                     dest[2] = base + 2;
-                    if (!useTris_)
-                    {
-                        dest[3] = base;
-                        dest[4] = base + 2;
-                        dest[5] = base + 3;
-                        dest += 6;
-                    }
-                    else
-                        dest += 3;
+                    dest[3] = base;
+                    dest[4] = base + 2;
+                    dest[5] = base + 3;
+                    dest += 6;
                 }
                 }
             }
             }
             else
             else
@@ -153,19 +162,14 @@ void Renderer2D::UpdateGeometry(const FrameInfo& frame)
                 unsigned short* dest = reinterpret_cast<unsigned short*>(buffer);
                 unsigned short* dest = reinterpret_cast<unsigned short*>(buffer);
                 for (unsigned i = 0; i < quadCount; ++i)
                 for (unsigned i = 0; i < quadCount; ++i)
                 {
                 {
-                    unsigned base = i * (useTris_ ? 3 : 4);
+                    unsigned base = i * 4;
                     dest[0] = (unsigned short)(base);
                     dest[0] = (unsigned short)(base);
                     dest[1] = (unsigned short)(base + 1);
                     dest[1] = (unsigned short)(base + 1);
                     dest[2] = (unsigned short)(base + 2);
                     dest[2] = (unsigned short)(base + 2);
-                    if (!useTris_)
-                    {
-                        dest[3] = (unsigned short)(base);
-                        dest[4] = (unsigned short)(base + 2);
-                        dest[5] = (unsigned short)(base + 3);
-                        dest += 6;
-                    }
-                    else
-                        dest += 3;
+                    dest[3] = (unsigned short)(base);
+                    dest[4] = (unsigned short)(base + 2);
+                    dest[5] = (unsigned short)(base + 3);
+                    dest += 6;
                 }
                 }
             }
             }
 
 
@@ -178,29 +182,37 @@ void Renderer2D::UpdateGeometry(const FrameInfo& frame)
         }
         }
     }
     }
 
 
-    if (vertexBuffer_->GetVertexCount() < vertexCount)
-        vertexBuffer_->SetSize(vertexCount, MASK_VERTEX2D);
+    Camera* camera = frame.camera_;
+    ViewBatchInfo2D& viewBatchInfo = viewBatchInfos_[camera];
 
 
-    if (vertexCount)
-    {
-        Vertex2D* dest = reinterpret_cast<Vertex2D*>(vertexBuffer_->Lock(0, vertexCount, true));
-        if (dest)
+    if (viewBatchInfo.vertexBufferUpdateFrameNumber_ != frame_.frameNumber_)
+    {       
+        unsigned vertexCount = viewBatchInfo.vertexCount_;
+        VertexBuffer* vertexBuffer = viewBatchInfo.vertexBuffer_;
+        if (vertexBuffer->GetVertexCount() < vertexCount)
+            vertexBuffer->SetSize(vertexCount, MASK_VERTEX2D, true);
+
+        if (vertexCount)
         {
         {
-            for (unsigned d = 0; d < drawables_.Size(); ++d)
+            Vertex2D* dest = reinterpret_cast<Vertex2D*>(vertexBuffer->Lock(0, vertexCount, true));
+            if (dest)
             {
             {
-                if (!drawables_[d]->IsInView(frame) || drawables_[d]->GetVertices().Empty())
-                    continue;
+                const PODVector<const SourceBatch2D*>& sourceBatches = viewBatchInfo.sourceBatches_;
+                for (unsigned b = 0; b < sourceBatches.Size(); ++b)
+                {
+                    const Vector<Vertex2D>& vertices = sourceBatches[b]->vertices_;
+                    for (unsigned i = 0; i < vertices.Size(); ++i)
+                        dest[i] = vertices[i];
+                    dest += vertices.Size();
+                }
 
 
-                const Vector<Vertex2D>& vertices = drawables_[d]->GetVertices();
-                for (unsigned i = 0; i < vertices.Size(); ++i)
-                    dest[i] = vertices[i];
-                dest += vertices.Size();
+                vertexBuffer->Unlock();
             }
             }
-
-            vertexBuffer_->Unlock();
+            else
+                LOGERROR("Failed to lock vertex buffer");
         }
         }
-        else
-            LOGERROR("Failed to lock vertex buffer");
+
+        viewBatchInfo.vertexBufferUpdateFrameNumber_ = frame_.frameNumber_;
     }
     }
 }
 }
 
 
@@ -215,9 +227,6 @@ void Renderer2D::AddDrawable(Drawable2D* drawable)
         return;
         return;
 
 
     drawables_.Push(drawable);
     drawables_.Push(drawable);
-    materialDirtyDrawables_.Push(drawable);
-
-    orderDirty_ = true;
 }
 }
 
 
 void Renderer2D::RemoveDrawable(Drawable2D* drawable)
 void Renderer2D::RemoveDrawable(Drawable2D* drawable)
@@ -226,24 +235,33 @@ void Renderer2D::RemoveDrawable(Drawable2D* drawable)
         return;
         return;
 
 
     drawables_.Remove(drawable);
     drawables_.Remove(drawable);
+}
+
+Material* Renderer2D::GetMaterial(Texture2D* texture, BlendMode blendMode)
+{
+    if (!material_)
+        return 0;
+
+    if (!texture)
+        return material_;
 
 
-    // Drawable may be on the dirty list multiple times; remove all instances
-    for (;;)
+    HashMap<Texture2D*, HashMap<int, SharedPtr<Material> > >::Iterator t = cachedMaterials_.Find(texture);
+    if (t == cachedMaterials_.End())
     {
     {
-        PODVector<Drawable2D*>::Iterator i = materialDirtyDrawables_.Find(drawable);
-        if (i != materialDirtyDrawables_.End())
-            materialDirtyDrawables_.Erase(i);
-        else
-            break;
+        SharedPtr<Material> newMaterial = CreateMaterial(texture, blendMode);
+        cachedMaterials_[texture][blendMode] = newMaterial;
+        return newMaterial;
     }
     }
 
 
-    orderDirty_ = true;
-}
+    HashMap<int, SharedPtr<Material> >& materials = t->second_;
+    HashMap<int, SharedPtr<Material> >::Iterator b = materials.Find(blendMode);
+    if (b != materials.End())
+        return b->second_;
 
 
-void Renderer2D::MarkMaterialDirty(Drawable2D* drawable)
-{
-    // Note: this may cause the drawable to appear on the dirty list multiple times
-    materialDirtyDrawables_.Push(drawable);
+    SharedPtr<Material> newMaterial = CreateMaterial(texture, blendMode);
+    materials[blendMode] = newMaterial;
+
+    return newMaterial;
 }
 }
 
 
 bool Renderer2D::CheckVisibility(Drawable2D* drawable) const
 bool Renderer2D::CheckVisibility(Drawable2D* drawable) const
@@ -262,6 +280,17 @@ void Renderer2D::OnWorldBoundingBoxUpdate()
     worldBoundingBox_ = boundingBox_;
     worldBoundingBox_ = boundingBox_;
 }
 }
 
 
+SharedPtr<Material> Renderer2D::CreateMaterial(Texture2D* texture, BlendMode blendMode)
+{
+    SharedPtr<Material> newMaterial = material_->Clone();
+
+    newMaterial->SetName(texture->GetName() + "_" + blendModeNames[blendMode]);
+    newMaterial->SetTexture(TU_DIFFUSE, texture);
+    newMaterial->GetTechnique(0)->GetPass("alpha")->SetBlendMode(blendMode);
+
+    return newMaterial;
+}
+
 void CheckDrawableVisibility(const WorkItem* item, unsigned threadIndex)
 void CheckDrawableVisibility(const WorkItem* item, unsigned threadIndex)
 {
 {
     Renderer2D* renderer = reinterpret_cast<Renderer2D*>(item->aux_);
     Renderer2D* renderer = reinterpret_cast<Renderer2D*>(item->aux_);
@@ -271,7 +300,7 @@ void CheckDrawableVisibility(const WorkItem* item, unsigned threadIndex)
     while (start != end)
     while (start != end)
     {
     {
         Drawable2D* drawable = *start++;
         Drawable2D* drawable = *start++;
-        if (renderer->CheckVisibility(drawable) && drawable->GetVertices().Size())
+        if (renderer->CheckVisibility(drawable))
             drawable->MarkInView(renderer->frame_);
             drawable->MarkInView(renderer->frame_);
     }
     }
 }
 }
@@ -280,35 +309,14 @@ void Renderer2D::HandleBeginViewUpdate(StringHash eventType, VariantMap& eventDa
 {
 {
     using namespace BeginViewUpdate;
     using namespace BeginViewUpdate;
 
 
-    Scene* scene = GetScene();
     // Check that we are updating the correct scene
     // Check that we are updating the correct scene
-    if (scene != eventData[P_SCENE].GetPtr())
+    if (GetScene() != eventData[P_SCENE].GetPtr())
         return;
         return;
-    unsigned lastFrameNumber = frame_.frameNumber_;
+
     frame_ = static_cast<View*>(eventData[P_VIEW].GetPtr())->GetFrameInfo();
     frame_ = static_cast<View*>(eventData[P_VIEW].GetPtr())->GetFrameInfo();
-    // Reset geometry use when new frame started
-    if (frame_.frameNumber_ != lastFrameNumber)
-        geometryCount_ = 0;
 
 
     PROFILE(UpdateRenderer2D);
     PROFILE(UpdateRenderer2D);
 
 
-    if (!materialDirtyDrawables_.Empty())
-    {
-        for (unsigned i = 0; i < materialDirtyDrawables_.Size(); ++i)
-        {
-            Drawable2D* drawable = materialDirtyDrawables_[i];
-            if (!drawable->GetMaterial())
-                drawable->SetMaterial(GetMaterial(drawable->GetTexture(), drawable->GetBlendMode()));
-        }
-        materialDirtyDrawables_.Clear();
-    }
-
-    if (orderDirty_)
-    {
-        Sort(drawables_.Begin(), drawables_.End(), CompareDrawable2Ds);
-        orderDirty_ = false;
-    }
-
     Camera* camera = static_cast<Camera*>(eventData[P_CAMERA].GetPtr());
     Camera* camera = static_cast<Camera*>(eventData[P_CAMERA].GetPtr());
     frustum_ = &camera->GetFrustum();
     frustum_ = &camera->GetFrustum();
     if (camera->IsOrthographic() && camera->GetNode()->GetWorldDirection() == Vector3::FORWARD)
     if (camera->IsOrthographic() && camera->GetNode()->GetWorldDirection() == Vector3::FORWARD)
@@ -348,59 +356,24 @@ void Renderer2D::HandleBeginViewUpdate(StringHash eventType, VariantMap& eventDa
         queue->Complete(M_MAX_UNSIGNED);
         queue->Complete(M_MAX_UNSIGNED);
     }
     }
 
 
+    ViewBatchInfo2D& viewBatchInfo = viewBatchInfos_[camera];
+    
+    // Create vertex buffer
+    if (!viewBatchInfo.vertexBuffer_)
+        viewBatchInfo.vertexBuffer_ = new VertexBuffer(context_);
+
+    UpdateViewBatchInfo(viewBatchInfo, camera);
+
     // Go through the drawables to form geometries & batches and calculate the total vertex / index count,
     // Go through the drawables to form geometries & batches and calculate the total vertex / index count,
     // but upload the actual vertex data later. The idea is that the View class copies our batch vector to
     // but upload the actual vertex data later. The idea is that the View class copies our batch vector to
     // its internal data structures, so we can reuse the batches for each view, provided that unique Geometry
     // its internal data structures, so we can reuse the batches for each view, provided that unique Geometry
     // objects are used for each view to specify the draw ranges
     // objects are used for each view to specify the draw ranges
-    batches_.Clear();
-    Material* material = 0;
-    unsigned iStart = 0;
-    unsigned iCount = 0;
-    unsigned vStart = 0;
-    unsigned vCount = 0;
-    unsigned& vTotal = vertexCount_[frame_.camera_];
-    unsigned& iTotal = indexCount_[frame_.camera_];
-    vTotal = 0;
-    iTotal = 0;
-
-    for (unsigned d = 0; d < drawables_.Size(); ++d)
+    batches_.Resize(viewBatchInfo.batchCount_);
+    for (unsigned i = 0; i < viewBatchInfo.batchCount_; ++i)
     {
     {
-        if (!drawables_[d]->IsInView(frame_))
-            continue;
-
-        Material* usedMaterial = drawables_[d]->GetMaterial();
-        const Vector<Vertex2D>& vertices = drawables_[d]->GetVertices();
-
-        // When new material encountered, finish the current batch and start new
-        if (material != usedMaterial)
-        {
-            if (material)
-            {
-                AddBatch(material, iStart, iCount, vStart, vCount);
-                iStart += iCount;
-                iCount = 0;
-                vStart += vCount;
-                vCount = 0;
-            }
-
-            material = usedMaterial;
-        }
-
-        unsigned indices;
-        if (useTris_)
-            indices = vertices.Size();
-        else
-            indices = vertices.Size() / 4 * 6;
-
-        iCount += indices;
-        iTotal += indices;
-        vCount += vertices.Size();
-        vTotal += vertices.Size();
+        batches_[i].material_ = viewBatchInfo.materials_[i];
+        batches_[i].geometry_ = viewBatchInfo.geometries_[i];
     }
     }
-
-    // Add the final batch if necessary
-    if (material && vCount)
-        AddBatch(material, iStart, iCount, vStart, vCount);
 }
 }
 
 
 void Renderer2D::GetDrawables(PODVector<Drawable2D*>& dest, Node* node)
 void Renderer2D::GetDrawables(PODVector<Drawable2D*>& dest, Node* node)
@@ -421,79 +394,103 @@ void Renderer2D::GetDrawables(PODVector<Drawable2D*>& dest, Node* node)
         GetDrawables(dest, i->Get());
         GetDrawables(dest, i->Get());
 }
 }
 
 
-Material* Renderer2D::GetMaterial(Texture2D* texture, BlendMode blendMode)
+static inline bool CompareSourceBatch2Ds(const SourceBatch2D* lhs, const SourceBatch2D* rhs)
 {
 {
-    HashMap<Texture2D*, HashMap<int, SharedPtr<Material> > >::Iterator t = cachedMaterials_.Find(texture);
-    if (t == cachedMaterials_.End())
-    {
-        SharedPtr<Material> material(CreateMaterial(texture, blendMode));
-        cachedMaterials_[texture][blendMode] = material;
-        return material;
-    }
-
-    HashMap<int, SharedPtr<Material> >& materials = t->second_;
-    HashMap<int, SharedPtr<Material> >::Iterator b = materials.Find(blendMode);
-    if (b != materials.End())
-        return b->second_;
+    if (lhs->drawOrder_ != rhs->drawOrder_)
+        return lhs->drawOrder_ < rhs->drawOrder_;
 
 
-    SharedPtr<Material> material(CreateMaterial(texture, blendMode));
-    materials[blendMode] = material;
+    if (lhs->material_ != rhs->material_)
+        return lhs->material_->GetNameHash() < rhs->material_->GetNameHash();
 
 
-    return material;
+    return lhs < rhs;
 }
 }
 
 
-Material* Renderer2D::CreateMaterial(Texture2D* texture, BlendMode blendMode)
+void Renderer2D::UpdateViewBatchInfo(ViewBatchInfo2D& viewBatchInfo, Camera* camera)
 {
 {
-    Material* material = new Material(context_);
-    if (texture)
-        material->SetName(texture->GetName() + "_" + blendModeNames[blendMode]);
-    else
-        material->SetName(blendModeNames[blendMode]);
+    // Already update in same frame
+    if (viewBatchInfo.batchUpdatedFrameNumber_ == frame_.frameNumber_)
+        return;
 
 
-    Technique* tech = new Technique(context_);
-    Pass* pass = tech->CreatePass(PASS_ALPHA);
-    pass->SetBlendMode(blendMode);
+    PODVector<const SourceBatch2D*>& soruceBatches = viewBatchInfo.sourceBatches_;
+    soruceBatches.Clear();
+    for (unsigned d = 0; d < drawables_.Size(); ++d)
+    {
+        if (!drawables_[d]->IsInView(camera))
+            continue;
 
 
-    pass->SetVertexShader("Atomic2D");
-    pass->SetPixelShader("Atomic2D");
+        const Vector<SourceBatch2D>& batches = drawables_[d]->GetSourceBatches();
+        for (unsigned b = 0; b < batches.Size(); ++b)
+        {
+            if (batches[b].material_ && !batches[b].vertices_.Empty())
+                soruceBatches.Push(&batches[b]);
+        }
+    }
 
 
-    pass->SetDepthWrite(false);
+    Sort(soruceBatches.Begin(), soruceBatches.End(), CompareSourceBatch2Ds);
+
+    viewBatchInfo.batchCount_ = 0;
+    Material* currMaterial = 0;
+    unsigned iStart = 0;
+    unsigned iCount = 0;
+    unsigned vStart = 0;
+    unsigned vCount = 0;
+
+    for (unsigned b = 0; b < soruceBatches.Size(); ++b)
+    {
+        Material* material = soruceBatches[b]->material_;
+        const Vector<Vertex2D>& vertices = soruceBatches[b]->vertices_;
+
+        // When new material encountered, finish the current batch and start new
+        if (currMaterial != material)
+        {
+            if (currMaterial)
+            {
+                AddViewBatch(viewBatchInfo, currMaterial, iStart, iCount, vStart, vCount);
+                iStart += iCount;
+                iCount = 0;
+                vStart += vCount;
+                vCount = 0;
+            }
 
 
-    material->SetTechnique(0, tech);
-    material->SetCullMode(CULL_NONE);
+            currMaterial = material;
+        }
 
 
-    material->SetTexture(TU_DIFFUSE, texture);
+        iCount += vertices.Size() * 6 / 4;
+        vCount += vertices.Size();
+    }
+
+    // Add the final batch if necessary
+    if (currMaterial && vCount)
+        AddViewBatch(viewBatchInfo, currMaterial, iStart, iCount, vStart, vCount);
 
 
-    return material;
+    viewBatchInfo.indexCount_ = iStart + iCount;
+    viewBatchInfo.vertexCount_ = vStart + vCount;
+    viewBatchInfo.batchUpdatedFrameNumber_ = frame_.frameNumber_;
 }
 }
 
 
-void Renderer2D::AddBatch(Material* material, unsigned indexStart, unsigned indexCount, unsigned vertexStart, unsigned vertexCount)
+void Renderer2D::AddViewBatch(ViewBatchInfo2D& viewBatchInfo, Material* material, unsigned indexStart, unsigned indexCount, unsigned vertexStart, unsigned vertexCount)
 {
 {
     if (!material || indexCount == 0 || vertexCount == 0)
     if (!material || indexCount == 0 || vertexCount == 0)
         return;
         return;
 
 
+    if (viewBatchInfo.materials_.Size() <= viewBatchInfo.batchCount_)
+        viewBatchInfo.materials_.Resize(viewBatchInfo.batchCount_ + 1);
+    viewBatchInfo.materials_[viewBatchInfo.batchCount_] = material;
+
     // Allocate new geometry if necessary
     // Allocate new geometry if necessary
-    if (geometries_.Size() <= geometryCount_)
+    if (viewBatchInfo.geometries_.Size() <= viewBatchInfo.batchCount_)
     {
     {
         SharedPtr<Geometry> geometry(new Geometry(context_));
         SharedPtr<Geometry> geometry(new Geometry(context_));
         geometry->SetIndexBuffer(indexBuffer_);
         geometry->SetIndexBuffer(indexBuffer_);
-        geometry->SetVertexBuffer(0, vertexBuffer_, MASK_VERTEX2D);
-        geometries_.Push(geometry);
-    }
+        geometry->SetVertexBuffer(0, viewBatchInfo.vertexBuffer_, MASK_VERTEX2D);
 
 
-    geometries_[geometryCount_]->SetDrawRange(TRIANGLE_LIST, indexStart, indexCount, vertexStart, vertexCount, false);
-
-    batches_.Resize(batches_.Size() + 1);
-    SourceBatch& batch = batches_.Back();
-    batch.geometry_ = geometries_[geometryCount_];
-    batch.material_ = material;
+        viewBatchInfo.geometries_.Push(geometry);
+    }
 
 
-    ++geometryCount_;
-}
+    Geometry* geometry = viewBatchInfo.geometries_[viewBatchInfo.batchCount_];
+    geometry->SetDrawRange(TRIANGLE_LIST, indexStart, indexCount, vertexStart, vertexCount, false);
 
 
-void Renderer2D::SetUseTris(bool tris)
-{
-    useTris_ = tris;
+    viewBatchInfo.batchCount_++;
 }
 }
 
 
 }
 }

+ 41 - 29
Source/Atomic/Atomic2D/Renderer2D.h

@@ -32,6 +32,33 @@ class IndexBuffer;
 class Material;
 class Material;
 class VertexBuffer;
 class VertexBuffer;
 struct FrameInfo;
 struct FrameInfo;
+struct SourceBatch2D;
+
+/// 2D view batch info.
+struct ViewBatchInfo2D
+{
+    /// Construct.
+    ViewBatchInfo2D();
+
+    /// Vertex buffer update frame number.
+    unsigned vertexBufferUpdateFrameNumber_;
+    /// Index count.
+    unsigned indexCount_;
+    /// Vertex count.
+    unsigned vertexCount_;
+    /// Vertex buffer.
+    SharedPtr<VertexBuffer> vertexBuffer_;
+    /// Batch updated frame number.
+    unsigned batchUpdatedFrameNumber_;
+    /// Source batches.
+    PODVector<const SourceBatch2D*> sourceBatches_;
+    /// Batch count;
+    unsigned batchCount_;
+    /// Materials.
+    Vector<SharedPtr<Material> > materials_;
+    /// Geometries.
+    Vector<SharedPtr<Geometry> > geometries_;
+};
 
 
 /// 2D renderer components.
 /// 2D renderer components.
 class ATOMIC_API Renderer2D : public Drawable
 class ATOMIC_API Renderer2D : public Drawable
@@ -61,57 +88,42 @@ public:
     void AddDrawable(Drawable2D* drawable);
     void AddDrawable(Drawable2D* drawable);
     /// Remove Drawable2D.
     /// Remove Drawable2D.
     void RemoveDrawable(Drawable2D* drawable);
     void RemoveDrawable(Drawable2D* drawable);
-    /// Mark material dirty.
-    void MarkMaterialDirty(Drawable2D* drawable);
-    /// Mark order dirty.
-    void MarkOrderDirty(){ orderDirty_ = true; }
+    /// Return material by texture and blend mode.
+    Material* GetMaterial(Texture2D* texture, BlendMode blendMode);
+
     /// Check visibility.
     /// Check visibility.
     bool CheckVisibility(Drawable2D* drawable) const;
     bool CheckVisibility(Drawable2D* drawable) const;
 
 
-    void SetUseTris(bool tris);
-
 private:
 private:
     /// Recalculate the world-space bounding box.
     /// Recalculate the world-space bounding box.
     virtual void OnWorldBoundingBoxUpdate();
     virtual void OnWorldBoundingBoxUpdate();
+    /// Create material by texture and blend mode.
+    SharedPtr<Material> CreateMaterial(Texture2D* texture, BlendMode blendMode);
     /// Handle view update begin event. Determine Drawable2D's and their batches here.
     /// Handle view update begin event. Determine Drawable2D's and their batches here.
     void HandleBeginViewUpdate(StringHash eventType, VariantMap& eventData);
     void HandleBeginViewUpdate(StringHash eventType, VariantMap& eventData);
     /// Get all drawables in node.
     /// Get all drawables in node.
     void GetDrawables(PODVector<Drawable2D*>& drawables, Node* node);
     void GetDrawables(PODVector<Drawable2D*>& drawables, Node* node);
-    /// Return material by texture and blend mode.
-    Material* GetMaterial(Texture2D* texture, BlendMode blendMode);
-    /// Create new material by texture and blend mode.
-    Material* CreateMaterial(Texture2D* Texture, BlendMode blendMode);
-    /// Add batch.
-    void AddBatch(Material* material, unsigned indexStart, unsigned indexCount, unsigned vertexStart, unsigned vertexCount);
+    /// Update view batch info.
+    void UpdateViewBatchInfo(ViewBatchInfo2D& viewBatchInfo, Camera* camera);
+    /// Add view batch.
+    void AddViewBatch(ViewBatchInfo2D& viewBatchInfo, Material* material, unsigned indexStart, unsigned indexCount, unsigned vertexStart, unsigned vertexCount);
 
 
     /// Index buffer.
     /// Index buffer.
     SharedPtr<IndexBuffer> indexBuffer_;
     SharedPtr<IndexBuffer> indexBuffer_;
-    /// Vertex buffer.
-    SharedPtr<VertexBuffer> vertexBuffer_;
+    /// Material.
+    SharedPtr<Material> material_;
     /// Drawables.
     /// Drawables.
     PODVector<Drawable2D*> drawables_;
     PODVector<Drawable2D*> drawables_;
-    /// Material dirty drawables.
-    PODVector<Drawable2D*> materialDirtyDrawables_;
-    /// Order dirty.
-    bool orderDirty_;
-    /// View frameinfo for current frame.
+    /// View frame info for current frame.
     FrameInfo frame_;
     FrameInfo frame_;
-    /// Used geometry count. Shared by all views and reset when a new frame begins.
-    unsigned geometryCount_;
-    /// Vertex count by view.
-    HashMap<Camera*, unsigned> vertexCount_;
-    /// Index count by view.
-    HashMap<Camera*, unsigned> indexCount_;
-    /// Geometries used in all views.
-    Vector<SharedPtr<Geometry> > geometries_;
+    /// View batch info.
+    HashMap<Camera*, ViewBatchInfo2D> viewBatchInfos_;
     /// Frustum for current frame.
     /// Frustum for current frame.
     const Frustum* frustum_;
     const Frustum* frustum_;
     /// Frustum bounding box for current frame.
     /// Frustum bounding box for current frame.
     BoundingBox frustumBoundingBox_;
     BoundingBox frustumBoundingBox_;
     /// Cached materials.
     /// Cached materials.
     HashMap<Texture2D*, HashMap<int, SharedPtr<Material> > > cachedMaterials_;
     HashMap<Texture2D*, HashMap<int, SharedPtr<Material> > > cachedMaterials_;
-
-    bool useTris_;
 };
 };
 
 
 }
 }

+ 56 - 1
Source/Atomic/Atomic2D/Sprite2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -24,6 +24,7 @@
 #include "../Core/Context.h"
 #include "../Core/Context.h"
 #include "../IO/Deserializer.h"
 #include "../IO/Deserializer.h"
 #include "../Resource/ResourceCache.h"
 #include "../Resource/ResourceCache.h"
+#include "../Atomic2D/Drawable2D.h"
 #include "../Atomic2D/Sprite2D.h"
 #include "../Atomic2D/Sprite2D.h"
 #include "../Atomic2D/SpriteSheet2D.h"
 #include "../Atomic2D/SpriteSheet2D.h"
 #include "../Graphics/Texture2D.h"
 #include "../Graphics/Texture2D.h"
@@ -126,6 +127,60 @@ void Sprite2D::SetSpriteSheet(SpriteSheet2D* spriteSheet)
     spriteSheet_ = spriteSheet;
     spriteSheet_ = spriteSheet;
 }
 }
 
 
+bool Sprite2D::GetDrawRectangle(Rect& rect, bool flipX, bool flipY) const
+{
+    return GetDrawRectangle(rect, hotSpot_, flipX, flipY);
+}
+
+bool Sprite2D::GetDrawRectangle(Rect& rect, const Vector2& hotSpot, bool flipX, bool flipY) const
+{
+    if (rectangle_.Width() == 0 || rectangle_.Height() == 0)
+        return false;
+
+    float width = (float)rectangle_.Width() * PIXEL_SIZE;
+    float height = (float)rectangle_.Height() * PIXEL_SIZE;        
+
+    float hotSpotX = flipX ? (1.0f - hotSpot.x_) : hotSpot.x_;
+    float hotSpotY = flipY ? (1.0f - hotSpot.y_) : hotSpot.y_;
+
+#ifdef ATOMIC_OPENGL
+    rect.min_.x_ = -width * hotSpotX;
+    rect.max_.x_ = width * (1.0f - hotSpotX);
+    rect.min_.y_ = -height * hotSpotY;
+    rect.max_.y_ = height * (1.0f - hotSpotY);
+#else
+    const float halfPixelOffset = 0.5f * PIXEL_SIZE;
+    rect.min_.x_ = -width * hotSpotX + halfPixelOffset;
+    rect.max_.x_ = width * (1.0f - hotSpotX) + halfPixelOffset;
+    rect.min_.y_ = -height * hotSpotY + halfPixelOffset;
+    rect.max_.y_ = height * (1.0f - hotSpotY) + halfPixelOffset;
+#endif
+    return true;
+}
+
+bool Sprite2D::GetTextureRectangle(Rect& rect, bool flipX, bool flipY) const
+{
+    if (!texture_)
+        return false;
+
+    float invWidth = 1.0f / (float)texture_->GetWidth();
+    float invHeight = 1.0f / (float)texture_->GetHeight();
+
+    rect.min_.x_ = rectangle_.left_ * invWidth;
+    rect.max_.x_ = rectangle_.right_ * invWidth;
+
+    rect.min_.y_ = rectangle_.bottom_ * invHeight;
+    rect.max_.y_ = rectangle_.top_ * invHeight;
+
+    if (flipX)
+        Swap(rect.min_.x_, rect.max_.x_);
+    
+    if (flipY)
+        Swap(rect.min_.y_, rect.max_.y_);
+
+    return true;
+}
+
 ResourceRef Sprite2D::SaveToResourceRef(Sprite2D* sprite)
 ResourceRef Sprite2D::SaveToResourceRef(Sprite2D* sprite)
 {
 {
     SpriteSheet2D* spriteSheet = 0;
     SpriteSheet2D* spriteSheet = 0;

+ 8 - 1
Source/Atomic/Atomic2D/Sprite2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -70,6 +70,13 @@ public:
     /// Return sprite sheet.
     /// Return sprite sheet.
     SpriteSheet2D* GetSpriteSheet() const { return spriteSheet_; }
     SpriteSheet2D* GetSpriteSheet() const { return spriteSheet_; }
 
 
+    /// Return draw rectangle.
+    bool GetDrawRectangle(Rect& rect, bool flipX = false, bool flipY = false) const;
+    /// Return draw rectangle with custom hot spot.
+    bool GetDrawRectangle(Rect& rect, const Vector2& hotSpot, bool flipX = false, bool flipY = false) const;
+    /// Return texture rectangle.
+    bool GetTextureRectangle(Rect& rect, bool flipX = false, bool flipY = false) const;
+
     /// Save sprite to ResourceRef.
     /// Save sprite to ResourceRef.
     static ResourceRef SaveToResourceRef(Sprite2D* sprite);
     static ResourceRef SaveToResourceRef(Sprite2D* sprite);
     /// Load sprite from ResourceRef.
     /// Load sprite from ResourceRef.

+ 109 - 83
Source/Atomic/Atomic2D/StaticSprite2D.cpp

@@ -22,10 +22,13 @@
 
 
 #include "Precompiled.h"
 #include "Precompiled.h"
 #include "../Core/Context.h"
 #include "../Core/Context.h"
+#include "../Graphics/Material.h"
+#include "../Graphics/Texture2D.h"
+#include "../Resource/ResourceCache.h"
 #include "../Scene/Scene.h"
 #include "../Scene/Scene.h"
+#include "../Atomic2D/Renderer2D.h"
 #include "../Atomic2D/Sprite2D.h"
 #include "../Atomic2D/Sprite2D.h"
 #include "../Atomic2D/StaticSprite2D.h"
 #include "../Atomic2D/StaticSprite2D.h"
-#include "../Graphics/Texture2D.h"
 
 
 #include "../DebugNew.h"
 #include "../DebugNew.h"
 
 
@@ -33,16 +36,18 @@ namespace Atomic
 {
 {
 
 
 extern const char* ATOMIC2D_CATEGORY;
 extern const char* ATOMIC2D_CATEGORY;
+extern const char* blendModeNames[];
 
 
 StaticSprite2D::StaticSprite2D(Context* context) :
 StaticSprite2D::StaticSprite2D(Context* context) :
     Drawable2D(context),
     Drawable2D(context),
+    blendMode_(BLEND_ALPHA),
     flipX_(false),
     flipX_(false),
     flipY_(false),
     flipY_(false),
     color_(Color::WHITE),
     color_(Color::WHITE),
     useHotSpot_(false),
     useHotSpot_(false),
     hotSpot_(0.5f, 0.5f)
     hotSpot_(0.5f, 0.5f)
 {
 {
-    vertices_.Reserve(6);
+    sourceBatches_.Resize(1);
 }
 }
 
 
 StaticSprite2D::~StaticSprite2D()
 StaticSprite2D::~StaticSprite2D()
@@ -54,11 +59,13 @@ void StaticSprite2D::RegisterObject(Context* context)
     context->RegisterFactory<StaticSprite2D>(ATOMIC2D_CATEGORY);
     context->RegisterFactory<StaticSprite2D>(ATOMIC2D_CATEGORY);
 
 
     ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
+    COPY_BASE_ATTRIBUTES(Drawable2D);
     MIXED_ACCESSOR_ATTRIBUTE("Sprite", GetSpriteAttr, SetSpriteAttr, ResourceRef, ResourceRef(Sprite2D::GetTypeStatic()), AM_DEFAULT);
     MIXED_ACCESSOR_ATTRIBUTE("Sprite", GetSpriteAttr, SetSpriteAttr, ResourceRef, ResourceRef(Sprite2D::GetTypeStatic()), AM_DEFAULT);
+    ENUM_ACCESSOR_ATTRIBUTE("Blend Mode", GetBlendMode, SetBlendMode, BlendMode, blendModeNames, BLEND_ALPHA, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Flip X", GetFlipX, SetFlipX, bool, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Flip X", GetFlipX, SetFlipX, bool, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Flip Y", GetFlipY, SetFlipY, bool, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Flip Y", GetFlipY, SetFlipY, bool, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Color", GetColor, SetColor, Color, Color::WHITE, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Color", GetColor, SetColor, Color, Color::WHITE, AM_DEFAULT);
-    COPY_BASE_ATTRIBUTES(Drawable2D);
+    MIXED_ACCESSOR_ATTRIBUTE("Custom material", GetCustomMaterialAttr, SetCustomMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
 }
 }
 
 
 void StaticSprite2D::SetSprite(Sprite2D* sprite)
 void StaticSprite2D::SetSprite(Sprite2D* sprite)
@@ -67,11 +74,21 @@ void StaticSprite2D::SetSprite(Sprite2D* sprite)
         return;
         return;
 
 
     sprite_ = sprite;
     sprite_ = sprite;
-    if (sprite)
-        verticesDirty_ = true;
+    UpdateMaterial();
 
 
+    sourceBatchesDirty_ = true;
+    MarkNetworkUpdate();
+}
 
 
-    SetTexture(sprite_ ? sprite_->GetTexture() : 0);
+void StaticSprite2D::SetBlendMode(BlendMode blendMode)
+{
+    if (blendMode == blendMode_)
+        return;
+
+    blendMode_ = blendMode;
+
+    UpdateMaterial();
+    MarkNetworkUpdate();
 }
 }
 
 
 void StaticSprite2D::SetFlip(bool flipX, bool flipY)
 void StaticSprite2D::SetFlip(bool flipX, bool flipY)
@@ -81,7 +98,7 @@ void StaticSprite2D::SetFlip(bool flipX, bool flipY)
 
 
     flipX_ = flipX;
     flipX_ = flipX;
     flipY_ = flipY;
     flipY_ = flipY;
-    verticesDirty_ = true;
+    sourceBatchesDirty_ = true;
 
 
     OnFlipChanged();
     OnFlipChanged();
 
 
@@ -104,7 +121,7 @@ void StaticSprite2D::SetColor(const Color& color)
         return;
         return;
 
 
     color_ = color;
     color_ = color;
-    verticesDirty_ = true;
+    sourceBatchesDirty_ = true;
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -114,7 +131,7 @@ void StaticSprite2D::SetAlpha(float alpha)
         return;
         return;
 
 
     color_.a_ = alpha;
     color_.a_ = alpha;
-    verticesDirty_ = true;
+    sourceBatchesDirty_ = true;
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -124,7 +141,7 @@ void StaticSprite2D::SetUseHotSpot(bool useHotSpot)
         return;
         return;
 
 
     useHotSpot_ = useHotSpot;
     useHotSpot_ = useHotSpot;
-    verticesDirty_ = true;
+    sourceBatchesDirty_ = true;
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -137,16 +154,34 @@ void StaticSprite2D::SetHotSpot(const Vector2& hotspot)
 
 
     if (useHotSpot_)
     if (useHotSpot_)
     {
     {
-        verticesDirty_ = true;
+        sourceBatchesDirty_ = true;
         MarkNetworkUpdate();
         MarkNetworkUpdate();
     }
     }
 }
 }
 
 
+void StaticSprite2D::SetCustomMaterial(Material* customMaterial)
+{
+    if (customMaterial == customMaterial_)
+        return;
+
+    customMaterial_ = customMaterial;
+    sourceBatchesDirty_ = true;
+
+    UpdateMaterial();
+    MarkNetworkUpdate();
+}
+
 Sprite2D* StaticSprite2D::GetSprite() const
 Sprite2D* StaticSprite2D::GetSprite() const
 {
 {
     return sprite_;
     return sprite_;
 }
 }
 
 
+
+Material* StaticSprite2D::GetCustomMaterial() const
+{
+    return customMaterial_;
+}
+
 void StaticSprite2D::SetSpriteAttr(const ResourceRef& value)
 void StaticSprite2D::SetSpriteAttr(const ResourceRef& value)
 {
 {
     Sprite2D* sprite = Sprite2D::LoadFromResourceRef(this, value);
     Sprite2D* sprite = Sprite2D::LoadFromResourceRef(this, value);
@@ -159,6 +194,17 @@ ResourceRef StaticSprite2D::GetSpriteAttr() const
     return Sprite2D::SaveToResourceRef(sprite_);
     return Sprite2D::SaveToResourceRef(sprite_);
 }
 }
 
 
+void StaticSprite2D::SetCustomMaterialAttr(const ResourceRef& value)
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    SetCustomMaterial(cache->GetResource<Material>(value.name_));
+}
+
+ResourceRef StaticSprite2D::GetCustomMaterialAttr() const
+{
+    return GetResourceRef(customMaterial_, Material::GetTypeStatic());
+}
+
 void StaticSprite2D::OnWorldBoundingBoxUpdate()
 void StaticSprite2D::OnWorldBoundingBoxUpdate()
 {
 {
     boundingBox_.Clear();
     boundingBox_.Clear();
@@ -185,21 +231,38 @@ void StaticSprite2D::OnWorldBoundingBoxUpdate()
     worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
     worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
 }
 }
 
 
-void StaticSprite2D::UpdateVertices()
+void StaticSprite2D::OnDrawOrderChanged()
 {
 {
-    if (!verticesDirty_)
+    sourceBatches_[0].drawOrder_ = GetDrawOrder();
+}
+
+void StaticSprite2D::UpdateSourceBatches()
+{
+    if (!sourceBatchesDirty_)
         return;
         return;
 
 
-    vertices_.Clear();
+    Vector<Vertex2D>& vertices = sourceBatches_[0].vertices_;
+    vertices.Clear();
 
 
-    Texture2D* texture = GetTexture();
-    if (!texture)
+    if (!sprite_)
         return;
         return;
 
 
-    const IntRect& rectangle_ = sprite_->GetRectangle();
-    if (rectangle_.Width() == 0 || rectangle_.Height() == 0)
-        return;
+    Rect drawRect;
+    if (useHotSpot_)
+    {
+        if (!sprite_->GetDrawRectangle(drawRect, hotSpot_, flipX_, flipY_))
+            return;
+    }
+    else
+    {
+        if (!sprite_->GetDrawRectangle(drawRect, flipX_, flipY_))
+            return;
+    }
 
 
+    Rect textureRect;
+    if (!sprite_->GetTextureRectangle(textureRect, flipX_, flipY_))
+        return;
+    
     /*
     /*
     V1---------V2
     V1---------V2
     |         / |
     |         / |
@@ -214,76 +277,26 @@ void StaticSprite2D::UpdateVertices()
     Vertex2D vertex2;
     Vertex2D vertex2;
     Vertex2D vertex3;
     Vertex2D vertex3;
 
 
-    float width = (float)rectangle_.Width() * PIXEL_SIZE;     // Compute width and height in pixels
-    float height = (float)rectangle_.Height() * PIXEL_SIZE;
-
-    float hotSpotX;
-    float hotSpotY;
-
-    if (useHotSpot_)
-    {
-        hotSpotX = flipX_ ? (1.0f - hotSpot_.x_) : hotSpot_.x_;
-        hotSpotY = flipY_ ? (1.0f - hotSpot_.y_) : hotSpot_.y_;
-    }
-    else
-    {
-        const Vector2& hotSpot = sprite_->GetHotSpot();
-        hotSpotX = flipX_ ? (1.0f - hotSpot.x_) : hotSpot.x_;
-        hotSpotY = flipY_ ? (1.0f - hotSpot.y_) : hotSpot.y_;
-    }
-
-#ifdef ATOMIC_OPENGL
-    float leftX = -width * hotSpotX;
-    float rightX = width * (1.0f - hotSpotX);
-    float bottomY = -height * hotSpotY;
-    float topY = height * (1.0f - hotSpotY);
-#else
-    const float halfPixelOffset = 0.5f * PIXEL_SIZE;
-    float leftX = -width * hotSpotX + halfPixelOffset;
-    float rightX = width * (1.0f - hotSpotX) + halfPixelOffset;
-    float bottomY = -height * hotSpotY + halfPixelOffset;
-    float topY = height * (1.0f - hotSpotY) + halfPixelOffset;
-#endif
-
+    // Convert to world space
     const Matrix3x4& worldTransform = node_->GetWorldTransform();
     const Matrix3x4& worldTransform = node_->GetWorldTransform();
+    vertex0.position_ = worldTransform * Vector3(drawRect.min_.x_, drawRect.min_.y_, 0.0f);
+    vertex1.position_ = worldTransform * Vector3(drawRect.min_.x_, drawRect.max_.y_, 0.0f);
+    vertex2.position_ = worldTransform * Vector3(drawRect.max_.x_, drawRect.max_.y_, 0.0f);
+    vertex3.position_ = worldTransform * Vector3(drawRect.max_.x_, drawRect.min_.y_, 0.0f);
 
 
-    vertex0.position_ = worldTransform * Vector3(leftX, bottomY, 0.0f);
-    vertex1.position_ = worldTransform * Vector3(leftX, topY, 0.0f);
-    vertex2.position_ = worldTransform * Vector3(rightX, topY, 0.0f);
-    vertex3.position_ = worldTransform * Vector3(rightX, bottomY, 0.0f);
-
-    float invTexW = 1.0f / (float)texture->GetWidth();
-    float invTexH = 1.0f / (float)texture->GetHeight();
-
-    float leftU = rectangle_.left_ * invTexW;
-    float rightU = rectangle_.right_ * invTexW;
-    float topV = rectangle_.top_ * invTexH;
-    float bottomV = rectangle_.bottom_ * invTexH;
-    vertex0.uv_ = Vector2(leftU, bottomV);
-    vertex1.uv_ = Vector2(leftU, topV);
-    vertex2.uv_ = Vector2(rightU, topV);
-    vertex3.uv_ = Vector2(rightU, bottomV);
-
-    if (flipX_)
-    {
-        Swap(vertex0.uv_.x_, vertex3.uv_.x_);
-        Swap(vertex1.uv_.x_, vertex2.uv_.x_);
-    }
-    
-    if (flipY_)
-    {
-        Swap(vertex0.uv_.y_, vertex1.uv_.y_);
-        Swap(vertex2.uv_.y_, vertex3.uv_.y_);
-    }
+    vertex0.uv_ = textureRect.min_;
+    vertex1.uv_ = Vector2(textureRect.min_.x_, textureRect.max_.y_);
+    vertex2.uv_ = textureRect.max_;
+    vertex3.uv_ = Vector2(textureRect.max_.x_, textureRect.min_.y_);
 
 
     vertex0.color_ = vertex1.color_ = vertex2.color_  = vertex3.color_ = color_.ToUInt();
     vertex0.color_ = vertex1.color_ = vertex2.color_  = vertex3.color_ = color_.ToUInt();
 
 
-    vertices_.Push(vertex0);
-    vertices_.Push(vertex1);
-    vertices_.Push(vertex2);
-    vertices_.Push(vertex3);
+    vertices.Push(vertex0);
+    vertices.Push(vertex1);
+    vertices.Push(vertex2);
+    vertices.Push(vertex3);
 
 
-    verticesDirty_ = false;
+    sourceBatchesDirty_ = false;
 }
 }
 
 
 void StaticSprite2D::OnFlipChanged()
 void StaticSprite2D::OnFlipChanged()
@@ -291,4 +304,17 @@ void StaticSprite2D::OnFlipChanged()
 
 
 }
 }
 
 
+void StaticSprite2D::UpdateMaterial()
+{
+    if (customMaterial_)
+        sourceBatches_[0].material_ = customMaterial_;
+    else
+    {
+        if (sprite_)
+            sourceBatches_[0].material_ = renderer_->GetMaterial(sprite_->GetTexture(), blendMode_);
+        else
+            sourceBatches_[0].material_ = 0;
+    }
+}
+
 }
 }

+ 23 - 3
Source/Atomic/Atomic2D/StaticSprite2D.h

@@ -44,6 +44,8 @@ public:
 
 
     /// Set sprite.
     /// Set sprite.
     void SetSprite(Sprite2D* sprite);
     void SetSprite(Sprite2D* sprite);
+    /// Set blend mode.
+    void SetBlendMode(BlendMode blendMode);
     /// Set flip.
     /// Set flip.
     void SetFlip(bool flipX, bool flipY);
     void SetFlip(bool flipX, bool flipY);
     /// Set flip X.
     /// Set flip X.
@@ -58,9 +60,13 @@ public:
     void SetUseHotSpot(bool useHotSpot);
     void SetUseHotSpot(bool useHotSpot);
     /// Set hot spot.
     /// Set hot spot.
     void SetHotSpot(const Vector2& hotspot);
     void SetHotSpot(const Vector2& hotspot);
-    
+    /// Set custom material.
+    void SetCustomMaterial(Material* customMaterial);
+
     /// Return sprite.
     /// Return sprite.
     Sprite2D* GetSprite() const;
     Sprite2D* GetSprite() const;
+    /// Return blend mode.
+    BlendMode GetBlendMode() const { return blendMode_; }
     /// Return flip X.
     /// Return flip X.
     bool GetFlipX() const { return flipX_; }
     bool GetFlipX() const { return flipX_; }
     /// Return flip Y.
     /// Return flip Y.
@@ -73,22 +79,34 @@ public:
     bool GetUseHotSpot() const { return useHotSpot_; }
     bool GetUseHotSpot() const { return useHotSpot_; }
     /// Return hot spot.
     /// Return hot spot.
     const Vector2& GetHotSpot() const { return hotSpot_; }
     const Vector2& GetHotSpot() const { return hotSpot_; }
+    /// Return custom material.
+    Material* GetCustomMaterial() const;
 
 
     /// Set sprite attribute.
     /// Set sprite attribute.
     void SetSpriteAttr(const ResourceRef& value);
     void SetSpriteAttr(const ResourceRef& value);
     /// Return sprite attribute.
     /// Return sprite attribute.
     ResourceRef GetSpriteAttr() const;
     ResourceRef GetSpriteAttr() const;
+    /// Set custom material attribute.
+    void SetCustomMaterialAttr(const ResourceRef& value);
+    /// Return custom material attribute.
+    ResourceRef GetCustomMaterialAttr() const;
 
 
 protected:
 protected:
     /// Recalculate the world-space bounding box.
     /// Recalculate the world-space bounding box.
     virtual void OnWorldBoundingBoxUpdate();
     virtual void OnWorldBoundingBoxUpdate();
-    /// Update vertices.
-    virtual void UpdateVertices();
+    /// Handle draw order changed.
+    virtual void OnDrawOrderChanged();
+    /// Update source batches.
+    virtual void UpdateSourceBatches();
     /// Handle flip changed.
     /// Handle flip changed.
     virtual void OnFlipChanged();
     virtual void OnFlipChanged();
+    /// Update material.
+    void UpdateMaterial();
 
 
     /// Sprite.
     /// Sprite.
     SharedPtr<Sprite2D> sprite_;
     SharedPtr<Sprite2D> sprite_;
+    /// Blend mode.
+    BlendMode blendMode_;
     /// Flip X.
     /// Flip X.
     bool flipX_;
     bool flipX_;
     /// Flip Y.
     /// Flip Y.
@@ -99,6 +117,8 @@ protected:
     bool useHotSpot_;
     bool useHotSpot_;
     /// Hot spot.
     /// Hot spot.
     Vector2 hotSpot_;
     Vector2 hotSpot_;
+    /// Custom material.
+    SharedPtr<Material> customMaterial_;
 };
 };
 
 
 }
 }

+ 3 - 3
Source/Atomic/Atomic3D/AnimatedModel.cpp

@@ -230,13 +230,13 @@ void AnimatedModel::UpdateBatches(const FrameInfo& frame)
 
 
     // Note: per-geometry distances do not take skinning into account. Especially in case of a ragdoll they may be
     // Note: per-geometry distances do not take skinning into account. Especially in case of a ragdoll they may be
     // much off base if the node's own transform is not updated
     // much off base if the node's own transform is not updated
-    if (batches_.Size() > 1)
+    if (batches_.Size() == 1)
+        batches_[0].distance_ = distance_;
+    else
     {
     {
         for (unsigned i = 0; i < batches_.Size(); ++i)
         for (unsigned i = 0; i < batches_.Size(); ++i)
             batches_[i].distance_ = frame.camera_->GetDistance(worldTransform * geometryData_[i].center_);
             batches_[i].distance_ = frame.camera_->GetDistance(worldTransform * geometryData_[i].center_);
     }
     }
-    else if (batches_.Size() == 1)
-        batches_[0].distance_ = distance_;
 
 
     // Use a transformed version of the model's bounding box instead of world bounding box for LOD scale
     // Use a transformed version of the model's bounding box instead of world bounding box for LOD scale
     // determination so that animation does not change the scale
     // determination so that animation does not change the scale

+ 2 - 2
Source/Atomic/Atomic3D/DecalSet.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -914,7 +914,7 @@ bool DecalSet::GetBones(Drawable* target, unsigned batchIndex, const float* blen
 
 
             if (!found)
             if (!found)
             {
             {
-                if (bones_.Size() >= MAX_SKIN_MATRICES)
+                if (bones_.Size() >= Graphics::GetMaxBones())
                 {
                 {
                     LOGWARNING("Maximum skinned decal bone count reached");
                     LOGWARNING("Maximum skinned decal bone count reached");
                     return false;
                     return false;

+ 2 - 0
Source/Atomic/Atomic3D/Model.h

@@ -165,6 +165,8 @@ public:
     const PODVector<Vector3>& GetGeometryCenters() const { return geometryCenters_; }
     const PODVector<Vector3>& GetGeometryCenters() const { return geometryCenters_; }
     /// Return geometry by index and LOD level. The LOD level is clamped if out of range.
     /// Return geometry by index and LOD level. The LOD level is clamped if out of range.
     Geometry* GetGeometry(unsigned index, unsigned lodLevel) const;
     Geometry* GetGeometry(unsigned index, unsigned lodLevel) const;
+    /// Return geometry center by index.
+    const Vector3& GetGeometryCenter(unsigned index) const { return index < geometryCenters_.Size() ? geometryCenters_[index] : Vector3::ZERO; }
     /// Return geometery bone mappings.
     /// Return geometery bone mappings.
     const Vector<PODVector<unsigned> >& GetGeometryBoneMappings() const { return geometryBoneMappings_; }
     const Vector<PODVector<unsigned> >& GetGeometryBoneMappings() const { return geometryBoneMappings_; }
     /// Return vertex morphs.
     /// Return vertex morphs.

+ 2 - 2
Source/Atomic/Atomic3D/ParticleEmitter.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -484,7 +484,7 @@ bool ParticleEmitter::EmitNewParticle()
     billboard.uv_ = textureFrames_.Size() ? textureFrames_[0].uv_ : Rect::POSITIVE;
     billboard.uv_ = textureFrames_.Size() ? textureFrames_[0].uv_ : Rect::POSITIVE;
     billboard.rotation_ = effect_->GetRandomRotation();
     billboard.rotation_ = effect_->GetRandomRotation();
     const Vector<ColorFrame>& colorFrames_ = effect_->GetColorFrames();
     const Vector<ColorFrame>& colorFrames_ = effect_->GetColorFrames();
-    billboard.color_ = colorFrames_[0].color_;
+    billboard.color_ = colorFrames_.Size() ? colorFrames_[0].color_ : Color();
     billboard.enabled_ = true;
     billboard.enabled_ = true;
 
 
     return true;
     return true;

+ 10 - 12
Source/Atomic/Atomic3D/StaticModel.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -87,6 +87,7 @@ void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQuer
         Ray localRay = query.ray_.Transformed(inverse);
         Ray localRay = query.ray_.Transformed(inverse);
         float distance = localRay.HitDistance(boundingBox_);
         float distance = localRay.HitDistance(boundingBox_);
         Vector3 normal = -query.ray_.direction_;
         Vector3 normal = -query.ray_.direction_;
+        unsigned hitBatch = M_MAX_UNSIGNED;
 
 
         if (level == RAY_TRIANGLE && distance < query.maxDistance_)
         if (level == RAY_TRIANGLE && distance < query.maxDistance_)
         {
         {
@@ -103,6 +104,7 @@ void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQuer
                     {
                     {
                         distance = geometryDistance;
                         distance = geometryDistance;
                         normal = (node_->GetWorldTransform() * Vector4(geometryNormal, 0.0f)).Normalized();
                         normal = (node_->GetWorldTransform() * Vector4(geometryNormal, 0.0f)).Normalized();
+                        hitBatch = i;
                     }
                     }
                 }
                 }
             }
             }
@@ -116,7 +118,7 @@ void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQuer
             result.distance_ = distance;
             result.distance_ = distance;
             result.drawable_ = this;
             result.drawable_ = this;
             result.node_ = node_;
             result.node_ = node_;
-            result.subObject_ = M_MAX_UNSIGNED;
+            result.subObject_ = hitBatch;
             results.Push(result);
             results.Push(result);
         }
         }
         break;
         break;
@@ -126,21 +128,15 @@ void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQuer
 void StaticModel::UpdateBatches(const FrameInfo& frame)
 void StaticModel::UpdateBatches(const FrameInfo& frame)
 {
 {
     const BoundingBox& worldBoundingBox = GetWorldBoundingBox();
     const BoundingBox& worldBoundingBox = GetWorldBoundingBox();
-    const Matrix3x4& worldTransform = node_->GetWorldTransform();
     distance_ = frame.camera_->GetDistance(worldBoundingBox.Center());
     distance_ = frame.camera_->GetDistance(worldBoundingBox.Center());
 
 
-    if (batches_.Size() > 1)
+    if (batches_.Size() == 1)
+        batches_[0].distance_ = distance_;
+    else
     {
     {
+        const Matrix3x4& worldTransform = node_->GetWorldTransform();
         for (unsigned i = 0; i < batches_.Size(); ++i)
         for (unsigned i = 0; i < batches_.Size(); ++i)
-        {
             batches_[i].distance_ = frame.camera_->GetDistance(worldTransform * geometryData_[i].center_);
             batches_[i].distance_ = frame.camera_->GetDistance(worldTransform * geometryData_[i].center_);
-            batches_[i].worldTransform_ = &worldTransform;
-        }
-    }
-    else if (batches_.Size() == 1)
-    {
-        batches_[0].distance_ = distance_;
-        batches_[0].worldTransform_ = &worldTransform;
     }
     }
 
 
     float scale = worldBoundingBox.Size().DotProduct(DOT_SCALE);
     float scale = worldBoundingBox.Size().DotProduct(DOT_SCALE);
@@ -255,8 +251,10 @@ void StaticModel::SetModel(Model* model)
         SetNumGeometries(model->GetNumGeometries());
         SetNumGeometries(model->GetNumGeometries());
         const Vector<Vector<SharedPtr<Geometry> > >& geometries = model->GetGeometries();
         const Vector<Vector<SharedPtr<Geometry> > >& geometries = model->GetGeometries();
         const PODVector<Vector3>& geometryCenters = model->GetGeometryCenters();
         const PODVector<Vector3>& geometryCenters = model->GetGeometryCenters();
+        const Matrix3x4* worldTransform = node_ ? &node_->GetWorldTransform() : (const Matrix3x4*)0;
         for (unsigned i = 0; i < geometries.Size(); ++i)
         for (unsigned i = 0; i < geometries.Size(); ++i)
         {
         {
+            batches_[i].worldTransform_ = worldTransform;
             geometries_[i] = geometries[i];
             geometries_[i] = geometries[i];
             geometryData_[i].center_ = geometryCenters[i];
             geometryData_[i].center_ = geometryCenters[i];
         }
         }

+ 208 - 244
Source/Atomic/Graphics/Batch.cpp

@@ -89,40 +89,39 @@ void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split
     float width = (float)shadowMap->GetWidth();
     float width = (float)shadowMap->GetWidth();
     float height = (float)shadowMap->GetHeight();
     float height = (float)shadowMap->GetHeight();
     
     
-    Vector2 offset(
+    Vector3 offset(
         (float)viewport.left_ / width,
         (float)viewport.left_ / width,
-        (float)viewport.top_ / height
+        (float)viewport.top_ / height,
+        0.0f
     );
     );
     
     
-    Vector2 scale(
+    Vector3 scale(
         0.5f * (float)viewport.Width() / width,
         0.5f * (float)viewport.Width() / width,
-        0.5f * (float)viewport.Height() / height
+        0.5f * (float)viewport.Height() / height,
+        1.0f
     );
     );
-    
+
+    // Add pixel-perfect offset if needed by the graphics API
+    const Vector2& pixelUVOffset = Graphics::GetPixelUVOffset();
+    offset.x_ += scale.x_ + pixelUVOffset.x_ / width;
+    offset.y_ += scale.y_ + pixelUVOffset.y_ / height;
+
     #ifdef ATOMIC_OPENGL
     #ifdef ATOMIC_OPENGL
-    offset.x_ += scale.x_;
-    offset.y_ += scale.y_;
+    offset.z_ = 0.5f;
+    scale.z_ = 0.5f;
     offset.y_ = 1.0f - offset.y_;
     offset.y_ = 1.0f - offset.y_;
-    // If using 4 shadow samples, offset the position diagonally by half pixel
-    if (renderer->GetShadowQuality() & SHADOWQUALITY_HIGH_16BIT)
-    {
-        offset.x_ -= 0.5f / width;
-        offset.y_ -= 0.5f / height;
-    }
-    texAdjust.SetTranslation(Vector3(offset.x_, offset.y_, 0.5f));
-    texAdjust.SetScale(Vector3(scale.x_, scale.y_, 0.5f));
     #else
     #else
-    offset.x_ += scale.x_ + 0.5f / width;
-    offset.y_ += scale.y_ + 0.5f / height;
+    scale.y_ = -scale.y_;
+    #endif
+
+    // If using 4 shadow samples, offset the position diagonally by half pixel
     if (renderer->GetShadowQuality() & SHADOWQUALITY_HIGH_16BIT)
     if (renderer->GetShadowQuality() & SHADOWQUALITY_HIGH_16BIT)
     {
     {
         offset.x_ -= 0.5f / width;
         offset.x_ -= 0.5f / width;
         offset.y_ -= 0.5f / height;
         offset.y_ -= 0.5f / height;
     }
     }
-    scale.y_ = -scale.y_;
-    texAdjust.SetTranslation(Vector3(offset.x_, offset.y_, 0.0f));
-    texAdjust.SetScale(Vector3(scale.x_, scale.y_, 1.0f));
-    #endif
+    texAdjust.SetTranslation(offset);
+    texAdjust.SetScale(scale);
     
     
     dest = texAdjust * shadowProj * shadowView * posAdjust;
     dest = texAdjust * shadowProj * shadowView * posAdjust;
 }
 }
@@ -181,11 +180,12 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
     Light* light = lightQueue_ ? lightQueue_->light_ : 0;
     Light* light = lightQueue_ ? lightQueue_->light_ : 0;
     Texture2D* shadowMap = lightQueue_ ? lightQueue_->shadowMap_ : 0;
     Texture2D* shadowMap = lightQueue_ ? lightQueue_->shadowMap_ : 0;
 
 
+    // Set shaders first. The available shader parameters and their register/uniform positions depend on the currently set shaders
+    graphics->SetShaders(vertexShader_, pixelShader_);
+
     // Set pass / material-specific renderstates
     // Set pass / material-specific renderstates
     if (pass_ && material_)
     if (pass_ && material_)
     {
     {
-        bool isShadowPass = pass_->GetType() == PASS_SHADOW;
-        
         BlendMode blend = pass_->GetBlendMode();
         BlendMode blend = pass_->GetBlendMode();
         // Turn additive blending into subtract if the light is negative
         // Turn additive blending into subtract if the light is negative
         if (light && light->IsNegative())
         if (light && light->IsNegative())
@@ -195,43 +195,40 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
             else if (blend == BLEND_ADDALPHA)
             else if (blend == BLEND_ADDALPHA)
                 blend = BLEND_SUBTRACTALPHA;
                 blend = BLEND_SUBTRACTALPHA;
         }
         }
-        
         graphics->SetBlendMode(blend);
         graphics->SetBlendMode(blend);
+
+        bool isShadowPass = pass_->GetIndex() == Technique::shadowPassIndex;
         renderer->SetCullMode(isShadowPass ? material_->GetShadowCullMode() : material_->GetCullMode(), camera_);
         renderer->SetCullMode(isShadowPass ? material_->GetShadowCullMode() : material_->GetCullMode(), camera_);
         if (!isShadowPass)
         if (!isShadowPass)
         {
         {
             const BiasParameters& depthBias = material_->GetDepthBias();
             const BiasParameters& depthBias = material_->GetDepthBias();
             graphics->SetDepthBias(depthBias.constantBias_, depthBias.slopeScaledBias_);
             graphics->SetDepthBias(depthBias.constantBias_, depthBias.slopeScaledBias_);
         }
         }
+
+        // Use the "least filled" fill mode combined from camera & material
+        graphics->SetFillMode((FillMode)(Max(camera_->GetFillMode(), material_->GetFillMode())));
         graphics->SetDepthTest(pass_->GetDepthTestMode());
         graphics->SetDepthTest(pass_->GetDepthTestMode());
         graphics->SetDepthWrite(pass_->GetDepthWrite() && allowDepthWrite);
         graphics->SetDepthWrite(pass_->GetDepthWrite() && allowDepthWrite);
     }
     }
     
     
-    // Set shaders first. The available shader parameters and their register/uniform positions depend on the currently set shaders
-    graphics->SetShaders(vertexShader_, pixelShader_);
-    
     // Set global (per-frame) shader parameters
     // Set global (per-frame) shader parameters
     if (graphics->NeedParameterUpdate(SP_FRAME, (void*)0))
     if (graphics->NeedParameterUpdate(SP_FRAME, (void*)0))
         view->SetGlobalShaderParameters();
         view->SetGlobalShaderParameters();
     
     
-    // Set camera shader parameters
+    // Set camera & viewport shader parameters
     unsigned cameraHash = (unsigned)(size_t)camera_;
     unsigned cameraHash = (unsigned)(size_t)camera_;
-    if (graphics->NeedParameterUpdate(SP_CAMERA, reinterpret_cast<void*>(cameraHash)))
-        view->SetCameraShaderParameters(camera_, true);
-    
-    // Set viewport shader parameters
     IntRect viewport = graphics->GetViewport();
     IntRect viewport = graphics->GetViewport();
     IntVector2 viewSize = IntVector2(viewport.Width(), viewport.Height());
     IntVector2 viewSize = IntVector2(viewport.Width(), viewport.Height());
     unsigned viewportHash = viewSize.x_ | (viewSize.y_ << 16);
     unsigned viewportHash = viewSize.x_ | (viewSize.y_ << 16);
-    
-    if (graphics->NeedParameterUpdate(SP_VIEWPORT, reinterpret_cast<void*>(viewportHash)))
+    if (graphics->NeedParameterUpdate(SP_CAMERA, reinterpret_cast<const void*>(cameraHash + viewportHash)))
     {
     {
+        view->SetCameraShaderParameters(camera_, true);
         // During renderpath commands the G-Buffer or viewport texture is assumed to always be viewport-sized
         // During renderpath commands the G-Buffer or viewport texture is assumed to always be viewport-sized
         view->SetGBufferShaderParameters(viewSize, IntRect(0, 0, viewSize.x_, viewSize.y_));
         view->SetGBufferShaderParameters(viewSize, IntRect(0, 0, viewSize.x_, viewSize.y_));
     }
     }
     
     
     // Set model or skinning transforms
     // Set model or skinning transforms
-    if (setModelTransform && graphics->NeedParameterUpdate(SP_OBJECTTRANSFORM, worldTransform_))
+    if (setModelTransform && graphics->NeedParameterUpdate(SP_OBJECT, worldTransform_))
     {
     {
         if (geometryType_ == GEOM_SKINNED)
         if (geometryType_ == GEOM_SKINNED)
         {
         {
@@ -263,7 +260,7 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
     unsigned zoneHash = (unsigned)(size_t)zone_;
     unsigned zoneHash = (unsigned)(size_t)zone_;
     if (overrideFogColorToBlack)
     if (overrideFogColorToBlack)
         zoneHash += 0x80000000;
         zoneHash += 0x80000000;
-    if (zone_ && graphics->NeedParameterUpdate(SP_ZONE, reinterpret_cast<void*>(zoneHash)))
+    if (zone_ && graphics->NeedParameterUpdate(SP_ZONE, reinterpret_cast<const void*>(zoneHash)))
     {
     {
         graphics->SetShaderParameter(VSP_AMBIENTSTARTCOLOR, zone_->GetAmbientStartColor());
         graphics->SetShaderParameter(VSP_AMBIENTSTARTCOLOR, zone_->GetAmbientStartColor());
         graphics->SetShaderParameter(VSP_AMBIENTENDCOLOR, zone_->GetAmbientEndColor().ToVector4() - zone_->GetAmbientStartColor().ToVector4());
         graphics->SetShaderParameter(VSP_AMBIENTENDCOLOR, zone_->GetAmbientEndColor().ToVector4() - zone_->GetAmbientStartColor().ToVector4());
@@ -301,104 +298,52 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
     // Set light-related shader parameters
     // Set light-related shader parameters
     if (lightQueue_)
     if (lightQueue_)
     {
     {
-        if (graphics->NeedParameterUpdate(SP_VERTEXLIGHTS, lightQueue_) && graphics->HasShaderParameter(VSP_VERTEXLIGHTS))
+        if (light && graphics->NeedParameterUpdate(SP_LIGHT, lightQueue_))
         {
         {
-            Vector4 vertexLights[MAX_VERTEX_LIGHTS * 3];
-            const PODVector<Light*>& lights = lightQueue_->vertexLights_;
-            
-            for (unsigned i = 0; i < lights.Size(); ++i)
-            {
-                Light* vertexLight = lights[i];
-                Node* vertexLightNode = vertexLight->GetNode();
-                LightType type = vertexLight->GetLightType();
-                
-                // Attenuation
-                float invRange, cutoff, invCutoff;
-                if (type == LIGHT_DIRECTIONAL)
-                    invRange = 0.0f;
-                else
-                    invRange = 1.0f / Max(vertexLight->GetRange(), M_EPSILON);
-                if (type == LIGHT_SPOT)
-                {
-                    cutoff = Cos(vertexLight->GetFov() * 0.5f);
-                    invCutoff = 1.0f / (1.0f - cutoff);
-                }
-                else
-                {
-                    cutoff = -1.0f;
-                    invCutoff = 1.0f;
-                }
-                
-                // Color
-                float fade = 1.0f;
-                float fadeEnd = vertexLight->GetDrawDistance();
-                float fadeStart = vertexLight->GetFadeDistance();
-                
-                // Do fade calculation for light if both fade & draw distance defined
-                if (vertexLight->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
-                    fade = Min(1.0f - (vertexLight->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
-                
-                Color color = vertexLight->GetEffectiveColor() * fade;
-                vertexLights[i * 3] = Vector4(color.r_, color.g_, color.b_, invRange);
-                
-                // Direction
-                vertexLights[i * 3 + 1] = Vector4(-(vertexLightNode->GetWorldDirection()), cutoff);
-                
-                // Position
-                vertexLights[i * 3 + 2] = Vector4(vertexLightNode->GetWorldPosition(), invCutoff);
-            }
-            
-            if (lights.Size())
-                graphics->SetShaderParameter(VSP_VERTEXLIGHTS, vertexLights[0].Data(), lights.Size() * 3 * 4);
-        }
-    }
-    
-    if (light && graphics->NeedParameterUpdate(SP_LIGHT, light))
-    {
-        // Deferred light volume batches operate in a camera-centered space. Detect from material, zone & pass all being null
-        bool isLightVolume = !material_ && !pass_ && !zone_;
-        
-        Matrix3x4 cameraEffectiveTransform = camera_->GetEffectiveWorldTransform();
-        Vector3 cameraEffectivePos = cameraEffectiveTransform.Translation();
+            // Deferred light volume batches operate in a camera-centered space. Detect from material, zone & pass all being null
+            bool isLightVolume = !material_ && !pass_ && !zone_;
 
 
-        Node* lightNode = light->GetNode();
-        Matrix3 lightWorldRotation = lightNode->GetWorldRotation().RotationMatrix();
-        
-        graphics->SetShaderParameter(VSP_LIGHTDIR, lightWorldRotation * Vector3::BACK);
-        
-        float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
-        graphics->SetShaderParameter(VSP_LIGHTPOS, Vector4(lightNode->GetWorldPosition(), atten));
-        
-        if (graphics->HasShaderParameter(VSP_LIGHTMATRICES))
-        {
-            switch (light->GetLightType())
+            Matrix3x4 cameraEffectiveTransform = camera_->GetEffectiveWorldTransform();
+            Vector3 cameraEffectivePos = cameraEffectiveTransform.Translation();
+
+            Node* lightNode = light->GetNode();
+            Matrix3 lightWorldRotation = lightNode->GetWorldRotation().RotationMatrix();
+
+            graphics->SetShaderParameter(VSP_LIGHTDIR, lightWorldRotation * Vector3::BACK);
+
+            float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
+            graphics->SetShaderParameter(VSP_LIGHTPOS, Vector4(lightNode->GetWorldPosition(), atten));
+
+            if (graphics->HasShaderParameter(VSP_LIGHTMATRICES))
             {
             {
-            case LIGHT_DIRECTIONAL:
+                switch (light->GetLightType())
+                {
+                case LIGHT_DIRECTIONAL:
                 {
                 {
                     Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
                     Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
                     unsigned numSplits = Min(MAX_CASCADE_SPLITS, (int)lightQueue_->shadowSplits_.Size());
                     unsigned numSplits = Min(MAX_CASCADE_SPLITS, (int)lightQueue_->shadowSplits_.Size());
 
 
                     for (unsigned i = 0; i < numSplits; ++i)
                     for (unsigned i = 0; i < numSplits; ++i)
                         CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, Vector3::ZERO);
                         CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, Vector3::ZERO);
-                    
+
                     graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
                     graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
                 }
                 }
                 break;
                 break;
-                
-            case LIGHT_SPOT:
+
+                case LIGHT_SPOT:
                 {
                 {
                     Matrix4 shadowMatrices[2];
                     Matrix4 shadowMatrices[2];
-                    
+
                     CalculateSpotMatrix(shadowMatrices[0], light, Vector3::ZERO);
                     CalculateSpotMatrix(shadowMatrices[0], light, Vector3::ZERO);
                     bool isShadowed = shadowMap && graphics->HasTextureUnit(TU_SHADOWMAP);
                     bool isShadowed = shadowMap && graphics->HasTextureUnit(TU_SHADOWMAP);
                     if (isShadowed)
                     if (isShadowed)
                         CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, Vector3::ZERO);
                         CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, Vector3::ZERO);
-                    
+
                     graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
                     graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
                 }
                 }
                 break;
                 break;
-                
-            case LIGHT_POINT:
+
+                case LIGHT_POINT:
                 {
                 {
                     Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
                     Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
                     // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
                     // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
@@ -410,29 +355,29 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
                     #endif
                     #endif
                 }
                 }
                 break;
                 break;
+                }
             }
             }
-        }
-        
-        float fade = 1.0f;
-        float fadeEnd = light->GetDrawDistance();
-        float fadeStart = light->GetFadeDistance();
-        
-        // Do fade calculation for light if both fade & draw distance defined
-        if (light->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
-            fade = Min(1.0f - (light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
-        
-        // Negative lights will use subtract blending, so write absolute RGB values to the shader parameter
-        graphics->SetShaderParameter(PSP_LIGHTCOLOR, Color(light->GetEffectiveColor().Abs(),
-            light->GetEffectiveSpecularIntensity()) * fade);
-        graphics->SetShaderParameter(PSP_LIGHTDIR, lightWorldRotation * Vector3::BACK);
-        graphics->SetShaderParameter(PSP_LIGHTPOS, Vector4((isLightVolume ? (lightNode->GetWorldPosition() -
-            cameraEffectivePos) : lightNode->GetWorldPosition()), atten));
-        
-        if (graphics->HasShaderParameter(PSP_LIGHTMATRICES))
-        {
-            switch (light->GetLightType())
+
+            float fade = 1.0f;
+            float fadeEnd = light->GetDrawDistance();
+            float fadeStart = light->GetFadeDistance();
+
+            // Do fade calculation for light if both fade & draw distance defined
+            if (light->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
+                fade = Min(1.0f - (light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
+
+            // Negative lights will use subtract blending, so write absolute RGB values to the shader parameter
+            graphics->SetShaderParameter(PSP_LIGHTCOLOR, Color(light->GetEffectiveColor().Abs(),
+                light->GetEffectiveSpecularIntensity()) * fade);
+            graphics->SetShaderParameter(PSP_LIGHTDIR, lightWorldRotation * Vector3::BACK);
+            graphics->SetShaderParameter(PSP_LIGHTPOS, Vector4((isLightVolume ? (lightNode->GetWorldPosition() -
+                cameraEffectivePos) : lightNode->GetWorldPosition()), atten));
+
+            if (graphics->HasShaderParameter(PSP_LIGHTMATRICES))
             {
             {
-            case LIGHT_DIRECTIONAL:
+                switch (light->GetLightType())
+                {
+                case LIGHT_DIRECTIONAL:
                 {
                 {
                     Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
                     Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
                     unsigned numSplits = Min(MAX_CASCADE_SPLITS, (int)lightQueue_->shadowSplits_.Size());
                     unsigned numSplits = Min(MAX_CASCADE_SPLITS, (int)lightQueue_->shadowSplits_.Size());
@@ -445,11 +390,11 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
                     graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
                     graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
                 }
                 }
                 break;
                 break;
-                
-            case LIGHT_SPOT:
+
+                case LIGHT_SPOT:
                 {
                 {
                     Matrix4 shadowMatrices[2];
                     Matrix4 shadowMatrices[2];
-                    
+
                     CalculateSpotMatrix(shadowMatrices[0], light, cameraEffectivePos);
                     CalculateSpotMatrix(shadowMatrices[0], light, cameraEffectivePos);
                     bool isShadowed = lightQueue_->shadowMap_ != 0;
                     bool isShadowed = lightQueue_->shadowMap_ != 0;
                     if (isShadowed)
                     if (isShadowed)
@@ -457,12 +402,12 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
                         CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, isLightVolume ? cameraEffectivePos :
                         CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, isLightVolume ? cameraEffectivePos :
                             Vector3::ZERO);
                             Vector3::ZERO);
                     }
                     }
-                    
+
                     graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
                     graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
                 }
                 }
                 break;
                 break;
-                
-            case LIGHT_POINT:
+
+                case LIGHT_POINT:
                 {
                 {
                     Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
                     Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
                     // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
                     // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
@@ -474,103 +419,151 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
                     #endif
                     #endif
                 }
                 }
                 break;
                 break;
+                }
             }
             }
-        }
-        
-        // Set shadow mapping shader parameters
-        if (shadowMap)
-        {
+
+            // Set shadow mapping shader parameters
+            if (shadowMap)
             {
             {
-                // Calculate point light shadow sampling offsets (unrolled cube map)
-                unsigned faceWidth = shadowMap->GetWidth() / 2;
-                unsigned faceHeight = shadowMap->GetHeight() / 3;
-                float width = (float)shadowMap->GetWidth();
-                float height = (float)shadowMap->GetHeight();
-                #ifdef ATOMIC_OPENGL
+                {
+                    // Calculate point light shadow sampling offsets (unrolled cube map)
+                    unsigned faceWidth = shadowMap->GetWidth() / 2;
+                    unsigned faceHeight = shadowMap->GetHeight() / 3;
+                    float width = (float)shadowMap->GetWidth();
+                    float height = (float)shadowMap->GetHeight();
+                    #ifdef ATOMIC_OPENGL
                     float mulX = (float)(faceWidth - 3) / width;
                     float mulX = (float)(faceWidth - 3) / width;
                     float mulY = (float)(faceHeight - 3) / height;
                     float mulY = (float)(faceHeight - 3) / height;
                     float addX = 1.5f / width;
                     float addX = 1.5f / width;
                     float addY = 1.5f / height;
                     float addY = 1.5f / height;
-                #else
+                    #else
                     float mulX = (float)(faceWidth - 4) / width;
                     float mulX = (float)(faceWidth - 4) / width;
                     float mulY = (float)(faceHeight - 4) / height;
                     float mulY = (float)(faceHeight - 4) / height;
                     float addX = 2.5f / width;
                     float addX = 2.5f / width;
                     float addY = 2.5f / height;
                     float addY = 2.5f / height;
-                #endif
-                // If using 4 shadow samples, offset the position diagonally by half pixel
-                if (renderer->GetShadowQuality() & SHADOWQUALITY_HIGH_16BIT)
+                    #endif
+                    // If using 4 shadow samples, offset the position diagonally by half pixel
+                    if (renderer->GetShadowQuality() & SHADOWQUALITY_HIGH_16BIT)
+                    {
+                        addX -= 0.5f / width;
+                        addY -= 0.5f / height;
+                    }
+                    graphics->SetShaderParameter(PSP_SHADOWCUBEADJUST, Vector4(mulX, mulY, addX, addY));
+                }
+
+                {
+                    // Calculate shadow camera depth parameters for point light shadows and shadow fade parameters for
+                    //  directional light shadows, stored in the same uniform
+                    Camera* shadowCamera = lightQueue_->shadowSplits_[0].shadowCamera_;
+                    float nearClip = shadowCamera->GetNearClip();
+                    float farClip = shadowCamera->GetFarClip();
+                    float q = farClip / (farClip - nearClip);
+                    float r = -q * nearClip;
+
+                    const CascadeParameters& parameters = light->GetShadowCascade();
+                    float viewFarClip = camera_->GetFarClip();
+                    float shadowRange = parameters.GetShadowRange();
+                    float fadeStart = parameters.fadeStart_ * shadowRange / viewFarClip;
+                    float fadeEnd = shadowRange / viewFarClip;
+                    float fadeRange = fadeEnd - fadeStart;
+
+                    graphics->SetShaderParameter(PSP_SHADOWDEPTHFADE, Vector4(q, r, fadeStart, 1.0f / fadeRange));
+                }
+
                 {
                 {
-                    addX -= 0.5f / width;
-                    addY -= 0.5f / height;
+                    float intensity = light->GetShadowIntensity();
+                    float fadeStart = light->GetShadowFadeDistance();
+                    float fadeEnd = light->GetShadowDistance();
+                    if (fadeStart > 0.0f && fadeEnd > 0.0f && fadeEnd > fadeStart)
+                        intensity = Lerp(intensity, 1.0f, Clamp((light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 0.0f, 1.0f));
+                    float pcfValues = (1.0f - intensity);
+                    float samples = renderer->GetShadowQuality() >= SHADOWQUALITY_HIGH_16BIT ? 4.0f : 1.0f;
+
+                    graphics->SetShaderParameter(PSP_SHADOWINTENSITY, Vector4(pcfValues / samples, intensity, 0.0f, 0.0f));
                 }
                 }
-                graphics->SetShaderParameter(PSP_SHADOWCUBEADJUST, Vector4(mulX, mulY, addX, addY));
+
+                float sizeX = 1.0f / (float)shadowMap->GetWidth();
+                float sizeY = 1.0f / (float)shadowMap->GetHeight();
+                graphics->SetShaderParameter(PSP_SHADOWMAPINVSIZE, Vector4(sizeX, sizeY, 0.0f, 0.0f));
+
+                Vector4 lightSplits(M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE);
+                if (lightQueue_->shadowSplits_.Size() > 1)
+                    lightSplits.x_ = lightQueue_->shadowSplits_[0].farSplit_ / camera_->GetFarClip();
+                if (lightQueue_->shadowSplits_.Size() > 2)
+                    lightSplits.y_ = lightQueue_->shadowSplits_[1].farSplit_ / camera_->GetFarClip();
+                if (lightQueue_->shadowSplits_.Size() > 3)
+                    lightSplits.z_ = lightQueue_->shadowSplits_[2].farSplit_ / camera_->GetFarClip();
+
+                graphics->SetShaderParameter(PSP_SHADOWSPLITS, lightSplits);
             }
             }
+        }
+        else if (lightQueue_->vertexLights_.Size() && graphics->HasShaderParameter(VSP_VERTEXLIGHTS) &&
+            graphics->NeedParameterUpdate(SP_LIGHT, lightQueue_))
+        {
+            Vector4 vertexLights[MAX_VERTEX_LIGHTS * 3];
+            const PODVector<Light*>& lights = lightQueue_->vertexLights_;
             
             
+            for (unsigned i = 0; i < lights.Size(); ++i)
             {
             {
-                // Calculate shadow camera depth parameters for point light shadows and shadow fade parameters for
-                //  directional light shadows, stored in the same uniform
-                Camera* shadowCamera = lightQueue_->shadowSplits_[0].shadowCamera_;
-                float nearClip = shadowCamera->GetNearClip();
-                float farClip = shadowCamera->GetFarClip();
-                float q = farClip / (farClip - nearClip);
-                float r = -q * nearClip;
+                Light* vertexLight = lights[i];
+                Node* vertexLightNode = vertexLight->GetNode();
+                LightType type = vertexLight->GetLightType();
                 
                 
-                const CascadeParameters& parameters = light->GetShadowCascade();
-                float viewFarClip = camera_->GetFarClip();
-                float shadowRange = parameters.GetShadowRange();
-                float fadeStart = parameters.fadeStart_ * shadowRange / viewFarClip;
-                float fadeEnd = shadowRange / viewFarClip;
-                float fadeRange = fadeEnd - fadeStart;
+                // Attenuation
+                float invRange, cutoff, invCutoff;
+                if (type == LIGHT_DIRECTIONAL)
+                    invRange = 0.0f;
+                else
+                    invRange = 1.0f / Max(vertexLight->GetRange(), M_EPSILON);
+                if (type == LIGHT_SPOT)
+                {
+                    cutoff = Cos(vertexLight->GetFov() * 0.5f);
+                    invCutoff = 1.0f / (1.0f - cutoff);
+                }
+                else
+                {
+                    cutoff = -1.0f;
+                    invCutoff = 1.0f;
+                }
                 
                 
-                graphics->SetShaderParameter(PSP_SHADOWDEPTHFADE, Vector4(q, r, fadeStart, 1.0f / fadeRange));
-            }
-            
-            {
-                float intensity = light->GetShadowIntensity();
-                float fadeStart = light->GetShadowFadeDistance();
-                float fadeEnd = light->GetShadowDistance();
-                if (fadeStart > 0.0f && fadeEnd > 0.0f && fadeEnd > fadeStart)
-                    intensity = Lerp(intensity, 1.0f, Clamp((light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 0.0f, 1.0f));
-                float pcfValues = (1.0f - intensity);
-                float samples = renderer->GetShadowQuality() >= SHADOWQUALITY_HIGH_16BIT ? 4.0f : 1.0f;
-
-                graphics->SetShaderParameter(PSP_SHADOWINTENSITY, Vector4(pcfValues / samples, intensity, 0.0f, 0.0f));
+                // Color
+                float fade = 1.0f;
+                float fadeEnd = vertexLight->GetDrawDistance();
+                float fadeStart = vertexLight->GetFadeDistance();
+                
+                // Do fade calculation for light if both fade & draw distance defined
+                if (vertexLight->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
+                    fade = Min(1.0f - (vertexLight->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
+                
+                Color color = vertexLight->GetEffectiveColor() * fade;
+                vertexLights[i * 3] = Vector4(color.r_, color.g_, color.b_, invRange);
+                
+                // Direction
+                vertexLights[i * 3 + 1] = Vector4(-(vertexLightNode->GetWorldDirection()), cutoff);
+                
+                // Position
+                vertexLights[i * 3 + 2] = Vector4(vertexLightNode->GetWorldPosition(), invCutoff);
             }
             }
             
             
-            float sizeX = 1.0f / (float)shadowMap->GetWidth();
-            float sizeY = 1.0f / (float)shadowMap->GetHeight();
-            graphics->SetShaderParameter(PSP_SHADOWMAPINVSIZE, Vector4(sizeX, sizeY, 0.0f, 0.0f));
-            
-            Vector4 lightSplits(M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE);
-            if (lightQueue_->shadowSplits_.Size() > 1)
-                lightSplits.x_ = lightQueue_->shadowSplits_[0].farSplit_ / camera_->GetFarClip();
-            if (lightQueue_->shadowSplits_.Size() > 2)
-                lightSplits.y_ = lightQueue_->shadowSplits_[1].farSplit_ / camera_->GetFarClip();
-            if (lightQueue_->shadowSplits_.Size() > 3)
-                lightSplits.z_ = lightQueue_->shadowSplits_[2].farSplit_ / camera_->GetFarClip();
-            
-            graphics->SetShaderParameter(PSP_SHADOWSPLITS, lightSplits);
+            graphics->SetShaderParameter(VSP_VERTEXLIGHTS, vertexLights[0].Data(), lights.Size() * 3 * 4);
         }
         }
     }
     }
-    
+
     // Set material-specific shader parameters and textures
     // Set material-specific shader parameters and textures
     if (material_)
     if (material_)
     {
     {
-        if (graphics->NeedParameterUpdate(SP_MATERIAL, (const void*)material_->GetShaderParameterHash()))
+        if (graphics->NeedParameterUpdate(SP_MATERIAL, reinterpret_cast<const void*>(material_->GetShaderParameterHash())))
         {
         {
             const HashMap<StringHash, MaterialShaderParameter>& parameters = material_->GetShaderParameters();
             const HashMap<StringHash, MaterialShaderParameter>& parameters = material_->GetShaderParameters();
             for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
             for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
                 graphics->SetShaderParameter(i->first_, i->second_.value_);
                 graphics->SetShaderParameter(i->first_, i->second_.value_);
         }
         }
         
         
-        const SharedPtr<Texture>* textures = material_->GetTextures();
-        unsigned numTextures = material_->GetNumUsedTextureUnits();
-
-        for (unsigned i = 0; i < numTextures; ++i)
+        const HashMap<TextureUnit, SharedPtr<Texture> >& textures = material_->GetTextures();
+        for (HashMap<TextureUnit, SharedPtr<Texture> >::ConstIterator i = textures.Begin(); i != textures.End(); ++i)
         {
         {
-            TextureUnit unit = (TextureUnit)i;
-            if (textures[i] && graphics->HasTextureUnit(unit))
-                graphics->SetTexture(i, textures[i]);
+            if (graphics->HasTextureUnit(i->first_))
+                graphics->SetTexture(i->first_, i->second_.Get());
         }
         }
     }
     }
     
     
@@ -596,8 +589,10 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
     }
     }
     
     
     // Set zone texture if necessary
     // Set zone texture if necessary
+    #ifdef DESKTOP_GRAPHICS
     if (zone_ && graphics->HasTextureUnit(TU_ZONE))
     if (zone_ && graphics->HasTextureUnit(TU_ZONE))
         graphics->SetTexture(TU_ZONE, zone_->GetZoneTexture());
         graphics->SetTexture(TU_ZONE, zone_->GetZoneTexture());
+    #endif
 }
 }
 
 
 void Batch::Draw(View* view, bool allowDepthWrite) const
 void Batch::Draw(View* view, bool allowDepthWrite) const
@@ -632,9 +627,9 @@ void BatchGroup::Draw(View* view, bool allowDepthWrite) const
     
     
     if (instances_.Size() && !geometry_->IsEmpty())
     if (instances_.Size() && !geometry_->IsEmpty())
     {
     {
-        // Draw as individual objects if instancing not supported
+        // Draw as individual objects if instancing not supported or could not fill the instancing buffer
         VertexBuffer* instanceBuffer = renderer->GetInstancingBuffer();
         VertexBuffer* instanceBuffer = renderer->GetInstancingBuffer();
-        if (!instanceBuffer || geometryType_ != GEOM_INSTANCED)
+        if (!instanceBuffer || geometryType_ != GEOM_INSTANCED || startIndex_ == M_MAX_UNSIGNED)
         {
         {
             Batch::Prepare(view, false, allowDepthWrite);
             Batch::Prepare(view, false, allowDepthWrite);
             
             
@@ -643,7 +638,7 @@ void BatchGroup::Draw(View* view, bool allowDepthWrite) const
             
             
             for (unsigned i = 0; i < instances_.Size(); ++i)
             for (unsigned i = 0; i < instances_.Size(); ++i)
             {
             {
-                if (graphics->NeedParameterUpdate(SP_OBJECTTRANSFORM, instances_[i].worldTransform_))
+                if (graphics->NeedParameterUpdate(SP_OBJECT, instances_[i].worldTransform_))
                     graphics->SetShaderParameter(VSP_MODEL, *instances_[i].worldTransform_);
                     graphics->SetShaderParameter(VSP_MODEL, *instances_[i].worldTransform_);
                 
                 
                 graphics->Draw(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
                 graphics->Draw(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
@@ -662,41 +657,10 @@ void BatchGroup::Draw(View* view, bool allowDepthWrite) const
             vertexBuffers.Push(SharedPtr<VertexBuffer>(instanceBuffer));
             vertexBuffers.Push(SharedPtr<VertexBuffer>(instanceBuffer));
             elementMasks.Push(instanceBuffer->GetElementMask());
             elementMasks.Push(instanceBuffer->GetElementMask());
             
             
-            // No stream offset support, instancing buffer not pre-filled with transforms: have to fill now
-            if (startIndex_ == M_MAX_UNSIGNED)
-            {
-                unsigned startIndex = 0;
-                while (startIndex < instances_.Size())
-                {
-                    unsigned instances = instances_.Size() - startIndex;
-                    if (instances > instanceBuffer->GetVertexCount())
-                        instances = instanceBuffer->GetVertexCount();
-                    
-                    // Copy the transforms
-                    Matrix3x4* dest = (Matrix3x4*)instanceBuffer->Lock(0, instances, true);
-                    if (dest)
-                    {
-                        for (unsigned i = 0; i < instances; ++i)
-                            dest[i] = *instances_[i + startIndex].worldTransform_;
-                        instanceBuffer->Unlock();
-                        
-                        graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
-                        graphics->SetVertexBuffers(vertexBuffers, elementMasks);
-                        graphics->DrawInstanced(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(),
-                            geometry_->GetIndexCount(), geometry_->GetVertexStart(), geometry_->GetVertexCount(), instances);
-                    }
-                    
-                    startIndex += instances;
-                }
-            }
-            // Stream offset supported and instancing buffer has been already filled, so just draw
-            else
-            {
-                graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
-                graphics->SetVertexBuffers(vertexBuffers, elementMasks, startIndex_);
-                graphics->DrawInstanced(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
-                    geometry_->GetVertexStart(), geometry_->GetVertexCount(), instances_.Size());
-            }
+            graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
+            graphics->SetVertexBuffers(vertexBuffers, elementMasks, startIndex_);
+            graphics->DrawInstanced(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
+                geometry_->GetVertexStart(), geometry_->GetVertexCount(), instances_.Size());
             
             
             // Remove the instancing buffer & element mask now
             // Remove the instancing buffer & element mask now
             vertexBuffers.Pop();
             vertexBuffers.Pop();

+ 3 - 1
Source/Atomic/Graphics/Batch.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -275,6 +275,8 @@ struct LightBatchQueue
 {
 {
     /// Per-pixel light.
     /// Per-pixel light.
     Light* light_;
     Light* light_;
+    /// Light negative flag.
+    bool negative_;
     /// Shadow map depth texture.
     /// Shadow map depth texture.
     Texture2D* shadowMap_;
     Texture2D* shadowMap_;
     /// Lit geometry draw calls, base (replace blend mode)
     /// Lit geometry draw calls, base (replace blend mode)

+ 2 - 2
Source/Atomic/Graphics/ConstantBuffer.h

@@ -22,8 +22,8 @@
 
 
 #pragma once
 #pragma once
 
 
-#if defined(URHO3D_OPENGL)
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLConstantBuffer.h"
 #include "OpenGL/OGLConstantBuffer.h"
-#elif defined(URHO3D_D3D11)
+#elif defined(ATOMIC_D3D11)
 #include "Direct3D11/D3D11ConstantBuffer.h"
 #include "Direct3D11/D3D11ConstantBuffer.h"
 #endif
 #endif

+ 27 - 3
Source/Atomic/Graphics/DebugRenderer.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -246,7 +246,27 @@ void DebugRenderer::AddSphere(const Sphere& sphere, const Color& color, bool dep
     }
     }
 }
 }
 
 
+void DebugRenderer::AddCylinder(const Vector3& position, float radius, float height, const Color& color, bool depthTest)
+{
+    Sphere sphere(position, radius);
+    Vector3 heightVec(0, height, 0);
+    Vector3 offsetXVec(radius, 0, 0);
+    Vector3 offsetZVec(0, 0, radius);
+    for (unsigned i = 0; i < 360; i += 45)
+    {
+        Vector3 p1 = PointOnSphere(sphere, i, 90);
+        Vector3 p2 = PointOnSphere(sphere, i + 45, 90);
+        AddLine(p1, p2, color, depthTest);
+        AddLine(p1 + heightVec, p2 + heightVec, color, depthTest);
+    }
+    AddLine(position + offsetXVec, position + heightVec + offsetXVec, color, depthTest);
+    AddLine(position - offsetXVec, position + heightVec - offsetXVec, color, depthTest);
+    AddLine(position + offsetZVec, position + heightVec + offsetZVec, color, depthTest);
+    AddLine(position - offsetZVec, position + heightVec - offsetZVec, color, depthTest);
+}
+
 #ifdef ATOMIC_3D
 #ifdef ATOMIC_3D
+
 void DebugRenderer::AddSkeleton(const Skeleton& skeleton, const Color& color, bool depthTest)
 void DebugRenderer::AddSkeleton(const Skeleton& skeleton, const Color& color, bool depthTest)
 {
 {
     const Vector<Bone>& bones = skeleton.GetBones();
     const Vector<Bone>& bones = skeleton.GetBones();
@@ -330,7 +350,7 @@ void DebugRenderer::AddTriangleMesh(const void* vertexData, unsigned vertexSize,
 
 
 void DebugRenderer::Render()
 void DebugRenderer::Render()
 {
 {
-    if (lines_.Empty() && noDepthLines_.Empty() && triangles_.Empty() && noDepthTriangles_.Empty())
+    if (!HasContent())
         return;
         return;
 
 
     Graphics* graphics = GetSubsystem<Graphics>();
     Graphics* graphics = GetSubsystem<Graphics>();
@@ -413,7 +433,6 @@ void DebugRenderer::Render()
     graphics->SetColorWrite(true);
     graphics->SetColorWrite(true);
     graphics->SetCullMode(CULL_NONE);
     graphics->SetCullMode(CULL_NONE);
     graphics->SetDepthWrite(true);
     graphics->SetDepthWrite(true);
-    graphics->SetDrawAntialiased(true);
     graphics->SetScissorTest(false);
     graphics->SetScissorTest(false);
     graphics->SetStencilTest(false);
     graphics->SetStencilTest(false);
     graphics->SetShaders(vs, ps);
     graphics->SetShaders(vs, ps);
@@ -461,6 +480,11 @@ bool DebugRenderer::IsInside(const BoundingBox& box) const
     return frustum_.IsInsideFast(box) == INSIDE;
     return frustum_.IsInsideFast(box) == INSIDE;
 }
 }
 
 
+bool DebugRenderer::HasContent() const
+{
+    return (lines_.Empty() && noDepthLines_.Empty() && triangles_.Empty() && noDepthTriangles_.Empty()) ? false : true;
+}
+
 void DebugRenderer::HandleEndFrame(StringHash eventType, VariantMap& eventData)
 void DebugRenderer::HandleEndFrame(StringHash eventType, VariantMap& eventData)
 {
 {
     // When the amount of debug geometry is reduced, release memory
     // When the amount of debug geometry is reduced, release memory

+ 5 - 1
Source/Atomic/Graphics/DebugRenderer.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -126,6 +126,8 @@ public:
     void AddPolyhedron(const Polyhedron& poly, const Color& color, bool depthTest = true);
     void AddPolyhedron(const Polyhedron& poly, const Color& color, bool depthTest = true);
     /// Add a sphere.
     /// Add a sphere.
     void AddSphere(const Sphere& sphere, const Color& color, bool depthTest = true);
     void AddSphere(const Sphere& sphere, const Color& color, bool depthTest = true);
+    /// Add a cylinder
+    void AddCylinder(const Vector3& position, float radius, float height, const Color& color, bool depthTest = true);
     /// Add a skeleton.
     /// Add a skeleton.
     void AddSkeleton(const Skeleton& skeleton, const Color& color, bool depthTest = true);
     void AddSkeleton(const Skeleton& skeleton, const Color& color, bool depthTest = true);
     /// Add a triangle mesh.
     /// Add a triangle mesh.
@@ -141,6 +143,8 @@ public:
     const Frustum& GetFrustum() const { return frustum_; }
     const Frustum& GetFrustum() const { return frustum_; }
     /// Check whether a bounding box is inside the view frustum.
     /// Check whether a bounding box is inside the view frustum.
     bool IsInside(const BoundingBox& box) const;
     bool IsInside(const BoundingBox& box) const;
+    /// Return whether has something to render.
+    bool HasContent() const;
     
     
 private:
 private:
     /// Handle end of frame. Clear debug geometry.
     /// Handle end of frame. Clear debug geometry.

+ 26 - 20
Source/Atomic/Graphics/Drawable.cpp

@@ -1,6 +1,6 @@
 //
 //
 
 
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -62,6 +62,9 @@ Drawable::Drawable(Context* context, unsigned char drawableFlags) :
     occluder_(false),
     occluder_(false),
     occludee_(true),
     occludee_(true),
     updateQueued_(false),
     updateQueued_(false),
+    zoneDirty_(false),
+    octant_(0),
+    zone_(0),
     viewMask_(DEFAULT_VIEWMASK),
     viewMask_(DEFAULT_VIEWMASK),
     lightMask_(DEFAULT_LIGHTMASK),
     lightMask_(DEFAULT_LIGHTMASK),
     shadowMask_(DEFAULT_SHADOWMASK),
     shadowMask_(DEFAULT_SHADOWMASK),
@@ -77,10 +80,7 @@ Drawable::Drawable(Context* context, unsigned char drawableFlags) :
     lodBias_(1.0f),
     lodBias_(1.0f),
     basePassFlags_(0),
     basePassFlags_(0),
     maxLights_(0),
     maxLights_(0),
-    octant_(0),
-    firstLight_(0),
-    zone_(0),
-    zoneDirty_(false)
+    firstLight_(0)
 {
 {
 }
 }
 
 
@@ -294,33 +294,30 @@ void Drawable::SetSortValue(float value)
     sortValue_ = value;
     sortValue_ = value;
 }
 }
 
 
-void Drawable::SetMinMaxZ(float minZ, float maxZ)
-{
-    minZ_ = minZ;
-    maxZ_ = maxZ;
-}
-
 void Drawable::MarkInView(const FrameInfo& frame)
 void Drawable::MarkInView(const FrameInfo& frame)
 {
 {
     if (frame.frameNumber_ != viewFrameNumber_)
     if (frame.frameNumber_ != viewFrameNumber_)
     {
     {
         viewFrameNumber_ = frame.frameNumber_;
         viewFrameNumber_ = frame.frameNumber_;
-        viewCameras_.Clear();
+        viewCameras_.Resize(1);
+        viewCameras_[0] = frame.camera_;
     }
     }
-    
-    viewCameras_.Insert(frame.camera_);
+    else
+        viewCameras_.Push(frame.camera_);
+
+    basePassFlags_ = 0;
+    firstLight_ = 0;
+    lights_.Clear();
+    vertexLights_.Clear();
 }
 }
 
 
-void Drawable::MarkInView(unsigned frameNumber, Camera* camera)
+void Drawable::MarkInView(unsigned frameNumber)
 {
 {
     if (frameNumber != viewFrameNumber_)
     if (frameNumber != viewFrameNumber_)
     {
     {
         viewFrameNumber_ = frameNumber;
         viewFrameNumber_ = frameNumber;
         viewCameras_.Clear();
         viewCameras_.Clear();
     }
     }
-    
-    if (camera)
-        viewCameras_.Insert(camera);
 }
 }
 
 
 void Drawable::LimitLights()
 void Drawable::LimitLights()
@@ -339,13 +336,22 @@ void Drawable::LimitLights()
     lights_.Resize(maxLights_);
     lights_.Resize(maxLights_);
 }
 }
 
 
-void Drawable::LimitVertexLights()
+void Drawable::LimitVertexLights(bool removeConvertedLights)
 {
 {
+    if (removeConvertedLights)
+    {
+        for (unsigned i = vertexLights_.Size() - 1; i < vertexLights_.Size(); --i)
+        {
+            if (!vertexLights_[i]->GetPerVertex())
+                vertexLights_.Erase(i);
+        }
+    }
+
     if (vertexLights_.Size() <= MAX_VERTEX_LIGHTS)
     if (vertexLights_.Size() <= MAX_VERTEX_LIGHTS)
         return;
         return;
 
 
     const BoundingBox& box = GetWorldBoundingBox();
     const BoundingBox& box = GetWorldBoundingBox();
-    for (unsigned i = vertexLights_.Size() - 1; i < vertexLights_.Size(); --i)
+    for (unsigned i = 0; i < vertexLights_.Size(); ++i)
         vertexLights_[i]->SetIntensitySortValue(box);
         vertexLights_[i]->SetIntensitySortValue(box);
 
 
     Sort(vertexLights_.Begin(), vertexLights_.End(), CompareDrawables);
     Sort(vertexLights_.Begin(), vertexLights_.End(), CompareDrawables);

+ 22 - 28
Source/Atomic/Graphics/Drawable.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,6 @@
 #include "../Math/BoundingBox.h"
 #include "../Math/BoundingBox.h"
 #include "../Scene/Component.h"
 #include "../Scene/Component.h"
 #include "../Graphics/GraphicsDefs.h"
 #include "../Graphics/GraphicsDefs.h"
-#include "../Container/HashSet.h"
 
 
 namespace Atomic
 namespace Atomic
 {
 {
@@ -201,15 +200,15 @@ public:
     /// Set sorting value.
     /// Set sorting value.
     void SetSortValue(float value);
     void SetSortValue(float value);
     /// Set view-space depth bounds.
     /// Set view-space depth bounds.
-    void SetMinMaxZ(float minZ, float maxZ);
-    /// Mark in view.
+    void SetMinMaxZ(float minZ, float maxZ) { minZ_ = minZ; maxZ_ = maxZ; }
+    /// Mark in view. Also clear the light list.
     void MarkInView(const FrameInfo& frame);
     void MarkInView(const FrameInfo& frame);
-    /// Mark in view of a specific camera. Specify null camera to update just the frame number.
-    void MarkInView(unsigned frameNumber, Camera* camera);
+    /// Mark in view without specifying a camera. Used for shadow casters.
+    void MarkInView(unsigned frameNumber);
     /// Sort and limit per-pixel lights to maximum allowed. Convert extra lights into vertex lights.
     /// Sort and limit per-pixel lights to maximum allowed. Convert extra lights into vertex lights.
     void LimitLights();
     void LimitLights();
     /// Sort and limit per-vertex lights to maximum allowed.
     /// Sort and limit per-vertex lights to maximum allowed.
-    void LimitVertexLights();
+    void LimitVertexLights(bool removeConvertedLights);
     /// Set base pass flag for a batch.
     /// Set base pass flag for a batch.
     void SetBasePass(unsigned batchIndex) { basePassFlags_ |= (1 << batchIndex); }
     void SetBasePass(unsigned batchIndex) { basePassFlags_ |= (1 << batchIndex); }
     /// Return octree octant.
     /// Return octree octant.
@@ -239,21 +238,16 @@ public:
     /// Return the maximum view-space depth.
     /// Return the maximum view-space depth.
     float GetMaxZ() const { return maxZ_; }
     float GetMaxZ() const { return maxZ_; }
     
     
-    // Clear the frame's light list.
-    void ClearLights()
-    {
-        basePassFlags_ = 0;
-        firstLight_ = 0;
-        lights_.Clear();
-        vertexLights_.Clear();
-    }
-
     // Add a per-pixel light affecting the object this frame.
     // Add a per-pixel light affecting the object this frame.
     void AddLight(Light* light)
     void AddLight(Light* light)
     {
     {
-        if (lights_.Empty())
+        if (!firstLight_)
             firstLight_ = light;
             firstLight_ = light;
-        lights_.Push(light);
+
+        // Need to store into the light list only if the per-pixel lights are being limited.
+        // Otherwise recording the first light is enough
+        if (maxLights_)
+            lights_.Push(light);
     }
     }
 
 
     // Add a per-vertex light affecting the object this frame.
     // Add a per-vertex light affecting the object this frame.
@@ -296,6 +290,12 @@ protected:
     bool occludee_;
     bool occludee_;
     /// Octree update queued flag.
     /// Octree update queued flag.
     bool updateQueued_;
     bool updateQueued_;
+    /// Zone inconclusive or dirtied flag.
+    bool zoneDirty_;
+    /// Octree octant.
+    Octant* octant_;
+    /// Current zone.
+    Zone* zone_;
     /// View mask.
     /// View mask.
     unsigned viewMask_;
     unsigned viewMask_;
     /// Light mask.
     /// Light mask.
@@ -322,24 +322,18 @@ protected:
     float maxZ_;
     float maxZ_;
     /// LOD bias.
     /// LOD bias.
     float lodBias_;
     float lodBias_;
-    /// Base pass flags.
+    /// Base pass flags, bit per batch.
     unsigned basePassFlags_;
     unsigned basePassFlags_;
-    /// Maximum lights.
+    /// Maximum per-pixel lights.
     unsigned maxLights_;
     unsigned maxLights_;
-    /// Octree octant.
-    Octant* octant_;
+    /// List of cameras from which is seen on the current frame.
+    PODVector<Camera*> viewCameras_;
     /// First per-pixel light added this frame.
     /// First per-pixel light added this frame.
     Light* firstLight_;
     Light* firstLight_;
     /// Per-pixel lights affecting this drawable.
     /// Per-pixel lights affecting this drawable.
     PODVector<Light*> lights_;
     PODVector<Light*> lights_;
     /// Per-vertex lights affecting this drawable.
     /// Per-vertex lights affecting this drawable.
     PODVector<Light*> vertexLights_;
     PODVector<Light*> vertexLights_;
-    /// Current zone.
-    Zone* zone_;
-    /// Zone inconclusive or dirtied flag.
-    bool zoneDirty_;
-    /// Set of cameras from which is seen on the current frame.
-    HashSet<Camera*> viewCameras_;
 };
 };
 
 
 inline bool CompareDrawables(Drawable* lhs, Drawable* rhs)
 inline bool CompareDrawables(Drawable* lhs, Drawable* rhs)

+ 4 - 2
Source/Atomic/Graphics/GPUObject.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLGPUObject.h"
 #include "OpenGL/OGLGPUObject.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11GPUObject.h"
 #else
 #else
 #include "Direct3D9/D3D9GPUObject.h"
 #include "Direct3D9/D3D9GPUObject.h"
 #endif
 #endif

+ 4 - 2
Source/Atomic/Graphics/Graphics.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLGraphics.h"
 #include "OpenGL/OGLGraphics.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11Graphics.h"
 #else
 #else
 #include "Direct3D9/D3D9Graphics.h"
 #include "Direct3D9/D3D9Graphics.h"
 #endif
 #endif

+ 2 - 15
Source/Atomic/Graphics/GraphicsDefs.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -35,6 +35,7 @@ extern ATOMIC_API const StringHash VSP_AMBIENTENDCOLOR("AmbientEndColor");
 extern ATOMIC_API const StringHash VSP_BILLBOARDROT("BillboardRot");
 extern ATOMIC_API const StringHash VSP_BILLBOARDROT("BillboardRot");
 extern ATOMIC_API const StringHash VSP_CAMERAPOS("CameraPos");
 extern ATOMIC_API const StringHash VSP_CAMERAPOS("CameraPos");
 extern ATOMIC_API const StringHash VSP_CAMERAROT("CameraRot");
 extern ATOMIC_API const StringHash VSP_CAMERAROT("CameraRot");
+extern ATOMIC_API const StringHash VSP_CLIPPLANE("ClipPlane");
 extern ATOMIC_API const StringHash VSP_NEARCLIP("NearClip");
 extern ATOMIC_API const StringHash VSP_NEARCLIP("NearClip");
 extern ATOMIC_API const StringHash VSP_FARCLIP("FarClip");
 extern ATOMIC_API const StringHash VSP_FARCLIP("FarClip");
 extern ATOMIC_API const StringHash VSP_DEPTHMODE("DepthMode");
 extern ATOMIC_API const StringHash VSP_DEPTHMODE("DepthMode");
@@ -77,20 +78,6 @@ extern ATOMIC_API const StringHash PSP_SHADOWMAPINVSIZE("ShadowMapInvSize");
 extern ATOMIC_API const StringHash PSP_SHADOWSPLITS("ShadowSplits");
 extern ATOMIC_API const StringHash PSP_SHADOWSPLITS("ShadowSplits");
 extern ATOMIC_API const StringHash PSP_LIGHTMATRICES("LightMatricesPS");
 extern ATOMIC_API const StringHash PSP_LIGHTMATRICES("LightMatricesPS");
 
 
-extern ATOMIC_API const StringHash PASS_BASE("base");
-extern ATOMIC_API const StringHash PASS_LITBASE("litbase");
-extern ATOMIC_API const StringHash PASS_LIGHT("light");
-extern ATOMIC_API const StringHash PASS_ALPHA("alpha");
-extern ATOMIC_API const StringHash PASS_LITALPHA("litalpha");
-extern ATOMIC_API const StringHash PASS_SHADOW("shadow");
-extern ATOMIC_API const StringHash PASS_DEFERRED("deferred");
-extern ATOMIC_API const StringHash PASS_PREPASS("prepass");
-extern ATOMIC_API const StringHash PASS_MATERIAL("material");
-extern ATOMIC_API const StringHash PASS_POSTOPAQUE("postopaque");
-extern ATOMIC_API const StringHash PASS_REFRACT("refract");
-extern ATOMIC_API const StringHash PASS_POSTALPHA("postalpha");
-extern ATOMIC_API const StringHash PASS_LIGHT2D("light2d");
-
 extern ATOMIC_API const Vector3 DOT_SCALE(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
 extern ATOMIC_API const Vector3 DOT_SCALE(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
 
 
 }
 }

+ 25 - 29
Source/Atomic/Graphics/GraphicsDefs.h

@@ -218,17 +218,16 @@ enum ShaderType
     PS,
     PS,
 };
 };
 
 
-/// Shader parameter groups for determining need to update.
+/// Shader parameter groups for determining need to update. On APIs that support constant buffers, these correspond to different constant buffers.
 enum ShaderParameterGroup
 enum ShaderParameterGroup
 {
 {
     SP_FRAME = 0,
     SP_FRAME = 0,
     SP_CAMERA,
     SP_CAMERA,
-    SP_VIEWPORT,
     SP_ZONE,
     SP_ZONE,
     SP_LIGHT,
     SP_LIGHT,
-    SP_VERTEXLIGHTS,
     SP_MATERIAL,
     SP_MATERIAL,
-    SP_OBJECTTRANSFORM,
+    SP_OBJECT,
+    SP_CUSTOM,
     MAX_SHADER_PARAMETER_GROUPS
     MAX_SHADER_PARAMETER_GROUPS
 };
 };
 
 
@@ -242,18 +241,30 @@ enum TextureUnit
     TU_SPECULAR = 2,
     TU_SPECULAR = 2,
     TU_EMISSIVE = 3,
     TU_EMISSIVE = 3,
     TU_ENVIRONMENT = 4,
     TU_ENVIRONMENT = 4,
-    MAX_MATERIAL_TEXTURE_UNITS = 5,
+#ifdef DESKTOP_GRAPHICS
+    TU_VOLUMEMAP = 5,
+    TU_CUSTOM1 = 6,
+    TU_CUSTOM2 = 7,
+    TU_LIGHTRAMP = 8,
+    TU_LIGHTSHAPE = 9,
+    TU_SHADOWMAP = 10,
+    TU_FACESELECT = 11,
+    TU_INDIRECTION = 12,
+    TU_DEPTHBUFFER = 13,
+    TU_LIGHTBUFFER = 14,
+    TU_ZONE = 15,
+    MAX_MATERIAL_TEXTURE_UNITS = 8,
+    MAX_TEXTURE_UNITS = 16
+#else
+    #error JSBind has a enum collision as doesn't know about "DESKTOP_GRAPHICS
+    /*
     TU_LIGHTRAMP = 5,
     TU_LIGHTRAMP = 5,
     TU_LIGHTSHAPE = 6,
     TU_LIGHTSHAPE = 6,
     TU_SHADOWMAP = 7,
     TU_SHADOWMAP = 7,
-    TU_FACESELECT = 8,
-    TU_INDIRECTION = 9,
-    TU_DEPTHBUFFER = 10,
-    TU_LIGHTBUFFER = 11,
-    TU_VOLUMEMAP = 12,
-    TU_ZONE = 13,
-    MAX_NAMED_TEXTURE_UNITS = 14,
-    MAX_TEXTURE_UNITS = 16
+    MAX_MATERIAL_TEXTURE_UNITS = 5,
+    MAX_TEXTURE_UNITS = 8
+    */
+#endif
 };
 };
 
 
 /// Billboard camera facing modes.
 /// Billboard camera facing modes.
@@ -272,6 +283,7 @@ extern ATOMIC_API const StringHash VSP_AMBIENTENDCOLOR;
 extern ATOMIC_API const StringHash VSP_BILLBOARDROT;
 extern ATOMIC_API const StringHash VSP_BILLBOARDROT;
 extern ATOMIC_API const StringHash VSP_CAMERAPOS;
 extern ATOMIC_API const StringHash VSP_CAMERAPOS;
 extern ATOMIC_API const StringHash VSP_CAMERAROT;
 extern ATOMIC_API const StringHash VSP_CAMERAROT;
+extern ATOMIC_API const StringHash VSP_CLIPPLANE;
 extern ATOMIC_API const StringHash VSP_NEARCLIP;
 extern ATOMIC_API const StringHash VSP_NEARCLIP;
 extern ATOMIC_API const StringHash VSP_FARCLIP;
 extern ATOMIC_API const StringHash VSP_FARCLIP;
 extern ATOMIC_API const StringHash VSP_DEPTHMODE;
 extern ATOMIC_API const StringHash VSP_DEPTHMODE;
@@ -314,21 +326,6 @@ extern ATOMIC_API const StringHash PSP_SHADOWMAPINVSIZE;
 extern ATOMIC_API const StringHash PSP_SHADOWSPLITS;
 extern ATOMIC_API const StringHash PSP_SHADOWSPLITS;
 extern ATOMIC_API const StringHash PSP_LIGHTMATRICES;
 extern ATOMIC_API const StringHash PSP_LIGHTMATRICES;
 
 
-// Inbuilt pass types
-extern ATOMIC_API const StringHash PASS_BASE;
-extern ATOMIC_API const StringHash PASS_LITBASE;
-extern ATOMIC_API const StringHash PASS_LIGHT;
-extern ATOMIC_API const StringHash PASS_ALPHA;
-extern ATOMIC_API const StringHash PASS_LITALPHA;
-extern ATOMIC_API const StringHash PASS_SHADOW;
-extern ATOMIC_API const StringHash PASS_DEFERRED;
-extern ATOMIC_API const StringHash PASS_PREPASS;
-extern ATOMIC_API const StringHash PASS_MATERIAL;
-extern ATOMIC_API const StringHash PASS_POSTOPAQUE;
-extern ATOMIC_API const StringHash PASS_REFRACT;
-extern ATOMIC_API const StringHash PASS_POSTALPHA;
-extern ATOMIC_API const StringHash PASS_LIGHT2D;
-
 // Scale calculation from bounding box diagonal.
 // Scale calculation from bounding box diagonal.
 extern ATOMIC_API const Vector3 DOT_SCALE;
 extern ATOMIC_API const Vector3 DOT_SCALE;
 
 
@@ -365,7 +362,6 @@ static const unsigned NO_ELEMENT = 0xffffffff;
 
 
 static const int MAX_RENDERTARGETS = 4;
 static const int MAX_RENDERTARGETS = 4;
 static const int MAX_VERTEX_STREAMS = 4;
 static const int MAX_VERTEX_STREAMS = 4;
-static const int MAX_SKIN_MATRICES = 64;
 static const int MAX_CONSTANT_REGISTERS = 256;
 static const int MAX_CONSTANT_REGISTERS = 256;
 
 
 static const int BITS_PER_COMPONENT = 8;
 static const int BITS_PER_COMPONENT = 8;

+ 0 - 5
Source/Atomic/Graphics/GraphicsEvents.h

@@ -44,11 +44,6 @@ EVENT(E_WINDOWPOS, WindowPos)
     PARAM(P_Y, Y);                          // int
     PARAM(P_Y, Y);                          // int
 }
 }
 
 
-/// Graphics features checked.
-EVENT(E_GRAPHICSFEATURES, GraphicsFeatures)
-{
-}
-
 /// Request for queuing autoupdated rendersurfaces.
 /// Request for queuing autoupdated rendersurfaces.
 EVENT(E_RENDERSURFACEUPDATE, RenderSurfaceUpdate)
 EVENT(E_RENDERSURFACEUPDATE, RenderSurfaceUpdate)
 {
 {

+ 4 - 2
Source/Atomic/Graphics/GraphicsImpl.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLGraphicsImpl.h"
 #include "OpenGL/OGLGraphicsImpl.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11GraphicsImpl.h"
 #else
 #else
 #include "Direct3D9/D3D9GraphicsImpl.h"
 #include "Direct3D9/D3D9GraphicsImpl.h"
 #endif
 #endif

+ 4 - 2
Source/Atomic/Graphics/IndexBuffer.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLIndexBuffer.h"
 #include "OpenGL/OGLIndexBuffer.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11IndexBuffer.h"
 #else
 #else
 #include "Direct3D9/D3D9IndexBuffer.h"
 #include "Direct3D9/D3D9IndexBuffer.h"
 #endif
 #endif

+ 3 - 12
Source/Atomic/Graphics/Light.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -397,16 +397,7 @@ int Light::GetNumShadowSplits() const
         }
         }
     }
     }
 
 
-    ret = Min(ret, MAX_CASCADE_SPLITS);
-    // Shader Model 2 can only support 3 splits max. due to pixel shader instruction count limits
-    if (ret == 4)
-    {
-        Graphics* graphics = GetSubsystem<Graphics>();
-        if (graphics && !graphics->GetSM3Support())
-            --ret;
-    }
-
-    return ret;
+    return Min(ret, MAX_CASCADE_SPLITS);
 }
 }
 
 
 const Matrix3x4& Light::GetVolumeTransform(Camera* camera)
 const Matrix3x4& Light::GetVolumeTransform(Camera* camera)
@@ -557,7 +548,7 @@ void Light::SetIntensitySortValue(const BoundingBox& box)
             float distance = lightRay.HitDistance(box);
             float distance = lightRay.HitDistance(box);
             float normDistance = distance / range_;
             float normDistance = distance / range_;
             float att = Max(1.0f - normDistance * normDistance, M_EPSILON);
             float att = Max(1.0f - normDistance * normDistance, M_EPSILON);
-            sortValue_ = 1.0f / (Max(color_.SumRGB(), 0.0f) * att + M_EPSILON);
+            sortValue_ = 1.0f / GetIntensityDivisor(att);
         }
         }
         break;
         break;
     }
     }

+ 65 - 24
Source/Atomic/Graphics/Material.cpp

@@ -36,6 +36,7 @@
 #include "../Core/StringUtils.h"
 #include "../Core/StringUtils.h"
 #include "../Graphics/Technique.h"
 #include "../Graphics/Technique.h"
 #include "../Graphics/Texture2D.h"
 #include "../Graphics/Texture2D.h"
+#include "../Graphics/Texture3D.h"
 #include "../Graphics/TextureCube.h"
 #include "../Graphics/TextureCube.h"
 #include "../Scene/ValueAnimation.h"
 #include "../Scene/ValueAnimation.h"
 #include "../Resource/XMLFile.h"
 #include "../Resource/XMLFile.h"
@@ -54,6 +55,10 @@ static const char* textureUnitNames[] =
     "specular",
     "specular",
     "emissive",
     "emissive",
     "environment",
     "environment",
+#ifdef DESKTOP_GRAPHICS
+    "volume",
+    "custom1",
+    "custom2",
     "lightramp",
     "lightramp",
     "lightshape",
     "lightshape",
     "shadowmap",
     "shadowmap",
@@ -61,9 +66,14 @@ static const char* textureUnitNames[] =
     "indirection",
     "indirection",
     "depth",
     "depth",
     "light",
     "light",
-    "volume",
     "zone",
     "zone",
     0
     0
+#else
+    "lightramp",
+    "lightshape",
+    "shadowmap",
+    0
+#endif
 };
 };
 
 
 static const char* cullModeNames[] =
 static const char* cullModeNames[] =
@@ -74,6 +84,14 @@ static const char* cullModeNames[] =
     0
     0
 };
 };
 
 
+static const char* fillModeNames[] =
+{
+    "solid",
+    "wireframe",
+    "point",
+    0
+};
+
 TextureUnit ParseTextureUnitName(String name)
 TextureUnit ParseTextureUnitName(String name)
 {
 {
     name = name.ToLower().Trimmed();
     name = name.ToLower().Trimmed();
@@ -154,7 +172,6 @@ void ShaderParameterAnimationInfo::ApplyValue(const Variant& newValue)
 Material::Material(Context* context) :
 Material::Material(Context* context) :
     Resource(context),
     Resource(context),
     auxViewFrameNumber_(0),
     auxViewFrameNumber_(0),
-    numUsedTextureUnits_(0),
     shaderParameterHash_(0),
     shaderParameterHash_(0),
     occlusion_(true),
     occlusion_(true),
     specular_(false),
     specular_(false),
@@ -203,7 +220,17 @@ bool Material::BeginLoad(Deserializer& source)
                 // Detect cube maps by file extension: they are defined by an XML file
                 // Detect cube maps by file extension: they are defined by an XML file
                 /// \todo Differentiate with 3D textures by actually reading the XML content
                 /// \todo Differentiate with 3D textures by actually reading the XML content
                 if (GetExtension(name) == ".xml")
                 if (GetExtension(name) == ".xml")
-                    cache->BackgroundLoadResource<TextureCube>(name, true, this);
+                {
+                    #ifdef DESKTOP_GRAPHICS
+                    TextureUnit unit = TU_DIFFUSE;
+                    if (textureElem.HasAttribute("unit"))
+                        unit = ParseTextureUnitName(textureElem.GetAttribute("unit"));
+                    if (unit == TU_VOLUMEMAP)
+                        cache->BackgroundLoadResource<Texture3D>(name, true, this);
+                    else
+                    #endif
+                        cache->BackgroundLoadResource<TextureCube>(name, true, this);
+                }
                 else
                 else
                     cache->BackgroundLoadResource<Texture2D>(name, true, this);
                     cache->BackgroundLoadResource<Texture2D>(name, true, this);
                 textureElem = textureElem.GetNext("texture");
                 textureElem = textureElem.GetNext("texture");
@@ -295,7 +322,14 @@ bool Material::Load(const XMLElement& source)
             // Detect cube maps by file extension: they are defined by an XML file
             // Detect cube maps by file extension: they are defined by an XML file
             /// \todo Differentiate with 3D textures by actually reading the XML content
             /// \todo Differentiate with 3D textures by actually reading the XML content
             if (GetExtension(name) == ".xml")
             if (GetExtension(name) == ".xml")
-                SetTexture(unit, cache->GetResource<TextureCube>(name));
+            {
+                #ifdef DESKTOP_GRAPHICS
+                if (unit == TU_VOLUMEMAP)
+                    SetTexture(unit, cache->GetResource<Texture3D>(name));
+                else
+                #endif
+                    SetTexture(unit, cache->GetResource<TextureCube>(name));
+            }
             else
             else
                 SetTexture(unit, cache->GetResource<Texture2D>(name));
                 SetTexture(unit, cache->GetResource<Texture2D>(name));
         }
         }
@@ -348,6 +382,10 @@ bool Material::Load(const XMLElement& source)
     if (shadowCullElem)
     if (shadowCullElem)
         SetShadowCullMode((CullMode)GetStringListIndex(shadowCullElem.GetAttribute("value").CString(), cullModeNames, CULL_CCW));
         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");
     XMLElement depthBiasElem = source.GetChild("depthbias");
     if (depthBiasElem)
     if (depthBiasElem)
         SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled")));
         SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled")));
@@ -386,7 +424,7 @@ bool Material::Save(XMLElement& dest) const
         if (texture)
         if (texture)
         {
         {
             XMLElement textureElem = dest.CreateChild("texture");
             XMLElement textureElem = dest.CreateChild("texture");
-            textureElem.SetString("unit", j < MAX_NAMED_TEXTURE_UNITS ? textureUnitNames[j] : String(j).CString());
+            textureElem.SetString("unit", textureUnitNames[j]);
             textureElem.SetString("name", texture->GetName());
             textureElem.SetString("name", texture->GetName());
         }
         }
     }
     }
@@ -419,6 +457,10 @@ bool Material::Save(XMLElement& dest) const
     XMLElement shadowCullElem = dest.CreateChild("shadowcull");
     XMLElement shadowCullElem = dest.CreateChild("shadowcull");
     shadowCullElem.SetString("value", cullModeNames[shadowCullMode_]);
     shadowCullElem.SetString("value", cullModeNames[shadowCullMode_]);
 
 
+    // Write fill mode
+    XMLElement fillElem = dest.CreateChild("fill");
+    fillElem.SetString("value", fillModeNames[fillMode_]);
+
     // Write depth bias
     // Write depth bias
     XMLElement depthBiasElem = dest.CreateChild("depthbias");
     XMLElement depthBiasElem = dest.CreateChild("depthbias");
     depthBiasElem.SetFloat("constant", depthBias_.constantBias_);
     depthBiasElem.SetFloat("constant", depthBias_.constantBias_);
@@ -527,16 +569,10 @@ void Material::SetTexture(TextureUnit unit, Texture* texture)
 {
 {
     if (unit < MAX_TEXTURE_UNITS)
     if (unit < MAX_TEXTURE_UNITS)
     {
     {
-        textures_[unit] = texture;
-
-        // Update the number of used texture units
-        if (texture && (unsigned)unit >= numUsedTextureUnits_)
-            numUsedTextureUnits_ = unit + 1;
-        else if (!texture && unit == numUsedTextureUnits_ - 1)
-        {
-            while (numUsedTextureUnits_ && !textures_[numUsedTextureUnits_ - 1])
-                --numUsedTextureUnits_;
-        }
+        if (texture)
+            textures_[unit] = texture;
+        else
+            textures_.Erase(unit);
     }
     }
 }
 }
 
 
@@ -583,6 +619,11 @@ void Material::SetShadowCullMode(CullMode mode)
     shadowCullMode_ = mode;
     shadowCullMode_ = mode;
 }
 }
 
 
+void Material::SetFillMode(FillMode mode)
+{
+    fillMode_ = mode;
+}
+
 void Material::SetDepthBias(const BiasParameters& parameters)
 void Material::SetDepthBias(const BiasParameters& parameters)
 {
 {
     depthBias_ = parameters;
     depthBias_ = parameters;
@@ -627,13 +668,12 @@ SharedPtr<Material> Material::Clone(const String& cloneName) const
     ret->SetName(cloneName);
     ret->SetName(cloneName);
     ret->techniques_ = techniques_;
     ret->techniques_ = techniques_;
     ret->shaderParameters_ = shaderParameters_;
     ret->shaderParameters_ = shaderParameters_;
-    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-        ret->textures_[i] = textures_[i];
+    ret->textures_ = textures_;
     ret->occlusion_ = occlusion_;
     ret->occlusion_ = occlusion_;
     ret->specular_ = specular_;
     ret->specular_ = specular_;
     ret->cullMode_ = cullMode_;
     ret->cullMode_ = cullMode_;
     ret->shadowCullMode_ = shadowCullMode_;
     ret->shadowCullMode_ = shadowCullMode_;
-    ret->numUsedTextureUnits_ = numUsedTextureUnits_;
+    ret->fillMode_ = fillMode_;
     ret->RefreshMemoryUse();
     ret->RefreshMemoryUse();
 
 
     return ret;
     return ret;
@@ -659,15 +699,16 @@ Technique* Material::GetTechnique(unsigned index) const
     return index < techniques_.Size() ? techniques_[index].technique_ : (Technique*)0;
     return index < techniques_.Size() ? techniques_[index].technique_ : (Technique*)0;
 }
 }
 
 
-Pass* Material::GetPass(unsigned index, StringHash passType) const
+Pass* Material::GetPass(unsigned index, const String& passName) const
 {
 {
     Technique* tech = index < techniques_.Size() ? techniques_[index].technique_ : (Technique*)0;
     Technique* tech = index < techniques_.Size() ? techniques_[index].technique_ : (Technique*)0;
-    return tech ? tech->GetPass(passType) : 0;
+    return tech ? tech->GetPass(passName) : 0;
 }
 }
 
 
 Texture* Material::GetTexture(TextureUnit unit) const
 Texture* Material::GetTexture(TextureUnit unit) const
 {
 {
-    return unit < MAX_TEXTURE_UNITS ? textures_[unit] : (Texture*)0;
+    HashMap<TextureUnit, SharedPtr<Texture> >::ConstIterator i = textures_.Find(unit);
+    return i != textures_.End() ? i->second_.Get() : (Texture*)0;
 }
 }
 
 
 const Variant& Material::GetShaderParameter(const String& name) const
 const Variant& Material::GetShaderParameter(const String& name) const
@@ -722,7 +763,7 @@ void Material::CheckOcclusion()
         Technique* tech = techniques_[i].technique_;
         Technique* tech = techniques_[i].technique_;
         if (tech)
         if (tech)
         {
         {
-            Pass* pass = tech->GetPass(PASS_BASE);
+            Pass* pass = tech->GetPass("base");
             if (pass && pass->GetDepthWrite() && !pass->GetAlphaMask())
             if (pass && pass->GetDepthWrite() && !pass->GetAlphaMask())
                 occlusion_ = true;
                 occlusion_ = true;
         }
         }
@@ -738,8 +779,7 @@ void Material::ResetToDefaults()
     SetNumTechniques(1);
     SetNumTechniques(1);
     SetTechnique(0, GetSubsystem<ResourceCache>()->GetResource<Technique>("Techniques/NoTexture.xml"));
     SetTechnique(0, GetSubsystem<ResourceCache>()->GetResource<Technique>("Techniques/NoTexture.xml"));
 
 
-    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-        textures_[i] = 0;
+    textures_.Clear();
 
 
     batchedParameterUpdate_ = true;
     batchedParameterUpdate_ = true;
     shaderParameters_.Clear();
     shaderParameters_.Clear();
@@ -753,6 +793,7 @@ void Material::ResetToDefaults()
 
 
     cullMode_ = CULL_CCW;
     cullMode_ = CULL_CCW;
     shadowCullMode_ = CULL_CCW;
     shadowCullMode_ = CULL_CCW;
+    fillMode_ = FILL_SOLID;
     depthBias_ = BiasParameters(0.0f, 0.0f);
     depthBias_ = BiasParameters(0.0f, 0.0f);
 
 
     RefreshShaderParameterHash();
     RefreshShaderParameterHash();

+ 16 - 8
Source/Atomic/Graphics/Material.h

@@ -90,6 +90,12 @@ private:
     String name_;
     String name_;
 };
 };
 
 
+/// TextureUnit hash function.
+template<> inline unsigned MakeHash(const TextureUnit& value)
+{
+    return (unsigned)value;
+}
+
 /// Describes how to render 3D geometries.
 /// Describes how to render 3D geometries.
 class ATOMIC_API Material : public Resource
 class ATOMIC_API Material : public Resource
 {
 {
@@ -136,6 +142,8 @@ public:
     void SetCullMode(CullMode mode);
     void SetCullMode(CullMode mode);
     /// Set culling mode for shadows.
     /// Set culling mode for shadows.
     void SetShadowCullMode(CullMode mode);
     void SetShadowCullMode(CullMode mode);
+    /// Set polygon fill mode. Interacts with the camera's fill mode setting so that the "least filled" mode will be used.
+    void SetFillMode(FillMode mode);
     /// Set depth bias.
     /// Set depth bias.
     void SetDepthBias(const BiasParameters& parameters);
     void SetDepthBias(const BiasParameters& parameters);
     /// Associate the material with a scene to ensure that shader parameter animation happens in sync with scene update, respecting the scene time scale. If no scene is set, the global update events will be used.
     /// Associate the material with a scene to ensure that shader parameter animation happens in sync with scene update, respecting the scene time scale. If no scene is set, the global update events will be used.
@@ -159,12 +167,12 @@ public:
     const TechniqueEntry& GetTechniqueEntry(unsigned index) const;
     const TechniqueEntry& GetTechniqueEntry(unsigned index) const;
     /// Return technique by index.
     /// Return technique by index.
     Technique* GetTechnique(unsigned index) const;
     Technique* GetTechnique(unsigned index) const;
-    /// Return pass by technique index and pass type.
-    Pass* GetPass(unsigned index, StringHash passType) const;
+    /// Return pass by technique index and pass name.
+    Pass* GetPass(unsigned index, const String& passName) const;
     /// Return texture by unit.
     /// Return texture by unit.
     Texture* GetTexture(TextureUnit unit) const;
     Texture* GetTexture(TextureUnit unit) const;
    /// Return all textures.
    /// Return all textures.
-    const SharedPtr<Texture>* GetTextures() const { return &textures_[0]; }
+    const HashMap<TextureUnit, SharedPtr<Texture> >& GetTextures() const { return textures_; }
     /// Return shader parameter.
     /// Return shader parameter.
     const Variant& GetShaderParameter(const String& name) const;
     const Variant& GetShaderParameter(const String& name) const;
     /// Return shader parameter animation.
     /// Return shader parameter animation.
@@ -179,6 +187,8 @@ public:
     CullMode GetCullMode() const { return cullMode_; }
     CullMode GetCullMode() const { return cullMode_; }
     /// Return culling mode for shadows.
     /// Return culling mode for shadows.
     CullMode GetShadowCullMode() const { return shadowCullMode_; }
     CullMode GetShadowCullMode() const { return shadowCullMode_; }
+    /// Return polygon fill mode.
+    FillMode GetFillMode() const { return fillMode_; }
     /// Return depth bias.
     /// Return depth bias.
     const BiasParameters& GetDepthBias() const { return depthBias_; }
     const BiasParameters& GetDepthBias() const { return depthBias_; }
     /// Return last auxiliary view rendered frame number.
     /// Return last auxiliary view rendered frame number.
@@ -189,8 +199,6 @@ public:
     bool GetSpecular() const { return specular_; }
     bool GetSpecular() const { return specular_; }
     /// Return the scene associated with the material for shader parameter animation updates.
     /// Return the scene associated with the material for shader parameter animation updates.
     Scene* GetScene() const;
     Scene* GetScene() const;
-    /// Return the last non-null texture unit + 1. Used as an optimization when applying the material to render state.
-    unsigned GetNumUsedTextureUnits() const { return numUsedTextureUnits_; }
     /// Return shader parameter hash value. Used as an optimization to avoid setting shader parameters unnecessarily.
     /// Return shader parameter hash value. Used as an optimization to avoid setting shader parameters unnecessarily.
     unsigned GetShaderParameterHash() const { return shaderParameterHash_; }
     unsigned GetShaderParameterHash() const { return shaderParameterHash_; }
 
 
@@ -218,7 +226,7 @@ private:
     /// Techniques.
     /// Techniques.
     Vector<TechniqueEntry> techniques_;
     Vector<TechniqueEntry> techniques_;
     /// Textures.
     /// Textures.
-    SharedPtr<Texture> textures_[MAX_TEXTURE_UNITS];
+    HashMap<TextureUnit, SharedPtr<Texture> > textures_;
     /// %Shader parameters.
     /// %Shader parameters.
     HashMap<StringHash, MaterialShaderParameter> shaderParameters_;
     HashMap<StringHash, MaterialShaderParameter> shaderParameters_;
     /// %Shader parameters animation infos.
     /// %Shader parameters animation infos.
@@ -227,12 +235,12 @@ private:
     CullMode cullMode_;
     CullMode cullMode_;
     /// Culling mode for shadow rendering.
     /// Culling mode for shadow rendering.
     CullMode shadowCullMode_;
     CullMode shadowCullMode_;
+    /// Polygon fill mode.
+    FillMode fillMode_;
     /// Depth bias parameters.
     /// Depth bias parameters.
     BiasParameters depthBias_;
     BiasParameters depthBias_;
     /// Last auxiliary view rendered frame number.
     /// Last auxiliary view rendered frame number.
     unsigned auxViewFrameNumber_;
     unsigned auxViewFrameNumber_;
-    /// Number of maximum non-null texture unit + 1.
-    unsigned numUsedTextureUnits_;
     /// Shader parameter hash value.
     /// Shader parameter hash value.
     unsigned shaderParameterHash_;
     unsigned shaderParameterHash_;
     /// Render occlusion flag.
     /// Render occlusion flag.

+ 1 - 1
Source/Atomic/Graphics/OpenGL/OGLConstantBuffer.cpp

@@ -27,7 +27,7 @@
 
 
 #include "../../DebugNew.h"
 #include "../../DebugNew.h"
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 
 

+ 2 - 2
Source/Atomic/Graphics/OpenGL/OGLConstantBuffer.h

@@ -27,11 +27,11 @@
 #include "../../Container/ArrayPtr.h"
 #include "../../Container/ArrayPtr.h"
 #include "../../Core/Object.h"
 #include "../../Core/Object.h"
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 /// Hardware constant buffer.
 /// Hardware constant buffer.
-class URHO3D_API ConstantBuffer : public Object, public GPUObject
+class ATOMIC_API ConstantBuffer : public Object, public GPUObject
 {
 {
     OBJECT(ConstantBuffer);
     OBJECT(ConstantBuffer);
     
     

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 322 - 316
Source/Atomic/Graphics/OpenGL/OGLGraphics.cpp


+ 61 - 42
Source/Atomic/Graphics/OpenGL/OGLGraphics.h

@@ -34,6 +34,7 @@
 namespace Atomic
 namespace Atomic
 {
 {
 
 
+class ConstantBuffer;
 class File;
 class File;
 class Image;
 class Image;
 class IndexBuffer;
 class IndexBuffer;
@@ -54,7 +55,6 @@ class VertexBuffer;
 typedef HashMap<Pair<ShaderVariation*, ShaderVariation*>, SharedPtr<ShaderProgram> > ShaderProgramMap;
 typedef HashMap<Pair<ShaderVariation*, ShaderVariation*>, SharedPtr<ShaderProgram> > ShaderProgramMap;
 
 
 static const unsigned NUM_SCREEN_BUFFERS = 2;
 static const unsigned NUM_SCREEN_BUFFERS = 2;
-static const unsigned NUM_TEMP_MATRICES = 8;
 
 
 /// CPU-side scratch buffer for vertex data updates.
 /// CPU-side scratch buffer for vertex data updates.
 struct ScratchBuffer
 struct ScratchBuffer
@@ -108,6 +108,8 @@ public:
     void SetSRGB(bool enable);
     void SetSRGB(bool enable);
     /// Set whether to flush the GPU command buffer to prevent multiple frames being queued and uneven frame timesteps. Not yet implemented on OpenGL.
     /// Set whether to flush the GPU command buffer to prevent multiple frames being queued and uneven frame timesteps. Not yet implemented on OpenGL.
     void SetFlushGPU(bool enable);
     void SetFlushGPU(bool enable);
+    /// Set forced use of OpenGL 2 even if OpenGL 3 is available. Must be called before setting the screen mode for the first time. Default false.
+    void SetForceGL2(bool enable);
     /// Set allowed screen orientations as a space-separated list of "LandscapeLeft", "LandscapeRight", "Portrait" and "PortraitUpsideDown". Affects currently only iOS platform.
     /// Set allowed screen orientations as a space-separated list of "LandscapeLeft", "LandscapeRight", "Portrait" and "PortraitUpsideDown". Affects currently only iOS platform.
     void SetOrientations(const String& orientations);
     void SetOrientations(const String& orientations);
     /// Toggle between full screen and windowed mode. Return true if successful.
     /// Toggle between full screen and windowed mode. Return true if successful.
@@ -172,8 +174,6 @@ public:
     void ClearParameterSources();
     void ClearParameterSources();
     /// Clear remembered transform shader parameter sources.
     /// Clear remembered transform shader parameter sources.
     void ClearTransformSources();
     void ClearTransformSources();
-    /// Clean up unused shader programs.
-    void CleanupShaderPrograms();
     /// Set texture.
     /// Set texture.
     void SetTexture(unsigned index, Texture* texture);
     void SetTexture(unsigned index, Texture* texture);
     /// Bind texture unit 0 for update. Called by Texture.
     /// Bind texture unit 0 for update. Called by Texture.
@@ -212,8 +212,6 @@ public:
     void SetDepthTest(CompareMode mode);
     void SetDepthTest(CompareMode mode);
     /// Set depth write on/off.
     /// Set depth write on/off.
     void SetDepthWrite(bool enable);
     void SetDepthWrite(bool enable);
-    /// Set antialiased drawing mode on/off. Default is on if the backbuffer is multisampled. Has no effect when backbuffer is not multisampled.
-    void SetDrawAntialiased(bool enable);
     /// Set polygon fill mode.
     /// Set polygon fill mode.
     void SetFillMode(FillMode mode);
     void SetFillMode(FillMode mode);
     /// Set scissor test.
     /// Set scissor test.
@@ -224,12 +222,6 @@ public:
     void SetStencilTest(bool enable, CompareMode mode = CMP_ALWAYS, StencilOp pass = OP_KEEP, StencilOp fail = OP_KEEP, StencilOp zFail = OP_KEEP, unsigned stencilRef = 0, unsigned compareMask = M_MAX_UNSIGNED, unsigned writeMask = M_MAX_UNSIGNED);
     void SetStencilTest(bool enable, CompareMode mode = CMP_ALWAYS, StencilOp pass = OP_KEEP, StencilOp fail = OP_KEEP, StencilOp zFail = OP_KEEP, unsigned stencilRef = 0, unsigned compareMask = M_MAX_UNSIGNED, unsigned writeMask = M_MAX_UNSIGNED);
     /// Set a custom clipping plane. The plane is specified in world space, but is dependent on the view and projection matrices.
     /// Set a custom clipping plane. The plane is specified in world space, but is dependent on the view and projection matrices.
     void SetClipPlane(bool enable, const Plane& clipPlane = Plane::UP, const Matrix3x4& view = Matrix3x4::IDENTITY, const Matrix4& projection = Matrix4::IDENTITY);
     void SetClipPlane(bool enable, const Plane& clipPlane = Plane::UP, const Matrix3x4& view = Matrix3x4::IDENTITY, const Matrix4& projection = Matrix4::IDENTITY);
-    /// Set vertex buffer stream frequency. No-op on OpenGL.
-    void SetStreamFrequency(unsigned index, unsigned frequency);
-    /// Reset stream frequencies. No-op on OpenGL.
-    void ResetStreamFrequencies();
-    /// Set force Shader Model 2 flag. No-op on OpenGL.
-    void SetForceSM2(bool enable);
     /// Begin dumping shader variation names to an XML file for precaching.
     /// Begin dumping shader variation names to an XML file for precaching.
     void BeginDumpShaders(const String& fileName);
     void BeginDumpShaders(const String& fileName);
     /// End dumping shader variations names.
     /// End dumping shader variations names.
@@ -245,6 +237,8 @@ public:
     void* GetExternalWindow() const { return externalWindow_; }
     void* GetExternalWindow() const { return externalWindow_; }
     /// Return window title.
     /// Return window title.
     const String& GetWindowTitle() const { return windowTitle_; }
     const String& GetWindowTitle() const { return windowTitle_; }
+    /// Return graphics API name.
+    const String& GetApiName() const { return apiName_; }
     /// Return window position.
     /// Return window position.
     IntVector2 GetWindowPosition() const;
     IntVector2 GetWindowPosition() const;
     /// Return window width.
     /// Return window width.
@@ -267,6 +261,8 @@ public:
     bool GetSRGB() const { return sRGB_; }
     bool GetSRGB() const { return sRGB_; }
     /// Return whether the GPU command buffer is flushed each frame. Not yet implemented on OpenGL.
     /// Return whether the GPU command buffer is flushed each frame. Not yet implemented on OpenGL.
     bool GetFlushGPU() const { return false; }
     bool GetFlushGPU() const { return false; }
+    /// Return whether OpenGL 2 use is forced.
+    bool GetForceGL2() const { return forceGL2_; }
     /// Return allowed screen orientations.
     /// Return allowed screen orientations.
     const String& GetOrientations() const { return orientations_; }
     const String& GetOrientations() const { return orientations_; }
     /// Return whether device is lost, and can not yet render.
     /// Return whether device is lost, and can not yet render.
@@ -281,8 +277,6 @@ public:
     unsigned GetShadowMapFormat() const { return shadowMapFormat_; }
     unsigned GetShadowMapFormat() const { return shadowMapFormat_; }
     /// Return 24-bit shadow map depth texture format, or 0 if not supported.
     /// Return 24-bit shadow map depth texture format, or 0 if not supported.
     unsigned GetHiresShadowMapFormat() const { return hiresShadowMapFormat_; }
     unsigned GetHiresShadowMapFormat() const { return hiresShadowMapFormat_; }
-    /// Return whether Shader Model 3 is supported. Has no meaning on OpenGL, so is assumed to be true.
-    bool GetSM3Support() const { return true; }
     /// Return whether hardware instancing is supported.
     /// Return whether hardware instancing is supported.
     bool GetInstancingSupport() const { return instancingSupport_; }
     bool GetInstancingSupport() const { return instancingSupport_; }
     /// Return whether light pre-pass rendering is supported.
     /// Return whether light pre-pass rendering is supported.
@@ -295,8 +289,6 @@ public:
     bool GetHardwareShadowSupport() const { return true; }
     bool GetHardwareShadowSupport() const { return true; }
     /// Return whether a readable hardware depth format is available.
     /// Return whether a readable hardware depth format is available.
     bool GetReadableDepthSupport() const { return GetReadableDepthFormat() != 0; }
     bool GetReadableDepthSupport() const { return GetReadableDepthFormat() != 0; }
-    /// Return whether stream offset is supported. Always true on OpenGL.
-    bool GetStreamOffsetSupport() const { return true; }
     /// Return whether sRGB conversion on texture sampling is supported.
     /// Return whether sRGB conversion on texture sampling is supported.
     bool GetSRGBSupport() const { return sRGBSupport_; }
     bool GetSRGBSupport() const { return sRGBSupport_; }
     /// Return whether sRGB conversion on rendertarget writing is supported.
     /// Return whether sRGB conversion on rendertarget writing is supported.
@@ -355,8 +347,6 @@ public:
     CompareMode GetDepthTest() const { return depthTestMode_; }
     CompareMode GetDepthTest() const { return depthTestMode_; }
     /// Return whether depth write is enabled.
     /// Return whether depth write is enabled.
     bool GetDepthWrite() const { return depthWrite_; }
     bool GetDepthWrite() const { return depthWrite_; }
-    /// Return whether antialiased drawing mode is enabled.
-    bool GetDrawAntialiased() const { return drawAntialiased_; }
     /// Return polygon fill mode.
     /// Return polygon fill mode.
     FillMode GetFillMode() const { return fillMode_; }
     FillMode GetFillMode() const { return fillMode_; }
     /// Return whether stencil test is enabled.
     /// Return whether stencil test is enabled.
@@ -381,12 +371,8 @@ public:
     unsigned GetStencilWriteMask() const { return stencilWriteMask_; }
     unsigned GetStencilWriteMask() const { return stencilWriteMask_; }
     /// Return whether a custom clipping plane is in use.
     /// Return whether a custom clipping plane is in use.
     bool GetUseClipPlane() const { return useClipPlane_; }
     bool GetUseClipPlane() const { return useClipPlane_; }
-    /// Return stream frequency by vertex buffer index. Always returns 0 on OpenGL.
-    unsigned GetStreamFrequency(unsigned index) const;
     /// Return rendertarget width and height.
     /// Return rendertarget width and height.
     IntVector2 GetRenderTargetDimensions() const;
     IntVector2 GetRenderTargetDimensions() const;
-    /// Return force Shader Model 2 flag. Always false on OpenGL.
-    bool GetForceSM2() const { return false; }
 
 
     /// Window was resized through user interaction. Called by Input subsystem.
     /// Window was resized through user interaction. Called by Input subsystem.
     void WindowResized();
     void WindowResized();
@@ -402,6 +388,12 @@ public:
     void FreeScratchBuffer(void* buffer);
     void FreeScratchBuffer(void* buffer);
     /// Clean up too large scratch buffers.
     /// Clean up too large scratch buffers.
     void CleanupScratchBuffers();
     void CleanupScratchBuffers();
+    /// Clean up a render surface from all FBOs.
+    void CleanupRenderSurface(RenderSurface* surface);
+    /// Clean up shader programs when a shader variation is released or destroyed.
+    void CleanupShaderPrograms(ShaderVariation* variation);
+    /// Reserve a constant buffer.
+    ConstantBuffer* GetOrCreateConstantBuffer(unsigned bindingIndex, unsigned size);
     /// Release/clear GPU objects and optionally close the window.
     /// Release/clear GPU objects and optionally close the window.
     void Release(bool clearGPUObjects, bool closeWindow);
     void Release(bool clearGPUObjects, bool closeWindow);
     /// Restore GPU objects and reinitialize state. Requires an open window.
     /// Restore GPU objects and reinitialize state. Requires an open window.
@@ -410,10 +402,12 @@ public:
     void Maximize();
     void Maximize();
     /// Minimize the Window.
     /// Minimize the Window.
     void Minimize();
     void Minimize();
-    /// Clean up a render surface from all FBOs.
-    void CleanupRenderSurface(RenderSurface* surface);
     /// Mark the FBO needing an update.
     /// Mark the FBO needing an update.
     void MarkFBODirty();
     void MarkFBODirty();
+    /// Bind a VBO, avoiding redundant operation.
+    void SetVBO(unsigned object);
+    /// Bind a UBO, avoiding redundant operation.
+    void SetUBO(unsigned object);
     
     
     /// Return the API-specific alpha texture format.
     /// Return the API-specific alpha texture format.
     static unsigned GetAlphaFormat();
     static unsigned GetAlphaFormat();
@@ -449,22 +443,40 @@ public:
     static unsigned GetReadableDepthFormat();
     static unsigned GetReadableDepthFormat();
     /// Return the API-specific texture format from a textual description, for example "rgb".
     /// Return the API-specific texture format from a textual description, for example "rgb".
     static unsigned GetFormat(const String& formatName);
     static unsigned GetFormat(const String& formatName);
-    
+    /// Return UV offset required for pixel perfect rendering.
+    static const Vector2& GetPixelUVOffset() { return pixelUVOffset; }
+    /// Return maximum number of supported bones for skinning.
+    static unsigned GetMaxBones();
+    /// Return whether is using an OpenGL 3 context.
+    static bool GetGL3Support() { return gl3Support; }
+
 private:
 private:
     /// Create the application window icon.
     /// Create the application window icon.
     void CreateWindowIcon();
     void CreateWindowIcon();
     /// Check supported rendering features.
     /// Check supported rendering features.
-    void CheckFeatureSupport(String& extensions);
-    /// Select FBO and commit changes.
-    void CommitFramebuffer();
-    /// Check FBO completeness.
-    bool CheckFramebuffer();
-    /// Cleanup unused and unbound FBO's.
-    void CleanupFramebuffers(bool force = false);
+    void CheckFeatureSupport();
+    /// Prepare for draw call. Update constant buffers and setup the FBO.
+    void PrepareDraw();
+    /// Clean up all framebuffers. Called when destroying the context.
+    void CleanupFramebuffers();
     /// Reset cached rendering state.
     /// Reset cached rendering state.
     void ResetCachedState();
     void ResetCachedState();
     /// Initialize texture unit mappings.
     /// Initialize texture unit mappings.
     void SetTextureUnitMappings();
     void SetTextureUnitMappings();
+    /// Create a framebuffer using either extension or core functionality.
+    unsigned CreateFramebuffer();
+    /// Delete a framebuffer using either extension or core functionality.
+    void DeleteFramebuffer(unsigned fbo);
+    /// Bind a framebuffer using either extension or core functionality.
+    void BindFramebuffer(unsigned fbo);
+    /// Bind a framebuffer color attachment using either extension or core functionality.
+    void BindColorAttachment(unsigned index, unsigned target, unsigned object);
+    /// Bind a framebuffer depth attachment using either extension or core functionality.
+    void BindDepthAttachment(unsigned object, bool isRenderBuffer);
+    /// Bind a framebuffer stencil attachment using either extension or core functionality.
+    void BindStencilAttachment(unsigned object, bool isRenderBuffer);
+    /// Check FBO completeness using either extension or core functionality.
+    bool CheckFramebuffer();
     
     
     /// Mutex for accessing the GPU objects vector from several threads.
     /// Mutex for accessing the GPU objects vector from several threads.
     Mutex gpuObjectMutex_;
     Mutex gpuObjectMutex_;
@@ -496,6 +508,8 @@ private:
     bool tripleBuffer_;
     bool tripleBuffer_;
     /// sRGB conversion on write flag for the main window.
     /// sRGB conversion on write flag for the main window.
     bool sRGB_;
     bool sRGB_;
+    /// Force OpenGL 2 use flag.
+    bool forceGL2_;
     /// Instancing support flag.
     /// Instancing support flag.
     bool instancingSupport_;
     bool instancingSupport_;
     /// Light prepass support flag.
     /// Light prepass support flag.
@@ -521,7 +535,7 @@ private:
     /// Largest scratch buffer request this frame.
     /// Largest scratch buffer request this frame.
     unsigned maxScratchBufferRequest_;
     unsigned maxScratchBufferRequest_;
     /// GPU objects.
     /// GPU objects.
-    Vector<GPUObject*> gpuObjects_;
+    PODVector<GPUObject*> gpuObjects_;
     /// Scratch buffers.
     /// Scratch buffers.
     Vector<ScratchBuffer> scratchBuffers_;
     Vector<ScratchBuffer> scratchBuffers_;
     /// Shadow map dummy color texture format.
     /// Shadow map dummy color texture format.
@@ -550,6 +564,12 @@ private:
     unsigned textureTypes_[MAX_TEXTURE_UNITS];
     unsigned textureTypes_[MAX_TEXTURE_UNITS];
     /// Texture unit mappings.
     /// Texture unit mappings.
     HashMap<String, TextureUnit> textureUnits_;
     HashMap<String, TextureUnit> textureUnits_;
+    /// All constant buffers.
+    HashMap<unsigned, SharedPtr<ConstantBuffer> > constantBuffers_;
+    /// Currently bound constant buffers.
+    ConstantBuffer* currentConstantBuffers_[MAX_SHADER_PARAMETER_GROUPS * 2];
+    /// Dirty constant buffers.
+    PODVector<ConstantBuffer*> dirtyConstantBuffers_;
     /// Rendertargets in use.
     /// Rendertargets in use.
     RenderSurface* renderTargets_[MAX_RENDERTARGETS];
     RenderSurface* renderTargets_[MAX_RENDERTARGETS];
     /// Depth-stencil surface in use.
     /// Depth-stencil surface in use.
@@ -578,6 +598,8 @@ private:
     IntRect scissorRect_;
     IntRect scissorRect_;
     /// Scissor test enable flag.
     /// Scissor test enable flag.
     bool scissorTest_;
     bool scissorTest_;
+    /// Current custom clip plane in post-projection space.
+    Vector4 clipPlane_;
     /// Stencil test compare mode.
     /// Stencil test compare mode.
     CompareMode stencilTestMode_;
     CompareMode stencilTestMode_;
     /// Stencil operation on pass.
     /// Stencil operation on pass.
@@ -596,22 +618,12 @@ private:
     bool stencilTest_;
     bool stencilTest_;
     /// Custom clip plane enable flag.
     /// Custom clip plane enable flag.
     bool useClipPlane_;
     bool useClipPlane_;
-    /// Draw antialiased mode flag.
-    bool drawAntialiased_;
-    /// Releasing GPU objects flag.
-    bool releasingGPUObjects_;
     /// Last used instance data offset.
     /// Last used instance data offset.
     unsigned lastInstanceOffset_;
     unsigned lastInstanceOffset_;
     /// Default texture filtering mode.
     /// Default texture filtering mode.
     TextureFilterMode defaultTextureFilterMode_;
     TextureFilterMode defaultTextureFilterMode_;
     /// Map for additional depth textures, to emulate Direct3D9 ability to mix render texture and backbuffer rendering.
     /// Map for additional depth textures, to emulate Direct3D9 ability to mix render texture and backbuffer rendering.
     HashMap<int, SharedPtr<Texture2D> > depthTextures_;
     HashMap<int, SharedPtr<Texture2D> > depthTextures_;
-    /// Remembered shader parameter sources.
-    const void* shaderParameterSources_[MAX_SHADER_PARAMETER_GROUPS];
-    /// Temp matrices for transposing shader parameters.
-    Matrix3 tempMatrices3_[NUM_TEMP_MATRICES];
-    /// Temp matrices for transposing shader parameters.
-    Matrix4 tempMatrices4_[NUM_TEMP_MATRICES];
     /// Base directory for shaders.
     /// Base directory for shaders.
     String shaderPath_;
     String shaderPath_;
     /// File extension for shaders.
     /// File extension for shaders.
@@ -624,6 +636,13 @@ private:
     SharedPtr<ShaderPrecache> shaderPrecache_;
     SharedPtr<ShaderPrecache> shaderPrecache_;
     /// Allowed screen orientations.
     /// Allowed screen orientations.
     String orientations_;
     String orientations_;
+    /// Graphics API name.
+    String apiName_;
+
+    /// Pixel perfect UV offset.
+    static const Vector2 pixelUVOffset;
+    /// Flag for OpenGL 3 support.
+    static bool gl3Support;
 };
 };
 
 
 /// Register Graphics library objects.
 /// Register Graphics library objects.

+ 5 - 3
Source/Atomic/Graphics/OpenGL/OGLGraphicsImpl.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -32,10 +32,12 @@ namespace Atomic
 GraphicsImpl::GraphicsImpl() :
 GraphicsImpl::GraphicsImpl() :
     window_(0),
     window_(0),
     context_(0),
     context_(0),
-    systemFbo_(0),
+    systemFBO_(0),
     activeTexture_(0),
     activeTexture_(0),
     enabledAttributes_(0),
     enabledAttributes_(0),
-    boundFbo_(0),
+    boundFBO_(0),
+    boundVBO_(0),
+    boundUBO_(0),
     pixelFormat_(0),
     pixelFormat_(0),
     fboDirty_(false)
     fboDirty_(false)
 {
 {

+ 12 - 4
Source/Atomic/Graphics/OpenGL/OGLGraphicsImpl.h

@@ -39,6 +39,12 @@
 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83f1
 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83f1
 #endif
 #endif
+#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83f2
+#endif
+#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83f3
+#endif
 #ifndef GL_ETC1_RGB8_OES
 #ifndef GL_ETC1_RGB8_OES
 #define GL_ETC1_RGB8_OES 0x8d64
 #define GL_ETC1_RGB8_OES 0x8d64
 #endif
 #endif
@@ -85,8 +91,6 @@ struct FrameBufferObject
     unsigned readBuffers_;
     unsigned readBuffers_;
     /// Draw buffer bits.
     /// Draw buffer bits.
     unsigned drawBuffers_;
     unsigned drawBuffers_;
-    /// Use timer for cleaning up.
-    Timer useTimer_;
 };
 };
 
 
 /// %Graphics subsystem implementation. Holds API-specific objects.
 /// %Graphics subsystem implementation. Holds API-specific objects.
@@ -106,13 +110,17 @@ private:
     /// SDL OpenGL context.
     /// SDL OpenGL context.
     SDL_GLContext context_;
     SDL_GLContext context_;
     /// IOS system framebuffer handle.
     /// IOS system framebuffer handle.
-    unsigned systemFbo_;
+    unsigned systemFBO_;
     /// Active texture unit.
     /// Active texture unit.
     unsigned activeTexture_;
     unsigned activeTexture_;
     /// Vertex attributes in use.
     /// Vertex attributes in use.
     unsigned enabledAttributes_;
     unsigned enabledAttributes_;
     /// Currently bound frame buffer object.
     /// Currently bound frame buffer object.
-    unsigned boundFbo_;
+    unsigned boundFBO_;
+    /// Currently bound vertex buffer object.
+    unsigned boundVBO_;
+    /// Currently bound uniform buffer object.
+    unsigned boundUBO_;
     /// Current pixel format.
     /// Current pixel format.
     int pixelFormat_;
     int pixelFormat_;
     /// Map for FBO's per resolution and format.
     /// Map for FBO's per resolution and format.

+ 4 - 8
Source/Atomic/Graphics/OpenGL/OGLIndexBuffer.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -144,8 +144,7 @@ bool IndexBuffer::SetData(const void* data)
     {
     {
         if (!graphics_->IsDeviceLost())
         if (!graphics_->IsDeviceLost())
         {
         {
-            graphics_->SetIndexBuffer(0);
-            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object_);
+            graphics_->SetIndexBuffer(this);
             glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount_ * indexSize_, data, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
             glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount_ * indexSize_, data, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
         }
         }
         else
         else
@@ -192,8 +191,7 @@ bool IndexBuffer::SetDataRange(const void* data, unsigned start, unsigned count,
     {
     {
         if (!graphics_->IsDeviceLost())
         if (!graphics_->IsDeviceLost())
         {
         {
-            graphics_->SetIndexBuffer(0);
-            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object_);
+            graphics_->SetIndexBuffer(this);
             if (!discard || start != 0)
             if (!discard || start != 0)
                 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, start * indexSize_, count * indexSize_, data);
                 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, start * indexSize_, count * indexSize_, data);
             else
             else
@@ -334,8 +332,6 @@ bool IndexBuffer::Create()
             return true;
             return true;
         }
         }
         
         
-        graphics_->SetIndexBuffer(0);
-        
         if (!object_)
         if (!object_)
             glGenBuffers(1, &object_);
             glGenBuffers(1, &object_);
         if (!object_)
         if (!object_)
@@ -344,7 +340,7 @@ bool IndexBuffer::Create()
             return false;
             return false;
         }
         }
         
         
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object_);
+        graphics_->SetIndexBuffer(this);
         glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount_ * indexSize_, 0, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
         glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount_ * indexSize_, 0, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
     }
     }
     
     

+ 185 - 11
Source/Atomic/Graphics/OpenGL/OGLShaderProgram.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -21,23 +21,41 @@
 //
 //
 
 
 #include "Precompiled.h"
 #include "Precompiled.h"
+#include "../../Graphics/ConstantBuffer.h"
 #include "../../Graphics/Graphics.h"
 #include "../../Graphics/Graphics.h"
 #include "../../Graphics/GraphicsImpl.h"
 #include "../../Graphics/GraphicsImpl.h"
 #include "../../Graphics/ShaderProgram.h"
 #include "../../Graphics/ShaderProgram.h"
 #include "../../Graphics/ShaderVariation.h"
 #include "../../Graphics/ShaderVariation.h"
+#include "../../IO/Log.h"
 
 
 #include "../../DebugNew.h"
 #include "../../DebugNew.h"
 
 
 namespace Atomic
 namespace Atomic
 {
 {
 
 
+const char* shaderParameterGroups[] = {
+    "frame",
+    "camera",
+    "zone",
+    "light",
+    "material",
+    "object",
+    "custom"
+};
+
+unsigned ShaderProgram::globalFrameNumber = 0;
+const void* ShaderProgram::globalParameterSources[MAX_SHADER_PARAMETER_GROUPS];
+
 ShaderProgram::ShaderProgram(Graphics* graphics, ShaderVariation* vertexShader, ShaderVariation* pixelShader) :
 ShaderProgram::ShaderProgram(Graphics* graphics, ShaderVariation* vertexShader, ShaderVariation* pixelShader) :
     GPUObject(graphics),
     GPUObject(graphics),
     vertexShader_(vertexShader),
     vertexShader_(vertexShader),
-    pixelShader_(pixelShader)
+    pixelShader_(pixelShader),
+    frameNumber_(0)
 {
 {
     for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
     for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         useTextureUnit_[i] = false;
         useTextureUnit_[i] = false;
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        parameterSources_[i] = (const void*)M_MAX_UNSIGNED;
 }
 }
 
 
 ShaderProgram::~ShaderProgram()
 ShaderProgram::~ShaderProgram()
@@ -51,7 +69,6 @@ void ShaderProgram::OnDeviceLost()
     
     
     if (graphics_ && graphics_->GetShaderProgram() == this)
     if (graphics_ && graphics_->GetShaderProgram() == this)
         graphics_->SetShaders(0, 0);
         graphics_->SetShaders(0, 0);
-    
 
 
     linkerOutput_.Clear();
     linkerOutput_.Clear();
 }
 }
@@ -77,6 +94,8 @@ void ShaderProgram::Release()
         
         
         for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
             useTextureUnit_[i] = false;
             useTextureUnit_[i] = false;
+        for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+            constantBuffers_[i].Reset();
     }
     }
 }
 }
 
 
@@ -141,6 +160,75 @@ bool ShaderProgram::Link()
     glUseProgram(object_);
     glUseProgram(object_);
     glGetProgramiv(object_, GL_ACTIVE_UNIFORMS, &uniformCount);
     glGetProgramiv(object_, GL_ACTIVE_UNIFORMS, &uniformCount);
     
     
+    // Check for constant buffers
+    #ifndef GL_ES_VERSION_2_0
+    HashMap<unsigned, unsigned> blockToBinding;
+
+    if (Graphics::GetGL3Support())
+    {
+        int numUniformBlocks = 0;
+
+        glGetProgramiv(object_, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
+        for (int i = 0; i < numUniformBlocks; ++i)
+        {
+            int nameLength;
+            glGetActiveUniformBlockName(object_, i, MAX_PARAMETER_NAME_LENGTH, &nameLength, uniformName);
+
+            String name(uniformName, nameLength);
+
+            unsigned blockIndex = glGetUniformBlockIndex(object_, name.CString());
+            unsigned group = M_MAX_UNSIGNED;
+
+            // Try to recognize the use of the buffer from its name
+            for (unsigned j = 0; j < MAX_SHADER_PARAMETER_GROUPS; ++j)
+            {
+                if (name.Contains(shaderParameterGroups[j], false))
+                {
+                    group = j;
+                    break;
+                }
+            }
+
+            // If name is not recognized, search for a digit in the name and use that as the group index
+            if (group == M_MAX_UNSIGNED)
+            {
+                for (unsigned j = 1; j < name.Length(); ++j)
+                {
+                    if (name[j] >= '0' && name[j] <= '5')
+                    {
+                        group = name[j] - '0';
+                        break;
+                    }
+                }
+            }
+
+            if (group >= MAX_SHADER_PARAMETER_GROUPS)
+            {
+                LOGWARNING("Skipping unrecognized uniform block " + name + " in shader program " + vertexShader_->GetFullName() +
+                    " " + pixelShader_->GetFullName());
+                continue;
+            }
+
+            // Find total constant buffer data size
+            int dataSize;
+            glGetActiveUniformBlockiv(object_, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &dataSize);
+            if (!dataSize)
+                continue;
+
+            unsigned bindingIndex = group;
+            // Vertex shader constant buffer bindings occupy slots starting from zero to maximum supported, pixel shader bindings
+            // from that point onward
+            if (name.Contains("PS", false))
+                bindingIndex += MAX_SHADER_PARAMETER_GROUPS;
+
+            glUniformBlockBinding(object_, blockIndex, bindingIndex);
+            blockToBinding[blockIndex] = bindingIndex;
+
+            constantBuffers_[bindingIndex] = graphics_->GetOrCreateConstantBuffer(bindingIndex, dataSize);
+        }
+    }
+    #endif
+
     // Check for shader parameters and texture units
     // Check for shader parameters and texture units
     for (int i = 0; i < uniformCount; ++i)
     for (int i = 0; i < uniformCount; ++i)
     {
     {
@@ -150,10 +238,6 @@ bool ShaderProgram::Link()
         glGetActiveUniform(object_, i, MAX_PARAMETER_NAME_LENGTH, 0, &count, &type, uniformName);
         glGetActiveUniform(object_, i, MAX_PARAMETER_NAME_LENGTH, 0, &count, &type, uniformName);
         int location = glGetUniformLocation(object_, uniformName);
         int location = glGetUniformLocation(object_, uniformName);
         
         
-        // Skip inbuilt or disabled uniforms
-        if (location < 0)
-            continue;
-        
         // Check for array index included in the name and strip it
         // Check for array index included in the name and strip it
         String name(uniformName);
         String name(uniformName);
         unsigned index = name.Find('[');
         unsigned index = name.Find('[');
@@ -168,14 +252,31 @@ bool ShaderProgram::Link()
         
         
         if (name[0] == 'c')
         if (name[0] == 'c')
         {
         {
-            // Store the constant uniform mapping
+            // Store constant uniform
             String paramName = name.Substring(1);
             String paramName = name.Substring(1);
             ShaderParameter newParam;
             ShaderParameter newParam;
-            newParam.location_ = location;
             newParam.type_ = type;
             newParam.type_ = type;
-            shaderParameters_[StringHash(paramName)] = newParam;
+            newParam.location_ = location;
+
+            #ifndef GL_ES_VERSION_2_0
+            // If running OpenGL 3, the uniform may be inside a constant buffer
+            if (newParam.location_ < 0 && Graphics::GetGL3Support())
+            {
+                int blockIndex, blockOffset;
+                glGetActiveUniformsiv(object_, 1, (const GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &blockIndex);
+                glGetActiveUniformsiv(object_, 1, (const GLuint*)&i, GL_UNIFORM_OFFSET, &blockOffset);
+                if (blockIndex >= 0)
+                {
+                    newParam.location_ = blockOffset;
+                    newParam.bufferPtr_ = constantBuffers_[blockToBinding[blockIndex]];
+                }
+            }
+            #endif
+
+            if (newParam.location_ >= 0)
+                shaderParameters_[StringHash(paramName)] = newParam;
         }
         }
-        else if (name[0] == 's')
+        else if (location >= 0 && name[0] == 's')
         {
         {
             // Set the samplers here so that they do not have to be set later
             // Set the samplers here so that they do not have to be set later
             int unit = graphics_->GetTextureUnit(name.Substring(1));
             int unit = graphics_->GetTextureUnit(name.Substring(1));
@@ -230,4 +331,77 @@ const ShaderParameter* ShaderProgram::GetParameter(StringHash param) const
         return 0;
         return 0;
 }
 }
 
 
+bool ShaderProgram::NeedParameterUpdate(ShaderParameterGroup group, const void* source)
+{
+    // If global framenumber has changed, invalidate all per-program parameter sources now
+    if (globalFrameNumber != frameNumber_)
+    {
+        for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+            parameterSources_[i] = (const void*)M_MAX_UNSIGNED;
+        frameNumber_ = globalFrameNumber;
+    }
+
+    // The shader program may use a mixture of constant buffers and individual uniforms even in the same group
+    #ifndef GL_ES_VERSION_2_0
+    bool useBuffer = constantBuffers_[group].Get() || constantBuffers_[group + MAX_SHADER_PARAMETER_GROUPS].Get();
+    bool useIndividual = !constantBuffers_[group].Get() || !constantBuffers_[group + MAX_SHADER_PARAMETER_GROUPS].Get();
+    bool needUpdate = false;
+
+    if (useBuffer && globalParameterSources[group] != source)
+    {
+        globalParameterSources[group] = source;
+        needUpdate = true;
+    }
+
+    if (useIndividual && parameterSources_[group] != source)
+    {
+        parameterSources_[group] = source;
+        needUpdate = true;
+    }
+
+    return needUpdate;
+    #else
+    if (parameterSources_[group] != source)
+    {
+        parameterSources_[group] = source;
+        return true;
+    }
+    else
+        return false;
+    #endif
+}
+
+void ShaderProgram::ClearParameterSource(ShaderParameterGroup group)
+{
+    // The shader program may use a mixture of constant buffers and individual uniforms even in the same group
+    #ifndef GL_ES_VERSION_2_0
+    bool useBuffer = constantBuffers_[group].Get() || constantBuffers_[group + MAX_SHADER_PARAMETER_GROUPS].Get();
+    bool useIndividual = !constantBuffers_[group].Get() || !constantBuffers_[group + MAX_SHADER_PARAMETER_GROUPS].Get();
+
+    if (useBuffer)
+        globalParameterSources[group] = (const void*)M_MAX_UNSIGNED;
+    if (useIndividual)
+        parameterSources_[group] = (const void*)M_MAX_UNSIGNED;
+    #else
+    parameterSources_[group] = (const void*)M_MAX_UNSIGNED;
+    #endif
+}
+
+void ShaderProgram::ClearParameterSources()
+{
+    ++globalFrameNumber;
+    if (!globalFrameNumber)
+        ++globalFrameNumber;
+
+    #ifndef GL_ES_VERSION_2_0
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        globalParameterSources[i] = (const void*)M_MAX_UNSIGNED;
+    #endif
+}
+
+void ShaderProgram::ClearGlobalParameterSource(ShaderParameterGroup group)
+{
+    globalParameterSources[group] = (const void*)M_MAX_UNSIGNED;
+}
+
 }
 }

+ 34 - 2
Source/Atomic/Graphics/OpenGL/OGLShaderProgram.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -30,16 +30,25 @@
 namespace Atomic
 namespace Atomic
 {
 {
 
 
+class ConstantBuffer;
 class Graphics;
 class Graphics;
 class ShaderVariation;
 class ShaderVariation;
 
 
 /// %Shader parameter definition.
 /// %Shader parameter definition.
 struct ShaderParameter
 struct ShaderParameter
 {
 {
-    /// Uniform location.
+    /// Construct with defaults.
+    ShaderParameter() :
+        bufferPtr_(0)
+    {
+    }
+
+    /// Uniform location or byte offset in constant buffer.
     int location_;
     int location_;
     /// Element type.
     /// Element type.
     unsigned type_;
     unsigned type_;
+    /// Constant buffer pointer.
+    ConstantBuffer* bufferPtr_;
 };
 };
 
 
 /// Linked shader program on the GPU.
 /// Linked shader program on the GPU.
@@ -71,7 +80,19 @@ public:
     const ShaderParameter* GetParameter(StringHash param) const;
     const ShaderParameter* GetParameter(StringHash param) const;
     /// Return linker output.
     /// Return linker output.
     const String& GetLinkerOutput() const { return linkerOutput_; }
     const String& GetLinkerOutput() const { return linkerOutput_; }
+    /// Return all constant buffers.
+    const SharedPtr<ConstantBuffer>* GetConstantBuffers() const { return &constantBuffers_[0]; }
     
     
+    /// Check whether a shader parameter group needs update. Does not actually check whether parameters exist in the shaders.
+    bool NeedParameterUpdate(ShaderParameterGroup group, const void* source);
+    /// Clear a parameter source. Affects only the current shader program if appropriate.
+    void ClearParameterSource(ShaderParameterGroup group);
+
+    /// Clear all parameter sources from all shader programs by incrementing the global parameter source framenumber.
+    static void ClearParameterSources();
+    /// Clear a global parameter source when constant buffers change.
+    static void ClearGlobalParameterSource(ShaderParameterGroup group);
+
 private:
 private:
     /// Vertex shader.
     /// Vertex shader.
     WeakPtr<ShaderVariation> vertexShader_;
     WeakPtr<ShaderVariation> vertexShader_;
@@ -81,8 +102,19 @@ private:
     HashMap<StringHash, ShaderParameter> shaderParameters_;
     HashMap<StringHash, ShaderParameter> shaderParameters_;
     /// Texture unit use.
     /// Texture unit use.
     bool useTextureUnit_[MAX_TEXTURE_UNITS];
     bool useTextureUnit_[MAX_TEXTURE_UNITS];
+    /// Constant buffers by binding index.
+    SharedPtr<ConstantBuffer> constantBuffers_[MAX_SHADER_PARAMETER_GROUPS * 2];
+    /// Remembered shader parameter sources for individual uniform mode.
+    const void* parameterSources_[MAX_SHADER_PARAMETER_GROUPS];
     /// Shader link error string.
     /// Shader link error string.
     String linkerOutput_;
     String linkerOutput_;
+    /// Shader parameter source framenumber.
+    unsigned frameNumber_;
+
+    /// Global shader parameter source framenumber.
+    static unsigned globalFrameNumber;
+    /// Remembered global shader parameter sources for constant buffer mode.
+    static const void* globalParameterSources[MAX_SHADER_PARAMETER_GROUPS];
 };
 };
 
 
 }
 }

+ 10 - 5
Source/Atomic/Graphics/OpenGL/OGLShaderVariation.cpp

@@ -50,9 +50,6 @@ void ShaderVariation::OnDeviceLost()
     GPUObject::OnDeviceLost();
     GPUObject::OnDeviceLost();
 
 
     compilerOutput_.Clear();
     compilerOutput_.Clear();
-    
-    if (graphics_)
-        graphics_->CleanupShaderPrograms();
 }
 }
 
 
 void ShaderVariation::Release()
 void ShaderVariation::Release()
@@ -79,7 +76,7 @@ void ShaderVariation::Release()
         }
         }
         
         
         object_ = 0;
         object_ = 0;
-        graphics_->CleanupShaderPrograms();
+        graphics_->CleanupShaderPrograms(this);
     }
     }
     
     
     compilerOutput_.Clear();
     compilerOutput_.Clear();
@@ -125,10 +122,16 @@ bool ShaderVariation::Create()
             shaderCode += versionDefine + "\n";
             shaderCode += versionDefine + "\n";
         }
         }
     }
     }
+    // Force GLSL version 150 if no version define and GL3 is being used
+    if (!verEnd && Graphics::GetGL3Support())
+        shaderCode += "#version 150\n";
 
 
     // Distinguish between VS and PS compile in case the shader code wants to include/omit different things
     // Distinguish between VS and PS compile in case the shader code wants to include/omit different things
     shaderCode += type_ == VS ? "#define COMPILEVS\n" : "#define COMPILEPS\n";
     shaderCode += type_ == VS ? "#define COMPILEVS\n" : "#define COMPILEPS\n";
-    
+
+    // Add define for the maximum number of supported bones
+    shaderCode += "#define MAXBONES " + String(Graphics::GetMaxBones()) + "\n";
+
     // Prepend the defines to the shader code
     // Prepend the defines to the shader code
     Vector<String> defineVec = defines_.Split(' ');
     Vector<String> defineVec = defines_.Split(' ');
     for (unsigned i = 0; i < defineVec.Size(); ++i)
     for (unsigned i = 0; i < defineVec.Size(); ++i)
@@ -152,6 +155,8 @@ bool ShaderVariation::Create()
     #ifdef EMSCRIPTEN
     #ifdef EMSCRIPTEN
     shaderCode += "#define WEBGL\n";
     shaderCode += "#define WEBGL\n";
     #endif
     #endif
+    if (Graphics::GetGL3Support())
+        shaderCode += "#define GL3\n";
 
 
     // When version define found, do not insert it a second time
     // When version define found, do not insert it a second time
     if (verEnd > 0)
     if (verEnd > 0)

+ 41 - 20
Source/Atomic/Graphics/OpenGL/OGLTexture.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -37,7 +37,7 @@
 namespace Atomic
 namespace Atomic
 {
 {
 
 
-GLenum glWrapModes[] =
+static GLenum glWrapModes[] =
 {
 {
     GL_REPEAT,
     GL_REPEAT,
     GL_MIRRORED_REPEAT,
     GL_MIRRORED_REPEAT,
@@ -49,6 +49,16 @@ GLenum glWrapModes[] =
     #endif
     #endif
 };
 };
 
 
+#ifndef GL_ES_VERSION_2_0
+static GLenum gl3WrapModes[] =
+{
+    GL_REPEAT,
+    GL_MIRRORED_REPEAT,
+    GL_CLAMP_TO_EDGE,
+    GL_CLAMP_TO_BORDER
+};
+#endif
+
 static const char* addressModeNames[] =
 static const char* addressModeNames[] =
 {
 {
     "wrap",
     "wrap",
@@ -68,6 +78,15 @@ static const char* filterModeNames[] =
     0
     0
 };
 };
 
 
+static GLenum GetWrapMode(TextureAddressMode mode)
+{
+    #ifndef GL_ES_VERSION_2_0
+    return Graphics::GetGL3Support() ? gl3WrapModes[mode] : glWrapModes[mode];
+    #else
+    return glWrapModes[mode];
+    #endif
+}
+
 Texture::Texture(Context* context) :
 Texture::Texture(Context* context) :
     Resource(context),
     Resource(context),
     GPUObject(GetSubsystem<Graphics>()),
     GPUObject(GetSubsystem<Graphics>()),
@@ -171,10 +190,10 @@ void Texture::UpdateParameters()
         return;
         return;
     
     
     // Wrapping
     // Wrapping
-    glTexParameteri(target_, GL_TEXTURE_WRAP_S, glWrapModes[addressMode_[COORD_U]]);
-    glTexParameteri(target_, GL_TEXTURE_WRAP_T, glWrapModes[addressMode_[COORD_V]]);
+    glTexParameteri(target_, GL_TEXTURE_WRAP_S, GetWrapMode(addressMode_[COORD_U]));
+    glTexParameteri(target_, GL_TEXTURE_WRAP_T, GetWrapMode(addressMode_[COORD_V]));
     #ifndef GL_ES_VERSION_2_0
     #ifndef GL_ES_VERSION_2_0
-    glTexParameteri(target_, GL_TEXTURE_WRAP_R, glWrapModes[addressMode_[COORD_W]]);
+    glTexParameteri(target_, GL_TEXTURE_WRAP_R, GetWrapMode(addressMode_[COORD_W]));
     #endif
     #endif
     
     
     TextureFilterMode filterMode = filterMode_;
     TextureFilterMode filterMode = filterMode_;
@@ -240,14 +259,10 @@ int Texture::GetMipsToSkip(int quality) const
 
 
 bool Texture::IsCompressed() const
 bool Texture::IsCompressed() const
 {
 {
-    #ifndef GL_ES_VERSION_2_0
     return format_ == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format_ == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
     return format_ == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format_ == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
-        format_ == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
-    #else
-    return format_ == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format_ == GL_ETC1_RGB8_OES ||
+        format_ == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT || format_ == GL_ETC1_RGB8_OES ||
         format_ == COMPRESSED_RGB_PVRTC_4BPPV1_IMG || format_ == COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ||
         format_ == COMPRESSED_RGB_PVRTC_4BPPV1_IMG || format_ == COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ||
         format_ == COMPRESSED_RGB_PVRTC_2BPPV1_IMG || format_ == COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
         format_ == COMPRESSED_RGB_PVRTC_2BPPV1_IMG || format_ == COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
-    #endif
 }
 }
 
 
 int Texture::GetLevelWidth(unsigned level) const
 int Texture::GetLevelWidth(unsigned level) const
@@ -307,14 +322,20 @@ unsigned Texture::GetRowDataSize(int width) const
         
         
     case GL_RGBA:
     case GL_RGBA:
     #ifndef GL_ES_VERSION_2_0
     #ifndef GL_ES_VERSION_2_0
-    case GL_LUMINANCE16F_ARB:
-    case GL_LUMINANCE32F_ARB:
     case GL_DEPTH24_STENCIL8_EXT:
     case GL_DEPTH24_STENCIL8_EXT:
     case GL_RG16:
     case GL_RG16:
+    case GL_R16F:
+    case GL_R32F:
     #endif
     #endif
         return width * 4;
         return width * 4;
         
         
     #ifndef GL_ES_VERSION_2_0
     #ifndef GL_ES_VERSION_2_0
+    case GL_R8:
+        return width;
+
+    case GL_RG8:
+        return width * 2;
+
     case GL_RGBA16:
     case GL_RGBA16:
         return width * 8;
         return width * 8;
         
         
@@ -326,11 +347,10 @@ unsigned Texture::GetRowDataSize(int width) const
     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
         return ((width + 3) >> 2) * 8;
         return ((width + 3) >> 2) * 8;
         
         
-    #ifndef GL_ES_VERSION_2_0
     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
         return ((width + 3) >> 2) * 16;
         return ((width + 3) >> 2) * 16;
-    #else
+
     case GL_ETC1_RGB8_OES:
     case GL_ETC1_RGB8_OES:
         return ((width + 3) >> 2) * 8;
         return ((width + 3) >> 2) * 8;
         
         
@@ -341,8 +361,7 @@ unsigned Texture::GetRowDataSize(int width) const
     case COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
     case COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
     case COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
     case COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
         return (width * 2 + 7) >> 3;
         return (width * 2 + 7) >> 3;
-    #endif
-        
+
     default:
     default:
         return 0;
         return 0;
     }
     }
@@ -355,11 +374,13 @@ unsigned Texture::GetExternalFormat(unsigned format)
         return GL_DEPTH_COMPONENT;
         return GL_DEPTH_COMPONENT;
     else if (format == GL_DEPTH24_STENCIL8_EXT)
     else if (format == GL_DEPTH24_STENCIL8_EXT)
         return GL_DEPTH_STENCIL_EXT;
         return GL_DEPTH_STENCIL_EXT;
-    else if (format == GL_LUMINANCE16F_ARB || format == GL_LUMINANCE32F_ARB || format == GL_SLUMINANCE_EXT)
+    else if (format == GL_SLUMINANCE_EXT)
         return GL_LUMINANCE;
         return GL_LUMINANCE;
     else if (format == GL_SLUMINANCE_ALPHA_EXT)
     else if (format == GL_SLUMINANCE_ALPHA_EXT)
         return GL_LUMINANCE_ALPHA;
         return GL_LUMINANCE_ALPHA;
-    else if (format == GL_RG16 || format == GL_RG16F || format == GL_RG32F)
+    else if (format == GL_R8 || format == GL_R16F || format == GL_R32F)
+        return GL_RED;
+    else if (format == GL_RG8 || format == GL_RG16 || format == GL_RG16F || format == GL_RG32F)
         return GL_RG;
         return GL_RG;
     else if (format == GL_RGBA16 || format == GL_RGBA16F_ARB || format == GL_RGBA32F_ARB || format == GL_SRGB_ALPHA_EXT)
     else if (format == GL_RGBA16 || format == GL_RGBA16F_ARB || format == GL_RGBA32F_ARB || format == GL_SRGB_ALPHA_EXT)
         return GL_RGBA;
         return GL_RGBA;
@@ -379,8 +400,8 @@ unsigned Texture::GetDataType(unsigned format)
         return GL_UNSIGNED_INT_24_8_EXT;
         return GL_UNSIGNED_INT_24_8_EXT;
     else if (format == GL_RG16 || format == GL_RGBA16)
     else if (format == GL_RG16 || format == GL_RGBA16)
         return GL_UNSIGNED_SHORT;
         return GL_UNSIGNED_SHORT;
-    else if (format == GL_LUMINANCE16F_ARB || format == GL_LUMINANCE32F_ARB || format == GL_RGBA16F_ARB ||
-        format == GL_RGBA32F_ARB || format == GL_RG16F || format == GL_RG32F)
+    else if (format == GL_RGBA16F_ARB || format == GL_RGBA32F_ARB || format == GL_RG16F || format == GL_RG32F || format == GL_R16F ||
+        format == GL_R32F)
         return GL_FLOAT;
         return GL_FLOAT;
     else
     else
         return GL_UNSIGNED_BYTE;
         return GL_UNSIGNED_BYTE;

+ 4 - 4
Source/Atomic/Graphics/OpenGL/OGLTexture.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -50,7 +50,7 @@ public:
     void SetFilterMode(TextureFilterMode filter);
     void SetFilterMode(TextureFilterMode filter);
     /// Set addressing mode by texture coordinate.
     /// Set addressing mode by texture coordinate.
     void SetAddressMode(TextureCoordinate coord, TextureAddressMode address);
     void SetAddressMode(TextureCoordinate coord, TextureAddressMode address);
-    /// Set shadow compare mode, OpenGL only.
+    /// Set shadow compare mode.
     void SetShadowCompare(bool enable);
     void SetShadowCompare(bool enable);
     /// Set border color for border addressing mode.
     /// Set border color for border addressing mode.
     void SetBorderColor(const Color& color);
     void SetBorderColor(const Color& color);
@@ -85,7 +85,7 @@ public:
     TextureFilterMode GetFilterMode() const { return filterMode_; }
     TextureFilterMode GetFilterMode() const { return filterMode_; }
     /// Return addressing mode by texture coordinate.
     /// Return addressing mode by texture coordinate.
     TextureAddressMode GetAddressMode(TextureCoordinate coord) const { return addressMode_[coord]; }
     TextureAddressMode GetAddressMode(TextureCoordinate coord) const { return addressMode_[coord]; }
-    /// Return whether shadow compare is enabled, OpenGL only.
+    /// Return whether shadow compare is enabled.
     bool GetShadowCompare() const { return shadowCompare_; }
     bool GetShadowCompare() const { return shadowCompare_; }
      /// Return border color.
      /// Return border color.
     const Color& GetBorderColor() const { return borderColor_; }
     const Color& GetBorderColor() const { return borderColor_; }
@@ -143,7 +143,7 @@ protected:
     int height_;
     int height_;
     /// Texture depth.
     /// Texture depth.
     int depth_;
     int depth_;
-    /// Shadow compare mode, OpenGL only.
+    /// Shadow compare mode.
     bool shadowCompare_;
     bool shadowCompare_;
     /// Parameters dirty flag.
     /// Parameters dirty flag.
     bool parametersDirty_;
     bool parametersDirty_;

+ 11 - 2
Source/Atomic/Graphics/OpenGL/OGLTexture2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -278,10 +278,19 @@ bool Texture2D::SetData(SharedPtr<Image> image, bool useAlpha)
     
     
     if (!image->IsCompressed())
     if (!image->IsCompressed())
     {
     {
+        // Convert unsuitable formats to RGBA
+        unsigned components = image->GetComponents();
+        if (Graphics::GetGL3Support() && ((components == 1 && !useAlpha) || components == 2))
+        {
+            image = image->ConvertToRGBA();
+            if (!image)
+                return false;
+            components = image->GetComponents();
+        }
+
         unsigned char* levelData = image->GetData();
         unsigned char* levelData = image->GetData();
         int levelWidth = image->GetWidth();
         int levelWidth = image->GetWidth();
         int levelHeight = image->GetHeight();
         int levelHeight = image->GetHeight();
-        unsigned components = image->GetComponents();
         unsigned format = 0;
         unsigned format = 0;
         
         
         // Discard unnecessary mip levels
         // Discard unnecessary mip levels

+ 12 - 3
Source/Atomic/Graphics/OpenGL/OGLTexture3D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -285,10 +285,10 @@ bool Texture3D::SetData(unsigned level, int x, int y, int z, int width, int heig
     
     
     graphics_->SetTextureForUpdate(this);
     graphics_->SetTextureForUpdate(this);
     
     
+    #ifndef GL_ES_VERSION_2_0
     bool wholeLevel = x == 0 && y == 0 && z == 0 && width == levelWidth && height == levelHeight && depth == levelDepth;
     bool wholeLevel = x == 0 && y == 0 && z == 0 && width == levelWidth && height == levelHeight && depth == levelDepth;
     unsigned format = GetSRGB() ? GetSRGBFormat(format_) : format_;
     unsigned format = GetSRGB() ? GetSRGBFormat(format_) : format_;
     
     
-    #ifndef GL_ES_VERSION_2_0
     if (!IsCompressed())
     if (!IsCompressed())
     {
     {
         if (wholeLevel)
         if (wholeLevel)
@@ -326,11 +326,20 @@ bool Texture3D::SetData(SharedPtr<Image> image, bool useAlpha)
     
     
     if (!image->IsCompressed())
     if (!image->IsCompressed())
     {
     {
+        // Convert unsuitable formats to RGBA
+        unsigned components = image->GetComponents();
+        if (Graphics::GetGL3Support() && ((components == 1 && !useAlpha) || components == 2))
+        {
+            image = image->ConvertToRGBA();
+            if (!image)
+                return false;
+            components = image->GetComponents();
+        }
+
         unsigned char* levelData = image->GetData();
         unsigned char* levelData = image->GetData();
         int levelWidth = image->GetWidth();
         int levelWidth = image->GetWidth();
         int levelHeight = image->GetHeight();
         int levelHeight = image->GetHeight();
         int levelDepth = image->GetDepth();
         int levelDepth = image->GetDepth();
-        unsigned components = image->GetComponents();
         unsigned format = 0;
         unsigned format = 0;
         
         
         // Discard unnecessary mip levels
         // Discard unnecessary mip levels

+ 11 - 2
Source/Atomic/Graphics/OpenGL/OGLTextureCube.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -441,10 +441,19 @@ bool TextureCube::SetData(CubeMapFace face, SharedPtr<Image> image, bool useAlph
     
     
     if (!image->IsCompressed())
     if (!image->IsCompressed())
     {
     {
+        // Convert unsuitable formats to RGBA
+        unsigned components = image->GetComponents();
+        if (Graphics::GetGL3Support() && ((components == 1 && !useAlpha) || components == 2))
+        {
+            image = image->ConvertToRGBA();
+            if (!image)
+                return false;
+            components = image->GetComponents();
+        }
+
         unsigned char* levelData = image->GetData();
         unsigned char* levelData = image->GetData();
         int levelWidth = image->GetWidth();
         int levelWidth = image->GetWidth();
         int levelHeight = image->GetHeight();
         int levelHeight = image->GetHeight();
-        unsigned components = image->GetComponents();
         unsigned format = 0;
         unsigned format = 0;
         
         
         if (levelWidth != levelHeight)
         if (levelWidth != levelHeight)

+ 5 - 4
Source/Atomic/Graphics/OpenGL/OGLVertexBuffer.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -155,6 +155,7 @@ void VertexBuffer::Release()
                     graphics_->SetVertexBuffer(0);
                     graphics_->SetVertexBuffer(0);
             }
             }
             
             
+            graphics_->SetVBO(0);
             glDeleteBuffers(1, &object_);
             glDeleteBuffers(1, &object_);
         }
         }
         
         
@@ -218,7 +219,7 @@ bool VertexBuffer::SetData(const void* data)
     {
     {
         if (!graphics_->IsDeviceLost())
         if (!graphics_->IsDeviceLost())
         {
         {
-            glBindBuffer(GL_ARRAY_BUFFER, object_);
+            graphics_->SetVBO(object_);
             glBufferData(GL_ARRAY_BUFFER, vertexCount_ * vertexSize_, data, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
             glBufferData(GL_ARRAY_BUFFER, vertexCount_ * vertexSize_, data, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
         }
         }
         else
         else
@@ -265,7 +266,7 @@ bool VertexBuffer::SetDataRange(const void* data, unsigned start, unsigned count
     {
     {
         if (!graphics_->IsDeviceLost())
         if (!graphics_->IsDeviceLost())
         {
         {
-            glBindBuffer(GL_ARRAY_BUFFER, object_);
+            graphics_->SetVBO(object_);
             if (!discard || start != 0)
             if (!discard || start != 0)
                 glBufferSubData(GL_ARRAY_BUFFER, start * vertexSize_, count * vertexSize_, data);
                 glBufferSubData(GL_ARRAY_BUFFER, start * vertexSize_, count * vertexSize_, data);
             else
             else
@@ -410,7 +411,7 @@ bool VertexBuffer::Create()
             return false;
             return false;
         }
         }
         
         
-        glBindBuffer(GL_ARRAY_BUFFER, object_);
+        graphics_->SetVBO(object_);
         glBufferData(GL_ARRAY_BUFFER, vertexCount_ * vertexSize_, 0, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
         glBufferData(GL_ARRAY_BUFFER, vertexCount_ * vertexSize_, 0, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
     }
     }
     
     

+ 42 - 14
Source/Atomic/Graphics/RenderPath.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -60,6 +60,8 @@ void RenderTargetInfo::Load(const XMLElement& element)
     tag_ = element.GetAttribute("tag");
     tag_ = element.GetAttribute("tag");
     if (element.HasAttribute("enabled"))
     if (element.HasAttribute("enabled"))
         enabled_ = element.GetBool("enabled");
         enabled_ = element.GetBool("enabled");
+    if (element.HasAttribute("cubemap"))
+        cubemap_ = element.GetBool("cubemap");
     
     
     String formatName = element.GetAttribute("format");
     String formatName = element.GetAttribute("format");
     format_ = Graphics::GetFormat(formatName);
     format_ = Graphics::GetFormat(formatName);
@@ -170,9 +172,12 @@ void RenderPathCommand::Load(const XMLElement& element)
     }
     }
     
     
     // By default use 1 output, which is the viewport
     // By default use 1 output, which is the viewport
-    outputNames_.Push("viewport");
+    outputs_.Resize(1);
+    outputs_[0] = MakePair(String("viewport"), FACE_POSITIVE_X);
     if (element.HasAttribute("output"))
     if (element.HasAttribute("output"))
-        outputNames_[0] = element.GetAttribute("output");
+        outputs_[0].first_ = element.GetAttribute("output");
+    if (element.HasAttribute("face"))
+        outputs_[0].second_ = (CubeMapFace)element.GetInt("face");
     if (element.HasAttribute("depthstencil"))
     if (element.HasAttribute("depthstencil"))
         depthStencilName_ = element.GetAttribute("depthstencil");
         depthStencilName_ = element.GetAttribute("depthstencil");
     // Check for defining multiple outputs
     // Check for defining multiple outputs
@@ -182,9 +187,10 @@ void RenderPathCommand::Load(const XMLElement& element)
         unsigned index = outputElem.GetInt("index");
         unsigned index = outputElem.GetInt("index");
         if (index < MAX_RENDERTARGETS)
         if (index < MAX_RENDERTARGETS)
         {
         {
-            if (index >= outputNames_.Size())
-                outputNames_.Resize(index + 1);
-            outputNames_[index] = outputElem.GetAttribute("name");
+            if (index >= outputs_.Size())
+                outputs_.Resize(index + 1);
+            outputs_[index].first_ = outputElem.GetAttribute("name");
+            outputs_[index].second_ = outputElem.HasAttribute("face") ? (CubeMapFace)outputElem.GetInt("face") : FACE_POSITIVE_X;
         }
         }
         outputElem = outputElem.GetNext("output");
         outputElem = outputElem.GetNext("output");
     }
     }
@@ -224,17 +230,34 @@ void RenderPathCommand::RemoveShaderParameter(const String& name)
 void RenderPathCommand::SetNumOutputs(unsigned num)
 void RenderPathCommand::SetNumOutputs(unsigned num)
 {
 {
     num = Clamp((int)num, 1, MAX_RENDERTARGETS);
     num = Clamp((int)num, 1, MAX_RENDERTARGETS);
-    outputNames_.Resize(num);
+    outputs_.Resize(num);
+}
+
+void RenderPathCommand::SetOutput(unsigned index, const String& name, CubeMapFace face)
+{
+    if (index < outputs_.Size())
+        outputs_[index] = MakePair(name, face);
+    else if (index == outputs_.Size() && index < MAX_RENDERTARGETS)
+        outputs_.Push(MakePair(name, face));
 }
 }
 
 
 void RenderPathCommand::SetOutputName(unsigned index, const String& name)
 void RenderPathCommand::SetOutputName(unsigned index, const String& name)
 {
 {
-    if (index < outputNames_.Size())
-        outputNames_[index] = name;
-    else if (index == outputNames_.Size() && index < MAX_RENDERTARGETS)
-        outputNames_.Push(name);
+    if (index < outputs_.Size())
+        outputs_[index].first_ = name;
+    else if (index == outputs_.Size() && index < MAX_RENDERTARGETS)
+        outputs_.Push(MakePair(name, FACE_POSITIVE_X));
+}
+
+void RenderPathCommand::SetOutputFace(unsigned index, CubeMapFace face)
+{
+    if (index < outputs_.Size())
+        outputs_[index].second_ = face;
+    else if (index == outputs_.Size() && index < MAX_RENDERTARGETS)
+        outputs_.Push(MakePair(String::EMPTY, face));
 }
 }
 
 
+
 void RenderPathCommand::SetDepthStencilName(const String& name)
 void RenderPathCommand::SetDepthStencilName(const String& name)
 {
 {
     depthStencilName_ = name;
     depthStencilName_ = name;
@@ -253,7 +276,12 @@ const Variant& RenderPathCommand::GetShaderParameter(const String& name) const
 
 
 const String& RenderPathCommand::GetOutputName(unsigned index) const
 const String& RenderPathCommand::GetOutputName(unsigned index) const
 {
 {
-    return index < outputNames_.Size() ? outputNames_[index] : String::EMPTY;
+    return index < outputs_.Size() ? outputs_[index].first_ : String::EMPTY;
+}
+
+CubeMapFace RenderPathCommand::GetOutputFace(unsigned index) const
+{
+    return index < outputs_.Size() ? outputs_[index].second_ : FACE_POSITIVE_X;
 }
 }
 
 
 RenderPath::RenderPath()
 RenderPath::RenderPath()
@@ -264,9 +292,9 @@ RenderPath::~RenderPath()
 {
 {
 }
 }
 
 
-RenderPath *RenderPath::Clone()
+SharedPtr<RenderPath> RenderPath::Clone()
 {
 {
-    RenderPath* newRenderPath = new RenderPath();
+    SharedPtr<RenderPath> newRenderPath(new RenderPath());
     newRenderPath->renderTargets_ = renderTargets_;
     newRenderPath->renderTargets_ = renderTargets_;
     newRenderPath->commands_ = commands_;
     newRenderPath->commands_ = commands_;
     return newRenderPath;
     return newRenderPath;

+ 16 - 5
Source/Atomic/Graphics/RenderPath.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -69,6 +69,7 @@ struct RenderTargetInfo
         size_(Vector2::ZERO),
         size_(Vector2::ZERO),
         sizeMode_(SIZE_ABSOLUTE),
         sizeMode_(SIZE_ABSOLUTE),
         enabled_(true),
         enabled_(true),
+        cubemap_(false),
         filtered_(false),
         filtered_(false),
         sRGB_(false),
         sRGB_(false),
         persistent_(false)
         persistent_(false)
@@ -90,6 +91,8 @@ struct RenderTargetInfo
     RenderTargetSizeMode sizeMode_;
     RenderTargetSizeMode sizeMode_;
     /// Enabled flag.
     /// Enabled flag.
     bool enabled_;
     bool enabled_;
+    /// Cube map flag.
+    bool cubemap_;
     /// Filtering flag.
     /// Filtering flag.
     bool filtered_;
     bool filtered_;
     /// sRGB sampling/writing mode flag.
     /// sRGB sampling/writing mode flag.
@@ -122,8 +125,12 @@ struct RenderPathCommand
     void RemoveShaderParameter(const String& name);
     void RemoveShaderParameter(const String& name);
     /// Set number of output rendertargets.
     /// Set number of output rendertargets.
     void SetNumOutputs(unsigned num);
     void SetNumOutputs(unsigned num);
+    /// Set output rendertarget name and face index for cube maps.
+    void SetOutput(unsigned index, const String& name, CubeMapFace face = FACE_POSITIVE_X);
     /// Set output rendertarget name.
     /// Set output rendertarget name.
     void SetOutputName(unsigned index, const String& name);
     void SetOutputName(unsigned index, const String& name);
+    /// Set output rendertarget face index for cube maps.
+    void SetOutputFace(unsigned index, CubeMapFace face);
     /// Set depth-stencil output name. When empty, will assign a depth-stencil buffer automatically.
     /// Set depth-stencil output name. When empty, will assign a depth-stencil buffer automatically.
     void SetDepthStencilName(const String& name);
     void SetDepthStencilName(const String& name);
     
     
@@ -132,9 +139,11 @@ struct RenderPathCommand
     /// Return shader parameter.
     /// Return shader parameter.
     const Variant& GetShaderParameter(const String& name) const;
     const Variant& GetShaderParameter(const String& name) const;
     /// Return number of output rendertargets.
     /// Return number of output rendertargets.
-    unsigned GetNumOutputs() const { return outputNames_.Size(); }
+    unsigned GetNumOutputs() const { return outputs_.Size(); }
     /// Return output rendertarget name.
     /// Return output rendertarget name.
     const String& GetOutputName(unsigned index) const;
     const String& GetOutputName(unsigned index) const;
+    /// Return output rendertarget face index.
+    CubeMapFace GetOutputFace(unsigned index) const;
     /// Return depth-stencil output name.
     /// Return depth-stencil output name.
     const String& GetDepthStencilName() const { return depthStencilName_; }
     const String& GetDepthStencilName() const { return depthStencilName_; }
     
     
@@ -146,6 +155,8 @@ struct RenderPathCommand
     RenderCommandSortMode sortMode_;
     RenderCommandSortMode sortMode_;
     /// Scene pass name.
     /// Scene pass name.
     String pass_;
     String pass_;
+    /// Scene pass index. Filled by View.
+    unsigned passIndex_;
     /// Command/pass metadata.
     /// Command/pass metadata.
     String metadata_;
     String metadata_;
     /// Vertex shader name.
     /// Vertex shader name.
@@ -160,8 +171,8 @@ struct RenderPathCommand
     String textureNames_[MAX_TEXTURE_UNITS];
     String textureNames_[MAX_TEXTURE_UNITS];
     /// %Shader parameters.
     /// %Shader parameters.
     HashMap<StringHash, Variant> shaderParameters_;
     HashMap<StringHash, Variant> shaderParameters_;
-    /// Output rendertarget names.
-    Vector<String> outputNames_;
+    /// Output rendertarget names and faces.
+    Vector<Pair<String, CubeMapFace> > outputs_;
     /// Depth-stencil output name.
     /// Depth-stencil output name.
     String depthStencilName_;
     String depthStencilName_;
     /// Clear flags.
     /// Clear flags.
@@ -194,7 +205,7 @@ public:
     ~RenderPath();
     ~RenderPath();
     
     
     /// Clone the rendering path.
     /// Clone the rendering path.
-    RenderPath* Clone();
+    SharedPtr<RenderPath> Clone();
     /// Clear existing data and load from an XML file. Return true if successful.
     /// Clear existing data and load from an XML file. Return true if successful.
     bool Load(XMLFile* file);
     bool Load(XMLFile* file);
     /// Append data from an XML file. Return true if successful.
     /// Append data from an XML file. Return true if successful.

+ 4 - 2
Source/Atomic/Graphics/RenderSurface.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLRenderSurface.h"
 #include "OpenGL/OGLRenderSurface.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11RenderSurface.h"
 #else
 #else
 #include "Direct3D9/D3D9RenderSurface.h"
 #include "Direct3D9/D3D9RenderSurface.h"
 #endif
 #endif

+ 54 - 56
Source/Atomic/Graphics/Renderer.cpp

@@ -261,7 +261,6 @@ Renderer::Renderer(Context* context) :
     shadowQuality_(SHADOWQUALITY_HIGH_16BIT),
     shadowQuality_(SHADOWQUALITY_HIGH_16BIT),
     maxShadowMaps_(1),
     maxShadowMaps_(1),
     minInstances_(2),
     minInstances_(2),
-    maxInstanceTriangles_(500),
     maxSortedInstances_(1000),
     maxSortedInstances_(1000),
     maxOccluderTriangles_(5000),
     maxOccluderTriangles_(5000),
     occlusionBufferSize_(256),
     occlusionBufferSize_(256),
@@ -281,7 +280,6 @@ Renderer::Renderer(Context* context) :
     resetViews_(false)
     resetViews_(false)
 {
 {
     SubscribeToEvent(E_SCREENMODE, HANDLER(Renderer, HandleScreenMode));
     SubscribeToEvent(E_SCREENMODE, HANDLER(Renderer, HandleScreenMode));
-    SubscribeToEvent(E_GRAPHICSFEATURES, HANDLER(Renderer, HandleGraphicsFeatures));
     
     
     // Try to initialize right now, but skip if screen mode is not yet set
     // Try to initialize right now, but skip if screen mode is not yet set
     Initialize();
     Initialize();
@@ -439,11 +437,6 @@ void Renderer::SetMinInstances(int instances)
     minInstances_ = Max(instances, 2);
     minInstances_ = Max(instances, 2);
 }
 }
 
 
-void Renderer::SetMaxInstanceTriangles(int triangles)
-{
-    maxInstanceTriangles_ = Max(triangles, 0);
-}
-
 void Renderer::SetMaxSortedInstances(int instances)
 void Renderer::SetMaxSortedInstances(int instances)
 {
 {
     maxSortedInstances_ = Max(instances, 0);
     maxSortedInstances_ = Max(instances, 0);
@@ -662,7 +655,6 @@ void Renderer::Render()
     
     
     graphics_->SetDefaultTextureFilterMode(textureFilterMode_);
     graphics_->SetDefaultTextureFilterMode(textureFilterMode_);
     graphics_->SetTextureAnisotropy(textureAnisotropy_);
     graphics_->SetTextureAnisotropy(textureAnisotropy_);
-    graphics_->ClearParameterSources();
     
     
     // If no views, just clear the screen
     // If no views, just clear the screen
     if (views_.Empty())
     if (views_.Empty())
@@ -673,7 +665,6 @@ void Renderer::Render()
         graphics_->SetScissorTest(false);
         graphics_->SetScissorTest(false);
         graphics_->SetStencilTest(false);
         graphics_->SetStencilTest(false);
         graphics_->ResetRenderTargets();
         graphics_->ResetRenderTargets();
-
         graphics_->Clear(CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL, defaultZone_->GetFogColor());
         graphics_->Clear(CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL, defaultZone_->GetFogColor());
         
         
         numPrimitives_ = 0;
         numPrimitives_ = 0;
@@ -893,13 +884,12 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid
         }
         }
         else
         else
         {
         {
-            #ifdef ATOMIC_OPENGL
             #ifndef GL_ES_VERSION_2_0
             #ifndef GL_ES_VERSION_2_0
-            // OpenGL (desktop): shadow compare mode needs to be specifically enabled for the shadow map
+            // OpenGL (desktop) and D3D11: shadow compare mode needs to be specifically enabled for the shadow map
             newShadowMap->SetFilterMode(FILTER_BILINEAR);
             newShadowMap->SetFilterMode(FILTER_BILINEAR);
             newShadowMap->SetShadowCompare(true);
             newShadowMap->SetShadowCompare(true);
             #endif
             #endif
-            #else
+            #ifndef ATOMIC_OPENGL
             // Direct3D9: when shadow compare must be done manually, use nearest filtering so that the filtering of point lights
             // Direct3D9: when shadow compare must be done manually, use nearest filtering so that the filtering of point lights
             // and other shadowed lights matches
             // and other shadowed lights matches
             newShadowMap->SetFilterMode(graphics_->GetHardwareShadowSupport() ? FILTER_BILINEAR : FILTER_NEAREST);
             newShadowMap->SetFilterMode(graphics_->GetHardwareShadowSupport() ? FILTER_BILINEAR : FILTER_NEAREST);
@@ -932,7 +922,7 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid
     return newShadowMap;
     return newShadowMap;
 }
 }
 
 
-Texture2D* Renderer::GetScreenBuffer(int width, int height, unsigned format, bool filtered, bool srgb, unsigned persistentKey)
+Texture* Renderer::GetScreenBuffer(int width, int height, unsigned format, bool cubemap, bool filtered, bool srgb, unsigned persistentKey)
 {
 {
     bool depthStencil = (format == Graphics::GetDepthStencilFormat()) || (format == Graphics::GetReadableDepthFormat());
     bool depthStencil = (format == Graphics::GetDepthStencilFormat()) || (format == Graphics::GetReadableDepthFormat());
     if (depthStencil)
     if (depthStencil)
@@ -941,11 +931,16 @@ Texture2D* Renderer::GetScreenBuffer(int width, int height, unsigned format, boo
         srgb = false;
         srgb = false;
     }
     }
     
     
+    if (cubemap)
+        height = width;
+
     long long searchKey = ((long long)format << 32) | (width << 16) | height;
     long long searchKey = ((long long)format << 32) | (width << 16) | height;
     if (filtered)
     if (filtered)
         searchKey |= 0x8000000000000000LL;
         searchKey |= 0x8000000000000000LL;
     if (srgb)
     if (srgb)
         searchKey |= 0x4000000000000000LL;
         searchKey |= 0x4000000000000000LL;
+    if (cubemap)
+        searchKey |= 0x2000000000000000LL;
     
     
     // Add persistent key if defined
     // Add persistent key if defined
     if (persistentKey)
     if (persistentKey)
@@ -962,32 +957,48 @@ Texture2D* Renderer::GetScreenBuffer(int width, int height, unsigned format, boo
     
     
     if (allocations >= screenBuffers_[searchKey].Size())
     if (allocations >= screenBuffers_[searchKey].Size())
     {
     {
-        SharedPtr<Texture2D> newBuffer(new Texture2D(context_));
+        SharedPtr<Texture> newBuffer;
+
+        if (!cubemap)
+        {
+            SharedPtr<Texture2D> newTex2D(new Texture2D(context_));
+            newTex2D->SetSize(width, height, format, depthStencil ? TEXTURE_DEPTHSTENCIL : TEXTURE_RENDERTARGET);
+
+            #ifdef ATOMIC_OPENGL
+            // OpenGL hack: clear persistent floating point screen buffers to ensure the initial contents aren't illegal (NaN)?
+            // Otherwise eg. the AutoExposure post process will not work correctly
+            if (persistentKey && Texture::GetDataType(format) == GL_FLOAT)
+            {
+                // Note: this loses current rendertarget assignment
+                graphics_->ResetRenderTargets();
+                graphics_->SetRenderTarget(0, newTex2D);
+                graphics_->SetDepthStencil((RenderSurface*)0);
+                graphics_->SetViewport(IntRect(0, 0, width, height));
+                graphics_->Clear(CLEAR_COLOR);
+            }
+            #endif
+
+            newBuffer = StaticCast<Texture>(newTex2D);
+        }
+        else
+        {
+            SharedPtr<TextureCube> newTexCube(new TextureCube(context_));
+            newTexCube->SetSize(width, format, TEXTURE_RENDERTARGET);
+
+            newBuffer = StaticCast<Texture>(newTexCube);
+        }
+        
         newBuffer->SetSRGB(srgb);
         newBuffer->SetSRGB(srgb);
-        newBuffer->SetSize(width, height, format, depthStencil ? TEXTURE_DEPTHSTENCIL : TEXTURE_RENDERTARGET);
         newBuffer->SetFilterMode(filtered ? FILTER_BILINEAR : FILTER_NEAREST);
         newBuffer->SetFilterMode(filtered ? FILTER_BILINEAR : FILTER_NEAREST);
         newBuffer->ResetUseTimer();
         newBuffer->ResetUseTimer();
         screenBuffers_[searchKey].Push(newBuffer);
         screenBuffers_[searchKey].Push(newBuffer);
-        #ifdef ATOMIC_OPENGL
-        // OpenGL hack: clear persistent floating point screen buffers to ensure the initial contents aren't illegal (NaN)?
-        // Otherwise eg. the AutoExposure post process will not work correctly
-        if (persistentKey && Texture::GetDataType(format) == GL_FLOAT)
-        {
-            // Note: this loses current rendertarget assignment
-            graphics_->ResetRenderTargets();
-            graphics_->SetRenderTarget(0, newBuffer);
-            graphics_->SetDepthStencil((RenderSurface*)0);
-            graphics_->SetViewport(IntRect(0, 0, width, height));
-            graphics_->Clear(CLEAR_COLOR);
-        }
-        #endif
-        
+
         LOGDEBUG("Allocated new screen buffer size " + String(width) + "x" + String(height) + " format " + String(format));
         LOGDEBUG("Allocated new screen buffer size " + String(width) + "x" + String(height) + " format " + String(format));
         return newBuffer;
         return newBuffer;
     }
     }
     else
     else
     {
     {
-        Texture2D* buffer = screenBuffers_[searchKey][allocations];
+        Texture* buffer = screenBuffers_[searchKey][allocations];
         buffer->ResetUseTimer();
         buffer->ResetUseTimer();
         return buffer;
         return buffer;
     }
     }
@@ -1000,7 +1011,10 @@ RenderSurface* Renderer::GetDepthStencil(int width, int height)
     if (width == graphics_->GetWidth() && height == graphics_->GetHeight() && graphics_->GetMultiSample() <= 1)
     if (width == graphics_->GetWidth() && height == graphics_->GetHeight() && graphics_->GetMultiSample() <= 1)
         return 0;
         return 0;
     else
     else
-        return GetScreenBuffer(width, height, Graphics::GetDepthStencilFormat(), false, false)->GetRenderSurface();
+    {
+        return static_cast<Texture2D*>(GetScreenBuffer(width, height, Graphics::GetDepthStencilFormat(), false, false, false))->
+            GetRenderSurface();
+    }
 }
 }
 
 
 OcclusionBuffer* Renderer::GetOcclusionBuffer(Camera* camera)
 OcclusionBuffer* Renderer::GetOcclusionBuffer(Camera* camera)
@@ -1053,7 +1067,7 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* tech, bool allowShadows)
     {
     {
         // First release all previous shaders, then load
         // First release all previous shaders, then load
         pass->ReleaseShaders();
         pass->ReleaseShaders();
-        LoadPassShaders(tech, pass->GetType());
+        LoadPassShaders(pass);
     }
     }
     
     
     // Make sure shaders are loaded now
     // Make sure shaders are loaded now
@@ -1061,10 +1075,8 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* tech, bool allowShadows)
     {
     {
         bool heightFog = batch.zone_ && batch.zone_->GetHeightFog();
         bool heightFog = batch.zone_ && batch.zone_->GetHeightFog();
         
         
-        // If instancing is not supported, but was requested, or the object is too large to be instanced,
-        // choose static geometry vertex shader instead
-        if (batch.geometryType_ == GEOM_INSTANCED && (!GetDynamicInstancing() || batch.geometry_->GetIndexCount() >
-            (unsigned)maxInstanceTriangles_ * 3))
+        // If instancing is not supported, but was requested, choose static geometry vertex shader instead
+        if (batch.geometryType_ == GEOM_INSTANCED && !GetDynamicInstancing())
             batch.geometryType_ = GEOM_STATIC;
             batch.geometryType_ = GEOM_STATIC;
         
         
         if (batch.geometryType_ == GEOM_STATIC_NOINSTANCING)
         if (batch.geometryType_ == GEOM_STATIC_NOINSTANCING)
@@ -1373,13 +1385,13 @@ void Renderer::RemoveUnusedBuffers()
         }
         }
     }
     }
     
     
-    for (HashMap<long long, Vector<SharedPtr<Texture2D> > >::Iterator i = screenBuffers_.Begin(); i != screenBuffers_.End();)
+    for (HashMap<long long, Vector<SharedPtr<Texture> > >::Iterator i = screenBuffers_.Begin(); i != screenBuffers_.End();)
     {
     {
-        HashMap<long long, Vector<SharedPtr<Texture2D> > >::Iterator current = i++;
-        Vector<SharedPtr<Texture2D> >& buffers = current->second_;
+        HashMap<long long, Vector<SharedPtr<Texture> > >::Iterator current = i++;
+        Vector<SharedPtr<Texture> >& buffers = current->second_;
         for (unsigned j = buffers.Size() - 1; j < buffers.Size(); --j)
         for (unsigned j = buffers.Size() - 1; j < buffers.Size(); --j)
         {
         {
-            Texture2D* buffer = buffers[j];
+            Texture* buffer = buffers[j];
             if (buffer->GetUseTimer() > MAX_BUFFER_AGE)
             if (buffer->GetUseTimer() > MAX_BUFFER_AGE)
             {
             {
                 LOGDEBUG("Removed unused screen buffer size " + String(buffer->GetWidth()) + "x" + String(buffer->GetHeight()) + " format " + String(buffer->GetFormat()));
                 LOGDEBUG("Removed unused screen buffer size " + String(buffer->GetWidth()) + "x" + String(buffer->GetHeight()) + " format " + String(buffer->GetFormat()));
@@ -1468,12 +1480,8 @@ void Renderer::LoadShaders()
     shadersDirty_ = false;
     shadersDirty_ = false;
 }
 }
 
 
-void Renderer::LoadPassShaders(Technique* tech, StringHash type)
+void Renderer::LoadPassShaders(Pass* pass)
 {
 {
-    Pass* pass = tech->GetPass(type);
-    if (!pass)
-        return;
-    
     PROFILE(LoadPassShaders);
     PROFILE(LoadPassShaders);
     
     
     unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
     unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
@@ -1697,11 +1705,8 @@ void Renderer::CreateInstancingBuffer()
         return;
         return;
     }
     }
     
     
-    // If must lock the buffer for each batch group, set a smaller size
-    unsigned defaultSize = graphics_->GetStreamOffsetSupport() ? INSTANCING_BUFFER_DEFAULT_SIZE : INSTANCING_BUFFER_DEFAULT_SIZE / 4;
-    
     instancingBuffer_ = new VertexBuffer(context_);
     instancingBuffer_ = new VertexBuffer(context_);
-    if (!instancingBuffer_->SetSize(defaultSize, INSTANCING_BUFFER_MASK, true))
+    if (!instancingBuffer_->SetSize(INSTANCING_BUFFER_DEFAULT_SIZE, INSTANCING_BUFFER_MASK, true))
     {
     {
         instancingBuffer_.Reset();
         instancingBuffer_.Reset();
         dynamicInstancing_ = false;
         dynamicInstancing_ = false;
@@ -1730,13 +1735,6 @@ void Renderer::HandleScreenMode(StringHash eventType, VariantMap& eventData)
         resetViews_ = true;
         resetViews_ = true;
 }
 }
 
 
-void Renderer::HandleGraphicsFeatures(StringHash eventType, VariantMap& eventData)
-{
-    // Reinitialize if already initialized
-    if (initialized_)
-        Initialize();
-}
-
 void Renderer::HandleRenderUpdate(StringHash eventType, VariantMap& eventData)
 void Renderer::HandleRenderUpdate(StringHash eventType, VariantMap& eventData)
 {
 {
     using namespace RenderUpdate;
     using namespace RenderUpdate;

+ 8 - 15
Source/Atomic/Graphics/Renderer.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -45,6 +45,7 @@ class RenderSurface;
 class ResourceCache;
 class ResourceCache;
 class Skeleton;
 class Skeleton;
 class OcclusionBuffer;
 class OcclusionBuffer;
+class Texture;
 class Texture2D;
 class Texture2D;
 class TextureCube;
 class TextureCube;
 class View;
 class View;
@@ -173,15 +174,15 @@ public:
     void SetTextureAnisotropy(int level);
     void SetTextureAnisotropy(int level);
     /// Set texture filtering.
     /// Set texture filtering.
     void SetTextureFilterMode(TextureFilterMode mode);
     void SetTextureFilterMode(TextureFilterMode mode);
-    /// Set texture quality level.
+    /// Set texture quality level. See the QUALITY constants in GraphicsDefs.h.
     void SetTextureQuality(int quality);
     void SetTextureQuality(int quality);
-    /// Set material quality level.
+    /// Set material quality level. See the QUALITY constants in GraphicsDefs.h.
     void SetMaterialQuality(int quality);
     void SetMaterialQuality(int quality);
     /// Set shadows on/off.
     /// Set shadows on/off.
     void SetDrawShadows(bool enable);
     void SetDrawShadows(bool enable);
     /// Set shadow map resolution.
     /// Set shadow map resolution.
     void SetShadowMapSize(int size);
     void SetShadowMapSize(int size);
-    /// Set shadow quality (amount of samples and bit depth.)
+    /// Set shadow quality mode. See the SHADOWQUALITY constants in GraphicsDefs.h.
     void SetShadowQuality(int quality);
     void SetShadowQuality(int quality);
     /// Set reuse of shadow maps. Default is true. If disabled, also transparent geometry can be shadowed.
     /// Set reuse of shadow maps. Default is true. If disabled, also transparent geometry can be shadowed.
     void SetReuseShadowMaps(bool enable);
     void SetReuseShadowMaps(bool enable);
@@ -191,8 +192,6 @@ public:
     void SetDynamicInstancing(bool enable);
     void SetDynamicInstancing(bool enable);
     /// Set minimum number of instances required in a batch group to render as instanced.
     /// Set minimum number of instances required in a batch group to render as instanced.
     void SetMinInstances(int instances);
     void SetMinInstances(int instances);
-    /// Set maximum number of triangles per object for instancing.
-    void SetMaxInstanceTriangles(int triangles);
     /// Set maximum number of sorted instances per batch group. If exceeded, instances are rendered unsorted.
     /// Set maximum number of sorted instances per batch group. If exceeded, instances are rendered unsorted.
     void SetMaxSortedInstances(int instances);
     void SetMaxSortedInstances(int instances);
     /// Set maximum number of occluder trianges.
     /// Set maximum number of occluder trianges.
@@ -240,8 +239,6 @@ public:
     bool GetDynamicInstancing() const { return dynamicInstancing_; }
     bool GetDynamicInstancing() const { return dynamicInstancing_; }
     /// Return minimum number of instances required in a batch group to render as instanced.
     /// Return minimum number of instances required in a batch group to render as instanced.
     int GetMinInstances() const { return minInstances_; }
     int GetMinInstances() const { return minInstances_; }
-    /// Return maximum number of triangles per object for instancing.
-    int GetMaxInstanceTriangles() const { return maxInstanceTriangles_; }
     /// Return maximum number of sorted instances per batch group.
     /// Return maximum number of sorted instances per batch group.
     int GetMaxSortedInstances() const { return maxSortedInstances_; }
     int GetMaxSortedInstances() const { return maxSortedInstances_; }
     /// Return maximum number of occluder triangles.
     /// Return maximum number of occluder triangles.
@@ -303,7 +300,7 @@ public:
     /// Allocate a shadow map. If shadow map reuse is disabled, a different map is returned each time.
     /// Allocate a shadow map. If shadow map reuse is disabled, a different map is returned each time.
     Texture2D* GetShadowMap(Light* light, Camera* camera, unsigned viewWidth, unsigned viewHeight);
     Texture2D* GetShadowMap(Light* light, Camera* camera, unsigned viewWidth, unsigned viewHeight);
     /// Allocate a rendertarget or depth-stencil texture for deferred rendering or postprocessing. Should only be called during actual rendering, not before.
     /// Allocate a rendertarget or depth-stencil texture for deferred rendering or postprocessing. Should only be called during actual rendering, not before.
-    Texture2D* GetScreenBuffer(int width, int height, unsigned format, bool filtered, bool srgb, unsigned persistentKey = 0);
+    Texture* GetScreenBuffer(int width, int height, unsigned format, bool cubemap, bool filtered, bool srgb, unsigned persistentKey = 0);
     /// Allocate a depth-stencil surface that does not need to be readable. Should only be called during actual rendering, not before.
     /// Allocate a depth-stencil surface that does not need to be readable. Should only be called during actual rendering, not before.
     RenderSurface* GetDepthStencil(int width, int height);
     RenderSurface* GetDepthStencil(int width, int height);
     /// Allocate an occlusion buffer.
     /// Allocate an occlusion buffer.
@@ -335,7 +332,7 @@ private:
     /// Reload shaders.
     /// Reload shaders.
     void LoadShaders();
     void LoadShaders();
     /// Reload shaders for a material pass.
     /// Reload shaders for a material pass.
-    void LoadPassShaders(Technique* tech, StringHash passType);
+    void LoadPassShaders(Pass* pass);
     /// Release shaders used in materials.
     /// Release shaders used in materials.
     void ReleaseMaterialShaders();
     void ReleaseMaterialShaders();
     /// Reload textures.
     /// Reload textures.
@@ -360,8 +357,6 @@ private:
     void ResetBuffers();
     void ResetBuffers();
     /// Handle screen mode event.
     /// Handle screen mode event.
     void HandleScreenMode(StringHash eventType, VariantMap& eventData);
     void HandleScreenMode(StringHash eventType, VariantMap& eventData);
-    /// Handle graphics features (re)check event. Event only sent by D3D9Graphics class.
-    void HandleGraphicsFeatures(StringHash eventType, VariantMap& eventData);
     /// Handle render update event.
     /// Handle render update event.
     void HandleRenderUpdate(StringHash eventType, VariantMap& eventData);
     void HandleRenderUpdate(StringHash eventType, VariantMap& eventData);
     
     
@@ -400,7 +395,7 @@ private:
     /// Shadow map allocations by resolution.
     /// Shadow map allocations by resolution.
     HashMap<int, PODVector<Light*> > shadowMapAllocations_;
     HashMap<int, PODVector<Light*> > shadowMapAllocations_;
     /// Screen buffers by resolution and format.
     /// Screen buffers by resolution and format.
-    HashMap<long long, Vector<SharedPtr<Texture2D> > > screenBuffers_;
+    HashMap<long long, Vector<SharedPtr<Texture> > > screenBuffers_;
     /// Current screen buffer allocations by resolution and format.
     /// Current screen buffer allocations by resolution and format.
     HashMap<long long, unsigned> screenBufferAllocations_;
     HashMap<long long, unsigned> screenBufferAllocations_;
     /// Saved status of screen buffer allocations for restoring.
     /// Saved status of screen buffer allocations for restoring.
@@ -439,8 +434,6 @@ private:
     int maxShadowMaps_;
     int maxShadowMaps_;
     /// Minimum number of instances required in a batch group to render as instanced.
     /// Minimum number of instances required in a batch group to render as instanced.
     int minInstances_;
     int minInstances_;
-    /// Maximum triangles per object for instancing.
-    int maxInstanceTriangles_;
     /// Maximum sorted instances per batch group.
     /// Maximum sorted instances per batch group.
     int maxSortedInstances_;
     int maxSortedInstances_;
     /// Maximum occluder triangles.
     /// Maximum occluder triangles.

+ 6 - 2
Source/Atomic/Graphics/ShaderProgram.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,6 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLShaderProgram.h"
 #include "OpenGL/OGLShaderProgram.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11ShaderProgram.h"
+#else
+#include "Direct3D9/D3D9ShaderProgram.h"
 #endif
 #endif

+ 4 - 2
Source/Atomic/Graphics/ShaderVariation.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLShaderVariation.h"
 #include "OpenGL/OGLShaderVariation.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11ShaderVariation.h"
 #else
 #else
 #include "Direct3D9/D3D9ShaderVariation.h"
 #include "Direct3D9/D3D9ShaderVariation.h"
 #endif
 #endif

+ 120 - 57
Source/Atomic/Graphics/Technique.cpp

@@ -70,21 +70,23 @@ static const char* lightingModeNames[] =
     0
     0
 };
 };
 
 
-Pass::Pass(StringHash type) :
-    type_(type),
+Pass::Pass(const String& name) :
     blendMode_(BLEND_REPLACE),
     blendMode_(BLEND_REPLACE),
     depthTestMode_(CMP_LESSEQUAL),
     depthTestMode_(CMP_LESSEQUAL),
     lightingMode_(LIGHTING_UNLIT),
     lightingMode_(LIGHTING_UNLIT),
     shadersLoadedFrameNumber_(0),
     shadersLoadedFrameNumber_(0),
     depthWrite_(true),
     depthWrite_(true),
     alphaMask_(false),
     alphaMask_(false),
-    isSM3_(false),
     isDesktop_(false)
     isDesktop_(false)
 {
 {
+    name_ = name.ToLower();
+    index_ = Technique::GetPassIndex(name_);
+
     // Guess default lighting mode from pass name
     // Guess default lighting mode from pass name
-    if (type == PASS_BASE || type == PASS_ALPHA || type == PASS_MATERIAL || type == PASS_DEFERRED)
+    if (index_ == Technique::basePassIndex || index_ == Technique::alphaPassIndex || index_ == Technique::materialPassIndex ||
+        index_ == Technique::deferredPassIndex)
         lightingMode_ = LIGHTING_PERVERTEX;
         lightingMode_ = LIGHTING_PERVERTEX;
-    else if (type == PASS_LIGHT || type == PASS_LITBASE || type == PASS_LITALPHA)
+    else if (index_ == Technique::lightPassIndex || index_ == Technique::litBasePassIndex || index_ == Technique::litAlphaPassIndex)
         lightingMode_ = LIGHTING_PERPIXEL;
         lightingMode_ = LIGHTING_PERPIXEL;
 }
 }
 
 
@@ -117,11 +119,6 @@ void Pass::SetAlphaMask(bool enable)
     alphaMask_ = enable;
     alphaMask_ = enable;
 }
 }
 
 
-void Pass::SetIsSM3(bool enable)
-{
-    isSM3_ = enable;
-}
-
 void Pass::SetIsDesktop(bool enable)
 void Pass::SetIsDesktop(bool enable)
 {
 {
     isDesktop_ = enable;
     isDesktop_ = enable;
@@ -162,15 +159,20 @@ void Pass::MarkShadersLoaded(unsigned frameNumber)
     shadersLoadedFrameNumber_ = frameNumber;
     shadersLoadedFrameNumber_ = frameNumber;
 }
 }
 
 
+unsigned Technique::basePassIndex = 0;
+unsigned Technique::alphaPassIndex = 0;
+unsigned Technique::materialPassIndex = 0;
+unsigned Technique::deferredPassIndex = 0;
+unsigned Technique::lightPassIndex = 0;
+unsigned Technique::litBasePassIndex = 0;
+unsigned Technique::litAlphaPassIndex = 0;
+unsigned Technique::shadowPassIndex = 0;
+HashMap<String, unsigned> Technique::passIndices;
+
 Technique::Technique(Context* context) :
 Technique::Technique(Context* context) :
     Resource(context),
     Resource(context),
-    isSM3_(false),
-    isDesktop_(false),
-    numPasses_(0)
+    isDesktop_(false)
 {
 {
-    Graphics* graphics = GetSubsystem<Graphics>();
-    sm3Support_ = graphics ? graphics->GetSM3Support() : true;
-    
     #ifdef DESKTOP_GRAPHICS
     #ifdef DESKTOP_GRAPHICS
     desktopSupport_ = true;
     desktopSupport_ = true;
     #else
     #else
@@ -191,7 +193,6 @@ bool Technique::BeginLoad(Deserializer& source)
 {
 {
     passes_.Clear();
     passes_.Clear();
 
 
-    numPasses_ = 0;
     SetMemoryUse(sizeof(Technique));
     SetMemoryUse(sizeof(Technique));
     
     
     SharedPtr<XMLFile> xml(new XMLFile(context_));
     SharedPtr<XMLFile> xml(new XMLFile(context_));
@@ -199,8 +200,6 @@ bool Technique::BeginLoad(Deserializer& source)
         return false;
         return false;
     
     
     XMLElement rootElem = xml->GetRoot();
     XMLElement rootElem = xml->GetRoot();
-    if (rootElem.HasAttribute("sm3"))
-        isSM3_ = rootElem.GetBool("sm3");
     if (rootElem.HasAttribute("desktop"))
     if (rootElem.HasAttribute("desktop"))
         isDesktop_ = rootElem.GetBool("desktop");
         isDesktop_ = rootElem.GetBool("desktop");
     
     
@@ -222,12 +221,8 @@ bool Technique::BeginLoad(Deserializer& source)
     {
     {
         if (passElem.HasAttribute("name"))
         if (passElem.HasAttribute("name"))
         {
         {
-            StringHash nameHash(passElem.GetAttribute("name"));
-            
-            Pass* newPass = CreatePass(nameHash);
-            
-            if (passElem.HasAttribute("sm3"))
-                newPass->SetIsSM3(passElem.GetBool("sm3"));
+            Pass* newPass = CreatePass(passElem.GetAttribute("name"));
+
             if (passElem.HasAttribute("desktop"))
             if (passElem.HasAttribute("desktop"))
                 newPass->SetIsDesktop(passElem.GetBool("desktop"));
                 newPass->SetIsDesktop(passElem.GetBool("desktop"));
             
             
@@ -292,11 +287,6 @@ bool Technique::BeginLoad(Deserializer& source)
     return true;
     return true;
 }
 }
 
 
-void Technique::SetIsSM3(bool enable)
-{
-    isSM3_ = enable;
-}
-
 void Technique::SetIsDesktop(bool enable)
 void Technique::SetIsDesktop(bool enable)
 {
 {
     isDesktop_ = enable;
     isDesktop_ = enable;
@@ -304,55 +294,128 @@ void Technique::SetIsDesktop(bool enable)
 
 
 void Technique::ReleaseShaders()
 void Technique::ReleaseShaders()
 {
 {
-    PODVector<SharedPtr<Pass>*> allPasses = passes_.Values();
-    
-    for (unsigned i = 0; i < allPasses.Size(); ++i)
-        allPasses[i]->Get()->ReleaseShaders();
+    for (Vector<SharedPtr<Pass> >::ConstIterator i = passes_.Begin(); i != passes_.End(); ++i)
+    {
+        Pass* pass = i->Get();
+        if (pass)
+            pass->ReleaseShaders();
+    }
 }
 }
 
 
-Pass* Technique::CreatePass(StringHash type)
+Pass* Technique::CreatePass(const String& name)
 {
 {
-    Pass* oldPass = GetPass(type);
+    Pass* oldPass = GetPass(name);
     if (oldPass)
     if (oldPass)
         return oldPass;
         return oldPass;
     
     
-    SharedPtr<Pass> newPass(new Pass(type));
-    passes_.Insert(type.Value(), newPass);
+    SharedPtr<Pass> newPass(new Pass(name));
+    unsigned passIndex = newPass->GetIndex();
+    if (passIndex >= passes_.Size())
+        passes_.Resize(passIndex + 1);
+    passes_[passIndex] = newPass;
     
     
     // Calculate memory use now
     // Calculate memory use now
-    SetMemoryUse(sizeof(Technique) + ++numPasses_ * sizeof(Pass));
+    SetMemoryUse(sizeof(Technique) + GetNumPasses() * sizeof(Pass));
 
 
     return newPass;
     return newPass;
 }
 }
 
 
-void Technique::RemovePass(StringHash type)
+void Technique::RemovePass(const String& name)
+{
+    HashMap<String, unsigned>::ConstIterator i = passIndices.Find(name.ToLower());
+    if (i == passIndices.End())
+        return;
+    else if (i->second_ < passes_.Size() && passes_[i->second_].Get())
+    {
+        passes_[i->second_].Reset();
+        SetMemoryUse(sizeof(Technique) + GetNumPasses() * sizeof(Pass));
+    }
+}
+
+bool Technique::HasPass(const String& name) const
+{
+    HashMap<String, unsigned>::ConstIterator i = passIndices.Find(name.ToLower());
+    return i != passIndices.End() ? HasPass(i->second_) : false;
+}
+
+Pass* Technique::GetPass(const String& name) const
 {
 {
-    if (passes_.Erase(type.Value()))
-        SetMemoryUse(sizeof(Technique) + --numPasses_ * sizeof(Pass));
+    HashMap<String, unsigned>::ConstIterator i = passIndices.Find(name.ToLower());
+    return i != passIndices.End() ? GetPass(i->second_) : 0;
 }
 }
 
 
-Vector<StringHash> Technique::GetPassTypes() const
+Pass* Technique::GetSupportedPass(const String& name) const
 {
 {
-    // Convert PODVector<unsigned> to Vector<StringHash>
-    PODVector<unsigned> vectorIn = passes_.Keys();
-    Vector<StringHash> vectorOut;
-    vectorOut.Reserve(vectorIn.Size());
-    for (unsigned i = 0; i < vectorIn.Size(); ++i)
-        vectorOut.Push(StringHash(vectorIn[i]));
+    HashMap<String, unsigned>::ConstIterator i = passIndices.Find(name.ToLower());
+    return i != passIndices.End() ? GetSupportedPass(i->second_) : 0;
+}
+
+unsigned Technique::GetNumPasses() const
+{
+    unsigned ret = 0;
+
+    for (Vector<SharedPtr<Pass> >::ConstIterator i = passes_.Begin(); i != passes_.End(); ++i)
+    {
+        if (i->Get())
+            ++ret;
+    }
+
+    return ret;
+}
+
+Vector<String> Technique::GetPassNames() const
+{
+    Vector<String> ret;
+
+    for (Vector<SharedPtr<Pass> >::ConstIterator i = passes_.Begin(); i != passes_.End(); ++i)
+    {
+        Pass* pass = i->Get();
+        if (pass)
+            ret.Push(pass->GetName());
+    }
 
 
-    return vectorOut;
+    return ret;
 }
 }
 
 
 PODVector<Pass*> Technique::GetPasses() const
 PODVector<Pass*> Technique::GetPasses() const
 {
 {
-    // Convert PODVector<SharedPtr<Pass>*> to PODVector<Pass*>
-    PODVector<SharedPtr<Pass>*> vectorIn = passes_.Values();
-    PODVector<Pass*> vectorOut;
-    vectorOut.Reserve(vectorIn.Size());
-    for (unsigned i = 0; i < vectorIn.Size(); ++i)
-        vectorOut.Push(vectorIn[i]->Get());
+    PODVector<Pass*> ret;
+
+    for (Vector<SharedPtr<Pass> >::ConstIterator i = passes_.Begin(); i != passes_.End(); ++i)
+    {
+        Pass* pass = i->Get();
+        if (pass)
+            ret.Push(pass);
+    }
+
+    return ret;
+}
+
+unsigned Technique::GetPassIndex(const String& passName)
+{
+    // Initialize built-in pass indices on first call
+    if (passIndices.Empty())
+    {
+        basePassIndex = passIndices["base"] = 0;
+        alphaPassIndex = passIndices["alpha"] = 1;
+        materialPassIndex = passIndices["material"] = 2;
+        deferredPassIndex = passIndices["deferred"] = 3;
+        lightPassIndex = passIndices["light"] = 4;
+        litBasePassIndex = passIndices["litbase"] = 5;
+        litAlphaPassIndex = passIndices["litalpha"] = 6;
+        shadowPassIndex = passIndices["shadow"] = 7;
+    }
 
 
-    return vectorOut;
+    String nameLower = passName.ToLower();
+    HashMap<String, unsigned>::Iterator i = passIndices.Find(nameLower);
+    if (i != passIndices.End())
+        return i->second_;
+    else
+    {
+        unsigned newPassIndex = passIndices.Size();
+        passIndices[nameLower] = newPassIndex;
+        return newPassIndex;
+    }
 }
 }
 
 
 }
 }

+ 53 - 40
Source/Atomic/Graphics/Technique.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,6 @@
 #pragma once
 #pragma once
 
 
 #include "../Graphics/GraphicsDefs.h"
 #include "../Graphics/GraphicsDefs.h"
-#include "../Container/HashTable.h"
 #include "../Resource/Resource.h"
 #include "../Resource/Resource.h"
 
 
 namespace Atomic
 namespace Atomic
@@ -44,7 +43,7 @@ class ATOMIC_API Pass : public RefCounted
 {
 {
 public:
 public:
     /// Construct.
     /// Construct.
-    Pass(StringHash type);
+    Pass(const String& passName);
     /// Destruct.
     /// Destruct.
     ~Pass();
     ~Pass();
     
     
@@ -58,8 +57,6 @@ public:
     void SetDepthWrite(bool enable);
     void SetDepthWrite(bool enable);
     /// Set alpha masking hint. Completely opaque draw calls will be performed before alpha masked.
     /// Set alpha masking hint. Completely opaque draw calls will be performed before alpha masked.
     void SetAlphaMask(bool enable);
     void SetAlphaMask(bool enable);
-    /// Set whether requires %Shader %Model 3.
-    void SetIsSM3(bool enable);
     /// Set whether requires desktop level hardware.
     /// Set whether requires desktop level hardware.
     void SetIsDesktop(bool enable);
     void SetIsDesktop(bool enable);
     /// Set vertex shader name.
     /// Set vertex shader name.
@@ -75,8 +72,10 @@ public:
     /// Mark shaders loaded this frame.
     /// Mark shaders loaded this frame.
     void MarkShadersLoaded(unsigned frameNumber);
     void MarkShadersLoaded(unsigned frameNumber);
     
     
-    /// Return pass type.
-    const StringHash& GetType() const { return type_; }
+    /// Return pass name.
+    const String& GetName() const { return name_; }
+    /// Return pass index. This is used for optimal render-time pass queries that avoid map lookups.
+    unsigned GetIndex() const { return index_; }
     /// Return blend mode.
     /// Return blend mode.
     BlendMode GetBlendMode() const { return blendMode_; }
     BlendMode GetBlendMode() const { return blendMode_; }
     /// Return depth compare mode.
     /// Return depth compare mode.
@@ -89,8 +88,6 @@ public:
     bool GetDepthWrite() const { return depthWrite_; }
     bool GetDepthWrite() const { return depthWrite_; }
     /// Return alpha masking hint.
     /// Return alpha masking hint.
     bool GetAlphaMask() const { return alphaMask_; }
     bool GetAlphaMask() const { return alphaMask_; }
-    /// Return whether requires %Shader %Model 3.
-    bool IsSM3() const { return isSM3_; }
     /// Return whether requires desktop level hardware.
     /// Return whether requires desktop level hardware.
     bool IsDesktop() const { return isDesktop_; }
     bool IsDesktop() const { return isDesktop_; }
     /// Return vertex shader name.
     /// Return vertex shader name.
@@ -107,8 +104,8 @@ public:
     Vector<SharedPtr<ShaderVariation> >& GetPixelShaders() { return pixelShaders_; }
     Vector<SharedPtr<ShaderVariation> >& GetPixelShaders() { return pixelShaders_; }
     
     
 private:
 private:
-    /// Pass type.
-    StringHash type_;
+    /// Pass index.
+    unsigned index_;
     /// Blend mode.
     /// Blend mode.
     BlendMode blendMode_;
     BlendMode blendMode_;
     /// Depth compare mode.
     /// Depth compare mode.
@@ -137,6 +134,8 @@ private:
     Vector<SharedPtr<ShaderVariation> > vertexShaders_;
     Vector<SharedPtr<ShaderVariation> > vertexShaders_;
     /// Pixel shaders.
     /// Pixel shaders.
     Vector<SharedPtr<ShaderVariation> > pixelShaders_;
     Vector<SharedPtr<ShaderVariation> > pixelShaders_;
+    /// Pass name.
+    String name_;
 };
 };
 
 
 /// %Material technique. Consists of several passes.
 /// %Material technique. Consists of several passes.
@@ -157,61 +156,75 @@ public:
     /// Load resource from stream. May be called from a worker thread. Return true if successful.
     /// Load resource from stream. May be called from a worker thread. Return true if successful.
     virtual bool BeginLoad(Deserializer& source);
     virtual bool BeginLoad(Deserializer& source);
     
     
-    /// Set whether requires %Shader %Model 3.
-    void SetIsSM3(bool enable);
     /// Set whether requires desktop level hardware.
     /// Set whether requires desktop level hardware.
     void SetIsDesktop(bool enable);
     void SetIsDesktop(bool enable);
     /// Create a new pass.
     /// Create a new pass.
-    Pass* CreatePass(StringHash type);
+    Pass* CreatePass(const String& passName);
     /// Remove a pass.
     /// Remove a pass.
-    void RemovePass(StringHash type);
+    void RemovePass(const String& passName);
     /// Reset shader pointers in all passes.
     /// Reset shader pointers in all passes.
     void ReleaseShaders();
     void ReleaseShaders();
     
     
-    /// Return whether requires %Shader %Model 3.
-    bool IsSM3() const { return isSM3_; }
     /// Return whether requires desktop level hardware.
     /// Return whether requires desktop level hardware.
     bool IsDesktop() const { return isDesktop_; }
     bool IsDesktop() const { return isDesktop_; }
     /// Return whether technique is supported by the current hardware.
     /// Return whether technique is supported by the current hardware.
-    bool IsSupported() const { return (!isSM3_ || sm3Support_) && (!isDesktop_ || desktopSupport_); }
+    bool IsSupported() const { return !isDesktop_ || desktopSupport_; }
     /// Return whether has a pass.
     /// Return whether has a pass.
-    bool HasPass(StringHash type) const { return  passes_.Find(type.Value()) != 0; }
-    
+    bool HasPass(unsigned passIndex) const { return passIndex < passes_.Size() && passes_[passIndex].Get() != 0; }
+    /// Return whether has a pass by name. This overload should not be called in time-critical rendering loops; use a pre-acquired pass index instead.
+    bool HasPass(const String& passName) const;
     /// Return a pass, or null if not found.
     /// Return a pass, or null if not found.
-    Pass* GetPass(StringHash type) const
-    {
-        SharedPtr<Pass>* passPtr = passes_.Find(type.Value());
-        return passPtr ? passPtr->Get() : 0;
-    }
+    Pass* GetPass(unsigned passIndex) const { return passIndex < passes_.Size() ? passes_[passIndex].Get() : 0; }
+    /// Return a pass by name, or null if not found. This overload should not be called in time-critical rendering loops; use a pre-acquired pass index instead.
+    Pass* GetPass(const String& passName) const;
     
     
     /// Return a pass that is supported for rendering, or null if not found.
     /// Return a pass that is supported for rendering, or null if not found.
-    Pass* GetSupportedPass(StringHash type) const
+    Pass* GetSupportedPass(unsigned passIndex) const
     {
     {
-        SharedPtr<Pass>* passPtr = passes_.Find(type.Value());
-        Pass* pass = passPtr ? passPtr->Get() : 0;
-        return pass && (!pass->IsSM3() || sm3Support_) && (!pass->IsDesktop() || desktopSupport_) ? pass : 0;
+        Pass* pass = passIndex < passes_.Size() ? passes_[passIndex].Get() : 0;
+        return pass && (!pass->IsDesktop() || desktopSupport_) ? pass : 0;
     }
     }
+
+    /// Return a supported pass by name. This overload should not be called in time-critical rendering loops; use a pre-acquired pass index instead.
+    Pass* GetSupportedPass(const String& passName) const;
     
     
     /// Return number of passes.
     /// Return number of passes.
-    unsigned GetNumPasses() const { return numPasses_; }
-    /// Return all the pass types in the hash table. The returned collection is not guaranteed to be in the same order as the hash table insertion order.
-    Vector<StringHash> GetPassTypes() const;
-    /// Return all the passes in the hash table. The returned collection is not guaranteed to be in the same order as the hash table insertion order.
+    unsigned GetNumPasses() const;
+    /// Return all pass names.
+    Vector<String> GetPassNames() const;
+    /// Return all passes.
     PODVector<Pass*> GetPasses() const;
     PODVector<Pass*> GetPasses() const;
 
 
+    /// Return a pass type index by name. Allocate new if not used yet.
+    static unsigned GetPassIndex(const String& passName);
+
+    /// Index for base pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned basePassIndex;
+    /// Index for alpha pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned alphaPassIndex;
+    /// Index for prepass material pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned materialPassIndex;
+    /// Index for deferred G-buffer pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned deferredPassIndex;
+    /// Index for per-pixel light pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned lightPassIndex;
+    /// Index for lit base pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned litBasePassIndex;
+    /// Index for lit alpha pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned litAlphaPassIndex;
+    /// Index for shadow pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned shadowPassIndex;
+
 private:
 private:
-    /// Require %Shader %Model 3 flag.
-    bool isSM3_;
-    /// Cached %Shader %Model 3 support flag.
-    bool sm3Support_;
     /// Require desktop GPU flag.
     /// Require desktop GPU flag.
     bool isDesktop_;
     bool isDesktop_;
     /// Cached desktop GPU support flag.
     /// Cached desktop GPU support flag.
     bool desktopSupport_;
     bool desktopSupport_;
     /// Passes.
     /// Passes.
-    HashTable<SharedPtr<Pass>, 16> passes_;
-    /// Number of passes.
-    unsigned numPasses_;
+    Vector<SharedPtr<Pass> > passes_;
+
+    /// Pass index assignments.
+    static HashMap<String, unsigned> passIndices;
 };
 };
 
 
 }
 }

+ 4 - 2
Source/Atomic/Graphics/Texture.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLTexture.h"
 #include "OpenGL/OGLTexture.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11Texture.h"
 #else
 #else
 #include "Direct3D9/D3D9Texture.h"
 #include "Direct3D9/D3D9Texture.h"
 #endif
 #endif

+ 4 - 2
Source/Atomic/Graphics/Texture2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLTexture2D.h"
 #include "OpenGL/OGLTexture2D.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11Texture2D.h"
 #else
 #else
 #include "Direct3D9/D3D9Texture2D.h"
 #include "Direct3D9/D3D9Texture2D.h"
 #endif
 #endif

+ 4 - 2
Source/Atomic/Graphics/Texture3D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLTexture3D.h"
 #include "OpenGL/OGLTexture3D.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11Texture3D.h"
 #else
 #else
 #include "Direct3D9/D3D9Texture3D.h"
 #include "Direct3D9/D3D9Texture3D.h"
 #endif
 #endif

+ 4 - 2
Source/Atomic/Graphics/TextureCube.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLTextureCube.h"
 #include "OpenGL/OGLTextureCube.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11TextureCube.h"
 #else
 #else
 #include "Direct3D9/D3D9TextureCube.h"
 #include "Direct3D9/D3D9TextureCube.h"
 #endif
 #endif

+ 4 - 2
Source/Atomic/Graphics/VertexBuffer.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifdef ATOMIC_OPENGL
+#if defined(ATOMIC_OPENGL)
 #include "OpenGL/OGLVertexBuffer.h"
 #include "OpenGL/OGLVertexBuffer.h"
+#elif defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11VertexBuffer.h"
 #else
 #else
 #include "Direct3D9/D3D9VertexBuffer.h"
 #include "Direct3D9/D3D9VertexBuffer.h"
 #endif
 #endif

+ 4 - 2
Source/Atomic/Graphics/VertexDeclaration.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -22,6 +22,8 @@
 
 
 #pragma once
 #pragma once
 
 
-#ifndef ATOMIC_OPENGL
+#if defined(ATOMIC_D3D11)
+#include "Direct3D11/D3D11VertexDeclaration.h"
+#else
 #include "Direct3D9/D3D9VertexDeclaration.h"
 #include "Direct3D9/D3D9VertexDeclaration.h"
 #endif
 #endif

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 252 - 302
Source/Atomic/Graphics/View.cpp


+ 35 - 23
Source/Atomic/Graphics/View.h

@@ -44,6 +44,7 @@ class Renderer;
 class RenderPath;
 class RenderPath;
 class RenderSurface;
 class RenderSurface;
 class Technique;
 class Technique;
+class Texture;
 class Texture2D;
 class Texture2D;
 class Viewport;
 class Viewport;
 class Zone;
 class Zone;
@@ -65,7 +66,7 @@ struct LightQueryResult
     unsigned shadowCasterBegin_[MAX_LIGHT_SPLITS];
     unsigned shadowCasterBegin_[MAX_LIGHT_SPLITS];
     /// Shadow caster end indices.
     /// Shadow caster end indices.
     unsigned shadowCasterEnd_[MAX_LIGHT_SPLITS];
     unsigned shadowCasterEnd_[MAX_LIGHT_SPLITS];
-    /// Combined bounding box of shadow casters in light view or projection space.
+    /// Combined bounding box of shadow casters in light projection space. Only used for focused spot lights.
     BoundingBox shadowCasterBox_[MAX_LIGHT_SPLITS];
     BoundingBox shadowCasterBox_[MAX_LIGHT_SPLITS];
     /// Shadow camera near splits (directional lights only.)
     /// Shadow camera near splits (directional lights only.)
     float shadowNearSplits_[MAX_LIGHT_SPLITS];
     float shadowNearSplits_[MAX_LIGHT_SPLITS];
@@ -78,8 +79,8 @@ struct LightQueryResult
 /// Scene render pass info.
 /// Scene render pass info.
 struct ScenePassInfo
 struct ScenePassInfo
 {
 {
-    /// Pass name hash.
-    StringHash pass_;
+    /// Pass index.
+    unsigned passIndex_;
     /// Allow instancing flag.
     /// Allow instancing flag.
     bool allowInstancing_;
     bool allowInstancing_;
     /// Mark to stencil flag.
     /// Mark to stencil flag.
@@ -164,6 +165,12 @@ private:
     void GetDrawables();
     void GetDrawables();
     /// Construct batches from the drawable objects.
     /// Construct batches from the drawable objects.
     void GetBatches();
     void GetBatches();
+    /// Get lit geometries and shadowcasters for visible lights.
+    void ProcessLights();
+    /// Get batches from lit geometries and shadowcasters.
+    void GetLightBatches();
+    /// Get unlit batches.
+    void GetBaseBatches();
     /// Update geometries and sort batches.
     /// Update geometries and sort batches.
     void UpdateGeometries();
     void UpdateGeometries();
     /// Get pixel lit batches for a certain light and drawable.
     /// Get pixel lit batches for a certain light and drawable.
@@ -187,7 +194,7 @@ private:
     /// Allocate needed screen buffers.
     /// Allocate needed screen buffers.
     void AllocateScreenBuffers();
     void AllocateScreenBuffers();
     /// Blit the viewport from one surface to another.
     /// Blit the viewport from one surface to another.
-    void BlitFramebuffer(Texture2D* source, RenderSurface* destination, bool depthWrite);
+    void BlitFramebuffer(Texture* source, RenderSurface* destination, bool depthWrite);
     /// Draw a fullscreen quad. Shaders and renderstates must have been set beforehand.
     /// Draw a fullscreen quad. Shaders and renderstates must have been set beforehand.
     void DrawFullscreenQuad(bool nearQuad);
     void DrawFullscreenQuad(bool nearQuad);
     /// Query for occluders as seen from a camera.
     /// Query for occluders as seen from a camera.
@@ -226,7 +233,11 @@ private:
     void RenderShadowMap(const LightBatchQueue& queue);
     void RenderShadowMap(const LightBatchQueue& queue);
     /// Return the proper depth-stencil surface to use for a rendertarget.
     /// Return the proper depth-stencil surface to use for a rendertarget.
     RenderSurface* GetDepthStencil(RenderSurface* renderTarget);
     RenderSurface* GetDepthStencil(RenderSurface* renderTarget);
-    
+    /// Helper function to get the render surface from a texture. 2D textures will always return the first face only.
+    RenderSurface* GetRenderSurfaceFromTexture(Texture* texture, CubeMapFace face = FACE_POSITIVE_X);
+    /// Get a named texture from the rendertarget list or from the resource cache, to be either used as a rendertarget or texture binding.
+    Texture* FindNamedTexture(const String& name, bool isRenderTarget, bool isVolumeMap = false);
+
     /// Return the drawable's zone, or camera zone if it has override mode enabled.
     /// Return the drawable's zone, or camera zone if it has override mode enabled.
     Zone* GetZone(Drawable* drawable)
     Zone* GetZone(Drawable* drawable)
     {
     {
@@ -280,13 +291,13 @@ private:
     /// Substitute rendertarget for deferred rendering. Allocated if necessary.
     /// Substitute rendertarget for deferred rendering. Allocated if necessary.
     RenderSurface* substituteRenderTarget_;
     RenderSurface* substituteRenderTarget_;
     /// Texture(s) for sampling the viewport contents. Allocated if necessary.
     /// Texture(s) for sampling the viewport contents. Allocated if necessary.
-    Texture2D* viewportTextures_[MAX_VIEWPORT_TEXTURES];
+    Texture* viewportTextures_[MAX_VIEWPORT_TEXTURES];
     /// Color rendertarget active for the current renderpath command.
     /// Color rendertarget active for the current renderpath command.
     RenderSurface* currentRenderTarget_;
     RenderSurface* currentRenderTarget_;
     /// Texture containing the latest viewport texture.
     /// Texture containing the latest viewport texture.
-    Texture2D* currentViewportTexture_;
+    Texture* currentViewportTexture_;
     /// Dummy texture for D3D9 depth only rendering.
     /// Dummy texture for D3D9 depth only rendering.
-    Texture2D* depthOnlyDummyTexture_;
+    Texture* depthOnlyDummyTexture_;
     /// Viewport rectangle.
     /// Viewport rectangle.
     IntRect viewRect_;
     IntRect viewRect_;
     /// Viewport size.
     /// Viewport size.
@@ -341,10 +352,11 @@ private:
     PODVector<Drawable*> occluders_;
     PODVector<Drawable*> occluders_;
     /// Lights.
     /// Lights.
     PODVector<Light*> lights_;
     PODVector<Light*> lights_;
+    
     /// Drawables that limit their maximum light count.
     /// Drawables that limit their maximum light count.
     HashSet<Drawable*> maxLightsDrawables_;
     HashSet<Drawable*> maxLightsDrawables_;
     /// Rendertargets defined by the renderpath.
     /// Rendertargets defined by the renderpath.
-    HashMap<StringHash, Texture2D*> renderTargets_;
+    HashMap<StringHash, Texture*> renderTargets_;
     /// Intermediate light processing results.
     /// Intermediate light processing results.
     Vector<LightQueryResult> lightQueryResults_;
     Vector<LightQueryResult> lightQueryResults_;
     /// Info for scene render passes defined by the renderpath.
     /// Info for scene render passes defined by the renderpath.
@@ -353,20 +365,20 @@ private:
     Vector<LightBatchQueue> lightQueues_;
     Vector<LightBatchQueue> lightQueues_;
     /// Per-vertex light queues.
     /// Per-vertex light queues.
     HashMap<unsigned long long, LightBatchQueue> vertexLightQueues_;
     HashMap<unsigned long long, LightBatchQueue> vertexLightQueues_;
-    /// Batch queues.
-    HashMap<StringHash, BatchQueue> batchQueues_;
-    /// Hash of the GBuffer pass, or null if none.
-    StringHash gBufferPassName_;
-    /// Hash of the opaque forward base pass.
-    StringHash basePassName_;
-    /// Hash of the alpha pass.
-    StringHash alphaPassName_;
-    /// Hash of the forward light pass.
-    StringHash lightPassName_;
-    /// Hash of the litbase pass.
-    StringHash litBasePassName_;
-    /// Hash of the litalpha pass.
-    StringHash litAlphaPassName_;
+    /// Batch queues by pass index.
+    HashMap<unsigned, BatchQueue> batchQueues_;
+    /// Index of the GBuffer pass.
+    unsigned gBufferPassIndex_;
+    /// Index of the opaque forward base pass.
+    unsigned basePassIndex_;
+    /// Index of the alpha pass.
+    unsigned alphaPassIndex_;
+    /// Index of the forward light pass.
+    unsigned lightPassIndex_;
+    /// Index of the litbase pass.
+    unsigned litBasePassIndex_;
+    /// Index of the litalpha pass.
+    unsigned litAlphaPassIndex_;
     /// Pointer to the light volume command if any.
     /// Pointer to the light volume command if any.
     const RenderPathCommand* lightVolumeCommand_;
     const RenderPathCommand* lightVolumeCommand_;
 };
 };

+ 1 - 2
Source/Atomic/Input/Input.cpp

@@ -20,6 +20,7 @@
 // THE SOFTWARE.
 // THE SOFTWARE.
 //
 //
 
 
+#include "Precompiled.h"
 #include "../Core/Context.h"
 #include "../Core/Context.h"
 #include "../Core/CoreEvents.h"
 #include "../Core/CoreEvents.h"
 #include "../IO/FileSystem.h"
 #include "../IO/FileSystem.h"
@@ -1988,8 +1989,6 @@ void Input::HandleScreenMode(StringHash eventType, VariantMap& eventData)
     else
     else
         lastMousePosition_ = GetMousePosition();
         lastMousePosition_ = GetMousePosition();
 
 
-    }
-
     if (graphics_->GetFullscreen())
     if (graphics_->GetFullscreen())
         focusedThisFrame_ = true;
         focusedThisFrame_ = true;
 
 

+ 5 - 5
Source/Atomic/Navigation/CrowdAgent.cpp

@@ -34,12 +34,12 @@
 #include "../Scene/Serializable.h"
 #include "../Scene/Serializable.h"
 #include "../Core/Variant.h"
 #include "../Core/Variant.h"
 
 
-#include <Detour/DetourCommon.h>
-#include <DetourCrowd/DetourCrowd.h>
+#include <Detour/include/DetourCommon.h>
+#include <DetourCrowd/include/DetourCrowd.h>
 
 
 #include "../DebugNew.h"
 #include "../DebugNew.h"
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 extern const char* NAVIGATION_CATEGORY;
 extern const char* NAVIGATION_CATEGORY;
@@ -352,7 +352,7 @@ Vector3 CrowdAgent::GetActualVelocity() const
     return Vector3::ZERO;
     return Vector3::ZERO;
 }
 }
 
 
-Urho3D::CrowdAgentState CrowdAgent::GetAgentState() const
+Atomic::CrowdAgentState CrowdAgent::GetAgentState() const
 {
 {
     if (crowdManager_ && inCrowd_)
     if (crowdManager_ && inCrowd_)
     {
     {
@@ -364,7 +364,7 @@ Urho3D::CrowdAgentState CrowdAgent::GetAgentState() const
     return CROWD_AGENT_INVALID;
     return CROWD_AGENT_INVALID;
 }
 }
 
 
-Urho3D::CrowdTargetState CrowdAgent::GetTargetState() const
+Atomic::CrowdTargetState CrowdAgent::GetTargetState() const
 {
 {
     if (crowdManager_ && inCrowd_)
     if (crowdManager_ && inCrowd_)
     {
     {

+ 2 - 2
Source/Atomic/Navigation/CrowdAgent.h

@@ -25,7 +25,7 @@
 #include "../Scene/Component.h"
 #include "../Scene/Component.h"
 #include "../Navigation/DetourCrowdManager.h"
 #include "../Navigation/DetourCrowdManager.h"
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 enum CrowdTargetState
 enum CrowdTargetState
@@ -48,7 +48,7 @@ enum CrowdAgentState
 };
 };
 
 
 /// DetourCrowd Agent, requires a DetourCrowdManager in the scene. Agent's radius and height is set through the navigation mesh.
 /// DetourCrowd Agent, requires a DetourCrowdManager in the scene. Agent's radius and height is set through the navigation mesh.
-class URHO3D_API CrowdAgent : public Component
+class ATOMIC_API CrowdAgent : public Component
 {
 {
     OBJECT(CrowdAgent);
     OBJECT(CrowdAgent);
     friend class DetourCrowdManager;
     friend class DetourCrowdManager;

+ 3 - 3
Source/Atomic/Navigation/DetourCrowdManager.cpp

@@ -39,12 +39,12 @@
 #include "../Physics/PhysicsEvents.h"
 #include "../Physics/PhysicsEvents.h"
 #endif
 #endif
 
 
-#include <DetourCrowd/DetourCrowd.h>
-#include <Recast/Recast.h>
+#include <DetourCrowd/include/DetourCrowd.h>
+#include <Recast/include/Recast.h>
 
 
 #include "../DebugNew.h"
 #include "../DebugNew.h"
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
     
     
 extern const char* NAVIGATION_CATEGORY;
 extern const char* NAVIGATION_CATEGORY;

+ 2 - 2
Source/Atomic/Navigation/DetourCrowdManager.h

@@ -28,7 +28,7 @@ class dtCrowd;
 struct dtCrowdAgent;
 struct dtCrowdAgent;
 struct dtCrowdAgentDebugInfo;
 struct dtCrowdAgentDebugInfo;
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 class CrowdAgent;
 class CrowdAgent;
@@ -50,7 +50,7 @@ enum NavigationPushiness
 
 
 
 
 /// Detour Crowd Simulation Scene Component. Should be added only to the root scene node. Agent's radius and height is set through the navigation mesh. \todo support multiple agent's radii and heights.
 /// Detour Crowd Simulation Scene Component. Should be added only to the root scene node. Agent's radius and height is set through the navigation mesh. \todo support multiple agent's radii and heights.
-class URHO3D_API DetourCrowdManager : public Component
+class ATOMIC_API DetourCrowdManager : public Component
 {
 {
     OBJECT(DetourCrowdManager);
     OBJECT(DetourCrowdManager);
     friend class CrowdAgent;
     friend class CrowdAgent;

+ 8 - 8
Source/Atomic/Navigation/DynamicNavigationMesh.cpp

@@ -38,20 +38,20 @@
 
 
 #include <LZ4/lz4.h>
 #include <LZ4/lz4.h>
 #include <cfloat>
 #include <cfloat>
-#include <Detour/DetourNavMesh.h>
-#include <Detour/DetourNavMeshBuilder.h>
-#include <Detour/DetourNavMeshQuery.h>
-#include <DetourTileCache/DetourTileCache.h>
-#include <DetourTileCache/DetourTileCacheBuilder.h>
-#include <Recast/Recast.h>
-#include <Recast/RecastAlloc.h>
+#include <Detour/include/DetourNavMesh.h>
+#include <Detour/include/DetourNavMeshBuilder.h>
+#include <Detour/include/DetourNavMeshQuery.h>
+#include <DetourTileCache/include/DetourTileCache.h>
+#include <DetourTileCache/include/DetourTileCacheBuilder.h>
+#include <Recast/include/Recast.h>
+#include <Recast/include/RecastAlloc.h>
 
 
 //DebugNew is deliberately not used because the macro 'free' conflicts DetourTileCache's LinearAllocator interface
 //DebugNew is deliberately not used because the macro 'free' conflicts DetourTileCache's LinearAllocator interface
 //#include "../DebugNew.h"
 //#include "../DebugNew.h"
 
 
 #define TILECACHE_MAXLAYERS 128
 #define TILECACHE_MAXLAYERS 128
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
     
     
 extern const char* NAVIGATION_CATEGORY;
 extern const char* NAVIGATION_CATEGORY;

+ 2 - 2
Source/Atomic/Navigation/DynamicNavigationMesh.h

@@ -32,13 +32,13 @@ struct dtTileCacheLayer;
 struct dtTileCacheContourSet;
 struct dtTileCacheContourSet;
 struct dtTileCachePolyMesh;
 struct dtTileCachePolyMesh;
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 class OffMeshConnection;
 class OffMeshConnection;
 class Obstacle;
 class Obstacle;
 
 
-class URHO3D_API DynamicNavigationMesh : public NavigationMesh
+class ATOMIC_API DynamicNavigationMesh : public NavigationMesh
 {
 {
     OBJECT(DynamicNavigationMesh)
     OBJECT(DynamicNavigationMesh)
     friend class Obstacle;
     friend class Obstacle;

+ 1 - 1
Source/Atomic/Navigation/NavArea.cpp

@@ -28,7 +28,7 @@
 #include "../Scene/Node.h"
 #include "../Scene/Node.h"
 #include "../Container/Str.h"
 #include "../Container/Str.h"
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
     static const unsigned MAX_NAV_AREA_ID = 255;
     static const unsigned MAX_NAV_AREA_ID = 255;
     static const Vector3 DEFAULT_BOUNDING_BOX_MIN(-10.0f, -10.0f, -10.0f);
     static const Vector3 DEFAULT_BOUNDING_BOX_MIN(-10.0f, -10.0f, -10.0f);

+ 2 - 2
Source/Atomic/Navigation/NavArea.h

@@ -25,9 +25,9 @@
 #include "../Scene/Component.h"
 #include "../Scene/Component.h"
 #include "../Math/BoundingBox.h"
 #include "../Math/BoundingBox.h"
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
-    class URHO3D_API NavArea : public Component
+    class ATOMIC_API NavArea : public Component
     {
     {
         OBJECT(NavArea);
         OBJECT(NavArea);
 
 

+ 7 - 7
Source/Atomic/Navigation/NavBuildData.cpp

@@ -22,14 +22,14 @@
 
 
 #include "../Navigation/NavBuildData.h"
 #include "../Navigation/NavBuildData.h"
 
 
-#include <Recast/Recast.h>
-#include <Detour/DetourNavMesh.h>
-#include <Detour/DetourNavMeshBuilder.h>
-#include <Detour/DetourNavMeshQuery.h>
-#include <DetourTileCache/DetourTileCache.h>
-#include <DetourTileCache/DetourTileCacheBuilder.h>
+#include <Recast/include/Recast.h>
+#include <Detour/include/DetourNavMesh.h>
+#include <Detour/include/DetourNavMeshBuilder.h>
+#include <Detour/include/DetourNavMeshQuery.h>
+#include <DetourTileCache/include/DetourTileCache.h>
+#include <DetourTileCache/include/DetourTileCacheBuilder.h>
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 NavBuildData::NavBuildData() :
 NavBuildData::NavBuildData() :

+ 3 - 3
Source/Atomic/Navigation/NavBuildData.h

@@ -38,11 +38,11 @@ struct dtTileCacheContourSet;
 struct dtTileCachePolyMesh;
 struct dtTileCachePolyMesh;
 struct dtTileCacheAlloc;
 struct dtTileCacheAlloc;
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 /// Navigation area stub.
 /// Navigation area stub.
-struct URHO3D_API NavAreaStub
+struct ATOMIC_API NavAreaStub
 {
 {
     /// Area bounding box.
     /// Area bounding box.
     BoundingBox bounds_;
     BoundingBox bounds_;
@@ -51,7 +51,7 @@ struct URHO3D_API NavAreaStub
 };
 };
 
 
 /// Navigation build data.
 /// Navigation build data.
-struct URHO3D_API NavBuildData
+struct ATOMIC_API NavBuildData
 {
 {
     /// Constructor.
     /// Constructor.
     NavBuildData();
     NavBuildData();

+ 1 - 1
Source/Atomic/Navigation/NavigationEvents.h

@@ -24,7 +24,7 @@
 
 
 #include "../Core/Object.h"
 #include "../Core/Object.h"
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 /// Complete rebuild of navigation mesh.
 /// Complete rebuild of navigation mesh.

+ 1 - 0
Source/Atomic/Navigation/NavigationMesh.h

@@ -68,6 +68,7 @@ struct NavigationGeometryInfo
 };
 };
 
 
 /// Navigation mesh component. Collects the navigation geometry from child nodes with the Navigable component and responds to path queries.
 /// Navigation mesh component. Collects the navigation geometry from child nodes with the Navigable component and responds to path queries.
+class ATOMIC_API NavigationMesh : public Component
 {
 {
     OBJECT(NavigationMesh);
     OBJECT(NavigationMesh);
     friend class DetourCrowdManager;
     friend class DetourCrowdManager;

+ 1 - 1
Source/Atomic/Navigation/Obstacle.cpp

@@ -31,7 +31,7 @@
 
 
 #include "../DebugNew.h"
 #include "../DebugNew.h"
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 extern const char* NAVIGATION_CATEGORY;
 extern const char* NAVIGATION_CATEGORY;

+ 2 - 2
Source/Atomic/Navigation/Obstacle.h

@@ -25,13 +25,13 @@
 #include "../Container/Ptr.h"
 #include "../Container/Ptr.h"
 #include "../Scene/Component.h"
 #include "../Scene/Component.h"
 
 
-namespace Urho3D
+namespace Atomic
 {
 {
 
 
 class DynamicNavigationMesh;
 class DynamicNavigationMesh;
 
 
 /// Obstacle for dynamic navigation mesh.
 /// Obstacle for dynamic navigation mesh.
-class URHO3D_API Obstacle : public Component
+class ATOMIC_API Obstacle : public Component
 {
 {
     OBJECT(Obstacle)
     OBJECT(Obstacle)
     friend class DynamicNavigationMesh;
     friend class DynamicNavigationMesh;

+ 54 - 37
Source/Atomic/Network/Connection.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -62,6 +62,7 @@ PackageUpload::PackageUpload() :
 
 
 Connection::Connection(Context* context, bool isClient, kNet::SharedPtr<kNet::MessageConnection> connection) :
 Connection::Connection(Context* context, bool isClient, kNet::SharedPtr<kNet::MessageConnection> connection) :
     Object(context),
     Object(context),
+    timeStamp_(0),
     connection_(connection),
     connection_(connection),
     sendMode_(OPSM_NONE),
     sendMode_(OPSM_NONE),
     isClient_(isClient),
     isClient_(isClient),
@@ -272,11 +273,14 @@ void Connection::SendClientUpdate()
     msg_.WriteFloat(controls_.yaw_);
     msg_.WriteFloat(controls_.yaw_);
     msg_.WriteFloat(controls_.pitch_);
     msg_.WriteFloat(controls_.pitch_);
     msg_.WriteVariantMap(controls_.extraData_);
     msg_.WriteVariantMap(controls_.extraData_);
+    msg_.WriteUByte(timeStamp_);
     if (sendMode_ >= OPSM_POSITION)
     if (sendMode_ >= OPSM_POSITION)
         msg_.WriteVector3(position_);
         msg_.WriteVector3(position_);
     if (sendMode_ >= OPSM_POSITION_ROTATION)
     if (sendMode_ >= OPSM_POSITION_ROTATION)
         msg_.WritePackedQuaternion(rotation_);
         msg_.WritePackedQuaternion(rotation_);
     SendMessage(MSG_CONTROLS, false, false, msg_, CONTROLS_CONTENT_ID);
     SendMessage(MSG_CONTROLS, false, false, msg_, CONTROLS_CONTENT_ID);
+
+    ++timeStamp_;
 }
 }
 
 
 void Connection::SendRemoteEvents()
 void Connection::SendRemoteEvents()
@@ -374,8 +378,8 @@ void Connection::ProcessPendingLatestData()
         {
         {
             MemoryBuffer msg(current->second_);
             MemoryBuffer msg(current->second_);
             msg.ReadNetID(); // Skip the component ID
             msg.ReadNetID(); // Skip the component ID
-            component->ReadLatestDataUpdate(msg);
-            component->ApplyAttributes();
+            if (component->ReadLatestDataUpdate(msg))
+                component->ApplyAttributes();
             componentLatestData_.Erase(current);
             componentLatestData_.Erase(current);
         }
         }
     }
     }
@@ -681,8 +685,8 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
             Component* component = scene_->GetComponent(componentID);
             Component* component = scene_->GetComponent(componentID);
             if (component)
             if (component)
             {
             {
-                component->ReadLatestDataUpdate(msg);
-                component->ApplyAttributes();
+                if (component->ReadLatestDataUpdate(msg))
+                    component->ApplyAttributes();
             }
             }
             else
             else
             {
             {
@@ -880,6 +884,8 @@ void Connection::ProcessControls(int msgID, MemoryBuffer& msg)
     newControls.extraData_ = msg.ReadVariantMap();
     newControls.extraData_ = msg.ReadVariantMap();
     
     
     SetControls(newControls);
     SetControls(newControls);
+    timeStamp_ = msg.ReadUByte();
+
     // Client may or may not send observer position & rotation for interest management
     // Client may or may not send observer position & rotation for interest management
     if (!msg.IsEof())
     if (!msg.IsEof())
         position_ = msg.ReadVector3();
         position_ = msg.ReadVector3();
@@ -1012,6 +1018,42 @@ float Connection::GetDownloadProgress() const
     return 1.0f;
     return 1.0f;
 }
 }
 
 
+void Connection::SendPackageToClient(PackageFile* package)
+{
+    if (!scene_)
+        return;
+
+    if (!IsClient())
+    {
+        LOGERROR("SendPackageToClient can be called on the server only");
+        return;
+    }
+    if (!package)
+    {
+        LOGERROR("Null package specified for SendPackageToClient");
+        return;
+    }
+
+    msg_.Clear();
+
+    String filename = GetFileNameAndExtension(package->GetName());
+    msg_.WriteString(filename);
+    msg_.WriteUInt(package->GetTotalSize());
+    msg_.WriteUInt(package->GetChecksum());
+    SendMessage(MSG_PACKAGEINFO, true, true, msg_);
+}
+
+void Connection::ConfigureNetworkSimulator(int latencyMs, float packetLoss)
+{
+    if (connection_)
+    {
+        kNet::NetworkSimulator& simulator = connection_->NetworkSendSimulator();
+        simulator.enabled = latencyMs > 0 || packetLoss > 0.0f;
+        simulator.constantPacketSendDelay = (float)latencyMs;
+        simulator.packetLossRate = packetLoss;
+    }
+}
+
 void Connection::HandleAsyncLoadFinished(StringHash eventType, VariantMap& eventData)
 void Connection::HandleAsyncLoadFinished(StringHash eventType, VariantMap& eventData)
 {
 {
     sceneLoaded_ = true;
     sceneLoaded_ = true;
@@ -1082,7 +1124,7 @@ void Connection::ProcessNewNode(Node* node)
     node->AddReplicationState(&nodeState);
     node->AddReplicationState(&nodeState);
     
     
     // Write node's attributes
     // Write node's attributes
-    node->WriteInitialDeltaUpdate(msg_);
+    node->WriteInitialDeltaUpdate(msg_, timeStamp_);
     
     
     // Write node's user variables
     // Write node's user variables
     const VariantMap& vars = node->GetVars();
     const VariantMap& vars = node->GetVars();
@@ -1111,7 +1153,7 @@ void Connection::ProcessNewNode(Node* node)
         
         
         msg_.WriteStringHash(component->GetType());
         msg_.WriteStringHash(component->GetType());
         msg_.WriteNetID(component->GetID());
         msg_.WriteNetID(component->GetID());
-        component->WriteInitialDeltaUpdate(msg_);
+        component->WriteInitialDeltaUpdate(msg_, timeStamp_);
     }
     }
     
     
     SendMessage(MSG_CREATENODE, true, true, msg_);
     SendMessage(MSG_CREATENODE, true, true, msg_);
@@ -1162,7 +1204,7 @@ void Connection::ProcessExistingNode(Node* node, NodeReplicationState& nodeState
         {
         {
             msg_.Clear();
             msg_.Clear();
             msg_.WriteNetID(node->GetID());
             msg_.WriteNetID(node->GetID());
-            node->WriteLatestDataUpdate(msg_);
+            node->WriteLatestDataUpdate(msg_, timeStamp_);
             
             
             SendMessage(MSG_NODELATESTDATA, true, false, msg_, node->GetID());
             SendMessage(MSG_NODELATESTDATA, true, false, msg_, node->GetID());
         }
         }
@@ -1172,7 +1214,7 @@ void Connection::ProcessExistingNode(Node* node, NodeReplicationState& nodeState
         {
         {
             msg_.Clear();
             msg_.Clear();
             msg_.WriteNetID(node->GetID());
             msg_.WriteNetID(node->GetID());
-            node->WriteDeltaUpdate(msg_, nodeState.dirtyAttributes_);
+            node->WriteDeltaUpdate(msg_, nodeState.dirtyAttributes_, timeStamp_);
             
             
             // Write changed variables
             // Write changed variables
             msg_.WriteVLE(nodeState.dirtyVars_.Size());
             msg_.WriteVLE(nodeState.dirtyVars_.Size());
@@ -1240,7 +1282,7 @@ void Connection::ProcessExistingNode(Node* node, NodeReplicationState& nodeState
                 {
                 {
                     msg_.Clear();
                     msg_.Clear();
                     msg_.WriteNetID(component->GetID());
                     msg_.WriteNetID(component->GetID());
-                    component->WriteLatestDataUpdate(msg_);
+                    component->WriteLatestDataUpdate(msg_, timeStamp_);
                     
                     
                     SendMessage(MSG_COMPONENTLATESTDATA, true, false, msg_, component->GetID());
                     SendMessage(MSG_COMPONENTLATESTDATA, true, false, msg_, component->GetID());
                 }
                 }
@@ -1250,7 +1292,7 @@ void Connection::ProcessExistingNode(Node* node, NodeReplicationState& nodeState
                 {
                 {
                     msg_.Clear();
                     msg_.Clear();
                     msg_.WriteNetID(component->GetID());
                     msg_.WriteNetID(component->GetID());
-                    component->WriteDeltaUpdate(msg_, componentState.dirtyAttributes_);
+                    component->WriteDeltaUpdate(msg_, componentState.dirtyAttributes_, timeStamp_);
                     
                     
                     SendMessage(MSG_COMPONENTDELTAUPDATE, true, true, msg_);
                     SendMessage(MSG_COMPONENTDELTAUPDATE, true, true, msg_);
                     
                     
@@ -1285,7 +1327,7 @@ void Connection::ProcessExistingNode(Node* node, NodeReplicationState& nodeState
                 msg_.WriteNetID(node->GetID());
                 msg_.WriteNetID(node->GetID());
                 msg_.WriteStringHash(component->GetType());
                 msg_.WriteStringHash(component->GetType());
                 msg_.WriteNetID(component->GetID());
                 msg_.WriteNetID(component->GetID());
-                component->WriteInitialDeltaUpdate(msg_);
+                component->WriteInitialDeltaUpdate(msg_, timeStamp_);
                 
                 
                 SendMessage(MSG_CREATECOMPONENT, true, true, msg_);
                 SendMessage(MSG_CREATECOMPONENT, true, true, msg_);
             }
             }
@@ -1452,31 +1494,6 @@ void Connection::OnPackagesReady()
     }
     }
 }
 }
 
 
-void Connection::SendPackageToClient(PackageFile* package)
-{
-    if (!scene_)
-        return;
-
-    if (!IsClient())
-    {
-        LOGERROR("SendPackageToClient can be called on the server only");
-        return;
-    }
-    if (!package)
-    {
-        LOGERROR("Null package specified for SendPackageToClient");
-        return;
-    }
-    
-    msg_.Clear();
-
-    String filename = GetFileNameAndExtension(package->GetName());
-    msg_.WriteString(filename);
-    msg_.WriteUInt(package->GetTotalSize());
-    msg_.WriteUInt(package->GetChecksum());
-    SendMessage(MSG_PACKAGEINFO, true, true, msg_);
-}
-
 void Connection::ProcessPackageInfo(int msgID, MemoryBuffer& msg)
 void Connection::ProcessPackageInfo(int msgID, MemoryBuffer& msg)
 {
 {
     if (!scene_)
     if (!scene_)

+ 7 - 0
Source/Atomic/Network/Connection.h

@@ -157,6 +157,8 @@ public:
     Scene* GetScene() const;
     Scene* GetScene() const;
     /// Return the client controls of this connection.
     /// Return the client controls of this connection.
     const Controls& GetControls() const { return controls_; }
     const Controls& GetControls() const { return controls_; }
+    /// Return the controls timestamp, sent from client to server along each control update.
+    unsigned char GetTimeStamp() const { return timeStamp_; }
     /// Return the observer position sent by the client for interest management.
     /// Return the observer position sent by the client for interest management.
     const Vector3& GetPosition() const { return position_; }
     const Vector3& GetPosition() const { return position_; }
     /// Return the observer rotation sent by the client for interest management.
     /// Return the observer rotation sent by the client for interest management.
@@ -186,8 +188,13 @@ public:
     /// Trigger client connection to download a package file from the server. Can be used to download additional resource packages when client is already joined in a scene. The package must have been added as a requirement to the scene the client is joined in, or else the eventual download will fail.
     /// Trigger client connection to download a package file from the server. Can be used to download additional resource packages when client is already joined in a scene. The package must have been added as a requirement to the scene the client is joined in, or else the eventual download will fail.
     void SendPackageToClient(PackageFile* package);
     void SendPackageToClient(PackageFile* package);
 
 
+    /// Set network simulation parameters. Called by Network.
+    void ConfigureNetworkSimulator(int latencyMs, float packetLoss);
+
     /// Current controls.
     /// Current controls.
     Controls controls_;
     Controls controls_;
+    /// Controls timestamp. Incremented after each sent update.
+    unsigned char timeStamp_;
     /// Identity map.
     /// Identity map.
     VariantMap identity_;
     VariantMap identity_;
     
     

+ 9 - 1
Source/Atomic/Scene/ReplicationState.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -124,6 +124,12 @@ struct ATOMIC_API DirtyBits
 /// Per-object attribute state for network replication, allocated on demand.
 /// Per-object attribute state for network replication, allocated on demand.
 struct ATOMIC_API NetworkState
 struct ATOMIC_API NetworkState
 {
 {
+    /// Construct with defaults.
+    NetworkState() :
+        interceptMask_(0)
+    {
+    }
+
     /// Cached network attribute infos.
     /// Cached network attribute infos.
     const Vector<AttributeInfo>* attributes_;
     const Vector<AttributeInfo>* attributes_;
     /// Current network attribute values.
     /// Current network attribute values.
@@ -134,6 +140,8 @@ struct ATOMIC_API NetworkState
     PODVector<ReplicationState*> replicationStates_;
     PODVector<ReplicationState*> replicationStates_;
     /// Previous user variables.
     /// Previous user variables.
     VariantMap previousVars_;
     VariantMap previousVars_;
+    /// Bitmask for intercepting network messages. Used on the client only.
+    unsigned long long interceptMask_;
 };
 };
 
 
 /// Base class for per-user network replication states.
 /// Base class for per-user network replication states.

+ 11 - 1
Source/Atomic/Scene/SceneEvents.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -170,4 +170,14 @@ EVENT(E_TEMPORARYCHANGED, TemporaryChanged)
     PARAM(P_SERIALIZABLE, Serializable);    // Serializable pointer
     PARAM(P_SERIALIZABLE, Serializable);    // Serializable pointer
 }
 }
 
 
+/// A network attribute update from the server has been intercepted.
+EVENT(E_INTERCEPTNETWORKUPDATE, InterceptNetworkUpdate)
+{
+    PARAM(P_SERIALIZABLE, Serializable);    // Serializable pointer
+    PARAM(P_TIMESTAMP, TimeStamp);          // unsigned (0-255)
+    PARAM(P_INDEX, Index);                  // unsigned
+    PARAM(P_NAME, Name);                    // String
+    PARAM(P_VALUE, Value);                  // Variant
+}
+
 }
 }

+ 117 - 10
Source/Atomic/Scene/Serializable.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -35,6 +35,24 @@
 namespace Atomic
 namespace Atomic
 {
 {
 
 
+static unsigned RemapAttributeIndex(const Vector<AttributeInfo>* attributes, const AttributeInfo& netAttr, unsigned netAttrIndex)
+{
+    if (!attributes)
+        return netAttrIndex; // Could not remap
+
+    for (unsigned i = 0; i < attributes->Size(); ++i)
+    {
+        const AttributeInfo& attr = attributes->At(i);
+        // Compare either the accessor or offset to avoid name string compare
+        if (attr.accessor_.Get() && attr.accessor_.Get() == netAttr.accessor_.Get())
+            return i;
+        else if (!attr.accessor_.Get() && attr.offset_ == netAttr.offset_)
+            return i;
+    }
+
+    return netAttrIndex; // Could not remap
+}
+
 Serializable::Serializable(Context* context) :
 Serializable::Serializable(Context* context) :
     Object(context),
     Object(context),
     networkState_(0),
     networkState_(0),
@@ -520,6 +538,28 @@ void Serializable::SetTemporary(bool enable)
     }
     }
 }
 }
 
 
+void Serializable::SetInterceptNetworkUpdate(const String& attributeName, bool enable)
+{
+    const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
+    if (!attributes)
+        return;
+
+    AllocateNetworkState();
+
+    for (unsigned i = 0; i < attributes->Size(); ++i)
+    {
+        const AttributeInfo& attr = attributes->At(i);
+        if (!attr.name_.Compare(attributeName, true))
+        {
+            if (enable)
+                networkState_->interceptMask_ |= 1ULL << i;
+            else
+                networkState_->interceptMask_ &= ~(1ULL << i);
+            break;
+        }
+    }
+}
+
 void Serializable::AllocateNetworkState()
 void Serializable::AllocateNetworkState()
 {
 {
     if (!networkState_)
     if (!networkState_)
@@ -530,7 +570,7 @@ void Serializable::AllocateNetworkState()
     }
     }
 }
 }
 
 
-void Serializable::WriteInitialDeltaUpdate(Serializer& dest)
+void Serializable::WriteInitialDeltaUpdate(Serializer& dest, unsigned char timeStamp)
 {
 {
     if (!networkState_)
     if (!networkState_)
     {
     {
@@ -554,6 +594,7 @@ void Serializable::WriteInitialDeltaUpdate(Serializer& dest)
     }
     }
 
 
     // First write the change bitfield, then attribute data for non-default attributes
     // First write the change bitfield, then attribute data for non-default attributes
+    dest.WriteUByte(timeStamp);
     dest.Write(attributeBits.data_, (numAttributes + 7) >> 3);
     dest.Write(attributeBits.data_, (numAttributes + 7) >> 3);
 
 
     for (unsigned i = 0; i < numAttributes; ++i)
     for (unsigned i = 0; i < numAttributes; ++i)
@@ -563,7 +604,7 @@ void Serializable::WriteInitialDeltaUpdate(Serializer& dest)
     }
     }
 }
 }
 
 
-void Serializable::WriteDeltaUpdate(Serializer& dest, const DirtyBits& attributeBits)
+void Serializable::WriteDeltaUpdate(Serializer& dest, const DirtyBits& attributeBits, unsigned char timeStamp)
 {
 {
     if (!networkState_)
     if (!networkState_)
     {
     {
@@ -579,6 +620,7 @@ void Serializable::WriteDeltaUpdate(Serializer& dest, const DirtyBits& attribute
 
 
     // First write the change bitfield, then attribute data for changed attributes
     // First write the change bitfield, then attribute data for changed attributes
     // Note: the attribute bits should not contain LATESTDATA attributes
     // Note: the attribute bits should not contain LATESTDATA attributes
+    dest.WriteUByte(timeStamp);
     dest.Write(attributeBits.data_, (numAttributes + 7) >> 3);
     dest.Write(attributeBits.data_, (numAttributes + 7) >> 3);
 
 
     for (unsigned i = 0; i < numAttributes; ++i)
     for (unsigned i = 0; i < numAttributes; ++i)
@@ -588,7 +630,7 @@ void Serializable::WriteDeltaUpdate(Serializer& dest, const DirtyBits& attribute
     }
     }
 }
 }
 
 
-void Serializable::WriteLatestDataUpdate(Serializer& dest)
+void Serializable::WriteLatestDataUpdate(Serializer& dest, unsigned char timeStamp)
 {
 {
     if (!networkState_)
     if (!networkState_)
     {
     {
@@ -602,6 +644,8 @@ void Serializable::WriteLatestDataUpdate(Serializer& dest)
 
 
     unsigned numAttributes = attributes->Size();
     unsigned numAttributes = attributes->Size();
 
 
+    dest.WriteUByte(timeStamp);
+
     for (unsigned i = 0; i < numAttributes; ++i)
     for (unsigned i = 0; i < numAttributes; ++i)
     {
     {
         if (attributes->At(i).mode_ & AM_LATESTDATA)
         if (attributes->At(i).mode_ & AM_LATESTDATA)
@@ -609,15 +653,18 @@ void Serializable::WriteLatestDataUpdate(Serializer& dest)
     }
     }
 }
 }
 
 
-void Serializable::ReadDeltaUpdate(Deserializer& source)
+bool Serializable::ReadDeltaUpdate(Deserializer& source)
 {
 {
     const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
     const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
     if (!attributes)
     if (!attributes)
-        return;
+        return false;
 
 
     unsigned numAttributes = attributes->Size();
     unsigned numAttributes = attributes->Size();
     DirtyBits attributeBits;
     DirtyBits attributeBits;
+    bool changed = false;
 
 
+    unsigned long long interceptMask = networkState_ ? networkState_->interceptMask_ : 0;
+    unsigned char timeStamp = source.ReadUByte();
     source.Read(attributeBits.data_, (numAttributes + 7) >> 3);
     source.Read(attributeBits.data_, (numAttributes + 7) >> 3);
 
 
     for (unsigned i = 0; i < numAttributes && !source.IsEof(); ++i)
     for (unsigned i = 0; i < numAttributes && !source.IsEof(); ++i)
@@ -625,25 +672,67 @@ void Serializable::ReadDeltaUpdate(Deserializer& source)
         if (attributeBits.IsSet(i))
         if (attributeBits.IsSet(i))
         {
         {
             const AttributeInfo& attr = attributes->At(i);
             const AttributeInfo& attr = attributes->At(i);
-            OnSetAttribute(attr, source.ReadVariant(attr.type_));
+            if (!(interceptMask & (1ULL << i)))
+            {
+                OnSetAttribute(attr, source.ReadVariant(attr.type_));
+                changed = true;
+            }
+            else
+            {
+                using namespace InterceptNetworkUpdate;
+
+                VariantMap& eventData = GetEventDataMap();
+                eventData[P_SERIALIZABLE] = this;
+                eventData[P_TIMESTAMP] = (unsigned)timeStamp;
+                eventData[P_INDEX] = RemapAttributeIndex(GetAttributes(), attr, i);
+                eventData[P_NAME] = attr.name_;
+                eventData[P_VALUE] = source.ReadVariant(attr.type_);
+                SendEvent(E_INTERCEPTNETWORKUPDATE, eventData);
+            }
         }
         }
     }
     }
+
+    return changed;
 }
 }
 
 
-void Serializable::ReadLatestDataUpdate(Deserializer& source)
+bool Serializable::ReadLatestDataUpdate(Deserializer& source)
 {
 {
     const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
     const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
     if (!attributes)
     if (!attributes)
-        return;
+        return false;
 
 
     unsigned numAttributes = attributes->Size();
     unsigned numAttributes = attributes->Size();
+    bool changed = false;
+
+    unsigned long long interceptMask = networkState_ ? networkState_->interceptMask_ : 0;
+    unsigned char timeStamp = source.ReadUByte();
 
 
     for (unsigned i = 0; i < numAttributes && !source.IsEof(); ++i)
     for (unsigned i = 0; i < numAttributes && !source.IsEof(); ++i)
     {
     {
         const AttributeInfo& attr = attributes->At(i);
         const AttributeInfo& attr = attributes->At(i);
         if (attr.mode_ & AM_LATESTDATA)
         if (attr.mode_ & AM_LATESTDATA)
-            OnSetAttribute(attr, source.ReadVariant(attr.type_));
+        {
+            if (!(interceptMask & (1ULL << i)))
+            {
+                OnSetAttribute(attr, source.ReadVariant(attr.type_));
+                changed = true;
+            }
+            else
+            {
+                using namespace InterceptNetworkUpdate;
+
+                VariantMap& eventData = GetEventDataMap();
+                eventData[P_SERIALIZABLE] = this;
+                eventData[P_TIMESTAMP] = (unsigned)timeStamp;
+                eventData[P_INDEX] = RemapAttributeIndex(GetAttributes(), attr, i);
+                eventData[P_NAME] = attr.name_;
+                eventData[P_VALUE] = source.ReadVariant(attr.type_);
+                SendEvent(E_INTERCEPTNETWORKUPDATE, eventData);
+            }
+        }
     }
     }
+
+    return changed;
 }
 }
 
 
 Variant Serializable::GetAttribute(unsigned index) const
 Variant Serializable::GetAttribute(unsigned index) const
@@ -745,6 +834,24 @@ unsigned Serializable::GetNumNetworkAttributes() const
     return attributes ? attributes->Size() : 0;
     return attributes ? attributes->Size() : 0;
 }
 }
 
 
+bool Serializable::GetInterceptNetworkUpdate(const String& attributeName) const
+{
+    const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
+    if (!attributes)
+        return false;
+
+    unsigned long long interceptMask = networkState_ ? networkState_->interceptMask_ : 0;
+
+    for (unsigned i = 0; i < attributes->Size(); ++i)
+    {
+        const AttributeInfo& attr = attributes->At(i);
+        if (!attr.name_.Compare(attributeName, true))
+            return interceptMask & (1ULL << i) ? true : false;
+    }
+
+    return false;
+}
+
 void Serializable::SetInstanceDefault(const String& name, const Variant& defaultValue)
 void Serializable::SetInstanceDefault(const String& name, const Variant& defaultValue)
 {
 {
     // Allocate the instance level default value
     // Allocate the instance level default value

+ 14 - 8
Source/Atomic/Scene/Serializable.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -83,18 +83,20 @@ public:
     void RemoveInstanceDefault();
     void RemoveInstanceDefault();
     /// Set temporary flag. Temporary objects will not be saved.
     /// Set temporary flag. Temporary objects will not be saved.
     void SetTemporary(bool enable);
     void SetTemporary(bool enable);
+    /// Enable interception of an attribute from network updates. Intercepted attributes are sent as events instead of applying directly. This can be used to implement client side prediction.
+    void SetInterceptNetworkUpdate(const String& attributeName, bool enable);
     /// Allocate network attribute state.
     /// Allocate network attribute state.
     void AllocateNetworkState();
     void AllocateNetworkState();
     /// Write initial delta network update.
     /// Write initial delta network update.
-    void WriteInitialDeltaUpdate(Serializer& dest);
+    void WriteInitialDeltaUpdate(Serializer& dest, unsigned char timeStamp);
     /// Write a delta network update according to dirty attribute bits.
     /// Write a delta network update according to dirty attribute bits.
-    void WriteDeltaUpdate(Serializer& dest, const DirtyBits& attributeBits);
+    void WriteDeltaUpdate(Serializer& dest, const DirtyBits& attributeBits, unsigned char timeStamp);
     /// Write a latest data network update.
     /// Write a latest data network update.
-    void WriteLatestDataUpdate(Serializer& dest);
-    /// Read and apply a network delta update.
-    void ReadDeltaUpdate(Deserializer& source);
-    /// Read and apply a network latest data update.
-    void ReadLatestDataUpdate(Deserializer& source);
+    void WriteLatestDataUpdate(Serializer& dest, unsigned char timeStamp);
+    /// Read and apply a network delta update. Return true if attributes were changed.
+    bool ReadDeltaUpdate(Deserializer& source);
+    /// Read and apply a network latest data update. Return true if attributes were changed.
+    bool ReadLatestDataUpdate(Deserializer& source);
 
 
     /// Return attribute value by index. Return empty if illegal index.
     /// Return attribute value by index. Return empty if illegal index.
     Variant GetAttribute(unsigned index) const;
     Variant GetAttribute(unsigned index) const;
@@ -110,6 +112,10 @@ public:
     unsigned GetNumNetworkAttributes() const;
     unsigned GetNumNetworkAttributes() const;
     /// Return whether is temporary.
     /// Return whether is temporary.
     bool IsTemporary() const { return temporary_; }
     bool IsTemporary() const { return temporary_; }
+    /// Return whether an attribute's network updates are being intercepted.
+    bool GetInterceptNetworkUpdate(const String& attributeName) const;
+    /// Return the network attribute state, if allocated.
+    NetworkState* GetNetworkState() const { return networkState_; }
 
 
 protected:
 protected:
     /// Network attribute state.
     /// Network attribute state.

+ 3 - 4
Source/Atomic/UI/UI.cpp

@@ -183,8 +183,7 @@ void UI::Render(VertexBuffer* buffer, const PODVector<UIBatch>& batches, unsigne
     graphics_->SetColorWrite(true);
     graphics_->SetColorWrite(true);
     graphics_->SetCullMode(CULL_NONE);
     graphics_->SetCullMode(CULL_NONE);
     graphics_->SetDepthTest(CMP_ALWAYS);
     graphics_->SetDepthTest(CMP_ALWAYS);
-    graphics_->SetDepthWrite(false);
-    graphics_->SetDrawAntialiased(false);
+    graphics_->SetDepthWrite(false);    
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetStencilTest(false);
     graphics_->SetStencilTest(false);
 
 
@@ -229,7 +228,7 @@ void UI::Render(VertexBuffer* buffer, const PODVector<UIBatch>& batches, unsigne
         }
         }
 
 
         graphics_->SetShaders(vs, ps);
         graphics_->SetShaders(vs, ps);
-        if (graphics_->NeedParameterUpdate(SP_OBJECTTRANSFORM, this))
+        if (graphics_->NeedParameterUpdate(SP_OBJECT, this))
             graphics_->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY);
             graphics_->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY);
         if (graphics_->NeedParameterUpdate(SP_CAMERA, this))
         if (graphics_->NeedParameterUpdate(SP_CAMERA, this))
             graphics_->SetShaderParameter(VSP_VIEWPROJ, projection);
             graphics_->SetShaderParameter(VSP_VIEWPROJ, projection);
@@ -259,7 +258,7 @@ void UI::SetVertexData(VertexBuffer* dest, const PODVector<float>& vertexData)
 }
 }
 
 
 
 
-void UI::Render()
+void UI::Render(bool resetRenderTargets)
 {
 {
     SetVertexData(vertexBuffer_, vertexData_);
     SetVertexData(vertexBuffer_, vertexData_);
     Render(vertexBuffer_, batches_, 0, batches_.Size());
     Render(vertexBuffer_, batches_, 0, batches_.Size());

+ 1 - 1
Source/Atomic/UI/UI.h

@@ -33,7 +33,7 @@ public:
     void SetKeyboardDisabled(bool disabled) {keyboardDisabled_ = disabled; }
     void SetKeyboardDisabled(bool disabled) {keyboardDisabled_ = disabled; }
     void SetInputDisabled(bool disabled) { inputDisabled_ = disabled; }
     void SetInputDisabled(bool disabled) { inputDisabled_ = disabled; }
 
 
-    void Render();
+    void Render(bool resetRenderTargets = true);
     void GetBatches(PODVector<UIBatch>& batches, PODVector<float>& vertexData, const IntRect& currentScissor);
     void GetBatches(PODVector<UIBatch>& batches, PODVector<float>& vertexData, const IntRect& currentScissor);
     void SubmitBatchVertexData(Texture* texture, const PODVector<float>& vertexData);
     void SubmitBatchVertexData(Texture* texture, const PODVector<float>& vertexData);
 
 

+ 2 - 0
Source/ThirdParty/CMakeLists.txt

@@ -18,6 +18,8 @@ if (NOT EMSCRIPTEN)
 	add_subdirectory(Recast)
 	add_subdirectory(Recast)
 	add_subdirectory(Civetweb)
 	add_subdirectory(Civetweb)
 	add_subdirectory(Detour)
 	add_subdirectory(Detour)
+        add_subdirectory(DetourCrowd)
+        add_subdirectory(DetourTileCache)
 	add_subdirectory(kNet)
 	add_subdirectory(kNet)
 endif()
 endif()
 
 

+ 3 - 32
Source/ThirdParty/DetourCrowd/CMakeLists.txt

@@ -1,36 +1,7 @@
-#
-# Copyright (c) 2008-2015 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.
-#
 
 
-# Define target name
-set (TARGET_NAME DetourCrowd)
+include_directories(include ${CMAKE_SOURCE_DIR}/Source/ThirdParty ${CMAKE_SOURCE_DIR}/Source/ThirdParty/Detour/include )
 
 
-# Define source files
-define_source_files (GLOB_CPP_PATTERNS source/*.cpp GLOB_H_PATTERNS include/*.h)
 
 
-# Define dependency libs
-set (INCLUDE_DIRS include ../Detour/include)
+file (GLOB SOURCE_FILES source/*.cpp include/*.h)
 
 
-# Setup target
-setup_library ()
-
-# Install headers for building the Urho3D library
-install_header_files (DIRECTORY include/ DESTINATION ${DEST_INCLUDE_DIR}/ThirdParty/DetourCrowd FILES_MATCHING PATTERN *.h BUILD_TREE_ONLY)  # Note: the trailing slash is significant
+add_library(DetourCrowd ${SOURCE_FILES})

+ 2 - 2
Source/ThirdParty/DetourCrowd/include/DetourCrowd.h

@@ -19,7 +19,7 @@
 #ifndef DETOURCROWD_H
 #ifndef DETOURCROWD_H
 #define DETOURCROWD_H
 #define DETOURCROWD_H
 
 
-#include "DetourNavMeshQuery.h"
+#include <Detour/include/DetourNavMeshQuery.h>
 #include "DetourObstacleAvoidance.h"
 #include "DetourObstacleAvoidance.h"
 #include "DetourLocalBoundary.h"
 #include "DetourLocalBoundary.h"
 #include "DetourPathCorridor.h"
 #include "DetourPathCorridor.h"
@@ -447,4 +447,4 @@ This value is often based on the agent radius. E.g. radius * 30
 A higher value will result in agents trying to stay farther away from each other at 
 A higher value will result in agents trying to stay farther away from each other at 
 the cost of more difficult steering in tight spaces.
 the cost of more difficult steering in tight spaces.
 
 
-*/
+*/

+ 1 - 1
Source/ThirdParty/DetourCrowd/include/DetourLocalBoundary.h

@@ -19,7 +19,7 @@
 #ifndef DETOURLOCALBOUNDARY_H
 #ifndef DETOURLOCALBOUNDARY_H
 #define DETOURLOCALBOUNDARY_H
 #define DETOURLOCALBOUNDARY_H
 
 
-#include "DetourNavMeshQuery.h"
+#include <Detour/include/DetourNavMeshQuery.h>
 
 
 
 
 class dtLocalBoundary
 class dtLocalBoundary

+ 1 - 1
Source/ThirdParty/DetourCrowd/include/DetourPathCorridor.h

@@ -19,7 +19,7 @@
 #ifndef DETOUTPATHCORRIDOR_H
 #ifndef DETOUTPATHCORRIDOR_H
 #define DETOUTPATHCORRIDOR_H
 #define DETOUTPATHCORRIDOR_H
 
 
-#include "DetourNavMeshQuery.h"
+#include <Detour/include/DetourNavMeshQuery.h>
 
 
 /// Represents a dynamic polygon corridor used to plan agent movement.
 /// Represents a dynamic polygon corridor used to plan agent movement.
 /// @ingroup crowd, detour
 /// @ingroup crowd, detour

+ 2 - 2
Source/ThirdParty/DetourCrowd/include/DetourPathQueue.h

@@ -19,8 +19,8 @@
 #ifndef DETOURPATHQUEUE_H
 #ifndef DETOURPATHQUEUE_H
 #define DETOURPATHQUEUE_H
 #define DETOURPATHQUEUE_H
 
 
-#include "DetourNavMesh.h"
-#include "DetourNavMeshQuery.h"
+#include <Detour/include/DetourNavMesh.h>
+#include <Detour/include/DetourNavMeshQuery.h>
 
 
 static const unsigned int DT_PATHQ_INVALID = 0;
 static const unsigned int DT_PATHQ_INVALID = 0;
 
 

+ 3 - 34
Source/ThirdParty/DetourTileCache/CMakeLists.txt

@@ -1,36 +1,5 @@
-#
-# Copyright (c) 2008-2015 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_directories(include ${CMAKE_SOURCE_DIR}/Source/ThirdParty ${CMAKE_SOURCE_DIR}/Source/ThirdParty/Detour/include )
 
 
-# Define target name
-set (TARGET_NAME DetourTileCache)
+file (GLOB SOURCE_FILES source/*.cpp include/*.h)
 
 
-# Define source files
-define_source_files (GLOB_CPP_PATTERNS source/*.cpp GLOB_H_PATTERNS include/*.h)
-
-# Define dependency libs
-set (INCLUDE_DIRS include ../Detour/include)
-
-# Setup target
-setup_library ()
-
-# Install headers for building the Urho3D library
-install_header_files (DIRECTORY include/ DESTINATION ${DEST_INCLUDE_DIR}/ThirdParty/DetourTileCache FILES_MATCHING PATTERN *.h BUILD_TREE_ONLY)  # Note: the trailing slash is significant
+add_library(DetourTileCache ${SOURCE_FILES})

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác