Browse Source

First phase of separating Graphics API from other graphics stuff [cache clear]

1vanK 3 years ago
parent
commit
653d12f952
100 changed files with 10588 additions and 10591 deletions
  1. 1 1
      Source/Samples/02_HelloGUI/HelloGUI.cpp
  2. 1 1
      Source/Samples/03_Sprites/Sprites.cpp
  3. 2 2
      Source/Samples/10_RenderToTexture/RenderToTexture.cpp
  4. 2 2
      Source/Samples/23_Water/Water.cpp
  5. 2 2
      Source/Samples/34_DynamicGeometry/DynamicGeometry.cpp
  6. 6 6
      Source/Samples/48_Hello3DUI/Hello3DUI.cpp
  7. 1 1
      Source/Samples/54_WindowSettingsDemo/WindowSettingsDemo.cpp
  8. 8 8
      Source/Samples/Sample.inl
  9. 1 1
      Source/Samples/Utilities2D/Sample2D.cpp
  10. 2 2
      Source/Tools/AssetImporter/AssetImporter.cpp
  11. 2 2
      Source/Tools/BindingGenerator/Doxyfile.in
  12. 3 3
      Source/Tools/BindingGenerator/Tuning.cpp
  13. 2 2
      Source/Tools/OgreImporter/OgreImporterUtils.h
  14. 1 1
      Source/Urho3D/AngelScript/APITemplates.h
  15. 15 15
      Source/Urho3D/AngelScript/Generated_Classes.cpp
  16. 2 2
      Source/Urho3D/AngelScript/Generated_DefaultConstructors.cpp
  17. 32 32
      Source/Urho3D/AngelScript/Generated_Enums.cpp
  18. 64 64
      Source/Urho3D/AngelScript/Generated_GlobalVariables.cpp
  19. 16 16
      Source/Urho3D/AngelScript/Generated_Includes.h
  20. 15 15
      Source/Urho3D/AngelScript/Generated_Members.h
  21. 15 15
      Source/Urho3D/AngelScript/Generated_ObjectTypes.cpp
  22. 1 1
      Source/Urho3D/AngelScript/Manual_Graphics.cpp
  23. 20 20
      Source/Urho3D/AngelScript/Manual_Graphics.h
  24. 3 3
      Source/Urho3D/CMakeLists.txt
  25. 2 2
      Source/Urho3D/Graphics/AnimatedModel.cpp
  26. 4 4
      Source/Urho3D/Graphics/Batch.cpp
  27. 2 2
      Source/Urho3D/Graphics/BillboardSet.cpp
  28. 1 1
      Source/Urho3D/Graphics/Camera.h
  29. 1 1
      Source/Urho3D/Graphics/CustomGeometry.cpp
  30. 2 2
      Source/Urho3D/Graphics/DebugRenderer.cpp
  31. 2 2
      Source/Urho3D/Graphics/DecalSet.cpp
  32. 2 2
      Source/Urho3D/Graphics/Drawable.cpp
  33. 1 1
      Source/Urho3D/Graphics/Drawable.h
  34. 2 2
      Source/Urho3D/Graphics/Geometry.cpp
  35. 1 1
      Source/Urho3D/Graphics/Geometry.h
  36. 7 9
      Source/Urho3D/Graphics/Graphics.cpp
  37. 2 2
      Source/Urho3D/Graphics/Graphics.h
  38. 2 2
      Source/Urho3D/Graphics/Light.cpp
  39. 2 2
      Source/Urho3D/Graphics/Light.h
  40. 4 4
      Source/Urho3D/Graphics/Material.cpp
  41. 1 1
      Source/Urho3D/Graphics/Material.h
  42. 4 4
      Source/Urho3D/Graphics/Model.cpp
  43. 1 1
      Source/Urho3D/Graphics/Model.h
  44. 1 1
      Source/Urho3D/Graphics/OcclusionBuffer.h
  45. 1 1
      Source/Urho3D/Graphics/ParticleEffect.h
  46. 1 1
      Source/Urho3D/Graphics/RenderPath.h
  47. 6 6
      Source/Urho3D/Graphics/Renderer.cpp
  48. 6 6
      Source/Urho3D/Graphics/RibbonTrail.cpp
  49. 1 1
      Source/Urho3D/Graphics/StaticModel.cpp
  50. 1 1
      Source/Urho3D/Graphics/StaticModelGroup.cpp
  51. 1 1
      Source/Urho3D/Graphics/Technique.cpp
  52. 1 1
      Source/Urho3D/Graphics/Technique.h
  53. 2 2
      Source/Urho3D/Graphics/Terrain.cpp
  54. 2 2
      Source/Urho3D/Graphics/TerrainPatch.cpp
  55. 7 7
      Source/Urho3D/Graphics/View.cpp
  56. 1 1
      Source/Urho3D/Graphics/Zone.cpp
  57. 1 1
      Source/Urho3D/Graphics/Zone.h
  58. 1 1
      Source/Urho3D/GraphicsAPI/ConstantBuffer.cpp
  59. 2 2
      Source/Urho3D/GraphicsAPI/ConstantBuffer.h
  60. 2 2
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11ConstantBuffer.cpp
  61. 9 9
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11Graphics.cpp
  62. 0 0
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11GraphicsImpl.cpp
  63. 4 4
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h
  64. 2 2
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11IndexBuffer.cpp
  65. 3 3
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11RenderSurface.cpp
  66. 2 2
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11ShaderProgram.h
  67. 3 3
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11ShaderVariation.cpp
  68. 1 1
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11Texture.cpp
  69. 2 2
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11Texture2D.cpp
  70. 2 2
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11Texture2DArray.cpp
  71. 2 2
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11Texture3D.cpp
  72. 2 2
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11TextureCube.cpp
  73. 3 3
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11VertexBuffer.cpp
  74. 3 3
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11VertexDeclaration.cpp
  75. 1 1
      Source/Urho3D/GraphicsAPI/Direct3D11/D3D11VertexDeclaration.h
  76. 1 1
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9ConstantBuffer.cpp
  77. 2699 2699
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9Graphics.cpp
  78. 60 60
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9GraphicsImpl.cpp
  79. 137 137
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9GraphicsImpl.h
  80. 302 302
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9IndexBuffer.cpp
  81. 72 72
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9RenderSurface.cpp
  82. 1 1
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9ShaderProgram.h
  83. 417 417
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9ShaderVariation.cpp
  84. 113 113
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9Texture.cpp
  85. 638 638
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9Texture2D.cpp
  86. 284 284
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9Texture2DArray.cpp
  87. 2 2
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9Texture3D.cpp
  88. 673 673
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9TextureCube.cpp
  89. 307 307
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9VertexBuffer.cpp
  90. 237 237
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9VertexDeclaration.cpp
  91. 78 78
      Source/Urho3D/GraphicsAPI/Direct3D9/D3D9VertexDeclaration.h
  92. 1 1
      Source/Urho3D/GraphicsAPI/GPUObject.cpp
  93. 84 84
      Source/Urho3D/GraphicsAPI/GPUObject.h
  94. 1 1
      Source/Urho3D/GraphicsAPI/GraphicsDefs.cpp
  95. 498 498
      Source/Urho3D/GraphicsAPI/GraphicsDefs.h
  96. 38 38
      Source/Urho3D/GraphicsAPI/GraphicsImpl.h
  97. 1 1
      Source/Urho3D/GraphicsAPI/IndexBuffer.cpp
  98. 167 167
      Source/Urho3D/GraphicsAPI/IndexBuffer.h
  99. 2 2
      Source/Urho3D/GraphicsAPI/OpenGL/OGLConstantBuffer.cpp
  100. 3439 3440
      Source/Urho3D/GraphicsAPI/OpenGL/OGLGraphics.cpp

+ 1 - 1
Source/Samples/02_HelloGUI/HelloGUI.cpp

@@ -23,7 +23,7 @@
 #include <Urho3D/Core/CoreEvents.h>
 #include <Urho3D/Engine/Engine.h>
 #include <Urho3D/Graphics/Graphics.h>
-#include <Urho3D/Graphics/Texture2D.h>
+#include <Urho3D/GraphicsAPI/Texture2D.h>
 #include <Urho3D/Input/Input.h>
 #include <Urho3D/Resource/ResourceCache.h>
 #include <Urho3D/UI/Button.h>

+ 1 - 1
Source/Samples/03_Sprites/Sprites.cpp

@@ -23,7 +23,7 @@
 #include <Urho3D/Core/CoreEvents.h>
 #include <Urho3D/Engine/Engine.h>
 #include <Urho3D/Graphics/Graphics.h>
-#include <Urho3D/Graphics/Texture2D.h>
+#include <Urho3D/GraphicsAPI/Texture2D.h>
 #include <Urho3D/UI/Sprite.h>
 #include <Urho3D/UI/UI.h>
 

+ 2 - 2
Source/Samples/10_RenderToTexture/RenderToTexture.cpp

@@ -28,11 +28,11 @@
 #include <Urho3D/Graphics/Model.h>
 #include <Urho3D/Graphics/Octree.h>
 #include <Urho3D/Graphics/Renderer.h>
-#include <Urho3D/Graphics/RenderSurface.h>
 #include <Urho3D/Graphics/StaticModel.h>
 #include <Urho3D/Graphics/Technique.h>
-#include <Urho3D/Graphics/Texture2D.h>
 #include <Urho3D/Graphics/Zone.h>
+#include <Urho3D/GraphicsAPI/RenderSurface.h>
+#include <Urho3D/GraphicsAPI/Texture2D.h>
 #include <Urho3D/Input/Input.h>
 #include <Urho3D/Resource/ResourceCache.h>
 #include <Urho3D/Scene/Scene.h>

+ 2 - 2
Source/Samples/23_Water/Water.cpp

@@ -29,11 +29,11 @@
 #include <Urho3D/Graphics/Model.h>
 #include <Urho3D/Graphics/Octree.h>
 #include <Urho3D/Graphics/Renderer.h>
-#include <Urho3D/Graphics/RenderSurface.h>
 #include <Urho3D/Graphics/Skybox.h>
 #include <Urho3D/Graphics/Terrain.h>
-#include <Urho3D/Graphics/Texture2D.h>
 #include <Urho3D/Graphics/Zone.h>
+#include <Urho3D/GraphicsAPI/RenderSurface.h>
+#include <Urho3D/GraphicsAPI/Texture2D.h>
 #include <Urho3D/Input/Input.h>
 #include <Urho3D/IO/File.h>
 #include <Urho3D/IO/FileSystem.h>

+ 2 - 2
Source/Samples/34_DynamicGeometry/DynamicGeometry.cpp

@@ -26,14 +26,14 @@
 #include <Urho3D/Graphics/Camera.h>
 #include <Urho3D/Graphics/Geometry.h>
 #include <Urho3D/Graphics/Graphics.h>
-#include <Urho3D/Graphics/IndexBuffer.h>
 #include <Urho3D/Graphics/Light.h>
 #include <Urho3D/Graphics/Model.h>
 #include <Urho3D/Graphics/Octree.h>
 #include <Urho3D/Graphics/Renderer.h>
 #include <Urho3D/Graphics/StaticModel.h>
-#include <Urho3D/Graphics/VertexBuffer.h>
 #include <Urho3D/Graphics/Zone.h>
+#include <Urho3D/GraphicsAPI/IndexBuffer.h>
+#include <Urho3D/GraphicsAPI/VertexBuffer.h>
 #include <Urho3D/Input/Input.h>
 #include <Urho3D/IO/Log.h>
 #include <Urho3D/Resource/ResourceCache.h>

+ 6 - 6
Source/Samples/48_Hello3DUI/Hello3DUI.cpp

@@ -23,24 +23,24 @@
 #include <Urho3D/Core/CoreEvents.h>
 #include <Urho3D/Engine/Engine.h>
 #include <Urho3D/Graphics/Graphics.h>
-#include <Urho3D/Graphics/Texture2D.h>
-#include <Urho3D/Graphics/Zone.h>
-#include <Urho3D/Graphics/StaticModel.h>
 #include <Urho3D/Graphics/Model.h>
-#include <Urho3D/Graphics/Technique.h>
 #include <Urho3D/Graphics/Octree.h>
+#include <Urho3D/Graphics/StaticModel.h>
+#include <Urho3D/Graphics/Technique.h>
+#include <Urho3D/Graphics/Zone.h>
+#include <Urho3D/GraphicsAPI/Texture2D.h>
 #include <Urho3D/Input/Input.h>
 #include <Urho3D/Resource/ResourceCache.h>
 #include <Urho3D/UI/Button.h>
 #include <Urho3D/UI/CheckBox.h>
 #include <Urho3D/UI/LineEdit.h>
+#include <Urho3D/UI/ListView.h>
 #include <Urho3D/UI/Text.h>
 #include <Urho3D/UI/ToolTip.h>
 #include <Urho3D/UI/UI.h>
+#include <Urho3D/UI/UIComponent.h>
 #include <Urho3D/UI/UIEvents.h>
 #include <Urho3D/UI/Window.h>
-#include <Urho3D/UI/ListView.h>
-#include <Urho3D/UI/UIComponent.h>
 
 #include "Hello3DUI.h"
 

+ 1 - 1
Source/Samples/54_WindowSettingsDemo/WindowSettingsDemo.cpp

@@ -28,8 +28,8 @@
 #include <Urho3D/Graphics/Model.h>
 #include <Urho3D/Graphics/Octree.h>
 #include <Urho3D/Graphics/StaticModel.h>
-#include <Urho3D/Graphics/Texture2D.h>
 #include <Urho3D/Graphics/Zone.h>
+#include <Urho3D/GraphicsAPI/Texture2D.h>
 #include <Urho3D/Input/Input.h>
 #include <Urho3D/Resource/ResourceCache.h>
 #include <Urho3D/UI/Button.h>

+ 8 - 8
Source/Samples/Sample.inl

@@ -20,27 +20,27 @@
 // THE SOFTWARE.
 //
 
+#include <Urho3D/Core/Timer.h>
 #include <Urho3D/Engine/Application.h>
-#include <Urho3D/Graphics/Camera.h>
 #include <Urho3D/Engine/Console.h>
-#include <Urho3D/UI/Cursor.h>
 #include <Urho3D/Engine/DebugHud.h>
 #include <Urho3D/Engine/Engine.h>
 #include <Urho3D/Engine/EngineDefs.h>
-#include <Urho3D/IO/FileSystem.h>
+#include <Urho3D/Graphics/Camera.h>
 #include <Urho3D/Graphics/Graphics.h>
+#include <Urho3D/Graphics/Renderer.h>
+#include <Urho3D/GraphicsAPI/Texture2D.h>
 #include <Urho3D/Input/Input.h>
 #include <Urho3D/Input/InputEvents.h>
-#include <Urho3D/Graphics/Renderer.h>
+#include <Urho3D/IO/FileSystem.h>
+#include <Urho3D/IO/Log.h>
 #include <Urho3D/Resource/ResourceCache.h>
+#include <Urho3D/Resource/XMLFile.h>
 #include <Urho3D/Scene/Scene.h>
 #include <Urho3D/Scene/SceneEvents.h>
+#include <Urho3D/UI/Cursor.h>
 #include <Urho3D/UI/Sprite.h>
-#include <Urho3D/Graphics/Texture2D.h>
-#include <Urho3D/Core/Timer.h>
 #include <Urho3D/UI/UI.h>
-#include <Urho3D/Resource/XMLFile.h>
-#include <Urho3D/IO/Log.h>
 
 Sample::Sample(Context* context) :
     Application(context),

+ 1 - 1
Source/Samples/Utilities2D/Sample2D.cpp

@@ -27,7 +27,7 @@
 #include <Urho3D/Core/StringUtils.h>
 #include <Urho3D/Engine/Engine.h>
 #include <Urho3D/Graphics/Camera.h>
-#include <Urho3D/Graphics/Texture2D.h>
+#include <Urho3D/GraphicsAPI/Texture2D.h>
 #include <Urho3D/Input/Input.h>
 #include <Urho3D/IO/File.h>
 #include <Urho3D/IO/FileSystem.h>

+ 2 - 2
Source/Tools/AssetImporter/AssetImporter.cpp

@@ -29,12 +29,12 @@
 #include <Urho3D/Graphics/DebugRenderer.h>
 #include <Urho3D/Graphics/Geometry.h>
 #include <Urho3D/Graphics/Graphics.h>
-#include <Urho3D/Graphics/IndexBuffer.h>
 #include <Urho3D/Graphics/Light.h>
 #include <Urho3D/Graphics/Material.h>
 #include <Urho3D/Graphics/Octree.h>
-#include <Urho3D/Graphics/VertexBuffer.h>
 #include <Urho3D/Graphics/Zone.h>
+#include <Urho3D/GraphicsAPI/IndexBuffer.h>
+#include <Urho3D/GraphicsAPI/VertexBuffer.h>
 #include <Urho3D/IO/File.h>
 #include <Urho3D/IO/FileSystem.h>
 #ifdef URHO3D_PHYSICS

+ 2 - 2
Source/Tools/BindingGenerator/Doxyfile.in

@@ -95,8 +95,8 @@ QUIET                  = YES
 
 EXCLUDE_PATTERNS       = "@CMAKE_SOURCE_DIR@/Source/Urho3D/AngelScript/*" \
                          "@CMAKE_SOURCE_DIR@/Source/Urho3D/LuaScript/*" \
-                         "@CMAKE_SOURCE_DIR@/Source/Urho3D/Graphics/Direct3D11/*" \
-                         "@CMAKE_SOURCE_DIR@/Source/Urho3D/Graphics/Direct3D9/*" \
+                         "@CMAKE_SOURCE_DIR@/Source/Urho3D/GraphicsAPI/Direct3D11/*" \
+                         "@CMAKE_SOURCE_DIR@/Source/Urho3D/GraphicsAPI/Direct3D9/*" \
                          "@CMAKE_SOURCE_DIR@/Source/Urho3D/Database/SQLite/*" # https://github.com/doxygen/doxygen/issues/8805
 
 # The WARNINGS tag can be used to turn on/off the warning messages that are

+ 3 - 3
Source/Tools/BindingGenerator/Tuning.cpp

@@ -64,9 +64,9 @@ bool IsIgnoredHeader(const string& headerFile)
         "../AngelScript",
         //"../Container",
         "../LuaScript",
-        "../Graphics/Direct3D11",
-        "../Graphics/Direct3D9",
-        "../Graphics/OpenGL",
+        "../GraphicsAPI/Direct3D11",
+        "../GraphicsAPI/Direct3D9",
+        "../GraphicsAPI/OpenGL",
         "../Database/ODBC",
         "../Database/SQLite",
     };

+ 2 - 2
Source/Tools/OgreImporter/OgreImporterUtils.h

@@ -23,10 +23,10 @@
 #pragma once
 
 #include <Urho3D/Graphics/Animation.h>
-#include <Urho3D/Math/BoundingBox.h>
 #include <Urho3D/Graphics/Graphics.h>
-#include <Urho3D/Graphics/VertexBuffer.h>
+#include <Urho3D/GraphicsAPI/VertexBuffer.h>
 #include <Urho3D/IO/Serializer.h>
+#include <Urho3D/Math/BoundingBox.h>
 #include <Urho3D/Math/Matrix3x4.h>
 
 using namespace Urho3D;

+ 1 - 1
Source/Urho3D/AngelScript/APITemplates.h

@@ -31,7 +31,7 @@
 #include "../Container/Sort.h"
 #include "../Graphics/Drawable.h"
 #include "../Graphics/StaticModel.h"
-#include "../Graphics/Texture.h"
+#include "../GraphicsAPI/Texture.h"
 #include "../IO/File.h"
 #include "../IO/Log.h"
 #include "../IO/VectorBuffer.h"

+ 15 - 15
Source/Urho3D/AngelScript/Generated_Classes.cpp

@@ -844,7 +844,7 @@ static void GPUObject__GPUObject_Graphicsstar(GPUObject* _ptr, Graphics* graphic
     new(_ptr) GPUObject(graphics);
 }
 
-// class GPUObject | File: ../Graphics/GPUObject.h
+// class GPUObject | File: ../GraphicsAPI/GPUObject.h
 static void Register_GPUObject(asIScriptEngine* engine)
 {
     // explicit GPUObject::GPUObject(Graphics* graphics)
@@ -2156,7 +2156,7 @@ static void ShaderParameter__ShaderParameter_ShaderType_constspStringamp_unsigne
     new(_ptr) ShaderParameter(type, name, reg, regCount);
 }
 
-// struct ShaderParameter | File: ../Graphics/ShaderVariation.h
+// struct ShaderParameter | File: ../GraphicsAPI/ShaderVariation.h
 static void Register_ShaderParameter(asIScriptEngine* engine)
 {
     // ShaderParameter::ShaderParameter(const String& name, unsigned glType, int location)
@@ -3160,7 +3160,7 @@ static void VertexElement__VertexElement_VertexElementType_VertexElementSemantic
     new(_ptr) VertexElement(type, semantic, index, perInstance);
 }
 
-// struct VertexElement | File: ../Graphics/GraphicsDefs.h
+// struct VertexElement | File: ../GraphicsAPI/GraphicsDefs.h
 static void Register_VertexElement(asIScriptEngine* engine)
 {
     // VertexElement::VertexElement(VertexElementType type, VertexElementSemantic semantic, unsigned char index = 0, bool perInstance = false) noexcept
@@ -3771,7 +3771,7 @@ static RenderSurface* RenderSurface__RenderSurface_Texturestar(Texture* parentTe
     return new RenderSurface(parentTexture);
 }
 
-// class RenderSurface | File: ../Graphics/RenderSurface.h
+// class RenderSurface | File: ../GraphicsAPI/RenderSurface.h
 static void Register_RenderSurface(asIScriptEngine* engine)
 {
     // explicit RenderSurface::RenderSurface(Texture* parentTexture)
@@ -3808,7 +3808,7 @@ static ShaderVariation* ShaderVariation__ShaderVariation_Shaderstar_ShaderType(S
     return new ShaderVariation(owner, type);
 }
 
-// class ShaderVariation | File: ../Graphics/ShaderVariation.h
+// class ShaderVariation | File: ../GraphicsAPI/ShaderVariation.h
 static void Register_ShaderVariation(asIScriptEngine* engine)
 {
     // ShaderVariation::ShaderVariation(Shader* owner, ShaderType type)
@@ -4092,7 +4092,7 @@ static ConstantBuffer* ConstantBuffer__ConstantBuffer_Contextstar()
     return new ConstantBuffer(context);
 }
 
-// class ConstantBuffer | File: ../Graphics/ConstantBuffer.h
+// class ConstantBuffer | File: ../GraphicsAPI/ConstantBuffer.h
 static void Register_ConstantBuffer(asIScriptEngine* engine)
 {
     // explicit ConstantBuffer::ConstantBuffer(Context* context)
@@ -4363,7 +4363,7 @@ static IndexBuffer* IndexBuffer__IndexBuffer_Contextstar_bool(bool forceHeadless
     return new IndexBuffer(context, forceHeadless);
 }
 
-// class IndexBuffer | File: ../Graphics/IndexBuffer.h
+// class IndexBuffer | File: ../GraphicsAPI/IndexBuffer.h
 static void Register_IndexBuffer(asIScriptEngine* engine)
 {
     // explicit IndexBuffer::IndexBuffer(Context* context, bool forceHeadless = false)
@@ -4737,7 +4737,7 @@ static ShaderPrecache* ShaderPrecache__ShaderPrecache_Contextstar_constspStringa
     return new ShaderPrecache(context, fileName);
 }
 
-// class ShaderPrecache | File: ../Graphics/ShaderPrecache.h
+// class ShaderPrecache | File: ../GraphicsAPI/ShaderPrecache.h
 static void Register_ShaderPrecache(asIScriptEngine* engine)
 {
     // ShaderPrecache::ShaderPrecache(Context* context, const String& fileName)
@@ -4836,7 +4836,7 @@ static VertexBuffer* VertexBuffer__VertexBuffer_Contextstar_bool(bool forceHeadl
     return new VertexBuffer(context, forceHeadless);
 }
 
-// class VertexBuffer | File: ../Graphics/VertexBuffer.h
+// class VertexBuffer | File: ../GraphicsAPI/VertexBuffer.h
 static void Register_VertexBuffer(asIScriptEngine* engine)
 {
     // explicit VertexBuffer::VertexBuffer(Context* context, bool forceHeadless = false)
@@ -5408,7 +5408,7 @@ static Shader* Shader__Shader_Contextstar()
     return new Shader(context);
 }
 
-// class Shader | File: ../Graphics/Shader.h
+// class Shader | File: ../GraphicsAPI/Shader.h
 static void Register_Shader(asIScriptEngine* engine)
 {
     // explicit Shader::Shader(Context* context)
@@ -5768,7 +5768,7 @@ static Texture* Texture__Texture_Contextstar()
     return new Texture(context);
 }
 
-// class Texture | File: ../Graphics/Texture.h
+// class Texture | File: ../GraphicsAPI/Texture.h
 static void Register_Texture(asIScriptEngine* engine)
 {
     // explicit Texture::Texture(Context* context)
@@ -6220,7 +6220,7 @@ static Texture2D* Texture2D__Texture2D_Contextstar()
     return new Texture2D(context);
 }
 
-// class Texture2D | File: ../Graphics/Texture2D.h
+// class Texture2D | File: ../GraphicsAPI/Texture2D.h
 static void Register_Texture2D(asIScriptEngine* engine)
 {
     // explicit Texture2D::Texture2D(Context* context)
@@ -6246,7 +6246,7 @@ static Texture2DArray* Texture2DArray__Texture2DArray_Contextstar()
     return new Texture2DArray(context);
 }
 
-// class Texture2DArray | File: ../Graphics/Texture2DArray.h
+// class Texture2DArray | File: ../GraphicsAPI/Texture2DArray.h
 static void Register_Texture2DArray(asIScriptEngine* engine)
 {
     // explicit Texture2DArray::Texture2DArray(Context* context)
@@ -6272,7 +6272,7 @@ static Texture3D* Texture3D__Texture3D_Contextstar()
     return new Texture3D(context);
 }
 
-// class Texture3D | File: ../Graphics/Texture3D.h
+// class Texture3D | File: ../GraphicsAPI/Texture3D.h
 static void Register_Texture3D(asIScriptEngine* engine)
 {
     // explicit Texture3D::Texture3D(Context* context)
@@ -6298,7 +6298,7 @@ static TextureCube* TextureCube__TextureCube_Contextstar()
     return new TextureCube(context);
 }
 
-// class TextureCube | File: ../Graphics/TextureCube.h
+// class TextureCube | File: ../GraphicsAPI/TextureCube.h
 static void Register_TextureCube(asIScriptEngine* engine)
 {
     // explicit TextureCube::TextureCube(Context* context)

+ 2 - 2
Source/Urho3D/AngelScript/Generated_DefaultConstructors.cpp

@@ -252,7 +252,7 @@ void ASRegisterGeneratedDefaultConstructors(asIScriptEngine* engine)
     // ScreenModeParams::ScreenModeParams() | Implicitly-declared
     engine->RegisterObjectBehaviour("ScreenModeParams", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ASCompatibleConstructor<ScreenModeParams>), AS_CALL_CDECL_OBJFIRST);
 
-    // ShaderParameter::ShaderParameter() = default | File: ../Graphics/ShaderVariation.h
+    // ShaderParameter::ShaderParameter() = default | File: ../GraphicsAPI/ShaderVariation.h
     engine->RegisterObjectBehaviour("ShaderParameter", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ASCompatibleConstructor<ShaderParameter>), AS_CALL_CDECL_OBJFIRST);
 
     // ShadowBatchQueue::ShadowBatchQueue() | Implicitly-declared
@@ -318,7 +318,7 @@ void ASRegisterGeneratedDefaultConstructors(asIScriptEngine* engine)
     // VertexBufferMorph::VertexBufferMorph() | Implicitly-declared
     engine->RegisterObjectBehaviour("VertexBufferMorph", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ASCompatibleConstructor<VertexBufferMorph>), AS_CALL_CDECL_OBJFIRST);
 
-    // VertexElement::VertexElement() noexcept | File: ../Graphics/GraphicsDefs.h
+    // VertexElement::VertexElement() noexcept | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterObjectBehaviour("VertexElement", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ASCompatibleConstructor<VertexElement>), AS_CALL_CDECL_OBJFIRST);
 
     // WindowModeParams::WindowModeParams() | Implicitly-declared

+ 32 - 32
Source/Urho3D/AngelScript/Generated_Enums.cpp

@@ -21,7 +21,7 @@ static const unsigned char BoneCollisionShape_BONECOLLISION_NONE = BONECOLLISION
 static const unsigned char BoneCollisionShape_BONECOLLISION_SPHERE = BONECOLLISION_SPHERE;
 static const unsigned char BoneCollisionShape_BONECOLLISION_BOX = BONECOLLISION_BOX;
 
-// enum ClearTarget : u32 | File: ../Graphics/GraphicsDefs.h
+// enum ClearTarget : u32 | File: ../GraphicsAPI/GraphicsDefs.h
 static const u32 ClearTarget_CLEAR_COLOR = CLEAR_COLOR;
 static const u32 ClearTarget_CLEAR_DEPTH = CLEAR_DEPTH;
 static const u32 ClearTarget_CLEAR_STENCIL = CLEAR_STENCIL;
@@ -305,7 +305,7 @@ static const unsigned Key_KEY_VOLUMEDOWN = KEY_VOLUMEDOWN;
 static const unsigned Key_KEY_VOLUMEUP = KEY_VOLUMEUP;
 static const unsigned Key_KEY_WWW = KEY_WWW;
 
-// enum MaterialQuality : u32 | File: ../Graphics/GraphicsDefs.h
+// enum MaterialQuality : u32 | File: ../GraphicsAPI/GraphicsDefs.h
 static const u32 MaterialQuality_QUALITY_LOW = QUALITY_LOW;
 static const u32 MaterialQuality_QUALITY_MEDIUM = QUALITY_MEDIUM;
 static const u32 MaterialQuality_QUALITY_HIGH = QUALITY_HIGH;
@@ -586,7 +586,7 @@ static const unsigned UpdateEvent_USE_POSTUPDATE = USE_POSTUPDATE;
 static const unsigned UpdateEvent_USE_FIXEDUPDATE = USE_FIXEDUPDATE;
 static const unsigned UpdateEvent_USE_FIXEDPOSTUPDATE = USE_FIXEDPOSTUPDATE;
 
-// enum VertexMask : u32 | File: ../Graphics/GraphicsDefs.h
+// enum VertexMask : u32 | File: ../GraphicsAPI/GraphicsDefs.h
 static const u32 VertexMask_MASK_NONE = MASK_NONE;
 static const u32 VertexMask_MASK_POSITION = MASK_POSITION;
 static const u32 VertexMask_MASK_NORMAL = MASK_NORMAL;
@@ -656,7 +656,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("AutoRemoveMode", "REMOVE_COMPONENT", REMOVE_COMPONENT);
     engine->RegisterEnumValue("AutoRemoveMode", "REMOVE_NODE", REMOVE_NODE);
 
-    // enum BlendMode | File: ../Graphics/GraphicsDefs.h
+    // enum BlendMode | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("BlendMode");
     engine->RegisterEnumValue("BlendMode", "BLEND_REPLACE", BLEND_REPLACE);
     engine->RegisterEnumValue("BlendMode", "BLEND_ADD", BLEND_ADD);
@@ -678,16 +678,16 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     // URHO3D_FLAGSET(BoneCollisionShape, BoneCollisionShapeFlags) | File: ../Graphics/Skeleton.h
     engine->RegisterTypedef("BoneCollisionShapeFlags", "uint8");
 
-    // enum ClearTarget : u32 | File: ../Graphics/GraphicsDefs.h
+    // enum ClearTarget : u32 | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterTypedef("ClearTarget", "uint");
     engine->RegisterGlobalProperty("const uint CLEAR_COLOR", (void*)&ClearTarget_CLEAR_COLOR);
     engine->RegisterGlobalProperty("const uint CLEAR_DEPTH", (void*)&ClearTarget_CLEAR_DEPTH);
     engine->RegisterGlobalProperty("const uint CLEAR_STENCIL", (void*)&ClearTarget_CLEAR_STENCIL);
 
-    // URHO3D_FLAGSET(ClearTarget, ClearTargetFlags) | File: ../Graphics/GraphicsDefs.h
+    // URHO3D_FLAGSET(ClearTarget, ClearTargetFlags) | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterTypedef("ClearTargetFlags", "uint");
 
-    // enum CompareMode | File: ../Graphics/GraphicsDefs.h
+    // enum CompareMode | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("CompareMode");
     engine->RegisterEnumValue("CompareMode", "CMP_ALWAYS", CMP_ALWAYS);
     engine->RegisterEnumValue("CompareMode", "CMP_EQUAL", CMP_EQUAL);
@@ -753,7 +753,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("CreateMode", "REPLICATED", REPLICATED);
     engine->RegisterEnumValue("CreateMode", "LOCAL", LOCAL);
 
-    // enum CubeMapFace | File: ../Graphics/GraphicsDefs.h
+    // enum CubeMapFace | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("CubeMapFace");
     engine->RegisterEnumValue("CubeMapFace", "FACE_POSITIVE_X", FACE_POSITIVE_X);
     engine->RegisterEnumValue("CubeMapFace", "FACE_NEGATIVE_X", FACE_NEGATIVE_X);
@@ -763,7 +763,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("CubeMapFace", "FACE_NEGATIVE_Z", FACE_NEGATIVE_Z);
     engine->RegisterEnumValue("CubeMapFace", "MAX_CUBEMAP_FACES", MAX_CUBEMAP_FACES);
 
-    // enum CubeMapLayout | File: ../Graphics/GraphicsDefs.h
+    // enum CubeMapLayout | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("CubeMapLayout");
     engine->RegisterEnumValue("CubeMapLayout", "CML_HORIZONTAL", CML_HORIZONTAL);
     engine->RegisterEnumValue("CubeMapLayout", "CML_HORIZONTALNVIDIA", CML_HORIZONTALNVIDIA);
@@ -771,7 +771,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("CubeMapLayout", "CML_VERTICALCROSS", CML_VERTICALCROSS);
     engine->RegisterEnumValue("CubeMapLayout", "CML_BLENDER", CML_BLENDER);
 
-    // enum CullMode | File: ../Graphics/GraphicsDefs.h
+    // enum CullMode | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("CullMode");
     engine->RegisterEnumValue("CullMode", "CULL_NONE", CULL_NONE);
     engine->RegisterEnumValue("CullMode", "CULL_CCW", CULL_CCW);
@@ -872,7 +872,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("EmitterType", "EMITTER_CYLINDER", EMITTER_CYLINDER);
     engine->RegisterEnumValue("EmitterType", "EMITTER_RING", EMITTER_RING);
 
-    // enum FaceCameraMode | File: ../Graphics/GraphicsDefs.h
+    // enum FaceCameraMode | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("FaceCameraMode");
     engine->RegisterEnumValue("FaceCameraMode", "FC_NONE", FC_NONE);
     engine->RegisterEnumValue("FaceCameraMode", "FC_ROTATE_XYZ", FC_ROTATE_XYZ);
@@ -888,7 +888,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("FileMode", "FILE_WRITE", FILE_WRITE);
     engine->RegisterEnumValue("FileMode", "FILE_READWRITE", FILE_READWRITE);
 
-    // enum FillMode | File: ../Graphics/GraphicsDefs.h
+    // enum FillMode | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("FillMode");
     engine->RegisterEnumValue("FillMode", "FILL_SOLID", FILL_SOLID);
     engine->RegisterEnumValue("FillMode", "FILL_WIREFRAME", FILL_WIREFRAME);
@@ -923,14 +923,14 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("FrustumPlane", "PLANE_DOWN", PLANE_DOWN);
     engine->RegisterEnumValue("FrustumPlane", "PLANE_FAR", PLANE_FAR);
 
-    // enum GAPI | File: ../Graphics/GraphicsDefs.h
+    // enum GAPI | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("GAPI");
     engine->RegisterEnumValue("GAPI", "GAPI_NONE", GAPI_NONE);
     engine->RegisterEnumValue("GAPI", "GAPI_OPENGL", GAPI_OPENGL);
     engine->RegisterEnumValue("GAPI", "GAPI_D3D9", GAPI_D3D9);
     engine->RegisterEnumValue("GAPI", "GAPI_D3D11", GAPI_D3D11);
 
-    // enum GeometryType | File: ../Graphics/GraphicsDefs.h
+    // enum GeometryType | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("GeometryType");
     engine->RegisterEnumValue("GeometryType", "GEOM_STATIC", GEOM_STATIC);
     engine->RegisterEnumValue("GeometryType", "GEOM_SKINNED", GEOM_SKINNED);
@@ -1246,7 +1246,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("LayoutMode", "LM_HORIZONTAL", LM_HORIZONTAL);
     engine->RegisterEnumValue("LayoutMode", "LM_VERTICAL", LM_VERTICAL);
 
-    // enum LegacyVertexElement | File: ../Graphics/GraphicsDefs.h
+    // enum LegacyVertexElement | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("LegacyVertexElement");
     engine->RegisterEnumValue("LegacyVertexElement", "ELEMENT_POSITION", ELEMENT_POSITION);
     engine->RegisterEnumValue("LegacyVertexElement", "ELEMENT_NORMAL", ELEMENT_NORMAL);
@@ -1309,14 +1309,14 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("LoadMode", "LOAD_SCENE", LOAD_SCENE);
     engine->RegisterEnumValue("LoadMode", "LOAD_SCENE_AND_RESOURCES", LOAD_SCENE_AND_RESOURCES);
 
-    // enum LockState | File: ../Graphics/GraphicsDefs.h
+    // enum LockState | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("LockState");
     engine->RegisterEnumValue("LockState", "LOCK_NONE", LOCK_NONE);
     engine->RegisterEnumValue("LockState", "LOCK_HARDWARE", LOCK_HARDWARE);
     engine->RegisterEnumValue("LockState", "LOCK_SHADOW", LOCK_SHADOW);
     engine->RegisterEnumValue("LockState", "LOCK_SCRATCH", LOCK_SCRATCH);
 
-    // enum MaterialQuality : u32 | File: ../Graphics/GraphicsDefs.h
+    // enum MaterialQuality : u32 | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterTypedef("MaterialQuality", "uint");
     engine->RegisterGlobalProperty("const uint QUALITY_LOW", (void*)&MaterialQuality_QUALITY_LOW);
     engine->RegisterGlobalProperty("const uint QUALITY_MEDIUM", (void*)&MaterialQuality_QUALITY_MEDIUM);
@@ -1355,7 +1355,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("PassLightingMode", "LIGHTING_PERVERTEX", LIGHTING_PERVERTEX);
     engine->RegisterEnumValue("PassLightingMode", "LIGHTING_PERPIXEL", LIGHTING_PERPIXEL);
 
-    // enum PrimitiveType | File: ../Graphics/GraphicsDefs.h
+    // enum PrimitiveType | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("PrimitiveType");
     engine->RegisterEnumValue("PrimitiveType", "TRIANGLE_LIST", TRIANGLE_LIST);
     engine->RegisterEnumValue("PrimitiveType", "LINE_LIST", LINE_LIST);
@@ -1398,7 +1398,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("RenderCommandType", "CMD_RENDERUI", CMD_RENDERUI);
     engine->RegisterEnumValue("RenderCommandType", "CMD_SENDEVENT", CMD_SENDEVENT);
 
-    // enum RenderSurfaceUpdateMode | File: ../Graphics/GraphicsDefs.h
+    // enum RenderSurfaceUpdateMode | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("RenderSurfaceUpdateMode");
     engine->RegisterEnumValue("RenderSurfaceUpdateMode", "SURFACE_MANUALUPDATE", SURFACE_MANUALUPDATE);
     engine->RegisterEnumValue("RenderSurfaceUpdateMode", "SURFACE_UPDATEVISIBLE", SURFACE_UPDATEVISIBLE);
@@ -1663,7 +1663,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterGlobalProperty("const uint SCANCODE_APP1", (void*)&Scancode_SCANCODE_APP1);
     engine->RegisterGlobalProperty("const uint SCANCODE_APP2", (void*)&Scancode_SCANCODE_APP2);
 
-    // enum ShaderParameterGroup | File: ../Graphics/GraphicsDefs.h
+    // enum ShaderParameterGroup | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("ShaderParameterGroup");
     engine->RegisterEnumValue("ShaderParameterGroup", "SP_FRAME", SP_FRAME);
     engine->RegisterEnumValue("ShaderParameterGroup", "SP_CAMERA", SP_CAMERA);
@@ -1674,12 +1674,12 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("ShaderParameterGroup", "SP_CUSTOM", SP_CUSTOM);
     engine->RegisterEnumValue("ShaderParameterGroup", "MAX_SHADER_PARAMETER_GROUPS", MAX_SHADER_PARAMETER_GROUPS);
 
-    // enum ShaderType | File: ../Graphics/GraphicsDefs.h
+    // enum ShaderType | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("ShaderType");
     engine->RegisterEnumValue("ShaderType", "VS", VS);
     engine->RegisterEnumValue("ShaderType", "PS", PS);
 
-    // enum ShadowQuality | File: ../Graphics/GraphicsDefs.h
+    // enum ShadowQuality | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("ShadowQuality");
     engine->RegisterEnumValue("ShadowQuality", "SHADOWQUALITY_SIMPLE_16BIT", SHADOWQUALITY_SIMPLE_16BIT);
     engine->RegisterEnumValue("ShadowQuality", "SHADOWQUALITY_SIMPLE_24BIT", SHADOWQUALITY_SIMPLE_24BIT);
@@ -1697,7 +1697,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     // URHO3D_FLAGSET(SmoothingType, SmoothingTypeFlags) | File: ../Scene/SmoothedTransform.h
     engine->RegisterTypedef("SmoothingTypeFlags", "uint");
 
-    // enum StencilOp | File: ../Graphics/GraphicsDefs.h
+    // enum StencilOp | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("StencilOp");
     engine->RegisterEnumValue("StencilOp", "OP_KEEP", OP_KEEP);
     engine->RegisterEnumValue("StencilOp", "OP_ZERO", OP_ZERO);
@@ -1711,7 +1711,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("TextEffect", "TE_SHADOW", TE_SHADOW);
     engine->RegisterEnumValue("TextEffect", "TE_STROKE", TE_STROKE);
 
-    // enum TextureAddressMode | File: ../Graphics/GraphicsDefs.h
+    // enum TextureAddressMode | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("TextureAddressMode");
     engine->RegisterEnumValue("TextureAddressMode", "ADDRESS_WRAP", ADDRESS_WRAP);
     engine->RegisterEnumValue("TextureAddressMode", "ADDRESS_MIRROR", ADDRESS_MIRROR);
@@ -1719,14 +1719,14 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("TextureAddressMode", "ADDRESS_BORDER", ADDRESS_BORDER);
     engine->RegisterEnumValue("TextureAddressMode", "MAX_ADDRESSMODES", MAX_ADDRESSMODES);
 
-    // enum TextureCoordinate | File: ../Graphics/GraphicsDefs.h
+    // enum TextureCoordinate | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("TextureCoordinate");
     engine->RegisterEnumValue("TextureCoordinate", "COORD_U", COORD_U);
     engine->RegisterEnumValue("TextureCoordinate", "COORD_V", COORD_V);
     engine->RegisterEnumValue("TextureCoordinate", "COORD_W", COORD_W);
     engine->RegisterEnumValue("TextureCoordinate", "MAX_COORDS", MAX_COORDS);
 
-    // enum TextureFilterMode | File: ../Graphics/GraphicsDefs.h
+    // enum TextureFilterMode | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("TextureFilterMode");
     engine->RegisterEnumValue("TextureFilterMode", "FILTER_NEAREST", FILTER_NEAREST);
     engine->RegisterEnumValue("TextureFilterMode", "FILTER_BILINEAR", FILTER_BILINEAR);
@@ -1736,10 +1736,10 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("TextureFilterMode", "FILTER_DEFAULT", FILTER_DEFAULT);
     engine->RegisterEnumValue("TextureFilterMode", "MAX_FILTERMODES", MAX_FILTERMODES);
 
-    // enum TextureUnit | File: ../Graphics/GraphicsDefs.h
+    // enum TextureUnit | File: ../GraphicsAPI/GraphicsDefs.h
     // Not registered because have @manualbind mark
 
-    // enum TextureUsage | File: ../Graphics/GraphicsDefs.h
+    // enum TextureUsage | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("TextureUsage");
     engine->RegisterEnumValue("TextureUsage", "TEXTURE_STATIC", TEXTURE_STATIC);
     engine->RegisterEnumValue("TextureUsage", "TEXTURE_DYNAMIC", TEXTURE_DYNAMIC);
@@ -1812,7 +1812,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("VariantType", "VAR_CUSTOM_STACK", VAR_CUSTOM_STACK);
     engine->RegisterEnumValue("VariantType", "MAX_VAR_TYPES", MAX_VAR_TYPES);
 
-    // enum VertexElementSemantic | File: ../Graphics/GraphicsDefs.h
+    // enum VertexElementSemantic | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("VertexElementSemantic");
     engine->RegisterEnumValue("VertexElementSemantic", "SEM_POSITION", SEM_POSITION);
     engine->RegisterEnumValue("VertexElementSemantic", "SEM_NORMAL", SEM_NORMAL);
@@ -1825,7 +1825,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("VertexElementSemantic", "SEM_OBJECTINDEX", SEM_OBJECTINDEX);
     engine->RegisterEnumValue("VertexElementSemantic", "MAX_VERTEX_ELEMENT_SEMANTICS", MAX_VERTEX_ELEMENT_SEMANTICS);
 
-    // enum VertexElementType | File: ../Graphics/GraphicsDefs.h
+    // enum VertexElementType | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("VertexElementType");
     engine->RegisterEnumValue("VertexElementType", "TYPE_INT", TYPE_INT);
     engine->RegisterEnumValue("VertexElementType", "TYPE_FLOAT", TYPE_FLOAT);
@@ -1845,7 +1845,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterEnumValue("VertexLightVSVariation", "VLVS_4LIGHTS", VLVS_4LIGHTS);
     engine->RegisterEnumValue("VertexLightVSVariation", "MAX_VERTEXLIGHT_VS_VARIATIONS", MAX_VERTEXLIGHT_VS_VARIATIONS);
 
-    // enum VertexMask : u32 | File: ../Graphics/GraphicsDefs.h
+    // enum VertexMask : u32 | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterTypedef("VertexMask", "uint");
     engine->RegisterGlobalProperty("const uint MASK_NONE", (void*)&VertexMask_MASK_NONE);
     engine->RegisterGlobalProperty("const uint MASK_POSITION", (void*)&VertexMask_MASK_POSITION);
@@ -1863,7 +1863,7 @@ void ASRegisterGeneratedEnums(asIScriptEngine* engine)
     engine->RegisterGlobalProperty("const uint MASK_INSTANCEMATRIX3", (void*)&VertexMask_MASK_INSTANCEMATRIX3);
     engine->RegisterGlobalProperty("const uint MASK_OBJECTINDEX", (void*)&VertexMask_MASK_OBJECTINDEX);
 
-    // URHO3D_FLAGSET(VertexMask, VertexMaskFlags) | File: ../Graphics/GraphicsDefs.h
+    // URHO3D_FLAGSET(VertexMask, VertexMaskFlags) | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterTypedef("VertexMaskFlags", "uint");
 
     // enum VerticalAlignment | File: ../UI/UIElement.h

+ 64 - 64
Source/Urho3D/AngelScript/Generated_GlobalVariables.cpp

@@ -16,7 +16,7 @@ void ASRegisterGeneratedGlobalVariables(asIScriptEngine* engine)
     // static const float ANIMATION_LOD_BASESCALE | File: ../Graphics/Drawable.h
     engine->RegisterGlobalProperty("const float ANIMATION_LOD_BASESCALE", (void*)&ANIMATION_LOD_BASESCALE);
 
-    // constexpr i32 BITS_PER_COMPONENT | File: ../Graphics/GraphicsDefs.h
+    // constexpr i32 BITS_PER_COMPONENT | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const int BITS_PER_COMPONENT", (void*)&BITS_PER_COMPONENT);
 
     // static const int COLOR_LUT_SIZE | File: ../Resource/Image.h
@@ -79,7 +79,7 @@ void ASRegisterGeneratedGlobalVariables(asIScriptEngine* engine)
     // static const unsigned DEFAULT_ZONEMASK | File: ../Graphics/Drawable.h
     engine->RegisterGlobalProperty("const uint DEFAULT_ZONEMASK", (void*)&DEFAULT_ZONEMASK);
 
-    // const Vector3 DOT_SCALE | File: ../Graphics/GraphicsDefs.h
+    // const Vector3 DOT_SCALE | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const Vector3 DOT_SCALE", (void*)&DOT_SCALE);
 
     // static const unsigned DRAWABLE_ANY | File: ../Graphics/Drawable.h
@@ -100,7 +100,7 @@ void ASRegisterGeneratedGlobalVariables(asIScriptEngine* engine)
     // static const unsigned DRAWABLE_ZONE | File: ../Graphics/Drawable.h
     engine->RegisterGlobalProperty("const uint DRAWABLE_ZONE", (void*)&DRAWABLE_ZONE);
 
-    // const u32 ELEMENT_TYPESIZES[] | File: ../Graphics/GraphicsDefs.h
+    // const u32 ELEMENT_TYPESIZES[] | File: ../GraphicsAPI/GraphicsDefs.h
     // Not registered because array
 
     // static const String EP_AUTOLOAD_PATHS | File: ../Engine/EngineDefs.h
@@ -274,7 +274,7 @@ void ASRegisterGeneratedGlobalVariables(asIScriptEngine* engine)
     // static const unsigned LAST_REPLICATED_ID | File: ../Scene/Scene.h
     engine->RegisterGlobalProperty("const uint LAST_REPLICATED_ID", (void*)&LAST_REPLICATED_ID);
 
-    // const VertexElement LEGACY_VERTEXELEMENTS[] | File: ../Graphics/GraphicsDefs.h
+    // const VertexElement LEGACY_VERTEXELEMENTS[] | File: ../GraphicsAPI/GraphicsDefs.h
     // Not registered because array
 
     // static const int LOG_DEBUG | File: ../IO/Log.h
@@ -304,7 +304,7 @@ void ASRegisterGeneratedGlobalVariables(asIScriptEngine* engine)
     // static const unsigned MAX_CASCADE_SPLITS | File: ../Graphics/Light.h
     engine->RegisterGlobalProperty("const uint MAX_CASCADE_SPLITS", (void*)&MAX_CASCADE_SPLITS);
 
-    // constexpr i32 MAX_CONSTANT_REGISTERS | File: ../Graphics/GraphicsDefs.h
+    // constexpr i32 MAX_CONSTANT_REGISTERS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const int MAX_CONSTANT_REGISTERS", (void*)&MAX_CONSTANT_REGISTERS);
 
     // static const int MAX_LIGHT_SPLITS | File: ../Graphics/Light.h
@@ -313,16 +313,16 @@ void ASRegisterGeneratedGlobalVariables(asIScriptEngine* engine)
     // static const unsigned MAX_NETWORK_ATTRIBUTES | File: ../Scene/ReplicationState.h
     engine->RegisterGlobalProperty("const uint MAX_NETWORK_ATTRIBUTES", (void*)&MAX_NETWORK_ATTRIBUTES);
 
-    // constexpr i32 MAX_RENDERTARGETS | File: ../Graphics/GraphicsDefs.h
+    // constexpr i32 MAX_RENDERTARGETS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const int MAX_RENDERTARGETS", (void*)&MAX_RENDERTARGETS);
 
-    // static const int MAX_TEXTURE_QUALITY_LEVELS | File: ../Graphics/Texture.h
+    // static const int MAX_TEXTURE_QUALITY_LEVELS | File: ../GraphicsAPI/Texture.h
     engine->RegisterGlobalProperty("const int MAX_TEXTURE_QUALITY_LEVELS", (void*)&MAX_TEXTURE_QUALITY_LEVELS);
 
     // static const int MAX_VERTEX_LIGHTS | File: ../Graphics/Drawable.h
     engine->RegisterGlobalProperty("const int MAX_VERTEX_LIGHTS", (void*)&MAX_VERTEX_LIGHTS);
 
-    // constexpr i32 MAX_VERTEX_STREAMS | File: ../Graphics/GraphicsDefs.h
+    // constexpr i32 MAX_VERTEX_STREAMS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const int MAX_VERTEX_STREAMS", (void*)&MAX_VERTEX_STREAMS);
 
     // static const unsigned MAX_VIEWPORT_TEXTURES | File: ../Graphics/View.h
@@ -406,97 +406,97 @@ void ASRegisterGeneratedGlobalVariables(asIScriptEngine* engine)
     // static const unsigned PRIORITY_LAST | File: ../Resource/ResourceCache.h
     engine->RegisterGlobalProperty("const uint PRIORITY_LAST", (void*)&PRIORITY_LAST);
 
-    // const StringHash PSP_AMBIENTCOLOR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_AMBIENTCOLOR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_AMBIENTCOLOR", (void*)&PSP_AMBIENTCOLOR);
 
-    // const StringHash PSP_CAMERAPOS | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_CAMERAPOS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_CAMERAPOS", (void*)&PSP_CAMERAPOS);
 
-    // const StringHash PSP_DELTATIME | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_DELTATIME | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_DELTATIME", (void*)&PSP_DELTATIME);
 
-    // const StringHash PSP_DEPTHRECONSTRUCT | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_DEPTHRECONSTRUCT | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_DEPTHRECONSTRUCT", (void*)&PSP_DEPTHRECONSTRUCT);
 
-    // const StringHash PSP_ELAPSEDTIME | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_ELAPSEDTIME | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_ELAPSEDTIME", (void*)&PSP_ELAPSEDTIME);
 
-    // const StringHash PSP_FARCLIP | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_FARCLIP | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_FARCLIP", (void*)&PSP_FARCLIP);
 
-    // const StringHash PSP_FOGCOLOR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_FOGCOLOR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_FOGCOLOR", (void*)&PSP_FOGCOLOR);
 
-    // const StringHash PSP_FOGPARAMS | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_FOGPARAMS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_FOGPARAMS", (void*)&PSP_FOGPARAMS);
 
-    // const StringHash PSP_GBUFFERINVSIZE | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_GBUFFERINVSIZE | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_GBUFFERINVSIZE", (void*)&PSP_GBUFFERINVSIZE);
 
-    // const StringHash PSP_LIGHTCOLOR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_LIGHTCOLOR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_LIGHTCOLOR", (void*)&PSP_LIGHTCOLOR);
 
-    // const StringHash PSP_LIGHTDIR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_LIGHTDIR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_LIGHTDIR", (void*)&PSP_LIGHTDIR);
 
-    // const StringHash PSP_LIGHTLENGTH | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_LIGHTLENGTH | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_LIGHTLENGTH", (void*)&PSP_LIGHTLENGTH);
 
-    // const StringHash PSP_LIGHTMATRICES | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_LIGHTMATRICES | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_LIGHTMATRICES", (void*)&PSP_LIGHTMATRICES);
 
-    // const StringHash PSP_LIGHTPOS | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_LIGHTPOS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_LIGHTPOS", (void*)&PSP_LIGHTPOS);
 
-    // const StringHash PSP_LIGHTRAD | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_LIGHTRAD | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_LIGHTRAD", (void*)&PSP_LIGHTRAD);
 
-    // const StringHash PSP_MATDIFFCOLOR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_MATDIFFCOLOR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_MATDIFFCOLOR", (void*)&PSP_MATDIFFCOLOR);
 
-    // const StringHash PSP_MATEMISSIVECOLOR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_MATEMISSIVECOLOR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_MATEMISSIVECOLOR", (void*)&PSP_MATEMISSIVECOLOR);
 
-    // const StringHash PSP_MATENVMAPCOLOR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_MATENVMAPCOLOR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_MATENVMAPCOLOR", (void*)&PSP_MATENVMAPCOLOR);
 
-    // const StringHash PSP_MATSPECCOLOR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_MATSPECCOLOR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_MATSPECCOLOR", (void*)&PSP_MATSPECCOLOR);
 
-    // const StringHash PSP_METALLIC | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_METALLIC | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_METALLIC", (void*)&PSP_METALLIC);
 
-    // const StringHash PSP_NEARCLIP | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_NEARCLIP | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_NEARCLIP", (void*)&PSP_NEARCLIP);
 
-    // const StringHash PSP_NORMALOFFSETSCALE | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_NORMALOFFSETSCALE | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_NORMALOFFSETSCALE", (void*)&PSP_NORMALOFFSETSCALE);
 
-    // const StringHash PSP_ROUGHNESS | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_ROUGHNESS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_ROUGHNESS", (void*)&PSP_ROUGHNESS);
 
-    // const StringHash PSP_SHADOWCUBEADJUST | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_SHADOWCUBEADJUST | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_SHADOWCUBEADJUST", (void*)&PSP_SHADOWCUBEADJUST);
 
-    // const StringHash PSP_SHADOWDEPTHFADE | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_SHADOWDEPTHFADE | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_SHADOWDEPTHFADE", (void*)&PSP_SHADOWDEPTHFADE);
 
-    // const StringHash PSP_SHADOWINTENSITY | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_SHADOWINTENSITY | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_SHADOWINTENSITY", (void*)&PSP_SHADOWINTENSITY);
 
-    // const StringHash PSP_SHADOWMAPINVSIZE | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_SHADOWMAPINVSIZE | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_SHADOWMAPINVSIZE", (void*)&PSP_SHADOWMAPINVSIZE);
 
-    // const StringHash PSP_SHADOWSPLITS | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_SHADOWSPLITS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_SHADOWSPLITS", (void*)&PSP_SHADOWSPLITS);
 
-    // const StringHash PSP_VSMSHADOWPARAMS | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_VSMSHADOWPARAMS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_VSMSHADOWPARAMS", (void*)&PSP_VSMSHADOWPARAMS);
 
-    // const StringHash PSP_ZONEMAX | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_ZONEMAX | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_ZONEMAX", (void*)&PSP_ZONEMAX);
 
-    // const StringHash PSP_ZONEMIN | File: ../Graphics/GraphicsDefs.h
+    // const StringHash PSP_ZONEMIN | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash PSP_ZONEMIN", (void*)&PSP_ZONEMIN);
 
     // static const int QUICKSORT_THRESHOLD | File: ../Container/Sort.h
@@ -547,79 +547,79 @@ void ASRegisterGeneratedGlobalVariables(asIScriptEngine* engine)
     // static const unsigned VARIANT_VALUE_SIZE | File: ../Core/Variant.h
     engine->RegisterGlobalProperty("const uint VARIANT_VALUE_SIZE", (void*)&VARIANT_VALUE_SIZE);
 
-    // const StringHash VSP_AMBIENTENDCOLOR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_AMBIENTENDCOLOR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_AMBIENTENDCOLOR", (void*)&VSP_AMBIENTENDCOLOR);
 
-    // const StringHash VSP_AMBIENTSTARTCOLOR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_AMBIENTSTARTCOLOR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_AMBIENTSTARTCOLOR", (void*)&VSP_AMBIENTSTARTCOLOR);
 
-    // const StringHash VSP_BILLBOARDROT | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_BILLBOARDROT | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_BILLBOARDROT", (void*)&VSP_BILLBOARDROT);
 
-    // const StringHash VSP_CAMERAPOS | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_CAMERAPOS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_CAMERAPOS", (void*)&VSP_CAMERAPOS);
 
-    // const StringHash VSP_CLIPPLANE | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_CLIPPLANE | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_CLIPPLANE", (void*)&VSP_CLIPPLANE);
 
-    // const StringHash VSP_DELTATIME | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_DELTATIME | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_DELTATIME", (void*)&VSP_DELTATIME);
 
-    // const StringHash VSP_DEPTHMODE | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_DEPTHMODE | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_DEPTHMODE", (void*)&VSP_DEPTHMODE);
 
-    // const StringHash VSP_ELAPSEDTIME | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_ELAPSEDTIME | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_ELAPSEDTIME", (void*)&VSP_ELAPSEDTIME);
 
-    // const StringHash VSP_FARCLIP | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_FARCLIP | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_FARCLIP", (void*)&VSP_FARCLIP);
 
-    // const StringHash VSP_FRUSTUMSIZE | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_FRUSTUMSIZE | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_FRUSTUMSIZE", (void*)&VSP_FRUSTUMSIZE);
 
-    // const StringHash VSP_GBUFFEROFFSETS | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_GBUFFEROFFSETS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_GBUFFEROFFSETS", (void*)&VSP_GBUFFEROFFSETS);
 
-    // const StringHash VSP_LIGHTDIR | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_LIGHTDIR | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_LIGHTDIR", (void*)&VSP_LIGHTDIR);
 
-    // const StringHash VSP_LIGHTMATRICES | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_LIGHTMATRICES | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_LIGHTMATRICES", (void*)&VSP_LIGHTMATRICES);
 
-    // const StringHash VSP_LIGHTPOS | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_LIGHTPOS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_LIGHTPOS", (void*)&VSP_LIGHTPOS);
 
-    // const StringHash VSP_MODEL | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_MODEL | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_MODEL", (void*)&VSP_MODEL);
 
-    // const StringHash VSP_NEARCLIP | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_NEARCLIP | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_NEARCLIP", (void*)&VSP_NEARCLIP);
 
-    // const StringHash VSP_NORMALOFFSETSCALE | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_NORMALOFFSETSCALE | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_NORMALOFFSETSCALE", (void*)&VSP_NORMALOFFSETSCALE);
 
-    // const StringHash VSP_SKINMATRICES | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_SKINMATRICES | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_SKINMATRICES", (void*)&VSP_SKINMATRICES);
 
-    // const StringHash VSP_UOFFSET | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_UOFFSET | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_UOFFSET", (void*)&VSP_UOFFSET);
 
-    // const StringHash VSP_VERTEXLIGHTS | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_VERTEXLIGHTS | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_VERTEXLIGHTS", (void*)&VSP_VERTEXLIGHTS);
 
-    // const StringHash VSP_VIEW | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_VIEW | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_VIEW", (void*)&VSP_VIEW);
 
-    // const StringHash VSP_VIEWINV | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_VIEWINV | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_VIEWINV", (void*)&VSP_VIEWINV);
 
-    // const StringHash VSP_VIEWPROJ | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_VIEWPROJ | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_VIEWPROJ", (void*)&VSP_VIEWPROJ);
 
-    // const StringHash VSP_VOFFSET | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_VOFFSET | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_VOFFSET", (void*)&VSP_VOFFSET);
 
-    // const StringHash VSP_ZONE | File: ../Graphics/GraphicsDefs.h
+    // const StringHash VSP_ZONE | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterGlobalProperty("const StringHash VSP_ZONE", (void*)&VSP_ZONE);
 
 #ifdef URHO3D_NETWORK

+ 16 - 16
Source/Urho3D/AngelScript/Generated_Includes.h

@@ -51,16 +51,12 @@
 #include "../Graphics/Batch.h"
 #include "../Graphics/BillboardSet.h"
 #include "../Graphics/Camera.h"
-#include "../Graphics/ConstantBuffer.h"
 #include "../Graphics/CustomGeometry.h"
 #include "../Graphics/DebugRenderer.h"
 #include "../Graphics/DecalSet.h"
 #include "../Graphics/Drawable.h"
-#include "../Graphics/GPUObject.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Graphics.h"
-#include "../Graphics/GraphicsDefs.h"
-#include "../Graphics/IndexBuffer.h"
 #include "../Graphics/Light.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/Model.h"
@@ -70,12 +66,8 @@
 #include "../Graphics/ParticleEffect.h"
 #include "../Graphics/ParticleEmitter.h"
 #include "../Graphics/RenderPath.h"
-#include "../Graphics/RenderSurface.h"
 #include "../Graphics/Renderer.h"
 #include "../Graphics/RibbonTrail.h"
-#include "../Graphics/Shader.h"
-#include "../Graphics/ShaderPrecache.h"
-#include "../Graphics/ShaderVariation.h"
 #include "../Graphics/Skeleton.h"
 #include "../Graphics/Skybox.h"
 #include "../Graphics/StaticModel.h"
@@ -84,15 +76,23 @@
 #include "../Graphics/Technique.h"
 #include "../Graphics/Terrain.h"
 #include "../Graphics/TerrainPatch.h"
-#include "../Graphics/Texture.h"
-#include "../Graphics/Texture2D.h"
-#include "../Graphics/Texture2DArray.h"
-#include "../Graphics/Texture3D.h"
-#include "../Graphics/TextureCube.h"
-#include "../Graphics/VertexBuffer.h"
 #include "../Graphics/View.h"
 #include "../Graphics/Viewport.h"
 #include "../Graphics/Zone.h"
+#include "../GraphicsAPI/ConstantBuffer.h"
+#include "../GraphicsAPI/GPUObject.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/RenderSurface.h"
+#include "../GraphicsAPI/Shader.h"
+#include "../GraphicsAPI/ShaderPrecache.h"
+#include "../GraphicsAPI/ShaderVariation.h"
+#include "../GraphicsAPI/Texture.h"
+#include "../GraphicsAPI/Texture2D.h"
+#include "../GraphicsAPI/Texture2DArray.h"
+#include "../GraphicsAPI/Texture3D.h"
+#include "../GraphicsAPI/TextureCube.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 
 #ifdef URHO3D_IK
 #include "../IK/IK.h"
@@ -267,8 +267,8 @@
 //#include "../Database/ODBC/ODBCConnection.h"
 //#include "../Database/ODBC/ODBCResult.h"
 //#include "../Engine/Application.h"
-//#include "../Graphics/OpenGL/OGLGraphicsImpl.h"
-//#include "../Graphics/OpenGL/OGLShaderProgram.h"
+//#include "../GraphicsAPI/OpenGL/OGLGraphicsImpl.h"
+//#include "../GraphicsAPI/OpenGL/OGLShaderProgram.h"
 
 //#ifdef URHO3D_IK
 //#include "../IK/IKConverters.h"

+ 15 - 15
Source/Urho3D/AngelScript/Generated_Members.h

@@ -1582,7 +1582,7 @@ template <class T> void RegisterMembers_Frustum(asIScriptEngine* engine, const c
     #endif
 }
 
-// class GPUObject | File: ../Graphics/GPUObject.h
+// class GPUObject | File: ../GraphicsAPI/GPUObject.h
 template <class T> void RegisterMembers_GPUObject(asIScriptEngine* engine, const char* className)
 {
     // void* GPUObject::GetGPUObject() const
@@ -4429,7 +4429,7 @@ template <class T> void RegisterMembers_Serializer(asIScriptEngine* engine, cons
     #endif
 }
 
-// struct ShaderParameter | File: ../Graphics/ShaderVariation.h
+// struct ShaderParameter | File: ../GraphicsAPI/ShaderVariation.h
 template <class T> void RegisterMembers_ShaderParameter(asIScriptEngine* engine, const char* className)
 {
     // union ShaderParameter::@? Urho3D::ShaderParameter::@?
@@ -6440,7 +6440,7 @@ template <class T> void RegisterMembers_VertexBufferMorph(asIScriptEngine* engin
     #endif
 }
 
-// struct VertexElement | File: ../Graphics/GraphicsDefs.h
+// struct VertexElement | File: ../GraphicsAPI/GraphicsDefs.h
 template <class T> void RegisterMembers_VertexElement(asIScriptEngine* engine, const char* className)
 {
     // bool VertexElement::operator !=(const VertexElement& rhs) const
@@ -8379,7 +8379,7 @@ template <class T> void RegisterMembers_RenderPath(asIScriptEngine* engine, cons
     #endif
 }
 
-// class RenderSurface | File: ../Graphics/RenderSurface.h
+// class RenderSurface | File: ../GraphicsAPI/RenderSurface.h
 template <class T> void RegisterMembers_RenderSurface(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_RefCounted<T>(engine, className);
@@ -8518,7 +8518,7 @@ template <class T> void RegisterMembers_SceneReplicationState(asIScriptEngine* e
     #endif
 }
 
-// class ShaderVariation | File: ../Graphics/ShaderVariation.h
+// class ShaderVariation | File: ../GraphicsAPI/ShaderVariation.h
 template <class T> void RegisterMembers_ShaderVariation(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_RefCounted<T>(engine, className);
@@ -9200,7 +9200,7 @@ template <class T> void RegisterMembers_Console(asIScriptEngine* engine, const c
     #endif
 }
 
-// class ConstantBuffer | File: ../Graphics/ConstantBuffer.h
+// class ConstantBuffer | File: ../GraphicsAPI/ConstantBuffer.h
 template <class T> void RegisterMembers_ConstantBuffer(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_Object<T>(engine, className);
@@ -10525,7 +10525,7 @@ template <class T> void RegisterMembers_Graphics(asIScriptEngine* engine, const
     #endif
 }
 
-// class IndexBuffer | File: ../Graphics/IndexBuffer.h
+// class IndexBuffer | File: ../GraphicsAPI/IndexBuffer.h
 template <class T> void RegisterMembers_IndexBuffer(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_Object<T>(engine, className);
@@ -11942,7 +11942,7 @@ template <class T> void RegisterMembers_ShaderParameterAnimationInfo(asIScriptEn
     #endif
 }
 
-// class ShaderPrecache | File: ../Graphics/ShaderPrecache.h
+// class ShaderPrecache | File: ../GraphicsAPI/ShaderPrecache.h
 template <class T> void RegisterMembers_ShaderPrecache(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_Object<T>(engine, className);
@@ -12344,7 +12344,7 @@ template <class T> unsigned VertexBuffer_unsigned_GetVertexSize_constspPODVector
     return result;
 }
 
-// class VertexBuffer | File: ../Graphics/VertexBuffer.h
+// class VertexBuffer | File: ../GraphicsAPI/VertexBuffer.h
 template <class T> void RegisterMembers_VertexBuffer(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_Object<T>(engine, className);
@@ -14233,7 +14233,7 @@ template <class T> void RegisterMembers_ResourceWithMetadata(asIScriptEngine* en
     #endif
 }
 
-// class Shader | File: ../Graphics/Shader.h
+// class Shader | File: ../GraphicsAPI/Shader.h
 template <class T> void RegisterMembers_Shader(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_Resource<T>(engine, className);
@@ -15973,7 +15973,7 @@ template <class T> void RegisterMembers_Sound(asIScriptEngine* engine, const cha
     #endif
 }
 
-// class Texture | File: ../Graphics/Texture.h
+// class Texture | File: ../GraphicsAPI/Texture.h
 template <class T> void RegisterMembers_Texture(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_ResourceWithMetadata<T>(engine, className);
@@ -18815,7 +18815,7 @@ template <class T> Image* Texture2D_SharedPtrlesImagegre_GetImage_void_template(
     return result.Detach();
 }
 
-// class Texture2D | File: ../Graphics/Texture2D.h
+// class Texture2D | File: ../GraphicsAPI/Texture2D.h
 template <class T> void RegisterMembers_Texture2D(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_Texture<T>(engine, className);
@@ -18849,7 +18849,7 @@ template <class T> void RegisterMembers_Texture2D(asIScriptEngine* engine, const
     #endif
 }
 
-// class Texture2DArray | File: ../Graphics/Texture2DArray.h
+// class Texture2DArray | File: ../GraphicsAPI/Texture2DArray.h
 template <class T> void RegisterMembers_Texture2DArray(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_Texture<T>(engine, className);
@@ -18888,7 +18888,7 @@ template <class T> void RegisterMembers_Texture2DArray(asIScriptEngine* engine,
     #endif
 }
 
-// class Texture3D | File: ../Graphics/Texture3D.h
+// class Texture3D | File: ../GraphicsAPI/Texture3D.h
 template <class T> void RegisterMembers_Texture3D(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_Texture<T>(engine, className);
@@ -18919,7 +18919,7 @@ template <class T> Image* TextureCube_SharedPtrlesImagegre_GetImage_CubeMapFace_
     return result.Detach();
 }
 
-// class TextureCube | File: ../Graphics/TextureCube.h
+// class TextureCube | File: ../GraphicsAPI/TextureCube.h
 template <class T> void RegisterMembers_TextureCube(asIScriptEngine* engine, const char* className)
 {
     RegisterMembers_Texture<T>(engine, className);

+ 15 - 15
Source/Urho3D/AngelScript/Generated_ObjectTypes.cpp

@@ -138,7 +138,7 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // class Frustum | File: ../Math/Frustum.h
     engine->RegisterObjectType("Frustum", sizeof(Frustum), asOBJ_VALUE | asGetTypeTraits<Frustum>());
 
-    // class GPUObject | File: ../Graphics/GPUObject.h
+    // class GPUObject | File: ../GraphicsAPI/GPUObject.h
     engine->RegisterObjectType("GPUObject", sizeof(GPUObject), asOBJ_VALUE | asGetTypeTraits<GPUObject>());
 
     // struct GeometryDesc | File: ../Graphics/Model.h
@@ -315,7 +315,7 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // class Serializer | File: ../IO/Serializer.h
     engine->RegisterObjectType("Serializer", 0, asOBJ_REF | asOBJ_NOCOUNT);
 
-    // struct ShaderParameter | File: ../Graphics/ShaderVariation.h
+    // struct ShaderParameter | File: ../GraphicsAPI/ShaderVariation.h
     engine->RegisterObjectType("ShaderParameter", sizeof(ShaderParameter), asOBJ_VALUE | asGetTypeTraits<ShaderParameter>());
 
     // struct ShadowBatchQueue | File: ../Graphics/Batch.h
@@ -399,7 +399,7 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // struct VertexBufferMorph | File: ../Graphics/Model.h
     engine->RegisterObjectType("VertexBufferMorph", sizeof(VertexBufferMorph), asOBJ_VALUE | asGetTypeTraits<VertexBufferMorph>());
 
-    // struct VertexElement | File: ../Graphics/GraphicsDefs.h
+    // struct VertexElement | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterObjectType("VertexElement", sizeof(VertexElement), asOBJ_VALUE | asGetTypeTraits<VertexElement>());
 
     // class WString | File: ../Container/Str.h
@@ -544,13 +544,13 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // class RenderPath | File: ../Graphics/RenderPath.h
     engine->RegisterObjectType("RenderPath", 0, asOBJ_REF);
 
-    // class RenderSurface | File: ../Graphics/RenderSurface.h
+    // class RenderSurface | File: ../GraphicsAPI/RenderSurface.h
     engine->RegisterObjectType("RenderSurface", 0, asOBJ_REF);
 
     // struct SceneReplicationState | File: ../Scene/ReplicationState.h
     engine->RegisterObjectType("SceneReplicationState", sizeof(SceneReplicationState), asOBJ_VALUE | asGetTypeTraits<SceneReplicationState>());
 
-    // class ShaderVariation | File: ../Graphics/ShaderVariation.h
+    // class ShaderVariation | File: ../GraphicsAPI/ShaderVariation.h
     engine->RegisterObjectType("ShaderVariation", 0, asOBJ_REF);
 
     // class SoundStream | File: ../Audio/SoundStream.h
@@ -609,7 +609,7 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // class Console | File: ../Engine/Console.h
     engine->RegisterObjectType("Console", 0, asOBJ_REF);
 
-    // class ConstantBuffer | File: ../Graphics/ConstantBuffer.h
+    // class ConstantBuffer | File: ../GraphicsAPI/ConstantBuffer.h
     engine->RegisterObjectType("ConstantBuffer", 0, asOBJ_REF);
 
     // class DebugHud | File: ../Engine/DebugHud.h
@@ -645,7 +645,7 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // class Graphics | File: ../Graphics/Graphics.h
     engine->RegisterObjectType("Graphics", 0, asOBJ_REF);
 
-    // class IndexBuffer | File: ../Graphics/IndexBuffer.h
+    // class IndexBuffer | File: ../GraphicsAPI/IndexBuffer.h
     engine->RegisterObjectType("IndexBuffer", 0, asOBJ_REF);
 
     // class Input | File: ../Input/Input.h
@@ -696,7 +696,7 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // class ShaderParameterAnimationInfo | File: ../Graphics/Material.h
     engine->RegisterObjectType("ShaderParameterAnimationInfo", 0, asOBJ_REF);
 
-    // class ShaderPrecache | File: ../Graphics/ShaderPrecache.h
+    // class ShaderPrecache | File: ../GraphicsAPI/ShaderPrecache.h
     engine->RegisterObjectType("ShaderPrecache", 0, asOBJ_REF);
 
     // class Time | File: ../Core/Timer.h
@@ -708,7 +708,7 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // class VectorBuffer | File: ../IO/VectorBuffer.h
     engine->RegisterObjectType("VectorBuffer", sizeof(VectorBuffer), asOBJ_VALUE | asGetTypeTraits<VectorBuffer>());
 
-    // class VertexBuffer | File: ../Graphics/VertexBuffer.h
+    // class VertexBuffer | File: ../GraphicsAPI/VertexBuffer.h
     engine->RegisterObjectType("VertexBuffer", 0, asOBJ_REF);
 
     // class View | File: ../Graphics/View.h
@@ -785,7 +785,7 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // class ResourceWithMetadata | File: ../Resource/Resource.h
     engine->RegisterObjectType("ResourceWithMetadata", 0, asOBJ_REF);
 
-    // class Shader | File: ../Graphics/Shader.h
+    // class Shader | File: ../GraphicsAPI/Shader.h
     engine->RegisterObjectType("Shader", 0, asOBJ_REF);
 
     // class Technique | File: ../Graphics/Technique.h
@@ -829,7 +829,7 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // class Sound | File: ../Audio/Sound.h
     engine->RegisterObjectType("Sound", 0, asOBJ_REF);
 
-    // class Texture | File: ../Graphics/Texture.h
+    // class Texture | File: ../GraphicsAPI/Texture.h
     engine->RegisterObjectType("Texture", 0, asOBJ_REF);
 
     // class UIElement | File: ../UI/UIElement.h
@@ -880,16 +880,16 @@ void ASRegisterGeneratedObjectTypes(asIScriptEngine* engine)
     // class Terrain | File: ../Graphics/Terrain.h
     engine->RegisterObjectType("Terrain", 0, asOBJ_REF);
 
-    // class Texture2D | File: ../Graphics/Texture2D.h
+    // class Texture2D | File: ../GraphicsAPI/Texture2D.h
     engine->RegisterObjectType("Texture2D", 0, asOBJ_REF);
 
-    // class Texture2DArray | File: ../Graphics/Texture2DArray.h
+    // class Texture2DArray | File: ../GraphicsAPI/Texture2DArray.h
     engine->RegisterObjectType("Texture2DArray", 0, asOBJ_REF);
 
-    // class Texture3D | File: ../Graphics/Texture3D.h
+    // class Texture3D | File: ../GraphicsAPI/Texture3D.h
     engine->RegisterObjectType("Texture3D", 0, asOBJ_REF);
 
-    // class TextureCube | File: ../Graphics/TextureCube.h
+    // class TextureCube | File: ../GraphicsAPI/TextureCube.h
     engine->RegisterObjectType("TextureCube", 0, asOBJ_REF);
 
     // class ToolTip | File: ../UI/ToolTip.h

+ 1 - 1
Source/Urho3D/AngelScript/Manual_Graphics.cpp

@@ -33,7 +33,7 @@ namespace Urho3D
 // This function is called before ASRegisterGenerated()
 void ASRegisterManualFirst_Graphics(asIScriptEngine* engine)
 {
-    // enum TextureUnit | File: ../Graphics/GraphicsDefs.h
+    // enum TextureUnit | File: ../GraphicsAPI/GraphicsDefs.h
     engine->RegisterEnum("TextureUnit");
     engine->RegisterEnumValue("TextureUnit", "TU_DIFFUSE", TU_DIFFUSE);
     engine->RegisterEnumValue("TextureUnit", "TU_ALBEDOBUFFER", TU_ALBEDOBUFFER);

+ 20 - 20
Source/Urho3D/AngelScript/Manual_Graphics.h

@@ -22,24 +22,24 @@
 
 #pragma once
 
-#include "../Graphics/AnimationController.h"
-#include "../Graphics/IndexBuffer.h"
-#include "../Graphics/RenderPath.h"
-#include "../Graphics/Texture2D.h"
+#include "../Graphics/AnimatedModel.h"
 #include "../Graphics/Animation.h"
-#include "../Graphics/AnimationState.h"
 #include "../Graphics/AnimationController.h"
-#include "../Graphics/GraphicsDefs.h"
-#include "../Graphics/Model.h"
-#include "../Graphics/AnimatedModel.h"
-#include "../Graphics/ParticleEffect.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../Graphics/AnimationController.h"
+#include "../Graphics/AnimationState.h"
 #include "../Graphics/Graphics.h"
+#include "../Graphics/Material.h"
+#include "../Graphics/Model.h"
 #include "../Graphics/Octree.h"
-#include "../Graphics/TextureCube.h"
+#include "../Graphics/ParticleEffect.h"
 #include "../Graphics/Renderer.h"
+#include "../Graphics/RenderPath.h"
 #include "../Graphics/Technique.h"
-#include "../Graphics/Material.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/Texture2D.h"
+#include "../GraphicsAPI/TextureCube.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 
 namespace Urho3D
 {
@@ -156,7 +156,7 @@ template <class T> VectorBuffer VertexBuffer_GetData(T* ptr)
     return ret;
 }
 
-// bool VertexBuffer::SetData(const void* data) | File: ../Graphics/VertexBuffer.h
+// bool VertexBuffer::SetData(const void* data) | File: ../GraphicsAPI/VertexBuffer.h
 template <class T> bool VertexBuffer_SetData(VectorBuffer& src, T* ptr)
 {
     // Make sure there is enough data
@@ -166,7 +166,7 @@ template <class T> bool VertexBuffer_SetData(VectorBuffer& src, T* ptr)
         return false;
 }
 
-// bool VertexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard = false) | File: ../Graphics/VertexBuffer.h
+// bool VertexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard = false) | File: ../GraphicsAPI/VertexBuffer.h
 template <class T> bool VertexBuffer_SetDataRange(VectorBuffer& src, unsigned start, unsigned count, bool discard, T* ptr)
 {
     // Make sure there is enough data
@@ -179,10 +179,10 @@ template <class T> bool VertexBuffer_SetDataRange(VectorBuffer& src, unsigned st
 #define REGISTER_MEMBERS_MANUAL_PART_VertexBuffer() \
     engine->RegisterObjectMethod(className, "VectorBuffer GetData() const", AS_FUNCTION_OBJLAST(VertexBuffer_GetData<T>), AS_CALL_CDECL_OBJLAST); \
     \
-    /* bool VertexBuffer::SetData(const void* data) | File: ../Graphics/VertexBuffer.h */ \
+    /* bool VertexBuffer::SetData(const void* data) | File: ../GraphicsAPI/VertexBuffer.h */ \
     engine->RegisterObjectMethod(className, "bool SetData(VectorBuffer&)", AS_FUNCTION_OBJLAST(VertexBuffer_SetData<T>), AS_CALL_CDECL_OBJLAST); \
     \
-    /* bool VertexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard = false) | File: ../Graphics/VertexBuffer.h */ \
+    /* bool VertexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard = false) | File: ../GraphicsAPI/VertexBuffer.h */ \
     engine->RegisterObjectMethod(className, "bool SetDataRange(VectorBuffer&, uint, uint, bool = false)", AS_FUNCTION_OBJLAST(VertexBuffer_SetDataRange<T>), AS_CALL_CDECL_OBJLAST);
 
 // ========================================================================================
@@ -202,7 +202,7 @@ template <class T> VectorBuffer IndexBuffer_GetData(T* ptr)
     return ret;
 }
 
-// bool IndexBuffer::SetData(const void* data) | File: ../Graphics/IndexBuffer.h
+// bool IndexBuffer::SetData(const void* data) | File: ../GraphicsAPI/IndexBuffer.h
 template <class T> bool IndexBuffer_SetData(VectorBuffer& src, T* ptr)
 {
     // Make sure there is enough data
@@ -212,7 +212,7 @@ template <class T> bool IndexBuffer_SetData(VectorBuffer& src, T* ptr)
         return false;
 }
 
-// bool IndexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard = false) | File: ../Graphics/IndexBuffer.h
+// bool IndexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard = false) | File: ../GraphicsAPI/IndexBuffer.h
 template <class T> bool IndexBuffer_SetDataRange(VectorBuffer& src, unsigned start, unsigned count, bool discard, T* ptr)
 {
     // Make sure there is enough data
@@ -225,10 +225,10 @@ template <class T> bool IndexBuffer_SetDataRange(VectorBuffer& src, unsigned sta
 #define REGISTER_MEMBERS_MANUAL_PART_IndexBuffer() \
     engine->RegisterObjectMethod(className, "VectorBuffer GetData()", AS_FUNCTION_OBJLAST(IndexBuffer_GetData<T>), AS_CALL_CDECL_OBJLAST); \
     \
-    /* bool IndexBuffer::SetData(const void* data) | File: ../Graphics/IndexBuffer.h */ \
+    /* bool IndexBuffer::SetData(const void* data) | File: ../GraphicsAPI/IndexBuffer.h */ \
     engine->RegisterObjectMethod(className, "bool SetData(VectorBuffer&)", AS_FUNCTION_OBJLAST(IndexBuffer_SetData<T>), AS_CALL_CDECL_OBJLAST); \
     \
-    /* bool IndexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard = false) | File: ../Graphics/IndexBuffer.h */ \
+    /* bool IndexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard = false) | File: ../GraphicsAPI/IndexBuffer.h */ \
     engine->RegisterObjectMethod(className, "bool SetDataRange(VectorBuffer&, uint, uint, bool discard = false)", AS_FUNCTION_OBJLAST(IndexBuffer_SetDataRange<T>), AS_CALL_CDECL_OBJLAST);
 
 // ========================================================================================

+ 3 - 3
Source/Urho3D/CMakeLists.txt

@@ -154,15 +154,15 @@ else ()
 endif ()
 
 if (NOT URHO3D_OPENGL)
-    list (APPEND EXCLUDED_SOURCE_DIRS Graphics/OpenGL)
+    list (APPEND EXCLUDED_SOURCE_DIRS GraphicsAPI/OpenGL)
 endif ()
 
 if (NOT URHO3D_D3D9)
-    list (APPEND EXCLUDED_SOURCE_DIRS Graphics/Direct3D9)
+    list (APPEND EXCLUDED_SOURCE_DIRS GraphicsAPI/Direct3D9)
 endif ()
 
 if (NOT URHO3D_D3D11)
-    list (APPEND EXCLUDED_SOURCE_DIRS Graphics/Direct3D11)
+    list (APPEND EXCLUDED_SOURCE_DIRS GraphicsAPI/Direct3D11)
 endif ()
 
 if (APPLE AND NOT ARM)

+ 2 - 2
Source/Urho3D/Graphics/AnimatedModel.cpp

@@ -33,10 +33,10 @@
 #include "../Graphics/DrawableEvents.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Graphics.h"
-#include "../Graphics/IndexBuffer.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/Octree.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/Log.h"
 #include "../Resource/ResourceCache.h"
 #include "../Resource/ResourceEvents.h"

+ 4 - 4
Source/Urho3D/Graphics/Batch.cpp

@@ -25,14 +25,14 @@
 #include "../Graphics/Camera.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Graphics.h"
-#include "../Graphics/GraphicsImpl.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/Renderer.h"
-#include "../Graphics/ShaderVariation.h"
 #include "../Graphics/Technique.h"
-#include "../Graphics/Texture2D.h"
-#include "../Graphics/VertexBuffer.h"
 #include "../Graphics/View.h"
+#include "../GraphicsAPI/GraphicsImpl.h"
+#include "../GraphicsAPI/ShaderVariation.h"
+#include "../GraphicsAPI/Texture2D.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../Scene/Scene.h"
 
 #include "../DebugNew.h"

+ 2 - 2
Source/Urho3D/Graphics/BillboardSet.cpp

@@ -29,9 +29,9 @@
 #include "../Graphics/Camera.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Graphics.h"
-#include "../Graphics/IndexBuffer.h"
 #include "../Graphics/OctreeQuery.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/MemoryBuffer.h"
 #include "../Resource/ResourceCache.h"
 #include "../Scene/Node.h"

+ 1 - 1
Source/Urho3D/Graphics/Camera.h

@@ -24,7 +24,7 @@
 
 #pragma once
 
-#include "../Graphics/GraphicsDefs.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
 #include "../Math/Frustum.h"
 #include "../Math/Ray.h"
 #include "../Scene/Component.h"

+ 1 - 1
Source/Urho3D/Graphics/CustomGeometry.cpp

@@ -31,7 +31,7 @@
 #include "../Graphics/Material.h"
 #include "../Graphics/OcclusionBuffer.h"
 #include "../Graphics/OctreeQuery.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/Log.h"
 #include "../IO/MemoryBuffer.h"
 #include "../Resource/ResourceCache.h"

+ 2 - 2
Source/Urho3D/Graphics/DebugRenderer.cpp

@@ -30,8 +30,8 @@
 #include "../Graphics/DebugRenderer.h"
 #include "../Graphics/Graphics.h"
 #include "../Graphics/Light.h"
-#include "../Graphics/ShaderVariation.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../GraphicsAPI/ShaderVariation.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../Math/Polyhedron.h"
 #include "../Resource/ResourceCache.h"
 

+ 2 - 2
Source/Urho3D/Graphics/DecalSet.cpp

@@ -30,10 +30,10 @@
 #include "../Graphics/DecalSet.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Graphics.h"
-#include "../Graphics/IndexBuffer.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/Tangent.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/Log.h"
 #include "../IO/MemoryBuffer.h"
 #include "../Resource/ResourceCache.h"

+ 2 - 2
Source/Urho3D/Graphics/Drawable.cpp

@@ -26,13 +26,13 @@
 #include "../Core/Context.h"
 #include "../Graphics/Camera.h"
 #include "../Graphics/DebugRenderer.h"
-#include "../IO/File.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/Octree.h"
 #include "../Graphics/Renderer.h"
-#include "../Graphics/VertexBuffer.h"
 #include "../Graphics/Zone.h"
+#include "../GraphicsAPI/VertexBuffer.h"
+#include "../IO/File.h"
 #include "../IO/Log.h"
 #include "../Scene/Scene.h"
 

+ 1 - 1
Source/Urho3D/Graphics/Drawable.h

@@ -24,7 +24,7 @@
 
 #pragma once
 
-#include "../Graphics/GraphicsDefs.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
 #include "../Math/BoundingBox.h"
 #include "../Scene/Component.h"
 

+ 2 - 2
Source/Urho3D/Graphics/Geometry.cpp

@@ -24,8 +24,8 @@
 
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Graphics.h"
-#include "../Graphics/IndexBuffer.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/Log.h"
 #include "../Math/Ray.h"
 

+ 1 - 1
Source/Urho3D/Graphics/Geometry.h

@@ -24,7 +24,7 @@
 
 #include "../Container/ArrayPtr.h"
 #include "../Core/Object.h"
-#include "../Graphics/GraphicsDefs.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
 
 namespace Urho3D
 {

+ 7 - 9
Source/Urho3D/Graphics/Graphics.cpp

@@ -32,26 +32,24 @@
 #include "../Graphics/DecalSet.h"
 #include "../Graphics/Graphics.h"
 #include "../Graphics/GraphicsEvents.h"
-#include "../Graphics/GraphicsImpl.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/Octree.h"
 #include "../Graphics/ParticleEffect.h"
 #include "../Graphics/ParticleEmitter.h"
 #include "../Graphics/RibbonTrail.h"
-#include "../Graphics/Shader.h"
-#include "../Graphics/ShaderPrecache.h"
 #include "../Graphics/Skybox.h"
 #include "../Graphics/StaticModelGroup.h"
 #include "../Graphics/Technique.h"
 #include "../Graphics/Terrain.h"
 #include "../Graphics/TerrainPatch.h"
-#ifdef _WIN32
-#include "../Graphics/Texture2D.h"
-#endif
-#include "../Graphics/Texture2DArray.h"
-#include "../Graphics/Texture3D.h"
-#include "../Graphics/TextureCube.h"
 #include "../Graphics/Zone.h"
+#include "../GraphicsAPI/GraphicsImpl.h"
+#include "../GraphicsAPI/Shader.h"
+#include "../GraphicsAPI/ShaderPrecache.h"
+#include "../GraphicsAPI/Texture2D.h"
+#include "../GraphicsAPI/Texture2DArray.h"
+#include "../GraphicsAPI/Texture3D.h"
+#include "../GraphicsAPI/TextureCube.h"
 #include "../IO/FileSystem.h"
 #include "../IO/Log.h"
 

+ 2 - 2
Source/Urho3D/Graphics/Graphics.h

@@ -26,8 +26,8 @@
 #include "../Container/HashSet.h"
 #include "../Core/Mutex.h"
 #include "../Core/Object.h"
-#include "../Graphics/GraphicsDefs.h"
-#include "../Graphics/ShaderVariation.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
+#include "../GraphicsAPI/ShaderVariation.h"
 #include "../Math/Color.h"
 #include "../Math/Plane.h"
 #include "../Math/Rect.h"

+ 2 - 2
Source/Urho3D/Graphics/Light.cpp

@@ -29,8 +29,8 @@
 #include "../Graphics/Graphics.h"
 #include "../Graphics/Light.h"
 #include "../Graphics/OctreeQuery.h"
-#include "../Graphics/Texture2D.h"
-#include "../Graphics/TextureCube.h"
+#include "../GraphicsAPI/Texture2D.h"
+#include "../GraphicsAPI/TextureCube.h"
 #include "../IO/Log.h"
 #include "../Resource/ResourceCache.h"
 #include "../Scene/Node.h"

+ 2 - 2
Source/Urho3D/Graphics/Light.h

@@ -24,10 +24,10 @@
 
 #pragma once
 
-#include "../Math/Color.h"
 #include "../Graphics/Drawable.h"
+#include "../GraphicsAPI/Texture.h"
+#include "../Math/Color.h"
 #include "../Math/Frustum.h"
-#include "../Graphics/Texture.h"
 
 namespace Urho3D
 {

+ 4 - 4
Source/Urho3D/Graphics/Material.cpp

@@ -29,10 +29,10 @@
 #include "../Graphics/Material.h"
 #include "../Graphics/Renderer.h"
 #include "../Graphics/Technique.h"
-#include "../Graphics/Texture2D.h"
-#include "../Graphics/Texture2DArray.h"
-#include "../Graphics/Texture3D.h"
-#include "../Graphics/TextureCube.h"
+#include "../GraphicsAPI/Texture2D.h"
+#include "../GraphicsAPI/Texture2DArray.h"
+#include "../GraphicsAPI/Texture3D.h"
+#include "../GraphicsAPI/TextureCube.h"
 #include "../IO/FileSystem.h"
 #include "../IO/Log.h"
 #include "../IO/VectorBuffer.h"

+ 1 - 1
Source/Urho3D/Graphics/Material.h

@@ -22,8 +22,8 @@
 
 #pragma once
 
-#include "../Graphics/GraphicsDefs.h"
 #include "../Graphics/Light.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
 #include "../Math/Vector4.h"
 #include "../Resource/Resource.h"
 #include "../Scene/ValueAnimationInfo.h"

+ 4 - 4
Source/Urho3D/Graphics/Model.cpp

@@ -25,13 +25,13 @@
 #include "../Core/Context.h"
 #include "../Core/Profiler.h"
 #include "../Graphics/Geometry.h"
-#include "../Graphics/IndexBuffer.h"
-#include "../Graphics/Model.h"
 #include "../Graphics/Graphics.h"
-#include "../Graphics/VertexBuffer.h"
-#include "../IO/Log.h"
+#include "../Graphics/Model.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/File.h"
 #include "../IO/FileSystem.h"
+#include "../IO/Log.h"
 #include "../Resource/ResourceCache.h"
 #include "../Resource/XMLFile.h"
 

+ 1 - 1
Source/Urho3D/Graphics/Model.h

@@ -24,8 +24,8 @@
 
 #include "../Container/ArrayPtr.h"
 #include "../Container/Ptr.h"
-#include "../Graphics/GraphicsDefs.h"
 #include "../Graphics/Skeleton.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
 #include "../Math/BoundingBox.h"
 #include "../Resource/Resource.h"
 

+ 1 - 1
Source/Urho3D/Graphics/OcclusionBuffer.h

@@ -27,7 +27,7 @@
 #include "../Core/Object.h"
 #include "../Core/Timer.h"
 #include "../Container/ArrayPtr.h"
-#include "../Graphics/GraphicsDefs.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
 #include "../Math/Frustum.h"
 
 namespace Urho3D

+ 1 - 1
Source/Urho3D/Graphics/ParticleEffect.h

@@ -24,7 +24,7 @@
 
 #pragma once
 
-#include "../Graphics/GraphicsDefs.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
 #include "../Resource/Resource.h"
 
 namespace Urho3D

+ 1 - 1
Source/Urho3D/Graphics/RenderPath.h

@@ -26,7 +26,7 @@
 
 #include "../Container/Ptr.h"
 #include "../Container/RefCounted.h"
-#include "../Graphics/GraphicsDefs.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
 #include "../Math/Color.h"
 #include "../Math/Vector4.h"
 

+ 6 - 6
Source/Urho3D/Graphics/Renderer.cpp

@@ -29,20 +29,20 @@
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Graphics.h"
 #include "../Graphics/GraphicsEvents.h"
-#include "../Graphics/GraphicsImpl.h"
-#include "../Graphics/IndexBuffer.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/OcclusionBuffer.h"
 #include "../Graphics/Octree.h"
 #include "../Graphics/Renderer.h"
 #include "../Graphics/RenderPath.h"
-#include "../Graphics/ShaderVariation.h"
 #include "../Graphics/Technique.h"
-#include "../Graphics/Texture2D.h"
-#include "../Graphics/TextureCube.h"
-#include "../Graphics/VertexBuffer.h"
 #include "../Graphics/View.h"
 #include "../Graphics/Zone.h"
+#include "../GraphicsAPI/GraphicsImpl.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/ShaderVariation.h"
+#include "../GraphicsAPI/Texture2D.h"
+#include "../GraphicsAPI/TextureCube.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/Log.h"
 #include "../Resource/ResourceCache.h"
 #include "../Resource/XMLFile.h"

+ 6 - 6
Source/Urho3D/Graphics/RibbonTrail.cpp

@@ -23,17 +23,17 @@
 #include "../Precompiled.h"
 
 #include "../Core/Context.h"
-#include "../Graphics/RibbonTrail.h"
-#include "../Graphics/VertexBuffer.h"
-#include "../Graphics/IndexBuffer.h"
 #include "../Graphics/Camera.h"
+#include "../Graphics/Geometry.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/OctreeQuery.h"
-#include "../Graphics/Geometry.h"
+#include "../Graphics/RibbonTrail.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
+#include "../IO/Log.h"
+#include "../Resource/ResourceCache.h"
 #include "../Scene/Scene.h"
 #include "../Scene/SceneEvents.h"
-#include "../Resource/ResourceCache.h"
-#include "../IO/Log.h"
 
 namespace Urho3D
 {

+ 1 - 1
Source/Urho3D/Graphics/StaticModel.cpp

@@ -31,7 +31,7 @@
 #include "../Graphics/Material.h"
 #include "../Graphics/OcclusionBuffer.h"
 #include "../Graphics/OctreeQuery.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/FileSystem.h"
 #include "../IO/Log.h"
 #include "../Resource/ResourceCache.h"

+ 1 - 1
Source/Urho3D/Graphics/StaticModelGroup.cpp

@@ -30,7 +30,7 @@
 #include "../Graphics/OcclusionBuffer.h"
 #include "../Graphics/OctreeQuery.h"
 #include "../Graphics/StaticModelGroup.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../Scene/Scene.h"
 
 #include "../DebugNew.h"

+ 1 - 1
Source/Urho3D/Graphics/Technique.cpp

@@ -27,7 +27,7 @@
 #include "../Core/Profiler.h"
 #include "../Graphics/Graphics.h"
 #include "../Graphics/Technique.h"
-#include "../Graphics/ShaderVariation.h"
+#include "../GraphicsAPI/ShaderVariation.h"
 #include "../IO/Log.h"
 #include "../Resource/ResourceCache.h"
 #include "../Resource/XMLFile.h"

+ 1 - 1
Source/Urho3D/Graphics/Technique.h

@@ -24,7 +24,7 @@
 
 #pragma once
 
-#include "../Graphics/GraphicsDefs.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
 #include "../Resource/Resource.h"
 
 namespace Urho3D

+ 2 - 2
Source/Urho3D/Graphics/Terrain.cpp

@@ -26,12 +26,12 @@
 #include "../Core/Profiler.h"
 #include "../Graphics/DrawableEvents.h"
 #include "../Graphics/Geometry.h"
-#include "../Graphics/IndexBuffer.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/Octree.h"
 #include "../Graphics/Terrain.h"
 #include "../Graphics/TerrainPatch.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/Log.h"
 #include "../Resource/Image.h"
 #include "../Resource/ResourceCache.h"

+ 2 - 2
Source/Urho3D/Graphics/TerrainPatch.cpp

@@ -26,13 +26,13 @@
 #include "../Graphics/Camera.h"
 #include "../Graphics/DebugRenderer.h"
 #include "../Graphics/Geometry.h"
-#include "../Graphics/IndexBuffer.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/OcclusionBuffer.h"
 #include "../Graphics/OctreeQuery.h"
 #include "../Graphics/Terrain.h"
 #include "../Graphics/TerrainPatch.h"
-#include "../Graphics/VertexBuffer.h"
+#include "../GraphicsAPI/IndexBuffer.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/Log.h"
 #include "../Scene/Node.h"
 

+ 7 - 7
Source/Urho3D/Graphics/View.cpp

@@ -29,21 +29,21 @@
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Graphics.h"
 #include "../Graphics/GraphicsEvents.h"
-#include "../Graphics/GraphicsImpl.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/OcclusionBuffer.h"
 #include "../Graphics/Octree.h"
 #include "../Graphics/Renderer.h"
 #include "../Graphics/RenderPath.h"
-#include "../Graphics/ShaderVariation.h"
 #include "../Graphics/Skybox.h"
 #include "../Graphics/Technique.h"
-#include "../Graphics/Texture2D.h"
-#include "../Graphics/Texture2DArray.h"
-#include "../Graphics/Texture3D.h"
-#include "../Graphics/TextureCube.h"
-#include "../Graphics/VertexBuffer.h"
 #include "../Graphics/View.h"
+#include "../GraphicsAPI/GraphicsImpl.h"
+#include "../GraphicsAPI/ShaderVariation.h"
+#include "../GraphicsAPI/Texture2D.h"
+#include "../GraphicsAPI/Texture2DArray.h"
+#include "../GraphicsAPI/Texture3D.h"
+#include "../GraphicsAPI/TextureCube.h"
+#include "../GraphicsAPI/VertexBuffer.h"
 #include "../IO/FileSystem.h"
 #include "../IO/Log.h"
 #include "../Resource/ResourceCache.h"

+ 1 - 1
Source/Urho3D/Graphics/Zone.cpp

@@ -25,8 +25,8 @@
 #include "../Core/Context.h"
 #include "../Graphics/DebugRenderer.h"
 #include "../Graphics/Octree.h"
-#include "../Graphics/TextureCube.h"
 #include "../Graphics/Zone.h"
+#include "../GraphicsAPI/TextureCube.h"
 #include "../Resource/ResourceCache.h"
 #include "../Scene/Node.h"
 #include "../Scene/Scene.h"

+ 1 - 1
Source/Urho3D/Graphics/Zone.h

@@ -23,7 +23,7 @@
 #pragma once
 
 #include "../Graphics/Drawable.h"
-#include "../Graphics/Texture.h"
+#include "../GraphicsAPI/Texture.h"
 #include "../Math/Color.h"
 
 namespace Urho3D

+ 1 - 1
Source/Urho3D/Graphics/ConstantBuffer.cpp → Source/Urho3D/GraphicsAPI/ConstantBuffer.cpp

@@ -23,7 +23,7 @@
 #include "../Precompiled.h"
 
 #include "../Graphics/Graphics.h"
-#include "../Graphics/ConstantBuffer.h"
+#include "../GraphicsAPI/ConstantBuffer.h"
 #include "../IO/Log.h"
 
 #include "../DebugNew.h"

+ 2 - 2
Source/Urho3D/Graphics/ConstantBuffer.h → Source/Urho3D/GraphicsAPI/ConstantBuffer.h

@@ -24,8 +24,8 @@
 
 #include "../Container/ArrayPtr.h"
 #include "../Core/Object.h"
-#include "../Graphics/GPUObject.h"
-#include "../Graphics/GraphicsDefs.h"
+#include "../GraphicsAPI/GPUObject.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
 
 namespace Urho3D
 {

+ 2 - 2
Source/Urho3D/Graphics/Direct3D11/D3D11ConstantBuffer.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11ConstantBuffer.cpp

@@ -23,9 +23,9 @@
 #include "../../Precompiled.h"
 
 #include "../../Graphics/Graphics.h"
-#include "../../Graphics/ConstantBuffer.h"
+#include "../../GraphicsAPI/ConstantBuffer.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
 #include "../../IO/Log.h"
-#include "D3D11GraphicsImpl.h"
 
 #include "../../DebugNew.h"
 

+ 9 - 9
Source/Urho3D/Graphics/Direct3D11/D3D11Graphics.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11Graphics.cpp

@@ -25,22 +25,22 @@
 #include "../../Core/Context.h"
 #include "../../Core/ProcessUtils.h"
 #include "../../Core/Profiler.h"
-#include "../../Graphics/ConstantBuffer.h"
 #include "../../Graphics/Geometry.h"
 #include "../../Graphics/Graphics.h"
 #include "../../Graphics/GraphicsEvents.h"
-#include "../../Graphics/IndexBuffer.h"
 #include "../../Graphics/Renderer.h"
-#include "../../Graphics/Shader.h"
-#include "../../Graphics/ShaderPrecache.h"
-#include "../../Graphics/Texture2D.h"
-#include "../../Graphics/TextureCube.h"
-#include "../../Graphics/VertexBuffer.h"
+#include "../../GraphicsAPI/ConstantBuffer.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11ShaderProgram.h"
+#include "../../GraphicsAPI/IndexBuffer.h"
+#include "../../GraphicsAPI/Shader.h"
+#include "../../GraphicsAPI/ShaderPrecache.h"
+#include "../../GraphicsAPI/Texture2D.h"
+#include "../../GraphicsAPI/TextureCube.h"
+#include "../../GraphicsAPI/VertexBuffer.h"
 #include "../../IO/File.h"
 #include "../../IO/Log.h"
 #include "../../Resource/ResourceCache.h"
-#include "D3D11GraphicsImpl.h"
-#include "D3D11ShaderProgram.h"
 
 #include <SDL/SDL.h>
 #include <SDL/SDL_syswm.h>

+ 0 - 0
Source/Urho3D/Graphics/Direct3D11/D3D11GraphicsImpl.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11GraphicsImpl.cpp


+ 4 - 4
Source/Urho3D/Graphics/Direct3D11/D3D11GraphicsImpl.h → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h

@@ -22,11 +22,11 @@
 
 #pragma once
 
-#include "../../Graphics/ConstantBuffer.h"
-#include "../../Graphics/GraphicsDefs.h"
+#include "../../GraphicsAPI/ConstantBuffer.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11ShaderProgram.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11VertexDeclaration.h"
+#include "../../GraphicsAPI/GraphicsDefs.h"
 #include "../../Math/Color.h"
-#include "D3D11ShaderProgram.h"
-#include "D3D11VertexDeclaration.h"
 
 #include <d3d11.h>
 #include <dxgi.h>

+ 2 - 2
Source/Urho3D/Graphics/Direct3D11/D3D11IndexBuffer.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11IndexBuffer.cpp

@@ -24,9 +24,9 @@
 
 #include "../../Core/Context.h"
 #include "../../Graphics/Graphics.h"
-#include "../../Graphics/IndexBuffer.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
+#include "../../GraphicsAPI/IndexBuffer.h"
 #include "../../IO/Log.h"
-#include "D3D11GraphicsImpl.h"
 
 #include "../../DebugNew.h"
 

+ 3 - 3
Source/Urho3D/Graphics/Direct3D11/D3D11RenderSurface.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11RenderSurface.cpp

@@ -24,10 +24,10 @@
 
 #include "../../Graphics/Camera.h"
 #include "../../Graphics/Graphics.h"
-#include "../../Graphics/GraphicsImpl.h"
 #include "../../Graphics/Renderer.h"
-#include "../../Graphics/RenderSurface.h"
-#include "../../Graphics/Texture.h"
+#include "../../GraphicsAPI/GraphicsImpl.h"
+#include "../../GraphicsAPI/RenderSurface.h"
+#include "../../GraphicsAPI/Texture.h"
 
 #include "../../DebugNew.h"
 

+ 2 - 2
Source/Urho3D/Graphics/Direct3D11/D3D11ShaderProgram.h → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11ShaderProgram.h

@@ -23,9 +23,9 @@
 #pragma once
 
 #include "../../Container/HashMap.h"
-#include "../../Graphics/ConstantBuffer.h"
 #include "../../Graphics/Graphics.h"
-#include "../../Graphics/ShaderVariation.h"
+#include "../../GraphicsAPI/ConstantBuffer.h"
+#include "../../GraphicsAPI/ShaderVariation.h"
 
 namespace Urho3D
 {

+ 3 - 3
Source/Urho3D/Graphics/Direct3D11/D3D11ShaderVariation.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11ShaderVariation.cpp

@@ -23,13 +23,13 @@
 #include "../../Precompiled.h"
 
 #include "../../Graphics/Graphics.h"
-#include "../../Graphics/Shader.h"
-#include "../../Graphics/VertexBuffer.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
+#include "../../GraphicsAPI/Shader.h"
+#include "../../GraphicsAPI/VertexBuffer.h"
 #include "../../IO/File.h"
 #include "../../IO/FileSystem.h"
 #include "../../IO/Log.h"
 #include "../../Resource/ResourceCache.h"
-#include "D3D11GraphicsImpl.h"
 
 #include <d3dcompiler.h>
 

+ 1 - 1
Source/Urho3D/Graphics/Direct3D11/D3D11Texture.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11Texture.cpp

@@ -25,11 +25,11 @@
 #include "../../Core/Profiler.h"
 #include "../../Graphics/Graphics.h"
 #include "../../Graphics/Material.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
 #include "../../IO/FileSystem.h"
 #include "../../IO/Log.h"
 #include "../../Resource/ResourceCache.h"
 #include "../../Resource/XMLFile.h"
-#include "D3D11GraphicsImpl.h"
 
 #include "../../DebugNew.h"
 

+ 2 - 2
Source/Urho3D/Graphics/Direct3D11/D3D11Texture2D.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11Texture2D.cpp

@@ -27,12 +27,12 @@
 #include "../../Graphics/Graphics.h"
 #include "../../Graphics/GraphicsEvents.h"
 #include "../../Graphics/Renderer.h"
-#include "../../Graphics/Texture2D.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
+#include "../../GraphicsAPI/Texture2D.h"
 #include "../../IO/FileSystem.h"
 #include "../../IO/Log.h"
 #include "../../Resource/ResourceCache.h"
 #include "../../Resource/XMLFile.h"
-#include "D3D11GraphicsImpl.h"
 
 #include "../../DebugNew.h"
 

+ 2 - 2
Source/Urho3D/Graphics/Direct3D11/D3D11Texture2DArray.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11Texture2DArray.cpp

@@ -27,12 +27,12 @@
 #include "../../Graphics/Graphics.h"
 #include "../../Graphics/GraphicsEvents.h"
 #include "../../Graphics/Renderer.h"
-#include "../../Graphics/Texture2DArray.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
+#include "../../GraphicsAPI/Texture2DArray.h"
 #include "../../IO/FileSystem.h"
 #include "../../IO/Log.h"
 #include "../../Resource/ResourceCache.h"
 #include "../../Resource/XMLFile.h"
-#include "D3D11GraphicsImpl.h"
 
 #include "../../DebugNew.h"
 

+ 2 - 2
Source/Urho3D/Graphics/Direct3D11/D3D11Texture3D.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11Texture3D.cpp

@@ -27,12 +27,12 @@
 #include "../../Graphics/Graphics.h"
 #include "../../Graphics/GraphicsEvents.h"
 #include "../../Graphics/Renderer.h"
-#include "../../Graphics/Texture3D.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
+#include "../../GraphicsAPI/Texture3D.h"
 #include "../../IO/FileSystem.h"
 #include "../../IO/Log.h"
 #include "../../Resource/ResourceCache.h"
 #include "../../Resource/XMLFile.h"
-#include "D3D11GraphicsImpl.h"
 
 #include "../../DebugNew.h"
 

+ 2 - 2
Source/Urho3D/Graphics/Direct3D11/D3D11TextureCube.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11TextureCube.cpp

@@ -27,12 +27,12 @@
 #include "../../Graphics/Graphics.h"
 #include "../../Graphics/GraphicsEvents.h"
 #include "../../Graphics/Renderer.h"
-#include "../../Graphics/TextureCube.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
+#include "../../GraphicsAPI/TextureCube.h"
 #include "../../IO/FileSystem.h"
 #include "../../IO/Log.h"
 #include "../../Resource/ResourceCache.h"
 #include "../../Resource/XMLFile.h"
-#include "D3D11GraphicsImpl.h"
 
 #include "../../DebugNew.h"
 

+ 3 - 3
Source/Urho3D/Graphics/Direct3D11/D3D11VertexBuffer.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11VertexBuffer.cpp

@@ -22,10 +22,10 @@
 
 #include "../../Precompiled.h"
 
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/VertexBuffer.h"
 #include "../../IO/Log.h"
-#include "D3D11GraphicsImpl.h"
+#include "../../GraphicsAPI/VertexBuffer.h"
+#include "../../Graphics/Graphics.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
 
 #include "../../DebugNew.h"
 

+ 3 - 3
Source/Urho3D/Graphics/Direct3D11/D3D11VertexDeclaration.cpp → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11VertexDeclaration.cpp

@@ -23,10 +23,10 @@
 #include "../../Precompiled.h"
 
 #include "../../Graphics/Graphics.h"
-#include "../../Graphics/ShaderVariation.h"
-#include "../../Graphics/VertexBuffer.h"
+#include "../../GraphicsAPI/Direct3D11/D3D11GraphicsImpl.h"
+#include "../../GraphicsAPI/ShaderVariation.h"
+#include "../../GraphicsAPI/VertexBuffer.h"
 #include "../../IO/Log.h"
-#include "D3D11GraphicsImpl.h"
 #include "D3D11VertexDeclaration.h"
 
 #include "../../DebugNew.h"

+ 1 - 1
Source/Urho3D/Graphics/Direct3D11/D3D11VertexDeclaration.h → Source/Urho3D/GraphicsAPI/Direct3D11/D3D11VertexDeclaration.h

@@ -24,7 +24,7 @@
 
 #include "../../Container/RefCounted.h"
 #include "../../Container/Vector.h"
-#include "../../Graphics/GraphicsDefs.h"
+#include "../../GraphicsAPI/GraphicsDefs.h"
 
 namespace Urho3D
 {

+ 1 - 1
Source/Urho3D/Graphics/Direct3D9/D3D9ConstantBuffer.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9ConstantBuffer.cpp

@@ -23,7 +23,7 @@
 #include "../../Precompiled.h"
 
 #include "../../Graphics/Graphics.h"
-#include "../../Graphics/ConstantBuffer.h"
+#include "../../GraphicsAPI/ConstantBuffer.h"
 #include "../../IO/Log.h"
 
 #include "../../DebugNew.h"

+ 2699 - 2699
Source/Urho3D/Graphics/Direct3D9/D3D9Graphics.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9Graphics.cpp

@@ -1,2699 +1,2699 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Core/Context.h"
-#include "../../Core/ProcessUtils.h"
-#include "../../Core/Profiler.h"
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/GraphicsEvents.h"
-#include "../../Graphics/GraphicsImpl.h"
-#include "../../Graphics/IndexBuffer.h"
-#include "../../Graphics/Shader.h"
-#include "../../Graphics/ShaderPrecache.h"
-#include "../../Graphics/Texture2D.h"
-#include "../../Graphics/TextureCube.h"
-#include "../../Graphics/VertexBuffer.h"
-#include "../../IO/File.h"
-#include "../../IO/Log.h"
-#include "../../Resource/ResourceCache.h"
-#include "D3D9GraphicsImpl.h"
-#include "D3D9ShaderProgram.h"
-#include "D3D9VertexDeclaration.h"
-
-#include <SDL/SDL.h>
-#include <SDL/SDL_syswm.h>
-
-#include "../../DebugNew.h"
-
-#ifdef _MSC_VER
-#pragma warning(disable:4355)
-#endif
-
-// Fix missing define in MinGW headers
-#ifndef D3DPRESENT_LINEAR_CONTENT
-#define D3DPRESENT_LINEAR_CONTENT 0x00000002L
-#endif
-#ifndef D3DSTREAMSOURCE_INDEXEDDATA
-#define D3DSTREAMSOURCE_INDEXEDDATA (1<<30)
-#endif
-#ifndef D3DSTREAMSOURCE_INSTANCEDATA
-#define D3DSTREAMSOURCE_INSTANCEDATA (2<<30)
-#endif
-
-namespace Urho3D
-{
-
-static const D3DCMPFUNC d3dCmpFunc[] =
-{
-    D3DCMP_ALWAYS,
-    D3DCMP_EQUAL,
-    D3DCMP_NOTEQUAL,
-    D3DCMP_LESS,
-    D3DCMP_LESSEQUAL,
-    D3DCMP_GREATER,
-    D3DCMP_GREATEREQUAL
-};
-
-static const D3DTEXTUREFILTERTYPE d3dMinFilter[] =
-{
-    D3DTEXF_POINT,
-    D3DTEXF_LINEAR,
-    D3DTEXF_LINEAR,
-    D3DTEXF_ANISOTROPIC,
-    D3DTEXF_ANISOTROPIC
-};
-
-static const D3DTEXTUREFILTERTYPE d3dMagFilter[] =
-{
-    D3DTEXF_POINT,
-    D3DTEXF_LINEAR,
-    D3DTEXF_LINEAR,
-    D3DTEXF_ANISOTROPIC,
-    D3DTEXF_POINT,
-};
-
-static const D3DTEXTUREFILTERTYPE d3dMipFilter[] =
-{
-    D3DTEXF_POINT,
-    D3DTEXF_POINT,
-    D3DTEXF_LINEAR,
-    D3DTEXF_ANISOTROPIC,
-    D3DTEXF_ANISOTROPIC
-};
-
-static const D3DTEXTUREADDRESS d3dAddressMode[] =
-{
-    D3DTADDRESS_WRAP,
-    D3DTADDRESS_MIRROR,
-    D3DTADDRESS_CLAMP,
-    D3DTADDRESS_BORDER
-};
-
-static const DWORD d3dBlendEnable[] =
-{
-    FALSE,
-    TRUE,
-    TRUE,
-    TRUE,
-    TRUE,
-    TRUE,
-    TRUE,
-    TRUE,
-    TRUE
-};
-
-static const D3DBLEND d3dSrcBlend[] =
-{
-    D3DBLEND_ONE,
-    D3DBLEND_ONE,
-    D3DBLEND_DESTCOLOR,
-    D3DBLEND_SRCALPHA,
-    D3DBLEND_SRCALPHA,
-    D3DBLEND_ONE,
-    D3DBLEND_INVDESTALPHA,
-    D3DBLEND_ONE,
-    D3DBLEND_SRCALPHA,
-};
-
-static const D3DBLEND d3dDestBlend[] =
-{
-    D3DBLEND_ZERO,
-    D3DBLEND_ONE,
-    D3DBLEND_ZERO,
-    D3DBLEND_INVSRCALPHA,
-    D3DBLEND_ONE,
-    D3DBLEND_INVSRCALPHA,
-    D3DBLEND_DESTALPHA,
-    D3DBLEND_ONE,
-    D3DBLEND_ONE
-};
-
-static const D3DBLENDOP d3dBlendOp[] =
-{
-    D3DBLENDOP_ADD,
-    D3DBLENDOP_ADD,
-    D3DBLENDOP_ADD,
-    D3DBLENDOP_ADD,
-    D3DBLENDOP_ADD,
-    D3DBLENDOP_ADD,
-    D3DBLENDOP_ADD,
-    D3DBLENDOP_REVSUBTRACT,
-    D3DBLENDOP_REVSUBTRACT
-};
-
-static const D3DCULL d3dCullMode[] =
-{
-    D3DCULL_NONE,
-    D3DCULL_CCW,
-    D3DCULL_CW
-};
-
-static const D3DFILLMODE d3dFillMode[] =
-{
-    D3DFILL_SOLID,
-    D3DFILL_WIREFRAME,
-    D3DFILL_POINT
-};
-
-static const D3DSTENCILOP d3dStencilOp[] =
-{
-    D3DSTENCILOP_KEEP,
-    D3DSTENCILOP_ZERO,
-    D3DSTENCILOP_REPLACE,
-    D3DSTENCILOP_INCR,
-    D3DSTENCILOP_DECR
-};
-
-static unsigned GetD3DColor(const Color& color)
-{
-    unsigned r = (unsigned)(Clamp(color.r_ * 255.0f, 0.0f, 255.0f));
-    unsigned g = (unsigned)(Clamp(color.g_ * 255.0f, 0.0f, 255.0f));
-    unsigned b = (unsigned)(Clamp(color.b_ * 255.0f, 0.0f, 255.0f));
-    unsigned a = (unsigned)(Clamp(color.a_ * 255.0f, 0.0f, 255.0f));
-    return (((a) & 0xff) << 24) | (((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff);
-}
-
-static void GetD3DPrimitiveType(unsigned elementCount, PrimitiveType type, unsigned& primitiveCount,
-    D3DPRIMITIVETYPE& d3dPrimitiveType)
-{
-    switch (type)
-    {
-    case TRIANGLE_LIST:
-        primitiveCount = elementCount / 3;
-        d3dPrimitiveType = D3DPT_TRIANGLELIST;
-        break;
-
-    case LINE_LIST:
-        primitiveCount = elementCount / 2;
-        d3dPrimitiveType = D3DPT_LINELIST;
-        break;
-
-    case POINT_LIST:
-        primitiveCount = elementCount;
-        d3dPrimitiveType = D3DPT_POINTLIST;
-        break;
-
-    case TRIANGLE_STRIP:
-        primitiveCount = elementCount - 2;
-        d3dPrimitiveType = D3DPT_TRIANGLESTRIP;
-        break;
-
-    case LINE_STRIP:
-        primitiveCount = elementCount - 1;
-        d3dPrimitiveType = D3DPT_LINESTRIP;
-        break;
-
-    case TRIANGLE_FAN:
-        primitiveCount = elementCount - 2;
-        d3dPrimitiveType = D3DPT_TRIANGLEFAN;
-        break;
-    }
-}
-
-static HWND GetWindowHandle(SDL_Window* window)
-{
-    SDL_SysWMinfo sysInfo;
-
-    SDL_VERSION(&sysInfo.version);
-    SDL_GetWindowWMInfo(window, &sysInfo);
-    return sysInfo.info.win.window;
-}
-
-static unsigned readableDepthFormat = 0;
-
-void Graphics::Constructor_D3D9()
-{
-    impl_ = new GraphicsImpl_D3D9();
-    position_ = IntVector2(SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED);
-    shaderPath_ = "Shaders/HLSL/";
-    shaderExtension_ = ".hlsl";
-    orientations_ = "LandscapeLeft LandscapeRight";
-    apiName_ = "D3D9";
-
-    Graphics::pixelUVOffset = Vector2(0.5f, 0.5f);
-    Graphics::gl3Support = false;
-
-    SetTextureUnitMappings_D3D9();
-
-    context_->RequireSDL(SDL_INIT_VIDEO);
-
-    // Register Graphics library object factories
-    RegisterGraphicsLibrary(context_);
-}
-
-void Graphics::Destructor_D3D9()
-{
-    {
-        MutexLock lock(gpuObjectMutex_);
-
-        // Release all GPU objects that still exist
-        for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
-            (*i)->Release();
-        gpuObjects_.Clear();
-    }
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    impl->vertexDeclarations_.Clear();
-
-    URHO3D_SAFE_RELEASE(impl->defaultColorSurface_);
-    URHO3D_SAFE_RELEASE(impl->defaultDepthStencilSurface_);
-    URHO3D_SAFE_RELEASE(impl->frameQuery_);
-    URHO3D_SAFE_RELEASE(impl->device_);
-    URHO3D_SAFE_RELEASE(impl->interface_);
-
-    if (window_)
-    {
-        SDL_ShowCursor(SDL_TRUE);
-        SDL_DestroyWindow(window_);
-        window_ = nullptr;
-    }
-
-    delete impl_;
-    impl_ = nullptr;
-
-    context_->ReleaseSDL();
-}
-
-bool Graphics::SetScreenMode_D3D9(int width, int height, const ScreenModeParams& params, bool maximize)
-{
-    URHO3D_PROFILE(SetScreenMode_D3D9);
-
-    // Ensure that parameters are properly filled
-    ScreenModeParams newParams = params;
-    AdjustScreenMode(width, height, newParams, maximize);
-
-    // If nothing changes, do not reset the device
-    if (width_ == width && height_ == height && screenParams_ == newParams)
-        return true;
-
-    // Find out the full screen mode display format (match desktop color depth)
-    SDL_DisplayMode mode;
-    SDL_GetDesktopDisplayMode(newParams.monitor_, &mode);
-    const D3DFORMAT fullscreenFormat = SDL_BITSPERPIXEL(mode.format) == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
-
-    const bool monitorChanged = screenParams_.monitor_ != newParams.monitor_;
-
-    SDL_SetHint(SDL_HINT_ORIENTATIONS, orientations_.CString());
-
-    if (!window_)
-    {
-        if (!OpenWindow_D3D9(width, height, newParams.resizable_, newParams.borderless_))
-            return false;
-    }
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (!impl->interface_)
-    {
-        if (!CreateInterface_D3D9())
-            return false;
-
-        CheckFeatureSupport_D3D9();
-    }
-
-    // Fall back to non-multisampled if unsupported multisampling mode
-    if (newParams.multiSample_ > 1)
-    {
-        if (!impl->CheckMultiSampleSupport(fullscreenFormat, newParams.multiSample_))
-            newParams.multiSample_ = 1;
-    }
-
-    AdjustWindow_D3D9(width, height, newParams.fullscreen_, newParams.borderless_, newParams.monitor_);
-
-    if (maximize)
-    {
-        Maximize();
-        SDL_GetWindowSize(window_, &width, &height);
-    }
-
-    if (newParams.fullscreen_)
-    {
-        impl->presentParams_.BackBufferFormat = fullscreenFormat;
-        impl->presentParams_.Windowed = false;
-    }
-    else
-    {
-        impl->presentParams_.BackBufferFormat = D3DFMT_UNKNOWN;
-        impl->presentParams_.Windowed = true;
-    }
-
-    impl->presentParams_.BackBufferWidth = (UINT)width;
-    impl->presentParams_.BackBufferHeight = (UINT)height;
-    impl->presentParams_.BackBufferCount = newParams.tripleBuffer_ ? 2 : 1;
-    impl->presentParams_.MultiSampleType = newParams.multiSample_ > 1 ? static_cast<D3DMULTISAMPLE_TYPE>(newParams.multiSample_) : D3DMULTISAMPLE_NONE;
-    impl->presentParams_.MultiSampleQuality = 0;
-    impl->presentParams_.SwapEffect = D3DSWAPEFFECT_DISCARD;
-    impl->presentParams_.hDeviceWindow = GetWindowHandle(window_);
-    impl->presentParams_.EnableAutoDepthStencil = TRUE;
-    impl->presentParams_.AutoDepthStencilFormat = D3DFMT_D24S8;
-    impl->presentParams_.Flags = D3DPRESENT_LINEAR_CONTENT;
-    impl->presentParams_.FullScreen_RefreshRateInHz = newParams.fullscreen_ ? newParams.refreshRate_ : D3DPRESENT_RATE_DEFAULT;
-
-    if (newParams.vsync_)
-        impl->presentParams_.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
-    else
-        impl->presentParams_.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
-
-    width_ = width;
-    height_ = height;
-    screenParams_ = newParams;
-
-    if (!impl->device_)
-    {
-        unsigned adapter = SDL_Direct3D9GetAdapterIndex(screenParams_.monitor_);
-        unsigned deviceType = D3DDEVTYPE_HAL;
-
-        // Check for PerfHUD adapter
-        for (unsigned i = 0; i < impl->interface_->GetAdapterCount(); ++i)
-        {
-            D3DADAPTER_IDENTIFIER9 identifier;
-            impl->interface_->GetAdapterIdentifier(i, 0, &identifier);
-            if (strstr(identifier.Description, "PerfHUD") != nullptr)
-            {
-                adapter = i;
-                deviceType = D3DDEVTYPE_REF;
-                break;
-            }
-        }
-
-        impl->interface_->GetAdapterIdentifier(adapter, 0, &impl->adapterIdentifier_);
-        if (!CreateDevice_D3D9(adapter, deviceType))
-            return false;
-    }
-    else
-    {
-        if (!monitorChanged)
-            ResetDevice_D3D9();
-        else
-        {
-            URHO3D_LOGINFO("Destroying D3D9 device");
-            // Monitor changed, re-create the D3D9 device on the new monitor
-            impl->vertexDeclarations_.Clear();
-            OnDeviceLost_D3D9();
-            
-            {
-                MutexLock lock(gpuObjectMutex_);
-                // Release all GPU objects that still exist
-                for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
-                    (*i)->Release();
-            }
-
-            // destroy previous device
-            URHO3D_SAFE_RELEASE(impl->device_);
-
-            // create new device on the specified monitor
-            unsigned adapter = SDL_Direct3D9GetAdapterIndex(screenParams_.monitor_);
-            unsigned deviceType = D3DDEVTYPE_HAL;
-            if (!CreateDevice_D3D9(adapter, deviceType))
-                return false;
-            ResetDevice_D3D9();
-        }
-    }
-
-    // Clear the initial window contents to black
-    impl->device_->BeginScene();
-    Clear_D3D9(CLEAR_COLOR);
-    impl->device_->EndScene();
-    impl->device_->Present(nullptr, nullptr, nullptr, nullptr);
-
-#ifdef URHO3D_LOGGING
-    D3DADAPTER_IDENTIFIER9 id = {0};
-    HRESULT hr = impl->interface_->GetAdapterIdentifier(SDL_Direct3D9GetAdapterIndex(screenParams_.monitor_), 0, &id);
-    if (S_OK == hr)
-        URHO3D_LOGINFOF("Adapter used %s", id.Description);
-#endif
-
-    OnScreenModeChanged();
-    return true;
-}
-
-void Graphics::SetSRGB_D3D9(bool enable)
-{
-    sRGB_ = enable && sRGBWriteSupport_;
-}
-
-void Graphics::SetDither_D3D9(bool enable)
-{
-    // No effect on Direct3D9
-}
-
-void Graphics::SetFlushGPU_D3D9(bool enable)
-{
-    flushGPU_ = enable;
-}
-
-void Graphics::SetForceGL2_D3D9(bool enable)
-{
-    // No effect on Direct3D9
-}
-
-void Graphics::Close_D3D9()
-{
-    if (window_)
-    {
-        SDL_ShowCursor(SDL_TRUE);
-        SDL_DestroyWindow(window_);
-        window_ = nullptr;
-    }
-}
-
-bool Graphics::TakeScreenShot_D3D9(Image& destImage)
-{
-    URHO3D_PROFILE(TakeScreenShot_D3D9);
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (!impl->device_)
-        return false;
-
-    if (IsDeviceLost_D3D9())
-    {
-        URHO3D_LOGERROR("Can not take screenshot while device is lost");
-        return false;
-    }
-
-    D3DSURFACE_DESC surfaceDesc;
-    impl->defaultColorSurface_->GetDesc(&surfaceDesc);
-
-    // If possible, get the backbuffer data, because it is a lot faster.
-    // However, if we are multisampled, need to use the front buffer
-    bool useBackBuffer = true;
-    unsigned surfaceWidth = (unsigned)width_;
-    unsigned surfaceHeight = (unsigned)height_;
-
-    if (impl->presentParams_.MultiSampleType)
-    {
-        // If windowed and multisampled, must still capture the whole screen
-        if (!screenParams_.fullscreen_)
-        {
-            IntVector2 desktopSize = GetDesktopResolution(screenParams_.monitor_);
-            surfaceWidth = (unsigned)desktopSize.x_;
-            surfaceHeight = (unsigned)desktopSize.y_;
-        }
-        useBackBuffer = false;
-        surfaceDesc.Format = D3DFMT_A8R8G8B8;
-    }
-
-    IDirect3DSurface9* surface = nullptr;
-    HRESULT hr = impl->device_->CreateOffscreenPlainSurface(surfaceWidth, surfaceHeight, surfaceDesc.Format, D3DPOOL_SYSTEMMEM, &surface, nullptr);
-    if (FAILED(hr))
-    {
-        URHO3D_SAFE_RELEASE(surface);
-        URHO3D_LOGD3DERROR("Could not create surface for taking a screenshot", hr);
-        return false;
-    }
-
-    if (useBackBuffer)
-        hr = impl->device_->GetRenderTargetData(impl->defaultColorSurface_, surface);
-    else
-        hr = impl->device_->GetFrontBufferData(0, surface);
-    if (FAILED(hr))
-    {
-        URHO3D_SAFE_RELEASE(surface);
-        URHO3D_LOGD3DERROR("Could not get rendertarget data for taking a screenshot", hr);
-        return false;
-    }
-
-    // If capturing the whole screen, determine the window rect
-    RECT sourceRect;
-    if (surfaceHeight == height_ && surfaceWidth == width_)
-    {
-        sourceRect.left = 0;
-        sourceRect.top = 0;
-        sourceRect.right = width_;
-        sourceRect.bottom = height_;
-    }
-    else
-    {
-        HWND hwnd = GetWindowHandle(window_);
-        GetClientRect(hwnd, &sourceRect);
-        ClientToScreen(hwnd, (LPPOINT)&sourceRect);
-    }
-
-    D3DLOCKED_RECT lockedRect;
-    lockedRect.pBits = nullptr;
-    hr = surface->LockRect(&lockedRect, &sourceRect, D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY);
-    if (FAILED(hr) || !lockedRect.pBits)
-    {
-        URHO3D_SAFE_RELEASE(surface);
-        URHO3D_LOGD3DERROR("Could not lock surface for taking a screenshot", hr);
-        return false;
-    }
-
-    destImage.SetSize(width_, height_, 3);
-    unsigned char* destData = destImage.GetData();
-
-    if (surfaceDesc.Format == D3DFMT_R5G6B5)
-    {
-        for (int y = 0; y < height_; ++y)
-        {
-            unsigned short* src = (unsigned short*)((unsigned char*)lockedRect.pBits + y * lockedRect.Pitch);
-            unsigned char* dest = destData + y * width_ * 3;
-
-            for (int x = 0; x < width_; ++x)
-            {
-                unsigned short rgb = *src++;
-                int b = rgb & 31;
-                int g = (rgb >> 5) & 63;
-                int r = (rgb >> 11);
-
-                dest[0] = (unsigned char)(r * 255.0f / 31.0f);
-                dest[1] = (unsigned char)(g * 255.0f / 63.0f);
-                dest[2] = (unsigned char)(b * 255.0f / 31.0f);
-                dest += 3;
-            }
-        }
-    }
-    else
-    {
-        for (int y = 0; y < height_; ++y)
-        {
-            unsigned char* src = (unsigned char*)lockedRect.pBits + y * lockedRect.Pitch;
-            unsigned char* dest = destData + y * width_ * 3;
-
-            for (int x = 0; x < width_; ++x)
-            {
-                dest[0] = src[2];
-                dest[1] = src[1];
-                dest[2] = src[0];
-                src += 4;
-                dest += 3;
-            }
-        }
-    }
-
-    surface->UnlockRect();
-    surface->Release();
-
-    return true;
-}
-
-bool Graphics::BeginFrame_D3D9()
-{
-    if (!IsInitialized_D3D9())
-        return false;
-
-    // If using an external window, check it for size changes, and reset screen mode if necessary
-    if (externalWindow_)
-    {
-        int width, height;
-
-        SDL_GetWindowSize(window_, &width, &height);
-        if (width != width_ || height != height_)
-            SetMode(width, height);
-    }
-    else
-    {
-        // To prevent a loop of endless device loss and flicker, do not attempt to render when in fullscreen
-        // and the window is minimized
-        if (screenParams_.fullscreen_ && (SDL_GetWindowFlags(window_) & SDL_WINDOW_MINIMIZED))
-            return false;
-    }
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    // Check for lost device before rendering
-    HRESULT hr = impl->device_->TestCooperativeLevel();
-    if (hr != D3D_OK)
-    {
-        URHO3D_PROFILE(DeviceLost);
-
-        impl->deviceLost_ = true;
-
-        // The device can not be reset yet, sleep and try again eventually
-        if (hr == D3DERR_DEVICELOST)
-        {
-            Time::Sleep(20);
-            return false;
-        }
-        // The device is lost, but ready to be reset. Reset device but do not render on this frame yet
-        if (hr == D3DERR_DEVICENOTRESET)
-        {
-            ResetDevice_D3D9();
-            return false;
-        }
-    }
-
-    impl->device_->BeginScene();
-
-    // Set default rendertarget and depth buffer
-    ResetRenderTargets_D3D9();
-
-    // Cleanup textures from previous frame
-    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-        SetTexture_D3D9(i, nullptr);
-
-    numPrimitives_ = 0;
-    numBatches_ = 0;
-
-    SendEvent(E_BEGINRENDERING);
-
-    return true;
-}
-
-void Graphics::EndFrame_D3D9()
-{
-    if (!IsInitialized_D3D9())
-        return;
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    {
-        URHO3D_PROFILE(Present);
-
-        SendEvent(E_ENDRENDERING);
-
-        impl->device_->EndScene();
-        impl->device_->Present(nullptr, nullptr, nullptr, nullptr);
-    }
-
-    // Optionally flush GPU buffer to avoid control lag or framerate fluctuations due to multiple frame buffering
-    // If a query was issued on the previous frame, first wait for it to finish
-    if (impl->frameQuery_)
-    {
-        if (impl->queryIssued_)
-        {
-            URHO3D_PROFILE(FlushGPU);
-
-            while (impl->frameQuery_->GetData(nullptr, 0, D3DGETDATA_FLUSH) == S_FALSE)
-            {
-            }
-
-            impl->queryIssued_ = false;
-        }
-
-        if (flushGPU_)
-        {
-            impl->frameQuery_->Issue(D3DISSUE_END);
-            impl->queryIssued_ = true;
-        }
-    }
-
-    // Clean up too large scratch buffers
-    CleanupScratchBuffers();
-}
-
-void Graphics::Clear_D3D9(ClearTargetFlags flags, const Color& color, float depth, unsigned stencil)
-{
-    DWORD d3dFlags = 0;
-    if (flags & CLEAR_COLOR)
-        d3dFlags |= D3DCLEAR_TARGET;
-    if (flags & CLEAR_DEPTH)
-        d3dFlags |= D3DCLEAR_ZBUFFER;
-    if (flags & CLEAR_STENCIL)
-        d3dFlags |= D3DCLEAR_STENCIL;
-
-    GetImpl_D3D9()->device_->Clear(0, nullptr, d3dFlags, GetD3DColor(color), depth, stencil);
-}
-
-bool Graphics::ResolveToTexture_D3D9(Texture2D* destination, const IntRect& viewport)
-{
-    if (!destination || !destination->GetRenderSurface())
-        return false;
-
-    URHO3D_PROFILE(ResolveToTexture_D3D9);
-
-    IntRect vpCopy = viewport;
-    if (vpCopy.right_ <= vpCopy.left_)
-        vpCopy.right_ = vpCopy.left_ + 1;
-    if (vpCopy.bottom_ <= vpCopy.top_)
-        vpCopy.bottom_ = vpCopy.top_ + 1;
-
-    RECT rect;
-    rect.left = Clamp(vpCopy.left_, 0, width_);
-    rect.top = Clamp(vpCopy.top_, 0, height_);
-    rect.right = Clamp(vpCopy.right_, 0, width_);
-    rect.bottom = Clamp(vpCopy.bottom_, 0, height_);
-
-    RECT destRect;
-    destRect.left = 0;
-    destRect.top = 0;
-    destRect.right = destination->GetWidth();
-    destRect.bottom = destination->GetHeight();
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    HRESULT hr = impl->device_->StretchRect(impl->defaultColorSurface_, &rect,
-        (IDirect3DSurface9*)destination->GetRenderSurface()->GetSurface(), &destRect, D3DTEXF_NONE);
-    if (FAILED(hr))
-    {
-        URHO3D_LOGD3DERROR("Failed to resolve to texture", hr);
-        return false;
-    }
-    else
-        return true;
-}
-
-bool Graphics::ResolveToTexture_D3D9(Texture2D* texture)
-{
-    if (!texture || !texture->GetRenderSurface() || !texture->GetGPUObject() || texture->GetMultiSample() < 2)
-        return false;
-
-    URHO3D_PROFILE(ResolveToTexture_D3D9);
-
-    // Clear dirty flag already, because if resolve fails it's no use to retry (e.g. on the same frame)
-    RenderSurface* surface = texture->GetRenderSurface();
-    texture->SetResolveDirty(false);
-    surface->SetResolveDirty(false);
-
-    RECT rect;
-    rect.left = 0;
-    rect.top = 0;
-    rect.right = texture->GetWidth();
-    rect.bottom = texture->GetHeight();
-
-    IDirect3DSurface9* srcSurface = (IDirect3DSurface9*)surface->GetSurface();
-    IDirect3DTexture9* destTexture = (IDirect3DTexture9*)texture->GetGPUObject();
-    IDirect3DSurface9* destSurface = nullptr;
-    HRESULT hr = destTexture->GetSurfaceLevel(0, &destSurface);
-    if (FAILED(hr))
-    {
-        URHO3D_LOGD3DERROR("Failed to get destination surface for resolve", hr);
-        URHO3D_SAFE_RELEASE(destSurface);
-        return false;
-    }
-
-    hr = GetImpl_D3D9()->device_->StretchRect(srcSurface, &rect, destSurface, &rect, D3DTEXF_NONE);
-    URHO3D_SAFE_RELEASE(destSurface);
-    if (FAILED(hr))
-    {
-        URHO3D_LOGD3DERROR("Failed to resolve to texture", hr);
-        return false;
-    }
-    else
-        return true;
-}
-
-bool Graphics::ResolveToTexture_D3D9(TextureCube* texture)
-{
-    if (!texture || !texture->GetRenderSurface(FACE_POSITIVE_X) || !texture->GetGPUObject() || texture->GetMultiSample() < 2)
-        return false;
-
-    URHO3D_PROFILE(ResolveToTexture_D3D9);
-
-    texture->SetResolveDirty(false);
-
-    RECT rect;
-    rect.left = 0;
-    rect.top = 0;
-    rect.right = texture->GetWidth();
-    rect.bottom = texture->GetHeight();
-
-    for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
-    {
-        // Resolve only the surface(s) that were actually rendered to
-        RenderSurface* surface = texture->GetRenderSurface((CubeMapFace)i);
-        if (!surface->IsResolveDirty())
-            continue;
-
-        surface->SetResolveDirty(false);
-        IDirect3DSurface9* srcSurface = (IDirect3DSurface9*)surface->GetSurface();
-        IDirect3DCubeTexture9* destTexture = (IDirect3DCubeTexture9*)texture->GetGPUObject();
-        IDirect3DSurface9* destSurface = nullptr;
-        HRESULT hr = destTexture->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &destSurface);
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Failed to get destination surface for resolve", hr);
-            URHO3D_SAFE_RELEASE(destSurface);
-            return false;
-        }
-
-        hr = GetImpl_D3D9()->device_->StretchRect(srcSurface, &rect, destSurface, &rect, D3DTEXF_NONE);
-        URHO3D_SAFE_RELEASE(destSurface);
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Failed to resolve to texture", hr);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-void Graphics::Draw_D3D9(PrimitiveType type, unsigned vertexStart, unsigned vertexCount)
-{
-    if (!vertexCount)
-        return;
-
-    ResetStreamFrequencies_D3D9();
-
-    unsigned primitiveCount;
-    D3DPRIMITIVETYPE d3dPrimitiveType;
-
-    GetD3DPrimitiveType(vertexCount, type, primitiveCount, d3dPrimitiveType);
-    GetImpl_D3D9()->device_->DrawPrimitive(d3dPrimitiveType, vertexStart, primitiveCount);
-
-    numPrimitives_ += primitiveCount;
-    ++numBatches_;
-}
-
-void Graphics::Draw_D3D9(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount)
-{
-    if (!indexCount)
-        return;
-
-    ResetStreamFrequencies_D3D9();
-
-    unsigned primitiveCount;
-    D3DPRIMITIVETYPE d3dPrimitiveType;
-
-    GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
-    GetImpl_D3D9()->device_->DrawIndexedPrimitive(d3dPrimitiveType, 0, minVertex, vertexCount, indexStart, primitiveCount);
-
-    numPrimitives_ += primitiveCount;
-    ++numBatches_;
-}
-
-void Graphics::Draw_D3D9(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned baseVertexIndex, unsigned minVertex, unsigned vertexCount)
-{
-    if (!indexCount)
-        return;
-
-    ResetStreamFrequencies_D3D9();
-
-    unsigned primitiveCount;
-    D3DPRIMITIVETYPE d3dPrimitiveType;
-
-    GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
-    GetImpl_D3D9()->device_->DrawIndexedPrimitive(d3dPrimitiveType, baseVertexIndex, minVertex, vertexCount, indexStart, primitiveCount);
-
-    numPrimitives_ += primitiveCount;
-    ++numBatches_;
-}
-
-void Graphics::DrawInstanced_D3D9(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount,
-    unsigned instanceCount)
-{
-    if (!indexCount || !instanceCount)
-        return;
-
-    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
-    {
-        VertexBuffer* buffer = vertexBuffers_[i];
-        if (buffer)
-        {
-            const PODVector<VertexElement>& elements = buffer->GetElements();
-            // Check if buffer has per-instance data
-            if (elements.Size() && elements[0].perInstance_)
-                SetStreamFrequency_D3D9(i, D3DSTREAMSOURCE_INSTANCEDATA | 1u);
-            else
-                SetStreamFrequency_D3D9(i, D3DSTREAMSOURCE_INDEXEDDATA | instanceCount);
-        }
-    }
-
-    unsigned primitiveCount;
-    D3DPRIMITIVETYPE d3dPrimitiveType;
-
-    GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
-    GetImpl_D3D9()->device_->DrawIndexedPrimitive(d3dPrimitiveType, 0, minVertex, vertexCount, indexStart, primitiveCount);
-
-    numPrimitives_ += instanceCount * primitiveCount;
-    ++numBatches_;
-}
-
-void Graphics::DrawInstanced_D3D9(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned baseVertexIndex, unsigned minVertex,
-    unsigned vertexCount, unsigned instanceCount)
-{
-    if (!indexCount || !instanceCount)
-        return;
-
-    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
-    {
-        VertexBuffer* buffer = vertexBuffers_[i];
-        if (buffer)
-        {
-            const PODVector<VertexElement>& elements = buffer->GetElements();
-            // Check if buffer has per-instance data
-            if (elements.Size() && elements[0].perInstance_)
-                SetStreamFrequency_D3D9(i, D3DSTREAMSOURCE_INSTANCEDATA | 1u);
-            else
-                SetStreamFrequency_D3D9(i, D3DSTREAMSOURCE_INDEXEDDATA | instanceCount);
-        }
-    }
-
-    unsigned primitiveCount;
-    D3DPRIMITIVETYPE d3dPrimitiveType;
-
-    GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
-    GetImpl_D3D9()->device_->DrawIndexedPrimitive(d3dPrimitiveType, baseVertexIndex, minVertex, vertexCount, indexStart, primitiveCount);
-
-    numPrimitives_ += instanceCount * primitiveCount;
-    ++numBatches_;
-}
-
-void Graphics::SetVertexBuffer_D3D9(VertexBuffer* buffer)
-{
-    // Note: this is not multi-instance safe
-    static PODVector<VertexBuffer*> vertexBuffers(1);
-    vertexBuffers[0] = buffer;
-    SetVertexBuffers_D3D9(vertexBuffers);
-}
-
-bool Graphics::SetVertexBuffers_D3D9(const PODVector<VertexBuffer*>& buffers, unsigned instanceOffset)
-{
-    if (buffers.Size() > MAX_VERTEX_STREAMS)
-    {
-        URHO3D_LOGERROR("Too many vertex buffers");
-        return false;
-    }
-
-    // Build vertex declaration hash code out of the buffers
-    unsigned long long hash = 0;
-    for (unsigned i = 0; i < buffers.Size(); ++i)
-    {
-        if (!buffers[i])
-            continue;
-
-        hash |= buffers[i]->GetBufferHash(i);
-    }
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (hash)
-    {
-        // If no previous vertex declaration for that hash, create new
-        VertexDeclarationMap_D3D9::Iterator i = impl->vertexDeclarations_.Find(hash);
-        if (i == impl->vertexDeclarations_.End())
-        {
-            SharedPtr<VertexDeclaration_D3D9> newDeclaration(new VertexDeclaration_D3D9(this, buffers));
-            if (!newDeclaration->GetDeclaration())
-                return false;
-
-            i = impl->vertexDeclarations_.Insert(MakePair(hash, newDeclaration));
-        }
-
-        VertexDeclaration_D3D9* declaration = i->second_;
-        if (declaration != impl->vertexDeclaration_)
-        {
-            impl->device_->SetVertexDeclaration(declaration->GetDeclaration());
-            impl->vertexDeclaration_ = declaration;
-        }
-    }
-
-    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
-    {
-        VertexBuffer* buffer = nullptr;
-        unsigned offset = 0;
-
-        if (i < buffers.Size() && buffers[i])
-        {
-            buffer = buffers[i];
-            const PODVector<VertexElement>& elements = buffer->GetElements();
-            // Check if buffer has per-instance data; add instance offset in that case
-            if (elements.Size() && elements[0].perInstance_)
-                offset = instanceOffset * buffer->GetVertexSize();
-        }
-
-        if (buffer != vertexBuffers_[i] || offset != impl->streamOffsets_[i])
-        {
-            if (buffer)
-                impl->device_->SetStreamSource(i, (IDirect3DVertexBuffer9*)buffer->GetGPUObject(), offset,
-                    buffer->GetVertexSize());
-            else
-                impl->device_->SetStreamSource(i, nullptr, 0, 0);
-
-            vertexBuffers_[i] = buffer;
-            impl->streamOffsets_[i] = offset;
-        }
-    }
-
-    return true;
-}
-
-bool Graphics::SetVertexBuffers_D3D9(const Vector<SharedPtr<VertexBuffer> >& buffers, unsigned instanceOffset)
-{
-    return SetVertexBuffers_D3D9(reinterpret_cast<const PODVector<VertexBuffer*>&>(buffers), instanceOffset);
-}
-
-void Graphics::SetIndexBuffer_D3D9(IndexBuffer* buffer)
-{
-    if (buffer != indexBuffer_)
-    {
-        GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-        if (buffer)
-            impl->device_->SetIndices((IDirect3DIndexBuffer9*)buffer->GetGPUObject());
-        else
-            impl->device_->SetIndices(nullptr);
-
-        indexBuffer_ = buffer;
-    }
-}
-
-void Graphics::SetShaders_D3D9(ShaderVariation* vs, ShaderVariation* ps)
-{
-    if (vs == vertexShader_ && ps == pixelShader_)
-        return;
-
-    ClearParameterSources_D3D9();
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (vs != vertexShader_)
-    {
-        // Create the shader now if not yet created. If already attempted, do not retry
-        if (vs && !vs->GetGPUObject())
-        {
-            if (vs->GetCompilerOutput().Empty())
-            {
-                URHO3D_PROFILE(CompileVertexShader);
-
-                bool success = vs->Create();
-                if (!success)
-                {
-                    URHO3D_LOGERROR("Failed to compile vertex shader " + vs->GetFullName() + ":\n" + vs->GetCompilerOutput());
-                    vs = nullptr;
-                }
-            }
-            else
-                vs = nullptr;
-        }
-
-        if (vs && vs->GetShaderType() == VS)
-            impl->device_->SetVertexShader((IDirect3DVertexShader9*)vs->GetGPUObject());
-        else
-        {
-            impl->device_->SetVertexShader(nullptr);
-            vs = nullptr;
-        }
-
-        vertexShader_ = vs;
-    }
-
-    if (ps != pixelShader_)
-    {
-        if (ps && !ps->GetGPUObject())
-        {
-            if (ps->GetCompilerOutput().Empty())
-            {
-                URHO3D_PROFILE(CompilePixelShader);
-
-                bool success = ps->Create();
-                if (!success)
-                {
-                    URHO3D_LOGERROR("Failed to compile pixel shader " + ps->GetFullName() + ":\n" + ps->GetCompilerOutput());
-                    ps = nullptr;
-                }
-            }
-            else
-                ps = nullptr;
-        }
-
-        if (ps && ps->GetShaderType() == PS)
-            impl->device_->SetPixelShader((IDirect3DPixelShader9*)ps->GetGPUObject());
-        else
-        {
-            impl->device_->SetPixelShader(nullptr);
-            ps = nullptr;
-        }
-
-        pixelShader_ = ps;
-    }
-
-    // Update current available shader parameters
-    if (vertexShader_ && pixelShader_)
-    {
-        Pair<ShaderVariation*, ShaderVariation*> key = MakePair(vertexShader_, pixelShader_);
-        ShaderProgramMap_D3D9::Iterator i = impl->shaderPrograms_.Find(key);
-        if (i != impl->shaderPrograms_.End())
-            impl->shaderProgram_ = i->second_.Get();
-        else
-        {
-            ShaderProgram_D3D9* newProgram = impl->shaderPrograms_[key] = new ShaderProgram_D3D9(vertexShader_, pixelShader_);
-            impl->shaderProgram_ = newProgram;
-        }
-    }
-    else
-        impl->shaderProgram_ = nullptr;
-
-    // Store shader combination if shader dumping in progress
-    if (shaderPrecache_)
-        shaderPrecache_->StoreShaders(vertexShader_, pixelShader_);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, const float* data, unsigned count)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantF(i->second_.register_, data, count / 4);
-    else
-        impl->device_->SetPixelShaderConstantF(i->second_.register_, data, count / 4);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, float value)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    static Vector4 data(Vector4::ZERO);
-    data.x_ = value;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantF(i->second_.register_, &data.x_, 1);
-    else
-        impl->device_->SetPixelShaderConstantF(i->second_.register_, &data.x_, 1);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, int value)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    /// \todo Int constants seem to have no effect on Direct3D9
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantI(i->second_.register_, &value, 1);
-    else
-        impl->device_->SetPixelShaderConstantI(i->second_.register_, &value, 1);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, bool value)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    /// \todo Bool constants seem to have no effect on Direct3D9
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    BOOL data = value;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantB(i->second_.register_, &data, 1);
-    else
-        impl->device_->SetPixelShaderConstantB(i->second_.register_, &data, 1);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, const Color& color)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantF(i->second_.register_, color.Data(), 1);
-    else
-        impl->device_->SetPixelShaderConstantF(i->second_.register_, color.Data(), 1);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, const Vector2& vector)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    static Vector4 data(Vector4::ZERO);
-    data.x_ = vector.x_;
-    data.y_ = vector.y_;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantF(i->second_.register_, &data.x_, 1);
-    else
-        impl->device_->SetPixelShaderConstantF(i->second_.register_, &data.x_, 1);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, const Matrix3& matrix)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    static Matrix3x4 data(Matrix3x4::ZERO);
-    data.m00_ = matrix.m00_;
-    data.m01_ = matrix.m01_;
-    data.m02_ = matrix.m02_;
-    data.m10_ = matrix.m10_;
-    data.m11_ = matrix.m11_;
-    data.m12_ = matrix.m12_;
-    data.m20_ = matrix.m20_;
-    data.m21_ = matrix.m21_;
-    data.m22_ = matrix.m22_;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantF(i->second_.register_, &data.m00_, 3);
-    else
-        impl->device_->SetPixelShaderConstantF(i->second_.register_, &data.m00_, 3);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, const Vector3& vector)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    static Vector4 data(Vector4::ZERO);
-    data.x_ = vector.x_;
-    data.y_ = vector.y_;
-    data.z_ = vector.z_;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantF(i->second_.register_, &data.x_, 1);
-    else
-        impl->device_->SetPixelShaderConstantF(i->second_.register_, &data.x_, 1);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, const Matrix4& matrix)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantF(i->second_.register_, matrix.Data(), 4);
-    else
-        impl->device_->SetPixelShaderConstantF(i->second_.register_, matrix.Data(), 4);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, const Vector4& vector)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantF(i->second_.register_, vector.Data(), 1);
-    else
-        impl->device_->SetPixelShaderConstantF(i->second_.register_, vector.Data(), 1);
-}
-
-void Graphics::SetShaderParameter_D3D9(StringHash param, const Matrix3x4& matrix)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
-        return;
-
-    if (i->second_.type_ == VS)
-        impl->device_->SetVertexShaderConstantF(i->second_.register_, matrix.Data(), 3);
-    else
-        impl->device_->SetPixelShaderConstantF(i->second_.register_, matrix.Data(), 3);
-}
-
-bool Graphics::NeedParameterUpdate_D3D9(ShaderParameterGroup group, const void* source)
-{
-    if ((unsigned)(size_t)shaderParameterSources_[group] == M_MAX_UNSIGNED || shaderParameterSources_[group] != source)
-    {
-        shaderParameterSources_[group] = source;
-        return true;
-    }
-    else
-        return false;
-}
-
-bool Graphics::HasShaderParameter_D3D9(StringHash param)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    return impl->shaderProgram_ && impl->shaderProgram_->parameters_.Find(param) != impl->shaderProgram_->parameters_.End();
-}
-
-bool Graphics::HasTextureUnit_D3D9(TextureUnit unit)
-{
-    return pixelShader_ && pixelShader_->HasTextureUnit(unit);
-}
-
-void Graphics::ClearParameterSource_D3D9(ShaderParameterGroup group)
-{
-    shaderParameterSources_[group] = (const void*)M_MAX_UNSIGNED;
-}
-
-void Graphics::ClearParameterSources_D3D9()
-{
-    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
-        shaderParameterSources_[i] = (const void*)M_MAX_UNSIGNED;
-}
-
-void Graphics::ClearTransformSources_D3D9()
-{
-    shaderParameterSources_[SP_CAMERA] = (const void*)M_MAX_UNSIGNED;
-    shaderParameterSources_[SP_OBJECT] = (const void*)M_MAX_UNSIGNED;
-}
-
-void Graphics::SetTexture_D3D9(unsigned index, Texture* texture)
-{
-    if (index >= MAX_TEXTURE_UNITS)
-        return;
-
-    if (texture)
-    {
-        // Check if texture is currently bound as a rendertarget. In that case, use its backup texture, or blank if not defined
-        if (renderTargets_[0] && renderTargets_[0]->GetParentTexture() == texture)
-            texture = texture->GetBackupTexture();
-        else
-        {
-            // Resolve multisampled texture now as necessary
-            if (texture->GetMultiSample() > 1 && texture->GetAutoResolve() && texture->IsResolveDirty())
-            {
-                if (texture->GetType() == Texture2D::GetTypeStatic())
-                    ResolveToTexture_D3D9(static_cast<Texture2D*>(texture));
-                else if (texture->GetType() == TextureCube::GetTypeStatic())
-                    ResolveToTexture_D3D9(static_cast<TextureCube*>(texture));
-            }
-        }
-    }
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (texture != textures_[index])
-    {
-        if (texture)
-            impl->device_->SetTexture(index, (IDirect3DBaseTexture9*)texture->GetGPUObject());
-        else
-            impl->device_->SetTexture(index, nullptr);
-
-        textures_[index] = texture;
-    }
-
-    if (texture)
-    {
-        TextureFilterMode filterMode = texture->GetFilterMode();
-        if (filterMode == FILTER_DEFAULT)
-            filterMode = defaultTextureFilterMode_;
-
-        D3DTEXTUREFILTERTYPE min, mag, mip;
-        min = d3dMinFilter[filterMode];
-        if (min != impl->minFilters_[index])
-        {
-            impl->device_->SetSamplerState(index, D3DSAMP_MINFILTER, min);
-            impl->minFilters_[index] = min;
-        }
-        mag = d3dMagFilter[filterMode];
-        if (mag != impl->magFilters_[index])
-        {
-            impl->device_->SetSamplerState(index, D3DSAMP_MAGFILTER, mag);
-            impl->magFilters_[index] = mag;
-        }
-        mip = d3dMipFilter[filterMode];
-        if (mip != impl->mipFilters_[index])
-        {
-            impl->device_->SetSamplerState(index, D3DSAMP_MIPFILTER, mip);
-            impl->mipFilters_[index] = mip;
-        }
-        D3DTEXTUREADDRESS u, v;
-        u = d3dAddressMode[texture->GetAddressMode(COORD_U)];
-        if (u != impl->uAddressModes_[index])
-        {
-            impl->device_->SetSamplerState(index, D3DSAMP_ADDRESSU, u);
-            impl->uAddressModes_[index] = u;
-        }
-        v = d3dAddressMode[texture->GetAddressMode(COORD_V)];
-        if (v != impl->vAddressModes_[index])
-        {
-            impl->device_->SetSamplerState(index, D3DSAMP_ADDRESSV, v);
-            impl->vAddressModes_[index] = v;
-        }
-        if (texture->GetType() == TextureCube::GetTypeStatic())
-        {
-            D3DTEXTUREADDRESS w = d3dAddressMode[texture->GetAddressMode(COORD_W)];
-            if (w != impl->wAddressModes_[index])
-            {
-                impl->device_->SetSamplerState(index, D3DSAMP_ADDRESSW, w);
-                impl->wAddressModes_[index] = w;
-            }
-        }
-        unsigned maxAnisotropy = texture->GetAnisotropy();
-        if (!maxAnisotropy)
-            maxAnisotropy = defaultTextureAnisotropy_;
-        if (maxAnisotropy != impl->maxAnisotropy_[index])
-        {
-            impl->device_->SetSamplerState(index, D3DSAMP_MAXANISOTROPY, maxAnisotropy);
-            impl->maxAnisotropy_[index] = maxAnisotropy;
-        }
-        if (u == D3DTADDRESS_BORDER || v == D3DTADDRESS_BORDER)
-        {
-            const Color& borderColor = texture->GetBorderColor();
-            if (borderColor != impl->borderColors_[index])
-            {
-                impl->device_->SetSamplerState(index, D3DSAMP_BORDERCOLOR, GetD3DColor(borderColor));
-                impl->borderColors_[index] = borderColor;
-            }
-        }
-        if (sRGBSupport_)
-        {
-            bool sRGB = texture->GetSRGB();
-            if (sRGB != impl->sRGBModes_[index])
-            {
-                impl->device_->SetSamplerState(index, D3DSAMP_SRGBTEXTURE, sRGB ? TRUE : FALSE);
-                impl->sRGBModes_[index] = sRGB;
-            }
-        }
-    }
-}
-
-void Graphics::SetDefaultTextureFilterMode_D3D9(TextureFilterMode mode)
-{
-    defaultTextureFilterMode_ = mode;
-}
-
-void Graphics::SetDefaultTextureAnisotropy_D3D9(unsigned level)
-{
-    defaultTextureAnisotropy_ = Max(level, 1U);
-}
-
-void Graphics::ResetRenderTargets_D3D9()
-{
-    for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
-        SetRenderTarget_D3D9(i, (RenderSurface*)nullptr);
-    SetDepthStencil_D3D9((RenderSurface*)nullptr);
-    SetViewport_D3D9(IntRect(0, 0, width_, height_));
-}
-
-void Graphics::ResetRenderTarget_D3D9(unsigned index)
-{
-    SetRenderTarget_D3D9(index, (RenderSurface*)nullptr);
-}
-
-void Graphics::ResetDepthStencil_D3D9()
-{
-    SetDepthStencil_D3D9((RenderSurface*)nullptr);
-}
-
-void Graphics::SetRenderTarget_D3D9(unsigned index, RenderSurface* renderTarget)
-{
-    if (index >= MAX_RENDERTARGETS)
-        return;
-
-    IDirect3DSurface9* newColorSurface = nullptr;
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (renderTarget)
-    {
-        if (renderTarget->GetUsage() != TEXTURE_RENDERTARGET)
-            return;
-        newColorSurface = (IDirect3DSurface9*)renderTarget->GetSurface();
-    }
-    else
-    {
-        if (!index)
-            newColorSurface = impl->defaultColorSurface_;
-    }
-
-    renderTargets_[index] = renderTarget;
-
-    if (newColorSurface != impl->colorSurfaces_[index])
-    {
-        impl->device_->SetRenderTarget(index, newColorSurface);
-        impl->colorSurfaces_[index] = newColorSurface;
-        // Setting the first rendertarget causes viewport to be reset
-        if (!index)
-        {
-            IntVector2 rtSize = GetRenderTargetDimensions_D3D9();
-            viewport_ = IntRect(0, 0, rtSize.x_, rtSize.y_);
-        }
-    }
-
-    if (renderTarget)
-    {
-        Texture* parentTexture = renderTarget->GetParentTexture();
-
-        // If the rendertarget is also bound as a texture, replace with backup texture or null
-        for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-        {
-            if (textures_[i] == parentTexture)
-                SetTexture_D3D9(i, textures_[i]->GetBackupTexture());
-        }
-
-        // If multisampled, mark the texture & surface needing resolve
-        if (parentTexture->GetMultiSample() > 1 && parentTexture->GetAutoResolve())
-        {
-            parentTexture->SetResolveDirty(true);
-            renderTarget->SetResolveDirty(true);
-        }
-    }
-
-    // First rendertarget controls sRGB write mode
-    if (!index && sRGBWriteSupport_)
-    {
-        bool sRGBWrite = renderTarget ? renderTarget->GetParentTexture()->GetSRGB() : sRGB_;
-        if (sRGBWrite != impl->sRGBWrite_)
-        {
-            impl->device_->SetRenderState(D3DRS_SRGBWRITEENABLE, sRGBWrite ? TRUE : FALSE);
-            impl->sRGBWrite_ = sRGBWrite;
-        }
-    }
-}
-
-void Graphics::SetRenderTarget_D3D9(unsigned index, Texture2D* texture)
-{
-    RenderSurface* renderTarget = nullptr;
-    if (texture)
-        renderTarget = texture->GetRenderSurface();
-
-    SetRenderTarget_D3D9(index, renderTarget);
-}
-
-void Graphics::SetDepthStencil_D3D9(RenderSurface* depthStencil)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-    IDirect3DSurface9* newDepthStencilSurface = nullptr;
-    if (depthStencil && depthStencil->GetUsage() == TEXTURE_DEPTHSTENCIL)
-    {
-        newDepthStencilSurface = (IDirect3DSurface9*)depthStencil->GetSurface();
-        depthStencil_ = depthStencil;
-    }
-    if (!newDepthStencilSurface)
-    {
-        newDepthStencilSurface = impl->defaultDepthStencilSurface_;
-        depthStencil_ = nullptr;
-    }
-    if (newDepthStencilSurface != impl->depthStencilSurface_)
-    {
-        impl->device_->SetDepthStencilSurface(newDepthStencilSurface);
-        impl->depthStencilSurface_ = newDepthStencilSurface;
-    }
-}
-
-void Graphics::SetDepthStencil_D3D9(Texture2D* texture)
-{
-    RenderSurface* depthStencil = nullptr;
-    if (texture)
-        depthStencil = texture->GetRenderSurface();
-
-    SetDepthStencil_D3D9(depthStencil);
-}
-
-void Graphics::SetViewport_D3D9(const IntRect& rect)
-{
-    IntVector2 size = GetRenderTargetDimensions_D3D9();
-
-    IntRect rectCopy = rect;
-
-    if (rectCopy.right_ <= rectCopy.left_)
-        rectCopy.right_ = rectCopy.left_ + 1;
-    if (rectCopy.bottom_ <= rectCopy.top_)
-        rectCopy.bottom_ = rectCopy.top_ + 1;
-    rectCopy.left_ = Clamp(rectCopy.left_, 0, size.x_);
-    rectCopy.top_ = Clamp(rectCopy.top_, 0, size.y_);
-    rectCopy.right_ = Clamp(rectCopy.right_, 0, size.x_);
-    rectCopy.bottom_ = Clamp(rectCopy.bottom_, 0, size.y_);
-
-    D3DVIEWPORT9 vp;
-    vp.MinZ = 0.0f;
-    vp.MaxZ = 1.0f;
-    vp.X = (DWORD)rectCopy.left_;
-    vp.Y = (DWORD)rectCopy.top_;
-    vp.Width = (DWORD)rectCopy.Width();
-    vp.Height = (DWORD)rectCopy.Height();
-
-    GetImpl_D3D9()->device_->SetViewport(&vp);
-    viewport_ = rectCopy;
-
-    // Disable scissor test, needs to be re-enabled by the user
-    SetScissorTest_D3D9(false);
-}
-
-void Graphics::SetBlendMode_D3D9(BlendMode mode, bool /* alphaToCoverage */)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (mode != blendMode_)
-    {
-        if (d3dBlendEnable[mode] != impl->blendEnable_)
-        {
-            impl->device_->SetRenderState(D3DRS_ALPHABLENDENABLE, d3dBlendEnable[mode]);
-            impl->blendEnable_ = d3dBlendEnable[mode];
-        }
-
-        if (impl->blendEnable_)
-        {
-            if (d3dSrcBlend[mode] != impl->srcBlend_)
-            {
-                impl->device_->SetRenderState(D3DRS_SRCBLEND, d3dSrcBlend[mode]);
-                impl->srcBlend_ = d3dSrcBlend[mode];
-            }
-            if (d3dDestBlend[mode] != impl->destBlend_)
-            {
-                impl->device_->SetRenderState(D3DRS_DESTBLEND, d3dDestBlend[mode]);
-                impl->destBlend_ = d3dDestBlend[mode];
-            }
-            if (d3dBlendOp[mode] != impl->blendOp_)
-            {
-                impl->device_->SetRenderState(D3DRS_BLENDOP, d3dBlendOp[mode]);
-                impl->blendOp_ = d3dBlendOp[mode];
-            }
-        }
-
-        blendMode_ = mode;
-    }
-}
-
-void Graphics::SetColorWrite_D3D9(bool enable)
-{
-    if (enable != colorWrite_)
-    {
-        GetImpl_D3D9()->device_->SetRenderState(D3DRS_COLORWRITEENABLE,
-            enable ? D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA :
-                0);
-        colorWrite_ = enable;
-    }
-}
-
-void Graphics::SetCullMode_D3D9(CullMode mode)
-{
-    if (mode != cullMode_)
-    {
-        GetImpl_D3D9()->device_->SetRenderState(D3DRS_CULLMODE, d3dCullMode[mode]);
-        cullMode_ = mode;
-    }
-}
-
-void Graphics::SetDepthBias_D3D9(float constantBias, float slopeScaledBias)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (constantBias != constantDepthBias_)
-    {
-        impl->device_->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&constantBias));
-        constantDepthBias_ = constantBias;
-    }
-    if (slopeScaledBias != slopeScaledDepthBias_)
-    {
-        impl->device_->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&slopeScaledBias));
-        slopeScaledDepthBias_ = slopeScaledBias;
-    }
-}
-
-void Graphics::SetDepthTest_D3D9(CompareMode mode)
-{
-    if (mode != depthTestMode_)
-    {
-        GetImpl_D3D9()->device_->SetRenderState(D3DRS_ZFUNC, d3dCmpFunc[mode]);
-        depthTestMode_ = mode;
-    }
-}
-
-void Graphics::SetDepthWrite_D3D9(bool enable)
-{
-    if (enable != depthWrite_)
-    {
-        GetImpl_D3D9()->device_->SetRenderState(D3DRS_ZWRITEENABLE, enable ? TRUE : FALSE);
-        depthWrite_ = enable;
-    }
-}
-
-void Graphics::SetFillMode_D3D9(FillMode mode)
-{
-    if (mode != fillMode_)
-    {
-        GetImpl_D3D9()->device_->SetRenderState(D3DRS_FILLMODE, d3dFillMode[mode]);
-        fillMode_ = mode;
-    }
-}
-
-void Graphics::SetLineAntiAlias_D3D9(bool enable)
-{
-    if (enable != lineAntiAlias_)
-    {
-        GetImpl_D3D9()->device_->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, enable ? TRUE : FALSE);
-        lineAntiAlias_ = enable;
-    }
-}
-
-void Graphics::SetScissorTest_D3D9(bool enable, const Rect& rect, bool borderInclusive)
-{
-    // During some light rendering loops, a full rect is toggled on/off repeatedly.
-    // Disable scissor in that case to reduce state changes
-    if (rect.min_.x_ <= 0.0f && rect.min_.y_ <= 0.0f && rect.max_.x_ >= 1.0f && rect.max_.y_ >= 1.0f)
-        enable = false;
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (enable)
-    {
-        IntVector2 rtSize(GetRenderTargetDimensions_D3D9());
-        IntVector2 viewSize(viewport_.Size());
-        IntVector2 viewPos(viewport_.left_, viewport_.top_);
-        IntRect intRect;
-        int expand = borderInclusive ? 1 : 0;
-
-        intRect.left_ = Clamp((int)((rect.min_.x_ + 1.0f) * 0.5f * viewSize.x_) + viewPos.x_, 0, rtSize.x_ - 1);
-        intRect.top_ = Clamp((int)((-rect.max_.y_ + 1.0f) * 0.5f * viewSize.y_) + viewPos.y_, 0, rtSize.y_ - 1);
-        intRect.right_ = Clamp((int)((rect.max_.x_ + 1.0f) * 0.5f * viewSize.x_) + viewPos.x_ + expand, 0, rtSize.x_);
-        intRect.bottom_ = Clamp((int)((-rect.min_.y_ + 1.0f) * 0.5f * viewSize.y_) + viewPos.y_ + expand, 0, rtSize.y_);
-
-        if (intRect.right_ == intRect.left_)
-            intRect.right_++;
-        if (intRect.bottom_ == intRect.top_)
-            intRect.bottom_++;
-
-        if (intRect.right_ < intRect.left_ || intRect.bottom_ < intRect.top_)
-            enable = false;
-
-        if (enable && scissorRect_ != intRect)
-        {
-            RECT d3dRect;
-            d3dRect.left = intRect.left_;
-            d3dRect.top = intRect.top_;
-            d3dRect.right = intRect.right_;
-            d3dRect.bottom = intRect.bottom_;
-
-            impl->device_->SetScissorRect(&d3dRect);
-            scissorRect_ = intRect;
-        }
-    }
-    else
-        scissorRect_ = IntRect::ZERO;
-
-    if (enable != scissorTest_)
-    {
-        impl->device_->SetRenderState(D3DRS_SCISSORTESTENABLE, enable ? TRUE : FALSE);
-        scissorTest_ = enable;
-    }
-}
-
-void Graphics::SetScissorTest_D3D9(bool enable, const IntRect& rect)
-{
-    IntVector2 rtSize(GetRenderTargetDimensions_D3D9());
-    IntVector2 viewPos(viewport_.left_, viewport_.top_);
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (enable)
-    {
-        IntRect intRect;
-        intRect.left_ = Clamp(rect.left_ + viewPos.x_, 0, rtSize.x_ - 1);
-        intRect.top_ = Clamp(rect.top_ + viewPos.y_, 0, rtSize.y_ - 1);
-        intRect.right_ = Clamp(rect.right_ + viewPos.x_, 0, rtSize.x_);
-        intRect.bottom_ = Clamp(rect.bottom_ + viewPos.y_, 0, rtSize.y_);
-
-        if (intRect.right_ == intRect.left_)
-            intRect.right_++;
-        if (intRect.bottom_ == intRect.top_)
-            intRect.bottom_++;
-
-        if (intRect.right_ < intRect.left_ || intRect.bottom_ < intRect.top_)
-            enable = false;
-
-        if (enable && scissorRect_ != intRect)
-        {
-            RECT d3dRect;
-            d3dRect.left = intRect.left_;
-            d3dRect.top = intRect.top_;
-            d3dRect.right = intRect.right_;
-            d3dRect.bottom = intRect.bottom_;
-
-            impl->device_->SetScissorRect(&d3dRect);
-            scissorRect_ = intRect;
-        }
-    }
-    else
-        scissorRect_ = IntRect::ZERO;
-
-    if (enable != scissorTest_)
-    {
-        impl->device_->SetRenderState(D3DRS_SCISSORTESTENABLE, enable ? TRUE : FALSE);
-        scissorTest_ = enable;
-    }
-}
-
-void Graphics::SetStencilTest_D3D9(bool enable, CompareMode mode, StencilOp pass, StencilOp fail, StencilOp zFail, unsigned stencilRef,
-    unsigned compareMask, unsigned writeMask)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (enable != stencilTest_)
-    {
-        impl->device_->SetRenderState(D3DRS_STENCILENABLE, enable ? TRUE : FALSE);
-        stencilTest_ = enable;
-    }
-
-    if (enable)
-    {
-        if (mode != stencilTestMode_)
-        {
-            impl->device_->SetRenderState(D3DRS_STENCILFUNC, d3dCmpFunc[mode]);
-            stencilTestMode_ = mode;
-        }
-        if (pass != stencilPass_)
-        {
-            impl->device_->SetRenderState(D3DRS_STENCILPASS, d3dStencilOp[pass]);
-            stencilPass_ = pass;
-        }
-        if (fail != stencilFail_)
-        {
-            impl->device_->SetRenderState(D3DRS_STENCILFAIL, d3dStencilOp[fail]);
-            stencilFail_ = fail;
-        }
-        if (zFail != stencilZFail_)
-        {
-            impl->device_->SetRenderState(D3DRS_STENCILZFAIL, d3dStencilOp[zFail]);
-            stencilZFail_ = zFail;
-        }
-        if (stencilRef != stencilRef_)
-        {
-            impl->device_->SetRenderState(D3DRS_STENCILREF, stencilRef);
-            stencilRef_ = stencilRef;
-        }
-        if (compareMask != stencilCompareMask_)
-        {
-            impl->device_->SetRenderState(D3DRS_STENCILMASK, compareMask);
-            stencilCompareMask_ = compareMask;
-        }
-        if (writeMask != stencilWriteMask_)
-        {
-            impl->device_->SetRenderState(D3DRS_STENCILWRITEMASK, writeMask);
-            stencilWriteMask_ = writeMask;
-        }
-    }
-}
-
-void Graphics::SetClipPlane_D3D9(bool enable, const Plane& clipPlane, const Matrix3x4& view, const Matrix4& projection)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (enable != useClipPlane_)
-    {
-        impl->device_->SetRenderState(D3DRS_CLIPPLANEENABLE, enable ? 1 : 0);
-        useClipPlane_ = enable;
-    }
-
-    if (enable)
-    {
-        Matrix4 viewProj = projection * view;
-        impl->device_->SetClipPlane(0, clipPlane.Transformed(viewProj).ToVector4().Data());
-    }
-}
-
-bool Graphics::IsInitialized_D3D9() const
-{
-    return window_ != nullptr && GetImpl_D3D9()->GetDevice() != nullptr;
-}
-
-PODVector<int> Graphics::GetMultiSampleLevels_D3D9() const
-{
-    PODVector<int> ret;
-    // No multisampling always supported
-    ret.Push(1);
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (!impl->interface_)
-        return ret;
-
-    SDL_DisplayMode mode;
-    SDL_GetDesktopDisplayMode(0, &mode);
-    D3DFORMAT fullscreenFormat = SDL_BITSPERPIXEL(mode.format) == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
-
-    for (int i = (int)D3DMULTISAMPLE_2_SAMPLES; i < (int)D3DMULTISAMPLE_16_SAMPLES; ++i)
-    {
-        if (impl->CheckMultiSampleSupport(fullscreenFormat, i))
-            ret.Push(i);
-    }
-
-    return ret;
-}
-
-unsigned Graphics::GetFormat_D3D9(CompressedFormat format) const
-{
-    switch (format)
-    {
-    case CF_RGBA:
-        return D3DFMT_A8R8G8B8;
-
-    case CF_DXT1:
-        return D3DFMT_DXT1;
-
-    case CF_DXT3:
-        return D3DFMT_DXT3;
-
-    case CF_DXT5:
-        return D3DFMT_DXT5;
-
-    default:
-        return 0;
-    }
-}
-
-ShaderVariation* Graphics::GetShader_D3D9(ShaderType type, const String& name, const String& defines) const
-{
-    return GetShader_D3D9(type, name.CString(), defines.CString());
-}
-
-ShaderVariation* Graphics::GetShader_D3D9(ShaderType type, const char* name, const char* defines) const
-{
-    if (lastShaderName_ != name || !lastShader_)
-    {
-        ResourceCache* cache = GetSubsystem<ResourceCache>();
-
-        String fullShaderName = shaderPath_ + name + shaderExtension_;
-        // Try to reduce repeated error log prints because of missing shaders
-        if (lastShaderName_ == name && !cache->Exists(fullShaderName))
-            return nullptr;
-
-        lastShader_ = cache->GetResource<Shader>(fullShaderName);
-        lastShaderName_ = name;
-    }
-
-    return lastShader_ ? lastShader_->GetVariation(type, defines) : nullptr;
-}
-
-VertexBuffer* Graphics::GetVertexBuffer_D3D9(unsigned index) const
-{
-    return index < MAX_VERTEX_STREAMS ? vertexBuffers_[index] : nullptr;
-}
-
-TextureUnit Graphics::GetTextureUnit_D3D9(const String& name)
-{
-    HashMap<String, TextureUnit>::Iterator i = textureUnits_.Find(name);
-    if (i != textureUnits_.End())
-        return i->second_;
-    else
-        return MAX_TEXTURE_UNITS;
-}
-
-const String& Graphics::GetTextureUnitName_D3D9(TextureUnit unit)
-{
-    for (HashMap<String, TextureUnit>::Iterator i = textureUnits_.Begin(); i != textureUnits_.End(); ++i)
-    {
-        if (i->second_ == unit)
-            return i->first_;
-    }
-    return String::EMPTY;
-}
-
-Texture* Graphics::GetTexture_D3D9(unsigned index) const
-{
-    return index < MAX_TEXTURE_UNITS ? textures_[index] : nullptr;
-}
-
-RenderSurface* Graphics::GetRenderTarget_D3D9(unsigned index) const
-{
-    return index < MAX_RENDERTARGETS ? renderTargets_[index] : nullptr;
-}
-
-IntVector2 Graphics::GetRenderTargetDimensions_D3D9() const
-{
-    int width, height;
-
-    if (renderTargets_[0])
-    {
-        width = renderTargets_[0]->GetWidth();
-        height = renderTargets_[0]->GetHeight();
-    }
-    else
-    {
-        width = width_;
-        height = height_;
-    }
-
-    return IntVector2(width, height);
-}
-
-bool Graphics::GetDither_D3D9() const
-{
-    return false;
-}
-
-bool Graphics::IsDeviceLost_D3D9() const
-{
-    return GetImpl_D3D9()->deviceLost_;
-}
-
-void Graphics::OnWindowResized_D3D9()
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (!impl->device_ || !window_)
-        return;
-
-    int newWidth, newHeight;
-
-    SDL_GetWindowSize(window_, &newWidth, &newHeight);
-    if (newWidth == width_ && newHeight == height_)
-        return;
-
-    width_ = newWidth;
-    height_ = newHeight;
-
-    impl->presentParams_.BackBufferWidth = (UINT)width_;
-    impl->presentParams_.BackBufferHeight = (UINT)height_;
-    ResetDevice_D3D9();
-
-    // Reset rendertargets and viewport for the new screen size
-    ResetRenderTargets_D3D9();
-
-    URHO3D_LOGDEBUGF("Window was resized to %dx%d", width_, height_);
-
-    using namespace ScreenMode;
-
-    VariantMap& eventData = GetEventDataMap();
-    eventData[P_WIDTH] = width_;
-    eventData[P_HEIGHT] = height_;
-    eventData[P_FULLSCREEN] = screenParams_.fullscreen_;
-    eventData[P_RESIZABLE] = screenParams_.resizable_;
-    eventData[P_BORDERLESS] = screenParams_.borderless_;
-    eventData[P_HIGHDPI] = screenParams_.highDPI_;
-    SendEvent(E_SCREENMODE, eventData);
-}
-
-void Graphics::OnWindowMoved_D3D9()
-{
-    if (!GetImpl_D3D9()->device_ || !window_ || screenParams_.fullscreen_)
-        return;
-
-    int newX, newY;
-
-    SDL_GetWindowPosition(window_, &newX, &newY);
-    if (newX == position_.x_ && newY == position_.y_)
-        return;
-
-    position_.x_ = newX;
-    position_.y_ = newY;
-
-    URHO3D_LOGTRACEF("Window was moved to %d,%d", position_.x_, position_.y_);
-
-    using namespace WindowPos;
-
-    VariantMap& eventData = GetEventDataMap();
-    eventData[P_X] = position_.x_;
-    eventData[P_Y] = position_.y_;
-    SendEvent(E_WINDOWPOS, eventData);
-}
-
-void Graphics::CleanupShaderPrograms_D3D9(ShaderVariation* variation)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    for (ShaderProgramMap_D3D9::Iterator i = impl->shaderPrograms_.Begin(); i != impl->shaderPrograms_.End();)
-    {
-        if (i->first_.first_ == variation || i->first_.second_ == variation)
-            i = impl->shaderPrograms_.Erase(i);
-        else
-            ++i;
-    }
-
-    if (vertexShader_ == variation || pixelShader_ == variation)
-        impl->shaderProgram_ = nullptr;
-}
-
-ConstantBuffer* Graphics::GetOrCreateConstantBuffer_D3D9(ShaderType /*type*/, unsigned index, unsigned size)
-{
-    // No-op on Direct3D 9
-    return nullptr;
-}
-
-unsigned Graphics::GetAlphaFormat_D3D9()
-{
-    return D3DFMT_A8;
-}
-
-unsigned Graphics::GetLuminanceFormat_D3D9()
-{
-    return D3DFMT_L8;
-}
-
-unsigned Graphics::GetLuminanceAlphaFormat_D3D9()
-{
-    return D3DFMT_A8L8;
-}
-
-unsigned Graphics::GetRGBFormat_D3D9()
-{
-    return D3DFMT_X8R8G8B8;
-}
-
-unsigned Graphics::GetRGBAFormat_D3D9()
-{
-    return D3DFMT_A8R8G8B8;
-}
-
-unsigned Graphics::GetRGBA16Format_D3D9()
-{
-    return D3DFMT_A16B16G16R16;
-}
-
-unsigned Graphics::GetRGBAFloat16Format_D3D9()
-{
-    return D3DFMT_A16B16G16R16F;
-}
-
-unsigned Graphics::GetRGBAFloat32Format_D3D9()
-{
-    return D3DFMT_A32B32G32R32F;
-}
-
-unsigned Graphics::GetRG16Format_D3D9()
-{
-    return D3DFMT_G16R16;
-}
-
-unsigned Graphics::GetRGFloat16Format_D3D9()
-{
-    return D3DFMT_G16R16F;
-}
-
-unsigned Graphics::GetRGFloat32Format_D3D9()
-{
-    return D3DFMT_G32R32F;
-}
-
-unsigned Graphics::GetFloat16Format_D3D9()
-{
-    return D3DFMT_R16F;
-}
-
-unsigned Graphics::GetFloat32Format_D3D9()
-{
-    return D3DFMT_R32F;
-}
-
-unsigned Graphics::GetLinearDepthFormat_D3D9()
-{
-    return D3DFMT_R32F;
-}
-
-unsigned Graphics::GetDepthStencilFormat_D3D9()
-{
-    return D3DFMT_D24S8;
-}
-
-unsigned Graphics::GetReadableDepthFormat_D3D9()
-{
-    return readableDepthFormat;
-}
-
-unsigned Graphics::GetFormat_D3D9(const String& formatName)
-{
-    String nameLower = formatName.ToLower().Trimmed();
-
-    if (nameLower == "a")
-        return GetAlphaFormat_D3D9();
-    if (nameLower == "l")
-        return GetLuminanceFormat_D3D9();
-    if (nameLower == "la")
-        return GetLuminanceAlphaFormat_D3D9();
-    if (nameLower == "rgb")
-        return GetRGBFormat_D3D9();
-    if (nameLower == "rgba")
-        return GetRGBAFormat_D3D9();
-    if (nameLower == "rgba16")
-        return GetRGBA16Format_D3D9();
-    if (nameLower == "rgba16f")
-        return GetRGBAFloat16Format_D3D9();
-    if (nameLower == "rgba32f")
-        return GetRGBAFloat32Format_D3D9();
-    if (nameLower == "rg16")
-        return GetRG16Format_D3D9();
-    if (nameLower == "rg16f")
-        return GetRGFloat16Format_D3D9();
-    if (nameLower == "rg32f")
-        return GetRGFloat32Format_D3D9();
-    if (nameLower == "r16f")
-        return GetFloat16Format_D3D9();
-    if (nameLower == "r32f" || nameLower == "float")
-        return GetFloat32Format_D3D9();
-    if (nameLower == "lineardepth" || nameLower == "depth")
-        return GetLinearDepthFormat_D3D9();
-    if (nameLower == "d24s8")
-        return GetDepthStencilFormat_D3D9();
-    if (nameLower == "readabledepth" || nameLower == "hwdepth")
-        return GetReadableDepthFormat_D3D9();
-
-    return GetRGBFormat_D3D9();
-}
-
-unsigned Graphics::GetMaxBones_D3D9()
-{
-    return 64;
-}
-
-bool Graphics::GetGL3Support_D3D9()
-{
-    return false;
-}
-
-void Graphics::SetStreamFrequency_D3D9(unsigned index, unsigned frequency)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (index < MAX_VERTEX_STREAMS && impl->streamFrequencies_[index] != frequency)
-    {
-        impl->device_->SetStreamSourceFreq(index, frequency);
-        impl->streamFrequencies_[index] = frequency;
-    }
-}
-
-void Graphics::ResetStreamFrequencies_D3D9()
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
-    {
-        if (impl->streamFrequencies_[i] != 1)
-        {
-            impl->device_->SetStreamSourceFreq(i, 1);
-            impl->streamFrequencies_[i] = 1;
-        }
-    }
-}
-
-bool Graphics::OpenWindow_D3D9(int width, int height, bool resizable, bool borderless)
-{
-    if (!externalWindow_)
-    {
-        unsigned flags = 0;
-        if (resizable)
-            flags |= SDL_WINDOW_RESIZABLE;
-        if (borderless)
-            flags |= SDL_WINDOW_BORDERLESS;
-
-        window_ = SDL_CreateWindow(windowTitle_.CString(), position_.x_, position_.y_, width, height, flags);
-    }
-    else
-        window_ = SDL_CreateWindowFrom(externalWindow_, 0);
-
-    if (!window_)
-    {
-        URHO3D_LOGERRORF("Could not create window, root cause: '%s'", SDL_GetError());
-        return false;
-    }
-
-    SDL_GetWindowPosition(window_, &position_.x_, &position_.y_);
-
-    CreateWindowIcon();
-
-    return true;
-}
-
-void Graphics::AdjustWindow_D3D9(int& newWidth, int& newHeight, bool& newFullscreen, bool& newBorderless, int& monitor)
-{
-    if (!externalWindow_)
-    {
-        // Keep current window position because it may change in intermediate callbacks
-        const IntVector2 oldPosition = position_;
-        bool reposition = false;
-        bool resizePostponed = false;
-        if (!newWidth || !newHeight)
-        {
-            SDL_MaximizeWindow(window_);
-            SDL_GetWindowSize(window_, &newWidth, &newHeight);
-        }
-        else {
-            SDL_Rect display_rect;
-            SDL_GetDisplayBounds(monitor, &display_rect);
-
-            reposition = newFullscreen || (newBorderless && newWidth >= display_rect.w && newHeight >= display_rect.h);
-            if (reposition)
-            {
-                // Reposition the window on the specified monitor if it's supposed to cover the entire monitor
-                SDL_SetWindowPosition(window_, display_rect.x, display_rect.y);
-            }
-
-            // Postpone window resize if exiting fullscreen to avoid redundant resolution change
-            if (!newFullscreen && screenParams_.fullscreen_)
-                resizePostponed = true;
-            else
-                SDL_SetWindowSize(window_, newWidth, newHeight);
-        }
-
-        // Hack fix: on SDL 2.0.4 a fullscreen->windowed transition results in a maximized window when the D3D device is reset, so hide before
-        if (!newFullscreen) SDL_HideWindow(window_);
-        SDL_SetWindowFullscreen(window_, newFullscreen ? SDL_WINDOW_FULLSCREEN : 0);
-        SDL_SetWindowBordered(window_, newBorderless ? SDL_FALSE : SDL_TRUE);
-        if (!newFullscreen) SDL_ShowWindow(window_);
-
-        // Resize now if was postponed
-        if (resizePostponed)
-            SDL_SetWindowSize(window_, newWidth, newHeight);
-
-        // Ensure that window keeps its position
-        if (!reposition)
-            SDL_SetWindowPosition(window_, oldPosition.x_, oldPosition.y_);
-        else
-            position_ = oldPosition;
-    }
-    else
-    {
-        // If external window, must ask its dimensions instead of trying to set them
-        SDL_GetWindowSize(window_, &newWidth, &newHeight);
-        newFullscreen = false;
-    }
-}
-
-bool Graphics::CreateInterface_D3D9()
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    impl->interface_ = Direct3DCreate9(D3D_SDK_VERSION);
-    if (!impl->interface_)
-    {
-        URHO3D_LOGERROR("Could not create Direct3D9 interface");
-        return false;
-    }
-
-    HRESULT hr = impl->interface_->GetDeviceCaps(impl->adapter_, impl->deviceType_, &impl->deviceCaps_);
-    if (FAILED(hr))
-    {
-        URHO3D_LOGD3DERROR("Could not get Direct3D capabilities", hr);
-        return false;
-    }
-
-    hr = impl->interface_->GetAdapterIdentifier(impl->adapter_, 0, &impl->adapterIdentifier_);
-    if (FAILED(hr))
-    {
-        URHO3D_LOGD3DERROR("Could not get Direct3D adapter identifier", hr);
-        return false;
-    }
-
-    if (impl->deviceCaps_.PixelShaderVersion < D3DPS_VERSION(3, 0))
-    {
-        URHO3D_LOGERROR("Shader model 3.0 display adapter is required");
-        return false;
-    }
-
-    return true;
-}
-
-bool Graphics::CreateDevice_D3D9(unsigned adapter, unsigned deviceType)
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-#ifdef URHO3D_LUAJIT
-    DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE;
-#else
-    DWORD behaviorFlags = 0;
-#endif
-    if (impl->deviceCaps_.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
-    {
-        behaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
-        if (impl->deviceCaps_.DevCaps & D3DDEVCAPS_PUREDEVICE)
-            behaviorFlags |= D3DCREATE_PUREDEVICE;
-    }
-    else
-        behaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
-
-    HRESULT hr = impl->interface_->CreateDevice(
-        adapter,
-        (D3DDEVTYPE)deviceType,
-        GetWindowHandle(window_),
-        behaviorFlags,
-        &impl->presentParams_,
-        &impl->device_);
-    if (FAILED(hr))
-    {
-        URHO3D_LOGD3DERROR("Could not create Direct3D9 device", hr);
-        return false;
-    }
-
-    impl->adapter_ = adapter;
-    impl->deviceType_ = (D3DDEVTYPE)deviceType;
-
-    OnDeviceReset_D3D9();
-
-    URHO3D_LOGINFO("Created Direct3D9 device");
-    return true;
-}
-
-void Graphics::CheckFeatureSupport_D3D9()
-{
-    anisotropySupport_ = true;
-    dxtTextureSupport_ = true;
-
-    // Reset features first
-    lightPrepassSupport_ = false;
-    deferredSupport_ = false;
-    hardwareShadowSupport_ = false;
-    instancingSupport_ = false;
-    readableDepthFormat = 0;
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    // Check hardware shadow map support: prefer NVIDIA style hardware depth compared shadow maps if available
-    shadowMapFormat_ = D3DFMT_D16;
-    if (impl->CheckFormatSupport((D3DFORMAT)shadowMapFormat_, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE))
-    {
-        hardwareShadowSupport_ = true;
-
-        // Check for hires depth support
-        hiresShadowMapFormat_ = D3DFMT_D24X8;
-        if (!impl->CheckFormatSupport((D3DFORMAT)hiresShadowMapFormat_, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE))
-            hiresShadowMapFormat_ = 0;
-    }
-    else
-    {
-        // ATI DF16 format needs manual depth compare in the shader
-        shadowMapFormat_ = MAKEFOURCC('D', 'F', '1', '6');
-        if (impl->CheckFormatSupport((D3DFORMAT)shadowMapFormat_, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE))
-        {
-            // Check for hires depth support
-            hiresShadowMapFormat_ = MAKEFOURCC('D', 'F', '2', '4');
-            if (!impl->CheckFormatSupport((D3DFORMAT)hiresShadowMapFormat_, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE))
-                hiresShadowMapFormat_ = 0;
-        }
-        else
-        {
-            // No shadow map support
-            shadowMapFormat_ = 0;
-            hiresShadowMapFormat_ = 0;
-        }
-    }
-
-    // Check for Intel 4 Series with an old driver, enable manual shadow map compare in that case
-    if (shadowMapFormat_ == D3DFMT_D16)
-    {
-        if (impl->adapterIdentifier_.VendorId == 0x8086 && impl->adapterIdentifier_.DeviceId == 0x2a42 &&
-            impl->adapterIdentifier_.DriverVersion.QuadPart <= 0x0007000f000a05d0ULL)
-            hardwareShadowSupport_ = false;
-    }
-
-    // Check for readable depth (INTZ hack)
-    D3DFORMAT intZFormat = (D3DFORMAT)MAKEFOURCC('I', 'N', 'T', 'Z');
-    if (impl->CheckFormatSupport(intZFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE))
-        readableDepthFormat = intZFormat;
-
-    // Check for dummy color rendertarget format used with hardware shadow maps
-    dummyColorFormat_ = D3DFMT_A8R8G8B8;
-    D3DFORMAT nullFormat = (D3DFORMAT)MAKEFOURCC('N', 'U', 'L', 'L');
-    if (impl->CheckFormatSupport(nullFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE))
-        dummyColorFormat_ = nullFormat;
-    else if (impl->CheckFormatSupport(D3DFMT_R16F, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE))
-        dummyColorFormat_ = D3DFMT_R16F;
-    else if (impl->CheckFormatSupport(D3DFMT_R5G6B5, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE))
-        dummyColorFormat_ = D3DFMT_R5G6B5;
-    else if (impl->CheckFormatSupport(D3DFMT_A4R4G4B4, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE))
-        dummyColorFormat_ = D3DFMT_A4R4G4B4;
-
-    // Check for light prepass and deferred rendering support
-    if (impl->deviceCaps_.NumSimultaneousRTs >= 2 && impl->CheckFormatSupport(D3DFMT_R32F, D3DUSAGE_RENDERTARGET,
-        D3DRTYPE_TEXTURE))
-    {
-        lightPrepassSupport_ = true;
-        if (impl->deviceCaps_.NumSimultaneousRTs >= 4)
-            deferredSupport_ = true;
-    }
-
-    // Check for stream offset (needed for instancing)
-    if (impl->deviceCaps_.DevCaps2 & D3DDEVCAPS2_STREAMOFFSET)
-        instancingSupport_ = true;
-
-    // Check for sRGB read & write
-    /// \todo Should be checked for each texture format separately
-    sRGBSupport_ = impl->CheckFormatSupport(D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_TEXTURE);
-    sRGBWriteSupport_ = impl->CheckFormatSupport(D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBWRITE, D3DRTYPE_TEXTURE);
-}
-
-void Graphics::ResetDevice_D3D9()
-{
-    OnDeviceLost_D3D9();
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (SUCCEEDED(impl->device_->Reset(&impl->presentParams_)))
-    {
-        impl->deviceLost_ = false;
-        OnDeviceReset_D3D9();
-    }
-}
-
-void Graphics::OnDeviceLost_D3D9()
-{
-    URHO3D_LOGINFO("Device lost");
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    if (impl->defaultColorSurface_)
-    {
-        impl->defaultColorSurface_->Release();
-        impl->defaultColorSurface_ = nullptr;
-    }
-    if (impl->defaultDepthStencilSurface_)
-    {
-        impl->defaultDepthStencilSurface_->Release();
-        impl->defaultDepthStencilSurface_ = nullptr;
-    }
-    if (impl->frameQuery_)
-    {
-        impl->frameQuery_->Release();
-        impl->frameQuery_ = nullptr;
-    }
-
-    {
-        MutexLock lock(gpuObjectMutex_);
-
-        for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
-            (*i)->OnDeviceLost();
-    }
-
-    SendEvent(E_DEVICELOST);
-}
-
-void Graphics::OnDeviceReset_D3D9()
-{
-    {
-        MutexLock lock(gpuObjectMutex_);
-
-        for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
-            (*i)->OnDeviceReset();
-    }
-
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    // Get default surfaces
-    impl->device_->GetRenderTarget(0, &impl->defaultColorSurface_);
-    impl->device_->GetDepthStencilSurface(&impl->defaultDepthStencilSurface_);
-
-    // Create frame query for flushing the GPU command buffer
-    impl->device_->CreateQuery(D3DQUERYTYPE_EVENT, &impl->frameQuery_);
-
-    ResetCachedState_D3D9();
-
-    SendEvent(E_DEVICERESET);
-}
-
-void Graphics::ResetCachedState_D3D9()
-{
-    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
-
-    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
-    {
-        vertexBuffers_[i] = nullptr;
-        impl->streamOffsets_[i] = 0;
-    }
-
-    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-    {
-        textures_[i] = nullptr;
-        impl->minFilters_[i] = D3DTEXF_POINT;
-        impl->magFilters_[i] = D3DTEXF_POINT;
-        impl->mipFilters_[i] = D3DTEXF_NONE;
-        impl->uAddressModes_[i] = D3DTADDRESS_WRAP;
-        impl->vAddressModes_[i] = D3DTADDRESS_WRAP;
-        impl->wAddressModes_[i] = D3DTADDRESS_WRAP;
-        impl->maxAnisotropy_[i] = M_MAX_UNSIGNED;
-        impl->borderColors_[i] = Color(0.0f, 0.0f, 0.0f, 0.0f);
-        impl->sRGBModes_[i] = false;
-    }
-
-    for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
-    {
-        renderTargets_[i] = nullptr;
-        impl->colorSurfaces_[i] = nullptr;
-    }
-
-    depthStencil_ = nullptr;
-    impl->depthStencilSurface_ = nullptr;
-    viewport_ = IntRect(0, 0, width_, height_);
-    impl->sRGBWrite_ = false;
-
-    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
-        impl->streamFrequencies_[i] = 1;
-
-    indexBuffer_ = nullptr;
-    vertexShader_ = nullptr;
-    pixelShader_ = nullptr;
-    blendMode_ = BLEND_REPLACE;
-    alphaToCoverage_ = false;
-    colorWrite_ = true;
-    cullMode_ = CULL_CCW;
-    constantDepthBias_ = 0.0f;
-    slopeScaledDepthBias_ = 0.0f;
-    depthTestMode_ = CMP_LESSEQUAL;
-    depthWrite_ = true;
-    lineAntiAlias_ = false;
-    fillMode_ = FILL_SOLID;
-    scissorTest_ = false;
-    scissorRect_ = IntRect::ZERO;
-    stencilTest_ = false;
-    stencilTestMode_ = CMP_ALWAYS;
-    stencilPass_ = OP_KEEP;
-    stencilFail_ = OP_KEEP;
-    stencilZFail_ = OP_KEEP;
-    stencilRef_ = 0;
-    stencilCompareMask_ = M_MAX_UNSIGNED;
-    stencilWriteMask_ = M_MAX_UNSIGNED;
-    useClipPlane_ = false;
-    impl->blendEnable_ = FALSE;
-    impl->srcBlend_ = D3DBLEND_ONE;
-    impl->destBlend_ = D3DBLEND_ZERO;
-    impl->blendOp_ = D3DBLENDOP_ADD;
-    impl->vertexDeclaration_ = nullptr;
-    impl->queryIssued_ = false;
-}
-
-void Graphics::SetTextureUnitMappings_D3D9()
-{
-    textureUnits_["DiffMap"] = TU_DIFFUSE;
-    textureUnits_["DiffCubeMap"] = TU_DIFFUSE;
-    textureUnits_["NormalMap"] = TU_NORMAL;
-    textureUnits_["SpecMap"] = TU_SPECULAR;
-    textureUnits_["EmissiveMap"] = TU_EMISSIVE;
-    textureUnits_["EnvMap"] = TU_ENVIRONMENT;
-    textureUnits_["EnvCubeMap"] = TU_ENVIRONMENT;
-    textureUnits_["LightRampMap"] = TU_LIGHTRAMP;
-    textureUnits_["LightSpotMap"] = TU_LIGHTSHAPE;
-    textureUnits_["LightCubeMap"] = TU_LIGHTSHAPE;
-    textureUnits_["ShadowMap"] = TU_SHADOWMAP;
-    textureUnits_["FaceSelectCubeMap"] = TU_FACESELECT;
-    textureUnits_["IndirectionCubeMap"] = TU_INDIRECTION;
-    textureUnits_["VolumeMap"] = TU_VOLUMEMAP;
-    textureUnits_["ZoneCubeMap"] = TU_ZONE;
-    textureUnits_["ZoneVolumeMap"] = TU_ZONE;
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Core/Context.h"
+#include "../../Core/ProcessUtils.h"
+#include "../../Core/Profiler.h"
+#include "../../Graphics/Graphics.h"
+#include "../../Graphics/GraphicsEvents.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9GraphicsImpl.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9ShaderProgram.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9VertexDeclaration.h"
+#include "../../GraphicsAPI/GraphicsImpl.h"
+#include "../../GraphicsAPI/IndexBuffer.h"
+#include "../../GraphicsAPI/Shader.h"
+#include "../../GraphicsAPI/ShaderPrecache.h"
+#include "../../GraphicsAPI/Texture2D.h"
+#include "../../GraphicsAPI/TextureCube.h"
+#include "../../GraphicsAPI/VertexBuffer.h"
+#include "../../IO/File.h"
+#include "../../IO/Log.h"
+#include "../../Resource/ResourceCache.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_syswm.h>
+
+#include "../../DebugNew.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable:4355)
+#endif
+
+// Fix missing define in MinGW headers
+#ifndef D3DPRESENT_LINEAR_CONTENT
+#define D3DPRESENT_LINEAR_CONTENT 0x00000002L
+#endif
+#ifndef D3DSTREAMSOURCE_INDEXEDDATA
+#define D3DSTREAMSOURCE_INDEXEDDATA (1<<30)
+#endif
+#ifndef D3DSTREAMSOURCE_INSTANCEDATA
+#define D3DSTREAMSOURCE_INSTANCEDATA (2<<30)
+#endif
+
+namespace Urho3D
+{
+
+static const D3DCMPFUNC d3dCmpFunc[] =
+{
+    D3DCMP_ALWAYS,
+    D3DCMP_EQUAL,
+    D3DCMP_NOTEQUAL,
+    D3DCMP_LESS,
+    D3DCMP_LESSEQUAL,
+    D3DCMP_GREATER,
+    D3DCMP_GREATEREQUAL
+};
+
+static const D3DTEXTUREFILTERTYPE d3dMinFilter[] =
+{
+    D3DTEXF_POINT,
+    D3DTEXF_LINEAR,
+    D3DTEXF_LINEAR,
+    D3DTEXF_ANISOTROPIC,
+    D3DTEXF_ANISOTROPIC
+};
+
+static const D3DTEXTUREFILTERTYPE d3dMagFilter[] =
+{
+    D3DTEXF_POINT,
+    D3DTEXF_LINEAR,
+    D3DTEXF_LINEAR,
+    D3DTEXF_ANISOTROPIC,
+    D3DTEXF_POINT,
+};
+
+static const D3DTEXTUREFILTERTYPE d3dMipFilter[] =
+{
+    D3DTEXF_POINT,
+    D3DTEXF_POINT,
+    D3DTEXF_LINEAR,
+    D3DTEXF_ANISOTROPIC,
+    D3DTEXF_ANISOTROPIC
+};
+
+static const D3DTEXTUREADDRESS d3dAddressMode[] =
+{
+    D3DTADDRESS_WRAP,
+    D3DTADDRESS_MIRROR,
+    D3DTADDRESS_CLAMP,
+    D3DTADDRESS_BORDER
+};
+
+static const DWORD d3dBlendEnable[] =
+{
+    FALSE,
+    TRUE,
+    TRUE,
+    TRUE,
+    TRUE,
+    TRUE,
+    TRUE,
+    TRUE,
+    TRUE
+};
+
+static const D3DBLEND d3dSrcBlend[] =
+{
+    D3DBLEND_ONE,
+    D3DBLEND_ONE,
+    D3DBLEND_DESTCOLOR,
+    D3DBLEND_SRCALPHA,
+    D3DBLEND_SRCALPHA,
+    D3DBLEND_ONE,
+    D3DBLEND_INVDESTALPHA,
+    D3DBLEND_ONE,
+    D3DBLEND_SRCALPHA,
+};
+
+static const D3DBLEND d3dDestBlend[] =
+{
+    D3DBLEND_ZERO,
+    D3DBLEND_ONE,
+    D3DBLEND_ZERO,
+    D3DBLEND_INVSRCALPHA,
+    D3DBLEND_ONE,
+    D3DBLEND_INVSRCALPHA,
+    D3DBLEND_DESTALPHA,
+    D3DBLEND_ONE,
+    D3DBLEND_ONE
+};
+
+static const D3DBLENDOP d3dBlendOp[] =
+{
+    D3DBLENDOP_ADD,
+    D3DBLENDOP_ADD,
+    D3DBLENDOP_ADD,
+    D3DBLENDOP_ADD,
+    D3DBLENDOP_ADD,
+    D3DBLENDOP_ADD,
+    D3DBLENDOP_ADD,
+    D3DBLENDOP_REVSUBTRACT,
+    D3DBLENDOP_REVSUBTRACT
+};
+
+static const D3DCULL d3dCullMode[] =
+{
+    D3DCULL_NONE,
+    D3DCULL_CCW,
+    D3DCULL_CW
+};
+
+static const D3DFILLMODE d3dFillMode[] =
+{
+    D3DFILL_SOLID,
+    D3DFILL_WIREFRAME,
+    D3DFILL_POINT
+};
+
+static const D3DSTENCILOP d3dStencilOp[] =
+{
+    D3DSTENCILOP_KEEP,
+    D3DSTENCILOP_ZERO,
+    D3DSTENCILOP_REPLACE,
+    D3DSTENCILOP_INCR,
+    D3DSTENCILOP_DECR
+};
+
+static unsigned GetD3DColor(const Color& color)
+{
+    unsigned r = (unsigned)(Clamp(color.r_ * 255.0f, 0.0f, 255.0f));
+    unsigned g = (unsigned)(Clamp(color.g_ * 255.0f, 0.0f, 255.0f));
+    unsigned b = (unsigned)(Clamp(color.b_ * 255.0f, 0.0f, 255.0f));
+    unsigned a = (unsigned)(Clamp(color.a_ * 255.0f, 0.0f, 255.0f));
+    return (((a) & 0xff) << 24) | (((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff);
+}
+
+static void GetD3DPrimitiveType(unsigned elementCount, PrimitiveType type, unsigned& primitiveCount,
+    D3DPRIMITIVETYPE& d3dPrimitiveType)
+{
+    switch (type)
+    {
+    case TRIANGLE_LIST:
+        primitiveCount = elementCount / 3;
+        d3dPrimitiveType = D3DPT_TRIANGLELIST;
+        break;
+
+    case LINE_LIST:
+        primitiveCount = elementCount / 2;
+        d3dPrimitiveType = D3DPT_LINELIST;
+        break;
+
+    case POINT_LIST:
+        primitiveCount = elementCount;
+        d3dPrimitiveType = D3DPT_POINTLIST;
+        break;
+
+    case TRIANGLE_STRIP:
+        primitiveCount = elementCount - 2;
+        d3dPrimitiveType = D3DPT_TRIANGLESTRIP;
+        break;
+
+    case LINE_STRIP:
+        primitiveCount = elementCount - 1;
+        d3dPrimitiveType = D3DPT_LINESTRIP;
+        break;
+
+    case TRIANGLE_FAN:
+        primitiveCount = elementCount - 2;
+        d3dPrimitiveType = D3DPT_TRIANGLEFAN;
+        break;
+    }
+}
+
+static HWND GetWindowHandle(SDL_Window* window)
+{
+    SDL_SysWMinfo sysInfo;
+
+    SDL_VERSION(&sysInfo.version);
+    SDL_GetWindowWMInfo(window, &sysInfo);
+    return sysInfo.info.win.window;
+}
+
+static unsigned readableDepthFormat = 0;
+
+void Graphics::Constructor_D3D9()
+{
+    impl_ = new GraphicsImpl_D3D9();
+    position_ = IntVector2(SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED);
+    shaderPath_ = "Shaders/HLSL/";
+    shaderExtension_ = ".hlsl";
+    orientations_ = "LandscapeLeft LandscapeRight";
+    apiName_ = "D3D9";
+
+    Graphics::pixelUVOffset = Vector2(0.5f, 0.5f);
+    Graphics::gl3Support = false;
+
+    SetTextureUnitMappings_D3D9();
+
+    context_->RequireSDL(SDL_INIT_VIDEO);
+
+    // Register Graphics library object factories
+    RegisterGraphicsLibrary(context_);
+}
+
+void Graphics::Destructor_D3D9()
+{
+    {
+        MutexLock lock(gpuObjectMutex_);
+
+        // Release all GPU objects that still exist
+        for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
+            (*i)->Release();
+        gpuObjects_.Clear();
+    }
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    impl->vertexDeclarations_.Clear();
+
+    URHO3D_SAFE_RELEASE(impl->defaultColorSurface_);
+    URHO3D_SAFE_RELEASE(impl->defaultDepthStencilSurface_);
+    URHO3D_SAFE_RELEASE(impl->frameQuery_);
+    URHO3D_SAFE_RELEASE(impl->device_);
+    URHO3D_SAFE_RELEASE(impl->interface_);
+
+    if (window_)
+    {
+        SDL_ShowCursor(SDL_TRUE);
+        SDL_DestroyWindow(window_);
+        window_ = nullptr;
+    }
+
+    delete impl_;
+    impl_ = nullptr;
+
+    context_->ReleaseSDL();
+}
+
+bool Graphics::SetScreenMode_D3D9(int width, int height, const ScreenModeParams& params, bool maximize)
+{
+    URHO3D_PROFILE(SetScreenMode_D3D9);
+
+    // Ensure that parameters are properly filled
+    ScreenModeParams newParams = params;
+    AdjustScreenMode(width, height, newParams, maximize);
+
+    // If nothing changes, do not reset the device
+    if (width_ == width && height_ == height && screenParams_ == newParams)
+        return true;
+
+    // Find out the full screen mode display format (match desktop color depth)
+    SDL_DisplayMode mode;
+    SDL_GetDesktopDisplayMode(newParams.monitor_, &mode);
+    const D3DFORMAT fullscreenFormat = SDL_BITSPERPIXEL(mode.format) == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
+
+    const bool monitorChanged = screenParams_.monitor_ != newParams.monitor_;
+
+    SDL_SetHint(SDL_HINT_ORIENTATIONS, orientations_.CString());
+
+    if (!window_)
+    {
+        if (!OpenWindow_D3D9(width, height, newParams.resizable_, newParams.borderless_))
+            return false;
+    }
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (!impl->interface_)
+    {
+        if (!CreateInterface_D3D9())
+            return false;
+
+        CheckFeatureSupport_D3D9();
+    }
+
+    // Fall back to non-multisampled if unsupported multisampling mode
+    if (newParams.multiSample_ > 1)
+    {
+        if (!impl->CheckMultiSampleSupport(fullscreenFormat, newParams.multiSample_))
+            newParams.multiSample_ = 1;
+    }
+
+    AdjustWindow_D3D9(width, height, newParams.fullscreen_, newParams.borderless_, newParams.monitor_);
+
+    if (maximize)
+    {
+        Maximize();
+        SDL_GetWindowSize(window_, &width, &height);
+    }
+
+    if (newParams.fullscreen_)
+    {
+        impl->presentParams_.BackBufferFormat = fullscreenFormat;
+        impl->presentParams_.Windowed = false;
+    }
+    else
+    {
+        impl->presentParams_.BackBufferFormat = D3DFMT_UNKNOWN;
+        impl->presentParams_.Windowed = true;
+    }
+
+    impl->presentParams_.BackBufferWidth = (UINT)width;
+    impl->presentParams_.BackBufferHeight = (UINT)height;
+    impl->presentParams_.BackBufferCount = newParams.tripleBuffer_ ? 2 : 1;
+    impl->presentParams_.MultiSampleType = newParams.multiSample_ > 1 ? static_cast<D3DMULTISAMPLE_TYPE>(newParams.multiSample_) : D3DMULTISAMPLE_NONE;
+    impl->presentParams_.MultiSampleQuality = 0;
+    impl->presentParams_.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    impl->presentParams_.hDeviceWindow = GetWindowHandle(window_);
+    impl->presentParams_.EnableAutoDepthStencil = TRUE;
+    impl->presentParams_.AutoDepthStencilFormat = D3DFMT_D24S8;
+    impl->presentParams_.Flags = D3DPRESENT_LINEAR_CONTENT;
+    impl->presentParams_.FullScreen_RefreshRateInHz = newParams.fullscreen_ ? newParams.refreshRate_ : D3DPRESENT_RATE_DEFAULT;
+
+    if (newParams.vsync_)
+        impl->presentParams_.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+    else
+        impl->presentParams_.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+
+    width_ = width;
+    height_ = height;
+    screenParams_ = newParams;
+
+    if (!impl->device_)
+    {
+        unsigned adapter = SDL_Direct3D9GetAdapterIndex(screenParams_.monitor_);
+        unsigned deviceType = D3DDEVTYPE_HAL;
+
+        // Check for PerfHUD adapter
+        for (unsigned i = 0; i < impl->interface_->GetAdapterCount(); ++i)
+        {
+            D3DADAPTER_IDENTIFIER9 identifier;
+            impl->interface_->GetAdapterIdentifier(i, 0, &identifier);
+            if (strstr(identifier.Description, "PerfHUD") != nullptr)
+            {
+                adapter = i;
+                deviceType = D3DDEVTYPE_REF;
+                break;
+            }
+        }
+
+        impl->interface_->GetAdapterIdentifier(adapter, 0, &impl->adapterIdentifier_);
+        if (!CreateDevice_D3D9(adapter, deviceType))
+            return false;
+    }
+    else
+    {
+        if (!monitorChanged)
+            ResetDevice_D3D9();
+        else
+        {
+            URHO3D_LOGINFO("Destroying D3D9 device");
+            // Monitor changed, re-create the D3D9 device on the new monitor
+            impl->vertexDeclarations_.Clear();
+            OnDeviceLost_D3D9();
+            
+            {
+                MutexLock lock(gpuObjectMutex_);
+                // Release all GPU objects that still exist
+                for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
+                    (*i)->Release();
+            }
+
+            // destroy previous device
+            URHO3D_SAFE_RELEASE(impl->device_);
+
+            // create new device on the specified monitor
+            unsigned adapter = SDL_Direct3D9GetAdapterIndex(screenParams_.monitor_);
+            unsigned deviceType = D3DDEVTYPE_HAL;
+            if (!CreateDevice_D3D9(adapter, deviceType))
+                return false;
+            ResetDevice_D3D9();
+        }
+    }
+
+    // Clear the initial window contents to black
+    impl->device_->BeginScene();
+    Clear_D3D9(CLEAR_COLOR);
+    impl->device_->EndScene();
+    impl->device_->Present(nullptr, nullptr, nullptr, nullptr);
+
+#ifdef URHO3D_LOGGING
+    D3DADAPTER_IDENTIFIER9 id = {0};
+    HRESULT hr = impl->interface_->GetAdapterIdentifier(SDL_Direct3D9GetAdapterIndex(screenParams_.monitor_), 0, &id);
+    if (S_OK == hr)
+        URHO3D_LOGINFOF("Adapter used %s", id.Description);
+#endif
+
+    OnScreenModeChanged();
+    return true;
+}
+
+void Graphics::SetSRGB_D3D9(bool enable)
+{
+    sRGB_ = enable && sRGBWriteSupport_;
+}
+
+void Graphics::SetDither_D3D9(bool enable)
+{
+    // No effect on Direct3D9
+}
+
+void Graphics::SetFlushGPU_D3D9(bool enable)
+{
+    flushGPU_ = enable;
+}
+
+void Graphics::SetForceGL2_D3D9(bool enable)
+{
+    // No effect on Direct3D9
+}
+
+void Graphics::Close_D3D9()
+{
+    if (window_)
+    {
+        SDL_ShowCursor(SDL_TRUE);
+        SDL_DestroyWindow(window_);
+        window_ = nullptr;
+    }
+}
+
+bool Graphics::TakeScreenShot_D3D9(Image& destImage)
+{
+    URHO3D_PROFILE(TakeScreenShot_D3D9);
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (!impl->device_)
+        return false;
+
+    if (IsDeviceLost_D3D9())
+    {
+        URHO3D_LOGERROR("Can not take screenshot while device is lost");
+        return false;
+    }
+
+    D3DSURFACE_DESC surfaceDesc;
+    impl->defaultColorSurface_->GetDesc(&surfaceDesc);
+
+    // If possible, get the backbuffer data, because it is a lot faster.
+    // However, if we are multisampled, need to use the front buffer
+    bool useBackBuffer = true;
+    unsigned surfaceWidth = (unsigned)width_;
+    unsigned surfaceHeight = (unsigned)height_;
+
+    if (impl->presentParams_.MultiSampleType)
+    {
+        // If windowed and multisampled, must still capture the whole screen
+        if (!screenParams_.fullscreen_)
+        {
+            IntVector2 desktopSize = GetDesktopResolution(screenParams_.monitor_);
+            surfaceWidth = (unsigned)desktopSize.x_;
+            surfaceHeight = (unsigned)desktopSize.y_;
+        }
+        useBackBuffer = false;
+        surfaceDesc.Format = D3DFMT_A8R8G8B8;
+    }
+
+    IDirect3DSurface9* surface = nullptr;
+    HRESULT hr = impl->device_->CreateOffscreenPlainSurface(surfaceWidth, surfaceHeight, surfaceDesc.Format, D3DPOOL_SYSTEMMEM, &surface, nullptr);
+    if (FAILED(hr))
+    {
+        URHO3D_SAFE_RELEASE(surface);
+        URHO3D_LOGD3DERROR("Could not create surface for taking a screenshot", hr);
+        return false;
+    }
+
+    if (useBackBuffer)
+        hr = impl->device_->GetRenderTargetData(impl->defaultColorSurface_, surface);
+    else
+        hr = impl->device_->GetFrontBufferData(0, surface);
+    if (FAILED(hr))
+    {
+        URHO3D_SAFE_RELEASE(surface);
+        URHO3D_LOGD3DERROR("Could not get rendertarget data for taking a screenshot", hr);
+        return false;
+    }
+
+    // If capturing the whole screen, determine the window rect
+    RECT sourceRect;
+    if (surfaceHeight == height_ && surfaceWidth == width_)
+    {
+        sourceRect.left = 0;
+        sourceRect.top = 0;
+        sourceRect.right = width_;
+        sourceRect.bottom = height_;
+    }
+    else
+    {
+        HWND hwnd = GetWindowHandle(window_);
+        GetClientRect(hwnd, &sourceRect);
+        ClientToScreen(hwnd, (LPPOINT)&sourceRect);
+    }
+
+    D3DLOCKED_RECT lockedRect;
+    lockedRect.pBits = nullptr;
+    hr = surface->LockRect(&lockedRect, &sourceRect, D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY);
+    if (FAILED(hr) || !lockedRect.pBits)
+    {
+        URHO3D_SAFE_RELEASE(surface);
+        URHO3D_LOGD3DERROR("Could not lock surface for taking a screenshot", hr);
+        return false;
+    }
+
+    destImage.SetSize(width_, height_, 3);
+    unsigned char* destData = destImage.GetData();
+
+    if (surfaceDesc.Format == D3DFMT_R5G6B5)
+    {
+        for (int y = 0; y < height_; ++y)
+        {
+            unsigned short* src = (unsigned short*)((unsigned char*)lockedRect.pBits + y * lockedRect.Pitch);
+            unsigned char* dest = destData + y * width_ * 3;
+
+            for (int x = 0; x < width_; ++x)
+            {
+                unsigned short rgb = *src++;
+                int b = rgb & 31;
+                int g = (rgb >> 5) & 63;
+                int r = (rgb >> 11);
+
+                dest[0] = (unsigned char)(r * 255.0f / 31.0f);
+                dest[1] = (unsigned char)(g * 255.0f / 63.0f);
+                dest[2] = (unsigned char)(b * 255.0f / 31.0f);
+                dest += 3;
+            }
+        }
+    }
+    else
+    {
+        for (int y = 0; y < height_; ++y)
+        {
+            unsigned char* src = (unsigned char*)lockedRect.pBits + y * lockedRect.Pitch;
+            unsigned char* dest = destData + y * width_ * 3;
+
+            for (int x = 0; x < width_; ++x)
+            {
+                dest[0] = src[2];
+                dest[1] = src[1];
+                dest[2] = src[0];
+                src += 4;
+                dest += 3;
+            }
+        }
+    }
+
+    surface->UnlockRect();
+    surface->Release();
+
+    return true;
+}
+
+bool Graphics::BeginFrame_D3D9()
+{
+    if (!IsInitialized_D3D9())
+        return false;
+
+    // If using an external window, check it for size changes, and reset screen mode if necessary
+    if (externalWindow_)
+    {
+        int width, height;
+
+        SDL_GetWindowSize(window_, &width, &height);
+        if (width != width_ || height != height_)
+            SetMode(width, height);
+    }
+    else
+    {
+        // To prevent a loop of endless device loss and flicker, do not attempt to render when in fullscreen
+        // and the window is minimized
+        if (screenParams_.fullscreen_ && (SDL_GetWindowFlags(window_) & SDL_WINDOW_MINIMIZED))
+            return false;
+    }
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    // Check for lost device before rendering
+    HRESULT hr = impl->device_->TestCooperativeLevel();
+    if (hr != D3D_OK)
+    {
+        URHO3D_PROFILE(DeviceLost);
+
+        impl->deviceLost_ = true;
+
+        // The device can not be reset yet, sleep and try again eventually
+        if (hr == D3DERR_DEVICELOST)
+        {
+            Time::Sleep(20);
+            return false;
+        }
+        // The device is lost, but ready to be reset. Reset device but do not render on this frame yet
+        if (hr == D3DERR_DEVICENOTRESET)
+        {
+            ResetDevice_D3D9();
+            return false;
+        }
+    }
+
+    impl->device_->BeginScene();
+
+    // Set default rendertarget and depth buffer
+    ResetRenderTargets_D3D9();
+
+    // Cleanup textures from previous frame
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+        SetTexture_D3D9(i, nullptr);
+
+    numPrimitives_ = 0;
+    numBatches_ = 0;
+
+    SendEvent(E_BEGINRENDERING);
+
+    return true;
+}
+
+void Graphics::EndFrame_D3D9()
+{
+    if (!IsInitialized_D3D9())
+        return;
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    {
+        URHO3D_PROFILE(Present);
+
+        SendEvent(E_ENDRENDERING);
+
+        impl->device_->EndScene();
+        impl->device_->Present(nullptr, nullptr, nullptr, nullptr);
+    }
+
+    // Optionally flush GPU buffer to avoid control lag or framerate fluctuations due to multiple frame buffering
+    // If a query was issued on the previous frame, first wait for it to finish
+    if (impl->frameQuery_)
+    {
+        if (impl->queryIssued_)
+        {
+            URHO3D_PROFILE(FlushGPU);
+
+            while (impl->frameQuery_->GetData(nullptr, 0, D3DGETDATA_FLUSH) == S_FALSE)
+            {
+            }
+
+            impl->queryIssued_ = false;
+        }
+
+        if (flushGPU_)
+        {
+            impl->frameQuery_->Issue(D3DISSUE_END);
+            impl->queryIssued_ = true;
+        }
+    }
+
+    // Clean up too large scratch buffers
+    CleanupScratchBuffers();
+}
+
+void Graphics::Clear_D3D9(ClearTargetFlags flags, const Color& color, float depth, unsigned stencil)
+{
+    DWORD d3dFlags = 0;
+    if (flags & CLEAR_COLOR)
+        d3dFlags |= D3DCLEAR_TARGET;
+    if (flags & CLEAR_DEPTH)
+        d3dFlags |= D3DCLEAR_ZBUFFER;
+    if (flags & CLEAR_STENCIL)
+        d3dFlags |= D3DCLEAR_STENCIL;
+
+    GetImpl_D3D9()->device_->Clear(0, nullptr, d3dFlags, GetD3DColor(color), depth, stencil);
+}
+
+bool Graphics::ResolveToTexture_D3D9(Texture2D* destination, const IntRect& viewport)
+{
+    if (!destination || !destination->GetRenderSurface())
+        return false;
+
+    URHO3D_PROFILE(ResolveToTexture_D3D9);
+
+    IntRect vpCopy = viewport;
+    if (vpCopy.right_ <= vpCopy.left_)
+        vpCopy.right_ = vpCopy.left_ + 1;
+    if (vpCopy.bottom_ <= vpCopy.top_)
+        vpCopy.bottom_ = vpCopy.top_ + 1;
+
+    RECT rect;
+    rect.left = Clamp(vpCopy.left_, 0, width_);
+    rect.top = Clamp(vpCopy.top_, 0, height_);
+    rect.right = Clamp(vpCopy.right_, 0, width_);
+    rect.bottom = Clamp(vpCopy.bottom_, 0, height_);
+
+    RECT destRect;
+    destRect.left = 0;
+    destRect.top = 0;
+    destRect.right = destination->GetWidth();
+    destRect.bottom = destination->GetHeight();
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    HRESULT hr = impl->device_->StretchRect(impl->defaultColorSurface_, &rect,
+        (IDirect3DSurface9*)destination->GetRenderSurface()->GetSurface(), &destRect, D3DTEXF_NONE);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Failed to resolve to texture", hr);
+        return false;
+    }
+    else
+        return true;
+}
+
+bool Graphics::ResolveToTexture_D3D9(Texture2D* texture)
+{
+    if (!texture || !texture->GetRenderSurface() || !texture->GetGPUObject() || texture->GetMultiSample() < 2)
+        return false;
+
+    URHO3D_PROFILE(ResolveToTexture_D3D9);
+
+    // Clear dirty flag already, because if resolve fails it's no use to retry (e.g. on the same frame)
+    RenderSurface* surface = texture->GetRenderSurface();
+    texture->SetResolveDirty(false);
+    surface->SetResolveDirty(false);
+
+    RECT rect;
+    rect.left = 0;
+    rect.top = 0;
+    rect.right = texture->GetWidth();
+    rect.bottom = texture->GetHeight();
+
+    IDirect3DSurface9* srcSurface = (IDirect3DSurface9*)surface->GetSurface();
+    IDirect3DTexture9* destTexture = (IDirect3DTexture9*)texture->GetGPUObject();
+    IDirect3DSurface9* destSurface = nullptr;
+    HRESULT hr = destTexture->GetSurfaceLevel(0, &destSurface);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Failed to get destination surface for resolve", hr);
+        URHO3D_SAFE_RELEASE(destSurface);
+        return false;
+    }
+
+    hr = GetImpl_D3D9()->device_->StretchRect(srcSurface, &rect, destSurface, &rect, D3DTEXF_NONE);
+    URHO3D_SAFE_RELEASE(destSurface);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Failed to resolve to texture", hr);
+        return false;
+    }
+    else
+        return true;
+}
+
+bool Graphics::ResolveToTexture_D3D9(TextureCube* texture)
+{
+    if (!texture || !texture->GetRenderSurface(FACE_POSITIVE_X) || !texture->GetGPUObject() || texture->GetMultiSample() < 2)
+        return false;
+
+    URHO3D_PROFILE(ResolveToTexture_D3D9);
+
+    texture->SetResolveDirty(false);
+
+    RECT rect;
+    rect.left = 0;
+    rect.top = 0;
+    rect.right = texture->GetWidth();
+    rect.bottom = texture->GetHeight();
+
+    for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
+    {
+        // Resolve only the surface(s) that were actually rendered to
+        RenderSurface* surface = texture->GetRenderSurface((CubeMapFace)i);
+        if (!surface->IsResolveDirty())
+            continue;
+
+        surface->SetResolveDirty(false);
+        IDirect3DSurface9* srcSurface = (IDirect3DSurface9*)surface->GetSurface();
+        IDirect3DCubeTexture9* destTexture = (IDirect3DCubeTexture9*)texture->GetGPUObject();
+        IDirect3DSurface9* destSurface = nullptr;
+        HRESULT hr = destTexture->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &destSurface);
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Failed to get destination surface for resolve", hr);
+            URHO3D_SAFE_RELEASE(destSurface);
+            return false;
+        }
+
+        hr = GetImpl_D3D9()->device_->StretchRect(srcSurface, &rect, destSurface, &rect, D3DTEXF_NONE);
+        URHO3D_SAFE_RELEASE(destSurface);
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Failed to resolve to texture", hr);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void Graphics::Draw_D3D9(PrimitiveType type, unsigned vertexStart, unsigned vertexCount)
+{
+    if (!vertexCount)
+        return;
+
+    ResetStreamFrequencies_D3D9();
+
+    unsigned primitiveCount;
+    D3DPRIMITIVETYPE d3dPrimitiveType;
+
+    GetD3DPrimitiveType(vertexCount, type, primitiveCount, d3dPrimitiveType);
+    GetImpl_D3D9()->device_->DrawPrimitive(d3dPrimitiveType, vertexStart, primitiveCount);
+
+    numPrimitives_ += primitiveCount;
+    ++numBatches_;
+}
+
+void Graphics::Draw_D3D9(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount)
+{
+    if (!indexCount)
+        return;
+
+    ResetStreamFrequencies_D3D9();
+
+    unsigned primitiveCount;
+    D3DPRIMITIVETYPE d3dPrimitiveType;
+
+    GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
+    GetImpl_D3D9()->device_->DrawIndexedPrimitive(d3dPrimitiveType, 0, minVertex, vertexCount, indexStart, primitiveCount);
+
+    numPrimitives_ += primitiveCount;
+    ++numBatches_;
+}
+
+void Graphics::Draw_D3D9(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned baseVertexIndex, unsigned minVertex, unsigned vertexCount)
+{
+    if (!indexCount)
+        return;
+
+    ResetStreamFrequencies_D3D9();
+
+    unsigned primitiveCount;
+    D3DPRIMITIVETYPE d3dPrimitiveType;
+
+    GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
+    GetImpl_D3D9()->device_->DrawIndexedPrimitive(d3dPrimitiveType, baseVertexIndex, minVertex, vertexCount, indexStart, primitiveCount);
+
+    numPrimitives_ += primitiveCount;
+    ++numBatches_;
+}
+
+void Graphics::DrawInstanced_D3D9(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount,
+    unsigned instanceCount)
+{
+    if (!indexCount || !instanceCount)
+        return;
+
+    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
+    {
+        VertexBuffer* buffer = vertexBuffers_[i];
+        if (buffer)
+        {
+            const PODVector<VertexElement>& elements = buffer->GetElements();
+            // Check if buffer has per-instance data
+            if (elements.Size() && elements[0].perInstance_)
+                SetStreamFrequency_D3D9(i, D3DSTREAMSOURCE_INSTANCEDATA | 1u);
+            else
+                SetStreamFrequency_D3D9(i, D3DSTREAMSOURCE_INDEXEDDATA | instanceCount);
+        }
+    }
+
+    unsigned primitiveCount;
+    D3DPRIMITIVETYPE d3dPrimitiveType;
+
+    GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
+    GetImpl_D3D9()->device_->DrawIndexedPrimitive(d3dPrimitiveType, 0, minVertex, vertexCount, indexStart, primitiveCount);
+
+    numPrimitives_ += instanceCount * primitiveCount;
+    ++numBatches_;
+}
+
+void Graphics::DrawInstanced_D3D9(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned baseVertexIndex, unsigned minVertex,
+    unsigned vertexCount, unsigned instanceCount)
+{
+    if (!indexCount || !instanceCount)
+        return;
+
+    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
+    {
+        VertexBuffer* buffer = vertexBuffers_[i];
+        if (buffer)
+        {
+            const PODVector<VertexElement>& elements = buffer->GetElements();
+            // Check if buffer has per-instance data
+            if (elements.Size() && elements[0].perInstance_)
+                SetStreamFrequency_D3D9(i, D3DSTREAMSOURCE_INSTANCEDATA | 1u);
+            else
+                SetStreamFrequency_D3D9(i, D3DSTREAMSOURCE_INDEXEDDATA | instanceCount);
+        }
+    }
+
+    unsigned primitiveCount;
+    D3DPRIMITIVETYPE d3dPrimitiveType;
+
+    GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
+    GetImpl_D3D9()->device_->DrawIndexedPrimitive(d3dPrimitiveType, baseVertexIndex, minVertex, vertexCount, indexStart, primitiveCount);
+
+    numPrimitives_ += instanceCount * primitiveCount;
+    ++numBatches_;
+}
+
+void Graphics::SetVertexBuffer_D3D9(VertexBuffer* buffer)
+{
+    // Note: this is not multi-instance safe
+    static PODVector<VertexBuffer*> vertexBuffers(1);
+    vertexBuffers[0] = buffer;
+    SetVertexBuffers_D3D9(vertexBuffers);
+}
+
+bool Graphics::SetVertexBuffers_D3D9(const PODVector<VertexBuffer*>& buffers, unsigned instanceOffset)
+{
+    if (buffers.Size() > MAX_VERTEX_STREAMS)
+    {
+        URHO3D_LOGERROR("Too many vertex buffers");
+        return false;
+    }
+
+    // Build vertex declaration hash code out of the buffers
+    unsigned long long hash = 0;
+    for (unsigned i = 0; i < buffers.Size(); ++i)
+    {
+        if (!buffers[i])
+            continue;
+
+        hash |= buffers[i]->GetBufferHash(i);
+    }
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (hash)
+    {
+        // If no previous vertex declaration for that hash, create new
+        VertexDeclarationMap_D3D9::Iterator i = impl->vertexDeclarations_.Find(hash);
+        if (i == impl->vertexDeclarations_.End())
+        {
+            SharedPtr<VertexDeclaration_D3D9> newDeclaration(new VertexDeclaration_D3D9(this, buffers));
+            if (!newDeclaration->GetDeclaration())
+                return false;
+
+            i = impl->vertexDeclarations_.Insert(MakePair(hash, newDeclaration));
+        }
+
+        VertexDeclaration_D3D9* declaration = i->second_;
+        if (declaration != impl->vertexDeclaration_)
+        {
+            impl->device_->SetVertexDeclaration(declaration->GetDeclaration());
+            impl->vertexDeclaration_ = declaration;
+        }
+    }
+
+    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
+    {
+        VertexBuffer* buffer = nullptr;
+        unsigned offset = 0;
+
+        if (i < buffers.Size() && buffers[i])
+        {
+            buffer = buffers[i];
+            const PODVector<VertexElement>& elements = buffer->GetElements();
+            // Check if buffer has per-instance data; add instance offset in that case
+            if (elements.Size() && elements[0].perInstance_)
+                offset = instanceOffset * buffer->GetVertexSize();
+        }
+
+        if (buffer != vertexBuffers_[i] || offset != impl->streamOffsets_[i])
+        {
+            if (buffer)
+                impl->device_->SetStreamSource(i, (IDirect3DVertexBuffer9*)buffer->GetGPUObject(), offset,
+                    buffer->GetVertexSize());
+            else
+                impl->device_->SetStreamSource(i, nullptr, 0, 0);
+
+            vertexBuffers_[i] = buffer;
+            impl->streamOffsets_[i] = offset;
+        }
+    }
+
+    return true;
+}
+
+bool Graphics::SetVertexBuffers_D3D9(const Vector<SharedPtr<VertexBuffer> >& buffers, unsigned instanceOffset)
+{
+    return SetVertexBuffers_D3D9(reinterpret_cast<const PODVector<VertexBuffer*>&>(buffers), instanceOffset);
+}
+
+void Graphics::SetIndexBuffer_D3D9(IndexBuffer* buffer)
+{
+    if (buffer != indexBuffer_)
+    {
+        GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+        if (buffer)
+            impl->device_->SetIndices((IDirect3DIndexBuffer9*)buffer->GetGPUObject());
+        else
+            impl->device_->SetIndices(nullptr);
+
+        indexBuffer_ = buffer;
+    }
+}
+
+void Graphics::SetShaders_D3D9(ShaderVariation* vs, ShaderVariation* ps)
+{
+    if (vs == vertexShader_ && ps == pixelShader_)
+        return;
+
+    ClearParameterSources_D3D9();
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (vs != vertexShader_)
+    {
+        // Create the shader now if not yet created. If already attempted, do not retry
+        if (vs && !vs->GetGPUObject())
+        {
+            if (vs->GetCompilerOutput().Empty())
+            {
+                URHO3D_PROFILE(CompileVertexShader);
+
+                bool success = vs->Create();
+                if (!success)
+                {
+                    URHO3D_LOGERROR("Failed to compile vertex shader " + vs->GetFullName() + ":\n" + vs->GetCompilerOutput());
+                    vs = nullptr;
+                }
+            }
+            else
+                vs = nullptr;
+        }
+
+        if (vs && vs->GetShaderType() == VS)
+            impl->device_->SetVertexShader((IDirect3DVertexShader9*)vs->GetGPUObject());
+        else
+        {
+            impl->device_->SetVertexShader(nullptr);
+            vs = nullptr;
+        }
+
+        vertexShader_ = vs;
+    }
+
+    if (ps != pixelShader_)
+    {
+        if (ps && !ps->GetGPUObject())
+        {
+            if (ps->GetCompilerOutput().Empty())
+            {
+                URHO3D_PROFILE(CompilePixelShader);
+
+                bool success = ps->Create();
+                if (!success)
+                {
+                    URHO3D_LOGERROR("Failed to compile pixel shader " + ps->GetFullName() + ":\n" + ps->GetCompilerOutput());
+                    ps = nullptr;
+                }
+            }
+            else
+                ps = nullptr;
+        }
+
+        if (ps && ps->GetShaderType() == PS)
+            impl->device_->SetPixelShader((IDirect3DPixelShader9*)ps->GetGPUObject());
+        else
+        {
+            impl->device_->SetPixelShader(nullptr);
+            ps = nullptr;
+        }
+
+        pixelShader_ = ps;
+    }
+
+    // Update current available shader parameters
+    if (vertexShader_ && pixelShader_)
+    {
+        Pair<ShaderVariation*, ShaderVariation*> key = MakePair(vertexShader_, pixelShader_);
+        ShaderProgramMap_D3D9::Iterator i = impl->shaderPrograms_.Find(key);
+        if (i != impl->shaderPrograms_.End())
+            impl->shaderProgram_ = i->second_.Get();
+        else
+        {
+            ShaderProgram_D3D9* newProgram = impl->shaderPrograms_[key] = new ShaderProgram_D3D9(vertexShader_, pixelShader_);
+            impl->shaderProgram_ = newProgram;
+        }
+    }
+    else
+        impl->shaderProgram_ = nullptr;
+
+    // Store shader combination if shader dumping in progress
+    if (shaderPrecache_)
+        shaderPrecache_->StoreShaders(vertexShader_, pixelShader_);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, const float* data, unsigned count)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantF(i->second_.register_, data, count / 4);
+    else
+        impl->device_->SetPixelShaderConstantF(i->second_.register_, data, count / 4);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, float value)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    static Vector4 data(Vector4::ZERO);
+    data.x_ = value;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantF(i->second_.register_, &data.x_, 1);
+    else
+        impl->device_->SetPixelShaderConstantF(i->second_.register_, &data.x_, 1);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, int value)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    /// \todo Int constants seem to have no effect on Direct3D9
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantI(i->second_.register_, &value, 1);
+    else
+        impl->device_->SetPixelShaderConstantI(i->second_.register_, &value, 1);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, bool value)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    /// \todo Bool constants seem to have no effect on Direct3D9
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    BOOL data = value;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantB(i->second_.register_, &data, 1);
+    else
+        impl->device_->SetPixelShaderConstantB(i->second_.register_, &data, 1);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, const Color& color)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantF(i->second_.register_, color.Data(), 1);
+    else
+        impl->device_->SetPixelShaderConstantF(i->second_.register_, color.Data(), 1);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, const Vector2& vector)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    static Vector4 data(Vector4::ZERO);
+    data.x_ = vector.x_;
+    data.y_ = vector.y_;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantF(i->second_.register_, &data.x_, 1);
+    else
+        impl->device_->SetPixelShaderConstantF(i->second_.register_, &data.x_, 1);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, const Matrix3& matrix)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    static Matrix3x4 data(Matrix3x4::ZERO);
+    data.m00_ = matrix.m00_;
+    data.m01_ = matrix.m01_;
+    data.m02_ = matrix.m02_;
+    data.m10_ = matrix.m10_;
+    data.m11_ = matrix.m11_;
+    data.m12_ = matrix.m12_;
+    data.m20_ = matrix.m20_;
+    data.m21_ = matrix.m21_;
+    data.m22_ = matrix.m22_;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantF(i->second_.register_, &data.m00_, 3);
+    else
+        impl->device_->SetPixelShaderConstantF(i->second_.register_, &data.m00_, 3);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, const Vector3& vector)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    static Vector4 data(Vector4::ZERO);
+    data.x_ = vector.x_;
+    data.y_ = vector.y_;
+    data.z_ = vector.z_;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantF(i->second_.register_, &data.x_, 1);
+    else
+        impl->device_->SetPixelShaderConstantF(i->second_.register_, &data.x_, 1);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, const Matrix4& matrix)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantF(i->second_.register_, matrix.Data(), 4);
+    else
+        impl->device_->SetPixelShaderConstantF(i->second_.register_, matrix.Data(), 4);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, const Vector4& vector)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantF(i->second_.register_, vector.Data(), 1);
+    else
+        impl->device_->SetPixelShaderConstantF(i->second_.register_, vector.Data(), 1);
+}
+
+void Graphics::SetShaderParameter_D3D9(StringHash param, const Matrix3x4& matrix)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    HashMap<StringHash, ShaderParameter>::Iterator i;
+    if (!impl->shaderProgram_ || (i = impl->shaderProgram_->parameters_.Find(param)) == impl->shaderProgram_->parameters_.End())
+        return;
+
+    if (i->second_.type_ == VS)
+        impl->device_->SetVertexShaderConstantF(i->second_.register_, matrix.Data(), 3);
+    else
+        impl->device_->SetPixelShaderConstantF(i->second_.register_, matrix.Data(), 3);
+}
+
+bool Graphics::NeedParameterUpdate_D3D9(ShaderParameterGroup group, const void* source)
+{
+    if ((unsigned)(size_t)shaderParameterSources_[group] == M_MAX_UNSIGNED || shaderParameterSources_[group] != source)
+    {
+        shaderParameterSources_[group] = source;
+        return true;
+    }
+    else
+        return false;
+}
+
+bool Graphics::HasShaderParameter_D3D9(StringHash param)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    return impl->shaderProgram_ && impl->shaderProgram_->parameters_.Find(param) != impl->shaderProgram_->parameters_.End();
+}
+
+bool Graphics::HasTextureUnit_D3D9(TextureUnit unit)
+{
+    return pixelShader_ && pixelShader_->HasTextureUnit(unit);
+}
+
+void Graphics::ClearParameterSource_D3D9(ShaderParameterGroup group)
+{
+    shaderParameterSources_[group] = (const void*)M_MAX_UNSIGNED;
+}
+
+void Graphics::ClearParameterSources_D3D9()
+{
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        shaderParameterSources_[i] = (const void*)M_MAX_UNSIGNED;
+}
+
+void Graphics::ClearTransformSources_D3D9()
+{
+    shaderParameterSources_[SP_CAMERA] = (const void*)M_MAX_UNSIGNED;
+    shaderParameterSources_[SP_OBJECT] = (const void*)M_MAX_UNSIGNED;
+}
+
+void Graphics::SetTexture_D3D9(unsigned index, Texture* texture)
+{
+    if (index >= MAX_TEXTURE_UNITS)
+        return;
+
+    if (texture)
+    {
+        // Check if texture is currently bound as a rendertarget. In that case, use its backup texture, or blank if not defined
+        if (renderTargets_[0] && renderTargets_[0]->GetParentTexture() == texture)
+            texture = texture->GetBackupTexture();
+        else
+        {
+            // Resolve multisampled texture now as necessary
+            if (texture->GetMultiSample() > 1 && texture->GetAutoResolve() && texture->IsResolveDirty())
+            {
+                if (texture->GetType() == Texture2D::GetTypeStatic())
+                    ResolveToTexture_D3D9(static_cast<Texture2D*>(texture));
+                else if (texture->GetType() == TextureCube::GetTypeStatic())
+                    ResolveToTexture_D3D9(static_cast<TextureCube*>(texture));
+            }
+        }
+    }
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (texture != textures_[index])
+    {
+        if (texture)
+            impl->device_->SetTexture(index, (IDirect3DBaseTexture9*)texture->GetGPUObject());
+        else
+            impl->device_->SetTexture(index, nullptr);
+
+        textures_[index] = texture;
+    }
+
+    if (texture)
+    {
+        TextureFilterMode filterMode = texture->GetFilterMode();
+        if (filterMode == FILTER_DEFAULT)
+            filterMode = defaultTextureFilterMode_;
+
+        D3DTEXTUREFILTERTYPE min, mag, mip;
+        min = d3dMinFilter[filterMode];
+        if (min != impl->minFilters_[index])
+        {
+            impl->device_->SetSamplerState(index, D3DSAMP_MINFILTER, min);
+            impl->minFilters_[index] = min;
+        }
+        mag = d3dMagFilter[filterMode];
+        if (mag != impl->magFilters_[index])
+        {
+            impl->device_->SetSamplerState(index, D3DSAMP_MAGFILTER, mag);
+            impl->magFilters_[index] = mag;
+        }
+        mip = d3dMipFilter[filterMode];
+        if (mip != impl->mipFilters_[index])
+        {
+            impl->device_->SetSamplerState(index, D3DSAMP_MIPFILTER, mip);
+            impl->mipFilters_[index] = mip;
+        }
+        D3DTEXTUREADDRESS u, v;
+        u = d3dAddressMode[texture->GetAddressMode(COORD_U)];
+        if (u != impl->uAddressModes_[index])
+        {
+            impl->device_->SetSamplerState(index, D3DSAMP_ADDRESSU, u);
+            impl->uAddressModes_[index] = u;
+        }
+        v = d3dAddressMode[texture->GetAddressMode(COORD_V)];
+        if (v != impl->vAddressModes_[index])
+        {
+            impl->device_->SetSamplerState(index, D3DSAMP_ADDRESSV, v);
+            impl->vAddressModes_[index] = v;
+        }
+        if (texture->GetType() == TextureCube::GetTypeStatic())
+        {
+            D3DTEXTUREADDRESS w = d3dAddressMode[texture->GetAddressMode(COORD_W)];
+            if (w != impl->wAddressModes_[index])
+            {
+                impl->device_->SetSamplerState(index, D3DSAMP_ADDRESSW, w);
+                impl->wAddressModes_[index] = w;
+            }
+        }
+        unsigned maxAnisotropy = texture->GetAnisotropy();
+        if (!maxAnisotropy)
+            maxAnisotropy = defaultTextureAnisotropy_;
+        if (maxAnisotropy != impl->maxAnisotropy_[index])
+        {
+            impl->device_->SetSamplerState(index, D3DSAMP_MAXANISOTROPY, maxAnisotropy);
+            impl->maxAnisotropy_[index] = maxAnisotropy;
+        }
+        if (u == D3DTADDRESS_BORDER || v == D3DTADDRESS_BORDER)
+        {
+            const Color& borderColor = texture->GetBorderColor();
+            if (borderColor != impl->borderColors_[index])
+            {
+                impl->device_->SetSamplerState(index, D3DSAMP_BORDERCOLOR, GetD3DColor(borderColor));
+                impl->borderColors_[index] = borderColor;
+            }
+        }
+        if (sRGBSupport_)
+        {
+            bool sRGB = texture->GetSRGB();
+            if (sRGB != impl->sRGBModes_[index])
+            {
+                impl->device_->SetSamplerState(index, D3DSAMP_SRGBTEXTURE, sRGB ? TRUE : FALSE);
+                impl->sRGBModes_[index] = sRGB;
+            }
+        }
+    }
+}
+
+void Graphics::SetDefaultTextureFilterMode_D3D9(TextureFilterMode mode)
+{
+    defaultTextureFilterMode_ = mode;
+}
+
+void Graphics::SetDefaultTextureAnisotropy_D3D9(unsigned level)
+{
+    defaultTextureAnisotropy_ = Max(level, 1U);
+}
+
+void Graphics::ResetRenderTargets_D3D9()
+{
+    for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
+        SetRenderTarget_D3D9(i, (RenderSurface*)nullptr);
+    SetDepthStencil_D3D9((RenderSurface*)nullptr);
+    SetViewport_D3D9(IntRect(0, 0, width_, height_));
+}
+
+void Graphics::ResetRenderTarget_D3D9(unsigned index)
+{
+    SetRenderTarget_D3D9(index, (RenderSurface*)nullptr);
+}
+
+void Graphics::ResetDepthStencil_D3D9()
+{
+    SetDepthStencil_D3D9((RenderSurface*)nullptr);
+}
+
+void Graphics::SetRenderTarget_D3D9(unsigned index, RenderSurface* renderTarget)
+{
+    if (index >= MAX_RENDERTARGETS)
+        return;
+
+    IDirect3DSurface9* newColorSurface = nullptr;
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (renderTarget)
+    {
+        if (renderTarget->GetUsage() != TEXTURE_RENDERTARGET)
+            return;
+        newColorSurface = (IDirect3DSurface9*)renderTarget->GetSurface();
+    }
+    else
+    {
+        if (!index)
+            newColorSurface = impl->defaultColorSurface_;
+    }
+
+    renderTargets_[index] = renderTarget;
+
+    if (newColorSurface != impl->colorSurfaces_[index])
+    {
+        impl->device_->SetRenderTarget(index, newColorSurface);
+        impl->colorSurfaces_[index] = newColorSurface;
+        // Setting the first rendertarget causes viewport to be reset
+        if (!index)
+        {
+            IntVector2 rtSize = GetRenderTargetDimensions_D3D9();
+            viewport_ = IntRect(0, 0, rtSize.x_, rtSize.y_);
+        }
+    }
+
+    if (renderTarget)
+    {
+        Texture* parentTexture = renderTarget->GetParentTexture();
+
+        // If the rendertarget is also bound as a texture, replace with backup texture or null
+        for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+        {
+            if (textures_[i] == parentTexture)
+                SetTexture_D3D9(i, textures_[i]->GetBackupTexture());
+        }
+
+        // If multisampled, mark the texture & surface needing resolve
+        if (parentTexture->GetMultiSample() > 1 && parentTexture->GetAutoResolve())
+        {
+            parentTexture->SetResolveDirty(true);
+            renderTarget->SetResolveDirty(true);
+        }
+    }
+
+    // First rendertarget controls sRGB write mode
+    if (!index && sRGBWriteSupport_)
+    {
+        bool sRGBWrite = renderTarget ? renderTarget->GetParentTexture()->GetSRGB() : sRGB_;
+        if (sRGBWrite != impl->sRGBWrite_)
+        {
+            impl->device_->SetRenderState(D3DRS_SRGBWRITEENABLE, sRGBWrite ? TRUE : FALSE);
+            impl->sRGBWrite_ = sRGBWrite;
+        }
+    }
+}
+
+void Graphics::SetRenderTarget_D3D9(unsigned index, Texture2D* texture)
+{
+    RenderSurface* renderTarget = nullptr;
+    if (texture)
+        renderTarget = texture->GetRenderSurface();
+
+    SetRenderTarget_D3D9(index, renderTarget);
+}
+
+void Graphics::SetDepthStencil_D3D9(RenderSurface* depthStencil)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+    IDirect3DSurface9* newDepthStencilSurface = nullptr;
+    if (depthStencil && depthStencil->GetUsage() == TEXTURE_DEPTHSTENCIL)
+    {
+        newDepthStencilSurface = (IDirect3DSurface9*)depthStencil->GetSurface();
+        depthStencil_ = depthStencil;
+    }
+    if (!newDepthStencilSurface)
+    {
+        newDepthStencilSurface = impl->defaultDepthStencilSurface_;
+        depthStencil_ = nullptr;
+    }
+    if (newDepthStencilSurface != impl->depthStencilSurface_)
+    {
+        impl->device_->SetDepthStencilSurface(newDepthStencilSurface);
+        impl->depthStencilSurface_ = newDepthStencilSurface;
+    }
+}
+
+void Graphics::SetDepthStencil_D3D9(Texture2D* texture)
+{
+    RenderSurface* depthStencil = nullptr;
+    if (texture)
+        depthStencil = texture->GetRenderSurface();
+
+    SetDepthStencil_D3D9(depthStencil);
+}
+
+void Graphics::SetViewport_D3D9(const IntRect& rect)
+{
+    IntVector2 size = GetRenderTargetDimensions_D3D9();
+
+    IntRect rectCopy = rect;
+
+    if (rectCopy.right_ <= rectCopy.left_)
+        rectCopy.right_ = rectCopy.left_ + 1;
+    if (rectCopy.bottom_ <= rectCopy.top_)
+        rectCopy.bottom_ = rectCopy.top_ + 1;
+    rectCopy.left_ = Clamp(rectCopy.left_, 0, size.x_);
+    rectCopy.top_ = Clamp(rectCopy.top_, 0, size.y_);
+    rectCopy.right_ = Clamp(rectCopy.right_, 0, size.x_);
+    rectCopy.bottom_ = Clamp(rectCopy.bottom_, 0, size.y_);
+
+    D3DVIEWPORT9 vp;
+    vp.MinZ = 0.0f;
+    vp.MaxZ = 1.0f;
+    vp.X = (DWORD)rectCopy.left_;
+    vp.Y = (DWORD)rectCopy.top_;
+    vp.Width = (DWORD)rectCopy.Width();
+    vp.Height = (DWORD)rectCopy.Height();
+
+    GetImpl_D3D9()->device_->SetViewport(&vp);
+    viewport_ = rectCopy;
+
+    // Disable scissor test, needs to be re-enabled by the user
+    SetScissorTest_D3D9(false);
+}
+
+void Graphics::SetBlendMode_D3D9(BlendMode mode, bool /* alphaToCoverage */)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (mode != blendMode_)
+    {
+        if (d3dBlendEnable[mode] != impl->blendEnable_)
+        {
+            impl->device_->SetRenderState(D3DRS_ALPHABLENDENABLE, d3dBlendEnable[mode]);
+            impl->blendEnable_ = d3dBlendEnable[mode];
+        }
+
+        if (impl->blendEnable_)
+        {
+            if (d3dSrcBlend[mode] != impl->srcBlend_)
+            {
+                impl->device_->SetRenderState(D3DRS_SRCBLEND, d3dSrcBlend[mode]);
+                impl->srcBlend_ = d3dSrcBlend[mode];
+            }
+            if (d3dDestBlend[mode] != impl->destBlend_)
+            {
+                impl->device_->SetRenderState(D3DRS_DESTBLEND, d3dDestBlend[mode]);
+                impl->destBlend_ = d3dDestBlend[mode];
+            }
+            if (d3dBlendOp[mode] != impl->blendOp_)
+            {
+                impl->device_->SetRenderState(D3DRS_BLENDOP, d3dBlendOp[mode]);
+                impl->blendOp_ = d3dBlendOp[mode];
+            }
+        }
+
+        blendMode_ = mode;
+    }
+}
+
+void Graphics::SetColorWrite_D3D9(bool enable)
+{
+    if (enable != colorWrite_)
+    {
+        GetImpl_D3D9()->device_->SetRenderState(D3DRS_COLORWRITEENABLE,
+            enable ? D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA :
+                0);
+        colorWrite_ = enable;
+    }
+}
+
+void Graphics::SetCullMode_D3D9(CullMode mode)
+{
+    if (mode != cullMode_)
+    {
+        GetImpl_D3D9()->device_->SetRenderState(D3DRS_CULLMODE, d3dCullMode[mode]);
+        cullMode_ = mode;
+    }
+}
+
+void Graphics::SetDepthBias_D3D9(float constantBias, float slopeScaledBias)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (constantBias != constantDepthBias_)
+    {
+        impl->device_->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&constantBias));
+        constantDepthBias_ = constantBias;
+    }
+    if (slopeScaledBias != slopeScaledDepthBias_)
+    {
+        impl->device_->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&slopeScaledBias));
+        slopeScaledDepthBias_ = slopeScaledBias;
+    }
+}
+
+void Graphics::SetDepthTest_D3D9(CompareMode mode)
+{
+    if (mode != depthTestMode_)
+    {
+        GetImpl_D3D9()->device_->SetRenderState(D3DRS_ZFUNC, d3dCmpFunc[mode]);
+        depthTestMode_ = mode;
+    }
+}
+
+void Graphics::SetDepthWrite_D3D9(bool enable)
+{
+    if (enable != depthWrite_)
+    {
+        GetImpl_D3D9()->device_->SetRenderState(D3DRS_ZWRITEENABLE, enable ? TRUE : FALSE);
+        depthWrite_ = enable;
+    }
+}
+
+void Graphics::SetFillMode_D3D9(FillMode mode)
+{
+    if (mode != fillMode_)
+    {
+        GetImpl_D3D9()->device_->SetRenderState(D3DRS_FILLMODE, d3dFillMode[mode]);
+        fillMode_ = mode;
+    }
+}
+
+void Graphics::SetLineAntiAlias_D3D9(bool enable)
+{
+    if (enable != lineAntiAlias_)
+    {
+        GetImpl_D3D9()->device_->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, enable ? TRUE : FALSE);
+        lineAntiAlias_ = enable;
+    }
+}
+
+void Graphics::SetScissorTest_D3D9(bool enable, const Rect& rect, bool borderInclusive)
+{
+    // During some light rendering loops, a full rect is toggled on/off repeatedly.
+    // Disable scissor in that case to reduce state changes
+    if (rect.min_.x_ <= 0.0f && rect.min_.y_ <= 0.0f && rect.max_.x_ >= 1.0f && rect.max_.y_ >= 1.0f)
+        enable = false;
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (enable)
+    {
+        IntVector2 rtSize(GetRenderTargetDimensions_D3D9());
+        IntVector2 viewSize(viewport_.Size());
+        IntVector2 viewPos(viewport_.left_, viewport_.top_);
+        IntRect intRect;
+        int expand = borderInclusive ? 1 : 0;
+
+        intRect.left_ = Clamp((int)((rect.min_.x_ + 1.0f) * 0.5f * viewSize.x_) + viewPos.x_, 0, rtSize.x_ - 1);
+        intRect.top_ = Clamp((int)((-rect.max_.y_ + 1.0f) * 0.5f * viewSize.y_) + viewPos.y_, 0, rtSize.y_ - 1);
+        intRect.right_ = Clamp((int)((rect.max_.x_ + 1.0f) * 0.5f * viewSize.x_) + viewPos.x_ + expand, 0, rtSize.x_);
+        intRect.bottom_ = Clamp((int)((-rect.min_.y_ + 1.0f) * 0.5f * viewSize.y_) + viewPos.y_ + expand, 0, rtSize.y_);
+
+        if (intRect.right_ == intRect.left_)
+            intRect.right_++;
+        if (intRect.bottom_ == intRect.top_)
+            intRect.bottom_++;
+
+        if (intRect.right_ < intRect.left_ || intRect.bottom_ < intRect.top_)
+            enable = false;
+
+        if (enable && scissorRect_ != intRect)
+        {
+            RECT d3dRect;
+            d3dRect.left = intRect.left_;
+            d3dRect.top = intRect.top_;
+            d3dRect.right = intRect.right_;
+            d3dRect.bottom = intRect.bottom_;
+
+            impl->device_->SetScissorRect(&d3dRect);
+            scissorRect_ = intRect;
+        }
+    }
+    else
+        scissorRect_ = IntRect::ZERO;
+
+    if (enable != scissorTest_)
+    {
+        impl->device_->SetRenderState(D3DRS_SCISSORTESTENABLE, enable ? TRUE : FALSE);
+        scissorTest_ = enable;
+    }
+}
+
+void Graphics::SetScissorTest_D3D9(bool enable, const IntRect& rect)
+{
+    IntVector2 rtSize(GetRenderTargetDimensions_D3D9());
+    IntVector2 viewPos(viewport_.left_, viewport_.top_);
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (enable)
+    {
+        IntRect intRect;
+        intRect.left_ = Clamp(rect.left_ + viewPos.x_, 0, rtSize.x_ - 1);
+        intRect.top_ = Clamp(rect.top_ + viewPos.y_, 0, rtSize.y_ - 1);
+        intRect.right_ = Clamp(rect.right_ + viewPos.x_, 0, rtSize.x_);
+        intRect.bottom_ = Clamp(rect.bottom_ + viewPos.y_, 0, rtSize.y_);
+
+        if (intRect.right_ == intRect.left_)
+            intRect.right_++;
+        if (intRect.bottom_ == intRect.top_)
+            intRect.bottom_++;
+
+        if (intRect.right_ < intRect.left_ || intRect.bottom_ < intRect.top_)
+            enable = false;
+
+        if (enable && scissorRect_ != intRect)
+        {
+            RECT d3dRect;
+            d3dRect.left = intRect.left_;
+            d3dRect.top = intRect.top_;
+            d3dRect.right = intRect.right_;
+            d3dRect.bottom = intRect.bottom_;
+
+            impl->device_->SetScissorRect(&d3dRect);
+            scissorRect_ = intRect;
+        }
+    }
+    else
+        scissorRect_ = IntRect::ZERO;
+
+    if (enable != scissorTest_)
+    {
+        impl->device_->SetRenderState(D3DRS_SCISSORTESTENABLE, enable ? TRUE : FALSE);
+        scissorTest_ = enable;
+    }
+}
+
+void Graphics::SetStencilTest_D3D9(bool enable, CompareMode mode, StencilOp pass, StencilOp fail, StencilOp zFail, unsigned stencilRef,
+    unsigned compareMask, unsigned writeMask)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (enable != stencilTest_)
+    {
+        impl->device_->SetRenderState(D3DRS_STENCILENABLE, enable ? TRUE : FALSE);
+        stencilTest_ = enable;
+    }
+
+    if (enable)
+    {
+        if (mode != stencilTestMode_)
+        {
+            impl->device_->SetRenderState(D3DRS_STENCILFUNC, d3dCmpFunc[mode]);
+            stencilTestMode_ = mode;
+        }
+        if (pass != stencilPass_)
+        {
+            impl->device_->SetRenderState(D3DRS_STENCILPASS, d3dStencilOp[pass]);
+            stencilPass_ = pass;
+        }
+        if (fail != stencilFail_)
+        {
+            impl->device_->SetRenderState(D3DRS_STENCILFAIL, d3dStencilOp[fail]);
+            stencilFail_ = fail;
+        }
+        if (zFail != stencilZFail_)
+        {
+            impl->device_->SetRenderState(D3DRS_STENCILZFAIL, d3dStencilOp[zFail]);
+            stencilZFail_ = zFail;
+        }
+        if (stencilRef != stencilRef_)
+        {
+            impl->device_->SetRenderState(D3DRS_STENCILREF, stencilRef);
+            stencilRef_ = stencilRef;
+        }
+        if (compareMask != stencilCompareMask_)
+        {
+            impl->device_->SetRenderState(D3DRS_STENCILMASK, compareMask);
+            stencilCompareMask_ = compareMask;
+        }
+        if (writeMask != stencilWriteMask_)
+        {
+            impl->device_->SetRenderState(D3DRS_STENCILWRITEMASK, writeMask);
+            stencilWriteMask_ = writeMask;
+        }
+    }
+}
+
+void Graphics::SetClipPlane_D3D9(bool enable, const Plane& clipPlane, const Matrix3x4& view, const Matrix4& projection)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (enable != useClipPlane_)
+    {
+        impl->device_->SetRenderState(D3DRS_CLIPPLANEENABLE, enable ? 1 : 0);
+        useClipPlane_ = enable;
+    }
+
+    if (enable)
+    {
+        Matrix4 viewProj = projection * view;
+        impl->device_->SetClipPlane(0, clipPlane.Transformed(viewProj).ToVector4().Data());
+    }
+}
+
+bool Graphics::IsInitialized_D3D9() const
+{
+    return window_ != nullptr && GetImpl_D3D9()->GetDevice() != nullptr;
+}
+
+PODVector<int> Graphics::GetMultiSampleLevels_D3D9() const
+{
+    PODVector<int> ret;
+    // No multisampling always supported
+    ret.Push(1);
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (!impl->interface_)
+        return ret;
+
+    SDL_DisplayMode mode;
+    SDL_GetDesktopDisplayMode(0, &mode);
+    D3DFORMAT fullscreenFormat = SDL_BITSPERPIXEL(mode.format) == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
+
+    for (int i = (int)D3DMULTISAMPLE_2_SAMPLES; i < (int)D3DMULTISAMPLE_16_SAMPLES; ++i)
+    {
+        if (impl->CheckMultiSampleSupport(fullscreenFormat, i))
+            ret.Push(i);
+    }
+
+    return ret;
+}
+
+unsigned Graphics::GetFormat_D3D9(CompressedFormat format) const
+{
+    switch (format)
+    {
+    case CF_RGBA:
+        return D3DFMT_A8R8G8B8;
+
+    case CF_DXT1:
+        return D3DFMT_DXT1;
+
+    case CF_DXT3:
+        return D3DFMT_DXT3;
+
+    case CF_DXT5:
+        return D3DFMT_DXT5;
+
+    default:
+        return 0;
+    }
+}
+
+ShaderVariation* Graphics::GetShader_D3D9(ShaderType type, const String& name, const String& defines) const
+{
+    return GetShader_D3D9(type, name.CString(), defines.CString());
+}
+
+ShaderVariation* Graphics::GetShader_D3D9(ShaderType type, const char* name, const char* defines) const
+{
+    if (lastShaderName_ != name || !lastShader_)
+    {
+        ResourceCache* cache = GetSubsystem<ResourceCache>();
+
+        String fullShaderName = shaderPath_ + name + shaderExtension_;
+        // Try to reduce repeated error log prints because of missing shaders
+        if (lastShaderName_ == name && !cache->Exists(fullShaderName))
+            return nullptr;
+
+        lastShader_ = cache->GetResource<Shader>(fullShaderName);
+        lastShaderName_ = name;
+    }
+
+    return lastShader_ ? lastShader_->GetVariation(type, defines) : nullptr;
+}
+
+VertexBuffer* Graphics::GetVertexBuffer_D3D9(unsigned index) const
+{
+    return index < MAX_VERTEX_STREAMS ? vertexBuffers_[index] : nullptr;
+}
+
+TextureUnit Graphics::GetTextureUnit_D3D9(const String& name)
+{
+    HashMap<String, TextureUnit>::Iterator i = textureUnits_.Find(name);
+    if (i != textureUnits_.End())
+        return i->second_;
+    else
+        return MAX_TEXTURE_UNITS;
+}
+
+const String& Graphics::GetTextureUnitName_D3D9(TextureUnit unit)
+{
+    for (HashMap<String, TextureUnit>::Iterator i = textureUnits_.Begin(); i != textureUnits_.End(); ++i)
+    {
+        if (i->second_ == unit)
+            return i->first_;
+    }
+    return String::EMPTY;
+}
+
+Texture* Graphics::GetTexture_D3D9(unsigned index) const
+{
+    return index < MAX_TEXTURE_UNITS ? textures_[index] : nullptr;
+}
+
+RenderSurface* Graphics::GetRenderTarget_D3D9(unsigned index) const
+{
+    return index < MAX_RENDERTARGETS ? renderTargets_[index] : nullptr;
+}
+
+IntVector2 Graphics::GetRenderTargetDimensions_D3D9() const
+{
+    int width, height;
+
+    if (renderTargets_[0])
+    {
+        width = renderTargets_[0]->GetWidth();
+        height = renderTargets_[0]->GetHeight();
+    }
+    else
+    {
+        width = width_;
+        height = height_;
+    }
+
+    return IntVector2(width, height);
+}
+
+bool Graphics::GetDither_D3D9() const
+{
+    return false;
+}
+
+bool Graphics::IsDeviceLost_D3D9() const
+{
+    return GetImpl_D3D9()->deviceLost_;
+}
+
+void Graphics::OnWindowResized_D3D9()
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (!impl->device_ || !window_)
+        return;
+
+    int newWidth, newHeight;
+
+    SDL_GetWindowSize(window_, &newWidth, &newHeight);
+    if (newWidth == width_ && newHeight == height_)
+        return;
+
+    width_ = newWidth;
+    height_ = newHeight;
+
+    impl->presentParams_.BackBufferWidth = (UINT)width_;
+    impl->presentParams_.BackBufferHeight = (UINT)height_;
+    ResetDevice_D3D9();
+
+    // Reset rendertargets and viewport for the new screen size
+    ResetRenderTargets_D3D9();
+
+    URHO3D_LOGDEBUGF("Window was resized to %dx%d", width_, height_);
+
+    using namespace ScreenMode;
+
+    VariantMap& eventData = GetEventDataMap();
+    eventData[P_WIDTH] = width_;
+    eventData[P_HEIGHT] = height_;
+    eventData[P_FULLSCREEN] = screenParams_.fullscreen_;
+    eventData[P_RESIZABLE] = screenParams_.resizable_;
+    eventData[P_BORDERLESS] = screenParams_.borderless_;
+    eventData[P_HIGHDPI] = screenParams_.highDPI_;
+    SendEvent(E_SCREENMODE, eventData);
+}
+
+void Graphics::OnWindowMoved_D3D9()
+{
+    if (!GetImpl_D3D9()->device_ || !window_ || screenParams_.fullscreen_)
+        return;
+
+    int newX, newY;
+
+    SDL_GetWindowPosition(window_, &newX, &newY);
+    if (newX == position_.x_ && newY == position_.y_)
+        return;
+
+    position_.x_ = newX;
+    position_.y_ = newY;
+
+    URHO3D_LOGTRACEF("Window was moved to %d,%d", position_.x_, position_.y_);
+
+    using namespace WindowPos;
+
+    VariantMap& eventData = GetEventDataMap();
+    eventData[P_X] = position_.x_;
+    eventData[P_Y] = position_.y_;
+    SendEvent(E_WINDOWPOS, eventData);
+}
+
+void Graphics::CleanupShaderPrograms_D3D9(ShaderVariation* variation)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    for (ShaderProgramMap_D3D9::Iterator i = impl->shaderPrograms_.Begin(); i != impl->shaderPrograms_.End();)
+    {
+        if (i->first_.first_ == variation || i->first_.second_ == variation)
+            i = impl->shaderPrograms_.Erase(i);
+        else
+            ++i;
+    }
+
+    if (vertexShader_ == variation || pixelShader_ == variation)
+        impl->shaderProgram_ = nullptr;
+}
+
+ConstantBuffer* Graphics::GetOrCreateConstantBuffer_D3D9(ShaderType /*type*/, unsigned index, unsigned size)
+{
+    // No-op on Direct3D 9
+    return nullptr;
+}
+
+unsigned Graphics::GetAlphaFormat_D3D9()
+{
+    return D3DFMT_A8;
+}
+
+unsigned Graphics::GetLuminanceFormat_D3D9()
+{
+    return D3DFMT_L8;
+}
+
+unsigned Graphics::GetLuminanceAlphaFormat_D3D9()
+{
+    return D3DFMT_A8L8;
+}
+
+unsigned Graphics::GetRGBFormat_D3D9()
+{
+    return D3DFMT_X8R8G8B8;
+}
+
+unsigned Graphics::GetRGBAFormat_D3D9()
+{
+    return D3DFMT_A8R8G8B8;
+}
+
+unsigned Graphics::GetRGBA16Format_D3D9()
+{
+    return D3DFMT_A16B16G16R16;
+}
+
+unsigned Graphics::GetRGBAFloat16Format_D3D9()
+{
+    return D3DFMT_A16B16G16R16F;
+}
+
+unsigned Graphics::GetRGBAFloat32Format_D3D9()
+{
+    return D3DFMT_A32B32G32R32F;
+}
+
+unsigned Graphics::GetRG16Format_D3D9()
+{
+    return D3DFMT_G16R16;
+}
+
+unsigned Graphics::GetRGFloat16Format_D3D9()
+{
+    return D3DFMT_G16R16F;
+}
+
+unsigned Graphics::GetRGFloat32Format_D3D9()
+{
+    return D3DFMT_G32R32F;
+}
+
+unsigned Graphics::GetFloat16Format_D3D9()
+{
+    return D3DFMT_R16F;
+}
+
+unsigned Graphics::GetFloat32Format_D3D9()
+{
+    return D3DFMT_R32F;
+}
+
+unsigned Graphics::GetLinearDepthFormat_D3D9()
+{
+    return D3DFMT_R32F;
+}
+
+unsigned Graphics::GetDepthStencilFormat_D3D9()
+{
+    return D3DFMT_D24S8;
+}
+
+unsigned Graphics::GetReadableDepthFormat_D3D9()
+{
+    return readableDepthFormat;
+}
+
+unsigned Graphics::GetFormat_D3D9(const String& formatName)
+{
+    String nameLower = formatName.ToLower().Trimmed();
+
+    if (nameLower == "a")
+        return GetAlphaFormat_D3D9();
+    if (nameLower == "l")
+        return GetLuminanceFormat_D3D9();
+    if (nameLower == "la")
+        return GetLuminanceAlphaFormat_D3D9();
+    if (nameLower == "rgb")
+        return GetRGBFormat_D3D9();
+    if (nameLower == "rgba")
+        return GetRGBAFormat_D3D9();
+    if (nameLower == "rgba16")
+        return GetRGBA16Format_D3D9();
+    if (nameLower == "rgba16f")
+        return GetRGBAFloat16Format_D3D9();
+    if (nameLower == "rgba32f")
+        return GetRGBAFloat32Format_D3D9();
+    if (nameLower == "rg16")
+        return GetRG16Format_D3D9();
+    if (nameLower == "rg16f")
+        return GetRGFloat16Format_D3D9();
+    if (nameLower == "rg32f")
+        return GetRGFloat32Format_D3D9();
+    if (nameLower == "r16f")
+        return GetFloat16Format_D3D9();
+    if (nameLower == "r32f" || nameLower == "float")
+        return GetFloat32Format_D3D9();
+    if (nameLower == "lineardepth" || nameLower == "depth")
+        return GetLinearDepthFormat_D3D9();
+    if (nameLower == "d24s8")
+        return GetDepthStencilFormat_D3D9();
+    if (nameLower == "readabledepth" || nameLower == "hwdepth")
+        return GetReadableDepthFormat_D3D9();
+
+    return GetRGBFormat_D3D9();
+}
+
+unsigned Graphics::GetMaxBones_D3D9()
+{
+    return 64;
+}
+
+bool Graphics::GetGL3Support_D3D9()
+{
+    return false;
+}
+
+void Graphics::SetStreamFrequency_D3D9(unsigned index, unsigned frequency)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (index < MAX_VERTEX_STREAMS && impl->streamFrequencies_[index] != frequency)
+    {
+        impl->device_->SetStreamSourceFreq(index, frequency);
+        impl->streamFrequencies_[index] = frequency;
+    }
+}
+
+void Graphics::ResetStreamFrequencies_D3D9()
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
+    {
+        if (impl->streamFrequencies_[i] != 1)
+        {
+            impl->device_->SetStreamSourceFreq(i, 1);
+            impl->streamFrequencies_[i] = 1;
+        }
+    }
+}
+
+bool Graphics::OpenWindow_D3D9(int width, int height, bool resizable, bool borderless)
+{
+    if (!externalWindow_)
+    {
+        unsigned flags = 0;
+        if (resizable)
+            flags |= SDL_WINDOW_RESIZABLE;
+        if (borderless)
+            flags |= SDL_WINDOW_BORDERLESS;
+
+        window_ = SDL_CreateWindow(windowTitle_.CString(), position_.x_, position_.y_, width, height, flags);
+    }
+    else
+        window_ = SDL_CreateWindowFrom(externalWindow_, 0);
+
+    if (!window_)
+    {
+        URHO3D_LOGERRORF("Could not create window, root cause: '%s'", SDL_GetError());
+        return false;
+    }
+
+    SDL_GetWindowPosition(window_, &position_.x_, &position_.y_);
+
+    CreateWindowIcon();
+
+    return true;
+}
+
+void Graphics::AdjustWindow_D3D9(int& newWidth, int& newHeight, bool& newFullscreen, bool& newBorderless, int& monitor)
+{
+    if (!externalWindow_)
+    {
+        // Keep current window position because it may change in intermediate callbacks
+        const IntVector2 oldPosition = position_;
+        bool reposition = false;
+        bool resizePostponed = false;
+        if (!newWidth || !newHeight)
+        {
+            SDL_MaximizeWindow(window_);
+            SDL_GetWindowSize(window_, &newWidth, &newHeight);
+        }
+        else {
+            SDL_Rect display_rect;
+            SDL_GetDisplayBounds(monitor, &display_rect);
+
+            reposition = newFullscreen || (newBorderless && newWidth >= display_rect.w && newHeight >= display_rect.h);
+            if (reposition)
+            {
+                // Reposition the window on the specified monitor if it's supposed to cover the entire monitor
+                SDL_SetWindowPosition(window_, display_rect.x, display_rect.y);
+            }
+
+            // Postpone window resize if exiting fullscreen to avoid redundant resolution change
+            if (!newFullscreen && screenParams_.fullscreen_)
+                resizePostponed = true;
+            else
+                SDL_SetWindowSize(window_, newWidth, newHeight);
+        }
+
+        // Hack fix: on SDL 2.0.4 a fullscreen->windowed transition results in a maximized window when the D3D device is reset, so hide before
+        if (!newFullscreen) SDL_HideWindow(window_);
+        SDL_SetWindowFullscreen(window_, newFullscreen ? SDL_WINDOW_FULLSCREEN : 0);
+        SDL_SetWindowBordered(window_, newBorderless ? SDL_FALSE : SDL_TRUE);
+        if (!newFullscreen) SDL_ShowWindow(window_);
+
+        // Resize now if was postponed
+        if (resizePostponed)
+            SDL_SetWindowSize(window_, newWidth, newHeight);
+
+        // Ensure that window keeps its position
+        if (!reposition)
+            SDL_SetWindowPosition(window_, oldPosition.x_, oldPosition.y_);
+        else
+            position_ = oldPosition;
+    }
+    else
+    {
+        // If external window, must ask its dimensions instead of trying to set them
+        SDL_GetWindowSize(window_, &newWidth, &newHeight);
+        newFullscreen = false;
+    }
+}
+
+bool Graphics::CreateInterface_D3D9()
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    impl->interface_ = Direct3DCreate9(D3D_SDK_VERSION);
+    if (!impl->interface_)
+    {
+        URHO3D_LOGERROR("Could not create Direct3D9 interface");
+        return false;
+    }
+
+    HRESULT hr = impl->interface_->GetDeviceCaps(impl->adapter_, impl->deviceType_, &impl->deviceCaps_);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Could not get Direct3D capabilities", hr);
+        return false;
+    }
+
+    hr = impl->interface_->GetAdapterIdentifier(impl->adapter_, 0, &impl->adapterIdentifier_);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Could not get Direct3D adapter identifier", hr);
+        return false;
+    }
+
+    if (impl->deviceCaps_.PixelShaderVersion < D3DPS_VERSION(3, 0))
+    {
+        URHO3D_LOGERROR("Shader model 3.0 display adapter is required");
+        return false;
+    }
+
+    return true;
+}
+
+bool Graphics::CreateDevice_D3D9(unsigned adapter, unsigned deviceType)
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+#ifdef URHO3D_LUAJIT
+    DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE;
+#else
+    DWORD behaviorFlags = 0;
+#endif
+    if (impl->deviceCaps_.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
+    {
+        behaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
+        if (impl->deviceCaps_.DevCaps & D3DDEVCAPS_PUREDEVICE)
+            behaviorFlags |= D3DCREATE_PUREDEVICE;
+    }
+    else
+        behaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
+
+    HRESULT hr = impl->interface_->CreateDevice(
+        adapter,
+        (D3DDEVTYPE)deviceType,
+        GetWindowHandle(window_),
+        behaviorFlags,
+        &impl->presentParams_,
+        &impl->device_);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Could not create Direct3D9 device", hr);
+        return false;
+    }
+
+    impl->adapter_ = adapter;
+    impl->deviceType_ = (D3DDEVTYPE)deviceType;
+
+    OnDeviceReset_D3D9();
+
+    URHO3D_LOGINFO("Created Direct3D9 device");
+    return true;
+}
+
+void Graphics::CheckFeatureSupport_D3D9()
+{
+    anisotropySupport_ = true;
+    dxtTextureSupport_ = true;
+
+    // Reset features first
+    lightPrepassSupport_ = false;
+    deferredSupport_ = false;
+    hardwareShadowSupport_ = false;
+    instancingSupport_ = false;
+    readableDepthFormat = 0;
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    // Check hardware shadow map support: prefer NVIDIA style hardware depth compared shadow maps if available
+    shadowMapFormat_ = D3DFMT_D16;
+    if (impl->CheckFormatSupport((D3DFORMAT)shadowMapFormat_, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE))
+    {
+        hardwareShadowSupport_ = true;
+
+        // Check for hires depth support
+        hiresShadowMapFormat_ = D3DFMT_D24X8;
+        if (!impl->CheckFormatSupport((D3DFORMAT)hiresShadowMapFormat_, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE))
+            hiresShadowMapFormat_ = 0;
+    }
+    else
+    {
+        // ATI DF16 format needs manual depth compare in the shader
+        shadowMapFormat_ = MAKEFOURCC('D', 'F', '1', '6');
+        if (impl->CheckFormatSupport((D3DFORMAT)shadowMapFormat_, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE))
+        {
+            // Check for hires depth support
+            hiresShadowMapFormat_ = MAKEFOURCC('D', 'F', '2', '4');
+            if (!impl->CheckFormatSupport((D3DFORMAT)hiresShadowMapFormat_, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE))
+                hiresShadowMapFormat_ = 0;
+        }
+        else
+        {
+            // No shadow map support
+            shadowMapFormat_ = 0;
+            hiresShadowMapFormat_ = 0;
+        }
+    }
+
+    // Check for Intel 4 Series with an old driver, enable manual shadow map compare in that case
+    if (shadowMapFormat_ == D3DFMT_D16)
+    {
+        if (impl->adapterIdentifier_.VendorId == 0x8086 && impl->adapterIdentifier_.DeviceId == 0x2a42 &&
+            impl->adapterIdentifier_.DriverVersion.QuadPart <= 0x0007000f000a05d0ULL)
+            hardwareShadowSupport_ = false;
+    }
+
+    // Check for readable depth (INTZ hack)
+    D3DFORMAT intZFormat = (D3DFORMAT)MAKEFOURCC('I', 'N', 'T', 'Z');
+    if (impl->CheckFormatSupport(intZFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE))
+        readableDepthFormat = intZFormat;
+
+    // Check for dummy color rendertarget format used with hardware shadow maps
+    dummyColorFormat_ = D3DFMT_A8R8G8B8;
+    D3DFORMAT nullFormat = (D3DFORMAT)MAKEFOURCC('N', 'U', 'L', 'L');
+    if (impl->CheckFormatSupport(nullFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE))
+        dummyColorFormat_ = nullFormat;
+    else if (impl->CheckFormatSupport(D3DFMT_R16F, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE))
+        dummyColorFormat_ = D3DFMT_R16F;
+    else if (impl->CheckFormatSupport(D3DFMT_R5G6B5, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE))
+        dummyColorFormat_ = D3DFMT_R5G6B5;
+    else if (impl->CheckFormatSupport(D3DFMT_A4R4G4B4, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE))
+        dummyColorFormat_ = D3DFMT_A4R4G4B4;
+
+    // Check for light prepass and deferred rendering support
+    if (impl->deviceCaps_.NumSimultaneousRTs >= 2 && impl->CheckFormatSupport(D3DFMT_R32F, D3DUSAGE_RENDERTARGET,
+        D3DRTYPE_TEXTURE))
+    {
+        lightPrepassSupport_ = true;
+        if (impl->deviceCaps_.NumSimultaneousRTs >= 4)
+            deferredSupport_ = true;
+    }
+
+    // Check for stream offset (needed for instancing)
+    if (impl->deviceCaps_.DevCaps2 & D3DDEVCAPS2_STREAMOFFSET)
+        instancingSupport_ = true;
+
+    // Check for sRGB read & write
+    /// \todo Should be checked for each texture format separately
+    sRGBSupport_ = impl->CheckFormatSupport(D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_TEXTURE);
+    sRGBWriteSupport_ = impl->CheckFormatSupport(D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBWRITE, D3DRTYPE_TEXTURE);
+}
+
+void Graphics::ResetDevice_D3D9()
+{
+    OnDeviceLost_D3D9();
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (SUCCEEDED(impl->device_->Reset(&impl->presentParams_)))
+    {
+        impl->deviceLost_ = false;
+        OnDeviceReset_D3D9();
+    }
+}
+
+void Graphics::OnDeviceLost_D3D9()
+{
+    URHO3D_LOGINFO("Device lost");
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    if (impl->defaultColorSurface_)
+    {
+        impl->defaultColorSurface_->Release();
+        impl->defaultColorSurface_ = nullptr;
+    }
+    if (impl->defaultDepthStencilSurface_)
+    {
+        impl->defaultDepthStencilSurface_->Release();
+        impl->defaultDepthStencilSurface_ = nullptr;
+    }
+    if (impl->frameQuery_)
+    {
+        impl->frameQuery_->Release();
+        impl->frameQuery_ = nullptr;
+    }
+
+    {
+        MutexLock lock(gpuObjectMutex_);
+
+        for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
+            (*i)->OnDeviceLost();
+    }
+
+    SendEvent(E_DEVICELOST);
+}
+
+void Graphics::OnDeviceReset_D3D9()
+{
+    {
+        MutexLock lock(gpuObjectMutex_);
+
+        for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
+            (*i)->OnDeviceReset();
+    }
+
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    // Get default surfaces
+    impl->device_->GetRenderTarget(0, &impl->defaultColorSurface_);
+    impl->device_->GetDepthStencilSurface(&impl->defaultDepthStencilSurface_);
+
+    // Create frame query for flushing the GPU command buffer
+    impl->device_->CreateQuery(D3DQUERYTYPE_EVENT, &impl->frameQuery_);
+
+    ResetCachedState_D3D9();
+
+    SendEvent(E_DEVICERESET);
+}
+
+void Graphics::ResetCachedState_D3D9()
+{
+    GraphicsImpl_D3D9* impl = GetImpl_D3D9();
+
+    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
+    {
+        vertexBuffers_[i] = nullptr;
+        impl->streamOffsets_[i] = 0;
+    }
+
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+    {
+        textures_[i] = nullptr;
+        impl->minFilters_[i] = D3DTEXF_POINT;
+        impl->magFilters_[i] = D3DTEXF_POINT;
+        impl->mipFilters_[i] = D3DTEXF_NONE;
+        impl->uAddressModes_[i] = D3DTADDRESS_WRAP;
+        impl->vAddressModes_[i] = D3DTADDRESS_WRAP;
+        impl->wAddressModes_[i] = D3DTADDRESS_WRAP;
+        impl->maxAnisotropy_[i] = M_MAX_UNSIGNED;
+        impl->borderColors_[i] = Color(0.0f, 0.0f, 0.0f, 0.0f);
+        impl->sRGBModes_[i] = false;
+    }
+
+    for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
+    {
+        renderTargets_[i] = nullptr;
+        impl->colorSurfaces_[i] = nullptr;
+    }
+
+    depthStencil_ = nullptr;
+    impl->depthStencilSurface_ = nullptr;
+    viewport_ = IntRect(0, 0, width_, height_);
+    impl->sRGBWrite_ = false;
+
+    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
+        impl->streamFrequencies_[i] = 1;
+
+    indexBuffer_ = nullptr;
+    vertexShader_ = nullptr;
+    pixelShader_ = nullptr;
+    blendMode_ = BLEND_REPLACE;
+    alphaToCoverage_ = false;
+    colorWrite_ = true;
+    cullMode_ = CULL_CCW;
+    constantDepthBias_ = 0.0f;
+    slopeScaledDepthBias_ = 0.0f;
+    depthTestMode_ = CMP_LESSEQUAL;
+    depthWrite_ = true;
+    lineAntiAlias_ = false;
+    fillMode_ = FILL_SOLID;
+    scissorTest_ = false;
+    scissorRect_ = IntRect::ZERO;
+    stencilTest_ = false;
+    stencilTestMode_ = CMP_ALWAYS;
+    stencilPass_ = OP_KEEP;
+    stencilFail_ = OP_KEEP;
+    stencilZFail_ = OP_KEEP;
+    stencilRef_ = 0;
+    stencilCompareMask_ = M_MAX_UNSIGNED;
+    stencilWriteMask_ = M_MAX_UNSIGNED;
+    useClipPlane_ = false;
+    impl->blendEnable_ = FALSE;
+    impl->srcBlend_ = D3DBLEND_ONE;
+    impl->destBlend_ = D3DBLEND_ZERO;
+    impl->blendOp_ = D3DBLENDOP_ADD;
+    impl->vertexDeclaration_ = nullptr;
+    impl->queryIssued_ = false;
+}
+
+void Graphics::SetTextureUnitMappings_D3D9()
+{
+    textureUnits_["DiffMap"] = TU_DIFFUSE;
+    textureUnits_["DiffCubeMap"] = TU_DIFFUSE;
+    textureUnits_["NormalMap"] = TU_NORMAL;
+    textureUnits_["SpecMap"] = TU_SPECULAR;
+    textureUnits_["EmissiveMap"] = TU_EMISSIVE;
+    textureUnits_["EnvMap"] = TU_ENVIRONMENT;
+    textureUnits_["EnvCubeMap"] = TU_ENVIRONMENT;
+    textureUnits_["LightRampMap"] = TU_LIGHTRAMP;
+    textureUnits_["LightSpotMap"] = TU_LIGHTSHAPE;
+    textureUnits_["LightCubeMap"] = TU_LIGHTSHAPE;
+    textureUnits_["ShadowMap"] = TU_SHADOWMAP;
+    textureUnits_["FaceSelectCubeMap"] = TU_FACESELECT;
+    textureUnits_["IndirectionCubeMap"] = TU_INDIRECTION;
+    textureUnits_["VolumeMap"] = TU_VOLUMEMAP;
+    textureUnits_["ZoneCubeMap"] = TU_ZONE;
+    textureUnits_["ZoneVolumeMap"] = TU_ZONE;
+}
+
+}

+ 60 - 60
Source/Urho3D/Graphics/Direct3D9/D3D9GraphicsImpl.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9GraphicsImpl.cpp

@@ -1,60 +1,60 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Graphics/Graphics.h"
-#include "D3D9GraphicsImpl.h"
-
-#include "../../DebugNew.h"
-
-namespace Urho3D
-{
-
-GraphicsImpl_D3D9::GraphicsImpl_D3D9() :
-    interface_(nullptr),
-    device_(nullptr),
-    defaultColorSurface_(nullptr),
-    defaultDepthStencilSurface_(nullptr),
-    frameQuery_(nullptr),
-    adapter_(D3DADAPTER_DEFAULT),
-    deviceType_(D3DDEVTYPE_HAL),
-    shaderProgram_(nullptr),
-    deviceLost_(false),
-    queryIssued_(false)
-{
-    memset(&presentParams_, 0, sizeof presentParams_);
-}
-
-bool GraphicsImpl_D3D9::CheckFormatSupport(D3DFORMAT format, DWORD usage, D3DRESOURCETYPE type)
-{
-    return interface_ ? SUCCEEDED(interface_->CheckDeviceFormat(adapter_, deviceType_, D3DFMT_X8R8G8B8, usage, type, format)) :
-        false;
-}
-
-bool GraphicsImpl_D3D9::CheckMultiSampleSupport(D3DFORMAT format, int level)
-{
-    return interface_ ? SUCCEEDED(interface_->CheckDeviceMultiSampleType(adapter_, deviceType_, format, FALSE,
-        (D3DMULTISAMPLE_TYPE)level, nullptr)) : false;
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Graphics/Graphics.h"
+#include "D3D9GraphicsImpl.h"
+
+#include "../../DebugNew.h"
+
+namespace Urho3D
+{
+
+GraphicsImpl_D3D9::GraphicsImpl_D3D9() :
+    interface_(nullptr),
+    device_(nullptr),
+    defaultColorSurface_(nullptr),
+    defaultDepthStencilSurface_(nullptr),
+    frameQuery_(nullptr),
+    adapter_(D3DADAPTER_DEFAULT),
+    deviceType_(D3DDEVTYPE_HAL),
+    shaderProgram_(nullptr),
+    deviceLost_(false),
+    queryIssued_(false)
+{
+    memset(&presentParams_, 0, sizeof presentParams_);
+}
+
+bool GraphicsImpl_D3D9::CheckFormatSupport(D3DFORMAT format, DWORD usage, D3DRESOURCETYPE type)
+{
+    return interface_ ? SUCCEEDED(interface_->CheckDeviceFormat(adapter_, deviceType_, D3DFMT_X8R8G8B8, usage, type, format)) :
+        false;
+}
+
+bool GraphicsImpl_D3D9::CheckMultiSampleSupport(D3DFORMAT format, int level)
+{
+    return interface_ ? SUCCEEDED(interface_->CheckDeviceMultiSampleType(adapter_, deviceType_, format, FALSE,
+        (D3DMULTISAMPLE_TYPE)level, nullptr)) : false;
+}
+
+}

+ 137 - 137
Source/Urho3D/Graphics/Direct3D9/D3D9GraphicsImpl.h → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9GraphicsImpl.h

@@ -1,137 +1,137 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#pragma once
-
-#include "../../Math/Color.h"
-#include "D3D9ShaderProgram.h"
-#include "D3D9VertexDeclaration.h"
-
-#include <d3d9.h>
-
-namespace Urho3D
-{
-
-#define URHO3D_SAFE_RELEASE(p) if (p) { ((IUnknown*)p)->Release();  p = 0; }
-
-#define URHO3D_LOGD3DERROR(msg, hr) URHO3D_LOGERRORF("%s (HRESULT %x)", msg, (unsigned)hr)
-
-using ShaderProgramMap_D3D9 = HashMap<Pair<ShaderVariation*, ShaderVariation*>, SharedPtr<ShaderProgram_D3D9> >;
-using VertexDeclarationMap_D3D9 = HashMap<unsigned long long, SharedPtr<VertexDeclaration_D3D9> >;
-
-/// %Graphics implementation. Holds API-specific objects.
-class URHO3D_API GraphicsImpl_D3D9
-{
-    friend class Graphics;
-
-public:
-    /// Construct.
-    GraphicsImpl_D3D9();
-
-    /// Return Direct3D device.
-    IDirect3DDevice9* GetDevice() const { return device_; }
-
-    /// Return device capabilities.
-    const D3DCAPS9& GetDeviceCaps() const { return deviceCaps_; }
-
-    /// Return adapter identifier.
-    const D3DADAPTER_IDENTIFIER9& GetAdapterIdentifier() const { return adapterIdentifier_; }
-
-    /// Return whether a texture format and usage is supported.
-    bool CheckFormatSupport(D3DFORMAT format, DWORD usage, D3DRESOURCETYPE type);
-
-    /// Return whether a multisample level is supported.
-    bool CheckMultiSampleSupport(D3DFORMAT format, int level);
-
-private:
-    /// Direct3D interface.
-    IDirect3D9* interface_;
-    /// Direct3D device.
-    IDirect3DDevice9* device_;
-    /// Default color surface.
-    IDirect3DSurface9* defaultColorSurface_;
-    /// Default depth-stencil surface.
-    IDirect3DSurface9* defaultDepthStencilSurface_;
-    /// Frame query for flushing the GPU command queue.
-    IDirect3DQuery9* frameQuery_;
-    /// Adapter number.
-    DWORD adapter_;
-    /// Device type.
-    D3DDEVTYPE deviceType_;
-    /// Device capabilities.
-    D3DCAPS9 deviceCaps_;
-    /// Adapter identifier.
-    D3DADAPTER_IDENTIFIER9 adapterIdentifier_;
-    /// Direct3D presentation parameters.
-    D3DPRESENT_PARAMETERS presentParams_;
-    /// Texture min filter modes in use.
-    D3DTEXTUREFILTERTYPE minFilters_[MAX_TEXTURE_UNITS];
-    /// Texture mag filter modes in use.
-    D3DTEXTUREFILTERTYPE magFilters_[MAX_TEXTURE_UNITS];
-    /// Texture mip filter modes in use.
-    D3DTEXTUREFILTERTYPE mipFilters_[MAX_TEXTURE_UNITS];
-    /// Texture U coordinate addressing modes in use.
-    D3DTEXTUREADDRESS uAddressModes_[MAX_TEXTURE_UNITS];
-    /// Texture V coordinate addressing modes in use.
-    D3DTEXTUREADDRESS vAddressModes_[MAX_TEXTURE_UNITS];
-    /// Texture W coordinate addressing modes in use.
-    D3DTEXTUREADDRESS wAddressModes_[MAX_TEXTURE_UNITS];
-    /// Texture anisotropy setting in use.
-    unsigned maxAnisotropy_[MAX_TEXTURE_UNITS];
-    /// Texture border colors in use.
-    Color borderColors_[MAX_TEXTURE_UNITS];
-    /// Device lost flag.
-    bool deviceLost_;
-    /// Frame query issued flag.
-    bool queryIssued_;
-    /// sRGB mode in use.
-    bool sRGBModes_[MAX_TEXTURE_UNITS];
-    /// sRGB write flag.
-    bool sRGBWrite_;
-    /// Color surfaces in use.
-    IDirect3DSurface9* colorSurfaces_[MAX_RENDERTARGETS];
-    /// Depth-stencil surface in use.
-    IDirect3DSurface9* depthStencilSurface_;
-    /// Blending enabled flag.
-    DWORD blendEnable_;
-    /// Source blend mode.
-    D3DBLEND srcBlend_;
-    /// Destination blend mode.
-    D3DBLEND destBlend_;
-    /// Blend operation.
-    D3DBLENDOP blendOp_;
-    /// Vertex declarations.
-    VertexDeclarationMap_D3D9 vertexDeclarations_;
-    /// Stream frequencies by vertex buffer.
-    unsigned streamFrequencies_[MAX_VERTEX_STREAMS];
-    /// Stream offsets by vertex buffer.
-    unsigned streamOffsets_[MAX_VERTEX_STREAMS];
-    /// Vertex declaration in use.
-    VertexDeclaration_D3D9* vertexDeclaration_;
-    /// Shader programs.
-    ShaderProgramMap_D3D9 shaderPrograms_;
-    /// Shader program in use.
-    ShaderProgram_D3D9* shaderProgram_;
-
-};
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "../../GraphicsAPI/Direct3D9/D3D9ShaderProgram.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9VertexDeclaration.h"
+#include "../../Math/Color.h"
+
+#include <d3d9.h>
+
+namespace Urho3D
+{
+
+#define URHO3D_SAFE_RELEASE(p) if (p) { ((IUnknown*)p)->Release();  p = 0; }
+
+#define URHO3D_LOGD3DERROR(msg, hr) URHO3D_LOGERRORF("%s (HRESULT %x)", msg, (unsigned)hr)
+
+using ShaderProgramMap_D3D9 = HashMap<Pair<ShaderVariation*, ShaderVariation*>, SharedPtr<ShaderProgram_D3D9> >;
+using VertexDeclarationMap_D3D9 = HashMap<unsigned long long, SharedPtr<VertexDeclaration_D3D9> >;
+
+/// %Graphics implementation. Holds API-specific objects.
+class URHO3D_API GraphicsImpl_D3D9
+{
+    friend class Graphics;
+
+public:
+    /// Construct.
+    GraphicsImpl_D3D9();
+
+    /// Return Direct3D device.
+    IDirect3DDevice9* GetDevice() const { return device_; }
+
+    /// Return device capabilities.
+    const D3DCAPS9& GetDeviceCaps() const { return deviceCaps_; }
+
+    /// Return adapter identifier.
+    const D3DADAPTER_IDENTIFIER9& GetAdapterIdentifier() const { return adapterIdentifier_; }
+
+    /// Return whether a texture format and usage is supported.
+    bool CheckFormatSupport(D3DFORMAT format, DWORD usage, D3DRESOURCETYPE type);
+
+    /// Return whether a multisample level is supported.
+    bool CheckMultiSampleSupport(D3DFORMAT format, int level);
+
+private:
+    /// Direct3D interface.
+    IDirect3D9* interface_;
+    /// Direct3D device.
+    IDirect3DDevice9* device_;
+    /// Default color surface.
+    IDirect3DSurface9* defaultColorSurface_;
+    /// Default depth-stencil surface.
+    IDirect3DSurface9* defaultDepthStencilSurface_;
+    /// Frame query for flushing the GPU command queue.
+    IDirect3DQuery9* frameQuery_;
+    /// Adapter number.
+    DWORD adapter_;
+    /// Device type.
+    D3DDEVTYPE deviceType_;
+    /// Device capabilities.
+    D3DCAPS9 deviceCaps_;
+    /// Adapter identifier.
+    D3DADAPTER_IDENTIFIER9 adapterIdentifier_;
+    /// Direct3D presentation parameters.
+    D3DPRESENT_PARAMETERS presentParams_;
+    /// Texture min filter modes in use.
+    D3DTEXTUREFILTERTYPE minFilters_[MAX_TEXTURE_UNITS];
+    /// Texture mag filter modes in use.
+    D3DTEXTUREFILTERTYPE magFilters_[MAX_TEXTURE_UNITS];
+    /// Texture mip filter modes in use.
+    D3DTEXTUREFILTERTYPE mipFilters_[MAX_TEXTURE_UNITS];
+    /// Texture U coordinate addressing modes in use.
+    D3DTEXTUREADDRESS uAddressModes_[MAX_TEXTURE_UNITS];
+    /// Texture V coordinate addressing modes in use.
+    D3DTEXTUREADDRESS vAddressModes_[MAX_TEXTURE_UNITS];
+    /// Texture W coordinate addressing modes in use.
+    D3DTEXTUREADDRESS wAddressModes_[MAX_TEXTURE_UNITS];
+    /// Texture anisotropy setting in use.
+    unsigned maxAnisotropy_[MAX_TEXTURE_UNITS];
+    /// Texture border colors in use.
+    Color borderColors_[MAX_TEXTURE_UNITS];
+    /// Device lost flag.
+    bool deviceLost_;
+    /// Frame query issued flag.
+    bool queryIssued_;
+    /// sRGB mode in use.
+    bool sRGBModes_[MAX_TEXTURE_UNITS];
+    /// sRGB write flag.
+    bool sRGBWrite_;
+    /// Color surfaces in use.
+    IDirect3DSurface9* colorSurfaces_[MAX_RENDERTARGETS];
+    /// Depth-stencil surface in use.
+    IDirect3DSurface9* depthStencilSurface_;
+    /// Blending enabled flag.
+    DWORD blendEnable_;
+    /// Source blend mode.
+    D3DBLEND srcBlend_;
+    /// Destination blend mode.
+    D3DBLEND destBlend_;
+    /// Blend operation.
+    D3DBLENDOP blendOp_;
+    /// Vertex declarations.
+    VertexDeclarationMap_D3D9 vertexDeclarations_;
+    /// Stream frequencies by vertex buffer.
+    unsigned streamFrequencies_[MAX_VERTEX_STREAMS];
+    /// Stream offsets by vertex buffer.
+    unsigned streamOffsets_[MAX_VERTEX_STREAMS];
+    /// Vertex declaration in use.
+    VertexDeclaration_D3D9* vertexDeclaration_;
+    /// Shader programs.
+    ShaderProgramMap_D3D9 shaderPrograms_;
+    /// Shader program in use.
+    ShaderProgram_D3D9* shaderProgram_;
+
+};
+
+}

+ 302 - 302
Source/Urho3D/Graphics/Direct3D9/D3D9IndexBuffer.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9IndexBuffer.cpp

@@ -1,302 +1,302 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Core/Context.h"
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/IndexBuffer.h"
-#include "../../IO/Log.h"
-#include "D3D9GraphicsImpl.h"
-
-#include "../../DebugNew.h"
-
-namespace Urho3D
-{
-
-void IndexBuffer::OnDeviceLost_D3D9()
-{
-    // Dynamic buffers are in the default pool and need to be released on device loss
-    if (dynamic_)
-        Release_D3D9();
-}
-
-void IndexBuffer::OnDeviceReset_D3D9()
-{
-    // Dynamic buffers are in the default pool and need to be recreated after device reset
-    if (dynamic_ || !object_.ptr_)
-    {
-        Create_D3D9();
-        dataLost_ = !UpdateToGPU_D3D9();
-    }
-    else if (dataPending_)
-        dataLost_ = !UpdateToGPU_D3D9();
-
-    dataPending_ = false;
-}
-
-void IndexBuffer::Release_D3D9()
-{
-    Unlock_D3D9();
-
-    if (graphics_ && graphics_->GetIndexBuffer() == this)
-        graphics_->SetIndexBuffer(nullptr);
-
-    URHO3D_SAFE_RELEASE(object_.ptr_);
-}
-
-bool IndexBuffer::SetData_D3D9(const void* data)
-{
-    if (!data)
-    {
-        URHO3D_LOGERROR("Null pointer for index buffer data");
-        return false;
-    }
-
-    if (!indexSize_)
-    {
-        URHO3D_LOGERROR("Index size not defined, can not set index buffer data");
-        return false;
-    }
-
-    if (shadowData_ && data != shadowData_.Get())
-        memcpy(shadowData_.Get(), data, indexCount_ * indexSize_);
-
-    if (object_.ptr_)
-    {
-        if (graphics_->IsDeviceLost())
-        {
-            URHO3D_LOGWARNING("Index buffer data assignment while device is lost");
-            dataPending_ = true;
-            return true;
-        }
-
-        void* hwData = MapBuffer_D3D9(0, indexCount_, true);
-        if (hwData)
-        {
-            memcpy(hwData, data, indexCount_ * indexSize_);
-            UnmapBuffer();
-        }
-        else
-            return false;
-    }
-
-    dataLost_ = false;
-    return true;
-}
-
-bool IndexBuffer::SetDataRange_D3D9(const void* data, unsigned start, unsigned count, bool discard)
-{
-    if (start == 0 && count == indexCount_)
-        return SetData_D3D9(data);
-
-    if (!data)
-    {
-        URHO3D_LOGERROR("Null pointer for index buffer data");
-        return false;
-    }
-
-    if (!indexSize_)
-    {
-        URHO3D_LOGERROR("Index size not defined, can not set index buffer data");
-        return false;
-    }
-
-    if (start + count > indexCount_)
-    {
-        URHO3D_LOGERROR("Illegal range for setting new index buffer data");
-        return false;
-    }
-
-    if (!count)
-        return true;
-
-    if (shadowData_ && shadowData_.Get() + start * indexSize_ != data)
-        memcpy(shadowData_.Get() + start * indexSize_, data, count * indexSize_);
-
-    if (object_.ptr_)
-    {
-        if (graphics_->IsDeviceLost())
-        {
-            URHO3D_LOGWARNING("Index buffer data assignment while device is lost");
-            dataPending_ = true;
-            return true;
-        }
-
-        void* hwData = MapBuffer_D3D9(start, count, discard);
-        if (hwData)
-        {
-            memcpy(hwData, data, count * indexSize_);
-            UnmapBuffer();
-        }
-        else
-            return false;
-    }
-
-    return true;
-}
-
-void* IndexBuffer::Lock_D3D9(unsigned start, unsigned count, bool discard)
-{
-    if (lockState_ != LOCK_NONE)
-    {
-        URHO3D_LOGERROR("Index buffer already locked");
-        return nullptr;
-    }
-
-    if (!indexSize_)
-    {
-        URHO3D_LOGERROR("Index size not defined, can not lock index buffer");
-        return nullptr;
-    }
-
-    if (start + count > indexCount_)
-    {
-        URHO3D_LOGERROR("Illegal range for locking index buffer");
-        return nullptr;
-    }
-
-    if (!count)
-        return nullptr;
-
-    lockStart_ = start;
-    lockCount_ = count;
-
-    // Because shadow data must be kept in sync, can only lock hardware buffer if not shadowed
-    if (object_.ptr_ && !shadowData_ && !graphics_->IsDeviceLost())
-        return MapBuffer_D3D9(start, count, discard);
-    else if (shadowData_)
-    {
-        lockState_ = LOCK_SHADOW;
-        return shadowData_.Get() + start * indexSize_;
-    }
-    else if (graphics_)
-    {
-        lockState_ = LOCK_SCRATCH;
-        lockScratchData_ = graphics_->ReserveScratchBuffer(count * indexSize_);
-        return lockScratchData_;
-    }
-    else
-        return nullptr;
-}
-
-void IndexBuffer::Unlock_D3D9()
-{
-    switch (lockState_)
-    {
-    case LOCK_HARDWARE:
-        UnmapBuffer();
-        break;
-
-    case LOCK_SHADOW:
-        SetDataRange_D3D9(shadowData_.Get() + lockStart_ * indexSize_, lockStart_, lockCount_);
-        lockState_ = LOCK_NONE;
-        break;
-
-    case LOCK_SCRATCH:
-        SetDataRange_D3D9(lockScratchData_, lockStart_, lockCount_);
-        if (graphics_)
-            graphics_->FreeScratchBuffer(lockScratchData_);
-        lockScratchData_ = nullptr;
-        lockState_ = LOCK_NONE;
-        break;
-
-    default: break;
-    }
-}
-
-bool IndexBuffer::Create_D3D9()
-{
-    Release_D3D9();
-
-    if (!indexCount_)
-        return true;
-
-    if (graphics_)
-    {
-        if (graphics_->IsDeviceLost())
-        {
-            URHO3D_LOGWARNING("Index buffer creation while device is lost");
-            return true;
-        }
-
-        unsigned pool = dynamic_ ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
-        unsigned d3dUsage = dynamic_ ? D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY : 0;
-
-        IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
-        HRESULT hr = device->CreateIndexBuffer(
-            indexCount_ * indexSize_,
-            d3dUsage,
-            indexSize_ == sizeof(unsigned) ? D3DFMT_INDEX32 : D3DFMT_INDEX16,
-            (D3DPOOL)pool,
-            (IDirect3DIndexBuffer9**)&object_,
-            nullptr);
-        if (FAILED(hr))
-        {
-            URHO3D_SAFE_RELEASE(object_.ptr_)
-            URHO3D_LOGD3DERROR("Could not create index buffer", hr);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-bool IndexBuffer::UpdateToGPU_D3D9()
-{
-    if (object_.ptr_ && shadowData_)
-        return SetData_D3D9(shadowData_.Get());
-    else
-        return false;
-}
-
-void* IndexBuffer::MapBuffer_D3D9(unsigned start, unsigned count, bool discard)
-{
-    void* hwData = nullptr;
-
-    if (object_.ptr_)
-    {
-        DWORD flags = 0;
-
-        if (discard && dynamic_)
-            flags = D3DLOCK_DISCARD;
-
-        HRESULT hr = ((IDirect3DIndexBuffer9*)object_.ptr_)->Lock(start * indexSize_, count * indexSize_, &hwData, flags);
-        if (FAILED(hr))
-            URHO3D_LOGD3DERROR("Could not lock index buffer", hr);
-        else
-            lockState_ = LOCK_HARDWARE;
-    }
-
-    return hwData;
-}
-
-void IndexBuffer::UnmapBuffer_D3D9()
-{
-    if (object_.ptr_ && lockState_ == LOCK_HARDWARE)
-    {
-        ((IDirect3DIndexBuffer9*)object_.ptr_)->Unlock();
-        lockState_ = LOCK_NONE;
-    }
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Core/Context.h"
+#include "../../Graphics/Graphics.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9GraphicsImpl.h"
+#include "../../GraphicsAPI/IndexBuffer.h"
+#include "../../IO/Log.h"
+
+#include "../../DebugNew.h"
+
+namespace Urho3D
+{
+
+void IndexBuffer::OnDeviceLost_D3D9()
+{
+    // Dynamic buffers are in the default pool and need to be released on device loss
+    if (dynamic_)
+        Release_D3D9();
+}
+
+void IndexBuffer::OnDeviceReset_D3D9()
+{
+    // Dynamic buffers are in the default pool and need to be recreated after device reset
+    if (dynamic_ || !object_.ptr_)
+    {
+        Create_D3D9();
+        dataLost_ = !UpdateToGPU_D3D9();
+    }
+    else if (dataPending_)
+        dataLost_ = !UpdateToGPU_D3D9();
+
+    dataPending_ = false;
+}
+
+void IndexBuffer::Release_D3D9()
+{
+    Unlock_D3D9();
+
+    if (graphics_ && graphics_->GetIndexBuffer() == this)
+        graphics_->SetIndexBuffer(nullptr);
+
+    URHO3D_SAFE_RELEASE(object_.ptr_);
+}
+
+bool IndexBuffer::SetData_D3D9(const void* data)
+{
+    if (!data)
+    {
+        URHO3D_LOGERROR("Null pointer for index buffer data");
+        return false;
+    }
+
+    if (!indexSize_)
+    {
+        URHO3D_LOGERROR("Index size not defined, can not set index buffer data");
+        return false;
+    }
+
+    if (shadowData_ && data != shadowData_.Get())
+        memcpy(shadowData_.Get(), data, indexCount_ * indexSize_);
+
+    if (object_.ptr_)
+    {
+        if (graphics_->IsDeviceLost())
+        {
+            URHO3D_LOGWARNING("Index buffer data assignment while device is lost");
+            dataPending_ = true;
+            return true;
+        }
+
+        void* hwData = MapBuffer_D3D9(0, indexCount_, true);
+        if (hwData)
+        {
+            memcpy(hwData, data, indexCount_ * indexSize_);
+            UnmapBuffer();
+        }
+        else
+            return false;
+    }
+
+    dataLost_ = false;
+    return true;
+}
+
+bool IndexBuffer::SetDataRange_D3D9(const void* data, unsigned start, unsigned count, bool discard)
+{
+    if (start == 0 && count == indexCount_)
+        return SetData_D3D9(data);
+
+    if (!data)
+    {
+        URHO3D_LOGERROR("Null pointer for index buffer data");
+        return false;
+    }
+
+    if (!indexSize_)
+    {
+        URHO3D_LOGERROR("Index size not defined, can not set index buffer data");
+        return false;
+    }
+
+    if (start + count > indexCount_)
+    {
+        URHO3D_LOGERROR("Illegal range for setting new index buffer data");
+        return false;
+    }
+
+    if (!count)
+        return true;
+
+    if (shadowData_ && shadowData_.Get() + start * indexSize_ != data)
+        memcpy(shadowData_.Get() + start * indexSize_, data, count * indexSize_);
+
+    if (object_.ptr_)
+    {
+        if (graphics_->IsDeviceLost())
+        {
+            URHO3D_LOGWARNING("Index buffer data assignment while device is lost");
+            dataPending_ = true;
+            return true;
+        }
+
+        void* hwData = MapBuffer_D3D9(start, count, discard);
+        if (hwData)
+        {
+            memcpy(hwData, data, count * indexSize_);
+            UnmapBuffer();
+        }
+        else
+            return false;
+    }
+
+    return true;
+}
+
+void* IndexBuffer::Lock_D3D9(unsigned start, unsigned count, bool discard)
+{
+    if (lockState_ != LOCK_NONE)
+    {
+        URHO3D_LOGERROR("Index buffer already locked");
+        return nullptr;
+    }
+
+    if (!indexSize_)
+    {
+        URHO3D_LOGERROR("Index size not defined, can not lock index buffer");
+        return nullptr;
+    }
+
+    if (start + count > indexCount_)
+    {
+        URHO3D_LOGERROR("Illegal range for locking index buffer");
+        return nullptr;
+    }
+
+    if (!count)
+        return nullptr;
+
+    lockStart_ = start;
+    lockCount_ = count;
+
+    // Because shadow data must be kept in sync, can only lock hardware buffer if not shadowed
+    if (object_.ptr_ && !shadowData_ && !graphics_->IsDeviceLost())
+        return MapBuffer_D3D9(start, count, discard);
+    else if (shadowData_)
+    {
+        lockState_ = LOCK_SHADOW;
+        return shadowData_.Get() + start * indexSize_;
+    }
+    else if (graphics_)
+    {
+        lockState_ = LOCK_SCRATCH;
+        lockScratchData_ = graphics_->ReserveScratchBuffer(count * indexSize_);
+        return lockScratchData_;
+    }
+    else
+        return nullptr;
+}
+
+void IndexBuffer::Unlock_D3D9()
+{
+    switch (lockState_)
+    {
+    case LOCK_HARDWARE:
+        UnmapBuffer();
+        break;
+
+    case LOCK_SHADOW:
+        SetDataRange_D3D9(shadowData_.Get() + lockStart_ * indexSize_, lockStart_, lockCount_);
+        lockState_ = LOCK_NONE;
+        break;
+
+    case LOCK_SCRATCH:
+        SetDataRange_D3D9(lockScratchData_, lockStart_, lockCount_);
+        if (graphics_)
+            graphics_->FreeScratchBuffer(lockScratchData_);
+        lockScratchData_ = nullptr;
+        lockState_ = LOCK_NONE;
+        break;
+
+    default: break;
+    }
+}
+
+bool IndexBuffer::Create_D3D9()
+{
+    Release_D3D9();
+
+    if (!indexCount_)
+        return true;
+
+    if (graphics_)
+    {
+        if (graphics_->IsDeviceLost())
+        {
+            URHO3D_LOGWARNING("Index buffer creation while device is lost");
+            return true;
+        }
+
+        unsigned pool = dynamic_ ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
+        unsigned d3dUsage = dynamic_ ? D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY : 0;
+
+        IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
+        HRESULT hr = device->CreateIndexBuffer(
+            indexCount_ * indexSize_,
+            d3dUsage,
+            indexSize_ == sizeof(unsigned) ? D3DFMT_INDEX32 : D3DFMT_INDEX16,
+            (D3DPOOL)pool,
+            (IDirect3DIndexBuffer9**)&object_,
+            nullptr);
+        if (FAILED(hr))
+        {
+            URHO3D_SAFE_RELEASE(object_.ptr_)
+            URHO3D_LOGD3DERROR("Could not create index buffer", hr);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool IndexBuffer::UpdateToGPU_D3D9()
+{
+    if (object_.ptr_ && shadowData_)
+        return SetData_D3D9(shadowData_.Get());
+    else
+        return false;
+}
+
+void* IndexBuffer::MapBuffer_D3D9(unsigned start, unsigned count, bool discard)
+{
+    void* hwData = nullptr;
+
+    if (object_.ptr_)
+    {
+        DWORD flags = 0;
+
+        if (discard && dynamic_)
+            flags = D3DLOCK_DISCARD;
+
+        HRESULT hr = ((IDirect3DIndexBuffer9*)object_.ptr_)->Lock(start * indexSize_, count * indexSize_, &hwData, flags);
+        if (FAILED(hr))
+            URHO3D_LOGD3DERROR("Could not lock index buffer", hr);
+        else
+            lockState_ = LOCK_HARDWARE;
+    }
+
+    return hwData;
+}
+
+void IndexBuffer::UnmapBuffer_D3D9()
+{
+    if (object_.ptr_ && lockState_ == LOCK_HARDWARE)
+    {
+        ((IDirect3DIndexBuffer9*)object_.ptr_)->Unlock();
+        lockState_ = LOCK_NONE;
+    }
+}
+
+}

+ 72 - 72
Source/Urho3D/Graphics/Direct3D9/D3D9RenderSurface.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9RenderSurface.cpp

@@ -1,72 +1,72 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Graphics/Camera.h"
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/GraphicsImpl.h"
-#include "../../Graphics/Renderer.h"
-#include "../../Graphics/RenderSurface.h"
-#include "../../Graphics/Texture.h"
-
-#include "../../DebugNew.h"
-
-namespace Urho3D
-{
-
-void RenderSurface::Constructor_D3D9(Texture* parentTexture)
-{
-    parentTexture_ = parentTexture;
-    surface_ = nullptr;
-}
-
-void RenderSurface::Release_D3D9()
-{
-    Graphics* graphics = parentTexture_->GetGraphics();
-    if (graphics)
-    {
-        for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
-        {
-            if (graphics->GetRenderTarget(i) == this)
-                graphics->ResetRenderTarget(i);
-        }
-
-        if (graphics->GetDepthStencil() == this)
-            graphics->ResetDepthStencil();
-    }
-
-    URHO3D_SAFE_RELEASE(surface_);
-}
-
-bool RenderSurface::CreateRenderBuffer_D3D9(unsigned width, unsigned height, unsigned format, int multiSample)
-{
-    // Not used on Direct3D
-    return false;
-}
-
-void RenderSurface::OnDeviceLost_D3D9()
-{
-    // No-op on Direct3D
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Graphics/Camera.h"
+#include "../../Graphics/Graphics.h"
+#include "../../Graphics/Renderer.h"
+#include "../../GraphicsAPI/GraphicsImpl.h"
+#include "../../GraphicsAPI/RenderSurface.h"
+#include "../../GraphicsAPI/Texture.h"
+
+#include "../../DebugNew.h"
+
+namespace Urho3D
+{
+
+void RenderSurface::Constructor_D3D9(Texture* parentTexture)
+{
+    parentTexture_ = parentTexture;
+    surface_ = nullptr;
+}
+
+void RenderSurface::Release_D3D9()
+{
+    Graphics* graphics = parentTexture_->GetGraphics();
+    if (graphics)
+    {
+        for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
+        {
+            if (graphics->GetRenderTarget(i) == this)
+                graphics->ResetRenderTarget(i);
+        }
+
+        if (graphics->GetDepthStencil() == this)
+            graphics->ResetDepthStencil();
+    }
+
+    URHO3D_SAFE_RELEASE(surface_);
+}
+
+bool RenderSurface::CreateRenderBuffer_D3D9(unsigned width, unsigned height, unsigned format, int multiSample)
+{
+    // Not used on Direct3D
+    return false;
+}
+
+void RenderSurface::OnDeviceLost_D3D9()
+{
+    // No-op on Direct3D
+}
+
+}

+ 1 - 1
Source/Urho3D/Graphics/Direct3D9/D3D9ShaderProgram.h → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9ShaderProgram.h

@@ -23,7 +23,7 @@
 #pragma once
 
 #include "../../Container/HashMap.h"
-#include "../../Graphics/ShaderVariation.h"
+#include "../../GraphicsAPI/ShaderVariation.h"
 
 namespace Urho3D
 {

+ 417 - 417
Source/Urho3D/Graphics/Direct3D9/D3D9ShaderVariation.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9ShaderVariation.cpp

@@ -1,417 +1,417 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/Shader.h"
-#include "../../Graphics/ShaderVariation.h"
-#include "../../IO/File.h"
-#include "../../IO/FileSystem.h"
-#include "../../IO/Log.h"
-#include "../../Resource/ResourceCache.h"
-#include "D3D9GraphicsImpl.h"
-
-#include <d3dcompiler.h>
-#include <MojoShader/mojoshader.h>
-
-#include "../../DebugNew.h"
-
-namespace Urho3D
-{
-
-static void CopyStrippedCode(PODVector<unsigned char>& byteCode, unsigned char* bufData, unsigned bufSize)
-{
-    unsigned const D3DSIO_COMMENT = 0xFFFE;
-    unsigned* srcWords = (unsigned*)bufData;
-    unsigned srcWordSize = bufSize >> 2;
-    byteCode.Clear();
-
-    for (unsigned i = 0; i < srcWordSize; ++i)
-    {
-        unsigned opcode = srcWords[i] & 0xffff;
-        // unsigned paramLength = (srcWords[i] & 0x0f000000) >> 24;
-        unsigned commentLength = srcWords[i] >> 16;
-
-        // For now, skip comment only at fixed position to prevent false positives
-        if (i == 1 && opcode == D3DSIO_COMMENT)
-        {
-            // Skip the comment
-            i += commentLength;
-        }
-        else
-        {
-            // Not a comment, copy the data
-            unsigned destPos = byteCode.Size();
-            byteCode.Resize(destPos + sizeof(unsigned));
-            unsigned* dest = (unsigned*)&byteCode[destPos];
-            *dest = srcWords[i];
-        }
-    }
-}
-
-void ShaderVariation::OnDeviceLost_D3D9()
-{
-    // No-op on Direct3D9, shaders are preserved through a device loss & reset
-}
-
-bool ShaderVariation::Create_D3D9()
-{
-    Release_D3D9();
-
-    if (!graphics_)
-        return false;
-
-    if (!owner_)
-    {
-        compilerOutput_ = "Owner shader has expired";
-        return false;
-    }
-
-    // Check for up-to-date bytecode on disk
-    String path, name, extension;
-    SplitPath(owner_->GetName(), path, name, extension);
-    extension = type_ == VS ? ".vs3" : ".ps3";
-
-    String binaryShaderName = graphics_->GetShaderCacheDir() + name + "_" + StringHash(defines_).ToString() + extension;
-
-    if (!LoadByteCode_D3D9(binaryShaderName))
-    {
-        // Compile shader if don't have valid bytecode
-        if (!Compile_D3D9())
-            return false;
-        // Save the bytecode after successful compile, but not if the source is from a package
-        if (owner_->GetTimeStamp())
-            SaveByteCode_D3D9(binaryShaderName);
-    }
-
-    // Then create shader from the bytecode
-    IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
-    if (type_ == VS)
-    {
-        HRESULT hr = device->CreateVertexShader(
-            (const DWORD*)&byteCode_[0],
-            (IDirect3DVertexShader9**)&object_.ptr_);
-        if (FAILED(hr))
-        {
-            URHO3D_SAFE_RELEASE(object_.ptr_);
-            compilerOutput_ = "Could not create vertex shader (HRESULT " + ToStringHex((unsigned)hr) + ")";
-        }
-    }
-    else
-    {
-        HRESULT hr = device->CreatePixelShader(
-            (const DWORD*)&byteCode_[0],
-            (IDirect3DPixelShader9**)&object_.ptr_);
-        if (FAILED(hr))
-        {
-            URHO3D_SAFE_RELEASE(object_.ptr_);
-            compilerOutput_ = "Could not create pixel shader (HRESULT " + ToStringHex((unsigned)hr) + ")";
-        }
-    }
-
-    // The bytecode is not needed on Direct3D9 after creation, so delete it to save memory
-    byteCode_.Clear();
-    byteCode_.Reserve(0);
-
-    return object_.ptr_ != nullptr;
-}
-
-void ShaderVariation::Release_D3D9()
-{
-    if (object_.ptr_ && graphics_)
-    {
-        graphics_->CleanupShaderPrograms_D3D9(this);
-
-        if (type_ == VS)
-        {
-            if (graphics_->GetVertexShader() == this)
-                graphics_->SetShaders(nullptr, nullptr);
-        }
-        else
-        {
-            if (graphics_->GetPixelShader() == this)
-                graphics_->SetShaders(nullptr, nullptr);
-        }
-    }
-
-    URHO3D_SAFE_RELEASE(object_.ptr_);
-
-    compilerOutput_.Clear();
-
-    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-        useTextureUnits_[i] = false;
-    parameters_.Clear();
-}
-
-void ShaderVariation::SetDefines_D3D9(const String& defines)
-{
-    defines_ = defines;
-}
-
-bool ShaderVariation::LoadByteCode_D3D9(const String& binaryShaderName)
-{
-    ResourceCache* cache = owner_->GetSubsystem<ResourceCache>();
-    if (!cache->Exists(binaryShaderName))
-        return false;
-
-    FileSystem* fileSystem = owner_->GetSubsystem<FileSystem>();
-    unsigned sourceTimeStamp = owner_->GetTimeStamp();
-    // If source code is loaded from a package, its timestamp will be zero. Else check that binary is not older
-    // than source
-    if (sourceTimeStamp && fileSystem->GetLastModifiedTime(cache->GetResourceFileName(binaryShaderName)) < sourceTimeStamp)
-        return false;
-
-    SharedPtr<File> file = cache->GetFile(binaryShaderName);
-    if (!file || file->ReadFileID() != "USHD")
-    {
-        URHO3D_LOGERROR(binaryShaderName + " is not a valid shader bytecode file");
-        return false;
-    }
-
-    /// \todo Check that shader type and model match
-    /*unsigned short shaderType = */file->ReadUShort();
-    /*unsigned short shaderModel = */file->ReadUShort();
-
-    unsigned numParameters = file->ReadUInt();
-    for (unsigned i = 0; i < numParameters; ++i)
-    {
-        String name = file->ReadString();
-        unsigned reg = file->ReadUByte();
-        unsigned regCount = file->ReadUByte();
-
-        parameters_[StringHash(name)] = ShaderParameter{type_, name, reg, regCount};
-    }
-
-    unsigned numTextureUnits = file->ReadUInt();
-    for (unsigned i = 0; i < numTextureUnits; ++i)
-    {
-        /*String unitName = */file->ReadString();
-        unsigned reg = file->ReadUByte();
-
-        if (reg < MAX_TEXTURE_UNITS)
-            useTextureUnits_[reg] = true;
-    }
-
-    unsigned byteCodeSize = file->ReadUInt();
-    if (byteCodeSize)
-    {
-        byteCode_.Resize(byteCodeSize);
-        file->Read(&byteCode_[0], byteCodeSize);
-
-        if (type_ == VS)
-            URHO3D_LOGDEBUG("Loaded cached vertex shader " + GetFullName());
-        else
-            URHO3D_LOGDEBUG("Loaded cached pixel shader " + GetFullName());
-
-        return true;
-    }
-    else
-    {
-        URHO3D_LOGERROR(binaryShaderName + " has zero length bytecode");
-        return false;
-    }
-}
-
-bool ShaderVariation::Compile_D3D9()
-{
-    const String& sourceCode = owner_->GetSourceCode(type_);
-    Vector<String> defines = defines_.Split(' ');
-
-    // Set the entrypoint, profile and flags according to the shader being compiled
-    const char* entryPoint = nullptr;
-    const char* profile = nullptr;
-    unsigned flags = D3DCOMPILE_OPTIMIZATION_LEVEL3;
-
-    if (type_ == VS)
-    {
-        entryPoint = "VS";
-        defines.Push("COMPILEVS");
-        profile = "vs_3_0";
-    }
-    else
-    {
-        entryPoint = "PS";
-        defines.Push("COMPILEPS");
-        profile = "ps_3_0";
-        flags |= D3DCOMPILE_PREFER_FLOW_CONTROL;
-    }
-
-    defines.Push("MAXBONES=" + String(Graphics::GetMaxBones()));
-
-    // Collect defines into macros
-    Vector<String> defineValues;
-    PODVector<D3D_SHADER_MACRO> macros;
-
-    for (unsigned i = 0; i < defines.Size(); ++i)
-    {
-        unsigned equalsPos = defines[i].Find('=');
-        if (equalsPos != String::NPOS)
-        {
-            defineValues.Push(defines[i].Substring(equalsPos + 1));
-            defines[i].Resize(equalsPos);
-        }
-        else
-            defineValues.Push("1");
-    }
-    for (unsigned i = 0; i < defines.Size(); ++i)
-    {
-        D3D_SHADER_MACRO macro;
-        macro.Name = defines[i].CString();
-        macro.Definition = defineValues[i].CString();
-        macros.Push(macro);
-
-        // In debug mode, check that all defines are referenced by the shader code
-#ifdef _DEBUG
-        if (sourceCode.Find(defines[i]) == String::NPOS)
-            URHO3D_LOGWARNING("Shader " + GetFullName() + " does not use the define " + defines[i]);
-#endif
-    }
-
-    D3D_SHADER_MACRO endMacro;
-    endMacro.Name = nullptr;
-    endMacro.Definition = nullptr;
-    macros.Push(endMacro);
-
-    // Compile using D3DCompile
-    ID3DBlob* shaderCode = nullptr;
-    ID3DBlob* errorMsgs = nullptr;
-
-    HRESULT hr = D3DCompile(sourceCode.CString(), sourceCode.Length(), owner_->GetName().CString(), &macros.Front(), nullptr,
-        entryPoint, profile, flags, 0, &shaderCode, &errorMsgs);
-    if (FAILED(hr))
-    {
-        // Do not include end zero unnecessarily
-        compilerOutput_ = String((const char*)errorMsgs->GetBufferPointer(), (unsigned)errorMsgs->GetBufferSize() - 1);
-    }
-    else
-    {
-        if (type_ == VS)
-            URHO3D_LOGDEBUG("Compiled vertex shader " + GetFullName());
-        else
-            URHO3D_LOGDEBUG("Compiled pixel shader " + GetFullName());
-
-        // Inspect the produced bytecode using MojoShader, then strip and store it
-        unsigned char* bufData = (unsigned char*)shaderCode->GetBufferPointer();
-        unsigned bufSize = (unsigned)shaderCode->GetBufferSize();
-        ParseParameters_D3D9(bufData, bufSize);
-        CopyStrippedCode(byteCode_, bufData, bufSize);
-    }
-
-    URHO3D_SAFE_RELEASE(shaderCode);
-    URHO3D_SAFE_RELEASE(errorMsgs);
-
-    return !byteCode_.Empty();
-}
-
-void ShaderVariation::ParseParameters_D3D9(unsigned char* bufData, unsigned bufSize)
-{
-    MOJOSHADER_parseData const* parseData = MOJOSHADER_parse("bytecode", bufData, bufSize, nullptr, 0, nullptr, 0, nullptr, nullptr, nullptr);
-
-    for (int i = 0; i < parseData->symbol_count; i++)
-    {
-        MOJOSHADER_symbol const& symbol = parseData->symbols[i];
-
-        String name(symbol.name);
-        unsigned reg = symbol.register_index;
-        unsigned regCount = symbol.register_count;
-
-        // Check if the parameter is a constant or a texture sampler
-        bool isSampler = (name[0] == 's');
-        name = name.Substring(1);
-
-        if (isSampler)
-        {
-            // Skip if it's a G-buffer sampler, which are aliases for the standard texture units
-            if (reg < MAX_TEXTURE_UNITS)
-            {
-                if (name != "AlbedoBuffer" && name != "NormalBuffer" && name != "DepthBuffer" && name != "LightBuffer")
-                    useTextureUnits_[reg] = true;
-            }
-        }
-        else
-        {
-            parameters_[StringHash(name)] = ShaderParameter{type_, name, reg, regCount};
-        }
-    }
-
-    MOJOSHADER_freeParseData(parseData);
-}
-
-void ShaderVariation::SaveByteCode_D3D9(const String& binaryShaderName)
-{
-    ResourceCache* cache = owner_->GetSubsystem<ResourceCache>();
-    FileSystem* fileSystem = owner_->GetSubsystem<FileSystem>();
-
-    // Filename may or may not be inside the resource system
-    String fullName = binaryShaderName;
-    if (!IsAbsolutePath(fullName))
-    {
-        // If not absolute, use the resource dir of the shader
-        String shaderFileName = cache->GetResourceFileName(owner_->GetName());
-        if (shaderFileName.Empty())
-            return;
-        fullName = shaderFileName.Substring(0, shaderFileName.Find(owner_->GetName())) + binaryShaderName;
-    }
-    String path = GetPath(fullName);
-    if (!fileSystem->DirExists(path))
-        fileSystem->CreateDir(path);
-
-    SharedPtr<File> file(new File(owner_->GetContext(), fullName, FILE_WRITE));
-    if (!file->IsOpen())
-        return;
-
-    file->WriteFileID("USHD");
-    file->WriteShort((unsigned short)type_);
-    file->WriteShort(3);
-
-    file->WriteUInt(parameters_.Size());
-    for (HashMap<StringHash, ShaderParameter>::ConstIterator i = parameters_.Begin(); i != parameters_.End(); ++i)
-    {
-        file->WriteString(i->second_.name_);
-        file->WriteUByte((unsigned char)i->second_.register_);
-        file->WriteUByte((unsigned char)i->second_.regCount_);
-    }
-
-    unsigned usedTextureUnits = 0;
-    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-    {
-        if (useTextureUnits_[i])
-            ++usedTextureUnits;
-    }
-    file->WriteUInt(usedTextureUnits);
-    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-    {
-        if (useTextureUnits_[i])
-        {
-            file->WriteString(graphics_->GetTextureUnitName((TextureUnit)i));
-            file->WriteUByte((unsigned char)i);
-        }
-    }
-
-    unsigned dataSize = byteCode_.Size();
-    file->WriteUInt(dataSize);
-    if (dataSize)
-        file->Write(&byteCode_[0], dataSize);
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Graphics/Graphics.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9GraphicsImpl.h"
+#include "../../GraphicsAPI/Shader.h"
+#include "../../GraphicsAPI/ShaderVariation.h"
+#include "../../IO/File.h"
+#include "../../IO/FileSystem.h"
+#include "../../IO/Log.h"
+#include "../../Resource/ResourceCache.h"
+
+#include <d3dcompiler.h>
+#include <MojoShader/mojoshader.h>
+
+#include "../../DebugNew.h"
+
+namespace Urho3D
+{
+
+static void CopyStrippedCode(PODVector<unsigned char>& byteCode, unsigned char* bufData, unsigned bufSize)
+{
+    unsigned const D3DSIO_COMMENT = 0xFFFE;
+    unsigned* srcWords = (unsigned*)bufData;
+    unsigned srcWordSize = bufSize >> 2;
+    byteCode.Clear();
+
+    for (unsigned i = 0; i < srcWordSize; ++i)
+    {
+        unsigned opcode = srcWords[i] & 0xffff;
+        // unsigned paramLength = (srcWords[i] & 0x0f000000) >> 24;
+        unsigned commentLength = srcWords[i] >> 16;
+
+        // For now, skip comment only at fixed position to prevent false positives
+        if (i == 1 && opcode == D3DSIO_COMMENT)
+        {
+            // Skip the comment
+            i += commentLength;
+        }
+        else
+        {
+            // Not a comment, copy the data
+            unsigned destPos = byteCode.Size();
+            byteCode.Resize(destPos + sizeof(unsigned));
+            unsigned* dest = (unsigned*)&byteCode[destPos];
+            *dest = srcWords[i];
+        }
+    }
+}
+
+void ShaderVariation::OnDeviceLost_D3D9()
+{
+    // No-op on Direct3D9, shaders are preserved through a device loss & reset
+}
+
+bool ShaderVariation::Create_D3D9()
+{
+    Release_D3D9();
+
+    if (!graphics_)
+        return false;
+
+    if (!owner_)
+    {
+        compilerOutput_ = "Owner shader has expired";
+        return false;
+    }
+
+    // Check for up-to-date bytecode on disk
+    String path, name, extension;
+    SplitPath(owner_->GetName(), path, name, extension);
+    extension = type_ == VS ? ".vs3" : ".ps3";
+
+    String binaryShaderName = graphics_->GetShaderCacheDir() + name + "_" + StringHash(defines_).ToString() + extension;
+
+    if (!LoadByteCode_D3D9(binaryShaderName))
+    {
+        // Compile shader if don't have valid bytecode
+        if (!Compile_D3D9())
+            return false;
+        // Save the bytecode after successful compile, but not if the source is from a package
+        if (owner_->GetTimeStamp())
+            SaveByteCode_D3D9(binaryShaderName);
+    }
+
+    // Then create shader from the bytecode
+    IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
+    if (type_ == VS)
+    {
+        HRESULT hr = device->CreateVertexShader(
+            (const DWORD*)&byteCode_[0],
+            (IDirect3DVertexShader9**)&object_.ptr_);
+        if (FAILED(hr))
+        {
+            URHO3D_SAFE_RELEASE(object_.ptr_);
+            compilerOutput_ = "Could not create vertex shader (HRESULT " + ToStringHex((unsigned)hr) + ")";
+        }
+    }
+    else
+    {
+        HRESULT hr = device->CreatePixelShader(
+            (const DWORD*)&byteCode_[0],
+            (IDirect3DPixelShader9**)&object_.ptr_);
+        if (FAILED(hr))
+        {
+            URHO3D_SAFE_RELEASE(object_.ptr_);
+            compilerOutput_ = "Could not create pixel shader (HRESULT " + ToStringHex((unsigned)hr) + ")";
+        }
+    }
+
+    // The bytecode is not needed on Direct3D9 after creation, so delete it to save memory
+    byteCode_.Clear();
+    byteCode_.Reserve(0);
+
+    return object_.ptr_ != nullptr;
+}
+
+void ShaderVariation::Release_D3D9()
+{
+    if (object_.ptr_ && graphics_)
+    {
+        graphics_->CleanupShaderPrograms_D3D9(this);
+
+        if (type_ == VS)
+        {
+            if (graphics_->GetVertexShader() == this)
+                graphics_->SetShaders(nullptr, nullptr);
+        }
+        else
+        {
+            if (graphics_->GetPixelShader() == this)
+                graphics_->SetShaders(nullptr, nullptr);
+        }
+    }
+
+    URHO3D_SAFE_RELEASE(object_.ptr_);
+
+    compilerOutput_.Clear();
+
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+        useTextureUnits_[i] = false;
+    parameters_.Clear();
+}
+
+void ShaderVariation::SetDefines_D3D9(const String& defines)
+{
+    defines_ = defines;
+}
+
+bool ShaderVariation::LoadByteCode_D3D9(const String& binaryShaderName)
+{
+    ResourceCache* cache = owner_->GetSubsystem<ResourceCache>();
+    if (!cache->Exists(binaryShaderName))
+        return false;
+
+    FileSystem* fileSystem = owner_->GetSubsystem<FileSystem>();
+    unsigned sourceTimeStamp = owner_->GetTimeStamp();
+    // If source code is loaded from a package, its timestamp will be zero. Else check that binary is not older
+    // than source
+    if (sourceTimeStamp && fileSystem->GetLastModifiedTime(cache->GetResourceFileName(binaryShaderName)) < sourceTimeStamp)
+        return false;
+
+    SharedPtr<File> file = cache->GetFile(binaryShaderName);
+    if (!file || file->ReadFileID() != "USHD")
+    {
+        URHO3D_LOGERROR(binaryShaderName + " is not a valid shader bytecode file");
+        return false;
+    }
+
+    /// \todo Check that shader type and model match
+    /*unsigned short shaderType = */file->ReadUShort();
+    /*unsigned short shaderModel = */file->ReadUShort();
+
+    unsigned numParameters = file->ReadUInt();
+    for (unsigned i = 0; i < numParameters; ++i)
+    {
+        String name = file->ReadString();
+        unsigned reg = file->ReadUByte();
+        unsigned regCount = file->ReadUByte();
+
+        parameters_[StringHash(name)] = ShaderParameter{type_, name, reg, regCount};
+    }
+
+    unsigned numTextureUnits = file->ReadUInt();
+    for (unsigned i = 0; i < numTextureUnits; ++i)
+    {
+        /*String unitName = */file->ReadString();
+        unsigned reg = file->ReadUByte();
+
+        if (reg < MAX_TEXTURE_UNITS)
+            useTextureUnits_[reg] = true;
+    }
+
+    unsigned byteCodeSize = file->ReadUInt();
+    if (byteCodeSize)
+    {
+        byteCode_.Resize(byteCodeSize);
+        file->Read(&byteCode_[0], byteCodeSize);
+
+        if (type_ == VS)
+            URHO3D_LOGDEBUG("Loaded cached vertex shader " + GetFullName());
+        else
+            URHO3D_LOGDEBUG("Loaded cached pixel shader " + GetFullName());
+
+        return true;
+    }
+    else
+    {
+        URHO3D_LOGERROR(binaryShaderName + " has zero length bytecode");
+        return false;
+    }
+}
+
+bool ShaderVariation::Compile_D3D9()
+{
+    const String& sourceCode = owner_->GetSourceCode(type_);
+    Vector<String> defines = defines_.Split(' ');
+
+    // Set the entrypoint, profile and flags according to the shader being compiled
+    const char* entryPoint = nullptr;
+    const char* profile = nullptr;
+    unsigned flags = D3DCOMPILE_OPTIMIZATION_LEVEL3;
+
+    if (type_ == VS)
+    {
+        entryPoint = "VS";
+        defines.Push("COMPILEVS");
+        profile = "vs_3_0";
+    }
+    else
+    {
+        entryPoint = "PS";
+        defines.Push("COMPILEPS");
+        profile = "ps_3_0";
+        flags |= D3DCOMPILE_PREFER_FLOW_CONTROL;
+    }
+
+    defines.Push("MAXBONES=" + String(Graphics::GetMaxBones()));
+
+    // Collect defines into macros
+    Vector<String> defineValues;
+    PODVector<D3D_SHADER_MACRO> macros;
+
+    for (unsigned i = 0; i < defines.Size(); ++i)
+    {
+        unsigned equalsPos = defines[i].Find('=');
+        if (equalsPos != String::NPOS)
+        {
+            defineValues.Push(defines[i].Substring(equalsPos + 1));
+            defines[i].Resize(equalsPos);
+        }
+        else
+            defineValues.Push("1");
+    }
+    for (unsigned i = 0; i < defines.Size(); ++i)
+    {
+        D3D_SHADER_MACRO macro;
+        macro.Name = defines[i].CString();
+        macro.Definition = defineValues[i].CString();
+        macros.Push(macro);
+
+        // In debug mode, check that all defines are referenced by the shader code
+#ifdef _DEBUG
+        if (sourceCode.Find(defines[i]) == String::NPOS)
+            URHO3D_LOGWARNING("Shader " + GetFullName() + " does not use the define " + defines[i]);
+#endif
+    }
+
+    D3D_SHADER_MACRO endMacro;
+    endMacro.Name = nullptr;
+    endMacro.Definition = nullptr;
+    macros.Push(endMacro);
+
+    // Compile using D3DCompile
+    ID3DBlob* shaderCode = nullptr;
+    ID3DBlob* errorMsgs = nullptr;
+
+    HRESULT hr = D3DCompile(sourceCode.CString(), sourceCode.Length(), owner_->GetName().CString(), &macros.Front(), nullptr,
+        entryPoint, profile, flags, 0, &shaderCode, &errorMsgs);
+    if (FAILED(hr))
+    {
+        // Do not include end zero unnecessarily
+        compilerOutput_ = String((const char*)errorMsgs->GetBufferPointer(), (unsigned)errorMsgs->GetBufferSize() - 1);
+    }
+    else
+    {
+        if (type_ == VS)
+            URHO3D_LOGDEBUG("Compiled vertex shader " + GetFullName());
+        else
+            URHO3D_LOGDEBUG("Compiled pixel shader " + GetFullName());
+
+        // Inspect the produced bytecode using MojoShader, then strip and store it
+        unsigned char* bufData = (unsigned char*)shaderCode->GetBufferPointer();
+        unsigned bufSize = (unsigned)shaderCode->GetBufferSize();
+        ParseParameters_D3D9(bufData, bufSize);
+        CopyStrippedCode(byteCode_, bufData, bufSize);
+    }
+
+    URHO3D_SAFE_RELEASE(shaderCode);
+    URHO3D_SAFE_RELEASE(errorMsgs);
+
+    return !byteCode_.Empty();
+}
+
+void ShaderVariation::ParseParameters_D3D9(unsigned char* bufData, unsigned bufSize)
+{
+    MOJOSHADER_parseData const* parseData = MOJOSHADER_parse("bytecode", bufData, bufSize, nullptr, 0, nullptr, 0, nullptr, nullptr, nullptr);
+
+    for (int i = 0; i < parseData->symbol_count; i++)
+    {
+        MOJOSHADER_symbol const& symbol = parseData->symbols[i];
+
+        String name(symbol.name);
+        unsigned reg = symbol.register_index;
+        unsigned regCount = symbol.register_count;
+
+        // Check if the parameter is a constant or a texture sampler
+        bool isSampler = (name[0] == 's');
+        name = name.Substring(1);
+
+        if (isSampler)
+        {
+            // Skip if it's a G-buffer sampler, which are aliases for the standard texture units
+            if (reg < MAX_TEXTURE_UNITS)
+            {
+                if (name != "AlbedoBuffer" && name != "NormalBuffer" && name != "DepthBuffer" && name != "LightBuffer")
+                    useTextureUnits_[reg] = true;
+            }
+        }
+        else
+        {
+            parameters_[StringHash(name)] = ShaderParameter{type_, name, reg, regCount};
+        }
+    }
+
+    MOJOSHADER_freeParseData(parseData);
+}
+
+void ShaderVariation::SaveByteCode_D3D9(const String& binaryShaderName)
+{
+    ResourceCache* cache = owner_->GetSubsystem<ResourceCache>();
+    FileSystem* fileSystem = owner_->GetSubsystem<FileSystem>();
+
+    // Filename may or may not be inside the resource system
+    String fullName = binaryShaderName;
+    if (!IsAbsolutePath(fullName))
+    {
+        // If not absolute, use the resource dir of the shader
+        String shaderFileName = cache->GetResourceFileName(owner_->GetName());
+        if (shaderFileName.Empty())
+            return;
+        fullName = shaderFileName.Substring(0, shaderFileName.Find(owner_->GetName())) + binaryShaderName;
+    }
+    String path = GetPath(fullName);
+    if (!fileSystem->DirExists(path))
+        fileSystem->CreateDir(path);
+
+    SharedPtr<File> file(new File(owner_->GetContext(), fullName, FILE_WRITE));
+    if (!file->IsOpen())
+        return;
+
+    file->WriteFileID("USHD");
+    file->WriteShort((unsigned short)type_);
+    file->WriteShort(3);
+
+    file->WriteUInt(parameters_.Size());
+    for (HashMap<StringHash, ShaderParameter>::ConstIterator i = parameters_.Begin(); i != parameters_.End(); ++i)
+    {
+        file->WriteString(i->second_.name_);
+        file->WriteUByte((unsigned char)i->second_.register_);
+        file->WriteUByte((unsigned char)i->second_.regCount_);
+    }
+
+    unsigned usedTextureUnits = 0;
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+    {
+        if (useTextureUnits_[i])
+            ++usedTextureUnits;
+    }
+    file->WriteUInt(usedTextureUnits);
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+    {
+        if (useTextureUnits_[i])
+        {
+            file->WriteString(graphics_->GetTextureUnitName((TextureUnit)i));
+            file->WriteUByte((unsigned char)i);
+        }
+    }
+
+    unsigned dataSize = byteCode_.Size();
+    file->WriteUInt(dataSize);
+    if (dataSize)
+        file->Write(&byteCode_[0], dataSize);
+}
+
+}

+ 113 - 113
Source/Urho3D/Graphics/Direct3D9/D3D9Texture.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9Texture.cpp

@@ -1,113 +1,113 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Core/StringUtils.h"
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/GraphicsImpl.h"
-#include "../../Graphics/Material.h"
-#include "../../IO/FileSystem.h"
-#include "../../Resource/ResourceCache.h"
-#include "../../Resource/XMLFile.h"
-
-#include "../../DebugNew.h"
-
-namespace Urho3D
-{
-
-void Texture::SetSRGB_D3D9(bool enable)
-{
-    if (graphics_)
-        enable &= graphics_->GetSRGBSupport();
-
-    sRGB_ = enable;
-}
-
-void Texture::UpdateParameters_D3D9()
-{
-    // No-op on Direct3D9, handled by Graphics instead by modifying the sampler settings as necessary
-}
-
-bool Texture::GetParametersDirty_D3D9() const
-{
-    return false;
-}
-
-bool Texture::IsCompressed_D3D9() const
-{
-    return format_ == D3DFMT_DXT1 || format_ == D3DFMT_DXT3 || format_ == D3DFMT_DXT5;
-}
-
-unsigned Texture::GetRowDataSize_D3D9(int width) const
-{
-    switch (format_)
-    {
-    case D3DFMT_A8:
-    case D3DFMT_L8:
-        return (unsigned)width;
-
-    case D3DFMT_D16:
-    case D3DFMT_R5G6B5:
-    case D3DFMT_A4R4G4B4:
-    case D3DFMT_A8L8:
-    case D3DFMT_R16F:
-        return (unsigned)(width * 2);
-
-    case D3DFMT_X8R8G8B8:
-        // Note: here source and destination data size differ
-        return (unsigned)(width * 3);
-
-    case D3DFMT_A8R8G8B8:
-    case D3DFMT_G16R16:
-    case D3DFMT_R32F:
-    case D3DFMT_G16R16F:
-    case D3DFMT_D24S8:
-    case D3DFMT_D32:
-        return (unsigned)(width * 4);
-
-    case D3DFMT_A16B16G16R16:
-    case D3DFMT_A16B16G16R16F:
-        return (unsigned)(width * 8);
-
-    case D3DFMT_A32B32G32R32F:
-        return (unsigned)(width * 16);
-
-    case D3DFMT_DXT1:
-        return (unsigned)(((width + 3) >> 2) * 8);
-
-    case D3DFMT_DXT3:
-    case D3DFMT_DXT5:
-        return (unsigned)(((width + 3) >> 2) * 16);
-
-    default:
-        return 0;
-    }
-}
-
-void Texture::RegenerateLevels_D3D9()
-{
-    // No-op on Direct3D9
-    levelsDirty_ = false;
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Core/StringUtils.h"
+#include "../../Graphics/Graphics.h"
+#include "../../Graphics/Material.h"
+#include "../../GraphicsAPI/GraphicsImpl.h"
+#include "../../IO/FileSystem.h"
+#include "../../Resource/ResourceCache.h"
+#include "../../Resource/XMLFile.h"
+
+#include "../../DebugNew.h"
+
+namespace Urho3D
+{
+
+void Texture::SetSRGB_D3D9(bool enable)
+{
+    if (graphics_)
+        enable &= graphics_->GetSRGBSupport();
+
+    sRGB_ = enable;
+}
+
+void Texture::UpdateParameters_D3D9()
+{
+    // No-op on Direct3D9, handled by Graphics instead by modifying the sampler settings as necessary
+}
+
+bool Texture::GetParametersDirty_D3D9() const
+{
+    return false;
+}
+
+bool Texture::IsCompressed_D3D9() const
+{
+    return format_ == D3DFMT_DXT1 || format_ == D3DFMT_DXT3 || format_ == D3DFMT_DXT5;
+}
+
+unsigned Texture::GetRowDataSize_D3D9(int width) const
+{
+    switch (format_)
+    {
+    case D3DFMT_A8:
+    case D3DFMT_L8:
+        return (unsigned)width;
+
+    case D3DFMT_D16:
+    case D3DFMT_R5G6B5:
+    case D3DFMT_A4R4G4B4:
+    case D3DFMT_A8L8:
+    case D3DFMT_R16F:
+        return (unsigned)(width * 2);
+
+    case D3DFMT_X8R8G8B8:
+        // Note: here source and destination data size differ
+        return (unsigned)(width * 3);
+
+    case D3DFMT_A8R8G8B8:
+    case D3DFMT_G16R16:
+    case D3DFMT_R32F:
+    case D3DFMT_G16R16F:
+    case D3DFMT_D24S8:
+    case D3DFMT_D32:
+        return (unsigned)(width * 4);
+
+    case D3DFMT_A16B16G16R16:
+    case D3DFMT_A16B16G16R16F:
+        return (unsigned)(width * 8);
+
+    case D3DFMT_A32B32G32R32F:
+        return (unsigned)(width * 16);
+
+    case D3DFMT_DXT1:
+        return (unsigned)(((width + 3) >> 2) * 8);
+
+    case D3DFMT_DXT3:
+    case D3DFMT_DXT5:
+        return (unsigned)(((width + 3) >> 2) * 16);
+
+    default:
+        return 0;
+    }
+}
+
+void Texture::RegenerateLevels_D3D9()
+{
+    // No-op on Direct3D9
+    levelsDirty_ = false;
+}
+
+}

+ 638 - 638
Source/Urho3D/Graphics/Direct3D9/D3D9Texture2D.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9Texture2D.cpp

@@ -1,638 +1,638 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Core/Context.h"
-#include "../../Core/Profiler.h"
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/GraphicsEvents.h"
-#include "../../Graphics/Renderer.h"
-#include "../../Graphics/Texture2D.h"
-#include "../../IO/Log.h"
-#include "../../IO/FileSystem.h"
-#include "../../Resource/ResourceCache.h"
-#include "../../Resource/XMLFile.h"
-#include "D3D9GraphicsImpl.h"
-
-#include "../../DebugNew.h"
-
-namespace Urho3D
-{
-
-void Texture2D::OnDeviceLost_D3D9()
-{
-    if (usage_ > TEXTURE_STATIC)
-        Release_D3D9();
-}
-
-void Texture2D::OnDeviceReset_D3D9()
-{
-    if (usage_ > TEXTURE_STATIC || !object_.ptr_ || dataPending_)
-    {
-        // If has a resource file, reload through the resource cache. Otherwise just recreate.
-        ResourceCache* cache = GetSubsystem<ResourceCache>();
-        if (cache->Exists(GetName()))
-            dataLost_ = !cache->ReloadResource(this);
-
-        if (!object_.ptr_)
-        {
-            Create_D3D9();
-            dataLost_ = true;
-        }
-    }
-
-    dataPending_ = false;
-}
-
-void Texture2D::Release_D3D9()
-{
-    if (graphics_)
-    {
-        for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-        {
-            if (graphics_->GetTexture(i) == this)
-                graphics_->SetTexture(i, nullptr);
-        }
-    }
-
-    if (renderSurface_)
-        renderSurface_->Release();
-
-    URHO3D_SAFE_RELEASE(object_.ptr_);
-
-    resolveDirty_ = false;
-    levelsDirty_ = false;
-}
-
-bool Texture2D::SetData_D3D9(unsigned level, int x, int y, int width, int height, const void* data)
-{
-    URHO3D_PROFILE(SetTextureData);
-
-    if (!object_.ptr_)
-    {
-        URHO3D_LOGERROR("No texture created, can not set data");
-        return false;
-    }
-
-    if (!data)
-    {
-        URHO3D_LOGERROR("Null source for setting data");
-        return false;
-    }
-
-    if (level >= levels_)
-    {
-        URHO3D_LOGERROR("Illegal mip level for setting data");
-        return false;
-    }
-
-    if (graphics_->IsDeviceLost())
-    {
-        URHO3D_LOGWARNING("Texture data assignment while device is lost");
-        dataPending_ = true;
-        return true;
-    }
-
-    if (IsCompressed_D3D9())
-    {
-        x &= ~3;
-        y &= ~3;
-    }
-
-    int levelWidth = GetLevelWidth(level);
-    int levelHeight = GetLevelHeight(level);
-    if (x < 0 || x + width > levelWidth || y < 0 || y + height > levelHeight || width <= 0 || height <= 0)
-    {
-        URHO3D_LOGERROR("Illegal dimensions for setting data");
-        return false;
-    }
-
-    D3DLOCKED_RECT d3dLockedRect;
-    RECT d3dRect;
-    d3dRect.left = x;
-    d3dRect.top = y;
-    d3dRect.right = x + width;
-    d3dRect.bottom = y + height;
-
-    DWORD flags = 0;
-    if (level == 0 && x == 0 && y == 0 && width == levelWidth && height == levelHeight && usage_ > TEXTURE_STATIC)
-        flags |= D3DLOCK_DISCARD;
-
-    HRESULT hr = ((IDirect3DTexture9*)object_.ptr_)->LockRect(level, &d3dLockedRect, (flags & D3DLOCK_DISCARD) ? nullptr : &d3dRect, flags);
-    if (FAILED(hr))
-    {
-        URHO3D_LOGD3DERROR("Could not lock texture", hr);
-        return false;
-    }
-
-    if (IsCompressed_D3D9())
-    {
-        height = (height + 3) >> 2;
-        y >>= 2;
-    }
-
-    unsigned char* src = (unsigned char*)data;
-    unsigned rowSize = GetRowDataSize_D3D9(width);
-
-    // GetRowDataSize_D3D9() returns CPU-side (source) data size, so need to convert for X8R8G8B8
-    if (format_ == D3DFMT_X8R8G8B8)
-        rowSize = rowSize / 3 * 4;
-
-    // Perform conversion from RGB / RGBA as necessary
-    switch (format_)
-    {
-    default:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            memcpy(dest, src, rowSize);
-            src += rowSize;
-        }
-        break;
-
-    case D3DFMT_X8R8G8B8:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            for (int j = 0; j < width; ++j)
-            {
-                *dest++ = src[2];
-                *dest++ = src[1];
-                *dest++ = src[0];
-                *dest++ = 255;
-                src += 3;
-            }
-        }
-        break;
-
-    case D3DFMT_A8R8G8B8:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            for (int j = 0; j < width; ++j)
-            {
-                *dest++ = src[2];
-                *dest++ = src[1];
-                *dest++ = src[0];
-                *dest++ = src[3];
-                src += 4;
-            }
-        }
-        break;
-    }
-
-    ((IDirect3DTexture9*)object_.ptr_)->UnlockRect(level);
-    return true;
-}
-
-bool Texture2D::SetData_D3D9(Image* image, bool useAlpha)
-{
-    if (!image)
-    {
-        URHO3D_LOGERROR("Null image, can not load texture");
-        return false;
-    }
-
-    // Use a shared ptr for managing the temporary mip images created during this function
-    SharedPtr<Image> mipImage;
-    unsigned memoryUse = sizeof(Texture2D);
-    MaterialQuality quality = QUALITY_HIGH;
-    Renderer* renderer = GetSubsystem<Renderer>();
-    if (renderer)
-        quality = renderer->GetTextureQuality();
-
-    if (!image->IsCompressed())
-    {
-        unsigned char* levelData = image->GetData();
-        int levelWidth = image->GetWidth();
-        int levelHeight = image->GetHeight();
-        unsigned components = image->GetComponents();
-        unsigned format = 0;
-
-        // Discard unnecessary mip levels
-        for (unsigned i = 0; i < mipsToSkip_[quality]; ++i)
-        {
-            mipImage = image->GetNextLevel(); image = mipImage;
-            levelData = image->GetData();
-            levelWidth = image->GetWidth();
-            levelHeight = image->GetHeight();
-        }
-
-        switch (components)
-        {
-        case 1:
-            format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat();
-            break;
-
-        case 2:
-            format = Graphics::GetLuminanceAlphaFormat();
-            break;
-
-        case 3:
-            format = Graphics::GetRGBFormat();
-            break;
-
-        case 4:
-            format = Graphics::GetRGBAFormat();
-            break;
-
-        default:
-            assert(false);  // Should never reach here
-            break;
-        }
-
-        // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size
-        if (IsCompressed_D3D9() && requestedLevels_ > 1)
-            requestedLevels_ = 0;
-        SetSize(levelWidth, levelHeight, format);
-
-        for (unsigned i = 0; i < levels_; ++i)
-        {
-            SetData_D3D9(i, 0, 0, levelWidth, levelHeight, levelData);
-            memoryUse += levelWidth * levelHeight * components;
-
-            if (i < levels_ - 1)
-            {
-                mipImage = image->GetNextLevel(); image = mipImage;
-                levelData = image->GetData();
-                levelWidth = image->GetWidth();
-                levelHeight = image->GetHeight();
-            }
-        }
-    }
-    else
-    {
-        int width = image->GetWidth();
-        int height = image->GetHeight();
-        unsigned levels = image->GetNumCompressedLevels();
-        unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
-        bool needDecompress = false;
-
-        if (!format)
-        {
-            format = Graphics::GetRGBAFormat();
-            needDecompress = true;
-        }
-
-        unsigned mipsToSkip = mipsToSkip_[quality];
-        if (mipsToSkip >= levels)
-            mipsToSkip = levels - 1;
-        while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4))
-            --mipsToSkip;
-        width /= (1 << mipsToSkip);
-        height /= (1 << mipsToSkip);
-
-        SetNumLevels(Max((levels - mipsToSkip), 1U));
-        SetSize(width, height, format);
-
-        for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i)
-        {
-            CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip);
-            if (!needDecompress)
-            {
-                SetData_D3D9(i, 0, 0, level.width_, level.height_, level.data_);
-                memoryUse += level.rows_ * level.rowSize_;
-            }
-            else
-            {
-                unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4];
-                level.Decompress(rgbaData);
-                SetData_D3D9(i, 0, 0, level.width_, level.height_, rgbaData);
-                memoryUse += level.width_ * level.height_ * 4;
-                delete[] rgbaData;
-            }
-        }
-    }
-
-    SetMemoryUse(memoryUse);
-    return true;
-}
-
-bool Texture2D::GetData_D3D9(unsigned level, void* dest) const
-{
-    if (!object_.ptr_)
-    {
-        URHO3D_LOGERROR("No texture created, can not get data");
-        return false;
-    }
-
-    if (!dest)
-    {
-        URHO3D_LOGERROR("Null destination for getting data");
-        return false;
-    }
-
-    if (level >= levels_)
-    {
-        URHO3D_LOGERROR("Illegal mip level for getting data");
-        return false;
-    }
-
-    if (graphics_->IsDeviceLost())
-    {
-        URHO3D_LOGWARNING("Getting texture data while device is lost");
-        return false;
-    }
-
-    if (resolveDirty_)
-        graphics_->ResolveToTexture(const_cast<Texture2D*>(this));
-
-    int levelWidth = GetLevelWidth(level);
-    int levelHeight = GetLevelHeight(level);
-
-    D3DLOCKED_RECT d3dLockedRect;
-    RECT d3dRect;
-    d3dRect.left = 0;
-    d3dRect.top = 0;
-    d3dRect.right = levelWidth;
-    d3dRect.bottom = levelHeight;
-
-    IDirect3DSurface9* offscreenSurface = nullptr;
-    // Need to use a offscreen surface & GetRenderTargetData() for rendertargets
-    if (renderSurface_)
-    {
-        if (level != 0)
-        {
-            URHO3D_LOGERROR("Can only get mip level 0 data from a rendertarget");
-            return false;
-        }
-
-        // If multisampled, must copy the surface of the resolve texture instead of the multisampled surface
-        IDirect3DSurface9* resolveSurface = nullptr;
-        if (multiSample_ > 1)
-        {
-            HRESULT hr = ((IDirect3DTexture9*)object_.ptr_)->GetSurfaceLevel(0, (IDirect3DSurface9**)&resolveSurface);
-            if (FAILED(hr))
-            {
-                URHO3D_LOGD3DERROR("Could not get surface of the resolve texture", hr);
-                URHO3D_SAFE_RELEASE(resolveSurface);
-                return false;
-            }
-        }
-
-        IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
-        HRESULT hr = device->CreateOffscreenPlainSurface((UINT)width_, (UINT)height_, (D3DFORMAT)format_,
-            D3DPOOL_SYSTEMMEM, &offscreenSurface, nullptr);
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Could not create surface for getting rendertarget data", hr);
-            URHO3D_SAFE_RELEASE(offscreenSurface)
-            URHO3D_SAFE_RELEASE(resolveSurface);
-            return false;
-        }
-
-        if (resolveSurface)
-            hr = device->GetRenderTargetData(resolveSurface, offscreenSurface);
-        else
-            hr = device->GetRenderTargetData((IDirect3DSurface9*)renderSurface_->GetSurface(), offscreenSurface);
-        URHO3D_SAFE_RELEASE(resolveSurface);
-
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Could not get rendertarget data", hr);
-            URHO3D_SAFE_RELEASE(offscreenSurface);
-            return false;
-        }
-
-        hr = offscreenSurface->LockRect(&d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Could not lock surface for getting rendertarget data", hr);
-            URHO3D_SAFE_RELEASE(offscreenSurface);
-            return false;
-        }
-    }
-    else
-    {
-        HRESULT hr = ((IDirect3DTexture9*)object_.ptr_)->LockRect(level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Could not lock texture", hr);
-            return false;
-        }
-    }
-
-    int height = levelHeight;
-    if (IsCompressed_D3D9())
-        height = (height + 3) >> 2;
-
-    unsigned char* destPtr = (unsigned char*)dest;
-    unsigned rowSize = GetRowDataSize_D3D9(levelWidth);
-    // GetRowDataSize_D3D9() returns CPU-side (destination) data size, so need to convert for X8R8G8B8
-    if (format_ == D3DFMT_X8R8G8B8)
-        rowSize = rowSize / 3 * 4;
-
-    // Perform conversion to RGB / RGBA as necessary
-    switch (format_)
-    {
-    default:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            memcpy(destPtr, src, rowSize);
-            destPtr += rowSize;
-        }
-        break;
-
-    case D3DFMT_X8R8G8B8:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            for (int j = 0; j < levelWidth; ++j)
-            {
-                destPtr[2] = *src++;
-                destPtr[1] = *src++;
-                destPtr[0] = *src++;
-                ++src;
-                destPtr += 3;
-            }
-        }
-        break;
-
-    case D3DFMT_A8R8G8B8:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            for (int j = 0; j < levelWidth; ++j)
-            {
-                destPtr[2] = *src++;
-                destPtr[1] = *src++;
-                destPtr[0] = *src++;
-                destPtr[3] = *src++;
-                destPtr += 4;
-            }
-        }
-        break;
-    }
-
-    if (offscreenSurface)
-        offscreenSurface->UnlockRect();
-    else
-        ((IDirect3DTexture9*)object_.ptr_)->UnlockRect(level);
-
-    URHO3D_SAFE_RELEASE(offscreenSurface);
-    return true;
-}
-
-bool Texture2D::Create_D3D9()
-{
-    Release_D3D9();
-
-    if (!graphics_ || !width_ || !height_)
-        return false;
-
-    if (graphics_->IsDeviceLost())
-    {
-        URHO3D_LOGWARNING("Texture creation while device is lost");
-        return true;
-    }
-
-    if (multiSample_ > 1 && !autoResolve_)
-    {
-        URHO3D_LOGWARNING("Multisampled texture without autoresolve is not supported on Direct3D9");
-        autoResolve_ = true;
-    }
-
-    GraphicsImpl_D3D9* impl = graphics_->GetImpl_D3D9();
-
-    unsigned pool = usage_ > TEXTURE_STATIC ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
-    unsigned d3dUsage = 0;
-
-    switch (usage_)
-    {
-    case TEXTURE_DYNAMIC:
-        d3dUsage |= D3DUSAGE_DYNAMIC;
-        break;
-    case TEXTURE_RENDERTARGET:
-        d3dUsage |= D3DUSAGE_RENDERTARGET;
-        if (requestedLevels_ != 1)
-        {
-            // Check mipmap autogeneration support
-            if (impl->CheckFormatSupport((D3DFORMAT)format_, D3DUSAGE_AUTOGENMIPMAP, D3DRTYPE_TEXTURE))
-            {
-                requestedLevels_ = 0;
-                d3dUsage |= D3DUSAGE_AUTOGENMIPMAP;
-            }
-            else
-                requestedLevels_ = 1;
-        }
-        break;
-    case TEXTURE_DEPTHSTENCIL:
-        d3dUsage |= D3DUSAGE_DEPTHSTENCIL;
-        // No mipmaps for depth-stencil textures
-        requestedLevels_ = 1;
-        break;
-    default:
-        break;
-    }
-
-    if (multiSample_ > 1)
-    {
-        // Fall back to non-multisampled if unsupported multisampling mode
-        if (!impl->CheckMultiSampleSupport((D3DFORMAT)format_,  multiSample_))
-        {
-            multiSample_ = 1;
-            autoResolve_ = false;
-        }
-    }
-
-    IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
-    // If creating a depth-stencil texture, and it is not supported, create a depth-stencil surface instead
-    // Multisampled surfaces need also to be created this way
-    if (usage_ == TEXTURE_DEPTHSTENCIL && (multiSample_ > 1 || !graphics_->GetImpl_D3D9()->CheckFormatSupport((D3DFORMAT)format_,
-        d3dUsage, D3DRTYPE_TEXTURE)))
-    {
-        HRESULT hr = device->CreateDepthStencilSurface(
-            (UINT)width_,
-            (UINT)height_,
-            (D3DFORMAT)format_,
-            (multiSample_ > 1) ? (D3DMULTISAMPLE_TYPE)multiSample_ : D3DMULTISAMPLE_NONE,
-            0,
-            FALSE,
-            (IDirect3DSurface9**)&renderSurface_->surface_,
-            nullptr);
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Could not create depth-stencil surface", hr);
-            URHO3D_SAFE_RELEASE(renderSurface_->surface_);
-            return false;
-        }
-
-        levels_ = 1;
-    }
-    else
-    {
-        HRESULT hr = graphics_->GetImpl_D3D9()->GetDevice()->CreateTexture(
-            (UINT)width_,
-            (UINT)height_,
-            requestedLevels_,
-            d3dUsage,
-            (D3DFORMAT)format_,
-            (D3DPOOL)pool,
-            (IDirect3DTexture9**)&object_,
-            nullptr);
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Could not create texture", hr);
-            URHO3D_SAFE_RELEASE(object_.ptr_);
-            return false;
-        }
-
-        levels_ = ((IDirect3DTexture9*)object_.ptr_)->GetLevelCount();
-
-        // Create the multisampled rendertarget for rendering to if necessary
-        if (usage_ == TEXTURE_RENDERTARGET && multiSample_ > 1)
-        {
-            HRESULT hr = device->CreateRenderTarget(
-                (UINT)width_,
-                (UINT)height_,
-                (D3DFORMAT)format_,
-                (D3DMULTISAMPLE_TYPE)multiSample_,
-                0,
-                FALSE,
-                (IDirect3DSurface9**)&renderSurface_->surface_,
-                nullptr);
-            if (FAILED(hr))
-            {
-                URHO3D_LOGD3DERROR("Could not create multisampled rendertarget surface", hr);
-                URHO3D_SAFE_RELEASE(renderSurface_->surface_);
-                return false;
-            }
-        }
-        else if (usage_ >= TEXTURE_RENDERTARGET)
-        {
-            // Else use the texture surface directly for rendering
-            hr = ((IDirect3DTexture9*)object_.ptr_)->GetSurfaceLevel(0, (IDirect3DSurface9**)&renderSurface_->surface_);
-            if (FAILED(hr))
-            {
-                URHO3D_LOGD3DERROR("Could not get rendertarget surface", hr);
-                URHO3D_SAFE_RELEASE(renderSurface_->surface_);
-                return false;
-            }
-        }
-    }
-
-    return true;
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Core/Context.h"
+#include "../../Core/Profiler.h"
+#include "../../Graphics/Graphics.h"
+#include "../../Graphics/GraphicsEvents.h"
+#include "../../Graphics/Renderer.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9GraphicsImpl.h"
+#include "../../GraphicsAPI/Texture2D.h"
+#include "../../IO/FileSystem.h"
+#include "../../IO/Log.h"
+#include "../../Resource/ResourceCache.h"
+#include "../../Resource/XMLFile.h"
+
+#include "../../DebugNew.h"
+
+namespace Urho3D
+{
+
+void Texture2D::OnDeviceLost_D3D9()
+{
+    if (usage_ > TEXTURE_STATIC)
+        Release_D3D9();
+}
+
+void Texture2D::OnDeviceReset_D3D9()
+{
+    if (usage_ > TEXTURE_STATIC || !object_.ptr_ || dataPending_)
+    {
+        // If has a resource file, reload through the resource cache. Otherwise just recreate.
+        ResourceCache* cache = GetSubsystem<ResourceCache>();
+        if (cache->Exists(GetName()))
+            dataLost_ = !cache->ReloadResource(this);
+
+        if (!object_.ptr_)
+        {
+            Create_D3D9();
+            dataLost_ = true;
+        }
+    }
+
+    dataPending_ = false;
+}
+
+void Texture2D::Release_D3D9()
+{
+    if (graphics_)
+    {
+        for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+        {
+            if (graphics_->GetTexture(i) == this)
+                graphics_->SetTexture(i, nullptr);
+        }
+    }
+
+    if (renderSurface_)
+        renderSurface_->Release();
+
+    URHO3D_SAFE_RELEASE(object_.ptr_);
+
+    resolveDirty_ = false;
+    levelsDirty_ = false;
+}
+
+bool Texture2D::SetData_D3D9(unsigned level, int x, int y, int width, int height, const void* data)
+{
+    URHO3D_PROFILE(SetTextureData);
+
+    if (!object_.ptr_)
+    {
+        URHO3D_LOGERROR("No texture created, can not set data");
+        return false;
+    }
+
+    if (!data)
+    {
+        URHO3D_LOGERROR("Null source for setting data");
+        return false;
+    }
+
+    if (level >= levels_)
+    {
+        URHO3D_LOGERROR("Illegal mip level for setting data");
+        return false;
+    }
+
+    if (graphics_->IsDeviceLost())
+    {
+        URHO3D_LOGWARNING("Texture data assignment while device is lost");
+        dataPending_ = true;
+        return true;
+    }
+
+    if (IsCompressed_D3D9())
+    {
+        x &= ~3;
+        y &= ~3;
+    }
+
+    int levelWidth = GetLevelWidth(level);
+    int levelHeight = GetLevelHeight(level);
+    if (x < 0 || x + width > levelWidth || y < 0 || y + height > levelHeight || width <= 0 || height <= 0)
+    {
+        URHO3D_LOGERROR("Illegal dimensions for setting data");
+        return false;
+    }
+
+    D3DLOCKED_RECT d3dLockedRect;
+    RECT d3dRect;
+    d3dRect.left = x;
+    d3dRect.top = y;
+    d3dRect.right = x + width;
+    d3dRect.bottom = y + height;
+
+    DWORD flags = 0;
+    if (level == 0 && x == 0 && y == 0 && width == levelWidth && height == levelHeight && usage_ > TEXTURE_STATIC)
+        flags |= D3DLOCK_DISCARD;
+
+    HRESULT hr = ((IDirect3DTexture9*)object_.ptr_)->LockRect(level, &d3dLockedRect, (flags & D3DLOCK_DISCARD) ? nullptr : &d3dRect, flags);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Could not lock texture", hr);
+        return false;
+    }
+
+    if (IsCompressed_D3D9())
+    {
+        height = (height + 3) >> 2;
+        y >>= 2;
+    }
+
+    unsigned char* src = (unsigned char*)data;
+    unsigned rowSize = GetRowDataSize_D3D9(width);
+
+    // GetRowDataSize_D3D9() returns CPU-side (source) data size, so need to convert for X8R8G8B8
+    if (format_ == D3DFMT_X8R8G8B8)
+        rowSize = rowSize / 3 * 4;
+
+    // Perform conversion from RGB / RGBA as necessary
+    switch (format_)
+    {
+    default:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            memcpy(dest, src, rowSize);
+            src += rowSize;
+        }
+        break;
+
+    case D3DFMT_X8R8G8B8:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            for (int j = 0; j < width; ++j)
+            {
+                *dest++ = src[2];
+                *dest++ = src[1];
+                *dest++ = src[0];
+                *dest++ = 255;
+                src += 3;
+            }
+        }
+        break;
+
+    case D3DFMT_A8R8G8B8:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            for (int j = 0; j < width; ++j)
+            {
+                *dest++ = src[2];
+                *dest++ = src[1];
+                *dest++ = src[0];
+                *dest++ = src[3];
+                src += 4;
+            }
+        }
+        break;
+    }
+
+    ((IDirect3DTexture9*)object_.ptr_)->UnlockRect(level);
+    return true;
+}
+
+bool Texture2D::SetData_D3D9(Image* image, bool useAlpha)
+{
+    if (!image)
+    {
+        URHO3D_LOGERROR("Null image, can not load texture");
+        return false;
+    }
+
+    // Use a shared ptr for managing the temporary mip images created during this function
+    SharedPtr<Image> mipImage;
+    unsigned memoryUse = sizeof(Texture2D);
+    MaterialQuality quality = QUALITY_HIGH;
+    Renderer* renderer = GetSubsystem<Renderer>();
+    if (renderer)
+        quality = renderer->GetTextureQuality();
+
+    if (!image->IsCompressed())
+    {
+        unsigned char* levelData = image->GetData();
+        int levelWidth = image->GetWidth();
+        int levelHeight = image->GetHeight();
+        unsigned components = image->GetComponents();
+        unsigned format = 0;
+
+        // Discard unnecessary mip levels
+        for (unsigned i = 0; i < mipsToSkip_[quality]; ++i)
+        {
+            mipImage = image->GetNextLevel(); image = mipImage;
+            levelData = image->GetData();
+            levelWidth = image->GetWidth();
+            levelHeight = image->GetHeight();
+        }
+
+        switch (components)
+        {
+        case 1:
+            format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat();
+            break;
+
+        case 2:
+            format = Graphics::GetLuminanceAlphaFormat();
+            break;
+
+        case 3:
+            format = Graphics::GetRGBFormat();
+            break;
+
+        case 4:
+            format = Graphics::GetRGBAFormat();
+            break;
+
+        default:
+            assert(false);  // Should never reach here
+            break;
+        }
+
+        // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size
+        if (IsCompressed_D3D9() && requestedLevels_ > 1)
+            requestedLevels_ = 0;
+        SetSize(levelWidth, levelHeight, format);
+
+        for (unsigned i = 0; i < levels_; ++i)
+        {
+            SetData_D3D9(i, 0, 0, levelWidth, levelHeight, levelData);
+            memoryUse += levelWidth * levelHeight * components;
+
+            if (i < levels_ - 1)
+            {
+                mipImage = image->GetNextLevel(); image = mipImage;
+                levelData = image->GetData();
+                levelWidth = image->GetWidth();
+                levelHeight = image->GetHeight();
+            }
+        }
+    }
+    else
+    {
+        int width = image->GetWidth();
+        int height = image->GetHeight();
+        unsigned levels = image->GetNumCompressedLevels();
+        unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
+        bool needDecompress = false;
+
+        if (!format)
+        {
+            format = Graphics::GetRGBAFormat();
+            needDecompress = true;
+        }
+
+        unsigned mipsToSkip = mipsToSkip_[quality];
+        if (mipsToSkip >= levels)
+            mipsToSkip = levels - 1;
+        while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4))
+            --mipsToSkip;
+        width /= (1 << mipsToSkip);
+        height /= (1 << mipsToSkip);
+
+        SetNumLevels(Max((levels - mipsToSkip), 1U));
+        SetSize(width, height, format);
+
+        for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i)
+        {
+            CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip);
+            if (!needDecompress)
+            {
+                SetData_D3D9(i, 0, 0, level.width_, level.height_, level.data_);
+                memoryUse += level.rows_ * level.rowSize_;
+            }
+            else
+            {
+                unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4];
+                level.Decompress(rgbaData);
+                SetData_D3D9(i, 0, 0, level.width_, level.height_, rgbaData);
+                memoryUse += level.width_ * level.height_ * 4;
+                delete[] rgbaData;
+            }
+        }
+    }
+
+    SetMemoryUse(memoryUse);
+    return true;
+}
+
+bool Texture2D::GetData_D3D9(unsigned level, void* dest) const
+{
+    if (!object_.ptr_)
+    {
+        URHO3D_LOGERROR("No texture created, can not get data");
+        return false;
+    }
+
+    if (!dest)
+    {
+        URHO3D_LOGERROR("Null destination for getting data");
+        return false;
+    }
+
+    if (level >= levels_)
+    {
+        URHO3D_LOGERROR("Illegal mip level for getting data");
+        return false;
+    }
+
+    if (graphics_->IsDeviceLost())
+    {
+        URHO3D_LOGWARNING("Getting texture data while device is lost");
+        return false;
+    }
+
+    if (resolveDirty_)
+        graphics_->ResolveToTexture(const_cast<Texture2D*>(this));
+
+    int levelWidth = GetLevelWidth(level);
+    int levelHeight = GetLevelHeight(level);
+
+    D3DLOCKED_RECT d3dLockedRect;
+    RECT d3dRect;
+    d3dRect.left = 0;
+    d3dRect.top = 0;
+    d3dRect.right = levelWidth;
+    d3dRect.bottom = levelHeight;
+
+    IDirect3DSurface9* offscreenSurface = nullptr;
+    // Need to use a offscreen surface & GetRenderTargetData() for rendertargets
+    if (renderSurface_)
+    {
+        if (level != 0)
+        {
+            URHO3D_LOGERROR("Can only get mip level 0 data from a rendertarget");
+            return false;
+        }
+
+        // If multisampled, must copy the surface of the resolve texture instead of the multisampled surface
+        IDirect3DSurface9* resolveSurface = nullptr;
+        if (multiSample_ > 1)
+        {
+            HRESULT hr = ((IDirect3DTexture9*)object_.ptr_)->GetSurfaceLevel(0, (IDirect3DSurface9**)&resolveSurface);
+            if (FAILED(hr))
+            {
+                URHO3D_LOGD3DERROR("Could not get surface of the resolve texture", hr);
+                URHO3D_SAFE_RELEASE(resolveSurface);
+                return false;
+            }
+        }
+
+        IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
+        HRESULT hr = device->CreateOffscreenPlainSurface((UINT)width_, (UINT)height_, (D3DFORMAT)format_,
+            D3DPOOL_SYSTEMMEM, &offscreenSurface, nullptr);
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Could not create surface for getting rendertarget data", hr);
+            URHO3D_SAFE_RELEASE(offscreenSurface)
+            URHO3D_SAFE_RELEASE(resolveSurface);
+            return false;
+        }
+
+        if (resolveSurface)
+            hr = device->GetRenderTargetData(resolveSurface, offscreenSurface);
+        else
+            hr = device->GetRenderTargetData((IDirect3DSurface9*)renderSurface_->GetSurface(), offscreenSurface);
+        URHO3D_SAFE_RELEASE(resolveSurface);
+
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Could not get rendertarget data", hr);
+            URHO3D_SAFE_RELEASE(offscreenSurface);
+            return false;
+        }
+
+        hr = offscreenSurface->LockRect(&d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Could not lock surface for getting rendertarget data", hr);
+            URHO3D_SAFE_RELEASE(offscreenSurface);
+            return false;
+        }
+    }
+    else
+    {
+        HRESULT hr = ((IDirect3DTexture9*)object_.ptr_)->LockRect(level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Could not lock texture", hr);
+            return false;
+        }
+    }
+
+    int height = levelHeight;
+    if (IsCompressed_D3D9())
+        height = (height + 3) >> 2;
+
+    unsigned char* destPtr = (unsigned char*)dest;
+    unsigned rowSize = GetRowDataSize_D3D9(levelWidth);
+    // GetRowDataSize_D3D9() returns CPU-side (destination) data size, so need to convert for X8R8G8B8
+    if (format_ == D3DFMT_X8R8G8B8)
+        rowSize = rowSize / 3 * 4;
+
+    // Perform conversion to RGB / RGBA as necessary
+    switch (format_)
+    {
+    default:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            memcpy(destPtr, src, rowSize);
+            destPtr += rowSize;
+        }
+        break;
+
+    case D3DFMT_X8R8G8B8:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            for (int j = 0; j < levelWidth; ++j)
+            {
+                destPtr[2] = *src++;
+                destPtr[1] = *src++;
+                destPtr[0] = *src++;
+                ++src;
+                destPtr += 3;
+            }
+        }
+        break;
+
+    case D3DFMT_A8R8G8B8:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            for (int j = 0; j < levelWidth; ++j)
+            {
+                destPtr[2] = *src++;
+                destPtr[1] = *src++;
+                destPtr[0] = *src++;
+                destPtr[3] = *src++;
+                destPtr += 4;
+            }
+        }
+        break;
+    }
+
+    if (offscreenSurface)
+        offscreenSurface->UnlockRect();
+    else
+        ((IDirect3DTexture9*)object_.ptr_)->UnlockRect(level);
+
+    URHO3D_SAFE_RELEASE(offscreenSurface);
+    return true;
+}
+
+bool Texture2D::Create_D3D9()
+{
+    Release_D3D9();
+
+    if (!graphics_ || !width_ || !height_)
+        return false;
+
+    if (graphics_->IsDeviceLost())
+    {
+        URHO3D_LOGWARNING("Texture creation while device is lost");
+        return true;
+    }
+
+    if (multiSample_ > 1 && !autoResolve_)
+    {
+        URHO3D_LOGWARNING("Multisampled texture without autoresolve is not supported on Direct3D9");
+        autoResolve_ = true;
+    }
+
+    GraphicsImpl_D3D9* impl = graphics_->GetImpl_D3D9();
+
+    unsigned pool = usage_ > TEXTURE_STATIC ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
+    unsigned d3dUsage = 0;
+
+    switch (usage_)
+    {
+    case TEXTURE_DYNAMIC:
+        d3dUsage |= D3DUSAGE_DYNAMIC;
+        break;
+    case TEXTURE_RENDERTARGET:
+        d3dUsage |= D3DUSAGE_RENDERTARGET;
+        if (requestedLevels_ != 1)
+        {
+            // Check mipmap autogeneration support
+            if (impl->CheckFormatSupport((D3DFORMAT)format_, D3DUSAGE_AUTOGENMIPMAP, D3DRTYPE_TEXTURE))
+            {
+                requestedLevels_ = 0;
+                d3dUsage |= D3DUSAGE_AUTOGENMIPMAP;
+            }
+            else
+                requestedLevels_ = 1;
+        }
+        break;
+    case TEXTURE_DEPTHSTENCIL:
+        d3dUsage |= D3DUSAGE_DEPTHSTENCIL;
+        // No mipmaps for depth-stencil textures
+        requestedLevels_ = 1;
+        break;
+    default:
+        break;
+    }
+
+    if (multiSample_ > 1)
+    {
+        // Fall back to non-multisampled if unsupported multisampling mode
+        if (!impl->CheckMultiSampleSupport((D3DFORMAT)format_,  multiSample_))
+        {
+            multiSample_ = 1;
+            autoResolve_ = false;
+        }
+    }
+
+    IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
+    // If creating a depth-stencil texture, and it is not supported, create a depth-stencil surface instead
+    // Multisampled surfaces need also to be created this way
+    if (usage_ == TEXTURE_DEPTHSTENCIL && (multiSample_ > 1 || !graphics_->GetImpl_D3D9()->CheckFormatSupport((D3DFORMAT)format_,
+        d3dUsage, D3DRTYPE_TEXTURE)))
+    {
+        HRESULT hr = device->CreateDepthStencilSurface(
+            (UINT)width_,
+            (UINT)height_,
+            (D3DFORMAT)format_,
+            (multiSample_ > 1) ? (D3DMULTISAMPLE_TYPE)multiSample_ : D3DMULTISAMPLE_NONE,
+            0,
+            FALSE,
+            (IDirect3DSurface9**)&renderSurface_->surface_,
+            nullptr);
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Could not create depth-stencil surface", hr);
+            URHO3D_SAFE_RELEASE(renderSurface_->surface_);
+            return false;
+        }
+
+        levels_ = 1;
+    }
+    else
+    {
+        HRESULT hr = graphics_->GetImpl_D3D9()->GetDevice()->CreateTexture(
+            (UINT)width_,
+            (UINT)height_,
+            requestedLevels_,
+            d3dUsage,
+            (D3DFORMAT)format_,
+            (D3DPOOL)pool,
+            (IDirect3DTexture9**)&object_,
+            nullptr);
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Could not create texture", hr);
+            URHO3D_SAFE_RELEASE(object_.ptr_);
+            return false;
+        }
+
+        levels_ = ((IDirect3DTexture9*)object_.ptr_)->GetLevelCount();
+
+        // Create the multisampled rendertarget for rendering to if necessary
+        if (usage_ == TEXTURE_RENDERTARGET && multiSample_ > 1)
+        {
+            HRESULT hr = device->CreateRenderTarget(
+                (UINT)width_,
+                (UINT)height_,
+                (D3DFORMAT)format_,
+                (D3DMULTISAMPLE_TYPE)multiSample_,
+                0,
+                FALSE,
+                (IDirect3DSurface9**)&renderSurface_->surface_,
+                nullptr);
+            if (FAILED(hr))
+            {
+                URHO3D_LOGD3DERROR("Could not create multisampled rendertarget surface", hr);
+                URHO3D_SAFE_RELEASE(renderSurface_->surface_);
+                return false;
+            }
+        }
+        else if (usage_ >= TEXTURE_RENDERTARGET)
+        {
+            // Else use the texture surface directly for rendering
+            hr = ((IDirect3DTexture9*)object_.ptr_)->GetSurfaceLevel(0, (IDirect3DSurface9**)&renderSurface_->surface_);
+            if (FAILED(hr))
+            {
+                URHO3D_LOGD3DERROR("Could not get rendertarget surface", hr);
+                URHO3D_SAFE_RELEASE(renderSurface_->surface_);
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+}

+ 284 - 284
Source/Urho3D/Graphics/Direct3D9/D3D9Texture2DArray.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9Texture2DArray.cpp

@@ -1,284 +1,284 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Core/Context.h"
-#include "../../Core/Profiler.h"
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/GraphicsEvents.h"
-#include "../../Graphics/GraphicsImpl.h"
-#include "../../Graphics/Renderer.h"
-#include "../../Graphics/Texture2DArray.h"
-#include "../../IO/FileSystem.h"
-#include "../../IO/Log.h"
-#include "../../Resource/ResourceCache.h"
-#include "../../Resource/XMLFile.h"
-
-#include "../../DebugNew.h"
-
-#ifdef _MSC_VER
-#pragma warning(disable:4355)
-#endif
-
-namespace Urho3D
-{
-
-void Texture2DArray::OnDeviceLost_D3D9()
-{
-    if (usage_ > TEXTURE_STATIC)
-        Release_D3D9();
-}
-
-void Texture2DArray::OnDeviceReset_D3D9()
-{
-    if (usage_ > TEXTURE_STATIC || !object_.ptr_ || dataPending_)
-    {
-        // If has a resource file, reload through the resource cache. Otherwise just recreate.
-        ResourceCache* cache = GetSubsystem<ResourceCache>();
-        if (cache->Exists(GetName()))
-            dataLost_ = !cache->ReloadResource(this);
-
-        if (!object_.ptr_)
-        {
-            Create_D3D9();
-            dataLost_ = true;
-        }
-    }
-
-    dataPending_ = false;
-}
-
-void Texture2DArray::Release_D3D9()
-{
-    if (graphics_)
-    {
-        for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-        {
-            if (graphics_->GetTexture(i) == this)
-                graphics_->SetTexture(i, nullptr);
-        }
-    }
-
-    if (renderSurface_)
-        renderSurface_->Release();
-
-    URHO3D_SAFE_RELEASE(object_.ptr_);
-}
-
-bool Texture2DArray::SetData_D3D9(unsigned layer, unsigned level, int x, int y, int width, int height, const void* data)
-{
-    URHO3D_LOGERROR("Texture2DArray not supported on Direct3D9, can not set data");
-    return false;
-}
-
-bool Texture2DArray::SetData_D3D9(unsigned layer, Deserializer& source)
-{
-    SharedPtr<Image> image(new Image(context_));
-    if (!image->Load(source))
-        return false;
-
-    return SetData_D3D9(layer, image);
-}
-
-bool Texture2DArray::SetData_D3D9(unsigned layer, Image* image, bool useAlpha)
-{
-    if (!image)
-    {
-        URHO3D_LOGERROR("Null image, can not set data");
-        return false;
-    }
-    if (!layers_)
-    {
-        URHO3D_LOGERROR("Number of layers in the array must be set first");
-        return false;
-    }
-    if (layer >= layers_)
-    {
-        URHO3D_LOGERROR("Illegal layer for setting data");
-        return false;
-    }
-
-    // Use a shared ptr for managing the temporary mip images created during this function
-    SharedPtr<Image> mipImage;
-    unsigned memoryUse = 0;
-    MaterialQuality quality = QUALITY_HIGH;
-    Renderer* renderer = GetSubsystem<Renderer>();
-    if (renderer)
-        quality = renderer->GetTextureQuality();
-
-    if (!image->IsCompressed())
-    {
-        unsigned char* levelData = image->GetData();
-        int levelWidth = image->GetWidth();
-        int levelHeight = image->GetHeight();
-        unsigned components = image->GetComponents();
-        unsigned format = 0;
-
-        // Discard unnecessary mip levels
-        for (unsigned i = 0; i < mipsToSkip_[quality]; ++i)
-        {
-            mipImage = image->GetNextLevel(); image = mipImage;
-            levelData = image->GetData();
-            levelWidth = image->GetWidth();
-            levelHeight = image->GetHeight();
-        }
-
-        switch (components)
-        {
-        case 1:
-            format = Graphics::GetAlphaFormat();
-            break;
-
-        case 4:
-            format = Graphics::GetRGBAFormat();
-            break;
-
-        default: break;
-        }
-
-        // Create the texture array when layer 0 is being loaded, check that rest of the layers are same size & format
-        if (!layer)
-        {
-            // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size
-            if (IsCompressed_D3D9() && requestedLevels_ > 1)
-                requestedLevels_ = 0;
-            // Create the texture array (the number of layers must have been already set)
-            SetSize(0, levelWidth, levelHeight, format);
-        }
-        else
-        {
-            if (!object_.ptr_)
-            {
-                // Do not spam this error on D3D9
-                //URHO3D_LOGERROR("Texture array layer 0 must be loaded first");
-                return false;
-            }
-            if (levelWidth != width_ || levelHeight != height_ || format != format_)
-            {
-                URHO3D_LOGERROR("Texture array layer does not match size or format of layer 0");
-                return false;
-            }
-        }
-
-        for (unsigned i = 0; i < levels_; ++i)
-        {
-            SetData_D3D9(layer, i, 0, 0, levelWidth, levelHeight, levelData);
-            memoryUse += levelWidth * levelHeight * components;
-
-            if (i < levels_ - 1)
-            {
-                mipImage = image->GetNextLevel(); image = mipImage;
-                levelData = image->GetData();
-                levelWidth = image->GetWidth();
-                levelHeight = image->GetHeight();
-            }
-        }
-    }
-    else
-    {
-        int width = image->GetWidth();
-        int height = image->GetHeight();
-        unsigned levels = image->GetNumCompressedLevels();
-        unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
-        bool needDecompress = false;
-
-        if (!format)
-        {
-            format = Graphics::GetRGBAFormat();
-            needDecompress = true;
-        }
-
-        unsigned mipsToSkip = mipsToSkip_[quality];
-        if (mipsToSkip >= levels)
-            mipsToSkip = levels - 1;
-        while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4))
-            --mipsToSkip;
-        width /= (1 << mipsToSkip);
-        height /= (1 << mipsToSkip);
-
-        // Create the texture array when layer 0 is being loaded, assume rest of the layers are same size & format
-        if (!layer)
-        {
-            SetNumLevels(Max((levels - mipsToSkip), 1U));
-            SetSize(0, width, height, format);
-        }
-        else
-        {
-            if (!object_.ptr_)
-            {
-                //URHO3D_LOGERROR("Texture array layer 0 must be loaded first");
-                return false;
-            }
-            if (width != width_ || height != height_ || format != format_)
-            {
-                URHO3D_LOGERROR("Texture array layer does not match size or format of layer 0");
-                return false;
-            }
-        }
-
-        for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i)
-        {
-            CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip);
-            if (!needDecompress)
-            {
-                SetData_D3D9(layer, i, 0, 0, level.width_, level.height_, level.data_);
-                memoryUse += level.rows_ * level.rowSize_;
-            }
-            else
-            {
-                unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4];
-                level.Decompress(rgbaData);
-                SetData_D3D9(layer, i, 0, 0, level.width_, level.height_, rgbaData);
-                memoryUse += level.width_ * level.height_ * 4;
-                delete[] rgbaData;
-            }
-        }
-    }
-
-    layerMemoryUse_[layer] = memoryUse;
-    unsigned totalMemoryUse = sizeof(Texture2DArray) + layerMemoryUse_.Capacity() * sizeof(unsigned);
-    for (unsigned i = 0; i < layers_; ++i)
-        totalMemoryUse += layerMemoryUse_[i];
-    SetMemoryUse(totalMemoryUse);
-
-    return true;
-}
-
-bool Texture2DArray::GetData_D3D9(unsigned layer, unsigned level, void* dest) const
-{
-    URHO3D_LOGERROR("Texture2DArray not supported on Direct3D9, can not get data");
-    return false;
-}
-
-bool Texture2DArray::Create_D3D9()
-{
-    Release_D3D9();
-
-    if (!graphics_ || !width_ || !height_ || !layers_)
-        return false;
-
-    URHO3D_LOGERROR("Texture2DArray not supported on Direct3D9, can not create");
-    return false;
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Core/Context.h"
+#include "../../Core/Profiler.h"
+#include "../../Graphics/Graphics.h"
+#include "../../Graphics/GraphicsEvents.h"
+#include "../../Graphics/Renderer.h"
+#include "../../GraphicsAPI/GraphicsImpl.h"
+#include "../../GraphicsAPI/Texture2DArray.h"
+#include "../../IO/FileSystem.h"
+#include "../../IO/Log.h"
+#include "../../Resource/ResourceCache.h"
+#include "../../Resource/XMLFile.h"
+
+#include "../../DebugNew.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable:4355)
+#endif
+
+namespace Urho3D
+{
+
+void Texture2DArray::OnDeviceLost_D3D9()
+{
+    if (usage_ > TEXTURE_STATIC)
+        Release_D3D9();
+}
+
+void Texture2DArray::OnDeviceReset_D3D9()
+{
+    if (usage_ > TEXTURE_STATIC || !object_.ptr_ || dataPending_)
+    {
+        // If has a resource file, reload through the resource cache. Otherwise just recreate.
+        ResourceCache* cache = GetSubsystem<ResourceCache>();
+        if (cache->Exists(GetName()))
+            dataLost_ = !cache->ReloadResource(this);
+
+        if (!object_.ptr_)
+        {
+            Create_D3D9();
+            dataLost_ = true;
+        }
+    }
+
+    dataPending_ = false;
+}
+
+void Texture2DArray::Release_D3D9()
+{
+    if (graphics_)
+    {
+        for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+        {
+            if (graphics_->GetTexture(i) == this)
+                graphics_->SetTexture(i, nullptr);
+        }
+    }
+
+    if (renderSurface_)
+        renderSurface_->Release();
+
+    URHO3D_SAFE_RELEASE(object_.ptr_);
+}
+
+bool Texture2DArray::SetData_D3D9(unsigned layer, unsigned level, int x, int y, int width, int height, const void* data)
+{
+    URHO3D_LOGERROR("Texture2DArray not supported on Direct3D9, can not set data");
+    return false;
+}
+
+bool Texture2DArray::SetData_D3D9(unsigned layer, Deserializer& source)
+{
+    SharedPtr<Image> image(new Image(context_));
+    if (!image->Load(source))
+        return false;
+
+    return SetData_D3D9(layer, image);
+}
+
+bool Texture2DArray::SetData_D3D9(unsigned layer, Image* image, bool useAlpha)
+{
+    if (!image)
+    {
+        URHO3D_LOGERROR("Null image, can not set data");
+        return false;
+    }
+    if (!layers_)
+    {
+        URHO3D_LOGERROR("Number of layers in the array must be set first");
+        return false;
+    }
+    if (layer >= layers_)
+    {
+        URHO3D_LOGERROR("Illegal layer for setting data");
+        return false;
+    }
+
+    // Use a shared ptr for managing the temporary mip images created during this function
+    SharedPtr<Image> mipImage;
+    unsigned memoryUse = 0;
+    MaterialQuality quality = QUALITY_HIGH;
+    Renderer* renderer = GetSubsystem<Renderer>();
+    if (renderer)
+        quality = renderer->GetTextureQuality();
+
+    if (!image->IsCompressed())
+    {
+        unsigned char* levelData = image->GetData();
+        int levelWidth = image->GetWidth();
+        int levelHeight = image->GetHeight();
+        unsigned components = image->GetComponents();
+        unsigned format = 0;
+
+        // Discard unnecessary mip levels
+        for (unsigned i = 0; i < mipsToSkip_[quality]; ++i)
+        {
+            mipImage = image->GetNextLevel(); image = mipImage;
+            levelData = image->GetData();
+            levelWidth = image->GetWidth();
+            levelHeight = image->GetHeight();
+        }
+
+        switch (components)
+        {
+        case 1:
+            format = Graphics::GetAlphaFormat();
+            break;
+
+        case 4:
+            format = Graphics::GetRGBAFormat();
+            break;
+
+        default: break;
+        }
+
+        // Create the texture array when layer 0 is being loaded, check that rest of the layers are same size & format
+        if (!layer)
+        {
+            // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size
+            if (IsCompressed_D3D9() && requestedLevels_ > 1)
+                requestedLevels_ = 0;
+            // Create the texture array (the number of layers must have been already set)
+            SetSize(0, levelWidth, levelHeight, format);
+        }
+        else
+        {
+            if (!object_.ptr_)
+            {
+                // Do not spam this error on D3D9
+                //URHO3D_LOGERROR("Texture array layer 0 must be loaded first");
+                return false;
+            }
+            if (levelWidth != width_ || levelHeight != height_ || format != format_)
+            {
+                URHO3D_LOGERROR("Texture array layer does not match size or format of layer 0");
+                return false;
+            }
+        }
+
+        for (unsigned i = 0; i < levels_; ++i)
+        {
+            SetData_D3D9(layer, i, 0, 0, levelWidth, levelHeight, levelData);
+            memoryUse += levelWidth * levelHeight * components;
+
+            if (i < levels_ - 1)
+            {
+                mipImage = image->GetNextLevel(); image = mipImage;
+                levelData = image->GetData();
+                levelWidth = image->GetWidth();
+                levelHeight = image->GetHeight();
+            }
+        }
+    }
+    else
+    {
+        int width = image->GetWidth();
+        int height = image->GetHeight();
+        unsigned levels = image->GetNumCompressedLevels();
+        unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
+        bool needDecompress = false;
+
+        if (!format)
+        {
+            format = Graphics::GetRGBAFormat();
+            needDecompress = true;
+        }
+
+        unsigned mipsToSkip = mipsToSkip_[quality];
+        if (mipsToSkip >= levels)
+            mipsToSkip = levels - 1;
+        while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4))
+            --mipsToSkip;
+        width /= (1 << mipsToSkip);
+        height /= (1 << mipsToSkip);
+
+        // Create the texture array when layer 0 is being loaded, assume rest of the layers are same size & format
+        if (!layer)
+        {
+            SetNumLevels(Max((levels - mipsToSkip), 1U));
+            SetSize(0, width, height, format);
+        }
+        else
+        {
+            if (!object_.ptr_)
+            {
+                //URHO3D_LOGERROR("Texture array layer 0 must be loaded first");
+                return false;
+            }
+            if (width != width_ || height != height_ || format != format_)
+            {
+                URHO3D_LOGERROR("Texture array layer does not match size or format of layer 0");
+                return false;
+            }
+        }
+
+        for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i)
+        {
+            CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip);
+            if (!needDecompress)
+            {
+                SetData_D3D9(layer, i, 0, 0, level.width_, level.height_, level.data_);
+                memoryUse += level.rows_ * level.rowSize_;
+            }
+            else
+            {
+                unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4];
+                level.Decompress(rgbaData);
+                SetData_D3D9(layer, i, 0, 0, level.width_, level.height_, rgbaData);
+                memoryUse += level.width_ * level.height_ * 4;
+                delete[] rgbaData;
+            }
+        }
+    }
+
+    layerMemoryUse_[layer] = memoryUse;
+    unsigned totalMemoryUse = sizeof(Texture2DArray) + layerMemoryUse_.Capacity() * sizeof(unsigned);
+    for (unsigned i = 0; i < layers_; ++i)
+        totalMemoryUse += layerMemoryUse_[i];
+    SetMemoryUse(totalMemoryUse);
+
+    return true;
+}
+
+bool Texture2DArray::GetData_D3D9(unsigned layer, unsigned level, void* dest) const
+{
+    URHO3D_LOGERROR("Texture2DArray not supported on Direct3D9, can not get data");
+    return false;
+}
+
+bool Texture2DArray::Create_D3D9()
+{
+    Release_D3D9();
+
+    if (!graphics_ || !width_ || !height_ || !layers_)
+        return false;
+
+    URHO3D_LOGERROR("Texture2DArray not supported on Direct3D9, can not create");
+    return false;
+}
+
+}

+ 2 - 2
Source/Urho3D/Graphics/Direct3D9/D3D9Texture3D.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9Texture3D.cpp

@@ -27,12 +27,12 @@
 #include "../../Graphics/Graphics.h"
 #include "../../Graphics/GraphicsEvents.h"
 #include "../../Graphics/Renderer.h"
-#include "../../Graphics/Texture3D.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9GraphicsImpl.h"
+#include "../../GraphicsAPI/Texture3D.h"
 #include "../../IO/FileSystem.h"
 #include "../../IO/Log.h"
 #include "../../Resource/ResourceCache.h"
 #include "../../Resource/XMLFile.h"
-#include "D3D9GraphicsImpl.h"
 
 #include "../../DebugNew.h"
 

+ 673 - 673
Source/Urho3D/Graphics/Direct3D9/D3D9TextureCube.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9TextureCube.cpp

@@ -1,673 +1,673 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Core/Context.h"
-#include "../../Core/Profiler.h"
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/GraphicsEvents.h"
-#include "../../Graphics/Renderer.h"
-#include "../../Graphics/TextureCube.h"
-#include "../../IO/FileSystem.h"
-#include "../../IO/Log.h"
-#include "../../Resource/ResourceCache.h"
-#include "../../Resource/XMLFile.h"
-#include "D3D9GraphicsImpl.h"
-
-#include "../../DebugNew.h"
-
-#ifdef _MSC_VER
-#pragma warning(disable:4355)
-#endif
-
-namespace Urho3D
-{
-
-void TextureCube::OnDeviceLost_D3D9()
-{
-    if (usage_ > TEXTURE_STATIC)
-        Release_D3D9();
-}
-
-void TextureCube::OnDeviceReset_D3D9()
-{
-    if (usage_ > TEXTURE_STATIC || !object_.ptr_ || dataPending_)
-    {
-        // If has a resource file, reload through the resource cache. Otherwise just recreate.
-        ResourceCache* cache = GetSubsystem<ResourceCache>();
-        if (cache->Exists(GetName()))
-            dataLost_ = !cache->ReloadResource(this);
-
-        if (!object_.ptr_)
-        {
-            Create_D3D9();
-            dataLost_ = true;
-        }
-    }
-
-    dataPending_ = false;
-}
-
-void TextureCube::Release_D3D9()
-{
-    if (graphics_)
-    {
-        for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-        {
-            if (graphics_->GetTexture(i) == this)
-                graphics_->SetTexture(i, nullptr);
-        }
-    }
-
-    for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
-    {
-        if (renderSurfaces_[i])
-            renderSurfaces_[i]->Release();
-    }
-
-    URHO3D_SAFE_RELEASE(object_.ptr_);
-
-    resolveDirty_ = false;
-    levelsDirty_ = false;
-}
-
-bool TextureCube::SetData_D3D9(CubeMapFace face, unsigned level, int x, int y, int width, int height, const void* data)
-{
-    URHO3D_PROFILE(SetTextureData);
-
-    if (!object_.ptr_)
-    {
-        URHO3D_LOGERROR("No texture created, can not set data");
-        return false;
-    }
-
-    if (!data)
-    {
-        URHO3D_LOGERROR("Null source for setting data");
-        return false;
-    }
-
-    if (level >= levels_)
-    {
-        URHO3D_LOGERROR("Illegal mip level for setting data");
-        return false;
-    }
-
-    if (graphics_->IsDeviceLost())
-    {
-        URHO3D_LOGWARNING("Texture data assignment while device is lost");
-        dataPending_ = true;
-        return true;
-    }
-
-    if (IsCompressed_D3D9())
-    {
-        x &= ~3;
-        y &= ~3;
-    }
-
-    int levelWidth = GetLevelWidth(level);
-    int levelHeight = GetLevelHeight(level);
-    if (x < 0 || x + width > levelWidth || y < 0 || y + height > levelHeight || width <= 0 || height <= 0)
-    {
-        URHO3D_LOGERROR("Illegal dimensions for setting data");
-        return false;
-    }
-
-    D3DLOCKED_RECT d3dLockedRect;
-    RECT d3dRect;
-    d3dRect.left = x;
-    d3dRect.top = y;
-    d3dRect.right = x + width;
-    d3dRect.bottom = y + height;
-
-    DWORD flags = 0;
-    if (level == 0 && x == 0 && y == 0 && width == levelWidth && height == levelHeight && usage_ > TEXTURE_STATIC)
-        flags |= D3DLOCK_DISCARD;
-
-    HRESULT hr = ((IDirect3DCubeTexture9*)object_.ptr_)->LockRect((D3DCUBEMAP_FACES)face, level, &d3dLockedRect,
-        (flags & D3DLOCK_DISCARD) ? nullptr : &d3dRect, flags);
-    if (FAILED(hr))
-    {
-        URHO3D_LOGD3DERROR("Could not lock texture", hr);
-        return false;
-    }
-
-    if (IsCompressed_D3D9())
-    {
-        height = (height + 3) >> 2;
-        y >>= 2;
-    }
-
-    unsigned char* src = (unsigned char*)data;
-    unsigned rowSize = GetRowDataSize_D3D9(width);
-
-    // GetRowDataSize_D3D9() returns CPU-side (source) data size, so need to convert for X8R8G8B8
-    if (format_ == D3DFMT_X8R8G8B8)
-        rowSize = rowSize / 3 * 4;
-
-    // Perform conversion from RGB / RGBA as necessary
-    switch (format_)
-    {
-    default:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            memcpy(dest, src, rowSize);
-            src += rowSize;
-        }
-        break;
-
-    case D3DFMT_X8R8G8B8:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            for (int j = 0; j < width; ++j)
-            {
-                *dest++ = src[2];
-                *dest++ = src[1];
-                *dest++ = src[0];
-                *dest++ = 255;
-                src += 3;
-            }
-        }
-        break;
-
-    case D3DFMT_A8R8G8B8:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            for (int j = 0; j < width; ++j)
-            {
-                *dest++ = src[2];
-                *dest++ = src[1];
-                *dest++ = src[0];
-                *dest++ = src[3];
-                src += 4;
-            }
-        }
-        break;
-    }
-
-    ((IDirect3DCubeTexture9*)object_.ptr_)->UnlockRect((D3DCUBEMAP_FACES)face, level);
-    return true;
-}
-
-bool TextureCube::SetData_D3D9(CubeMapFace face, Deserializer& source)
-{
-    SharedPtr<Image> image(new Image(context_));
-    if (!image->Load(source))
-        return false;
-
-    return SetData_D3D9(face, image);
-}
-
-bool TextureCube::SetData_D3D9(CubeMapFace face, Image* image, bool useAlpha)
-{
-    if (!image)
-    {
-        URHO3D_LOGERROR("Null image, can not load texture");
-        return false;
-    }
-
-    // Use a shared ptr for managing the temporary mip images created during this function
-    SharedPtr<Image> mipImage;
-    unsigned memoryUse = 0;
-    MaterialQuality quality = QUALITY_HIGH;
-    Renderer* renderer = GetSubsystem<Renderer>();
-    if (renderer)
-        quality = renderer->GetTextureQuality();
-
-    if (!image->IsCompressed())
-    {
-        unsigned char* levelData = image->GetData();
-        int levelWidth = image->GetWidth();
-        int levelHeight = image->GetHeight();
-        unsigned components = image->GetComponents();
-        unsigned format = 0;
-
-        if (levelWidth != levelHeight)
-        {
-            URHO3D_LOGERROR("Cube texture width not equal to height");
-            return false;
-        }
-
-        // Discard unnecessary mip levels
-        for (unsigned i = 0; i < mipsToSkip_[quality]; ++i)
-        {
-            mipImage = image->GetNextLevel(); image = mipImage;
-            levelData = image->GetData();
-            levelWidth = image->GetWidth();
-            levelHeight = image->GetHeight();
-        }
-
-        switch (components)
-        {
-        case 1:
-            format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat();
-            break;
-
-        case 2:
-            format = Graphics::GetLuminanceAlphaFormat();
-            break;
-
-        case 3:
-            format = Graphics::GetRGBFormat();
-            break;
-
-        case 4:
-            format = Graphics::GetRGBAFormat();
-            break;
-
-        default:
-            assert(false);  // Should never reach here
-            break;
-        }
-
-        // Create the texture when face 0 is being loaded, check that rest of the faces are same size & format
-        if (!face)
-        {
-            // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size
-            if (IsCompressed_D3D9() && requestedLevels_ > 1)
-                requestedLevels_ = 0;
-            SetSize(levelWidth, format);
-        }
-        else
-        {
-            if (!object_.ptr_)
-            {
-                URHO3D_LOGERROR("Cube texture face 0 must be loaded first");
-                return false;
-            }
-            if (levelWidth != width_ || format != format_)
-            {
-                URHO3D_LOGERROR("Cube texture face does not match size or format of face 0");
-                return false;
-            }
-        }
-
-        for (unsigned i = 0; i < levels_; ++i)
-        {
-            SetData_D3D9(face, i, 0, 0, levelWidth, levelHeight, levelData);
-            memoryUse += levelWidth * levelHeight * components;
-
-            if (i < levels_ - 1)
-            {
-                mipImage = image->GetNextLevel(); image = mipImage;
-                levelData = image->GetData();
-                levelWidth = image->GetWidth();
-                levelHeight = image->GetHeight();
-            }
-        }
-    }
-    else
-    {
-        int width = image->GetWidth();
-        int height = image->GetHeight();
-        unsigned levels = image->GetNumCompressedLevels();
-        unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
-        bool needDecompress = false;
-
-        if (width != height)
-        {
-            URHO3D_LOGERROR("Cube texture width not equal to height");
-            return false;
-        }
-
-        if (!format)
-        {
-            format = Graphics::GetRGBAFormat();
-            needDecompress = true;
-        }
-
-        unsigned mipsToSkip = mipsToSkip_[quality];
-        if (mipsToSkip >= levels)
-            mipsToSkip = levels - 1;
-        while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4))
-            --mipsToSkip;
-        width /= (1 << mipsToSkip);
-        height /= (1 << mipsToSkip);
-
-        // Create the texture when face 0 is being loaded, assume rest of the faces are same size & format
-        if (!face)
-        {
-            SetNumLevels(Max((levels - mipsToSkip), 1U));
-            SetSize(width, format);
-        }
-        else
-        {
-            if (!object_.ptr_)
-            {
-                URHO3D_LOGERROR("Cube texture face 0 must be loaded first");
-                return false;
-            }
-            if (width != width_ || format != format_)
-            {
-                URHO3D_LOGERROR("Cube texture face does not match size or format of face 0");
-                return false;
-            }
-        }
-
-        for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i)
-        {
-            CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip);
-            if (!needDecompress)
-            {
-                SetData_D3D9(face, i, 0, 0, level.width_, level.height_, level.data_);
-                memoryUse += level.rows_ * level.rowSize_;
-            }
-            else
-            {
-                unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4];
-                level.Decompress(rgbaData);
-                SetData_D3D9(face, i, 0, 0, level.width_, level.height_, rgbaData);
-                memoryUse += level.width_ * level.height_ * 4;
-                delete[] rgbaData;
-            }
-        }
-    }
-
-    faceMemoryUse_[face] = memoryUse;
-    unsigned totalMemoryUse = sizeof(TextureCube);
-    for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
-        totalMemoryUse += faceMemoryUse_[i];
-    SetMemoryUse(totalMemoryUse);
-
-    return true;
-}
-
-bool TextureCube::GetData_D3D9(CubeMapFace face, unsigned level, void* dest) const
-{
-    if (!object_.ptr_)
-    {
-        URHO3D_LOGERROR("No texture created, can not get data");
-        return false;
-    }
-
-    if (!dest)
-    {
-        URHO3D_LOGERROR("Null destination for getting data");
-        return false;
-    }
-
-    if (level >= levels_)
-    {
-        URHO3D_LOGERROR("Illegal mip level for getting data");
-        return false;
-    }
-
-    if (graphics_->IsDeviceLost())
-    {
-        URHO3D_LOGWARNING("Getting texture data while device is lost");
-        return false;
-    }
-
-    if (resolveDirty_)
-        graphics_->ResolveToTexture(const_cast<TextureCube*>(this));
-
-    int levelWidth = GetLevelWidth(level);
-    int levelHeight = GetLevelHeight(level);
-
-    D3DLOCKED_RECT d3dLockedRect;
-    RECT d3dRect;
-    d3dRect.left = 0;
-    d3dRect.top = 0;
-    d3dRect.right = levelWidth;
-    d3dRect.bottom = levelHeight;
-
-    IDirect3DSurface9* offscreenSurface = nullptr;
-    // Need to use a offscreen surface & GetRenderTargetData() for rendertargets
-    if (renderSurfaces_[face])
-    {
-        if (level != 0)
-        {
-            URHO3D_LOGERROR("Can only get mip level 0 data from a rendertarget");
-            return false;
-        }
-
-        // If multisampled, must copy the surface of the resolve texture instead of the multisampled surface
-        IDirect3DSurface9* resolveSurface = nullptr;
-        if (multiSample_ > 1)
-        {
-            HRESULT hr = ((IDirect3DCubeTexture9*)object_.ptr_)->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0,
-                (IDirect3DSurface9**)&resolveSurface);
-            if (FAILED(hr))
-            {
-                URHO3D_LOGD3DERROR("Could not get surface of the resolve texture", hr);
-                URHO3D_SAFE_RELEASE(resolveSurface);
-                return false;
-            }
-        }
-
-        IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
-        HRESULT hr = device->CreateOffscreenPlainSurface((UINT)width_, (UINT)height_, (D3DFORMAT)format_, D3DPOOL_SYSTEMMEM, &offscreenSurface, nullptr);
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Could not create surface for getting rendertarget data", hr);
-            URHO3D_SAFE_RELEASE(offscreenSurface);
-            URHO3D_SAFE_RELEASE(resolveSurface);
-            return false;
-        }
-
-        if (resolveSurface)
-            hr = device->GetRenderTargetData(resolveSurface, offscreenSurface);
-        else
-            hr = device->GetRenderTargetData((IDirect3DSurface9*)renderSurfaces_[face]->GetSurface(), offscreenSurface);
-        URHO3D_SAFE_RELEASE(resolveSurface);
-
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Could not get rendertarget data", hr);
-            URHO3D_SAFE_RELEASE(offscreenSurface);
-            return false;
-        }
-        if (FAILED(offscreenSurface->LockRect(&d3dLockedRect, &d3dRect, D3DLOCK_READONLY)))
-        {
-            URHO3D_LOGD3DERROR("Could not lock surface for getting rendertarget data", hr);
-            URHO3D_SAFE_RELEASE(offscreenSurface);
-            return false;
-        }
-    }
-    else
-    {
-        HRESULT hr = ((IDirect3DCubeTexture9*)object_.ptr_)->LockRect((D3DCUBEMAP_FACES)face, level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
-        if (FAILED(hr))
-        {
-            URHO3D_LOGD3DERROR("Could not lock texture", hr);
-            return false;
-        }
-    }
-
-    int height = levelHeight;
-    if (IsCompressed_D3D9())
-        height = (height + 3) >> 2;
-
-    unsigned char* destPtr = (unsigned char*)dest;
-    unsigned rowSize = GetRowDataSize_D3D9(levelWidth);
-    // GetRowDataSize_D3D9() returns CPU-side (destination) data size, so need to convert for X8R8G8B8
-    if (format_ == D3DFMT_X8R8G8B8)
-        rowSize = rowSize / 3 * 4;
-
-    // Perform conversion to RGB / RGBA as necessary
-    switch (format_)
-    {
-    default:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            memcpy(destPtr, src, rowSize);
-            destPtr += rowSize;
-        }
-        break;
-
-    case D3DFMT_X8R8G8B8:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            for (int j = 0; j < levelWidth; ++j)
-            {
-                destPtr[2] = *src++;
-                destPtr[1] = *src++;
-                destPtr[0] = *src++;
-                ++src;
-                destPtr += 3;
-            }
-        }
-        break;
-
-    case D3DFMT_A8R8G8B8:
-        for (int i = 0; i < height; ++i)
-        {
-            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
-            for (int j = 0; j < levelWidth; ++j)
-            {
-                destPtr[2] = *src++;
-                destPtr[1] = *src++;
-                destPtr[0] = *src++;
-                destPtr[3] = *src++;
-                destPtr += 4;
-            }
-        }
-        break;
-    }
-
-    if (offscreenSurface)
-        offscreenSurface->UnlockRect();
-    else
-        ((IDirect3DCubeTexture9*)object_.ptr_)->UnlockRect((D3DCUBEMAP_FACES)face, level);
-
-    URHO3D_SAFE_RELEASE(offscreenSurface);
-    return true;
-}
-
-bool TextureCube::Create_D3D9()
-{
-    Release_D3D9();
-
-    if (!graphics_ || !width_ || !height_)
-        return false;
-
-    if (graphics_->IsDeviceLost())
-    {
-        URHO3D_LOGWARNING("Texture creation while device is lost");
-        return true;
-    }
-
-    GraphicsImpl_D3D9* impl = graphics_->GetImpl_D3D9();
-
-    unsigned pool = usage_ > TEXTURE_STATIC ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
-    unsigned d3dUsage = 0;
-
-    switch (usage_)
-    {
-    case TEXTURE_DYNAMIC:
-        d3dUsage |= D3DUSAGE_DYNAMIC;
-        break;
-    case TEXTURE_RENDERTARGET:
-        d3dUsage |= D3DUSAGE_RENDERTARGET;
-        if (requestedLevels_ != 1)
-        {
-            // Check mipmap autogeneration support
-            if (impl->CheckFormatSupport((D3DFORMAT)format_, D3DUSAGE_AUTOGENMIPMAP, D3DRTYPE_TEXTURE))
-            {
-                requestedLevels_ = 0;
-                d3dUsage |= D3DUSAGE_AUTOGENMIPMAP;
-            }
-            else
-                requestedLevels_ = 1;
-        }
-        break;
-    default:
-        break;
-    }
-
-    if (multiSample_ > 1)
-    {
-        // Fall back to non-multisampled if unsupported multisampling mode
-        GraphicsImpl_D3D9* impl = graphics_->GetImpl_D3D9();
-        if (!impl->CheckMultiSampleSupport((D3DFORMAT)format_, multiSample_))
-        {
-            multiSample_ = 1;
-            autoResolve_ = false;
-        }
-    }
-
-    IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
-    HRESULT hr = device->CreateCubeTexture(
-        (UINT)width_,
-        requestedLevels_,
-        d3dUsage,
-        (D3DFORMAT)format_,
-        (D3DPOOL)pool,
-        (IDirect3DCubeTexture9**)&object_.ptr_,
-        nullptr);
-    if (FAILED(hr))
-    {
-        URHO3D_LOGD3DERROR("Could not create cube texture", hr);
-        URHO3D_SAFE_RELEASE(object_.ptr_);
-        return false;
-    }
-
-    levels_ = ((IDirect3DCubeTexture9*)object_.ptr_)->GetLevelCount();
-
-    if (usage_ == TEXTURE_RENDERTARGET)
-    {
-        for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
-        {
-            if (multiSample_ > 1)
-            {
-                // Create the multisampled face rendertarget if necessary
-                HRESULT hr = device->CreateRenderTarget(
-                    (UINT)width_,
-                    (UINT)height_,
-                    (D3DFORMAT)format_,
-                    (D3DMULTISAMPLE_TYPE)multiSample_,
-                    0,
-                    FALSE,
-                    (IDirect3DSurface9**)&renderSurfaces_[i]->surface_,
-                    nullptr);
-                if (FAILED(hr))
-                {
-                    URHO3D_LOGD3DERROR("Could not create multisampled rendertarget surface", hr);
-                    URHO3D_SAFE_RELEASE(renderSurfaces_[i]->surface_);
-                    return false;
-                }
-            }
-            else
-            {
-                hr = ((IDirect3DCubeTexture9*)object_.ptr_)->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0,
-                    (IDirect3DSurface9**)&renderSurfaces_[i]->surface_);
-                if (FAILED(hr))
-                {
-                    URHO3D_LOGD3DERROR("Could not get rendertarget surface", hr);
-                    URHO3D_SAFE_RELEASE(renderSurfaces_[i]->surface_);
-                    return false;
-                }
-            }
-        }
-    }
-
-    return true;
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Core/Context.h"
+#include "../../Core/Profiler.h"
+#include "../../Graphics/Graphics.h"
+#include "../../Graphics/GraphicsEvents.h"
+#include "../../Graphics/Renderer.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9GraphicsImpl.h"
+#include "../../GraphicsAPI/TextureCube.h"
+#include "../../IO/FileSystem.h"
+#include "../../IO/Log.h"
+#include "../../Resource/ResourceCache.h"
+#include "../../Resource/XMLFile.h"
+
+#include "../../DebugNew.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable:4355)
+#endif
+
+namespace Urho3D
+{
+
+void TextureCube::OnDeviceLost_D3D9()
+{
+    if (usage_ > TEXTURE_STATIC)
+        Release_D3D9();
+}
+
+void TextureCube::OnDeviceReset_D3D9()
+{
+    if (usage_ > TEXTURE_STATIC || !object_.ptr_ || dataPending_)
+    {
+        // If has a resource file, reload through the resource cache. Otherwise just recreate.
+        ResourceCache* cache = GetSubsystem<ResourceCache>();
+        if (cache->Exists(GetName()))
+            dataLost_ = !cache->ReloadResource(this);
+
+        if (!object_.ptr_)
+        {
+            Create_D3D9();
+            dataLost_ = true;
+        }
+    }
+
+    dataPending_ = false;
+}
+
+void TextureCube::Release_D3D9()
+{
+    if (graphics_)
+    {
+        for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+        {
+            if (graphics_->GetTexture(i) == this)
+                graphics_->SetTexture(i, nullptr);
+        }
+    }
+
+    for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
+    {
+        if (renderSurfaces_[i])
+            renderSurfaces_[i]->Release();
+    }
+
+    URHO3D_SAFE_RELEASE(object_.ptr_);
+
+    resolveDirty_ = false;
+    levelsDirty_ = false;
+}
+
+bool TextureCube::SetData_D3D9(CubeMapFace face, unsigned level, int x, int y, int width, int height, const void* data)
+{
+    URHO3D_PROFILE(SetTextureData);
+
+    if (!object_.ptr_)
+    {
+        URHO3D_LOGERROR("No texture created, can not set data");
+        return false;
+    }
+
+    if (!data)
+    {
+        URHO3D_LOGERROR("Null source for setting data");
+        return false;
+    }
+
+    if (level >= levels_)
+    {
+        URHO3D_LOGERROR("Illegal mip level for setting data");
+        return false;
+    }
+
+    if (graphics_->IsDeviceLost())
+    {
+        URHO3D_LOGWARNING("Texture data assignment while device is lost");
+        dataPending_ = true;
+        return true;
+    }
+
+    if (IsCompressed_D3D9())
+    {
+        x &= ~3;
+        y &= ~3;
+    }
+
+    int levelWidth = GetLevelWidth(level);
+    int levelHeight = GetLevelHeight(level);
+    if (x < 0 || x + width > levelWidth || y < 0 || y + height > levelHeight || width <= 0 || height <= 0)
+    {
+        URHO3D_LOGERROR("Illegal dimensions for setting data");
+        return false;
+    }
+
+    D3DLOCKED_RECT d3dLockedRect;
+    RECT d3dRect;
+    d3dRect.left = x;
+    d3dRect.top = y;
+    d3dRect.right = x + width;
+    d3dRect.bottom = y + height;
+
+    DWORD flags = 0;
+    if (level == 0 && x == 0 && y == 0 && width == levelWidth && height == levelHeight && usage_ > TEXTURE_STATIC)
+        flags |= D3DLOCK_DISCARD;
+
+    HRESULT hr = ((IDirect3DCubeTexture9*)object_.ptr_)->LockRect((D3DCUBEMAP_FACES)face, level, &d3dLockedRect,
+        (flags & D3DLOCK_DISCARD) ? nullptr : &d3dRect, flags);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Could not lock texture", hr);
+        return false;
+    }
+
+    if (IsCompressed_D3D9())
+    {
+        height = (height + 3) >> 2;
+        y >>= 2;
+    }
+
+    unsigned char* src = (unsigned char*)data;
+    unsigned rowSize = GetRowDataSize_D3D9(width);
+
+    // GetRowDataSize_D3D9() returns CPU-side (source) data size, so need to convert for X8R8G8B8
+    if (format_ == D3DFMT_X8R8G8B8)
+        rowSize = rowSize / 3 * 4;
+
+    // Perform conversion from RGB / RGBA as necessary
+    switch (format_)
+    {
+    default:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            memcpy(dest, src, rowSize);
+            src += rowSize;
+        }
+        break;
+
+    case D3DFMT_X8R8G8B8:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            for (int j = 0; j < width; ++j)
+            {
+                *dest++ = src[2];
+                *dest++ = src[1];
+                *dest++ = src[0];
+                *dest++ = 255;
+                src += 3;
+            }
+        }
+        break;
+
+    case D3DFMT_A8R8G8B8:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* dest = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            for (int j = 0; j < width; ++j)
+            {
+                *dest++ = src[2];
+                *dest++ = src[1];
+                *dest++ = src[0];
+                *dest++ = src[3];
+                src += 4;
+            }
+        }
+        break;
+    }
+
+    ((IDirect3DCubeTexture9*)object_.ptr_)->UnlockRect((D3DCUBEMAP_FACES)face, level);
+    return true;
+}
+
+bool TextureCube::SetData_D3D9(CubeMapFace face, Deserializer& source)
+{
+    SharedPtr<Image> image(new Image(context_));
+    if (!image->Load(source))
+        return false;
+
+    return SetData_D3D9(face, image);
+}
+
+bool TextureCube::SetData_D3D9(CubeMapFace face, Image* image, bool useAlpha)
+{
+    if (!image)
+    {
+        URHO3D_LOGERROR("Null image, can not load texture");
+        return false;
+    }
+
+    // Use a shared ptr for managing the temporary mip images created during this function
+    SharedPtr<Image> mipImage;
+    unsigned memoryUse = 0;
+    MaterialQuality quality = QUALITY_HIGH;
+    Renderer* renderer = GetSubsystem<Renderer>();
+    if (renderer)
+        quality = renderer->GetTextureQuality();
+
+    if (!image->IsCompressed())
+    {
+        unsigned char* levelData = image->GetData();
+        int levelWidth = image->GetWidth();
+        int levelHeight = image->GetHeight();
+        unsigned components = image->GetComponents();
+        unsigned format = 0;
+
+        if (levelWidth != levelHeight)
+        {
+            URHO3D_LOGERROR("Cube texture width not equal to height");
+            return false;
+        }
+
+        // Discard unnecessary mip levels
+        for (unsigned i = 0; i < mipsToSkip_[quality]; ++i)
+        {
+            mipImage = image->GetNextLevel(); image = mipImage;
+            levelData = image->GetData();
+            levelWidth = image->GetWidth();
+            levelHeight = image->GetHeight();
+        }
+
+        switch (components)
+        {
+        case 1:
+            format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat();
+            break;
+
+        case 2:
+            format = Graphics::GetLuminanceAlphaFormat();
+            break;
+
+        case 3:
+            format = Graphics::GetRGBFormat();
+            break;
+
+        case 4:
+            format = Graphics::GetRGBAFormat();
+            break;
+
+        default:
+            assert(false);  // Should never reach here
+            break;
+        }
+
+        // Create the texture when face 0 is being loaded, check that rest of the faces are same size & format
+        if (!face)
+        {
+            // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size
+            if (IsCompressed_D3D9() && requestedLevels_ > 1)
+                requestedLevels_ = 0;
+            SetSize(levelWidth, format);
+        }
+        else
+        {
+            if (!object_.ptr_)
+            {
+                URHO3D_LOGERROR("Cube texture face 0 must be loaded first");
+                return false;
+            }
+            if (levelWidth != width_ || format != format_)
+            {
+                URHO3D_LOGERROR("Cube texture face does not match size or format of face 0");
+                return false;
+            }
+        }
+
+        for (unsigned i = 0; i < levels_; ++i)
+        {
+            SetData_D3D9(face, i, 0, 0, levelWidth, levelHeight, levelData);
+            memoryUse += levelWidth * levelHeight * components;
+
+            if (i < levels_ - 1)
+            {
+                mipImage = image->GetNextLevel(); image = mipImage;
+                levelData = image->GetData();
+                levelWidth = image->GetWidth();
+                levelHeight = image->GetHeight();
+            }
+        }
+    }
+    else
+    {
+        int width = image->GetWidth();
+        int height = image->GetHeight();
+        unsigned levels = image->GetNumCompressedLevels();
+        unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
+        bool needDecompress = false;
+
+        if (width != height)
+        {
+            URHO3D_LOGERROR("Cube texture width not equal to height");
+            return false;
+        }
+
+        if (!format)
+        {
+            format = Graphics::GetRGBAFormat();
+            needDecompress = true;
+        }
+
+        unsigned mipsToSkip = mipsToSkip_[quality];
+        if (mipsToSkip >= levels)
+            mipsToSkip = levels - 1;
+        while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4))
+            --mipsToSkip;
+        width /= (1 << mipsToSkip);
+        height /= (1 << mipsToSkip);
+
+        // Create the texture when face 0 is being loaded, assume rest of the faces are same size & format
+        if (!face)
+        {
+            SetNumLevels(Max((levels - mipsToSkip), 1U));
+            SetSize(width, format);
+        }
+        else
+        {
+            if (!object_.ptr_)
+            {
+                URHO3D_LOGERROR("Cube texture face 0 must be loaded first");
+                return false;
+            }
+            if (width != width_ || format != format_)
+            {
+                URHO3D_LOGERROR("Cube texture face does not match size or format of face 0");
+                return false;
+            }
+        }
+
+        for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i)
+        {
+            CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip);
+            if (!needDecompress)
+            {
+                SetData_D3D9(face, i, 0, 0, level.width_, level.height_, level.data_);
+                memoryUse += level.rows_ * level.rowSize_;
+            }
+            else
+            {
+                unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4];
+                level.Decompress(rgbaData);
+                SetData_D3D9(face, i, 0, 0, level.width_, level.height_, rgbaData);
+                memoryUse += level.width_ * level.height_ * 4;
+                delete[] rgbaData;
+            }
+        }
+    }
+
+    faceMemoryUse_[face] = memoryUse;
+    unsigned totalMemoryUse = sizeof(TextureCube);
+    for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
+        totalMemoryUse += faceMemoryUse_[i];
+    SetMemoryUse(totalMemoryUse);
+
+    return true;
+}
+
+bool TextureCube::GetData_D3D9(CubeMapFace face, unsigned level, void* dest) const
+{
+    if (!object_.ptr_)
+    {
+        URHO3D_LOGERROR("No texture created, can not get data");
+        return false;
+    }
+
+    if (!dest)
+    {
+        URHO3D_LOGERROR("Null destination for getting data");
+        return false;
+    }
+
+    if (level >= levels_)
+    {
+        URHO3D_LOGERROR("Illegal mip level for getting data");
+        return false;
+    }
+
+    if (graphics_->IsDeviceLost())
+    {
+        URHO3D_LOGWARNING("Getting texture data while device is lost");
+        return false;
+    }
+
+    if (resolveDirty_)
+        graphics_->ResolveToTexture(const_cast<TextureCube*>(this));
+
+    int levelWidth = GetLevelWidth(level);
+    int levelHeight = GetLevelHeight(level);
+
+    D3DLOCKED_RECT d3dLockedRect;
+    RECT d3dRect;
+    d3dRect.left = 0;
+    d3dRect.top = 0;
+    d3dRect.right = levelWidth;
+    d3dRect.bottom = levelHeight;
+
+    IDirect3DSurface9* offscreenSurface = nullptr;
+    // Need to use a offscreen surface & GetRenderTargetData() for rendertargets
+    if (renderSurfaces_[face])
+    {
+        if (level != 0)
+        {
+            URHO3D_LOGERROR("Can only get mip level 0 data from a rendertarget");
+            return false;
+        }
+
+        // If multisampled, must copy the surface of the resolve texture instead of the multisampled surface
+        IDirect3DSurface9* resolveSurface = nullptr;
+        if (multiSample_ > 1)
+        {
+            HRESULT hr = ((IDirect3DCubeTexture9*)object_.ptr_)->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0,
+                (IDirect3DSurface9**)&resolveSurface);
+            if (FAILED(hr))
+            {
+                URHO3D_LOGD3DERROR("Could not get surface of the resolve texture", hr);
+                URHO3D_SAFE_RELEASE(resolveSurface);
+                return false;
+            }
+        }
+
+        IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
+        HRESULT hr = device->CreateOffscreenPlainSurface((UINT)width_, (UINT)height_, (D3DFORMAT)format_, D3DPOOL_SYSTEMMEM, &offscreenSurface, nullptr);
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Could not create surface for getting rendertarget data", hr);
+            URHO3D_SAFE_RELEASE(offscreenSurface);
+            URHO3D_SAFE_RELEASE(resolveSurface);
+            return false;
+        }
+
+        if (resolveSurface)
+            hr = device->GetRenderTargetData(resolveSurface, offscreenSurface);
+        else
+            hr = device->GetRenderTargetData((IDirect3DSurface9*)renderSurfaces_[face]->GetSurface(), offscreenSurface);
+        URHO3D_SAFE_RELEASE(resolveSurface);
+
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Could not get rendertarget data", hr);
+            URHO3D_SAFE_RELEASE(offscreenSurface);
+            return false;
+        }
+        if (FAILED(offscreenSurface->LockRect(&d3dLockedRect, &d3dRect, D3DLOCK_READONLY)))
+        {
+            URHO3D_LOGD3DERROR("Could not lock surface for getting rendertarget data", hr);
+            URHO3D_SAFE_RELEASE(offscreenSurface);
+            return false;
+        }
+    }
+    else
+    {
+        HRESULT hr = ((IDirect3DCubeTexture9*)object_.ptr_)->LockRect((D3DCUBEMAP_FACES)face, level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Could not lock texture", hr);
+            return false;
+        }
+    }
+
+    int height = levelHeight;
+    if (IsCompressed_D3D9())
+        height = (height + 3) >> 2;
+
+    unsigned char* destPtr = (unsigned char*)dest;
+    unsigned rowSize = GetRowDataSize_D3D9(levelWidth);
+    // GetRowDataSize_D3D9() returns CPU-side (destination) data size, so need to convert for X8R8G8B8
+    if (format_ == D3DFMT_X8R8G8B8)
+        rowSize = rowSize / 3 * 4;
+
+    // Perform conversion to RGB / RGBA as necessary
+    switch (format_)
+    {
+    default:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            memcpy(destPtr, src, rowSize);
+            destPtr += rowSize;
+        }
+        break;
+
+    case D3DFMT_X8R8G8B8:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            for (int j = 0; j < levelWidth; ++j)
+            {
+                destPtr[2] = *src++;
+                destPtr[1] = *src++;
+                destPtr[0] = *src++;
+                ++src;
+                destPtr += 3;
+            }
+        }
+        break;
+
+    case D3DFMT_A8R8G8B8:
+        for (int i = 0; i < height; ++i)
+        {
+            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
+            for (int j = 0; j < levelWidth; ++j)
+            {
+                destPtr[2] = *src++;
+                destPtr[1] = *src++;
+                destPtr[0] = *src++;
+                destPtr[3] = *src++;
+                destPtr += 4;
+            }
+        }
+        break;
+    }
+
+    if (offscreenSurface)
+        offscreenSurface->UnlockRect();
+    else
+        ((IDirect3DCubeTexture9*)object_.ptr_)->UnlockRect((D3DCUBEMAP_FACES)face, level);
+
+    URHO3D_SAFE_RELEASE(offscreenSurface);
+    return true;
+}
+
+bool TextureCube::Create_D3D9()
+{
+    Release_D3D9();
+
+    if (!graphics_ || !width_ || !height_)
+        return false;
+
+    if (graphics_->IsDeviceLost())
+    {
+        URHO3D_LOGWARNING("Texture creation while device is lost");
+        return true;
+    }
+
+    GraphicsImpl_D3D9* impl = graphics_->GetImpl_D3D9();
+
+    unsigned pool = usage_ > TEXTURE_STATIC ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
+    unsigned d3dUsage = 0;
+
+    switch (usage_)
+    {
+    case TEXTURE_DYNAMIC:
+        d3dUsage |= D3DUSAGE_DYNAMIC;
+        break;
+    case TEXTURE_RENDERTARGET:
+        d3dUsage |= D3DUSAGE_RENDERTARGET;
+        if (requestedLevels_ != 1)
+        {
+            // Check mipmap autogeneration support
+            if (impl->CheckFormatSupport((D3DFORMAT)format_, D3DUSAGE_AUTOGENMIPMAP, D3DRTYPE_TEXTURE))
+            {
+                requestedLevels_ = 0;
+                d3dUsage |= D3DUSAGE_AUTOGENMIPMAP;
+            }
+            else
+                requestedLevels_ = 1;
+        }
+        break;
+    default:
+        break;
+    }
+
+    if (multiSample_ > 1)
+    {
+        // Fall back to non-multisampled if unsupported multisampling mode
+        GraphicsImpl_D3D9* impl = graphics_->GetImpl_D3D9();
+        if (!impl->CheckMultiSampleSupport((D3DFORMAT)format_, multiSample_))
+        {
+            multiSample_ = 1;
+            autoResolve_ = false;
+        }
+    }
+
+    IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
+    HRESULT hr = device->CreateCubeTexture(
+        (UINT)width_,
+        requestedLevels_,
+        d3dUsage,
+        (D3DFORMAT)format_,
+        (D3DPOOL)pool,
+        (IDirect3DCubeTexture9**)&object_.ptr_,
+        nullptr);
+    if (FAILED(hr))
+    {
+        URHO3D_LOGD3DERROR("Could not create cube texture", hr);
+        URHO3D_SAFE_RELEASE(object_.ptr_);
+        return false;
+    }
+
+    levels_ = ((IDirect3DCubeTexture9*)object_.ptr_)->GetLevelCount();
+
+    if (usage_ == TEXTURE_RENDERTARGET)
+    {
+        for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
+        {
+            if (multiSample_ > 1)
+            {
+                // Create the multisampled face rendertarget if necessary
+                HRESULT hr = device->CreateRenderTarget(
+                    (UINT)width_,
+                    (UINT)height_,
+                    (D3DFORMAT)format_,
+                    (D3DMULTISAMPLE_TYPE)multiSample_,
+                    0,
+                    FALSE,
+                    (IDirect3DSurface9**)&renderSurfaces_[i]->surface_,
+                    nullptr);
+                if (FAILED(hr))
+                {
+                    URHO3D_LOGD3DERROR("Could not create multisampled rendertarget surface", hr);
+                    URHO3D_SAFE_RELEASE(renderSurfaces_[i]->surface_);
+                    return false;
+                }
+            }
+            else
+            {
+                hr = ((IDirect3DCubeTexture9*)object_.ptr_)->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0,
+                    (IDirect3DSurface9**)&renderSurfaces_[i]->surface_);
+                if (FAILED(hr))
+                {
+                    URHO3D_LOGD3DERROR("Could not get rendertarget surface", hr);
+                    URHO3D_SAFE_RELEASE(renderSurfaces_[i]->surface_);
+                    return false;
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+}

+ 307 - 307
Source/Urho3D/Graphics/Direct3D9/D3D9VertexBuffer.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9VertexBuffer.cpp

@@ -1,307 +1,307 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/VertexBuffer.h"
-#include "../../IO/Log.h"
-#include "D3D9GraphicsImpl.h"
-
-#include "../../DebugNew.h"
-
-namespace Urho3D
-{
-
-void VertexBuffer::OnDeviceLost_D3D9()
-{
-    // Dynamic buffers are in the default pool and need to be released on device loss
-    if (dynamic_)
-        Release_D3D9();
-}
-
-void VertexBuffer::OnDeviceReset_D3D9()
-{
-    // Dynamic buffers are in the default pool and need to be recreated after device reset
-    if (dynamic_ || !object_.ptr_)
-    {
-        Create_D3D9();
-        dataLost_ = !UpdateToGPU_D3D9();
-    }
-    else if (dataPending_)
-        dataLost_ = !UpdateToGPU_D3D9();
-
-    dataPending_ = false;
-}
-
-void VertexBuffer::Release_D3D9()
-{
-    Unlock_D3D9();
-
-    if (graphics_)
-    {
-        for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
-        {
-            if (graphics_->GetVertexBuffer(i) == this)
-                graphics_->SetVertexBuffer(nullptr);
-        }
-    }
-
-    URHO3D_SAFE_RELEASE(object_.ptr_);
-}
-
-bool VertexBuffer::SetData_D3D9(const void* data)
-{
-    if (!data)
-    {
-        URHO3D_LOGERROR("Null pointer for vertex buffer data");
-        return false;
-    }
-
-    if (!vertexSize_)
-    {
-        URHO3D_LOGERROR("Vertex elements not defined, can not set vertex buffer data");
-        return false;
-    }
-
-    if (shadowData_ && data != shadowData_.Get())
-        memcpy(shadowData_.Get(), data, vertexCount_ * vertexSize_);
-
-    if (object_.ptr_)
-    {
-        if (graphics_->IsDeviceLost())
-        {
-            URHO3D_LOGWARNING("Vertex buffer data assignment while device is lost");
-            dataPending_ = true;
-            return true;
-        }
-
-        void* hwData = MapBuffer_D3D9(0, vertexCount_, true);
-        if (hwData)
-        {
-            memcpy(hwData, data, vertexCount_ * vertexSize_);
-            UnmapBuffer_D3D9();
-        }
-        else
-            return false;
-    }
-
-    dataLost_ = false;
-    return true;
-}
-
-bool VertexBuffer::SetDataRange_D3D9(const void* data, unsigned start, unsigned count, bool discard)
-{
-    if (start == 0 && count == vertexCount_)
-        return SetData_D3D9(data);
-
-    if (!data)
-    {
-        URHO3D_LOGERROR("Null pointer for vertex buffer data");
-        return false;
-    }
-
-    if (!vertexSize_)
-    {
-        URHO3D_LOGERROR("Vertex elements not defined, can not set vertex buffer data");
-        return false;
-    }
-
-    if (start + count > vertexCount_)
-    {
-        URHO3D_LOGERROR("Illegal range for setting new vertex buffer data");
-        return false;
-    }
-
-    if (!count)
-        return true;
-
-    if (shadowData_ && shadowData_.Get() + start * vertexSize_ != data)
-        memcpy(shadowData_.Get() + start * vertexSize_, data, count * vertexSize_);
-
-    if (object_.ptr_)
-    {
-        if (graphics_->IsDeviceLost())
-        {
-            URHO3D_LOGWARNING("Vertex buffer data assignment while device is lost");
-            dataPending_ = true;
-            return true;
-        }
-
-        void* hwData = MapBuffer_D3D9(start, count, discard);
-        if (hwData)
-        {
-            memcpy(hwData, data, count * vertexSize_);
-            UnmapBuffer_D3D9();
-        }
-        else
-            return false;
-    }
-
-    return true;
-}
-
-void* VertexBuffer::Lock_D3D9(unsigned start, unsigned count, bool discard)
-{
-    if (lockState_ != LOCK_NONE)
-    {
-        URHO3D_LOGERROR("Vertex buffer already locked");
-        return nullptr;
-    }
-
-    if (!vertexSize_)
-    {
-        URHO3D_LOGERROR("Vertex elements not defined, can not lock vertex buffer");
-        return nullptr;
-    }
-
-    if (start + count > vertexCount_)
-    {
-        URHO3D_LOGERROR("Illegal range for locking vertex buffer");
-        return nullptr;
-    }
-
-    if (!count)
-        return nullptr;
-
-    lockStart_ = start;
-    lockCount_ = count;
-
-    // Because shadow data must be kept in sync, can only lock hardware buffer if not shadowed
-    if (object_.ptr_ && !shadowData_ && !graphics_->IsDeviceLost())
-        return MapBuffer_D3D9(start, count, discard);
-    else if (shadowData_)
-    {
-        lockState_ = LOCK_SHADOW;
-        return shadowData_.Get() + start * vertexSize_;
-    }
-    else if (graphics_)
-    {
-        lockState_ = LOCK_SCRATCH;
-        lockScratchData_ = graphics_->ReserveScratchBuffer(count * vertexSize_);
-        return lockScratchData_;
-    }
-    else
-        return nullptr;
-}
-
-void VertexBuffer::Unlock_D3D9()
-{
-    switch (lockState_)
-    {
-    case LOCK_HARDWARE:
-        UnmapBuffer_D3D9();
-        break;
-
-    case LOCK_SHADOW:
-        SetDataRange_D3D9(shadowData_.Get() + lockStart_ * vertexSize_, lockStart_, lockCount_);
-        lockState_ = LOCK_NONE;
-        break;
-
-    case LOCK_SCRATCH:
-        SetDataRange_D3D9(lockScratchData_, lockStart_, lockCount_);
-        if (graphics_)
-            graphics_->FreeScratchBuffer(lockScratchData_);
-        lockScratchData_ = nullptr;
-        lockState_ = LOCK_NONE;
-        break;
-
-    default: break;
-    }
-}
-
-bool VertexBuffer::Create_D3D9()
-{
-    Release_D3D9();
-
-    if (!vertexCount_ || elements_.Empty())
-        return true;
-
-    if (graphics_)
-    {
-        if (graphics_->IsDeviceLost())
-        {
-            URHO3D_LOGWARNING("Vertex buffer creation while device is lost");
-            return true;
-        }
-
-        unsigned pool = dynamic_ ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
-        unsigned d3dUsage = dynamic_ ? D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY : 0;
-
-        IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
-        HRESULT hr = device->CreateVertexBuffer(
-            vertexCount_ * vertexSize_,
-            d3dUsage,
-            0,
-            (D3DPOOL)pool,
-            (IDirect3DVertexBuffer9**)&object_.ptr_,
-            nullptr);
-        if (FAILED(hr))
-        {
-            URHO3D_SAFE_RELEASE(object_.ptr_);
-            URHO3D_LOGD3DERROR("Could not create vertex buffer", hr);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-bool VertexBuffer::UpdateToGPU_D3D9()
-{
-    if (object_.ptr_ && shadowData_)
-        return SetData_D3D9(shadowData_.Get());
-    else
-        return false;
-}
-
-void* VertexBuffer::MapBuffer_D3D9(unsigned start, unsigned count, bool discard)
-{
-    void* hwData = nullptr;
-
-    if (object_.ptr_)
-    {
-        DWORD flags = 0;
-
-        if (discard && dynamic_)
-            flags = D3DLOCK_DISCARD;
-
-        HRESULT hr = ((IDirect3DVertexBuffer9*)object_.ptr_)->Lock(start * vertexSize_, count * vertexSize_, &hwData, flags);
-        if (FAILED(hr))
-            URHO3D_LOGD3DERROR("Could not lock vertex buffer", hr);
-        else
-            lockState_ = LOCK_HARDWARE;
-    }
-
-    return hwData;
-}
-
-void VertexBuffer::UnmapBuffer_D3D9()
-{
-    if (object_.ptr_ && lockState_ == LOCK_HARDWARE)
-    {
-        ((IDirect3DVertexBuffer9*)object_.ptr_)->Unlock();
-        lockState_ = LOCK_NONE;
-    }
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Graphics/Graphics.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9GraphicsImpl.h"
+#include "../../GraphicsAPI/VertexBuffer.h"
+#include "../../IO/Log.h"
+
+#include "../../DebugNew.h"
+
+namespace Urho3D
+{
+
+void VertexBuffer::OnDeviceLost_D3D9()
+{
+    // Dynamic buffers are in the default pool and need to be released on device loss
+    if (dynamic_)
+        Release_D3D9();
+}
+
+void VertexBuffer::OnDeviceReset_D3D9()
+{
+    // Dynamic buffers are in the default pool and need to be recreated after device reset
+    if (dynamic_ || !object_.ptr_)
+    {
+        Create_D3D9();
+        dataLost_ = !UpdateToGPU_D3D9();
+    }
+    else if (dataPending_)
+        dataLost_ = !UpdateToGPU_D3D9();
+
+    dataPending_ = false;
+}
+
+void VertexBuffer::Release_D3D9()
+{
+    Unlock_D3D9();
+
+    if (graphics_)
+    {
+        for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
+        {
+            if (graphics_->GetVertexBuffer(i) == this)
+                graphics_->SetVertexBuffer(nullptr);
+        }
+    }
+
+    URHO3D_SAFE_RELEASE(object_.ptr_);
+}
+
+bool VertexBuffer::SetData_D3D9(const void* data)
+{
+    if (!data)
+    {
+        URHO3D_LOGERROR("Null pointer for vertex buffer data");
+        return false;
+    }
+
+    if (!vertexSize_)
+    {
+        URHO3D_LOGERROR("Vertex elements not defined, can not set vertex buffer data");
+        return false;
+    }
+
+    if (shadowData_ && data != shadowData_.Get())
+        memcpy(shadowData_.Get(), data, vertexCount_ * vertexSize_);
+
+    if (object_.ptr_)
+    {
+        if (graphics_->IsDeviceLost())
+        {
+            URHO3D_LOGWARNING("Vertex buffer data assignment while device is lost");
+            dataPending_ = true;
+            return true;
+        }
+
+        void* hwData = MapBuffer_D3D9(0, vertexCount_, true);
+        if (hwData)
+        {
+            memcpy(hwData, data, vertexCount_ * vertexSize_);
+            UnmapBuffer_D3D9();
+        }
+        else
+            return false;
+    }
+
+    dataLost_ = false;
+    return true;
+}
+
+bool VertexBuffer::SetDataRange_D3D9(const void* data, unsigned start, unsigned count, bool discard)
+{
+    if (start == 0 && count == vertexCount_)
+        return SetData_D3D9(data);
+
+    if (!data)
+    {
+        URHO3D_LOGERROR("Null pointer for vertex buffer data");
+        return false;
+    }
+
+    if (!vertexSize_)
+    {
+        URHO3D_LOGERROR("Vertex elements not defined, can not set vertex buffer data");
+        return false;
+    }
+
+    if (start + count > vertexCount_)
+    {
+        URHO3D_LOGERROR("Illegal range for setting new vertex buffer data");
+        return false;
+    }
+
+    if (!count)
+        return true;
+
+    if (shadowData_ && shadowData_.Get() + start * vertexSize_ != data)
+        memcpy(shadowData_.Get() + start * vertexSize_, data, count * vertexSize_);
+
+    if (object_.ptr_)
+    {
+        if (graphics_->IsDeviceLost())
+        {
+            URHO3D_LOGWARNING("Vertex buffer data assignment while device is lost");
+            dataPending_ = true;
+            return true;
+        }
+
+        void* hwData = MapBuffer_D3D9(start, count, discard);
+        if (hwData)
+        {
+            memcpy(hwData, data, count * vertexSize_);
+            UnmapBuffer_D3D9();
+        }
+        else
+            return false;
+    }
+
+    return true;
+}
+
+void* VertexBuffer::Lock_D3D9(unsigned start, unsigned count, bool discard)
+{
+    if (lockState_ != LOCK_NONE)
+    {
+        URHO3D_LOGERROR("Vertex buffer already locked");
+        return nullptr;
+    }
+
+    if (!vertexSize_)
+    {
+        URHO3D_LOGERROR("Vertex elements not defined, can not lock vertex buffer");
+        return nullptr;
+    }
+
+    if (start + count > vertexCount_)
+    {
+        URHO3D_LOGERROR("Illegal range for locking vertex buffer");
+        return nullptr;
+    }
+
+    if (!count)
+        return nullptr;
+
+    lockStart_ = start;
+    lockCount_ = count;
+
+    // Because shadow data must be kept in sync, can only lock hardware buffer if not shadowed
+    if (object_.ptr_ && !shadowData_ && !graphics_->IsDeviceLost())
+        return MapBuffer_D3D9(start, count, discard);
+    else if (shadowData_)
+    {
+        lockState_ = LOCK_SHADOW;
+        return shadowData_.Get() + start * vertexSize_;
+    }
+    else if (graphics_)
+    {
+        lockState_ = LOCK_SCRATCH;
+        lockScratchData_ = graphics_->ReserveScratchBuffer(count * vertexSize_);
+        return lockScratchData_;
+    }
+    else
+        return nullptr;
+}
+
+void VertexBuffer::Unlock_D3D9()
+{
+    switch (lockState_)
+    {
+    case LOCK_HARDWARE:
+        UnmapBuffer_D3D9();
+        break;
+
+    case LOCK_SHADOW:
+        SetDataRange_D3D9(shadowData_.Get() + lockStart_ * vertexSize_, lockStart_, lockCount_);
+        lockState_ = LOCK_NONE;
+        break;
+
+    case LOCK_SCRATCH:
+        SetDataRange_D3D9(lockScratchData_, lockStart_, lockCount_);
+        if (graphics_)
+            graphics_->FreeScratchBuffer(lockScratchData_);
+        lockScratchData_ = nullptr;
+        lockState_ = LOCK_NONE;
+        break;
+
+    default: break;
+    }
+}
+
+bool VertexBuffer::Create_D3D9()
+{
+    Release_D3D9();
+
+    if (!vertexCount_ || elements_.Empty())
+        return true;
+
+    if (graphics_)
+    {
+        if (graphics_->IsDeviceLost())
+        {
+            URHO3D_LOGWARNING("Vertex buffer creation while device is lost");
+            return true;
+        }
+
+        unsigned pool = dynamic_ ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
+        unsigned d3dUsage = dynamic_ ? D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY : 0;
+
+        IDirect3DDevice9* device = graphics_->GetImpl_D3D9()->GetDevice();
+        HRESULT hr = device->CreateVertexBuffer(
+            vertexCount_ * vertexSize_,
+            d3dUsage,
+            0,
+            (D3DPOOL)pool,
+            (IDirect3DVertexBuffer9**)&object_.ptr_,
+            nullptr);
+        if (FAILED(hr))
+        {
+            URHO3D_SAFE_RELEASE(object_.ptr_);
+            URHO3D_LOGD3DERROR("Could not create vertex buffer", hr);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool VertexBuffer::UpdateToGPU_D3D9()
+{
+    if (object_.ptr_ && shadowData_)
+        return SetData_D3D9(shadowData_.Get());
+    else
+        return false;
+}
+
+void* VertexBuffer::MapBuffer_D3D9(unsigned start, unsigned count, bool discard)
+{
+    void* hwData = nullptr;
+
+    if (object_.ptr_)
+    {
+        DWORD flags = 0;
+
+        if (discard && dynamic_)
+            flags = D3DLOCK_DISCARD;
+
+        HRESULT hr = ((IDirect3DVertexBuffer9*)object_.ptr_)->Lock(start * vertexSize_, count * vertexSize_, &hwData, flags);
+        if (FAILED(hr))
+            URHO3D_LOGD3DERROR("Could not lock vertex buffer", hr);
+        else
+            lockState_ = LOCK_HARDWARE;
+    }
+
+    return hwData;
+}
+
+void VertexBuffer::UnmapBuffer_D3D9()
+{
+    if (object_.ptr_ && lockState_ == LOCK_HARDWARE)
+    {
+        ((IDirect3DVertexBuffer9*)object_.ptr_)->Unlock();
+        lockState_ = LOCK_NONE;
+    }
+}
+
+}

+ 237 - 237
Source/Urho3D/Graphics/Direct3D9/D3D9VertexDeclaration.cpp → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9VertexDeclaration.cpp

@@ -1,237 +1,237 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/VertexBuffer.h"
-#include "../../IO/Log.h"
-#include "D3D9GraphicsImpl.h"
-#include "D3D9VertexDeclaration.h"
-
-#include "../../DebugNew.h"
-
-namespace Urho3D
-{
-
-const BYTE d3dElementType[] =
-{
-    D3DDECLTYPE_UNUSED, // Int (not supported by D3D9)
-    D3DDECLTYPE_FLOAT1, // Float
-    D3DDECLTYPE_FLOAT2, // Vector2
-    D3DDECLTYPE_FLOAT3, // Vector3
-    D3DDECLTYPE_FLOAT4, // Vector4
-    D3DDECLTYPE_UBYTE4, // 4 bytes, not normalized
-    D3DDECLTYPE_UBYTE4N // 4 bytes, normalized
-};
-
-const BYTE d3dElementUsage[] =
-{
-    D3DDECLUSAGE_POSITION,
-    D3DDECLUSAGE_NORMAL,
-    D3DDECLUSAGE_BINORMAL,
-    D3DDECLUSAGE_TANGENT,
-    D3DDECLUSAGE_TEXCOORD,
-    D3DDECLUSAGE_COLOR,
-    D3DDECLUSAGE_BLENDWEIGHT,
-    D3DDECLUSAGE_BLENDINDICES,
-    D3DDECLUSAGE_TEXCOORD // Object index (not supported by D3D9)
-};
-
-VertexDeclaration_D3D9::VertexDeclaration_D3D9(Graphics* graphics, const PODVector<VertexElement>& srcElements) :
-    declaration_(nullptr)
-{
-    PODVector<VertexDeclarationElement_D3D9> elements;
-
-    for (unsigned i = 0; i < srcElements.Size(); ++i)
-    {
-        const VertexElement& srcElement = srcElements[i];
-
-        if (srcElement.semantic_ == SEM_OBJECTINDEX)
-        {
-            URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
-            continue;
-        }
-
-        VertexDeclarationElement_D3D9 element;
-        element.semantic_ = srcElement.semantic_;
-        element.type_ = srcElement.type_;
-        element.index_ = srcElement.index_;
-        element.streamIndex_ = 0;
-        element.offset_ = srcElement.offset_;
-        elements.Push(element);
-    }
-
-    Create(graphics, elements);
-}
-
-VertexDeclaration_D3D9::VertexDeclaration_D3D9(Graphics* graphics, const PODVector<VertexBuffer*>& buffers) :
-    declaration_(nullptr)
-{
-    PODVector<VertexDeclarationElement_D3D9> elements;
-    unsigned prevBufferElements = 0;
-
-    for (unsigned i = 0; i < buffers.Size(); ++i)
-    {
-        if (!buffers[i])
-            continue;
-
-        const PODVector<VertexElement>& srcElements = buffers[i]->GetElements();
-        bool isExisting = false;
-
-        for (unsigned j = 0; j < srcElements.Size(); ++j)
-        {
-            const VertexElement& srcElement = srcElements[j];
-
-            if (srcElement.semantic_ == SEM_OBJECTINDEX)
-            {
-                URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
-                continue;
-            }
-
-            // Override existing element if necessary
-            for (unsigned k = 0; k < prevBufferElements; ++k)
-            {
-                if (elements[k].semantic_ == srcElement.semantic_ && elements[k].index_ == srcElement.index_)
-                {
-                    isExisting = true;
-                    elements[k].streamIndex_ = i;
-                    elements[k].offset_ = srcElement.offset_;
-                    break;
-                }
-            }
-
-            if (isExisting)
-                continue;
-
-            VertexDeclarationElement_D3D9 element;
-            element.semantic_ = srcElement.semantic_;
-            element.type_ = srcElement.type_;
-            element.index_ = srcElement.index_;
-            element.streamIndex_ = i;
-            element.offset_ = srcElement.offset_;
-            elements.Push(element);
-        }
-
-        prevBufferElements = elements.Size();
-    }
-
-    Create(graphics, elements);
-}
-
-VertexDeclaration_D3D9::VertexDeclaration_D3D9(Graphics* graphics, const Vector<SharedPtr<VertexBuffer> >& buffers) :
-    declaration_(nullptr)
-{
-    PODVector<VertexDeclarationElement_D3D9> elements;
-    unsigned prevBufferElements = 0;
-
-    for (unsigned i = 0; i < buffers.Size(); ++i)
-    {
-        if (!buffers[i])
-            continue;
-
-        const PODVector<VertexElement>& srcElements = buffers[i]->GetElements();
-        bool isExisting = false;
-
-        for (unsigned j = 0; j < srcElements.Size(); ++j)
-        {
-            const VertexElement& srcElement = srcElements[j];
-
-            if (srcElement.semantic_ == SEM_OBJECTINDEX)
-            {
-                URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
-                continue;
-            }
-
-            // Override existing element if necessary
-            for (unsigned k = 0; k < prevBufferElements; ++k)
-            {
-                if (elements[k].semantic_ == srcElement.semantic_ && elements[k].index_ == srcElement.index_)
-                {
-                    isExisting = true;
-                    elements[k].streamIndex_ = i;
-                    elements[k].offset_ = srcElement.offset_;
-                    break;
-                }
-            }
-
-            if (isExisting)
-                continue;
-
-            VertexDeclarationElement_D3D9 element;
-            element.semantic_ = srcElement.semantic_;
-            element.type_ = srcElement.type_;
-            element.index_ = srcElement.index_;
-            element.streamIndex_ = i;
-            element.offset_ = srcElement.offset_;
-            elements.Push(element);
-        }
-
-        prevBufferElements = elements.Size();
-    }
-
-    Create(graphics, elements);
-}
-
-VertexDeclaration_D3D9::~VertexDeclaration_D3D9()
-{
-    Release();
-}
-
-void VertexDeclaration_D3D9::Create(Graphics* graphics, const PODVector<VertexDeclarationElement_D3D9>& elements)
-{
-    SharedArrayPtr<D3DVERTEXELEMENT9> elementArray(new D3DVERTEXELEMENT9[elements.Size() + 1]);
-
-    D3DVERTEXELEMENT9* dest = elementArray;
-    for (Vector<VertexDeclarationElement_D3D9>::ConstIterator i = elements.Begin(); i != elements.End(); ++i)
-    {
-        dest->Stream = (WORD)i->streamIndex_;
-        dest->Offset = (WORD)i->offset_;
-        dest->Type = d3dElementType[i->type_];
-        dest->Method = D3DDECLMETHOD_DEFAULT;
-        dest->Usage = d3dElementUsage[i->semantic_];
-        dest->UsageIndex = i->index_;
-        dest++;
-    }
-
-    dest->Stream = 0xff;
-    dest->Offset = 0;
-    dest->Type = D3DDECLTYPE_UNUSED;
-    dest->Method = 0;
-    dest->Usage = 0;
-    dest->UsageIndex = 0;
-
-    IDirect3DDevice9* device = graphics->GetImpl_D3D9()->GetDevice();
-    HRESULT hr = device->CreateVertexDeclaration(elementArray, &declaration_);
-    if (FAILED(hr))
-    {
-        URHO3D_SAFE_RELEASE(declaration_);
-        URHO3D_LOGD3DERROR("Failed to create vertex declaration", hr);
-    }
-}
-
-void VertexDeclaration_D3D9::Release()
-{
-    URHO3D_SAFE_RELEASE(declaration_);
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Graphics/Graphics.h"
+#include "../../GraphicsAPI/Direct3D9/D3D9GraphicsImpl.h"
+#include "../../GraphicsAPI/VertexBuffer.h"
+#include "../../IO/Log.h"
+#include "D3D9VertexDeclaration.h"
+
+#include "../../DebugNew.h"
+
+namespace Urho3D
+{
+
+const BYTE d3dElementType[] =
+{
+    D3DDECLTYPE_UNUSED, // Int (not supported by D3D9)
+    D3DDECLTYPE_FLOAT1, // Float
+    D3DDECLTYPE_FLOAT2, // Vector2
+    D3DDECLTYPE_FLOAT3, // Vector3
+    D3DDECLTYPE_FLOAT4, // Vector4
+    D3DDECLTYPE_UBYTE4, // 4 bytes, not normalized
+    D3DDECLTYPE_UBYTE4N // 4 bytes, normalized
+};
+
+const BYTE d3dElementUsage[] =
+{
+    D3DDECLUSAGE_POSITION,
+    D3DDECLUSAGE_NORMAL,
+    D3DDECLUSAGE_BINORMAL,
+    D3DDECLUSAGE_TANGENT,
+    D3DDECLUSAGE_TEXCOORD,
+    D3DDECLUSAGE_COLOR,
+    D3DDECLUSAGE_BLENDWEIGHT,
+    D3DDECLUSAGE_BLENDINDICES,
+    D3DDECLUSAGE_TEXCOORD // Object index (not supported by D3D9)
+};
+
+VertexDeclaration_D3D9::VertexDeclaration_D3D9(Graphics* graphics, const PODVector<VertexElement>& srcElements) :
+    declaration_(nullptr)
+{
+    PODVector<VertexDeclarationElement_D3D9> elements;
+
+    for (unsigned i = 0; i < srcElements.Size(); ++i)
+    {
+        const VertexElement& srcElement = srcElements[i];
+
+        if (srcElement.semantic_ == SEM_OBJECTINDEX)
+        {
+            URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
+            continue;
+        }
+
+        VertexDeclarationElement_D3D9 element;
+        element.semantic_ = srcElement.semantic_;
+        element.type_ = srcElement.type_;
+        element.index_ = srcElement.index_;
+        element.streamIndex_ = 0;
+        element.offset_ = srcElement.offset_;
+        elements.Push(element);
+    }
+
+    Create(graphics, elements);
+}
+
+VertexDeclaration_D3D9::VertexDeclaration_D3D9(Graphics* graphics, const PODVector<VertexBuffer*>& buffers) :
+    declaration_(nullptr)
+{
+    PODVector<VertexDeclarationElement_D3D9> elements;
+    unsigned prevBufferElements = 0;
+
+    for (unsigned i = 0; i < buffers.Size(); ++i)
+    {
+        if (!buffers[i])
+            continue;
+
+        const PODVector<VertexElement>& srcElements = buffers[i]->GetElements();
+        bool isExisting = false;
+
+        for (unsigned j = 0; j < srcElements.Size(); ++j)
+        {
+            const VertexElement& srcElement = srcElements[j];
+
+            if (srcElement.semantic_ == SEM_OBJECTINDEX)
+            {
+                URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
+                continue;
+            }
+
+            // Override existing element if necessary
+            for (unsigned k = 0; k < prevBufferElements; ++k)
+            {
+                if (elements[k].semantic_ == srcElement.semantic_ && elements[k].index_ == srcElement.index_)
+                {
+                    isExisting = true;
+                    elements[k].streamIndex_ = i;
+                    elements[k].offset_ = srcElement.offset_;
+                    break;
+                }
+            }
+
+            if (isExisting)
+                continue;
+
+            VertexDeclarationElement_D3D9 element;
+            element.semantic_ = srcElement.semantic_;
+            element.type_ = srcElement.type_;
+            element.index_ = srcElement.index_;
+            element.streamIndex_ = i;
+            element.offset_ = srcElement.offset_;
+            elements.Push(element);
+        }
+
+        prevBufferElements = elements.Size();
+    }
+
+    Create(graphics, elements);
+}
+
+VertexDeclaration_D3D9::VertexDeclaration_D3D9(Graphics* graphics, const Vector<SharedPtr<VertexBuffer> >& buffers) :
+    declaration_(nullptr)
+{
+    PODVector<VertexDeclarationElement_D3D9> elements;
+    unsigned prevBufferElements = 0;
+
+    for (unsigned i = 0; i < buffers.Size(); ++i)
+    {
+        if (!buffers[i])
+            continue;
+
+        const PODVector<VertexElement>& srcElements = buffers[i]->GetElements();
+        bool isExisting = false;
+
+        for (unsigned j = 0; j < srcElements.Size(); ++j)
+        {
+            const VertexElement& srcElement = srcElements[j];
+
+            if (srcElement.semantic_ == SEM_OBJECTINDEX)
+            {
+                URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
+                continue;
+            }
+
+            // Override existing element if necessary
+            for (unsigned k = 0; k < prevBufferElements; ++k)
+            {
+                if (elements[k].semantic_ == srcElement.semantic_ && elements[k].index_ == srcElement.index_)
+                {
+                    isExisting = true;
+                    elements[k].streamIndex_ = i;
+                    elements[k].offset_ = srcElement.offset_;
+                    break;
+                }
+            }
+
+            if (isExisting)
+                continue;
+
+            VertexDeclarationElement_D3D9 element;
+            element.semantic_ = srcElement.semantic_;
+            element.type_ = srcElement.type_;
+            element.index_ = srcElement.index_;
+            element.streamIndex_ = i;
+            element.offset_ = srcElement.offset_;
+            elements.Push(element);
+        }
+
+        prevBufferElements = elements.Size();
+    }
+
+    Create(graphics, elements);
+}
+
+VertexDeclaration_D3D9::~VertexDeclaration_D3D9()
+{
+    Release();
+}
+
+void VertexDeclaration_D3D9::Create(Graphics* graphics, const PODVector<VertexDeclarationElement_D3D9>& elements)
+{
+    SharedArrayPtr<D3DVERTEXELEMENT9> elementArray(new D3DVERTEXELEMENT9[elements.Size() + 1]);
+
+    D3DVERTEXELEMENT9* dest = elementArray;
+    for (Vector<VertexDeclarationElement_D3D9>::ConstIterator i = elements.Begin(); i != elements.End(); ++i)
+    {
+        dest->Stream = (WORD)i->streamIndex_;
+        dest->Offset = (WORD)i->offset_;
+        dest->Type = d3dElementType[i->type_];
+        dest->Method = D3DDECLMETHOD_DEFAULT;
+        dest->Usage = d3dElementUsage[i->semantic_];
+        dest->UsageIndex = i->index_;
+        dest++;
+    }
+
+    dest->Stream = 0xff;
+    dest->Offset = 0;
+    dest->Type = D3DDECLTYPE_UNUSED;
+    dest->Method = 0;
+    dest->Usage = 0;
+    dest->UsageIndex = 0;
+
+    IDirect3DDevice9* device = graphics->GetImpl_D3D9()->GetDevice();
+    HRESULT hr = device->CreateVertexDeclaration(elementArray, &declaration_);
+    if (FAILED(hr))
+    {
+        URHO3D_SAFE_RELEASE(declaration_);
+        URHO3D_LOGD3DERROR("Failed to create vertex declaration", hr);
+    }
+}
+
+void VertexDeclaration_D3D9::Release()
+{
+    URHO3D_SAFE_RELEASE(declaration_);
+}
+
+}

+ 78 - 78
Source/Urho3D/Graphics/Direct3D9/D3D9VertexDeclaration.h → Source/Urho3D/GraphicsAPI/Direct3D9/D3D9VertexDeclaration.h

@@ -1,78 +1,78 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#pragma once
-
-#include "../../Container/RefCounted.h"
-#include "../../Container/Vector.h"
-#include "../../Graphics/GraphicsDefs.h"
-
-#include <d3d9.h>
-
-namespace Urho3D
-{
-
-class Graphics;
-class VertexBuffer;
-
-/// One element in a vertex declaration. In contrast to the VertexElement structure, takes into account the stream source index.
-struct VertexDeclarationElement_D3D9
-{
-    /// Element type.
-    VertexElementType type_;
-    /// Element semantic.
-    VertexElementSemantic semantic_;
-    /// Semantic index.
-    unsigned char index_;
-    /// Stream index.
-    unsigned char streamIndex_;
-    /// Byte offset.
-    unsigned offset_;
-};
-
-/// Vertex declaration.
-class URHO3D_API VertexDeclaration_D3D9 : public RefCounted
-{
-public:
-    /// Construct with a single buffer's vertex element list.
-    VertexDeclaration_D3D9(Graphics* graphics, const PODVector<VertexElement>& srcElements);
-    /// Construct with vertex buffers to base declaration on. Higher index buffers will override semantics on lower indices.
-    VertexDeclaration_D3D9(Graphics* graphics, const PODVector<VertexBuffer*>& buffers);
-    /// Construct with vertex buffers (shared pointer vector) to base declaration on. Higher index buffers will override semantics on lower indices.
-    VertexDeclaration_D3D9(Graphics* graphics, const Vector<SharedPtr<VertexBuffer> >& buffers);
-    /// Destruct.
-    ~VertexDeclaration_D3D9();
-
-    /// Return Direct3D vertex declaration.
-    IDirect3DVertexDeclaration9* GetDeclaration() const { return declaration_; }
-
-private:
-    /// Create declaration.
-    void Create(Graphics* graphics, const PODVector<VertexDeclarationElement_D3D9>& elements);
-    /// Release declaration.
-    void Release();
-
-    /// Direct3D vertex declaration.
-    IDirect3DVertexDeclaration9* declaration_;
-};
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "../../Container/Ptr.h"
+#include "../../Container/Vector.h"
+#include "../../GraphicsAPI/GraphicsDefs.h"
+
+#include <d3d9.h>
+
+namespace Urho3D
+{
+
+class Graphics;
+class VertexBuffer;
+
+/// One element in a vertex declaration. In contrast to the VertexElement structure, takes into account the stream source index.
+struct VertexDeclarationElement_D3D9
+{
+    /// Element type.
+    VertexElementType type_;
+    /// Element semantic.
+    VertexElementSemantic semantic_;
+    /// Semantic index.
+    unsigned char index_;
+    /// Stream index.
+    unsigned char streamIndex_;
+    /// Byte offset.
+    unsigned offset_;
+};
+
+/// Vertex declaration.
+class URHO3D_API VertexDeclaration_D3D9 : public RefCounted
+{
+public:
+    /// Construct with a single buffer's vertex element list.
+    VertexDeclaration_D3D9(Graphics* graphics, const PODVector<VertexElement>& srcElements);
+    /// Construct with vertex buffers to base declaration on. Higher index buffers will override semantics on lower indices.
+    VertexDeclaration_D3D9(Graphics* graphics, const PODVector<VertexBuffer*>& buffers);
+    /// Construct with vertex buffers (shared pointer vector) to base declaration on. Higher index buffers will override semantics on lower indices.
+    VertexDeclaration_D3D9(Graphics* graphics, const Vector<SharedPtr<VertexBuffer> >& buffers);
+    /// Destruct.
+    ~VertexDeclaration_D3D9();
+
+    /// Return Direct3D vertex declaration.
+    IDirect3DVertexDeclaration9* GetDeclaration() const { return declaration_; }
+
+private:
+    /// Create declaration.
+    void Create(Graphics* graphics, const PODVector<VertexDeclarationElement_D3D9>& elements);
+    /// Release declaration.
+    void Release();
+
+    /// Direct3D vertex declaration.
+    IDirect3DVertexDeclaration9* declaration_;
+};
+
+}

+ 1 - 1
Source/Urho3D/Graphics/GPUObject.cpp → Source/Urho3D/GraphicsAPI/GPUObject.cpp

@@ -22,8 +22,8 @@
 
 #include "../Precompiled.h"
 
+#include "../GraphicsAPI/GPUObject.h"
 #include "../Graphics/Graphics.h"
-#include "../Graphics/GPUObject.h"
 
 #include "../DebugNew.h"
 

+ 84 - 84
Source/Urho3D/Graphics/GPUObject.h → Source/Urho3D/GraphicsAPI/GPUObject.h

@@ -1,84 +1,84 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#pragma once
-
-#include "../Container/Ptr.h"
-
-namespace Urho3D
-{
-
-class Graphics;
-
-/// API-specific GPU object representation.
-union GPUObjectHandle
-{
-    /// Object pointer (Direct3D).
-    void* ptr_;
-    /// Object name (OpenGL).
-    unsigned name_;
-};
-
-/// Base class for GPU resources.
-class URHO3D_API GPUObject
-{
-public:
-    /// Construct with graphics subsystem pointer.
-    explicit GPUObject(Graphics* graphics);
-    /// Destruct. Remove from the Graphics.
-    virtual ~GPUObject();
-
-    /// Mark the GPU resource destroyed on graphics context destruction.
-    virtual void OnDeviceLost();
-    /// Recreate the GPU resource and restore data if applicable.
-    virtual void OnDeviceReset();
-    /// Unconditionally release the GPU resource.
-    virtual void Release();
-
-    /// Clear the data lost flag.
-    void ClearDataLost();
-
-    /// Return the graphics subsystem associated with this GPU object.
-    Graphics* GetGraphics() const;
-    /// Return the object pointer. Applicable only on Direct3D.
-    void* GetGPUObject() const { return object_.ptr_; }
-    /// Return the object name. Applicable only on OpenGL.
-    unsigned GetGPUObjectName() const { return object_.name_; }
-    /// Return whether data is lost due to context loss.
-    /// @property
-    bool IsDataLost() const { return dataLost_; }
-    /// Return whether has pending data assigned while graphics context was lost.
-    bool HasPendingData() const { return dataPending_; }
-
-protected:
-    /// Graphics subsystem.
-    WeakPtr<Graphics> graphics_;
-    /// Object pointer or name.
-    GPUObjectHandle object_{};
-    /// Data lost flag.
-    bool dataLost_{};
-    /// Data pending flag.
-    bool dataPending_{};
-};
-
-}
-
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "../Container/Ptr.h"
+
+namespace Urho3D
+{
+
+class Graphics;
+
+/// API-specific GPU object representation.
+union GPUObjectHandle
+{
+    /// Object pointer (Direct3D).
+    void* ptr_;
+    /// Object name (OpenGL).
+    unsigned name_;
+};
+
+/// Base class for GPU resources.
+class URHO3D_API GPUObject
+{
+public:
+    /// Construct with graphics subsystem pointer.
+    explicit GPUObject(Graphics* graphics);
+    /// Destruct. Remove from the Graphics.
+    virtual ~GPUObject();
+
+    /// Mark the GPU resource destroyed on graphics context destruction.
+    virtual void OnDeviceLost();
+    /// Recreate the GPU resource and restore data if applicable.
+    virtual void OnDeviceReset();
+    /// Unconditionally release the GPU resource.
+    virtual void Release();
+
+    /// Clear the data lost flag.
+    void ClearDataLost();
+
+    /// Return the graphics subsystem associated with this GPU object.
+    Graphics* GetGraphics() const;
+    /// Return the object pointer. Applicable only on Direct3D.
+    void* GetGPUObject() const { return object_.ptr_; }
+    /// Return the object name. Applicable only on OpenGL.
+    unsigned GetGPUObjectName() const { return object_.name_; }
+    /// Return whether data is lost due to context loss.
+    /// @property
+    bool IsDataLost() const { return dataLost_; }
+    /// Return whether has pending data assigned while graphics context was lost.
+    bool HasPendingData() const { return dataPending_; }
+
+protected:
+    /// Graphics subsystem.
+    WeakPtr<Graphics> graphics_;
+    /// Object pointer or name.
+    GPUObjectHandle object_{};
+    /// Data lost flag.
+    bool dataLost_{};
+    /// Data pending flag.
+    bool dataPending_{};
+};
+
+}
+

+ 1 - 1
Source/Urho3D/Graphics/GraphicsDefs.cpp → Source/Urho3D/GraphicsAPI/GraphicsDefs.cpp

@@ -22,7 +22,7 @@
 
 #include "../Precompiled.h"
 
-#include "../Graphics/GraphicsDefs.h"
+#include "GraphicsDefs.h"
 
 #include "../DebugNew.h"
 

+ 498 - 498
Source/Urho3D/Graphics/GraphicsDefs.h → Source/Urho3D/GraphicsAPI/GraphicsDefs.h

@@ -1,498 +1,498 @@
-//
-// Copyright (c) 2008-2022 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.
-//
-
-/// \file
-
-#pragma once
-
-#include "../Container/FlagSet.h"
-#include "../Container/HashBase.h"
-#include "../Math/StringHash.h"
-#include "../Math/Vector3.h"
-
-namespace Urho3D
-{
-
-class Vector3;
-
-// Graphics capability support level. Web platform (Emscripten) also uses OpenGL ES, but is considered a desktop platform capability-wise
-#if defined(IOS) || defined(TVOS) || defined(__ANDROID__) || defined(__arm__) || defined(__aarch64__)
-#define MOBILE_GRAPHICS
-#else
-#define DESKTOP_GRAPHICS
-#endif
-
-enum GAPI
-{
-    GAPI_NONE = 0,
-    GAPI_OPENGL,
-    GAPI_D3D9,
-    GAPI_D3D11
-};
-
-/// Primitive type.
-enum PrimitiveType
-{
-    TRIANGLE_LIST = 0,
-    LINE_LIST,
-    POINT_LIST,
-    TRIANGLE_STRIP,
-    LINE_STRIP,
-    TRIANGLE_FAN
-};
-
-/// %Geometry type for vertex shader geometry variations.
-enum GeometryType
-{
-    GEOM_STATIC = 0,
-    GEOM_SKINNED = 1,
-    GEOM_INSTANCED = 2,
-    GEOM_BILLBOARD = 3,
-    GEOM_DIRBILLBOARD = 4,
-    GEOM_TRAIL_FACE_CAMERA = 5,
-    GEOM_TRAIL_BONE = 6,
-    MAX_GEOMETRYTYPES = 7,
-    // This is not a real geometry type for VS, but used to mark objects that do not desire to be instanced
-    GEOM_STATIC_NOINSTANCING = 7,
-};
-
-/// Blending mode.
-enum BlendMode
-{
-    BLEND_REPLACE = 0,
-    BLEND_ADD,
-    BLEND_MULTIPLY,
-    BLEND_ALPHA,
-    BLEND_ADDALPHA,
-    BLEND_PREMULALPHA,
-    BLEND_INVDESTALPHA,
-    BLEND_SUBTRACT,
-    BLEND_SUBTRACTALPHA,
-    MAX_BLENDMODES
-};
-
-/// Depth or stencil compare mode.
-enum CompareMode
-{
-    CMP_ALWAYS = 0,
-    CMP_EQUAL,
-    CMP_NOTEQUAL,
-    CMP_LESS,
-    CMP_LESSEQUAL,
-    CMP_GREATER,
-    CMP_GREATEREQUAL,
-    MAX_COMPAREMODES
-};
-
-/// Culling mode.
-enum CullMode
-{
-    CULL_NONE = 0,
-    CULL_CCW,
-    CULL_CW,
-    MAX_CULLMODES
-};
-
-/// Fill mode.
-enum FillMode
-{
-    FILL_SOLID = 0,
-    FILL_WIREFRAME,
-    FILL_POINT
-};
-
-/// Stencil operation.
-enum StencilOp
-{
-    OP_KEEP = 0,
-    OP_ZERO,
-    OP_REF,
-    OP_INCR,
-    OP_DECR
-};
-
-/// Vertex/index buffer lock state.
-enum LockState
-{
-    LOCK_NONE = 0,
-    LOCK_HARDWARE,
-    LOCK_SHADOW,
-    LOCK_SCRATCH
-};
-
-/// Hardcoded legacy vertex elements.
-enum LegacyVertexElement
-{
-    ELEMENT_POSITION = 0,
-    ELEMENT_NORMAL,
-    ELEMENT_COLOR,
-    ELEMENT_TEXCOORD1,
-    ELEMENT_TEXCOORD2,
-    ELEMENT_CUBETEXCOORD1,
-    ELEMENT_CUBETEXCOORD2,
-    ELEMENT_TANGENT,
-    ELEMENT_BLENDWEIGHTS,
-    ELEMENT_BLENDINDICES,
-    ELEMENT_INSTANCEMATRIX1,
-    ELEMENT_INSTANCEMATRIX2,
-    ELEMENT_INSTANCEMATRIX3,
-    // Custom 32-bit integer object index. Due to API limitations, not supported on D3D9
-    ELEMENT_OBJECTINDEX,
-    MAX_LEGACY_VERTEX_ELEMENTS
-};
-
-/// Arbitrary vertex declaration element datatypes.
-enum VertexElementType
-{
-    TYPE_INT = 0,
-    TYPE_FLOAT,
-    TYPE_VECTOR2,
-    TYPE_VECTOR3,
-    TYPE_VECTOR4,
-    TYPE_UBYTE4,
-    TYPE_UBYTE4_NORM,
-    MAX_VERTEX_ELEMENT_TYPES
-};
-
-/// Arbitrary vertex declaration element semantics.
-enum VertexElementSemantic
-{
-    SEM_POSITION = 0,
-    SEM_NORMAL,
-    SEM_BINORMAL,
-    SEM_TANGENT,
-    SEM_TEXCOORD,
-    SEM_COLOR,
-    SEM_BLENDWEIGHTS,
-    SEM_BLENDINDICES,
-    SEM_OBJECTINDEX,
-    MAX_VERTEX_ELEMENT_SEMANTICS
-};
-
-/// Vertex element description for arbitrary vertex declarations.
-struct URHO3D_API VertexElement
-{
-    /// Default-construct.
-    VertexElement() noexcept :
-        type_(TYPE_VECTOR3),
-        semantic_(SEM_POSITION),
-        index_(0),
-        perInstance_(false),
-        offset_(0)
-    {
-    }
-
-    /// Construct with type, semantic, index and whether is per-instance data.
-    VertexElement(VertexElementType type, VertexElementSemantic semantic, unsigned char index = 0, bool perInstance = false) noexcept :
-        type_(type),
-        semantic_(semantic),
-        index_(index),
-        perInstance_(perInstance),
-        offset_(0)
-    {
-    }
-
-    /// Test for equality with another vertex element. Offset is intentionally not compared, as it's relevant only when an element exists within a vertex buffer.
-    bool operator ==(const VertexElement& rhs) const { return type_ == rhs.type_ && semantic_ == rhs.semantic_ && index_ == rhs.index_ && perInstance_ == rhs.perInstance_; }
-
-    /// Test for inequality with another vertex element.
-    bool operator !=(const VertexElement& rhs) const { return !(*this == rhs); }
-
-    /// Data type of element.
-    VertexElementType type_;
-    /// Semantic of element.
-    VertexElementSemantic semantic_;
-    /// Semantic index of element, for example multi-texcoords.
-    unsigned char index_;
-    /// Per-instance flag.
-    bool perInstance_;
-    /// Offset of element from vertex start. Filled by VertexBuffer once the vertex declaration is built.
-    unsigned offset_;
-};
-
-/// Sizes of vertex element types.
-extern URHO3D_API const u32 ELEMENT_TYPESIZES[];
-
-/// Vertex element definitions for the legacy elements.
-extern URHO3D_API const VertexElement LEGACY_VERTEXELEMENTS[];
-
-/// Texture filtering mode.
-enum TextureFilterMode
-{
-    FILTER_NEAREST = 0,
-    FILTER_BILINEAR,
-    FILTER_TRILINEAR,
-    FILTER_ANISOTROPIC,
-    FILTER_NEAREST_ANISOTROPIC,
-    FILTER_DEFAULT,
-    MAX_FILTERMODES
-};
-
-/// Texture addressing mode.
-enum TextureAddressMode
-{
-    ADDRESS_WRAP = 0,
-    ADDRESS_MIRROR,
-    ADDRESS_CLAMP,
-    ADDRESS_BORDER,
-    MAX_ADDRESSMODES
-};
-
-/// Texture coordinates.
-enum TextureCoordinate
-{
-    COORD_U = 0,
-    COORD_V,
-    COORD_W,
-    MAX_COORDS
-};
-
-/// Texture usage types.
-enum TextureUsage
-{
-    TEXTURE_STATIC = 0,
-    TEXTURE_DYNAMIC,
-    TEXTURE_RENDERTARGET,
-    TEXTURE_DEPTHSTENCIL
-};
-
-/// Cube map faces.
-enum CubeMapFace
-{
-    FACE_POSITIVE_X = 0,
-    FACE_NEGATIVE_X,
-    FACE_POSITIVE_Y,
-    FACE_NEGATIVE_Y,
-    FACE_POSITIVE_Z,
-    FACE_NEGATIVE_Z,
-    MAX_CUBEMAP_FACES
-};
-
-/// Cubemap single image layout modes.
-enum CubeMapLayout
-{
-    CML_HORIZONTAL = 0,
-    CML_HORIZONTALNVIDIA,
-    CML_HORIZONTALCROSS,
-    CML_VERTICALCROSS,
-    CML_BLENDER
-};
-
-/// Update mode for render surface viewports.
-enum RenderSurfaceUpdateMode
-{
-    SURFACE_MANUALUPDATE = 0,
-    SURFACE_UPDATEVISIBLE,
-    SURFACE_UPDATEALWAYS
-};
-
-/// Shader types.
-enum ShaderType
-{
-    VS = 0,
-    PS,
-};
-
-/// Shader parameter groups for determining need to update. On APIs that support constant buffers, these correspond to different constant buffers.
-enum ShaderParameterGroup
-{
-    SP_FRAME = 0,
-    SP_CAMERA,
-    SP_ZONE,
-    SP_LIGHT,
-    SP_MATERIAL,
-    SP_OBJECT,
-    SP_CUSTOM,
-    MAX_SHADER_PARAMETER_GROUPS
-};
-
-/// Texture units.
-/// @manualbind
-enum TextureUnit
-{
-    TU_DIFFUSE = 0,
-    TU_ALBEDOBUFFER = 0,
-    TU_NORMAL = 1,
-    TU_NORMALBUFFER = 1,
-    TU_SPECULAR = 2,
-    TU_EMISSIVE = 3,
-    TU_ENVIRONMENT = 4,
-#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
-    TU_LIGHTRAMP = 5,
-    TU_LIGHTSHAPE = 6,
-    TU_SHADOWMAP = 7,
-    MAX_MATERIAL_TEXTURE_UNITS = 5,
-    MAX_TEXTURE_UNITS = 8
-#endif
-};
-
-/// Billboard camera facing modes.
-enum FaceCameraMode
-{
-    FC_NONE = 0,
-    FC_ROTATE_XYZ,
-    FC_ROTATE_Y,
-    FC_LOOKAT_XYZ,
-    FC_LOOKAT_Y,
-    FC_LOOKAT_MIXED,
-    FC_DIRECTION,
-};
-
-/// Shadow type.
-enum ShadowQuality
-{
-    SHADOWQUALITY_SIMPLE_16BIT = 0,
-    SHADOWQUALITY_SIMPLE_24BIT,
-    SHADOWQUALITY_PCF_16BIT,
-    SHADOWQUALITY_PCF_24BIT,
-    SHADOWQUALITY_VSM,
-    SHADOWQUALITY_BLUR_VSM
-};
-
-// Inbuilt shader parameters.
-inline const StringHash VSP_AMBIENTENDCOLOR{"AmbientEndColor"};
-inline const StringHash VSP_AMBIENTSTARTCOLOR{"AmbientStartColor"};
-inline const StringHash VSP_BILLBOARDROT{"BillboardRot"};
-inline const StringHash VSP_CLIPPLANE{"ClipPlane"};
-inline const StringHash VSP_DEPTHMODE{"DepthMode"};
-inline const StringHash VSP_FRUSTUMSIZE{"FrustumSize"};
-inline const StringHash VSP_GBUFFEROFFSETS{"GBufferOffsets"};
-inline const StringHash VSP_MODEL{"Model"};
-inline const StringHash VSP_SKINMATRICES{"SkinMatrices"};
-inline const StringHash VSP_UOFFSET{"UOffset"};
-inline const StringHash VSP_VERTEXLIGHTS{"VertexLights"};
-inline const StringHash VSP_VIEW{"View"};
-inline const StringHash VSP_VIEWINV{"ViewInv"};
-inline const StringHash VSP_VIEWPROJ{"ViewProj"};
-inline const StringHash VSP_VOFFSET{"VOffset"};
-inline const StringHash VSP_ZONE{"Zone"};
-inline const StringHash PSP_AMBIENTCOLOR{"AmbientColor"};
-inline const StringHash PSP_DEPTHRECONSTRUCT{"DepthReconstruct"};
-inline const StringHash PSP_FOGCOLOR{"FogColor"};
-inline const StringHash PSP_FOGPARAMS{"FogParams"};
-inline const StringHash PSP_GBUFFERINVSIZE{"GBufferInvSize"};
-inline const StringHash PSP_LIGHTCOLOR{"LightColor"};
-inline const StringHash PSP_LIGHTLENGTH{"LightLength"};
-inline const StringHash PSP_LIGHTRAD{"LightRad"};
-inline const StringHash PSP_MATDIFFCOLOR{"MatDiffColor"};
-inline const StringHash PSP_MATEMISSIVECOLOR{"MatEmissiveColor"};
-inline const StringHash PSP_MATENVMAPCOLOR{"MatEnvMapColor"};
-inline const StringHash PSP_MATSPECCOLOR{"MatSpecColor"};
-inline const StringHash PSP_METALLIC{"Metallic"};
-inline const StringHash PSP_ROUGHNESS{"Roughness"};
-inline const StringHash PSP_SHADOWCUBEADJUST{"ShadowCubeAdjust"};
-inline const StringHash PSP_SHADOWDEPTHFADE{"ShadowDepthFade"};
-inline const StringHash PSP_SHADOWINTENSITY{"ShadowIntensity"};
-inline const StringHash PSP_SHADOWMAPINVSIZE{"ShadowMapInvSize"};
-inline const StringHash PSP_SHADOWSPLITS{"ShadowSplits"};
-inline const StringHash PSP_VSMSHADOWPARAMS{"VSMShadowParams"};
-inline const StringHash PSP_ZONEMAX{"ZoneMax"};
-inline const StringHash PSP_ZONEMIN{"ZoneMin"};
-
-inline const StringHash VSP_CAMERAPOS{"CameraPos"};
-inline const StringHash PSP_CAMERAPOS{"CameraPosPS"};
-
-inline const StringHash VSP_DELTATIME{"DeltaTime"};
-inline const StringHash PSP_DELTATIME{"DeltaTimePS"};
-
-inline const StringHash VSP_ELAPSEDTIME{"ElapsedTime"};
-inline const StringHash PSP_ELAPSEDTIME{"ElapsedTimePS"};
-
-inline const StringHash VSP_FARCLIP{"FarClip"};
-inline const StringHash PSP_FARCLIP{"FarClipPS"};
-
-inline const StringHash VSP_LIGHTDIR{"LightDir"};
-inline const StringHash PSP_LIGHTDIR{"LightDirPS"};
-
-inline const StringHash VSP_LIGHTMATRICES{"LightMatrices"};
-inline const StringHash PSP_LIGHTMATRICES{"LightMatricesPS"};
-
-inline const StringHash VSP_LIGHTPOS{"LightPos"};
-inline const StringHash PSP_LIGHTPOS{"LightPosPS"};
-
-inline const StringHash VSP_NEARCLIP{"NearClip"};
-inline const StringHash PSP_NEARCLIP{"NearClipPS"};
-
-inline const StringHash VSP_NORMALOFFSETSCALE{"NormalOffsetScale"};
-inline const StringHash PSP_NORMALOFFSETSCALE{"NormalOffsetScalePS"};
-
-// Scale calculation from bounding box diagonal.
-inline const Vector3 DOT_SCALE{1 / 3.0f, 1 / 3.0f, 1 / 3.0f};
-
-enum MaterialQuality : u32
-{
-    QUALITY_LOW = 0,
-    QUALITY_MEDIUM = 1,
-    QUALITY_HIGH = 2,
-    QUALITY_MAX = 15,
-};
-
-enum ClearTarget : u32
-{
-    CLEAR_COLOR = 0x1,
-    CLEAR_DEPTH = 0x2,
-    CLEAR_STENCIL = 0x4,
-};
-URHO3D_FLAGSET(ClearTarget, ClearTargetFlags);
-
-// Legacy vertex element bitmasks.
-enum VertexMask : u32
-{
-    MASK_NONE = 0x0,
-    MASK_POSITION = 0x1,
-    MASK_NORMAL = 0x2,
-    MASK_COLOR = 0x4,
-    MASK_TEXCOORD1 = 0x8,
-    MASK_TEXCOORD2 = 0x10,
-    MASK_CUBETEXCOORD1 = 0x20,
-    MASK_CUBETEXCOORD2 = 0x40,
-    MASK_TANGENT = 0x80,
-    MASK_BLENDWEIGHTS = 0x100,
-    MASK_BLENDINDICES = 0x200,
-    MASK_INSTANCEMATRIX1 = 0x400,
-    MASK_INSTANCEMATRIX2 = 0x800,
-    MASK_INSTANCEMATRIX3 = 0x1000,
-    MASK_OBJECTINDEX = 0x2000,
-};
-URHO3D_FLAGSET(VertexMask, VertexMaskFlags);
-
-inline constexpr i32 MAX_RENDERTARGETS = 4;
-inline constexpr i32 MAX_VERTEX_STREAMS = 4;
-inline constexpr i32 MAX_CONSTANT_REGISTERS = 256;
-
-inline constexpr i32 BITS_PER_COMPONENT = 8;
-
-} // namespace Urho3D
+//
+// Copyright (c) 2008-2022 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.
+//
+
+/// \file
+
+#pragma once
+
+#include "../Container/FlagSet.h"
+#include "../Container/HashBase.h"
+#include "../Math/StringHash.h"
+#include "../Math/Vector3.h"
+
+namespace Urho3D
+{
+
+class Vector3;
+
+// Graphics capability support level. Web platform (Emscripten) also uses OpenGL ES, but is considered a desktop platform capability-wise
+#if defined(IOS) || defined(TVOS) || defined(__ANDROID__) || defined(__arm__) || defined(__aarch64__)
+#define MOBILE_GRAPHICS
+#else
+#define DESKTOP_GRAPHICS
+#endif
+
+enum GAPI
+{
+    GAPI_NONE = 0,
+    GAPI_OPENGL,
+    GAPI_D3D9,
+    GAPI_D3D11
+};
+
+/// Primitive type.
+enum PrimitiveType
+{
+    TRIANGLE_LIST = 0,
+    LINE_LIST,
+    POINT_LIST,
+    TRIANGLE_STRIP,
+    LINE_STRIP,
+    TRIANGLE_FAN
+};
+
+/// %Geometry type for vertex shader geometry variations.
+enum GeometryType
+{
+    GEOM_STATIC = 0,
+    GEOM_SKINNED = 1,
+    GEOM_INSTANCED = 2,
+    GEOM_BILLBOARD = 3,
+    GEOM_DIRBILLBOARD = 4,
+    GEOM_TRAIL_FACE_CAMERA = 5,
+    GEOM_TRAIL_BONE = 6,
+    MAX_GEOMETRYTYPES = 7,
+    // This is not a real geometry type for VS, but used to mark objects that do not desire to be instanced
+    GEOM_STATIC_NOINSTANCING = 7,
+};
+
+/// Blending mode.
+enum BlendMode
+{
+    BLEND_REPLACE = 0,
+    BLEND_ADD,
+    BLEND_MULTIPLY,
+    BLEND_ALPHA,
+    BLEND_ADDALPHA,
+    BLEND_PREMULALPHA,
+    BLEND_INVDESTALPHA,
+    BLEND_SUBTRACT,
+    BLEND_SUBTRACTALPHA,
+    MAX_BLENDMODES
+};
+
+/// Depth or stencil compare mode.
+enum CompareMode
+{
+    CMP_ALWAYS = 0,
+    CMP_EQUAL,
+    CMP_NOTEQUAL,
+    CMP_LESS,
+    CMP_LESSEQUAL,
+    CMP_GREATER,
+    CMP_GREATEREQUAL,
+    MAX_COMPAREMODES
+};
+
+/// Culling mode.
+enum CullMode
+{
+    CULL_NONE = 0,
+    CULL_CCW,
+    CULL_CW,
+    MAX_CULLMODES
+};
+
+/// Fill mode.
+enum FillMode
+{
+    FILL_SOLID = 0,
+    FILL_WIREFRAME,
+    FILL_POINT
+};
+
+/// Stencil operation.
+enum StencilOp
+{
+    OP_KEEP = 0,
+    OP_ZERO,
+    OP_REF,
+    OP_INCR,
+    OP_DECR
+};
+
+/// Vertex/index buffer lock state.
+enum LockState
+{
+    LOCK_NONE = 0,
+    LOCK_HARDWARE,
+    LOCK_SHADOW,
+    LOCK_SCRATCH
+};
+
+/// Hardcoded legacy vertex elements.
+enum LegacyVertexElement
+{
+    ELEMENT_POSITION = 0,
+    ELEMENT_NORMAL,
+    ELEMENT_COLOR,
+    ELEMENT_TEXCOORD1,
+    ELEMENT_TEXCOORD2,
+    ELEMENT_CUBETEXCOORD1,
+    ELEMENT_CUBETEXCOORD2,
+    ELEMENT_TANGENT,
+    ELEMENT_BLENDWEIGHTS,
+    ELEMENT_BLENDINDICES,
+    ELEMENT_INSTANCEMATRIX1,
+    ELEMENT_INSTANCEMATRIX2,
+    ELEMENT_INSTANCEMATRIX3,
+    // Custom 32-bit integer object index. Due to API limitations, not supported on D3D9
+    ELEMENT_OBJECTINDEX,
+    MAX_LEGACY_VERTEX_ELEMENTS
+};
+
+/// Arbitrary vertex declaration element datatypes.
+enum VertexElementType
+{
+    TYPE_INT = 0,
+    TYPE_FLOAT,
+    TYPE_VECTOR2,
+    TYPE_VECTOR3,
+    TYPE_VECTOR4,
+    TYPE_UBYTE4,
+    TYPE_UBYTE4_NORM,
+    MAX_VERTEX_ELEMENT_TYPES
+};
+
+/// Arbitrary vertex declaration element semantics.
+enum VertexElementSemantic
+{
+    SEM_POSITION = 0,
+    SEM_NORMAL,
+    SEM_BINORMAL,
+    SEM_TANGENT,
+    SEM_TEXCOORD,
+    SEM_COLOR,
+    SEM_BLENDWEIGHTS,
+    SEM_BLENDINDICES,
+    SEM_OBJECTINDEX,
+    MAX_VERTEX_ELEMENT_SEMANTICS
+};
+
+/// Vertex element description for arbitrary vertex declarations.
+struct URHO3D_API VertexElement
+{
+    /// Default-construct.
+    VertexElement() noexcept :
+        type_(TYPE_VECTOR3),
+        semantic_(SEM_POSITION),
+        index_(0),
+        perInstance_(false),
+        offset_(0)
+    {
+    }
+
+    /// Construct with type, semantic, index and whether is per-instance data.
+    VertexElement(VertexElementType type, VertexElementSemantic semantic, unsigned char index = 0, bool perInstance = false) noexcept :
+        type_(type),
+        semantic_(semantic),
+        index_(index),
+        perInstance_(perInstance),
+        offset_(0)
+    {
+    }
+
+    /// Test for equality with another vertex element. Offset is intentionally not compared, as it's relevant only when an element exists within a vertex buffer.
+    bool operator ==(const VertexElement& rhs) const { return type_ == rhs.type_ && semantic_ == rhs.semantic_ && index_ == rhs.index_ && perInstance_ == rhs.perInstance_; }
+
+    /// Test for inequality with another vertex element.
+    bool operator !=(const VertexElement& rhs) const { return !(*this == rhs); }
+
+    /// Data type of element.
+    VertexElementType type_;
+    /// Semantic of element.
+    VertexElementSemantic semantic_;
+    /// Semantic index of element, for example multi-texcoords.
+    unsigned char index_;
+    /// Per-instance flag.
+    bool perInstance_;
+    /// Offset of element from vertex start. Filled by VertexBuffer once the vertex declaration is built.
+    unsigned offset_;
+};
+
+/// Sizes of vertex element types.
+extern URHO3D_API const u32 ELEMENT_TYPESIZES[];
+
+/// Vertex element definitions for the legacy elements.
+extern URHO3D_API const VertexElement LEGACY_VERTEXELEMENTS[];
+
+/// Texture filtering mode.
+enum TextureFilterMode
+{
+    FILTER_NEAREST = 0,
+    FILTER_BILINEAR,
+    FILTER_TRILINEAR,
+    FILTER_ANISOTROPIC,
+    FILTER_NEAREST_ANISOTROPIC,
+    FILTER_DEFAULT,
+    MAX_FILTERMODES
+};
+
+/// Texture addressing mode.
+enum TextureAddressMode
+{
+    ADDRESS_WRAP = 0,
+    ADDRESS_MIRROR,
+    ADDRESS_CLAMP,
+    ADDRESS_BORDER,
+    MAX_ADDRESSMODES
+};
+
+/// Texture coordinates.
+enum TextureCoordinate
+{
+    COORD_U = 0,
+    COORD_V,
+    COORD_W,
+    MAX_COORDS
+};
+
+/// Texture usage types.
+enum TextureUsage
+{
+    TEXTURE_STATIC = 0,
+    TEXTURE_DYNAMIC,
+    TEXTURE_RENDERTARGET,
+    TEXTURE_DEPTHSTENCIL
+};
+
+/// Cube map faces.
+enum CubeMapFace
+{
+    FACE_POSITIVE_X = 0,
+    FACE_NEGATIVE_X,
+    FACE_POSITIVE_Y,
+    FACE_NEGATIVE_Y,
+    FACE_POSITIVE_Z,
+    FACE_NEGATIVE_Z,
+    MAX_CUBEMAP_FACES
+};
+
+/// Cubemap single image layout modes.
+enum CubeMapLayout
+{
+    CML_HORIZONTAL = 0,
+    CML_HORIZONTALNVIDIA,
+    CML_HORIZONTALCROSS,
+    CML_VERTICALCROSS,
+    CML_BLENDER
+};
+
+/// Update mode for render surface viewports.
+enum RenderSurfaceUpdateMode
+{
+    SURFACE_MANUALUPDATE = 0,
+    SURFACE_UPDATEVISIBLE,
+    SURFACE_UPDATEALWAYS
+};
+
+/// Shader types.
+enum ShaderType
+{
+    VS = 0,
+    PS,
+};
+
+/// Shader parameter groups for determining need to update. On APIs that support constant buffers, these correspond to different constant buffers.
+enum ShaderParameterGroup
+{
+    SP_FRAME = 0,
+    SP_CAMERA,
+    SP_ZONE,
+    SP_LIGHT,
+    SP_MATERIAL,
+    SP_OBJECT,
+    SP_CUSTOM,
+    MAX_SHADER_PARAMETER_GROUPS
+};
+
+/// Texture units.
+/// @manualbind
+enum TextureUnit
+{
+    TU_DIFFUSE = 0,
+    TU_ALBEDOBUFFER = 0,
+    TU_NORMAL = 1,
+    TU_NORMALBUFFER = 1,
+    TU_SPECULAR = 2,
+    TU_EMISSIVE = 3,
+    TU_ENVIRONMENT = 4,
+#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
+    TU_LIGHTRAMP = 5,
+    TU_LIGHTSHAPE = 6,
+    TU_SHADOWMAP = 7,
+    MAX_MATERIAL_TEXTURE_UNITS = 5,
+    MAX_TEXTURE_UNITS = 8
+#endif
+};
+
+/// Billboard camera facing modes.
+enum FaceCameraMode
+{
+    FC_NONE = 0,
+    FC_ROTATE_XYZ,
+    FC_ROTATE_Y,
+    FC_LOOKAT_XYZ,
+    FC_LOOKAT_Y,
+    FC_LOOKAT_MIXED,
+    FC_DIRECTION,
+};
+
+/// Shadow type.
+enum ShadowQuality
+{
+    SHADOWQUALITY_SIMPLE_16BIT = 0,
+    SHADOWQUALITY_SIMPLE_24BIT,
+    SHADOWQUALITY_PCF_16BIT,
+    SHADOWQUALITY_PCF_24BIT,
+    SHADOWQUALITY_VSM,
+    SHADOWQUALITY_BLUR_VSM
+};
+
+// Inbuilt shader parameters.
+inline const StringHash VSP_AMBIENTENDCOLOR{"AmbientEndColor"};
+inline const StringHash VSP_AMBIENTSTARTCOLOR{"AmbientStartColor"};
+inline const StringHash VSP_BILLBOARDROT{"BillboardRot"};
+inline const StringHash VSP_CLIPPLANE{"ClipPlane"};
+inline const StringHash VSP_DEPTHMODE{"DepthMode"};
+inline const StringHash VSP_FRUSTUMSIZE{"FrustumSize"};
+inline const StringHash VSP_GBUFFEROFFSETS{"GBufferOffsets"};
+inline const StringHash VSP_MODEL{"Model"};
+inline const StringHash VSP_SKINMATRICES{"SkinMatrices"};
+inline const StringHash VSP_UOFFSET{"UOffset"};
+inline const StringHash VSP_VERTEXLIGHTS{"VertexLights"};
+inline const StringHash VSP_VIEW{"View"};
+inline const StringHash VSP_VIEWINV{"ViewInv"};
+inline const StringHash VSP_VIEWPROJ{"ViewProj"};
+inline const StringHash VSP_VOFFSET{"VOffset"};
+inline const StringHash VSP_ZONE{"Zone"};
+inline const StringHash PSP_AMBIENTCOLOR{"AmbientColor"};
+inline const StringHash PSP_DEPTHRECONSTRUCT{"DepthReconstruct"};
+inline const StringHash PSP_FOGCOLOR{"FogColor"};
+inline const StringHash PSP_FOGPARAMS{"FogParams"};
+inline const StringHash PSP_GBUFFERINVSIZE{"GBufferInvSize"};
+inline const StringHash PSP_LIGHTCOLOR{"LightColor"};
+inline const StringHash PSP_LIGHTLENGTH{"LightLength"};
+inline const StringHash PSP_LIGHTRAD{"LightRad"};
+inline const StringHash PSP_MATDIFFCOLOR{"MatDiffColor"};
+inline const StringHash PSP_MATEMISSIVECOLOR{"MatEmissiveColor"};
+inline const StringHash PSP_MATENVMAPCOLOR{"MatEnvMapColor"};
+inline const StringHash PSP_MATSPECCOLOR{"MatSpecColor"};
+inline const StringHash PSP_METALLIC{"Metallic"};
+inline const StringHash PSP_ROUGHNESS{"Roughness"};
+inline const StringHash PSP_SHADOWCUBEADJUST{"ShadowCubeAdjust"};
+inline const StringHash PSP_SHADOWDEPTHFADE{"ShadowDepthFade"};
+inline const StringHash PSP_SHADOWINTENSITY{"ShadowIntensity"};
+inline const StringHash PSP_SHADOWMAPINVSIZE{"ShadowMapInvSize"};
+inline const StringHash PSP_SHADOWSPLITS{"ShadowSplits"};
+inline const StringHash PSP_VSMSHADOWPARAMS{"VSMShadowParams"};
+inline const StringHash PSP_ZONEMAX{"ZoneMax"};
+inline const StringHash PSP_ZONEMIN{"ZoneMin"};
+
+inline const StringHash VSP_CAMERAPOS{"CameraPos"};
+inline const StringHash PSP_CAMERAPOS{"CameraPosPS"};
+
+inline const StringHash VSP_DELTATIME{"DeltaTime"};
+inline const StringHash PSP_DELTATIME{"DeltaTimePS"};
+
+inline const StringHash VSP_ELAPSEDTIME{"ElapsedTime"};
+inline const StringHash PSP_ELAPSEDTIME{"ElapsedTimePS"};
+
+inline const StringHash VSP_FARCLIP{"FarClip"};
+inline const StringHash PSP_FARCLIP{"FarClipPS"};
+
+inline const StringHash VSP_LIGHTDIR{"LightDir"};
+inline const StringHash PSP_LIGHTDIR{"LightDirPS"};
+
+inline const StringHash VSP_LIGHTMATRICES{"LightMatrices"};
+inline const StringHash PSP_LIGHTMATRICES{"LightMatricesPS"};
+
+inline const StringHash VSP_LIGHTPOS{"LightPos"};
+inline const StringHash PSP_LIGHTPOS{"LightPosPS"};
+
+inline const StringHash VSP_NEARCLIP{"NearClip"};
+inline const StringHash PSP_NEARCLIP{"NearClipPS"};
+
+inline const StringHash VSP_NORMALOFFSETSCALE{"NormalOffsetScale"};
+inline const StringHash PSP_NORMALOFFSETSCALE{"NormalOffsetScalePS"};
+
+// Scale calculation from bounding box diagonal.
+inline const Vector3 DOT_SCALE{1 / 3.0f, 1 / 3.0f, 1 / 3.0f};
+
+enum MaterialQuality : u32
+{
+    QUALITY_LOW = 0,
+    QUALITY_MEDIUM = 1,
+    QUALITY_HIGH = 2,
+    QUALITY_MAX = 15,
+};
+
+enum ClearTarget : u32
+{
+    CLEAR_COLOR = 0x1,
+    CLEAR_DEPTH = 0x2,
+    CLEAR_STENCIL = 0x4,
+};
+URHO3D_FLAGSET(ClearTarget, ClearTargetFlags);
+
+// Legacy vertex element bitmasks.
+enum VertexMask : u32
+{
+    MASK_NONE = 0x0,
+    MASK_POSITION = 0x1,
+    MASK_NORMAL = 0x2,
+    MASK_COLOR = 0x4,
+    MASK_TEXCOORD1 = 0x8,
+    MASK_TEXCOORD2 = 0x10,
+    MASK_CUBETEXCOORD1 = 0x20,
+    MASK_CUBETEXCOORD2 = 0x40,
+    MASK_TANGENT = 0x80,
+    MASK_BLENDWEIGHTS = 0x100,
+    MASK_BLENDINDICES = 0x200,
+    MASK_INSTANCEMATRIX1 = 0x400,
+    MASK_INSTANCEMATRIX2 = 0x800,
+    MASK_INSTANCEMATRIX3 = 0x1000,
+    MASK_OBJECTINDEX = 0x2000,
+};
+URHO3D_FLAGSET(VertexMask, VertexMaskFlags);
+
+inline constexpr i32 MAX_RENDERTARGETS = 4;
+inline constexpr i32 MAX_VERTEX_STREAMS = 4;
+inline constexpr i32 MAX_CONSTANT_REGISTERS = 256;
+
+inline constexpr i32 BITS_PER_COMPONENT = 8;
+
+} // namespace Urho3D

+ 38 - 38
Source/Urho3D/Graphics/GraphicsImpl.h → Source/Urho3D/GraphicsAPI/GraphicsImpl.h

@@ -1,38 +1,38 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#pragma once
-
-// Note: GraphicsImpl class is purposefully API-specific. It should not be used by Urho3D client applications,
-// unless required for e.g. integration of 3rd party libraries that interface directly with the graphics device.
-
-#ifdef URHO3D_OPENGL
-#include "OpenGL/OGLGraphicsImpl.h"
-#endif
-
-#ifdef URHO3D_D3D9
-#include "Direct3D9/D3D9GraphicsImpl.h"
-#endif
-
-#ifdef URHO3D_D3D11
-#include "Direct3D11/D3D11GraphicsImpl.h"
-#endif
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+// Note: GraphicsImpl class is purposefully API-specific. It should not be used by Urho3D client applications,
+// unless required for e.g. integration of 3rd party libraries that interface directly with the graphics device.
+
+#ifdef URHO3D_OPENGL
+#include "OpenGL/OGLGraphicsImpl.h"
+#endif
+
+#ifdef URHO3D_D3D9
+#include "Direct3D9/D3D9GraphicsImpl.h"
+#endif
+
+#ifdef URHO3D_D3D11
+#include "Direct3D11/D3D11GraphicsImpl.h"
+#endif

+ 1 - 1
Source/Urho3D/Graphics/IndexBuffer.cpp → Source/Urho3D/GraphicsAPI/IndexBuffer.cpp

@@ -25,7 +25,7 @@
 #include "../Precompiled.h"
 
 #include "../Graphics/Graphics.h"
-#include "../Graphics/IndexBuffer.h"
+#include "../GraphicsAPI/IndexBuffer.h"
 #include "../IO/Log.h"
 
 #include "../DebugNew.h"

+ 167 - 167
Source/Urho3D/Graphics/IndexBuffer.h → Source/Urho3D/GraphicsAPI/IndexBuffer.h

@@ -1,167 +1,167 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#pragma once
-
-#include "../Core/Object.h"
-#include "../Container/ArrayPtr.h"
-#include "../Graphics/GPUObject.h"
-#include "../Graphics/GraphicsDefs.h"
-
-namespace Urho3D
-{
-
-/// Hardware index buffer.
-class URHO3D_API IndexBuffer : public Object, public GPUObject
-{
-    URHO3D_OBJECT(IndexBuffer, Object);
-
-public:
-    /// Construct. Optionally force headless (no GPU-side buffer) operation.
-    explicit IndexBuffer(Context* context, bool forceHeadless = false);
-    /// Destruct.
-    ~IndexBuffer() override;
-
-    /// Mark the buffer destroyed on graphics context destruction. May be a no-op depending on the API.
-    void OnDeviceLost() override;
-    /// Recreate the buffer and restore data if applicable. May be a no-op depending on the API.
-    void OnDeviceReset() override;
-    /// Release buffer.
-    void Release() override;
-
-    /// Enable shadowing in CPU memory. Shadowing is forced on if the graphics subsystem does not exist.
-    /// @property
-    void SetShadowed(bool enable);
-    /// Set size and vertex elements and dynamic mode. Previous data will be lost.
-    bool SetSize(unsigned indexCount, bool largeIndices, bool dynamic = false);
-    /// Set all data in the buffer.
-    bool SetData(const void* data);
-    /// Set a data range in the buffer. Optionally discard data outside the range.
-    bool SetDataRange(const void* data, unsigned start, unsigned count, bool discard = false);
-    /// Lock the buffer for write-only editing. Return data pointer if successful. Optionally discard data outside the range.
-    void* Lock(unsigned start, unsigned count, bool discard = false);
-    /// Unlock the buffer and apply changes to the GPU buffer.
-    void Unlock();
-
-    /// Return whether CPU memory shadowing is enabled.
-    /// @property
-    bool IsShadowed() const { return shadowed_; }
-
-    /// Return whether is dynamic.
-    /// @property
-    bool IsDynamic() const { return dynamic_; }
-
-    /// Return whether is currently locked.
-    bool IsLocked() const { return lockState_ != LOCK_NONE; }
-
-    /// Return number of indices.
-    /// @property
-    unsigned GetIndexCount() const { return indexCount_; }
-
-    /// Return index size in bytes.
-    /// @property
-    unsigned GetIndexSize() const { return indexSize_; }
-
-    /// Return used vertex range from index range.
-    bool GetUsedVertexRange(unsigned start, unsigned count, unsigned& minVertex, unsigned& vertexCount);
-
-    /// Return CPU memory shadow data.
-    unsigned char* GetShadowData() const { return shadowData_.Get(); }
-
-    /// Return shared array pointer to the CPU memory shadow data.
-    SharedArrayPtr<unsigned char> GetShadowDataShared() const { return shadowData_; }
-
-private:
-    /// Create buffer.
-    bool Create();
-    /// Update the shadow data to the GPU buffer.
-    bool UpdateToGPU();
-    /// Map the GPU buffer into CPU memory. Not used on OpenGL.
-    void* MapBuffer(unsigned start, unsigned count, bool discard);
-    /// Unmap the GPU buffer. Not used on OpenGL.
-    void UnmapBuffer();
-
-#ifdef URHO3D_OPENGL
-    void OnDeviceLost_OGL();
-    void OnDeviceReset_OGL();
-    void Release_OGL();
-    bool SetData_OGL(const void* data);
-    bool SetDataRange_OGL(const void* data, unsigned start, unsigned count, bool discard = false);
-    void* Lock_OGL(unsigned start, unsigned count, bool discard);
-    void Unlock_OGL();
-    bool Create_OGL();
-    bool UpdateToGPU_OGL();
-    void* MapBuffer_OGL(unsigned start, unsigned count, bool discard);
-    void UnmapBuffer_OGL();
-#endif // def URHO3D_OPENGL
-
-#ifdef URHO3D_D3D9
-    void OnDeviceLost_D3D9();
-    void OnDeviceReset_D3D9();
-    void Release_D3D9();
-    bool SetData_D3D9(const void* data);
-    bool SetDataRange_D3D9(const void* data, unsigned start, unsigned count, bool discard = false);
-    void* Lock_D3D9(unsigned start, unsigned count, bool discard);
-    void Unlock_D3D9();
-    bool Create_D3D9();
-    bool UpdateToGPU_D3D9();
-    void* MapBuffer_D3D9(unsigned start, unsigned count, bool discard);
-    void UnmapBuffer_D3D9();
-#endif // def URHO3D_D3D9
-
-#ifdef URHO3D_D3D11
-    void OnDeviceLost_D3D11();
-    void OnDeviceReset_D3D11();
-    void Release_D3D11();
-    bool SetData_D3D11(const void* data);
-    bool SetDataRange_D3D11(const void* data, unsigned start, unsigned count, bool discard = false);
-    void* Lock_D3D11(unsigned start, unsigned count, bool discard);
-    void Unlock_D3D11();
-    bool Create_D3D11();
-    bool UpdateToGPU_D3D11();
-    void* MapBuffer_D3D11(unsigned start, unsigned count, bool discard);
-    void UnmapBuffer_D3D11();
-#endif // def URHO3D_D3D11
-
-    /// Shadow data.
-    SharedArrayPtr<unsigned char> shadowData_;
-    /// Number of indices.
-    unsigned indexCount_;
-    /// Index size.
-    unsigned indexSize_;
-    /// Buffer locking state.
-    LockState lockState_;
-    /// Lock start vertex.
-    unsigned lockStart_;
-    /// Lock number of vertices.
-    unsigned lockCount_;
-    /// Scratch buffer for fallback locking.
-    void* lockScratchData_;
-    /// Dynamic flag.
-    bool dynamic_;
-    /// Shadowed flag.
-    bool shadowed_;
-    /// Discard lock flag. Used by OpenGL only.
-    bool discardLock_;
-};
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "../Container/ArrayPtr.h"
+#include "../Core/Object.h"
+#include "../GraphicsAPI/GPUObject.h"
+#include "../GraphicsAPI/GraphicsDefs.h"
+
+namespace Urho3D
+{
+
+/// Hardware index buffer.
+class URHO3D_API IndexBuffer : public Object, public GPUObject
+{
+    URHO3D_OBJECT(IndexBuffer, Object);
+
+public:
+    /// Construct. Optionally force headless (no GPU-side buffer) operation.
+    explicit IndexBuffer(Context* context, bool forceHeadless = false);
+    /// Destruct.
+    ~IndexBuffer() override;
+
+    /// Mark the buffer destroyed on graphics context destruction. May be a no-op depending on the API.
+    void OnDeviceLost() override;
+    /// Recreate the buffer and restore data if applicable. May be a no-op depending on the API.
+    void OnDeviceReset() override;
+    /// Release buffer.
+    void Release() override;
+
+    /// Enable shadowing in CPU memory. Shadowing is forced on if the graphics subsystem does not exist.
+    /// @property
+    void SetShadowed(bool enable);
+    /// Set size and vertex elements and dynamic mode. Previous data will be lost.
+    bool SetSize(unsigned indexCount, bool largeIndices, bool dynamic = false);
+    /// Set all data in the buffer.
+    bool SetData(const void* data);
+    /// Set a data range in the buffer. Optionally discard data outside the range.
+    bool SetDataRange(const void* data, unsigned start, unsigned count, bool discard = false);
+    /// Lock the buffer for write-only editing. Return data pointer if successful. Optionally discard data outside the range.
+    void* Lock(unsigned start, unsigned count, bool discard = false);
+    /// Unlock the buffer and apply changes to the GPU buffer.
+    void Unlock();
+
+    /// Return whether CPU memory shadowing is enabled.
+    /// @property
+    bool IsShadowed() const { return shadowed_; }
+
+    /// Return whether is dynamic.
+    /// @property
+    bool IsDynamic() const { return dynamic_; }
+
+    /// Return whether is currently locked.
+    bool IsLocked() const { return lockState_ != LOCK_NONE; }
+
+    /// Return number of indices.
+    /// @property
+    unsigned GetIndexCount() const { return indexCount_; }
+
+    /// Return index size in bytes.
+    /// @property
+    unsigned GetIndexSize() const { return indexSize_; }
+
+    /// Return used vertex range from index range.
+    bool GetUsedVertexRange(unsigned start, unsigned count, unsigned& minVertex, unsigned& vertexCount);
+
+    /// Return CPU memory shadow data.
+    unsigned char* GetShadowData() const { return shadowData_.Get(); }
+
+    /// Return shared array pointer to the CPU memory shadow data.
+    SharedArrayPtr<unsigned char> GetShadowDataShared() const { return shadowData_; }
+
+private:
+    /// Create buffer.
+    bool Create();
+    /// Update the shadow data to the GPU buffer.
+    bool UpdateToGPU();
+    /// Map the GPU buffer into CPU memory. Not used on OpenGL.
+    void* MapBuffer(unsigned start, unsigned count, bool discard);
+    /// Unmap the GPU buffer. Not used on OpenGL.
+    void UnmapBuffer();
+
+#ifdef URHO3D_OPENGL
+    void OnDeviceLost_OGL();
+    void OnDeviceReset_OGL();
+    void Release_OGL();
+    bool SetData_OGL(const void* data);
+    bool SetDataRange_OGL(const void* data, unsigned start, unsigned count, bool discard = false);
+    void* Lock_OGL(unsigned start, unsigned count, bool discard);
+    void Unlock_OGL();
+    bool Create_OGL();
+    bool UpdateToGPU_OGL();
+    void* MapBuffer_OGL(unsigned start, unsigned count, bool discard);
+    void UnmapBuffer_OGL();
+#endif // def URHO3D_OPENGL
+
+#ifdef URHO3D_D3D9
+    void OnDeviceLost_D3D9();
+    void OnDeviceReset_D3D9();
+    void Release_D3D9();
+    bool SetData_D3D9(const void* data);
+    bool SetDataRange_D3D9(const void* data, unsigned start, unsigned count, bool discard = false);
+    void* Lock_D3D9(unsigned start, unsigned count, bool discard);
+    void Unlock_D3D9();
+    bool Create_D3D9();
+    bool UpdateToGPU_D3D9();
+    void* MapBuffer_D3D9(unsigned start, unsigned count, bool discard);
+    void UnmapBuffer_D3D9();
+#endif // def URHO3D_D3D9
+
+#ifdef URHO3D_D3D11
+    void OnDeviceLost_D3D11();
+    void OnDeviceReset_D3D11();
+    void Release_D3D11();
+    bool SetData_D3D11(const void* data);
+    bool SetDataRange_D3D11(const void* data, unsigned start, unsigned count, bool discard = false);
+    void* Lock_D3D11(unsigned start, unsigned count, bool discard);
+    void Unlock_D3D11();
+    bool Create_D3D11();
+    bool UpdateToGPU_D3D11();
+    void* MapBuffer_D3D11(unsigned start, unsigned count, bool discard);
+    void UnmapBuffer_D3D11();
+#endif // def URHO3D_D3D11
+
+    /// Shadow data.
+    SharedArrayPtr<unsigned char> shadowData_;
+    /// Number of indices.
+    unsigned indexCount_;
+    /// Index size.
+    unsigned indexSize_;
+    /// Buffer locking state.
+    LockState lockState_;
+    /// Lock start vertex.
+    unsigned lockStart_;
+    /// Lock number of vertices.
+    unsigned lockCount_;
+    /// Scratch buffer for fallback locking.
+    void* lockScratchData_;
+    /// Dynamic flag.
+    bool dynamic_;
+    /// Shadowed flag.
+    bool shadowed_;
+    /// Discard lock flag. Used by OpenGL only.
+    bool discardLock_;
+};
+
+}

+ 2 - 2
Source/Urho3D/Graphics/OpenGL/OGLConstantBuffer.cpp → Source/Urho3D/GraphicsAPI/OpenGL/OGLConstantBuffer.cpp

@@ -23,8 +23,8 @@
 #include "../../Precompiled.h"
 
 #include "../../Graphics/Graphics.h"
-#include "../../Graphics/GraphicsImpl.h"
-#include "../../Graphics/ConstantBuffer.h"
+#include "../../GraphicsAPI/ConstantBuffer.h"
+#include "../../GraphicsAPI/GraphicsImpl.h"
 #include "../../IO/Log.h"
 
 #include "../../DebugNew.h"

+ 3439 - 3440
Source/Urho3D/Graphics/OpenGL/OGLGraphics.cpp → Source/Urho3D/GraphicsAPI/OpenGL/OGLGraphics.cpp

@@ -1,3440 +1,3439 @@
-//
-// Copyright (c) 2008-2022 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "../../Precompiled.h"
-
-#include "../../Core/Context.h"
-#include "../../Core/Mutex.h"
-#include "../../Core/ProcessUtils.h"
-#include "../../Core/Profiler.h"
-#include "../../Graphics/ConstantBuffer.h"
-#include "../../Graphics/Graphics.h"
-#include "../../Graphics/GraphicsEvents.h"
-
-#include "../../Graphics/IndexBuffer.h"
-#include "../../Graphics/RenderSurface.h"
-#include "../../Graphics/Shader.h"
-#include "../../Graphics/ShaderPrecache.h"
-#include "../../Graphics/ShaderVariation.h"
-#include "../../Graphics/Texture2D.h"
-#include "../../Graphics/TextureCube.h"
-#include "../../Graphics/VertexBuffer.h"
-#include "../../IO/File.h"
-#include "../../IO/Log.h"
-#include "../../Resource/ResourceCache.h"
-#include "OGLGraphicsImpl.h"
-#include "OGLShaderProgram.h"
-
-#include <SDL/SDL.h>
-
-#include "../../DebugNew.h"
-
-#ifdef GL_ES_VERSION_2_0
-#define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
-#define glClearDepth glClearDepthf
-#endif
-
-#ifdef __EMSCRIPTEN__
-#include "../../Input/Input.h"
-#include "../../UI/Cursor.h"
-#include "../../UI/UI.h"
-#include <emscripten/emscripten.h>
-#include <emscripten/bind.h>
-
-// Emscripten provides even all GL extension functions via static linking. However there is
-// no GLES2-specific extension header at the moment to include instanced rendering declarations,
-// so declare them manually from GLES3 gl2ext.h. Emscripten will provide these when linking final output.
-extern "C"
-{
-    GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
-    GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
-    GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor);
-}
-
-// Helper functions to support emscripten canvas resolution change
-static const Urho3D::Context *appContext;
-
-static void JSCanvasSize(int width, int height, bool fullscreen, float scale)
-{
-    URHO3D_LOGINFOF("JSCanvasSize: width=%d height=%d fullscreen=%d ui scale=%f", width, height, fullscreen, scale);
-
-    using namespace Urho3D;
-
-    if (appContext)
-    {
-        bool uiCursorVisible = false;
-        bool systemCursorVisible = false;
-        MouseMode mouseMode{};
-
-        // Detect current system pointer state
-        Input* input = appContext->GetSubsystem<Input>();
-        if (input)
-        {
-            systemCursorVisible = input->IsMouseVisible();
-            mouseMode = input->GetMouseMode();
-        }
-
-        UI* ui = appContext->GetSubsystem<UI>();
-        if (ui)
-        {
-            ui->SetScale(scale);
-
-            // Detect current UI pointer state
-            Cursor* cursor = ui->GetCursor();
-            if (cursor)
-                uiCursorVisible = cursor->IsVisible();
-        }
-
-        // Apply new resolution
-        appContext->GetSubsystem<Graphics>()->SetMode(width, height);
-
-        // Reset the pointer state as it was before resolution change
-        if (input)
-        {
-            if (uiCursorVisible)
-                input->SetMouseVisible(false);
-            else
-                input->SetMouseVisible(systemCursorVisible);
-
-            input->SetMouseMode(mouseMode);
-        }
-
-        if (ui)
-        {
-            Cursor* cursor = ui->GetCursor();
-            if (cursor)
-            {
-                cursor->SetVisible(uiCursorVisible);
-
-                IntVector2 pos = input->GetMousePosition();
-                pos = ui->ConvertSystemToUI(pos);
-
-                cursor->SetPosition(pos);
-            }
-        }
-    }
-}
-
-using namespace emscripten;
-EMSCRIPTEN_BINDINGS(Module) {
-    function("JSCanvasSize", &JSCanvasSize);
-}
-#endif
-
-namespace Urho3D
-{
-
-static const unsigned glCmpFunc[] =
-{
-    GL_ALWAYS,
-    GL_EQUAL,
-    GL_NOTEQUAL,
-    GL_LESS,
-    GL_LEQUAL,
-    GL_GREATER,
-    GL_GEQUAL
-};
-
-static const unsigned glSrcBlend[] =
-{
-    GL_ONE,
-    GL_ONE,
-    GL_DST_COLOR,
-    GL_SRC_ALPHA,
-    GL_SRC_ALPHA,
-    GL_ONE,
-    GL_ONE_MINUS_DST_ALPHA,
-    GL_ONE,
-    GL_SRC_ALPHA
-};
-
-static const unsigned glDestBlend[] =
-{
-    GL_ZERO,
-    GL_ONE,
-    GL_ZERO,
-    GL_ONE_MINUS_SRC_ALPHA,
-    GL_ONE,
-    GL_ONE_MINUS_SRC_ALPHA,
-    GL_DST_ALPHA,
-    GL_ONE,
-    GL_ONE
-};
-
-static const unsigned glBlendOp[] =
-{
-    GL_FUNC_ADD,
-    GL_FUNC_ADD,
-    GL_FUNC_ADD,
-    GL_FUNC_ADD,
-    GL_FUNC_ADD,
-    GL_FUNC_ADD,
-    GL_FUNC_ADD,
-    GL_FUNC_REVERSE_SUBTRACT,
-    GL_FUNC_REVERSE_SUBTRACT
-};
-
-#ifndef GL_ES_VERSION_2_0
-static const unsigned glFillMode[] =
-{
-    GL_FILL,
-    GL_LINE,
-    GL_POINT
-};
-
-static const unsigned glStencilOps[] =
-{
-    GL_KEEP,
-    GL_ZERO,
-    GL_REPLACE,
-    GL_INCR_WRAP,
-    GL_DECR_WRAP
-};
-#endif
-
-static const unsigned glElementTypes[] =
-{
-    GL_INT,
-    GL_FLOAT,
-    GL_FLOAT,
-    GL_FLOAT,
-    GL_FLOAT,
-    GL_UNSIGNED_BYTE,
-    GL_UNSIGNED_BYTE
-};
-
-static const unsigned glElementComponents[] =
-{
-    1,
-    1,
-    2,
-    3,
-    4,
-    4,
-    4
-};
-
-#ifdef GL_ES_VERSION_2_0
-static unsigned glesDepthStencilFormat = GL_DEPTH_COMPONENT16;
-static unsigned glesReadableDepthFormat = GL_DEPTH_COMPONENT;
-#endif
-
-static String extensions;
-
-bool CheckExtension(const String& name)
-{
-    if (extensions.Empty())
-        extensions = (const char*)glGetString(GL_EXTENSIONS);
-    return extensions.Contains(name);
-}
-
-static void GetGLPrimitiveType(unsigned elementCount, PrimitiveType type, unsigned& primitiveCount, GLenum& glPrimitiveType)
-{
-    switch (type)
-    {
-    case TRIANGLE_LIST:
-        primitiveCount = elementCount / 3;
-        glPrimitiveType = GL_TRIANGLES;
-        break;
-
-    case LINE_LIST:
-        primitiveCount = elementCount / 2;
-        glPrimitiveType = GL_LINES;
-        break;
-
-    case POINT_LIST:
-        primitiveCount = elementCount;
-        glPrimitiveType = GL_POINTS;
-        break;
-
-    case TRIANGLE_STRIP:
-        primitiveCount = elementCount - 2;
-        glPrimitiveType = GL_TRIANGLE_STRIP;
-        break;
-
-    case LINE_STRIP:
-        primitiveCount = elementCount - 1;
-        glPrimitiveType = GL_LINE_STRIP;
-        break;
-
-    case TRIANGLE_FAN:
-        primitiveCount = elementCount - 2;
-        glPrimitiveType = GL_TRIANGLE_FAN;
-        break;
-    }
-}
-
-void Graphics::Constructor_OGL()
-{
-    impl_ = new GraphicsImpl_OGL();
-    position_ = IntVector2(SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED);
-    shadowMapFormat_ = GL_DEPTH_COMPONENT16;
-    hiresShadowMapFormat_ = GL_DEPTH_COMPONENT24;
-    shaderPath_ = "Shaders/GLSL/";
-    shaderExtension_ = ".glsl";
-    orientations_ = "LandscapeLeft LandscapeRight";
-#ifndef GL_ES_VERSION_2_0
-    apiName_ = "GL2";
-#else
-    apiName_ = "GLES2";
-#endif
-
-    Graphics::pixelUVOffset = Vector2(0.0f, 0.0f);
-    Graphics::gl3Support = false;
-
-    SetTextureUnitMappings_OGL();
-    ResetCachedState_OGL();
-
-    context_->RequireSDL(SDL_INIT_VIDEO);
-
-    // Register Graphics library object factories
-    RegisterGraphicsLibrary(context_);
-
-#ifdef __EMSCRIPTEN__
-    appContext = context_;
-#endif
-}
-
-void Graphics::Destructor_OGL()
-{
-    Close_OGL();
-
-    delete impl_;
-    impl_ = nullptr;
-
-    context_->ReleaseSDL();
-}
-
-bool Graphics::SetScreenMode_OGL(int width, int height, const ScreenModeParams& params, bool maximize)
-{
-    URHO3D_PROFILE(SetScreenMode_OGL);
-
-    // Ensure that parameters are properly filled
-    ScreenModeParams newParams = params;
-    AdjustScreenMode(width, height, newParams, maximize);
-
-    if (IsInitialized_OGL() && width == width_ && height == height_ && screenParams_ == newParams)
-        return true;
-
-    // If only vsync changes, do not destroy/recreate the context
-    if (IsInitialized_OGL() && width == width_ && height == height_
-        && screenParams_.EqualsExceptVSync(newParams) && screenParams_.vsync_ != newParams.vsync_)
-    {
-        SDL_GL_SetSwapInterval(newParams.vsync_ ? 1 : 0);
-        screenParams_.vsync_ = newParams.vsync_;
-        return true;
-    }
-
-    // Track if the window was repositioned and don't update window position in this case
-    bool reposition = false;
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    // With an external window, only the size can change after initial setup, so do not recreate context
-    if (!externalWindow_ || !impl->context_)
-    {
-        // Close the existing window and OpenGL context, mark GPU objects as lost
-        Release_OGL(false, true);
-
-        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-
-#ifndef GL_ES_VERSION_2_0
-        SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
-        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
-        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
-
-        if (externalWindow_)
-            SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
-        else
-            SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
-
-        SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
-
-        if (!forceGL2_)
-        {
-            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
-            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
-            SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
-        }
-        else
-        {
-            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
-            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
-            SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
-        }
-#else
-        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
-        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
-#endif
-
-        SDL_Rect display_rect;
-        SDL_GetDisplayBounds(newParams.monitor_, &display_rect);
-        reposition = newParams.fullscreen_ || (newParams.borderless_ && width >= display_rect.w && height >= display_rect.h);
-
-        const int x = reposition ? display_rect.x : position_.x_;
-        const int y = reposition ? display_rect.y : position_.y_;
-
-        unsigned flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
-        if (newParams.fullscreen_)
-            flags |= SDL_WINDOW_FULLSCREEN;
-        if (newParams.borderless_)
-            flags |= SDL_WINDOW_BORDERLESS;
-        if (newParams.resizable_)
-            flags |= SDL_WINDOW_RESIZABLE;
-
-#ifndef __EMSCRIPTEN__
-        if (newParams.highDPI_)
-            flags |= SDL_WINDOW_ALLOW_HIGHDPI;
-#endif
-
-        SDL_SetHint(SDL_HINT_ORIENTATIONS, orientations_.CString());
-
-        // Try 24-bit depth first, fallback to 16-bit
-        for (const int depthSize : { 24, 16 })
-        {
-            SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthSize);
-
-            // Try requested multisample level first, fallback to lower levels and no multisample
-            for (int multiSample = newParams.multiSample_; multiSample > 0; multiSample /= 2)
-            {
-                if (multiSample > 1)
-                {
-                    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
-                    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multiSample);
-                }
-                else
-                {
-                    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
-                    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
-                }
-
-                if (!externalWindow_)
-                    window_ = SDL_CreateWindow(windowTitle_.CString(), x, y, width, height, flags);
-                else
-                {
-    #ifndef __EMSCRIPTEN__
-                    if (!window_)
-                        window_ = SDL_CreateWindowFrom(externalWindow_, SDL_WINDOW_OPENGL);
-                    newParams.fullscreen_ = false;
-    #endif
-                }
-
-                if (window_)
-                {
-                    // TODO: We probably want to keep depthSize as well
-                    newParams.multiSample_ = multiSample;
-                    break;
-                }
-            }
-
-            if (window_)
-                break;
-        }
-
-        if (!window_)
-        {
-            URHO3D_LOGERRORF("Could not create window, root cause: '%s'", SDL_GetError());
-            return false;
-        }
-
-        // Reposition the window on the specified monitor
-        if (reposition)
-            SDL_SetWindowPosition(window_, display_rect.x, display_rect.y);
-
-        CreateWindowIcon();
-
-        if (maximize)
-        {
-            Maximize();
-            SDL_GL_GetDrawableSize(window_, &width, &height);
-        }
-
-        // Create/restore context and GPU objects and set initial renderstate
-        Restore_OGL();
-
-        // Specific error message is already logged by Restore_OGL() when context creation or OpenGL extensions check fails
-        if (!impl->context_)
-            return false;
-    }
-
-    // Set vsync
-    SDL_GL_SetSwapInterval(newParams.vsync_ ? 1 : 0);
-
-    // Store the system FBO on iOS/tvOS now
-#if defined(IOS) || defined(TVOS)
-    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&impl->systemFBO_);
-#endif
-
-    screenParams_ = newParams;
-
-    SDL_GL_GetDrawableSize(window_, &width_, &height_);
-    if (!reposition)
-        SDL_GetWindowPosition(window_, &position_.x_, &position_.y_);
-
-    int logicalWidth, logicalHeight;
-    SDL_GetWindowSize(window_, &logicalWidth, &logicalHeight);
-    screenParams_.highDPI_ = (width_ != logicalWidth) || (height_ != logicalHeight);
-
-    // Reset rendertargets and viewport for the new screen mode
-    ResetRenderTargets_OGL();
-
-    // Clear the initial window contents to black
-    Clear_OGL(CLEAR_COLOR);
-    SDL_GL_SwapWindow(window_);
-
-    CheckFeatureSupport_OGL();
-
-#ifdef URHO3D_LOGGING
-    URHO3D_LOGINFOF("Adapter used %s %s", (const char *) glGetString(GL_VENDOR), (const char *) glGetString(GL_RENDERER));
-#endif
-
-    OnScreenModeChanged();
-    return true;
-}
-
-void Graphics::SetSRGB_OGL(bool enable)
-{
-    enable &= sRGBWriteSupport_;
-
-    if (enable != sRGB_)
-    {
-        sRGB_ = enable;
-        GetImpl_OGL()->fboDirty_ = true;
-    }
-}
-
-void Graphics::SetDither_OGL(bool enable)
-{
-    if (enable)
-        glEnable(GL_DITHER);
-    else
-        glDisable(GL_DITHER);
-}
-
-void Graphics::SetFlushGPU_OGL(bool enable)
-{
-    // Currently unimplemented on OpenGL
-}
-
-void Graphics::SetForceGL2_OGL(bool enable)
-{
-    if (IsInitialized_OGL())
-    {
-        URHO3D_LOGERROR("OpenGL 2 can only be forced before setting the initial screen mode");
-        return;
-    }
-
-    forceGL2_ = enable;
-}
-
-void Graphics::Close_OGL()
-{
-    if (!IsInitialized_OGL())
-        return;
-
-    // Actually close the window
-    Release_OGL(true, true);
-}
-
-bool Graphics::TakeScreenShot_OGL(Image& destImage)
-{
-    URHO3D_PROFILE(TakeScreenShot_OGL);
-
-    if (!IsInitialized_OGL())
-        return false;
-
-    if (IsDeviceLost_OGL())
-    {
-        URHO3D_LOGERROR("Can not take screenshot while device is lost");
-        return false;
-    }
-
-    ResetRenderTargets_OGL();
-
-#ifndef GL_ES_VERSION_2_0
-    destImage.SetSize(width_, height_, 3);
-    glReadPixels(0, 0, width_, height_, GL_RGB, GL_UNSIGNED_BYTE, destImage.GetData());
-#else
-    // Use RGBA format on OpenGL ES, as otherwise (at least on Android) the produced image is all black
-    destImage.SetSize(width_, height_, 4);
-    glReadPixels(0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, destImage.GetData());
-#endif
-
-    // On OpenGL we need to flip the image vertically after reading
-    destImage.FlipVertical();
-
-    return true;
-}
-
-bool Graphics::BeginFrame_OGL()
-{
-    if (!IsInitialized_OGL() || IsDeviceLost_OGL())
-        return false;
-
-    // If using an external window, check it for size changes, and reset screen mode if necessary
-    if (externalWindow_)
-    {
-        int width, height;
-
-        SDL_GL_GetDrawableSize(window_, &width, &height);
-        if (width != width_ || height != height_)
-            SetMode(width, height);
-    }
-
-    // Re-enable depth test and depth func in case a third party program has modified it
-    glEnable(GL_DEPTH_TEST);
-    glDepthFunc(glCmpFunc[depthTestMode_]);
-
-    // Set default rendertarget and depth buffer
-    ResetRenderTargets_OGL();
-
-    // Cleanup textures from previous frame
-    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-        SetTexture_OGL(i, nullptr);
-
-    // Enable color and depth write
-    SetColorWrite_OGL(true);
-    SetDepthWrite_OGL(true);
-
-    numPrimitives_ = 0;
-    numBatches_ = 0;
-
-    SendEvent(E_BEGINRENDERING);
-
-    return true;
-}
-
-void Graphics::EndFrame_OGL()
-{
-    if (!IsInitialized_OGL())
-        return;
-
-    URHO3D_PROFILE(Present);
-
-    SendEvent(E_ENDRENDERING);
-
-    SDL_GL_SwapWindow(window_);
-
-    // Clean up too large scratch buffers
-    CleanupScratchBuffers();
-}
-
-void Graphics::Clear_OGL(ClearTargetFlags flags, const Color& color, float depth, unsigned stencil)
-{
-    PrepareDraw_OGL();
-
-#ifdef GL_ES_VERSION_2_0
-    flags &= ~CLEAR_STENCIL;
-#endif
-
-    bool oldColorWrite = colorWrite_;
-    bool oldDepthWrite = depthWrite_;
-
-    if (flags & CLEAR_COLOR && !oldColorWrite)
-        SetColorWrite_OGL(true);
-    if (flags & CLEAR_DEPTH && !oldDepthWrite)
-        SetDepthWrite_OGL(true);
-    if (flags & CLEAR_STENCIL && stencilWriteMask_ != M_MAX_UNSIGNED)
-        glStencilMask(M_MAX_UNSIGNED);
-
-    unsigned glFlags = 0;
-    if (flags & CLEAR_COLOR)
-    {
-        glFlags |= GL_COLOR_BUFFER_BIT;
-        glClearColor(color.r_, color.g_, color.b_, color.a_);
-    }
-    if (flags & CLEAR_DEPTH)
-    {
-        glFlags |= GL_DEPTH_BUFFER_BIT;
-        glClearDepth(depth);
-    }
-    if (flags & CLEAR_STENCIL)
-    {
-        glFlags |= GL_STENCIL_BUFFER_BIT;
-        glClearStencil(stencil);
-    }
-
-    // If viewport is less than full screen, set a scissor to limit the clear
-    /// \todo Any user-set scissor test will be lost
-    IntVector2 viewSize = GetRenderTargetDimensions_OGL();
-    if (viewport_.left_ != 0 || viewport_.top_ != 0 || viewport_.right_ != viewSize.x_ || viewport_.bottom_ != viewSize.y_)
-        SetScissorTest_OGL(true, IntRect(0, 0, viewport_.Width(), viewport_.Height()));
-    else
-        SetScissorTest_OGL(false);
-
-    glClear(glFlags);
-
-    SetScissorTest_OGL(false);
-    SetColorWrite_OGL(oldColorWrite);
-    SetDepthWrite_OGL(oldDepthWrite);
-    if (flags & CLEAR_STENCIL && stencilWriteMask_ != M_MAX_UNSIGNED)
-        glStencilMask(stencilWriteMask_);
-}
-
-bool Graphics::ResolveToTexture_OGL(Texture2D* destination, const IntRect& viewport)
-{
-    if (!destination || !destination->GetRenderSurface())
-        return false;
-
-    URHO3D_PROFILE(ResolveToTexture_OGL);
-
-    IntRect vpCopy = viewport;
-    if (vpCopy.right_ <= vpCopy.left_)
-        vpCopy.right_ = vpCopy.left_ + 1;
-    if (vpCopy.bottom_ <= vpCopy.top_)
-        vpCopy.bottom_ = vpCopy.top_ + 1;
-    vpCopy.left_ = Clamp(vpCopy.left_, 0, width_);
-    vpCopy.top_ = Clamp(vpCopy.top_, 0, height_);
-    vpCopy.right_ = Clamp(vpCopy.right_, 0, width_);
-    vpCopy.bottom_ = Clamp(vpCopy.bottom_, 0, height_);
-
-    // Make sure the FBO is not in use
-    ResetRenderTargets_OGL();
-
-    // Use Direct3D convention with the vertical coordinates ie. 0 is top
-    SetTextureForUpdate_OGL(destination);
-    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vpCopy.left_, height_ - vpCopy.bottom_, vpCopy.Width(), vpCopy.Height());
-    SetTexture_OGL(0, nullptr);
-
-    return true;
-}
-
-bool Graphics::ResolveToTexture_OGL(Texture2D* texture)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (!texture)
-        return false;
-    RenderSurface* surface = texture->GetRenderSurface();
-    if (!surface || !surface->GetRenderBuffer())
-        return false;
-
-    URHO3D_PROFILE(ResolveToTexture_OGL);
-
-    texture->SetResolveDirty(false);
-    surface->SetResolveDirty(false);
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    // Use separate FBOs for resolve to not disturb the currently set rendertarget(s)
-    if (!impl->resolveSrcFBO_)
-        impl->resolveSrcFBO_ = CreateFramebuffer_OGL();
-    if (!impl->resolveDestFBO_)
-        impl->resolveDestFBO_ = CreateFramebuffer_OGL();
-
-    if (!gl3Support)
-    {
-        glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, impl->resolveSrcFBO_);
-        glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT,
-            surface->GetRenderBuffer());
-        glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, impl->resolveDestFBO_);
-        glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->GetGPUObjectName(),
-            0);
-        glBlitFramebufferEXT(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
-            GL_COLOR_BUFFER_BIT, GL_NEAREST);
-        glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
-        glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
-    }
-    else
-    {
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, impl->resolveSrcFBO_);
-        glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, surface->GetRenderBuffer());
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, impl->resolveDestFBO_);
-        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGPUObjectName(), 0);
-        glBlitFramebuffer(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
-            GL_COLOR_BUFFER_BIT, GL_NEAREST);
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-    }
-
-    // Restore previously bound FBO
-    BindFramebuffer_OGL(impl->boundFBO_);
-    return true;
-#else
-    // Not supported on GLES
-    return false;
-#endif
-}
-
-bool Graphics::ResolveToTexture_OGL(TextureCube* texture)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (!texture)
-        return false;
-
-    URHO3D_PROFILE(ResolveToTexture_OGL);
-
-    texture->SetResolveDirty(false);
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    // Use separate FBOs for resolve to not disturb the currently set rendertarget(s)
-    if (!impl->resolveSrcFBO_)
-        impl->resolveSrcFBO_ = CreateFramebuffer_OGL();
-    if (!impl->resolveDestFBO_)
-        impl->resolveDestFBO_ = CreateFramebuffer_OGL();
-
-    if (!gl3Support)
-    {
-        for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
-        {
-            // Resolve only the surface(s) that were actually rendered to
-            RenderSurface* surface = texture->GetRenderSurface((CubeMapFace)i);
-            if (!surface->IsResolveDirty())
-                continue;
-
-            surface->SetResolveDirty(false);
-            glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, impl->resolveSrcFBO_);
-            glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT,
-                surface->GetRenderBuffer());
-            glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, impl->resolveDestFBO_);
-            glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
-                texture->GetGPUObjectName(), 0);
-            glBlitFramebufferEXT(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
-                GL_COLOR_BUFFER_BIT, GL_NEAREST);
-        }
-
-        glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
-        glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
-    }
-    else
-    {
-        for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
-        {
-            RenderSurface* surface = texture->GetRenderSurface((CubeMapFace)i);
-            if (!surface->IsResolveDirty())
-                continue;
-
-            surface->SetResolveDirty(false);
-            glBindFramebuffer(GL_READ_FRAMEBUFFER, impl->resolveSrcFBO_);
-            glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, surface->GetRenderBuffer());
-            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, impl->resolveDestFBO_);
-            glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
-                texture->GetGPUObjectName(), 0);
-            glBlitFramebuffer(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
-                GL_COLOR_BUFFER_BIT, GL_NEAREST);
-        }
-
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-    }
-
-    // Restore previously bound FBO
-    BindFramebuffer_OGL(impl->boundFBO_);
-    return true;
-#else
-    // Not supported on GLES
-    return false;
-#endif
-}
-
-void Graphics::Draw_OGL(PrimitiveType type, unsigned vertexStart, unsigned vertexCount)
-{
-    if (!vertexCount)
-        return;
-
-    PrepareDraw_OGL();
-
-    unsigned primitiveCount;
-    GLenum glPrimitiveType;
-
-    GetGLPrimitiveType(vertexCount, type, primitiveCount, glPrimitiveType);
-    glDrawArrays(glPrimitiveType, vertexStart, vertexCount);
-
-    numPrimitives_ += primitiveCount;
-    ++numBatches_;
-}
-
-void Graphics::Draw_OGL(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount)
-{
-    if (!indexCount || !indexBuffer_ || !indexBuffer_->GetGPUObjectName())
-        return;
-
-    PrepareDraw_OGL();
-
-    unsigned indexSize = indexBuffer_->GetIndexSize();
-    unsigned primitiveCount;
-    GLenum glPrimitiveType;
-
-    GetGLPrimitiveType(indexCount, type, primitiveCount, glPrimitiveType);
-    GLenum indexType = indexSize == sizeof(unsigned short) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
-    glDrawElements(glPrimitiveType, indexCount, indexType, reinterpret_cast<const GLvoid*>(indexStart * indexSize));
-
-    numPrimitives_ += primitiveCount;
-    ++numBatches_;
-}
-
-void Graphics::Draw_OGL(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned baseVertexIndex, unsigned minVertex, unsigned vertexCount)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (!gl3Support || !indexCount || !indexBuffer_ || !indexBuffer_->GetGPUObjectName())
-        return;
-
-    PrepareDraw_OGL();
-
-    unsigned indexSize = indexBuffer_->GetIndexSize();
-    unsigned primitiveCount;
-    GLenum glPrimitiveType;
-
-    GetGLPrimitiveType(indexCount, type, primitiveCount, glPrimitiveType);
-    GLenum indexType = indexSize == sizeof(unsigned short) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
-    glDrawElementsBaseVertex(glPrimitiveType, indexCount, indexType, reinterpret_cast<GLvoid*>(indexStart * indexSize), baseVertexIndex);
-
-    numPrimitives_ += primitiveCount;
-    ++numBatches_;
-#endif
-}
-
-void Graphics::DrawInstanced_OGL(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount,
-    unsigned instanceCount)
-{
-#if !defined(GL_ES_VERSION_2_0) || defined(__EMSCRIPTEN__)
-    if (!indexCount || !indexBuffer_ || !indexBuffer_->GetGPUObjectName() || !instancingSupport_)
-        return;
-
-    PrepareDraw_OGL();
-
-    unsigned indexSize = indexBuffer_->GetIndexSize();
-    unsigned primitiveCount;
-    GLenum glPrimitiveType;
-
-    GetGLPrimitiveType(indexCount, type, primitiveCount, glPrimitiveType);
-    GLenum indexType = indexSize == sizeof(unsigned short) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
-#ifdef __EMSCRIPTEN__
-    glDrawElementsInstancedANGLE(glPrimitiveType, indexCount, indexType, reinterpret_cast<const GLvoid*>(indexStart * indexSize),
-        instanceCount);
-#else
-    if (gl3Support)
-    {
-        glDrawElementsInstanced(glPrimitiveType, indexCount, indexType, reinterpret_cast<const GLvoid*>(indexStart * indexSize),
-            instanceCount);
-    }
-    else
-    {
-        glDrawElementsInstancedARB(glPrimitiveType, indexCount, indexType, reinterpret_cast<const GLvoid*>(indexStart * indexSize),
-            instanceCount);
-    }
-#endif
-
-    numPrimitives_ += instanceCount * primitiveCount;
-    ++numBatches_;
-#endif
-}
-
-void Graphics::DrawInstanced_OGL(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned baseVertexIndex, unsigned minVertex,
-        unsigned vertexCount, unsigned instanceCount)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (!gl3Support || !indexCount || !indexBuffer_ || !indexBuffer_->GetGPUObjectName() || !instancingSupport_)
-        return;
-
-    PrepareDraw_OGL();
-
-    unsigned indexSize = indexBuffer_->GetIndexSize();
-    unsigned primitiveCount;
-    GLenum glPrimitiveType;
-
-    GetGLPrimitiveType(indexCount, type, primitiveCount, glPrimitiveType);
-    GLenum indexType = indexSize == sizeof(unsigned short) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
-
-    glDrawElementsInstancedBaseVertex(glPrimitiveType, indexCount, indexType, reinterpret_cast<const GLvoid*>(indexStart * indexSize),
-        instanceCount, baseVertexIndex);
-
-    numPrimitives_ += instanceCount * primitiveCount;
-    ++numBatches_;
-#endif
-}
-
-void Graphics::SetVertexBuffer_OGL(VertexBuffer* buffer)
-{
-    // Note: this is not multi-instance safe
-    static PODVector<VertexBuffer*> vertexBuffers(1);
-    vertexBuffers[0] = buffer;
-    SetVertexBuffers_OGL(vertexBuffers);
-}
-
-bool Graphics::SetVertexBuffers_OGL(const PODVector<VertexBuffer*>& buffers, unsigned instanceOffset)
-{
-    if (buffers.Size() > MAX_VERTEX_STREAMS)
-    {
-        URHO3D_LOGERROR("Too many vertex buffers");
-        return false;
-    }
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (instanceOffset != impl->lastInstanceOffset_)
-    {
-        impl->lastInstanceOffset_ = instanceOffset;
-        impl->vertexBuffersDirty_ = true;
-    }
-
-    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
-    {
-        VertexBuffer* buffer = nullptr;
-        if (i < buffers.Size())
-            buffer = buffers[i];
-        if (buffer != vertexBuffers_[i])
-        {
-            vertexBuffers_[i] = buffer;
-            impl->vertexBuffersDirty_ = true;
-        }
-    }
-
-    return true;
-}
-
-bool Graphics::SetVertexBuffers_OGL(const Vector<SharedPtr<VertexBuffer> >& buffers, unsigned instanceOffset)
-{
-    return SetVertexBuffers_OGL(reinterpret_cast<const PODVector<VertexBuffer*>&>(buffers), instanceOffset);
-}
-
-void Graphics::SetIndexBuffer_OGL(IndexBuffer* buffer)
-{
-    if (indexBuffer_ == buffer)
-        return;
-
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer ? buffer->GetGPUObjectName() : 0);
-    indexBuffer_ = buffer;
-}
-
-void Graphics::SetShaders_OGL(ShaderVariation* vs, ShaderVariation* ps)
-{
-    if (vs == vertexShader_ && ps == pixelShader_)
-        return;
-
-    // Compile the shaders now if not yet compiled. If already attempted, do not retry
-    if (vs && !vs->GetGPUObjectName())
-    {
-        if (vs->GetCompilerOutput().Empty())
-        {
-            URHO3D_PROFILE(CompileVertexShader);
-
-            bool success = vs->Create();
-            if (success)
-                URHO3D_LOGDEBUG("Compiled vertex shader " + vs->GetFullName());
-            else
-            {
-                URHO3D_LOGERROR("Failed to compile vertex shader " + vs->GetFullName() + ":\n" + vs->GetCompilerOutput());
-                vs = nullptr;
-            }
-        }
-        else
-            vs = nullptr;
-    }
-
-    if (ps && !ps->GetGPUObjectName())
-    {
-        if (ps->GetCompilerOutput().Empty())
-        {
-            URHO3D_PROFILE(CompilePixelShader);
-
-            bool success = ps->Create();
-            if (success)
-                URHO3D_LOGDEBUG("Compiled pixel shader " + ps->GetFullName());
-            else
-            {
-                URHO3D_LOGERROR("Failed to compile pixel shader " + ps->GetFullName() + ":\n" + ps->GetCompilerOutput());
-                ps = nullptr;
-            }
-        }
-        else
-            ps = nullptr;
-    }
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (!vs || !ps)
-    {
-        glUseProgram(0);
-        vertexShader_ = nullptr;
-        pixelShader_ = nullptr;
-        impl->shaderProgram_ = nullptr;
-    }
-    else
-    {
-        vertexShader_ = vs;
-        pixelShader_ = ps;
-
-        Pair<ShaderVariation*, ShaderVariation*> combination(vs, ps);
-        ShaderProgramMap_OGL::Iterator i = impl->shaderPrograms_.Find(combination);
-
-        if (i != impl->shaderPrograms_.End())
-        {
-            // Use the existing linked program
-            if (i->second_->GetGPUObjectName())
-            {
-                glUseProgram(i->second_->GetGPUObjectName());
-                impl->shaderProgram_ = i->second_;
-            }
-            else
-            {
-                glUseProgram(0);
-                impl->shaderProgram_ = nullptr;
-            }
-        }
-        else
-        {
-            // Link a new combination
-            URHO3D_PROFILE(LinkShaders);
-
-            SharedPtr<ShaderProgram_OGL> newProgram(new ShaderProgram_OGL(this, vs, ps));
-            if (newProgram->Link())
-            {
-                URHO3D_LOGDEBUG("Linked vertex shader " + vs->GetFullName() + " and pixel shader " + ps->GetFullName());
-                // Note: Link() calls glUseProgram() to set the texture sampler uniforms,
-                // so it is not necessary to call it again
-                impl->shaderProgram_ = newProgram;
-            }
-            else
-            {
-                URHO3D_LOGERROR("Failed to link vertex shader " + vs->GetFullName() + " and pixel shader " + ps->GetFullName() + ":\n" +
-                         newProgram->GetLinkerOutput());
-                glUseProgram(0);
-                impl->shaderProgram_ = nullptr;
-            }
-
-            impl->shaderPrograms_[combination] = newProgram;
-        }
-    }
-
-    // Update the clip plane uniform on GL3, and set constant buffers
-#ifndef GL_ES_VERSION_2_0
-    if (gl3Support && impl->shaderProgram_)
-    {
-        const SharedPtr<ConstantBuffer>* constantBuffers = impl->shaderProgram_->GetConstantBuffers();
-        for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS * 2; ++i)
-        {
-            ConstantBuffer* buffer = constantBuffers[i].Get();
-            if (buffer != impl->constantBuffers_[i])
-            {
-                unsigned object = buffer ? buffer->GetGPUObjectName() : 0;
-                glBindBufferBase(GL_UNIFORM_BUFFER, i, object);
-                // Calling glBindBufferBase also affects the generic buffer binding point
-                impl->boundUBO_ = object;
-                impl->constantBuffers_[i] = buffer;
-                ShaderProgram_OGL::ClearGlobalParameterSource((ShaderParameterGroup)(i % MAX_SHADER_PARAMETER_GROUPS));
-            }
-        }
-
-        SetShaderParameter_OGL(VSP_CLIPPLANE, useClipPlane_ ? clipPlane_ : Vector4(0.0f, 0.0f, 0.0f, 1.0f));
-    }
-#endif
-
-    // Store shader combination if shader dumping in progress
-    if (shaderPrecache_)
-        shaderPrecache_->StoreShaders(vertexShader_, pixelShader_);
-
-    if (impl->shaderProgram_)
-    {
-        impl->usedVertexAttributes_ = impl->shaderProgram_->GetUsedVertexAttributes();
-        impl->vertexAttributes_ = &impl->shaderProgram_->GetVertexAttributes();
-    }
-    else
-    {
-        impl->usedVertexAttributes_ = 0;
-        impl->vertexAttributes_ = nullptr;
-    }
-
-    impl->vertexBuffersDirty_ = true;
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, const float* data, unsigned count)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->shaderProgram_)
-    {
-        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
-        if (info)
-        {
-            if (info->bufferPtr_)
-            {
-                ConstantBuffer* buffer = info->bufferPtr_;
-                if (!buffer->IsDirty())
-                    impl->dirtyConstantBuffers_.Push(buffer);
-                buffer->SetParameter(info->offset_, (unsigned)(count * sizeof(float)), data);
-                return;
-            }
-
-            switch (info->glType_)
-            {
-            case GL_FLOAT:
-                glUniform1fv(info->location_, count, data);
-                break;
-
-            case GL_FLOAT_VEC2:
-                glUniform2fv(info->location_, count / 2, data);
-                break;
-
-            case GL_FLOAT_VEC3:
-                glUniform3fv(info->location_, count / 3, data);
-                break;
-
-            case GL_FLOAT_VEC4:
-                glUniform4fv(info->location_, count / 4, data);
-                break;
-
-            case GL_FLOAT_MAT3:
-                glUniformMatrix3fv(info->location_, count / 9, GL_FALSE, data);
-                break;
-
-            case GL_FLOAT_MAT4:
-                glUniformMatrix4fv(info->location_, count / 16, GL_FALSE, data);
-                break;
-
-            default: break;
-            }
-        }
-    }
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, float value)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->shaderProgram_)
-    {
-        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
-        if (info)
-        {
-            if (info->bufferPtr_)
-            {
-                ConstantBuffer* buffer = info->bufferPtr_;
-                if (!buffer->IsDirty())
-                    impl->dirtyConstantBuffers_.Push(buffer);
-                buffer->SetParameter(info->offset_, sizeof(float), &value);
-                return;
-            }
-
-            glUniform1fv(info->location_, 1, &value);
-        }
-    }
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, int value)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->shaderProgram_)
-    {
-        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
-        if (info)
-        {
-            if (info->bufferPtr_)
-            {
-                ConstantBuffer* buffer = info->bufferPtr_;
-                if (!buffer->IsDirty())
-                    impl->dirtyConstantBuffers_.Push(buffer);
-                buffer->SetParameter(info->offset_, sizeof(int), &value);
-                return;
-            }
-
-            glUniform1i(info->location_, value);
-        }
-    }
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, bool value)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    // \todo Not tested
-    if (impl->shaderProgram_)
-    {
-        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
-        if (info)
-        {
-            if (info->bufferPtr_)
-            {
-                ConstantBuffer* buffer = info->bufferPtr_;
-                if (!buffer->IsDirty())
-                    impl->dirtyConstantBuffers_.Push(buffer);
-                buffer->SetParameter(info->offset_, sizeof(bool), &value);
-                return;
-            }
-
-            glUniform1i(info->location_, (int)value);
-        }
-    }
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, const Color& color)
-{
-    SetShaderParameter_OGL(param, color.Data(), 4);
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, const Vector2& vector)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->shaderProgram_)
-    {
-        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
-        if (info)
-        {
-            if (info->bufferPtr_)
-            {
-                ConstantBuffer* buffer = info->bufferPtr_;
-                if (!buffer->IsDirty())
-                    impl->dirtyConstantBuffers_.Push(buffer);
-                buffer->SetParameter(info->offset_, sizeof(Vector2), &vector);
-                return;
-            }
-
-            // Check the uniform type to avoid mismatch
-            switch (info->glType_)
-            {
-            case GL_FLOAT:
-                glUniform1fv(info->location_, 1, vector.Data());
-                break;
-
-            case GL_FLOAT_VEC2:
-                glUniform2fv(info->location_, 1, vector.Data());
-                break;
-
-            default: break;
-            }
-        }
-    }
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, const Matrix3& matrix)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->shaderProgram_)
-    {
-        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
-        if (info)
-        {
-            if (info->bufferPtr_)
-            {
-                ConstantBuffer* buffer = info->bufferPtr_;
-                if (!buffer->IsDirty())
-                    impl->dirtyConstantBuffers_.Push(buffer);
-                buffer->SetVector3ArrayParameter(info->offset_, 3, &matrix);
-                return;
-            }
-
-            glUniformMatrix3fv(info->location_, 1, GL_FALSE, matrix.Data());
-        }
-    }
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, const Vector3& vector)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->shaderProgram_)
-    {
-        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
-        if (info)
-        {
-            if (info->bufferPtr_)
-            {
-                ConstantBuffer* buffer = info->bufferPtr_;
-                if (!buffer->IsDirty())
-                    impl->dirtyConstantBuffers_.Push(buffer);
-                buffer->SetParameter(info->offset_, sizeof(Vector3), &vector);
-                return;
-            }
-
-            // Check the uniform type to avoid mismatch
-            switch (info->glType_)
-            {
-            case GL_FLOAT:
-                glUniform1fv(info->location_, 1, vector.Data());
-                break;
-
-            case GL_FLOAT_VEC2:
-                glUniform2fv(info->location_, 1, vector.Data());
-                break;
-
-            case GL_FLOAT_VEC3:
-                glUniform3fv(info->location_, 1, vector.Data());
-                break;
-
-            default: break;
-            }
-        }
-    }
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, const Matrix4& matrix)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->shaderProgram_)
-    {
-        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
-        if (info)
-        {
-            if (info->bufferPtr_)
-            {
-                ConstantBuffer* buffer = info->bufferPtr_;
-                if (!buffer->IsDirty())
-                    impl->dirtyConstantBuffers_.Push(buffer);
-                buffer->SetParameter(info->offset_, sizeof(Matrix4), &matrix);
-                return;
-            }
-
-            glUniformMatrix4fv(info->location_, 1, GL_FALSE, matrix.Data());
-        }
-    }
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, const Vector4& vector)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->shaderProgram_)
-    {
-        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
-        if (info)
-        {
-            if (info->bufferPtr_)
-            {
-                ConstantBuffer* buffer = info->bufferPtr_;
-                if (!buffer->IsDirty())
-                    impl->dirtyConstantBuffers_.Push(buffer);
-                buffer->SetParameter(info->offset_, sizeof(Vector4), &vector);
-                return;
-            }
-
-            // Check the uniform type to avoid mismatch
-            switch (info->glType_)
-            {
-            case GL_FLOAT:
-                glUniform1fv(info->location_, 1, vector.Data());
-                break;
-
-            case GL_FLOAT_VEC2:
-                glUniform2fv(info->location_, 1, vector.Data());
-                break;
-
-            case GL_FLOAT_VEC3:
-                glUniform3fv(info->location_, 1, vector.Data());
-                break;
-
-            case GL_FLOAT_VEC4:
-                glUniform4fv(info->location_, 1, vector.Data());
-                break;
-
-            default: break;
-            }
-        }
-    }
-}
-
-void Graphics::SetShaderParameter_OGL(StringHash param, const Matrix3x4& matrix)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->shaderProgram_)
-    {
-        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
-        if (info)
-        {
-            // Expand to a full Matrix4
-            static Matrix4 fullMatrix;
-            fullMatrix.m00_ = matrix.m00_;
-            fullMatrix.m01_ = matrix.m01_;
-            fullMatrix.m02_ = matrix.m02_;
-            fullMatrix.m03_ = matrix.m03_;
-            fullMatrix.m10_ = matrix.m10_;
-            fullMatrix.m11_ = matrix.m11_;
-            fullMatrix.m12_ = matrix.m12_;
-            fullMatrix.m13_ = matrix.m13_;
-            fullMatrix.m20_ = matrix.m20_;
-            fullMatrix.m21_ = matrix.m21_;
-            fullMatrix.m22_ = matrix.m22_;
-            fullMatrix.m23_ = matrix.m23_;
-
-            if (info->bufferPtr_)
-            {
-                ConstantBuffer* buffer = info->bufferPtr_;
-                if (!buffer->IsDirty())
-                    impl->dirtyConstantBuffers_.Push(buffer);
-                buffer->SetParameter(info->offset_, sizeof(Matrix4), &fullMatrix);
-                return;
-            }
-
-            glUniformMatrix4fv(info->location_, 1, GL_FALSE, fullMatrix.Data());
-        }
-    }
-}
-
-bool Graphics::NeedParameterUpdate_OGL(ShaderParameterGroup group, const void* source)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-    return impl->shaderProgram_ ? impl->shaderProgram_->NeedParameterUpdate(group, source) : false;
-}
-
-bool Graphics::HasShaderParameter_OGL(StringHash param)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-    return impl->shaderProgram_ && impl->shaderProgram_->HasParameter(param);
-}
-
-bool Graphics::HasTextureUnit_OGL(TextureUnit unit)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-    return impl->shaderProgram_ && impl->shaderProgram_->HasTextureUnit(unit);
-}
-
-void Graphics::ClearParameterSource_OGL(ShaderParameterGroup group)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-    if (impl->shaderProgram_)
-        impl->shaderProgram_->ClearParameterSource(group);
-}
-
-void Graphics::ClearParameterSources_OGL()
-{
-    ShaderProgram_OGL::ClearParameterSources();
-}
-
-void Graphics::ClearTransformSources_OGL()
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-    if (impl->shaderProgram_)
-    {
-        impl->shaderProgram_->ClearParameterSource(SP_CAMERA);
-        impl->shaderProgram_->ClearParameterSource(SP_OBJECT);
-    }
-}
-
-void Graphics::SetTexture_OGL(unsigned index, Texture* texture)
-{
-    if (index >= MAX_TEXTURE_UNITS)
-        return;
-
-    // Check if texture is currently bound as a rendertarget. In that case, use its backup texture, or blank if not defined
-    if (texture)
-    {
-        if (renderTargets_[0] && renderTargets_[0]->GetParentTexture() == texture)
-            texture = texture->GetBackupTexture();
-        else
-        {
-            // Resolve multisampled texture now as necessary
-            if (texture->GetMultiSample() > 1 && texture->GetAutoResolve() && texture->IsResolveDirty())
-            {
-                if (texture->GetType() == Texture2D::GetTypeStatic())
-                    ResolveToTexture_OGL(static_cast<Texture2D*>(texture));
-                if (texture->GetType() == TextureCube::GetTypeStatic())
-                    ResolveToTexture_OGL(static_cast<TextureCube*>(texture));
-            }
-        }
-    }
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (textures_[index] != texture)
-    {
-        if (impl->activeTexture_ != index)
-        {
-            glActiveTexture(GL_TEXTURE0 + index);
-            impl->activeTexture_ = index;
-        }
-
-        if (texture)
-        {
-            unsigned glType = texture->GetTarget();
-            // Unbind old texture type if necessary
-            if (impl->textureTypes_[index] && impl->textureTypes_[index] != glType)
-                glBindTexture(impl->textureTypes_[index], 0);
-            glBindTexture(glType, texture->GetGPUObjectName());
-            impl->textureTypes_[index] = glType;
-
-            if (texture->GetParametersDirty())
-                texture->UpdateParameters();
-            if (texture->GetLevelsDirty())
-                texture->RegenerateLevels();
-        }
-        else if (impl->textureTypes_[index])
-        {
-            glBindTexture(impl->textureTypes_[index], 0);
-            impl->textureTypes_[index] = 0;
-        }
-
-        textures_[index] = texture;
-    }
-    else
-    {
-        if (texture && (texture->GetParametersDirty() || texture->GetLevelsDirty()))
-        {
-            if (impl->activeTexture_ != index)
-            {
-                glActiveTexture(GL_TEXTURE0 + index);
-                impl->activeTexture_ = index;
-            }
-
-            glBindTexture(texture->GetTarget(), texture->GetGPUObjectName());
-            if (texture->GetParametersDirty())
-                texture->UpdateParameters();
-            if (texture->GetLevelsDirty())
-                texture->RegenerateLevels();
-        }
-    }
-}
-
-void Graphics::SetTextureForUpdate_OGL(Texture* texture)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->activeTexture_ != 0)
-    {
-        glActiveTexture(GL_TEXTURE0);
-        impl->activeTexture_ = 0;
-    }
-
-    unsigned glType = texture->GetTarget();
-    // Unbind old texture type if necessary
-    if (impl->textureTypes_[0] && impl->textureTypes_[0] != glType)
-        glBindTexture(impl->textureTypes_[0], 0);
-    glBindTexture(glType, texture->GetGPUObjectName());
-    impl->textureTypes_[0] = glType;
-    textures_[0] = texture;
-}
-
-void Graphics::SetDefaultTextureFilterMode_OGL(TextureFilterMode mode)
-{
-    if (mode != defaultTextureFilterMode_)
-    {
-        defaultTextureFilterMode_ = mode;
-        SetTextureParametersDirty_OGL();
-    }
-}
-
-void Graphics::SetDefaultTextureAnisotropy_OGL(unsigned level)
-{
-    level = Max(level, 1U);
-
-    if (level != defaultTextureAnisotropy_)
-    {
-        defaultTextureAnisotropy_ = level;
-        SetTextureParametersDirty_OGL();
-    }
-}
-
-void Graphics::SetTextureParametersDirty_OGL()
-{
-    MutexLock lock(gpuObjectMutex_);
-
-    for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
-    {
-        auto* texture = dynamic_cast<Texture*>(*i);
-        if (texture)
-            texture->SetParametersDirty();
-    }
-}
-
-void Graphics::ResetRenderTargets_OGL()
-{
-    for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
-        SetRenderTarget_OGL(i, (RenderSurface*)nullptr);
-    SetDepthStencil_OGL((RenderSurface*)nullptr);
-    SetViewport_OGL(IntRect(0, 0, width_, height_));
-}
-
-void Graphics::ResetRenderTarget_OGL(unsigned index)
-{
-    SetRenderTarget_OGL(index, (RenderSurface*)nullptr);
-}
-
-void Graphics::ResetDepthStencil_OGL()
-{
-    SetDepthStencil_OGL((RenderSurface*)nullptr);
-}
-
-void Graphics::SetRenderTarget_OGL(unsigned index, RenderSurface* renderTarget)
-{
-    if (index >= MAX_RENDERTARGETS)
-        return;
-
-    if (renderTarget != renderTargets_[index])
-    {
-        renderTargets_[index] = renderTarget;
-
-        // If the rendertarget is also bound as a texture, replace with backup texture or null
-        if (renderTarget)
-        {
-            Texture* parentTexture = renderTarget->GetParentTexture();
-
-            for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-            {
-                if (textures_[i] == parentTexture)
-                    SetTexture_OGL(i, textures_[i]->GetBackupTexture());
-            }
-
-            // If multisampled, mark the texture & surface needing resolve
-            if (parentTexture->GetMultiSample() > 1 && parentTexture->GetAutoResolve())
-            {
-                parentTexture->SetResolveDirty(true);
-                renderTarget->SetResolveDirty(true);
-            }
-
-            // If mipmapped, mark the levels needing regeneration
-            if (parentTexture->GetLevels() > 1)
-                parentTexture->SetLevelsDirty();
-        }
-
-        GetImpl_OGL()->fboDirty_ = true;
-    }
-}
-
-void Graphics::SetRenderTarget_OGL(unsigned index, Texture2D* texture)
-{
-    RenderSurface* renderTarget = nullptr;
-    if (texture)
-        renderTarget = texture->GetRenderSurface();
-
-    SetRenderTarget_OGL(index, renderTarget);
-}
-
-void Graphics::SetDepthStencil_OGL(RenderSurface* depthStencil)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    // If we are using a rendertarget texture, it is required in OpenGL to also have an own depth-stencil
-    // Create a new depth-stencil texture as necessary to be able to provide similar behaviour as Direct3D9
-    // Only do this for non-multisampled rendertargets; when using multisampled target a similarly multisampled
-    // depth-stencil should also be provided (backbuffer depth isn't compatible)
-    if (renderTargets_[0] && renderTargets_[0]->GetMultiSample() == 1 && !depthStencil)
-    {
-        int width = renderTargets_[0]->GetWidth();
-        int height = renderTargets_[0]->GetHeight();
-
-        // Direct3D9 default depth-stencil can not be used when rendertarget is larger than the window.
-        // Check size similarly
-        if (width <= width_ && height <= height_)
-        {
-            unsigned searchKey = (width << 16u) | height;
-            HashMap<unsigned, SharedPtr<Texture2D> >::Iterator i = impl->depthTextures_.Find(searchKey);
-            if (i != impl->depthTextures_.End())
-                depthStencil = i->second_->GetRenderSurface();
-            else
-            {
-                SharedPtr<Texture2D> newDepthTexture(new Texture2D(context_));
-                newDepthTexture->SetSize(width, height, GetDepthStencilFormat_OGL(), TEXTURE_DEPTHSTENCIL);
-                impl->depthTextures_[searchKey] = newDepthTexture;
-                depthStencil = newDepthTexture->GetRenderSurface();
-            }
-        }
-    }
-
-    if (depthStencil != depthStencil_)
-    {
-        depthStencil_ = depthStencil;
-        impl->fboDirty_ = true;
-    }
-}
-
-void Graphics::SetDepthStencil_OGL(Texture2D* texture)
-{
-    RenderSurface* depthStencil = nullptr;
-    if (texture)
-        depthStencil = texture->GetRenderSurface();
-
-    SetDepthStencil_OGL(depthStencil);
-}
-
-void Graphics::SetViewport_OGL(const IntRect& rect)
-{
-    PrepareDraw_OGL();
-
-    IntVector2 rtSize = GetRenderTargetDimensions_OGL();
-
-    IntRect rectCopy = rect;
-
-    if (rectCopy.right_ <= rectCopy.left_)
-        rectCopy.right_ = rectCopy.left_ + 1;
-    if (rectCopy.bottom_ <= rectCopy.top_)
-        rectCopy.bottom_ = rectCopy.top_ + 1;
-    rectCopy.left_ = Clamp(rectCopy.left_, 0, rtSize.x_);
-    rectCopy.top_ = Clamp(rectCopy.top_, 0, rtSize.y_);
-    rectCopy.right_ = Clamp(rectCopy.right_, 0, rtSize.x_);
-    rectCopy.bottom_ = Clamp(rectCopy.bottom_, 0, rtSize.y_);
-
-    // Use Direct3D convention with the vertical coordinates ie. 0 is top
-    glViewport(rectCopy.left_, rtSize.y_ - rectCopy.bottom_, rectCopy.Width(), rectCopy.Height());
-    viewport_ = rectCopy;
-
-    // Disable scissor test, needs to be re-enabled by the user
-    SetScissorTest_OGL(false);
-}
-
-void Graphics::SetBlendMode_OGL(BlendMode mode, bool alphaToCoverage)
-{
-    if (mode != blendMode_)
-    {
-        if (mode == BLEND_REPLACE)
-            glDisable(GL_BLEND);
-        else
-        {
-            glEnable(GL_BLEND);
-            glBlendFunc(glSrcBlend[mode], glDestBlend[mode]);
-            glBlendEquation(glBlendOp[mode]);
-        }
-
-        blendMode_ = mode;
-    }
-
-    if (alphaToCoverage != alphaToCoverage_)
-    {
-        if (alphaToCoverage)
-            glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
-        else
-            glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
-
-        alphaToCoverage_ = alphaToCoverage;
-    }
-}
-
-void Graphics::SetColorWrite_OGL(bool enable)
-{
-    if (enable != colorWrite_)
-    {
-        if (enable)
-            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-        else
-            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-
-        colorWrite_ = enable;
-    }
-}
-
-void Graphics::SetCullMode_OGL(CullMode mode)
-{
-    if (mode != cullMode_)
-    {
-        if (mode == CULL_NONE)
-            glDisable(GL_CULL_FACE);
-        else
-        {
-            // Use Direct3D convention, ie. clockwise vertices define a front face
-            glEnable(GL_CULL_FACE);
-            glCullFace(mode == CULL_CCW ? GL_FRONT : GL_BACK);
-        }
-
-        cullMode_ = mode;
-    }
-}
-
-void Graphics::SetDepthBias_OGL(float constantBias, float slopeScaledBias)
-{
-    if (constantBias != constantDepthBias_ || slopeScaledBias != slopeScaledDepthBias_)
-    {
-#ifndef GL_ES_VERSION_2_0
-        if (slopeScaledBias != 0.0f)
-        {
-            // OpenGL constant bias is unreliable and dependent on depth buffer bitdepth, apply in the projection matrix instead
-            glEnable(GL_POLYGON_OFFSET_FILL);
-            glPolygonOffset(slopeScaledBias, 0.0f);
-        }
-        else
-            glDisable(GL_POLYGON_OFFSET_FILL);
-#endif
-
-        constantDepthBias_ = constantBias;
-        slopeScaledDepthBias_ = slopeScaledBias;
-        // Force update of the projection matrix shader parameter
-        ClearParameterSource_OGL(SP_CAMERA);
-    }
-}
-
-void Graphics::SetDepthTest_OGL(CompareMode mode)
-{
-    if (mode != depthTestMode_)
-    {
-        glDepthFunc(glCmpFunc[mode]);
-        depthTestMode_ = mode;
-    }
-}
-
-void Graphics::SetDepthWrite_OGL(bool enable)
-{
-    if (enable != depthWrite_)
-    {
-        glDepthMask(enable ? GL_TRUE : GL_FALSE);
-        depthWrite_ = enable;
-    }
-}
-
-void Graphics::SetFillMode_OGL(FillMode mode)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (mode != fillMode_)
-    {
-        glPolygonMode(GL_FRONT_AND_BACK, glFillMode[mode]);
-        fillMode_ = mode;
-    }
-#endif
-}
-
-void Graphics::SetLineAntiAlias_OGL(bool enable)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (enable != lineAntiAlias_)
-    {
-        if (enable)
-            glEnable(GL_LINE_SMOOTH);
-        else
-            glDisable(GL_LINE_SMOOTH);
-        lineAntiAlias_ = enable;
-    }
-#endif
-}
-
-void Graphics::SetScissorTest_OGL(bool enable, const Rect& rect, bool borderInclusive)
-{
-    // During some light rendering loops, a full rect is toggled on/off repeatedly.
-    // Disable scissor in that case to reduce state changes
-    if (rect.min_.x_ <= 0.0f && rect.min_.y_ <= 0.0f && rect.max_.x_ >= 1.0f && rect.max_.y_ >= 1.0f)
-        enable = false;
-
-    if (enable)
-    {
-        IntVector2 rtSize(GetRenderTargetDimensions_OGL());
-        IntVector2 viewSize(viewport_.Size());
-        IntVector2 viewPos(viewport_.left_, viewport_.top_);
-        IntRect intRect;
-        int expand = borderInclusive ? 1 : 0;
-
-        intRect.left_ = Clamp((int)((rect.min_.x_ + 1.0f) * 0.5f * viewSize.x_) + viewPos.x_, 0, rtSize.x_ - 1);
-        intRect.top_ = Clamp((int)((-rect.max_.y_ + 1.0f) * 0.5f * viewSize.y_) + viewPos.y_, 0, rtSize.y_ - 1);
-        intRect.right_ = Clamp((int)((rect.max_.x_ + 1.0f) * 0.5f * viewSize.x_) + viewPos.x_ + expand, 0, rtSize.x_);
-        intRect.bottom_ = Clamp((int)((-rect.min_.y_ + 1.0f) * 0.5f * viewSize.y_) + viewPos.y_ + expand, 0, rtSize.y_);
-
-        if (intRect.right_ == intRect.left_)
-            intRect.right_++;
-        if (intRect.bottom_ == intRect.top_)
-            intRect.bottom_++;
-
-        if (intRect.right_ < intRect.left_ || intRect.bottom_ < intRect.top_)
-            enable = false;
-
-        if (enable && scissorRect_ != intRect)
-        {
-            // Use Direct3D convention with the vertical coordinates ie. 0 is top
-            glScissor(intRect.left_, rtSize.y_ - intRect.bottom_, intRect.Width(), intRect.Height());
-            scissorRect_ = intRect;
-        }
-    }
-    else
-        scissorRect_ = IntRect::ZERO;
-
-    if (enable != scissorTest_)
-    {
-        if (enable)
-            glEnable(GL_SCISSOR_TEST);
-        else
-            glDisable(GL_SCISSOR_TEST);
-        scissorTest_ = enable;
-    }
-}
-
-void Graphics::SetScissorTest_OGL(bool enable, const IntRect& rect)
-{
-    IntVector2 rtSize(GetRenderTargetDimensions_OGL());
-    IntVector2 viewPos(viewport_.left_, viewport_.top_);
-
-    if (enable)
-    {
-        IntRect intRect;
-        intRect.left_ = Clamp(rect.left_ + viewPos.x_, 0, rtSize.x_ - 1);
-        intRect.top_ = Clamp(rect.top_ + viewPos.y_, 0, rtSize.y_ - 1);
-        intRect.right_ = Clamp(rect.right_ + viewPos.x_, 0, rtSize.x_);
-        intRect.bottom_ = Clamp(rect.bottom_ + viewPos.y_, 0, rtSize.y_);
-
-        if (intRect.right_ == intRect.left_)
-            intRect.right_++;
-        if (intRect.bottom_ == intRect.top_)
-            intRect.bottom_++;
-
-        if (intRect.right_ < intRect.left_ || intRect.bottom_ < intRect.top_)
-            enable = false;
-
-        if (enable && scissorRect_ != intRect)
-        {
-            // Use Direct3D convention with the vertical coordinates ie. 0 is top
-            glScissor(intRect.left_, rtSize.y_ - intRect.bottom_, intRect.Width(), intRect.Height());
-            scissorRect_ = intRect;
-        }
-    }
-    else
-        scissorRect_ = IntRect::ZERO;
-
-    if (enable != scissorTest_)
-    {
-        if (enable)
-            glEnable(GL_SCISSOR_TEST);
-        else
-            glDisable(GL_SCISSOR_TEST);
-        scissorTest_ = enable;
-    }
-}
-
-void Graphics::SetClipPlane_OGL(bool enable, const Plane& clipPlane, const Matrix3x4& view, const Matrix4& projection)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (enable != useClipPlane_)
-    {
-        if (enable)
-            glEnable(GL_CLIP_PLANE0);
-        else
-            glDisable(GL_CLIP_PLANE0);
-
-        useClipPlane_ = enable;
-    }
-
-    if (enable)
-    {
-        Matrix4 viewProj = projection * view;
-        clipPlane_ = clipPlane.Transformed(viewProj).ToVector4();
-
-        if (!gl3Support)
-        {
-            GLdouble planeData[4];
-            planeData[0] = clipPlane_.x_;
-            planeData[1] = clipPlane_.y_;
-            planeData[2] = clipPlane_.z_;
-            planeData[3] = clipPlane_.w_;
-
-            glClipPlane(GL_CLIP_PLANE0, &planeData[0]);
-        }
-    }
-#endif
-}
-
-void Graphics::SetStencilTest_OGL(bool enable, CompareMode mode, StencilOp pass, StencilOp fail, StencilOp zFail, unsigned stencilRef,
-    unsigned compareMask, unsigned writeMask)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (enable != stencilTest_)
-    {
-        if (enable)
-            glEnable(GL_STENCIL_TEST);
-        else
-            glDisable(GL_STENCIL_TEST);
-        stencilTest_ = enable;
-    }
-
-    if (enable)
-    {
-        if (mode != stencilTestMode_ || stencilRef != stencilRef_ || compareMask != stencilCompareMask_)
-        {
-            glStencilFunc(glCmpFunc[mode], stencilRef, compareMask);
-            stencilTestMode_ = mode;
-            stencilRef_ = stencilRef;
-            stencilCompareMask_ = compareMask;
-        }
-        if (writeMask != stencilWriteMask_)
-        {
-            glStencilMask(writeMask);
-            stencilWriteMask_ = writeMask;
-        }
-        if (pass != stencilPass_ || fail != stencilFail_ || zFail != stencilZFail_)
-        {
-            glStencilOp(glStencilOps[fail], glStencilOps[zFail], glStencilOps[pass]);
-            stencilPass_ = pass;
-            stencilFail_ = fail;
-            stencilZFail_ = zFail;
-        }
-    }
-#endif
-}
-
-bool Graphics::IsInitialized_OGL() const
-{
-    return window_ != nullptr;
-}
-
-bool Graphics::GetDither_OGL() const
-{
-    return glIsEnabled(GL_DITHER) ? true : false;
-}
-
-bool Graphics::IsDeviceLost_OGL() const
-{
-    // On iOS and tvOS treat window minimization as device loss, as it is forbidden to access OpenGL when minimized
-#if defined(IOS) || defined(TVOS)
-    if (window_ && (SDL_GetWindowFlags(window_) & SDL_WINDOW_MINIMIZED) != 0)
-        return true;
-#endif
-
-    return GetImpl_OGL()->context_ == nullptr;
-}
-
-PODVector<int> Graphics::GetMultiSampleLevels_OGL() const
-{
-    PODVector<int> ret;
-    // No multisampling always supported
-    ret.Push(1);
-
-#ifndef GL_ES_VERSION_2_0
-    int maxSamples = 0;
-    glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
-    for (int i = 2; i <= maxSamples && i <= 16; i *= 2)
-        ret.Push(i);
-#endif
-
-    return ret;
-}
-
-unsigned Graphics::GetFormat_OGL(CompressedFormat format) const
-{
-    switch (format)
-    {
-    case CF_RGBA:
-        return GL_RGBA;
-
-    case CF_DXT1:
-        return dxtTextureSupport_ ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : 0;
-
-#if !defined(GL_ES_VERSION_2_0) || defined(__EMSCRIPTEN__)
-    case CF_DXT3:
-        return dxtTextureSupport_ ? GL_COMPRESSED_RGBA_S3TC_DXT3_EXT : 0;
-
-    case CF_DXT5:
-        return dxtTextureSupport_ ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : 0;
-#endif
-#ifdef GL_ES_VERSION_2_0
-    case CF_ETC1:
-        return etcTextureSupport_ ? GL_ETC1_RGB8_OES : 0;
-
-    case CF_ETC2_RGB:
-        return etc2TextureSupport_ ? GL_ETC2_RGB8_OES : 0;
-
-    case CF_ETC2_RGBA:
-        return etc2TextureSupport_ ? GL_ETC2_RGBA8_OES : 0;
-
-    case CF_PVRTC_RGB_2BPP:
-        return pvrtcTextureSupport_ ? COMPRESSED_RGB_PVRTC_2BPPV1_IMG : 0;
-
-    case CF_PVRTC_RGB_4BPP:
-        return pvrtcTextureSupport_ ? COMPRESSED_RGB_PVRTC_4BPPV1_IMG : 0;
-
-    case CF_PVRTC_RGBA_2BPP:
-        return pvrtcTextureSupport_ ? COMPRESSED_RGBA_PVRTC_2BPPV1_IMG : 0;
-
-    case CF_PVRTC_RGBA_4BPP:
-        return pvrtcTextureSupport_ ? COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : 0;
-#endif
-
-    default:
-        return 0;
-    }
-}
-
-unsigned Graphics::GetMaxBones_OGL()
-{
-#ifdef RPI
-    // At the moment all RPI GPUs are low powered and only have limited number of uniforms
-    return 32;
-#else
-    return gl3Support ? 128 : 64;
-#endif
-}
-
-bool Graphics::GetGL3Support_OGL()
-{
-    return gl3Support;
-}
-
-ShaderVariation* Graphics::GetShader_OGL(ShaderType type, const String& name, const String& defines) const
-{
-    return GetShader_OGL(type, name.CString(), defines.CString());
-}
-
-ShaderVariation* Graphics::GetShader_OGL(ShaderType type, const char* name, const char* defines) const
-{
-    if (lastShaderName_ != name || !lastShader_)
-    {
-        auto* cache = GetSubsystem<ResourceCache>();
-
-        String fullShaderName = shaderPath_ + name + shaderExtension_;
-        // Try to reduce repeated error log prints because of missing shaders
-        if (lastShaderName_ == name && !cache->Exists(fullShaderName))
-            return nullptr;
-
-        lastShader_ = cache->GetResource<Shader>(fullShaderName);
-        lastShaderName_ = name;
-    }
-
-    return lastShader_ ? lastShader_->GetVariation(type, defines) : nullptr;
-}
-
-VertexBuffer* Graphics::GetVertexBuffer_OGL(unsigned index) const
-{
-    return index < MAX_VERTEX_STREAMS ? vertexBuffers_[index] : nullptr;
-}
-
-ShaderProgram_OGL* Graphics::GetShaderProgram_OGL() const
-{
-    return GetImpl_OGL()->shaderProgram_;
-}
-
-TextureUnit Graphics::GetTextureUnit_OGL(const String& name)
-{
-    HashMap<String, TextureUnit>::Iterator i = textureUnits_.Find(name);
-    if (i != textureUnits_.End())
-        return i->second_;
-    else
-        return MAX_TEXTURE_UNITS;
-}
-
-const String& Graphics::GetTextureUnitName_OGL(TextureUnit unit)
-{
-    for (HashMap<String, TextureUnit>::Iterator i = textureUnits_.Begin(); i != textureUnits_.End(); ++i)
-    {
-        if (i->second_ == unit)
-            return i->first_;
-    }
-    return String::EMPTY;
-}
-
-Texture* Graphics::GetTexture_OGL(unsigned index) const
-{
-    return index < MAX_TEXTURE_UNITS ? textures_[index] : nullptr;
-}
-
-RenderSurface* Graphics::GetRenderTarget_OGL(unsigned index) const
-{
-    return index < MAX_RENDERTARGETS ? renderTargets_[index] : nullptr;
-}
-
-IntVector2 Graphics::GetRenderTargetDimensions_OGL() const
-{
-    int width, height;
-
-    if (renderTargets_[0])
-    {
-        width = renderTargets_[0]->GetWidth();
-        height = renderTargets_[0]->GetHeight();
-    }
-    else if (depthStencil_)
-    {
-        width = depthStencil_->GetWidth();
-        height = depthStencil_->GetHeight();
-    }
-    else
-    {
-        width = width_;
-        height = height_;
-    }
-
-    return IntVector2(width, height);
-}
-
-void Graphics::OnWindowResized_OGL()
-{
-    if (!window_)
-        return;
-
-    int newWidth, newHeight;
-
-    SDL_GL_GetDrawableSize(window_, &newWidth, &newHeight);
-    if (newWidth == width_ && newHeight == height_)
-        return;
-
-    width_ = newWidth;
-    height_ = newHeight;
-
-    int logicalWidth, logicalHeight;
-    SDL_GetWindowSize(window_, &logicalWidth, &logicalHeight);
-    screenParams_.highDPI_ = (width_ != logicalWidth) || (height_ != logicalHeight);
-
-    // Reset rendertargets and viewport for the new screen size. Also clean up any FBO's, as they may be screen size dependent
-    CleanupFramebuffers_OGL();
-    ResetRenderTargets_OGL();
-
-    URHO3D_LOGDEBUGF("Window was resized to %dx%d", width_, height_);
-
-#ifdef __EMSCRIPTEN__
-    EM_ASM({
-        Module.SetRendererSize($0, $1);
-    }, width_, height_);
-#endif
-
-    using namespace ScreenMode;
-
-    VariantMap& eventData = GetEventDataMap();
-    eventData[P_WIDTH] = width_;
-    eventData[P_HEIGHT] = height_;
-    eventData[P_FULLSCREEN] = screenParams_.fullscreen_;
-    eventData[P_RESIZABLE] = screenParams_.resizable_;
-    eventData[P_BORDERLESS] = screenParams_.borderless_;
-    eventData[P_HIGHDPI] = screenParams_.highDPI_;
-    SendEvent(E_SCREENMODE, eventData);
-}
-
-void Graphics::OnWindowMoved_OGL()
-{
-    if (!window_ || screenParams_.fullscreen_)
-        return;
-
-    int newX, newY;
-
-    SDL_GetWindowPosition(window_, &newX, &newY);
-    if (newX == position_.x_ && newY == position_.y_)
-        return;
-
-    position_.x_ = newX;
-    position_.y_ = newY;
-
-    URHO3D_LOGTRACEF("Window was moved to %d,%d", position_.x_, position_.y_);
-
-    using namespace WindowPos;
-
-    VariantMap& eventData = GetEventDataMap();
-    eventData[P_X] = position_.x_;
-    eventData[P_Y] = position_.y_;
-    SendEvent(E_WINDOWPOS, eventData);
-}
-
-void Graphics::CleanupRenderSurface_OGL(RenderSurface* surface)
-{
-    if (!surface)
-        return;
-
-    // Flush pending FBO changes first if any
-    PrepareDraw_OGL();
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    unsigned currentFBO = impl->boundFBO_;
-
-    // Go through all FBOs and clean up the surface from them
-    for (HashMap<unsigned long long, FrameBufferObject>::Iterator i = impl->frameBuffers_.Begin();
-         i != impl->frameBuffers_.End(); ++i)
-    {
-        for (unsigned j = 0; j < MAX_RENDERTARGETS; ++j)
-        {
-            if (i->second_.colorAttachments_[j] == surface)
-            {
-                if (currentFBO != i->second_.fbo_)
-                {
-                    BindFramebuffer_OGL(i->second_.fbo_);
-                    currentFBO = i->second_.fbo_;
-                }
-                BindColorAttachment_OGL(j, GL_TEXTURE_2D, 0, false);
-                i->second_.colorAttachments_[j] = nullptr;
-                // Mark drawbuffer bits to need recalculation
-                i->second_.drawBuffers_ = M_MAX_UNSIGNED;
-            }
-        }
-        if (i->second_.depthAttachment_ == surface)
-        {
-            if (currentFBO != i->second_.fbo_)
-            {
-                BindFramebuffer_OGL(i->second_.fbo_);
-                currentFBO = i->second_.fbo_;
-            }
-            BindDepthAttachment_OGL(0, false);
-            BindStencilAttachment_OGL(0, false);
-            i->second_.depthAttachment_ = nullptr;
-        }
-    }
-
-    // Restore previously bound FBO now if needed
-    if (currentFBO != impl->boundFBO_)
-        BindFramebuffer_OGL(impl->boundFBO_);
-}
-
-void Graphics::CleanupShaderPrograms_OGL(ShaderVariation* variation)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    for (ShaderProgramMap_OGL::Iterator i = impl->shaderPrograms_.Begin(); i != impl->shaderPrograms_.End();)
-    {
-        if (i->second_->GetVertexShader() == variation || i->second_->GetPixelShader() == variation)
-            i = impl->shaderPrograms_.Erase(i);
-        else
-            ++i;
-    }
-
-    if (vertexShader_ == variation || pixelShader_ == variation)
-        impl->shaderProgram_ = nullptr;
-}
-
-ConstantBuffer* Graphics::GetOrCreateConstantBuffer_OGL(ShaderType type,  unsigned index, unsigned size)
-{
-    // Note: shaderType parameter is not used on OpenGL, instead binding index should already use the PS range
-    // for PS constant buffers
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    unsigned key = (index << 16u) | size;
-    HashMap<unsigned, SharedPtr<ConstantBuffer> >::Iterator i = impl->allConstantBuffers_.Find(key);
-    if (i == impl->allConstantBuffers_.End())
-    {
-        i = impl->allConstantBuffers_.Insert(MakePair(key, SharedPtr<ConstantBuffer>(new ConstantBuffer(context_))));
-        i->second_->SetSize(size);
-    }
-    return i->second_.Get();
-}
-
-void Graphics::Release_OGL(bool clearGPUObjects, bool closeWindow)
-{
-    if (!window_)
-        return;
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    {
-        MutexLock lock(gpuObjectMutex_);
-
-        if (clearGPUObjects)
-        {
-            // Shutting down: release all GPU objects that still exist
-            // Shader programs are also GPU objects; clear them first to avoid list modification during iteration
-            impl->shaderPrograms_.Clear();
-
-            for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
-                (*i)->Release();
-            gpuObjects_.Clear();
-        }
-        else
-        {
-            // We are not shutting down, but recreating the context: mark GPU objects lost
-            for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
-                (*i)->OnDeviceLost();
-
-            // In this case clear shader programs last so that they do not attempt to delete their OpenGL program
-            // from a context that may no longer exist
-            impl->shaderPrograms_.Clear();
-
-            SendEvent(E_DEVICELOST);
-        }
-    }
-
-    CleanupFramebuffers_OGL();
-    impl->depthTextures_.Clear();
-
-    // End fullscreen mode first to counteract transition and getting stuck problems on OS X
-#if defined(__APPLE__) && !defined(IOS) && !defined(TVOS)
-    if (closeWindow && screenParams_.fullscreen_ && !externalWindow_)
-        SDL_SetWindowFullscreen(window_, 0);
-#endif
-
-    if (impl->context_)
-    {
-        // Do not log this message if we are exiting
-        if (!clearGPUObjects)
-            URHO3D_LOGINFO("OpenGL context lost");
-
-        SDL_GL_DeleteContext(impl->context_);
-        impl->context_ = nullptr;
-    }
-
-    if (closeWindow)
-    {
-        SDL_ShowCursor(SDL_TRUE);
-
-        // Do not destroy external window except when shutting down
-        if (!externalWindow_ || clearGPUObjects)
-        {
-            SDL_DestroyWindow(window_);
-            window_ = nullptr;
-        }
-    }
-}
-
-void Graphics::Restore_OGL()
-{
-    if (!window_)
-        return;
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-#ifdef __ANDROID__
-    // On Android the context may be lost behind the scenes as the application is minimized
-    if (impl->context_ && !SDL_GL_GetCurrentContext())
-    {
-        impl->context_ = 0;
-        // Mark GPU objects lost without a current context. In this case they just mark their internal state lost
-        // but do not perform OpenGL commands to delete the GL objects
-        Release_OGL(false, false);
-    }
-#endif
-
-    // Ensure first that the context exists
-    if (!impl->context_)
-    {
-        impl->context_ = SDL_GL_CreateContext(window_);
-
-#ifndef GL_ES_VERSION_2_0
-        // If we're trying to use OpenGL 3, but context creation fails, retry with 2
-        if (!forceGL2_ && !impl->context_)
-        {
-            forceGL2_ = true;
-            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
-            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
-            SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
-            impl->context_ = SDL_GL_CreateContext(window_);
-        }
-#endif
-
-#if defined(IOS) || defined(TVOS)
-        glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&impl->systemFBO_);
-#endif
-
-        if (!impl->context_)
-        {
-            URHO3D_LOGERRORF("Could not create OpenGL context, root cause '%s'", SDL_GetError());
-            return;
-        }
-
-        // Clear cached extensions string from the previous context
-        extensions.Clear();
-
-        // Initialize OpenGL extensions library (desktop only)
-#ifndef GL_ES_VERSION_2_0
-        GLenum err = glewInit();
-        if (GLEW_OK != err)
-        {
-            URHO3D_LOGERRORF("Could not initialize OpenGL extensions, root cause: '%s'", glewGetErrorString(err));
-            return;
-        }
-
-        if (!forceGL2_ && GLEW_VERSION_3_2)
-        {
-            gl3Support = true;
-            apiName_ = "GL3";
-
-            // Create and bind a vertex array object that will stay in use throughout
-            unsigned vertexArrayObject;
-            glGenVertexArrays(1, &vertexArrayObject);
-            glBindVertexArray(vertexArrayObject);
-        }
-        else if (GLEW_VERSION_2_0)
-        {
-            if (!GLEW_EXT_framebuffer_object || !GLEW_EXT_packed_depth_stencil)
-            {
-                URHO3D_LOGERROR("EXT_framebuffer_object and EXT_packed_depth_stencil OpenGL extensions are required");
-                return;
-            }
-
-            gl3Support = false;
-            apiName_ = "GL2";
-        }
-        else
-        {
-            URHO3D_LOGERROR("OpenGL 2.0 is required");
-            return;
-        }
-
-        // Enable seamless cubemap if possible
-        // Note: even though we check the extension, this can lead to software fallback on some old GPU's
-        // See https://github.com/urho3d/Urho3D/issues/1380 or
-        // http://distrustsimplicity.net/articles/gl_texture_cube_map_seamless-on-os-x/
-        // In case of trouble or for wanting maximum compatibility, simply remove the glEnable below.
-        if (gl3Support || GLEW_ARB_seamless_cube_map)
-            glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
-#endif
-
-        // Set up texture data read/write alignment. It is important that this is done before uploading any texture data
-        glPixelStorei(GL_PACK_ALIGNMENT, 1);
-        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-        ResetCachedState_OGL();
-    }
-
-    {
-        MutexLock lock(gpuObjectMutex_);
-
-        for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
-            (*i)->OnDeviceReset();
-    }
-
-    SendEvent(E_DEVICERESET);
-}
-
-void Graphics::MarkFBODirty_OGL()
-{
-    GetImpl_OGL()->fboDirty_ = true;
-}
-
-void Graphics::SetVBO_OGL(unsigned object)
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (impl->boundVBO_ != object)
-    {
-        if (object)
-            glBindBuffer(GL_ARRAY_BUFFER, object);
-        impl->boundVBO_ = object;
-    }
-}
-
-void Graphics::SetUBO_OGL(unsigned object)
-{
-#ifndef GL_ES_VERSION_2_0
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-    if (impl->boundUBO_ != object)
-    {
-        if (object)
-            glBindBuffer(GL_UNIFORM_BUFFER, object);
-        impl->boundUBO_ = object;
-    }
-#endif
-}
-
-unsigned Graphics::GetAlphaFormat_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    // Alpha format is deprecated on OpenGL 3+
-    if (gl3Support)
-        return GL_R8;
-#endif
-    return GL_ALPHA;
-}
-
-unsigned Graphics::GetLuminanceFormat_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    // Luminance format is deprecated on OpenGL 3+
-    if (gl3Support)
-        return GL_R8;
-#endif
-    return GL_LUMINANCE;
-}
-
-unsigned Graphics::GetLuminanceAlphaFormat_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    // Luminance alpha format is deprecated on OpenGL 3+
-    if (gl3Support)
-        return GL_RG8;
-#endif
-    return GL_LUMINANCE_ALPHA;
-}
-
-unsigned Graphics::GetRGBFormat_OGL()
-{
-    return GL_RGB;
-}
-
-unsigned Graphics::GetRGBAFormat_OGL()
-{
-    return GL_RGBA;
-}
-
-unsigned Graphics::GetRGBA16Format_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    return GL_RGBA16;
-#else
-    return GL_RGBA;
-#endif
-}
-
-unsigned Graphics::GetRGBAFloat16Format_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    return GL_RGBA16F_ARB;
-#else
-    return GL_RGBA;
-#endif
-}
-
-unsigned Graphics::GetRGBAFloat32Format_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    return GL_RGBA32F_ARB;
-#else
-    return GL_RGBA;
-#endif
-}
-
-unsigned Graphics::GetRG16Format_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    return GL_RG16;
-#else
-    return GL_RGBA;
-#endif
-}
-
-unsigned Graphics::GetRGFloat16Format_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    return GL_RG16F;
-#else
-    return GL_RGBA;
-#endif
-}
-
-unsigned Graphics::GetRGFloat32Format_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    return GL_RG32F;
-#else
-    return GL_RGBA;
-#endif
-}
-
-unsigned Graphics::GetFloat16Format_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    return GL_R16F;
-#else
-    return GL_LUMINANCE;
-#endif
-}
-
-unsigned Graphics::GetFloat32Format_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    return GL_R32F;
-#else
-    return GL_LUMINANCE;
-#endif
-}
-
-unsigned Graphics::GetLinearDepthFormat_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    // OpenGL 3 can use different color attachment formats
-    if (gl3Support)
-        return GL_R32F;
-#endif
-    // OpenGL 2 requires color attachments to have the same format, therefore encode deferred depth to RGBA manually
-    // if not using a readable hardware depth texture
-    return GL_RGBA;
-}
-
-unsigned Graphics::GetDepthStencilFormat_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    return GL_DEPTH24_STENCIL8_EXT;
-#else
-    return glesDepthStencilFormat;
-#endif
-}
-
-unsigned Graphics::GetReadableDepthFormat_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    return GL_DEPTH_COMPONENT24;
-#else
-    return glesReadableDepthFormat;
-#endif
-}
-
-unsigned Graphics::GetFormat_OGL(const String& formatName)
-{
-    String nameLower = formatName.ToLower().Trimmed();
-
-    if (nameLower == "a")
-        return GetAlphaFormat_OGL();
-    if (nameLower == "l")
-        return GetLuminanceFormat_OGL();
-    if (nameLower == "la")
-        return GetLuminanceAlphaFormat_OGL();
-    if (nameLower == "rgb")
-        return GetRGBFormat_OGL();
-    if (nameLower == "rgba")
-        return GetRGBAFormat_OGL();
-    if (nameLower == "rgba16")
-        return GetRGBA16Format_OGL();
-    if (nameLower == "rgba16f")
-        return GetRGBAFloat16Format_OGL();
-    if (nameLower == "rgba32f")
-        return GetRGBAFloat32Format_OGL();
-    if (nameLower == "rg16")
-        return GetRG16Format_OGL();
-    if (nameLower == "rg16f")
-        return GetRGFloat16Format_OGL();
-    if (nameLower == "rg32f")
-        return GetRGFloat32Format_OGL();
-    if (nameLower == "r16f")
-        return GetFloat16Format_OGL();
-    if (nameLower == "r32f" || nameLower == "float")
-        return GetFloat32Format_OGL();
-    if (nameLower == "lineardepth" || nameLower == "depth")
-        return GetLinearDepthFormat_OGL();
-    if (nameLower == "d24s8")
-        return GetDepthStencilFormat_OGL();
-    if (nameLower == "readabledepth" || nameLower == "hwdepth")
-        return GetReadableDepthFormat_OGL();
-
-    return GetRGBFormat_OGL();
-}
-
-void Graphics::CheckFeatureSupport_OGL()
-{
-    // Check supported features: light pre-pass, deferred rendering and hardware depth texture
-    lightPrepassSupport_ = false;
-    deferredSupport_ = false;
-
-#ifndef GL_ES_VERSION_2_0
-    int numSupportedRTs = 1;
-    if (gl3Support)
-    {
-        // Work around GLEW failure to check extensions properly from a GL3 context
-        instancingSupport_ = glDrawElementsInstanced != nullptr && glVertexAttribDivisor != nullptr;
-        dxtTextureSupport_ = true;
-        anisotropySupport_ = true;
-        sRGBSupport_ = true;
-        sRGBWriteSupport_ = true;
-
-        glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &numSupportedRTs);
-    }
-    else
-    {
-        instancingSupport_ = GLEW_ARB_instanced_arrays != 0;
-        dxtTextureSupport_ = GLEW_EXT_texture_compression_s3tc != 0;
-        anisotropySupport_ = GLEW_EXT_texture_filter_anisotropic != 0;
-        sRGBSupport_ = GLEW_EXT_texture_sRGB != 0;
-        sRGBWriteSupport_ = GLEW_EXT_framebuffer_sRGB != 0;
-
-        glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &numSupportedRTs);
-    }
-
-    // Must support 2 rendertargets for light pre-pass, and 4 for deferred
-    if (numSupportedRTs >= 2)
-        lightPrepassSupport_ = true;
-    if (numSupportedRTs >= 4)
-        deferredSupport_ = true;
-
-#if defined(__APPLE__) && !defined(IOS) && !defined(TVOS)
-    // On macOS check for an Intel driver and use shadow map RGBA dummy color textures, because mixing
-    // depth-only FBO rendering and backbuffer rendering will bug, resulting in a black screen in full
-    // screen mode, and incomplete shadow maps in windowed mode
-    String renderer((const char*)glGetString(GL_RENDERER));
-    if (renderer.Contains("Intel", false))
-        dummyColorFormat_ = GetRGBAFormat_OGL();
-#endif
-#else
-    // Check for supported compressed texture formats
-#ifdef __EMSCRIPTEN__
-    dxtTextureSupport_ = CheckExtension("WEBGL_compressed_texture_s3tc"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
-    etcTextureSupport_ = CheckExtension("WEBGL_compressed_texture_etc1"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/
-    pvrtcTextureSupport_ = CheckExtension("WEBGL_compressed_texture_pvrtc"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/
-    etc2TextureSupport_ = gl3Support || CheckExtension("WEBGL_compressed_texture_etc"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc/
-    // Instancing is in core in WebGL 2, so the extension may not be present anymore. In WebGL 1, find https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
-    // TODO: In the distant future, this may break if WebGL 3 is introduced, so either improve the GL_VERSION parsing here, or keep track of which WebGL version we attempted to initialize.
-    instancingSupport_ = (strstr((const char *)glGetString(GL_VERSION), "WebGL 2.") != 0) || CheckExtension("ANGLE_instanced_arrays");
-#else
-    dxtTextureSupport_ = CheckExtension("EXT_texture_compression_dxt1");
-    etcTextureSupport_ = CheckExtension("OES_compressed_ETC1_RGB8_texture");
-    etc2TextureSupport_ = gl3Support || CheckExtension("OES_compressed_ETC2_RGBA8_texture");
-    pvrtcTextureSupport_ = CheckExtension("IMG_texture_compression_pvrtc");
-#endif
-
-    // Check for best supported depth renderbuffer format for GLES2
-    if (CheckExtension("GL_OES_depth24"))
-        glesDepthStencilFormat = GL_DEPTH_COMPONENT24_OES;
-    if (CheckExtension("GL_OES_packed_depth_stencil"))
-        glesDepthStencilFormat = GL_DEPTH24_STENCIL8_OES;
-    #ifdef __EMSCRIPTEN__
-    if (!CheckExtension("WEBGL_depth_texture"))
-#else
-    if (!CheckExtension("GL_OES_depth_texture"))
-#endif
-    {
-        shadowMapFormat_ = 0;
-        hiresShadowMapFormat_ = 0;
-        glesReadableDepthFormat = 0;
-    }
-    else
-    {
-#if defined(IOS) || defined(TVOS)
-        // iOS hack: depth renderbuffer seems to fail, so use depth textures for everything if supported
-        glesDepthStencilFormat = GL_DEPTH_COMPONENT;
-#endif
-        shadowMapFormat_ = GL_DEPTH_COMPONENT;
-        hiresShadowMapFormat_ = 0;
-        // WebGL shadow map rendering seems to be extremely slow without an attached dummy color texture
-        #ifdef __EMSCRIPTEN__
-        dummyColorFormat_ = GetRGBAFormat_OGL();
-#endif
-    }
-#endif
-
-    // Consider OpenGL shadows always hardware sampled, if supported at all
-    hardwareShadowSupport_ = shadowMapFormat_ != 0;
-}
-
-void Graphics::PrepareDraw_OGL()
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-#ifndef GL_ES_VERSION_2_0
-    if (gl3Support)
-    {
-        for (PODVector<ConstantBuffer*>::Iterator i = impl->dirtyConstantBuffers_.Begin(); i != impl->dirtyConstantBuffers_.End(); ++i)
-            (*i)->Apply();
-        impl->dirtyConstantBuffers_.Clear();
-    }
-#endif
-
-    if (impl->fboDirty_)
-    {
-        impl->fboDirty_ = false;
-
-        // First check if no framebuffer is needed. In that case simply return to backbuffer rendering
-        bool noFbo = !depthStencil_;
-        if (noFbo)
-        {
-            for (auto& renderTarget : renderTargets_)
-            {
-                if (renderTarget)
-                {
-                    noFbo = false;
-                    break;
-                }
-            }
-        }
-
-        if (noFbo)
-        {
-            if (impl->boundFBO_ != impl->systemFBO_)
-            {
-                BindFramebuffer_OGL(impl->systemFBO_);
-                impl->boundFBO_ = impl->systemFBO_;
-            }
-
-#ifndef GL_ES_VERSION_2_0
-            // Disable/enable sRGB write
-            if (sRGBWriteSupport_)
-            {
-                bool sRGBWrite = sRGB_;
-                if (sRGBWrite != impl->sRGBWrite_)
-                {
-                    if (sRGBWrite)
-                        glEnable(GL_FRAMEBUFFER_SRGB_EXT);
-                    else
-                        glDisable(GL_FRAMEBUFFER_SRGB_EXT);
-                    impl->sRGBWrite_ = sRGBWrite;
-                }
-            }
-#endif
-
-            return;
-        }
-
-        // Search for a new framebuffer based on format & size, or create new
-        IntVector2 rtSize = Graphics::GetRenderTargetDimensions_OGL();
-        unsigned format = 0;
-        if (renderTargets_[0])
-            format = renderTargets_[0]->GetParentTexture()->GetFormat();
-        else if (depthStencil_)
-            format = depthStencil_->GetParentTexture()->GetFormat();
-
-        auto fboKey = (unsigned long long)format << 32u | rtSize.x_ << 16u | rtSize.y_;
-        HashMap<unsigned long long, FrameBufferObject>::Iterator i = impl->frameBuffers_.Find(fboKey);
-        if (i == impl->frameBuffers_.End())
-        {
-            FrameBufferObject newFbo;
-            newFbo.fbo_ = CreateFramebuffer_OGL();
-            i = impl->frameBuffers_.Insert(MakePair(fboKey, newFbo));
-        }
-
-        if (impl->boundFBO_ != i->second_.fbo_)
-        {
-            BindFramebuffer_OGL(i->second_.fbo_);
-            impl->boundFBO_ = i->second_.fbo_;
-        }
-
-#ifndef GL_ES_VERSION_2_0
-        // Setup readbuffers & drawbuffers if needed
-        if (i->second_.readBuffers_ != GL_NONE)
-        {
-            glReadBuffer(GL_NONE);
-            i->second_.readBuffers_ = GL_NONE;
-        }
-
-        // Calculate the bit combination of non-zero color rendertargets to first check if the combination changed
-        unsigned newDrawBuffers = 0;
-        for (unsigned j = 0; j < MAX_RENDERTARGETS; ++j)
-        {
-            if (renderTargets_[j])
-                newDrawBuffers |= 1u << j;
-        }
-
-        if (newDrawBuffers != i->second_.drawBuffers_)
-        {
-            // Check for no color rendertargets (depth rendering only)
-            if (!newDrawBuffers)
-                glDrawBuffer(GL_NONE);
-            else
-            {
-                int drawBufferIds[MAX_RENDERTARGETS];
-                unsigned drawBufferCount = 0;
-
-                for (unsigned j = 0; j < MAX_RENDERTARGETS; ++j)
-                {
-                    if (renderTargets_[j])
-                    {
-                        if (!gl3Support)
-                            drawBufferIds[drawBufferCount++] = GL_COLOR_ATTACHMENT0_EXT + j;
-                        else
-                            drawBufferIds[drawBufferCount++] = GL_COLOR_ATTACHMENT0 + j;
-                    }
-                }
-                glDrawBuffers(drawBufferCount, (const GLenum*)drawBufferIds);
-            }
-
-            i->second_.drawBuffers_ = newDrawBuffers;
-        }
-#endif
-
-        for (unsigned j = 0; j < MAX_RENDERTARGETS; ++j)
-        {
-            if (renderTargets_[j])
-            {
-                Texture* texture = renderTargets_[j]->GetParentTexture();
-
-                // Bind either a renderbuffer or texture, depending on what is available
-                unsigned renderBufferID = renderTargets_[j]->GetRenderBuffer();
-                if (!renderBufferID)
-                {
-                    // If texture's parameters are dirty, update before attaching
-                    if (texture->GetParametersDirty())
-                    {
-                        SetTextureForUpdate_OGL(texture);
-                        texture->UpdateParameters();
-                        SetTexture_OGL(0, nullptr);
-                    }
-
-                    if (i->second_.colorAttachments_[j] != renderTargets_[j])
-                    {
-                        BindColorAttachment_OGL(j, renderTargets_[j]->GetTarget(), texture->GetGPUObjectName(), false);
-                        i->second_.colorAttachments_[j] = renderTargets_[j];
-                    }
-                }
-                else
-                {
-                    if (i->second_.colorAttachments_[j] != renderTargets_[j])
-                    {
-                        BindColorAttachment_OGL(j, renderTargets_[j]->GetTarget(), renderBufferID, true);
-                        i->second_.colorAttachments_[j] = renderTargets_[j];
-                    }
-                }
-            }
-            else
-            {
-                if (i->second_.colorAttachments_[j])
-                {
-                    BindColorAttachment_OGL(j, GL_TEXTURE_2D, 0, false);
-                    i->second_.colorAttachments_[j] = nullptr;
-                }
-            }
-        }
-
-        if (depthStencil_)
-        {
-            // Bind either a renderbuffer or a depth texture, depending on what is available
-            Texture* texture = depthStencil_->GetParentTexture();
-#ifndef GL_ES_VERSION_2_0
-            bool hasStencil = texture->GetFormat() == GL_DEPTH24_STENCIL8_EXT;
-#else
-            bool hasStencil = texture->GetFormat() == GL_DEPTH24_STENCIL8_OES;
-#endif
-            unsigned renderBufferID = depthStencil_->GetRenderBuffer();
-            if (!renderBufferID)
-            {
-                // If texture's parameters are dirty, update before attaching
-                if (texture->GetParametersDirty())
-                {
-                    SetTextureForUpdate_OGL(texture);
-                    texture->UpdateParameters();
-                    SetTexture_OGL(0, nullptr);
-                }
-
-                if (i->second_.depthAttachment_ != depthStencil_)
-                {
-                    BindDepthAttachment_OGL(texture->GetGPUObjectName(), false);
-                    BindStencilAttachment_OGL(hasStencil ? texture->GetGPUObjectName() : 0, false);
-                    i->second_.depthAttachment_ = depthStencil_;
-                }
-            }
-            else
-            {
-                if (i->second_.depthAttachment_ != depthStencil_)
-                {
-                    BindDepthAttachment_OGL(renderBufferID, true);
-                    BindStencilAttachment_OGL(hasStencil ? renderBufferID : 0, true);
-                    i->second_.depthAttachment_ = depthStencil_;
-                }
-            }
-        }
-        else
-        {
-            if (i->second_.depthAttachment_)
-            {
-                BindDepthAttachment_OGL(0, false);
-                BindStencilAttachment_OGL(0, false);
-                i->second_.depthAttachment_ = nullptr;
-            }
-        }
-
-#ifndef GL_ES_VERSION_2_0
-        // Disable/enable sRGB write
-        if (sRGBWriteSupport_)
-        {
-            bool sRGBWrite = renderTargets_[0] ? renderTargets_[0]->GetParentTexture()->GetSRGB() : sRGB_;
-            if (sRGBWrite != impl->sRGBWrite_)
-            {
-                if (sRGBWrite)
-                    glEnable(GL_FRAMEBUFFER_SRGB_EXT);
-                else
-                    glDisable(GL_FRAMEBUFFER_SRGB_EXT);
-                impl->sRGBWrite_ = sRGBWrite;
-            }
-        }
-#endif
-    }
-
-    if (impl->vertexBuffersDirty_)
-    {
-        // Go through currently bound vertex buffers and set the attribute pointers that are available & required
-        // Use reverse order so that elements from higher index buffers will override lower index buffers
-        unsigned assignedLocations = 0;
-
-        for (unsigned i = MAX_VERTEX_STREAMS - 1; i < MAX_VERTEX_STREAMS; --i)
-        {
-            VertexBuffer* buffer = vertexBuffers_[i];
-            // Beware buffers with missing OpenGL objects, as binding a zero buffer object means accessing CPU memory for vertex data,
-            // in which case the pointer will be invalid and cause a crash
-            if (!buffer || !buffer->GetGPUObjectName() || !impl->vertexAttributes_)
-                continue;
-
-            const PODVector<VertexElement>& elements = buffer->GetElements();
-
-            for (PODVector<VertexElement>::ConstIterator j = elements.Begin(); j != elements.End(); ++j)
-            {
-                const VertexElement& element = *j;
-                HashMap<Pair<unsigned char, unsigned char>, unsigned>::ConstIterator k =
-                    impl->vertexAttributes_->Find(MakePair((unsigned char)element.semantic_, element.index_));
-
-                if (k != impl->vertexAttributes_->End())
-                {
-                    unsigned location = k->second_;
-                    unsigned locationMask = 1u << location;
-                    if (assignedLocations & locationMask)
-                        continue; // Already assigned by higher index vertex buffer
-                    assignedLocations |= locationMask;
-
-                    // Enable attribute if not enabled yet
-                    if (!(impl->enabledVertexAttributes_ & locationMask))
-                    {
-                        glEnableVertexAttribArray(location);
-                        impl->enabledVertexAttributes_ |= locationMask;
-                    }
-
-                    // Enable/disable instancing divisor as necessary
-                    unsigned dataStart = element.offset_;
-                    if (element.perInstance_)
-                    {
-                        dataStart += impl->lastInstanceOffset_ * buffer->GetVertexSize();
-                        if (!(impl->instancingVertexAttributes_ & locationMask))
-                        {
-                            SetVertexAttribDivisor_OGL(location, 1);
-                            impl->instancingVertexAttributes_ |= locationMask;
-                        }
-                    }
-                    else
-                    {
-                        if (impl->instancingVertexAttributes_ & locationMask)
-                        {
-                            SetVertexAttribDivisor_OGL(location, 0);
-                            impl->instancingVertexAttributes_ &= ~locationMask;
-                        }
-                    }
-
-                    SetVBO_OGL(buffer->GetGPUObjectName());
-                    glVertexAttribPointer(location, glElementComponents[element.type_], glElementTypes[element.type_],
-                        element.type_ == TYPE_UBYTE4_NORM ? GL_TRUE : GL_FALSE, (unsigned)buffer->GetVertexSize(),
-                        (const void *)(size_t)dataStart);
-                }
-            }
-        }
-
-        // Finally disable unnecessary vertex attributes
-        unsigned disableVertexAttributes = impl->enabledVertexAttributes_ & (~impl->usedVertexAttributes_);
-        unsigned location = 0;
-        while (disableVertexAttributes)
-        {
-            if (disableVertexAttributes & 1u)
-            {
-                glDisableVertexAttribArray(location);
-                impl->enabledVertexAttributes_ &= ~(1u << location);
-            }
-            ++location;
-            disableVertexAttributes >>= 1;
-        }
-
-        impl->vertexBuffersDirty_ = false;
-    }
-}
-
-void Graphics::CleanupFramebuffers_OGL()
-{
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    if (!IsDeviceLost_OGL())
-    {
-        BindFramebuffer_OGL(impl->systemFBO_);
-        impl->boundFBO_ = impl->systemFBO_;
-        impl->fboDirty_ = true;
-
-        for (HashMap<unsigned long long, FrameBufferObject>::Iterator i = impl->frameBuffers_.Begin();
-             i != impl->frameBuffers_.End(); ++i)
-            DeleteFramebuffer_OGL(i->second_.fbo_);
-
-        if (impl->resolveSrcFBO_)
-            DeleteFramebuffer_OGL(impl->resolveSrcFBO_);
-        if (impl->resolveDestFBO_)
-            DeleteFramebuffer_OGL(impl->resolveDestFBO_);
-    }
-    else
-        impl->boundFBO_ = 0;
-
-    impl->resolveSrcFBO_ = 0;
-    impl->resolveDestFBO_ = 0;
-
-    impl->frameBuffers_.Clear();
-}
-
-void Graphics::ResetCachedState_OGL()
-{
-    for (auto& vertexBuffer : vertexBuffers_)
-        vertexBuffer = nullptr;
-
-    GraphicsImpl_OGL* impl = GetImpl_OGL();
-
-    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-    {
-        textures_[i] = nullptr;
-        impl->textureTypes_[i] = 0;
-    }
-
-    for (auto& renderTarget : renderTargets_)
-        renderTarget = nullptr;
-
-    depthStencil_ = nullptr;
-    viewport_ = IntRect(0, 0, 0, 0);
-    indexBuffer_ = nullptr;
-    vertexShader_ = nullptr;
-    pixelShader_ = nullptr;
-    blendMode_ = BLEND_REPLACE;
-    alphaToCoverage_ = false;
-    colorWrite_ = true;
-    cullMode_ = CULL_NONE;
-    constantDepthBias_ = 0.0f;
-    slopeScaledDepthBias_ = 0.0f;
-    depthTestMode_ = CMP_ALWAYS;
-    depthWrite_ = false;
-    lineAntiAlias_ = false;
-    fillMode_ = FILL_SOLID;
-    scissorTest_ = false;
-    scissorRect_ = IntRect::ZERO;
-    stencilTest_ = false;
-    stencilTestMode_ = CMP_ALWAYS;
-    stencilPass_ = OP_KEEP;
-    stencilFail_ = OP_KEEP;
-    stencilZFail_ = OP_KEEP;
-    stencilRef_ = 0;
-    stencilCompareMask_ = M_MAX_UNSIGNED;
-    stencilWriteMask_ = M_MAX_UNSIGNED;
-    useClipPlane_ = false;
-    impl->shaderProgram_ = nullptr;
-    impl->lastInstanceOffset_ = 0;
-    impl->activeTexture_ = 0;
-    impl->enabledVertexAttributes_ = 0;
-    impl->usedVertexAttributes_ = 0;
-    impl->instancingVertexAttributes_ = 0;
-    impl->boundFBO_ = impl->systemFBO_;
-    impl->boundVBO_ = 0;
-    impl->boundUBO_ = 0;
-    impl->sRGBWrite_ = false;
-
-    // Set initial state to match Direct3D
-    if (impl->context_)
-    {
-        glEnable(GL_DEPTH_TEST);
-        SetCullMode_OGL(CULL_CCW);
-        SetDepthTest_OGL(CMP_LESSEQUAL);
-        SetDepthWrite_OGL(true);
-    }
-
-    for (auto& constantBuffer : impl->constantBuffers_)
-        constantBuffer = nullptr;
-    impl->dirtyConstantBuffers_.Clear();
-}
-
-void Graphics::SetTextureUnitMappings_OGL()
-{
-    textureUnits_["DiffMap"] = TU_DIFFUSE;
-    textureUnits_["DiffCubeMap"] = TU_DIFFUSE;
-    textureUnits_["AlbedoBuffer"] = TU_ALBEDOBUFFER;
-    textureUnits_["NormalMap"] = TU_NORMAL;
-    textureUnits_["NormalBuffer"] = TU_NORMALBUFFER;
-    textureUnits_["SpecMap"] = TU_SPECULAR;
-    textureUnits_["EmissiveMap"] = TU_EMISSIVE;
-    textureUnits_["EnvMap"] = TU_ENVIRONMENT;
-    textureUnits_["EnvCubeMap"] = TU_ENVIRONMENT;
-    textureUnits_["LightRampMap"] = TU_LIGHTRAMP;
-    textureUnits_["LightSpotMap"] = TU_LIGHTSHAPE;
-    textureUnits_["LightCubeMap"] = TU_LIGHTSHAPE;
-    textureUnits_["ShadowMap"] = TU_SHADOWMAP;
-#ifndef GL_ES_VERSION_2_0
-    textureUnits_["VolumeMap"] = TU_VOLUMEMAP;
-    textureUnits_["FaceSelectCubeMap"] = TU_FACESELECT;
-    textureUnits_["IndirectionCubeMap"] = TU_INDIRECTION;
-    textureUnits_["DepthBuffer"] = TU_DEPTHBUFFER;
-    textureUnits_["LightBuffer"] = TU_LIGHTBUFFER;
-    textureUnits_["ZoneCubeMap"] = TU_ZONE;
-    textureUnits_["ZoneVolumeMap"] = TU_ZONE;
-#endif
-}
-
-unsigned Graphics::CreateFramebuffer_OGL()
-{
-    unsigned newFbo = 0;
-#ifndef GL_ES_VERSION_2_0
-    if (!gl3Support)
-        glGenFramebuffersEXT(1, &newFbo);
-    else
-#endif
-        glGenFramebuffers(1, &newFbo);
-    return newFbo;
-}
-
-void Graphics::DeleteFramebuffer_OGL(unsigned fbo)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (!gl3Support)
-        glDeleteFramebuffersEXT(1, &fbo);
-    else
-#endif
-        glDeleteFramebuffers(1, &fbo);
-}
-
-void Graphics::BindFramebuffer_OGL(unsigned fbo)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (!gl3Support)
-        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
-    else
-#endif
-        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-}
-
-void Graphics::BindColorAttachment_OGL(unsigned index, unsigned target, unsigned object, bool isRenderBuffer)
-{
-    if (!object)
-        isRenderBuffer = false;
-
-#ifndef GL_ES_VERSION_2_0
-    if (!gl3Support)
-    {
-        if (!isRenderBuffer)
-            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, object, 0);
-        else
-            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_RENDERBUFFER_EXT, object);
-    }
-    else
-#endif
-    {
-        if (!isRenderBuffer)
-            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, target, object, 0);
-        else
-            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, GL_RENDERBUFFER, object);
-    }
-}
-
-void Graphics::BindDepthAttachment_OGL(unsigned object, bool isRenderBuffer)
-{
-    if (!object)
-        isRenderBuffer = false;
-
-#ifndef GL_ES_VERSION_2_0
-    if (!gl3Support)
-    {
-        if (!isRenderBuffer)
-            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, object, 0);
-        else
-            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, object);
-    }
-    else
-#endif
-    {
-        if (!isRenderBuffer)
-            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, object, 0);
-        else
-            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, object);
-    }
-}
-
-void Graphics::BindStencilAttachment_OGL(unsigned object, bool isRenderBuffer)
-{
-    if (!object)
-        isRenderBuffer = false;
-
-#ifndef GL_ES_VERSION_2_0
-    if (!gl3Support)
-    {
-        if (!isRenderBuffer)
-            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, object, 0);
-        else
-            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, object);
-    }
-    else
-#endif
-    {
-        if (!isRenderBuffer)
-            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, object, 0);
-        else
-            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, object);
-    }
-}
-
-bool Graphics::CheckFramebuffer_OGL()
-{
-#ifndef GL_ES_VERSION_2_0
-    if (!gl3Support)
-        return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT;
-    else
-#endif
-        return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
-}
-
-void Graphics::SetVertexAttribDivisor_OGL(unsigned location, unsigned divisor)
-{
-#ifndef GL_ES_VERSION_2_0
-    if (gl3Support && instancingSupport_)
-        glVertexAttribDivisor(location, divisor);
-    else if (instancingSupport_)
-        glVertexAttribDivisorARB(location, divisor);
-#else
-#ifdef __EMSCRIPTEN__
-    if (instancingSupport_)
-        glVertexAttribDivisorANGLE(location, divisor);
-#endif
-#endif
-}
-
-}
+//
+// Copyright (c) 2008-2022 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "../../Precompiled.h"
+
+#include "../../Core/Context.h"
+#include "../../Core/Mutex.h"
+#include "../../Core/ProcessUtils.h"
+#include "../../Core/Profiler.h"
+#include "../../Graphics/Graphics.h"
+#include "../../Graphics/GraphicsEvents.h"
+#include "../../GraphicsAPI/ConstantBuffer.h"
+#include "../../GraphicsAPI/IndexBuffer.h"
+#include "../../GraphicsAPI/OpenGL/OGLGraphicsImpl.h"
+#include "../../GraphicsAPI/OpenGL/OGLShaderProgram.h"
+#include "../../GraphicsAPI/RenderSurface.h"
+#include "../../GraphicsAPI/Shader.h"
+#include "../../GraphicsAPI/ShaderPrecache.h"
+#include "../../GraphicsAPI/ShaderVariation.h"
+#include "../../GraphicsAPI/Texture2D.h"
+#include "../../GraphicsAPI/TextureCube.h"
+#include "../../GraphicsAPI/VertexBuffer.h"
+#include "../../IO/File.h"
+#include "../../IO/Log.h"
+#include "../../Resource/ResourceCache.h"
+
+#include <SDL/SDL.h>
+
+#include "../../DebugNew.h"
+
+#ifdef GL_ES_VERSION_2_0
+#define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
+#define glClearDepth glClearDepthf
+#endif
+
+#ifdef __EMSCRIPTEN__
+#include "../../Input/Input.h"
+#include "../../UI/Cursor.h"
+#include "../../UI/UI.h"
+#include <emscripten/emscripten.h>
+#include <emscripten/bind.h>
+
+// Emscripten provides even all GL extension functions via static linking. However there is
+// no GLES2-specific extension header at the moment to include instanced rendering declarations,
+// so declare them manually from GLES3 gl2ext.h. Emscripten will provide these when linking final output.
+extern "C"
+{
+    GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+    GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+    GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor);
+}
+
+// Helper functions to support emscripten canvas resolution change
+static const Urho3D::Context *appContext;
+
+static void JSCanvasSize(int width, int height, bool fullscreen, float scale)
+{
+    URHO3D_LOGINFOF("JSCanvasSize: width=%d height=%d fullscreen=%d ui scale=%f", width, height, fullscreen, scale);
+
+    using namespace Urho3D;
+
+    if (appContext)
+    {
+        bool uiCursorVisible = false;
+        bool systemCursorVisible = false;
+        MouseMode mouseMode{};
+
+        // Detect current system pointer state
+        Input* input = appContext->GetSubsystem<Input>();
+        if (input)
+        {
+            systemCursorVisible = input->IsMouseVisible();
+            mouseMode = input->GetMouseMode();
+        }
+
+        UI* ui = appContext->GetSubsystem<UI>();
+        if (ui)
+        {
+            ui->SetScale(scale);
+
+            // Detect current UI pointer state
+            Cursor* cursor = ui->GetCursor();
+            if (cursor)
+                uiCursorVisible = cursor->IsVisible();
+        }
+
+        // Apply new resolution
+        appContext->GetSubsystem<Graphics>()->SetMode(width, height);
+
+        // Reset the pointer state as it was before resolution change
+        if (input)
+        {
+            if (uiCursorVisible)
+                input->SetMouseVisible(false);
+            else
+                input->SetMouseVisible(systemCursorVisible);
+
+            input->SetMouseMode(mouseMode);
+        }
+
+        if (ui)
+        {
+            Cursor* cursor = ui->GetCursor();
+            if (cursor)
+            {
+                cursor->SetVisible(uiCursorVisible);
+
+                IntVector2 pos = input->GetMousePosition();
+                pos = ui->ConvertSystemToUI(pos);
+
+                cursor->SetPosition(pos);
+            }
+        }
+    }
+}
+
+using namespace emscripten;
+EMSCRIPTEN_BINDINGS(Module) {
+    function("JSCanvasSize", &JSCanvasSize);
+}
+#endif
+
+namespace Urho3D
+{
+
+static const unsigned glCmpFunc[] =
+{
+    GL_ALWAYS,
+    GL_EQUAL,
+    GL_NOTEQUAL,
+    GL_LESS,
+    GL_LEQUAL,
+    GL_GREATER,
+    GL_GEQUAL
+};
+
+static const unsigned glSrcBlend[] =
+{
+    GL_ONE,
+    GL_ONE,
+    GL_DST_COLOR,
+    GL_SRC_ALPHA,
+    GL_SRC_ALPHA,
+    GL_ONE,
+    GL_ONE_MINUS_DST_ALPHA,
+    GL_ONE,
+    GL_SRC_ALPHA
+};
+
+static const unsigned glDestBlend[] =
+{
+    GL_ZERO,
+    GL_ONE,
+    GL_ZERO,
+    GL_ONE_MINUS_SRC_ALPHA,
+    GL_ONE,
+    GL_ONE_MINUS_SRC_ALPHA,
+    GL_DST_ALPHA,
+    GL_ONE,
+    GL_ONE
+};
+
+static const unsigned glBlendOp[] =
+{
+    GL_FUNC_ADD,
+    GL_FUNC_ADD,
+    GL_FUNC_ADD,
+    GL_FUNC_ADD,
+    GL_FUNC_ADD,
+    GL_FUNC_ADD,
+    GL_FUNC_ADD,
+    GL_FUNC_REVERSE_SUBTRACT,
+    GL_FUNC_REVERSE_SUBTRACT
+};
+
+#ifndef GL_ES_VERSION_2_0
+static const unsigned glFillMode[] =
+{
+    GL_FILL,
+    GL_LINE,
+    GL_POINT
+};
+
+static const unsigned glStencilOps[] =
+{
+    GL_KEEP,
+    GL_ZERO,
+    GL_REPLACE,
+    GL_INCR_WRAP,
+    GL_DECR_WRAP
+};
+#endif
+
+static const unsigned glElementTypes[] =
+{
+    GL_INT,
+    GL_FLOAT,
+    GL_FLOAT,
+    GL_FLOAT,
+    GL_FLOAT,
+    GL_UNSIGNED_BYTE,
+    GL_UNSIGNED_BYTE
+};
+
+static const unsigned glElementComponents[] =
+{
+    1,
+    1,
+    2,
+    3,
+    4,
+    4,
+    4
+};
+
+#ifdef GL_ES_VERSION_2_0
+static unsigned glesDepthStencilFormat = GL_DEPTH_COMPONENT16;
+static unsigned glesReadableDepthFormat = GL_DEPTH_COMPONENT;
+#endif
+
+static String extensions;
+
+bool CheckExtension(const String& name)
+{
+    if (extensions.Empty())
+        extensions = (const char*)glGetString(GL_EXTENSIONS);
+    return extensions.Contains(name);
+}
+
+static void GetGLPrimitiveType(unsigned elementCount, PrimitiveType type, unsigned& primitiveCount, GLenum& glPrimitiveType)
+{
+    switch (type)
+    {
+    case TRIANGLE_LIST:
+        primitiveCount = elementCount / 3;
+        glPrimitiveType = GL_TRIANGLES;
+        break;
+
+    case LINE_LIST:
+        primitiveCount = elementCount / 2;
+        glPrimitiveType = GL_LINES;
+        break;
+
+    case POINT_LIST:
+        primitiveCount = elementCount;
+        glPrimitiveType = GL_POINTS;
+        break;
+
+    case TRIANGLE_STRIP:
+        primitiveCount = elementCount - 2;
+        glPrimitiveType = GL_TRIANGLE_STRIP;
+        break;
+
+    case LINE_STRIP:
+        primitiveCount = elementCount - 1;
+        glPrimitiveType = GL_LINE_STRIP;
+        break;
+
+    case TRIANGLE_FAN:
+        primitiveCount = elementCount - 2;
+        glPrimitiveType = GL_TRIANGLE_FAN;
+        break;
+    }
+}
+
+void Graphics::Constructor_OGL()
+{
+    impl_ = new GraphicsImpl_OGL();
+    position_ = IntVector2(SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED);
+    shadowMapFormat_ = GL_DEPTH_COMPONENT16;
+    hiresShadowMapFormat_ = GL_DEPTH_COMPONENT24;
+    shaderPath_ = "Shaders/GLSL/";
+    shaderExtension_ = ".glsl";
+    orientations_ = "LandscapeLeft LandscapeRight";
+#ifndef GL_ES_VERSION_2_0
+    apiName_ = "GL2";
+#else
+    apiName_ = "GLES2";
+#endif
+
+    Graphics::pixelUVOffset = Vector2(0.0f, 0.0f);
+    Graphics::gl3Support = false;
+
+    SetTextureUnitMappings_OGL();
+    ResetCachedState_OGL();
+
+    context_->RequireSDL(SDL_INIT_VIDEO);
+
+    // Register Graphics library object factories
+    RegisterGraphicsLibrary(context_);
+
+#ifdef __EMSCRIPTEN__
+    appContext = context_;
+#endif
+}
+
+void Graphics::Destructor_OGL()
+{
+    Close_OGL();
+
+    delete impl_;
+    impl_ = nullptr;
+
+    context_->ReleaseSDL();
+}
+
+bool Graphics::SetScreenMode_OGL(int width, int height, const ScreenModeParams& params, bool maximize)
+{
+    URHO3D_PROFILE(SetScreenMode_OGL);
+
+    // Ensure that parameters are properly filled
+    ScreenModeParams newParams = params;
+    AdjustScreenMode(width, height, newParams, maximize);
+
+    if (IsInitialized_OGL() && width == width_ && height == height_ && screenParams_ == newParams)
+        return true;
+
+    // If only vsync changes, do not destroy/recreate the context
+    if (IsInitialized_OGL() && width == width_ && height == height_
+        && screenParams_.EqualsExceptVSync(newParams) && screenParams_.vsync_ != newParams.vsync_)
+    {
+        SDL_GL_SetSwapInterval(newParams.vsync_ ? 1 : 0);
+        screenParams_.vsync_ = newParams.vsync_;
+        return true;
+    }
+
+    // Track if the window was repositioned and don't update window position in this case
+    bool reposition = false;
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    // With an external window, only the size can change after initial setup, so do not recreate context
+    if (!externalWindow_ || !impl->context_)
+    {
+        // Close the existing window and OpenGL context, mark GPU objects as lost
+        Release_OGL(false, true);
+
+        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+#ifndef GL_ES_VERSION_2_0
+        SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+
+        if (externalWindow_)
+            SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+        else
+            SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
+
+        SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
+
+        if (!forceGL2_)
+        {
+            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+            SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+        }
+        else
+        {
+            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+            SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
+        }
+#else
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+#endif
+
+        SDL_Rect display_rect;
+        SDL_GetDisplayBounds(newParams.monitor_, &display_rect);
+        reposition = newParams.fullscreen_ || (newParams.borderless_ && width >= display_rect.w && height >= display_rect.h);
+
+        const int x = reposition ? display_rect.x : position_.x_;
+        const int y = reposition ? display_rect.y : position_.y_;
+
+        unsigned flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
+        if (newParams.fullscreen_)
+            flags |= SDL_WINDOW_FULLSCREEN;
+        if (newParams.borderless_)
+            flags |= SDL_WINDOW_BORDERLESS;
+        if (newParams.resizable_)
+            flags |= SDL_WINDOW_RESIZABLE;
+
+#ifndef __EMSCRIPTEN__
+        if (newParams.highDPI_)
+            flags |= SDL_WINDOW_ALLOW_HIGHDPI;
+#endif
+
+        SDL_SetHint(SDL_HINT_ORIENTATIONS, orientations_.CString());
+
+        // Try 24-bit depth first, fallback to 16-bit
+        for (const int depthSize : { 24, 16 })
+        {
+            SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthSize);
+
+            // Try requested multisample level first, fallback to lower levels and no multisample
+            for (int multiSample = newParams.multiSample_; multiSample > 0; multiSample /= 2)
+            {
+                if (multiSample > 1)
+                {
+                    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
+                    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multiSample);
+                }
+                else
+                {
+                    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
+                    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
+                }
+
+                if (!externalWindow_)
+                    window_ = SDL_CreateWindow(windowTitle_.CString(), x, y, width, height, flags);
+                else
+                {
+    #ifndef __EMSCRIPTEN__
+                    if (!window_)
+                        window_ = SDL_CreateWindowFrom(externalWindow_, SDL_WINDOW_OPENGL);
+                    newParams.fullscreen_ = false;
+    #endif
+                }
+
+                if (window_)
+                {
+                    // TODO: We probably want to keep depthSize as well
+                    newParams.multiSample_ = multiSample;
+                    break;
+                }
+            }
+
+            if (window_)
+                break;
+        }
+
+        if (!window_)
+        {
+            URHO3D_LOGERRORF("Could not create window, root cause: '%s'", SDL_GetError());
+            return false;
+        }
+
+        // Reposition the window on the specified monitor
+        if (reposition)
+            SDL_SetWindowPosition(window_, display_rect.x, display_rect.y);
+
+        CreateWindowIcon();
+
+        if (maximize)
+        {
+            Maximize();
+            SDL_GL_GetDrawableSize(window_, &width, &height);
+        }
+
+        // Create/restore context and GPU objects and set initial renderstate
+        Restore_OGL();
+
+        // Specific error message is already logged by Restore_OGL() when context creation or OpenGL extensions check fails
+        if (!impl->context_)
+            return false;
+    }
+
+    // Set vsync
+    SDL_GL_SetSwapInterval(newParams.vsync_ ? 1 : 0);
+
+    // Store the system FBO on iOS/tvOS now
+#if defined(IOS) || defined(TVOS)
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&impl->systemFBO_);
+#endif
+
+    screenParams_ = newParams;
+
+    SDL_GL_GetDrawableSize(window_, &width_, &height_);
+    if (!reposition)
+        SDL_GetWindowPosition(window_, &position_.x_, &position_.y_);
+
+    int logicalWidth, logicalHeight;
+    SDL_GetWindowSize(window_, &logicalWidth, &logicalHeight);
+    screenParams_.highDPI_ = (width_ != logicalWidth) || (height_ != logicalHeight);
+
+    // Reset rendertargets and viewport for the new screen mode
+    ResetRenderTargets_OGL();
+
+    // Clear the initial window contents to black
+    Clear_OGL(CLEAR_COLOR);
+    SDL_GL_SwapWindow(window_);
+
+    CheckFeatureSupport_OGL();
+
+#ifdef URHO3D_LOGGING
+    URHO3D_LOGINFOF("Adapter used %s %s", (const char *) glGetString(GL_VENDOR), (const char *) glGetString(GL_RENDERER));
+#endif
+
+    OnScreenModeChanged();
+    return true;
+}
+
+void Graphics::SetSRGB_OGL(bool enable)
+{
+    enable &= sRGBWriteSupport_;
+
+    if (enable != sRGB_)
+    {
+        sRGB_ = enable;
+        GetImpl_OGL()->fboDirty_ = true;
+    }
+}
+
+void Graphics::SetDither_OGL(bool enable)
+{
+    if (enable)
+        glEnable(GL_DITHER);
+    else
+        glDisable(GL_DITHER);
+}
+
+void Graphics::SetFlushGPU_OGL(bool enable)
+{
+    // Currently unimplemented on OpenGL
+}
+
+void Graphics::SetForceGL2_OGL(bool enable)
+{
+    if (IsInitialized_OGL())
+    {
+        URHO3D_LOGERROR("OpenGL 2 can only be forced before setting the initial screen mode");
+        return;
+    }
+
+    forceGL2_ = enable;
+}
+
+void Graphics::Close_OGL()
+{
+    if (!IsInitialized_OGL())
+        return;
+
+    // Actually close the window
+    Release_OGL(true, true);
+}
+
+bool Graphics::TakeScreenShot_OGL(Image& destImage)
+{
+    URHO3D_PROFILE(TakeScreenShot_OGL);
+
+    if (!IsInitialized_OGL())
+        return false;
+
+    if (IsDeviceLost_OGL())
+    {
+        URHO3D_LOGERROR("Can not take screenshot while device is lost");
+        return false;
+    }
+
+    ResetRenderTargets_OGL();
+
+#ifndef GL_ES_VERSION_2_0
+    destImage.SetSize(width_, height_, 3);
+    glReadPixels(0, 0, width_, height_, GL_RGB, GL_UNSIGNED_BYTE, destImage.GetData());
+#else
+    // Use RGBA format on OpenGL ES, as otherwise (at least on Android) the produced image is all black
+    destImage.SetSize(width_, height_, 4);
+    glReadPixels(0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, destImage.GetData());
+#endif
+
+    // On OpenGL we need to flip the image vertically after reading
+    destImage.FlipVertical();
+
+    return true;
+}
+
+bool Graphics::BeginFrame_OGL()
+{
+    if (!IsInitialized_OGL() || IsDeviceLost_OGL())
+        return false;
+
+    // If using an external window, check it for size changes, and reset screen mode if necessary
+    if (externalWindow_)
+    {
+        int width, height;
+
+        SDL_GL_GetDrawableSize(window_, &width, &height);
+        if (width != width_ || height != height_)
+            SetMode(width, height);
+    }
+
+    // Re-enable depth test and depth func in case a third party program has modified it
+    glEnable(GL_DEPTH_TEST);
+    glDepthFunc(glCmpFunc[depthTestMode_]);
+
+    // Set default rendertarget and depth buffer
+    ResetRenderTargets_OGL();
+
+    // Cleanup textures from previous frame
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+        SetTexture_OGL(i, nullptr);
+
+    // Enable color and depth write
+    SetColorWrite_OGL(true);
+    SetDepthWrite_OGL(true);
+
+    numPrimitives_ = 0;
+    numBatches_ = 0;
+
+    SendEvent(E_BEGINRENDERING);
+
+    return true;
+}
+
+void Graphics::EndFrame_OGL()
+{
+    if (!IsInitialized_OGL())
+        return;
+
+    URHO3D_PROFILE(Present);
+
+    SendEvent(E_ENDRENDERING);
+
+    SDL_GL_SwapWindow(window_);
+
+    // Clean up too large scratch buffers
+    CleanupScratchBuffers();
+}
+
+void Graphics::Clear_OGL(ClearTargetFlags flags, const Color& color, float depth, unsigned stencil)
+{
+    PrepareDraw_OGL();
+
+#ifdef GL_ES_VERSION_2_0
+    flags &= ~CLEAR_STENCIL;
+#endif
+
+    bool oldColorWrite = colorWrite_;
+    bool oldDepthWrite = depthWrite_;
+
+    if (flags & CLEAR_COLOR && !oldColorWrite)
+        SetColorWrite_OGL(true);
+    if (flags & CLEAR_DEPTH && !oldDepthWrite)
+        SetDepthWrite_OGL(true);
+    if (flags & CLEAR_STENCIL && stencilWriteMask_ != M_MAX_UNSIGNED)
+        glStencilMask(M_MAX_UNSIGNED);
+
+    unsigned glFlags = 0;
+    if (flags & CLEAR_COLOR)
+    {
+        glFlags |= GL_COLOR_BUFFER_BIT;
+        glClearColor(color.r_, color.g_, color.b_, color.a_);
+    }
+    if (flags & CLEAR_DEPTH)
+    {
+        glFlags |= GL_DEPTH_BUFFER_BIT;
+        glClearDepth(depth);
+    }
+    if (flags & CLEAR_STENCIL)
+    {
+        glFlags |= GL_STENCIL_BUFFER_BIT;
+        glClearStencil(stencil);
+    }
+
+    // If viewport is less than full screen, set a scissor to limit the clear
+    /// \todo Any user-set scissor test will be lost
+    IntVector2 viewSize = GetRenderTargetDimensions_OGL();
+    if (viewport_.left_ != 0 || viewport_.top_ != 0 || viewport_.right_ != viewSize.x_ || viewport_.bottom_ != viewSize.y_)
+        SetScissorTest_OGL(true, IntRect(0, 0, viewport_.Width(), viewport_.Height()));
+    else
+        SetScissorTest_OGL(false);
+
+    glClear(glFlags);
+
+    SetScissorTest_OGL(false);
+    SetColorWrite_OGL(oldColorWrite);
+    SetDepthWrite_OGL(oldDepthWrite);
+    if (flags & CLEAR_STENCIL && stencilWriteMask_ != M_MAX_UNSIGNED)
+        glStencilMask(stencilWriteMask_);
+}
+
+bool Graphics::ResolveToTexture_OGL(Texture2D* destination, const IntRect& viewport)
+{
+    if (!destination || !destination->GetRenderSurface())
+        return false;
+
+    URHO3D_PROFILE(ResolveToTexture_OGL);
+
+    IntRect vpCopy = viewport;
+    if (vpCopy.right_ <= vpCopy.left_)
+        vpCopy.right_ = vpCopy.left_ + 1;
+    if (vpCopy.bottom_ <= vpCopy.top_)
+        vpCopy.bottom_ = vpCopy.top_ + 1;
+    vpCopy.left_ = Clamp(vpCopy.left_, 0, width_);
+    vpCopy.top_ = Clamp(vpCopy.top_, 0, height_);
+    vpCopy.right_ = Clamp(vpCopy.right_, 0, width_);
+    vpCopy.bottom_ = Clamp(vpCopy.bottom_, 0, height_);
+
+    // Make sure the FBO is not in use
+    ResetRenderTargets_OGL();
+
+    // Use Direct3D convention with the vertical coordinates ie. 0 is top
+    SetTextureForUpdate_OGL(destination);
+    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vpCopy.left_, height_ - vpCopy.bottom_, vpCopy.Width(), vpCopy.Height());
+    SetTexture_OGL(0, nullptr);
+
+    return true;
+}
+
+bool Graphics::ResolveToTexture_OGL(Texture2D* texture)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (!texture)
+        return false;
+    RenderSurface* surface = texture->GetRenderSurface();
+    if (!surface || !surface->GetRenderBuffer())
+        return false;
+
+    URHO3D_PROFILE(ResolveToTexture_OGL);
+
+    texture->SetResolveDirty(false);
+    surface->SetResolveDirty(false);
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    // Use separate FBOs for resolve to not disturb the currently set rendertarget(s)
+    if (!impl->resolveSrcFBO_)
+        impl->resolveSrcFBO_ = CreateFramebuffer_OGL();
+    if (!impl->resolveDestFBO_)
+        impl->resolveDestFBO_ = CreateFramebuffer_OGL();
+
+    if (!gl3Support)
+    {
+        glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, impl->resolveSrcFBO_);
+        glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT,
+            surface->GetRenderBuffer());
+        glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, impl->resolveDestFBO_);
+        glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->GetGPUObjectName(),
+            0);
+        glBlitFramebufferEXT(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
+            GL_COLOR_BUFFER_BIT, GL_NEAREST);
+        glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
+        glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+    }
+    else
+    {
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, impl->resolveSrcFBO_);
+        glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, surface->GetRenderBuffer());
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, impl->resolveDestFBO_);
+        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGPUObjectName(), 0);
+        glBlitFramebuffer(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
+            GL_COLOR_BUFFER_BIT, GL_NEAREST);
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+    }
+
+    // Restore previously bound FBO
+    BindFramebuffer_OGL(impl->boundFBO_);
+    return true;
+#else
+    // Not supported on GLES
+    return false;
+#endif
+}
+
+bool Graphics::ResolveToTexture_OGL(TextureCube* texture)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (!texture)
+        return false;
+
+    URHO3D_PROFILE(ResolveToTexture_OGL);
+
+    texture->SetResolveDirty(false);
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    // Use separate FBOs for resolve to not disturb the currently set rendertarget(s)
+    if (!impl->resolveSrcFBO_)
+        impl->resolveSrcFBO_ = CreateFramebuffer_OGL();
+    if (!impl->resolveDestFBO_)
+        impl->resolveDestFBO_ = CreateFramebuffer_OGL();
+
+    if (!gl3Support)
+    {
+        for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
+        {
+            // Resolve only the surface(s) that were actually rendered to
+            RenderSurface* surface = texture->GetRenderSurface((CubeMapFace)i);
+            if (!surface->IsResolveDirty())
+                continue;
+
+            surface->SetResolveDirty(false);
+            glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, impl->resolveSrcFBO_);
+            glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT,
+                surface->GetRenderBuffer());
+            glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, impl->resolveDestFBO_);
+            glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
+                texture->GetGPUObjectName(), 0);
+            glBlitFramebufferEXT(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
+                GL_COLOR_BUFFER_BIT, GL_NEAREST);
+        }
+
+        glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
+        glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+    }
+    else
+    {
+        for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
+        {
+            RenderSurface* surface = texture->GetRenderSurface((CubeMapFace)i);
+            if (!surface->IsResolveDirty())
+                continue;
+
+            surface->SetResolveDirty(false);
+            glBindFramebuffer(GL_READ_FRAMEBUFFER, impl->resolveSrcFBO_);
+            glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, surface->GetRenderBuffer());
+            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, impl->resolveDestFBO_);
+            glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
+                texture->GetGPUObjectName(), 0);
+            glBlitFramebuffer(0, 0, texture->GetWidth(), texture->GetHeight(), 0, 0, texture->GetWidth(), texture->GetHeight(),
+                GL_COLOR_BUFFER_BIT, GL_NEAREST);
+        }
+
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+    }
+
+    // Restore previously bound FBO
+    BindFramebuffer_OGL(impl->boundFBO_);
+    return true;
+#else
+    // Not supported on GLES
+    return false;
+#endif
+}
+
+void Graphics::Draw_OGL(PrimitiveType type, unsigned vertexStart, unsigned vertexCount)
+{
+    if (!vertexCount)
+        return;
+
+    PrepareDraw_OGL();
+
+    unsigned primitiveCount;
+    GLenum glPrimitiveType;
+
+    GetGLPrimitiveType(vertexCount, type, primitiveCount, glPrimitiveType);
+    glDrawArrays(glPrimitiveType, vertexStart, vertexCount);
+
+    numPrimitives_ += primitiveCount;
+    ++numBatches_;
+}
+
+void Graphics::Draw_OGL(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount)
+{
+    if (!indexCount || !indexBuffer_ || !indexBuffer_->GetGPUObjectName())
+        return;
+
+    PrepareDraw_OGL();
+
+    unsigned indexSize = indexBuffer_->GetIndexSize();
+    unsigned primitiveCount;
+    GLenum glPrimitiveType;
+
+    GetGLPrimitiveType(indexCount, type, primitiveCount, glPrimitiveType);
+    GLenum indexType = indexSize == sizeof(unsigned short) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
+    glDrawElements(glPrimitiveType, indexCount, indexType, reinterpret_cast<const GLvoid*>(indexStart * indexSize));
+
+    numPrimitives_ += primitiveCount;
+    ++numBatches_;
+}
+
+void Graphics::Draw_OGL(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned baseVertexIndex, unsigned minVertex, unsigned vertexCount)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (!gl3Support || !indexCount || !indexBuffer_ || !indexBuffer_->GetGPUObjectName())
+        return;
+
+    PrepareDraw_OGL();
+
+    unsigned indexSize = indexBuffer_->GetIndexSize();
+    unsigned primitiveCount;
+    GLenum glPrimitiveType;
+
+    GetGLPrimitiveType(indexCount, type, primitiveCount, glPrimitiveType);
+    GLenum indexType = indexSize == sizeof(unsigned short) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
+    glDrawElementsBaseVertex(glPrimitiveType, indexCount, indexType, reinterpret_cast<GLvoid*>(indexStart * indexSize), baseVertexIndex);
+
+    numPrimitives_ += primitiveCount;
+    ++numBatches_;
+#endif
+}
+
+void Graphics::DrawInstanced_OGL(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount,
+    unsigned instanceCount)
+{
+#if !defined(GL_ES_VERSION_2_0) || defined(__EMSCRIPTEN__)
+    if (!indexCount || !indexBuffer_ || !indexBuffer_->GetGPUObjectName() || !instancingSupport_)
+        return;
+
+    PrepareDraw_OGL();
+
+    unsigned indexSize = indexBuffer_->GetIndexSize();
+    unsigned primitiveCount;
+    GLenum glPrimitiveType;
+
+    GetGLPrimitiveType(indexCount, type, primitiveCount, glPrimitiveType);
+    GLenum indexType = indexSize == sizeof(unsigned short) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
+#ifdef __EMSCRIPTEN__
+    glDrawElementsInstancedANGLE(glPrimitiveType, indexCount, indexType, reinterpret_cast<const GLvoid*>(indexStart * indexSize),
+        instanceCount);
+#else
+    if (gl3Support)
+    {
+        glDrawElementsInstanced(glPrimitiveType, indexCount, indexType, reinterpret_cast<const GLvoid*>(indexStart * indexSize),
+            instanceCount);
+    }
+    else
+    {
+        glDrawElementsInstancedARB(glPrimitiveType, indexCount, indexType, reinterpret_cast<const GLvoid*>(indexStart * indexSize),
+            instanceCount);
+    }
+#endif
+
+    numPrimitives_ += instanceCount * primitiveCount;
+    ++numBatches_;
+#endif
+}
+
+void Graphics::DrawInstanced_OGL(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned baseVertexIndex, unsigned minVertex,
+        unsigned vertexCount, unsigned instanceCount)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (!gl3Support || !indexCount || !indexBuffer_ || !indexBuffer_->GetGPUObjectName() || !instancingSupport_)
+        return;
+
+    PrepareDraw_OGL();
+
+    unsigned indexSize = indexBuffer_->GetIndexSize();
+    unsigned primitiveCount;
+    GLenum glPrimitiveType;
+
+    GetGLPrimitiveType(indexCount, type, primitiveCount, glPrimitiveType);
+    GLenum indexType = indexSize == sizeof(unsigned short) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
+
+    glDrawElementsInstancedBaseVertex(glPrimitiveType, indexCount, indexType, reinterpret_cast<const GLvoid*>(indexStart * indexSize),
+        instanceCount, baseVertexIndex);
+
+    numPrimitives_ += instanceCount * primitiveCount;
+    ++numBatches_;
+#endif
+}
+
+void Graphics::SetVertexBuffer_OGL(VertexBuffer* buffer)
+{
+    // Note: this is not multi-instance safe
+    static PODVector<VertexBuffer*> vertexBuffers(1);
+    vertexBuffers[0] = buffer;
+    SetVertexBuffers_OGL(vertexBuffers);
+}
+
+bool Graphics::SetVertexBuffers_OGL(const PODVector<VertexBuffer*>& buffers, unsigned instanceOffset)
+{
+    if (buffers.Size() > MAX_VERTEX_STREAMS)
+    {
+        URHO3D_LOGERROR("Too many vertex buffers");
+        return false;
+    }
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (instanceOffset != impl->lastInstanceOffset_)
+    {
+        impl->lastInstanceOffset_ = instanceOffset;
+        impl->vertexBuffersDirty_ = true;
+    }
+
+    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
+    {
+        VertexBuffer* buffer = nullptr;
+        if (i < buffers.Size())
+            buffer = buffers[i];
+        if (buffer != vertexBuffers_[i])
+        {
+            vertexBuffers_[i] = buffer;
+            impl->vertexBuffersDirty_ = true;
+        }
+    }
+
+    return true;
+}
+
+bool Graphics::SetVertexBuffers_OGL(const Vector<SharedPtr<VertexBuffer> >& buffers, unsigned instanceOffset)
+{
+    return SetVertexBuffers_OGL(reinterpret_cast<const PODVector<VertexBuffer*>&>(buffers), instanceOffset);
+}
+
+void Graphics::SetIndexBuffer_OGL(IndexBuffer* buffer)
+{
+    if (indexBuffer_ == buffer)
+        return;
+
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer ? buffer->GetGPUObjectName() : 0);
+    indexBuffer_ = buffer;
+}
+
+void Graphics::SetShaders_OGL(ShaderVariation* vs, ShaderVariation* ps)
+{
+    if (vs == vertexShader_ && ps == pixelShader_)
+        return;
+
+    // Compile the shaders now if not yet compiled. If already attempted, do not retry
+    if (vs && !vs->GetGPUObjectName())
+    {
+        if (vs->GetCompilerOutput().Empty())
+        {
+            URHO3D_PROFILE(CompileVertexShader);
+
+            bool success = vs->Create();
+            if (success)
+                URHO3D_LOGDEBUG("Compiled vertex shader " + vs->GetFullName());
+            else
+            {
+                URHO3D_LOGERROR("Failed to compile vertex shader " + vs->GetFullName() + ":\n" + vs->GetCompilerOutput());
+                vs = nullptr;
+            }
+        }
+        else
+            vs = nullptr;
+    }
+
+    if (ps && !ps->GetGPUObjectName())
+    {
+        if (ps->GetCompilerOutput().Empty())
+        {
+            URHO3D_PROFILE(CompilePixelShader);
+
+            bool success = ps->Create();
+            if (success)
+                URHO3D_LOGDEBUG("Compiled pixel shader " + ps->GetFullName());
+            else
+            {
+                URHO3D_LOGERROR("Failed to compile pixel shader " + ps->GetFullName() + ":\n" + ps->GetCompilerOutput());
+                ps = nullptr;
+            }
+        }
+        else
+            ps = nullptr;
+    }
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (!vs || !ps)
+    {
+        glUseProgram(0);
+        vertexShader_ = nullptr;
+        pixelShader_ = nullptr;
+        impl->shaderProgram_ = nullptr;
+    }
+    else
+    {
+        vertexShader_ = vs;
+        pixelShader_ = ps;
+
+        Pair<ShaderVariation*, ShaderVariation*> combination(vs, ps);
+        ShaderProgramMap_OGL::Iterator i = impl->shaderPrograms_.Find(combination);
+
+        if (i != impl->shaderPrograms_.End())
+        {
+            // Use the existing linked program
+            if (i->second_->GetGPUObjectName())
+            {
+                glUseProgram(i->second_->GetGPUObjectName());
+                impl->shaderProgram_ = i->second_;
+            }
+            else
+            {
+                glUseProgram(0);
+                impl->shaderProgram_ = nullptr;
+            }
+        }
+        else
+        {
+            // Link a new combination
+            URHO3D_PROFILE(LinkShaders);
+
+            SharedPtr<ShaderProgram_OGL> newProgram(new ShaderProgram_OGL(this, vs, ps));
+            if (newProgram->Link())
+            {
+                URHO3D_LOGDEBUG("Linked vertex shader " + vs->GetFullName() + " and pixel shader " + ps->GetFullName());
+                // Note: Link() calls glUseProgram() to set the texture sampler uniforms,
+                // so it is not necessary to call it again
+                impl->shaderProgram_ = newProgram;
+            }
+            else
+            {
+                URHO3D_LOGERROR("Failed to link vertex shader " + vs->GetFullName() + " and pixel shader " + ps->GetFullName() + ":\n" +
+                         newProgram->GetLinkerOutput());
+                glUseProgram(0);
+                impl->shaderProgram_ = nullptr;
+            }
+
+            impl->shaderPrograms_[combination] = newProgram;
+        }
+    }
+
+    // Update the clip plane uniform on GL3, and set constant buffers
+#ifndef GL_ES_VERSION_2_0
+    if (gl3Support && impl->shaderProgram_)
+    {
+        const SharedPtr<ConstantBuffer>* constantBuffers = impl->shaderProgram_->GetConstantBuffers();
+        for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS * 2; ++i)
+        {
+            ConstantBuffer* buffer = constantBuffers[i].Get();
+            if (buffer != impl->constantBuffers_[i])
+            {
+                unsigned object = buffer ? buffer->GetGPUObjectName() : 0;
+                glBindBufferBase(GL_UNIFORM_BUFFER, i, object);
+                // Calling glBindBufferBase also affects the generic buffer binding point
+                impl->boundUBO_ = object;
+                impl->constantBuffers_[i] = buffer;
+                ShaderProgram_OGL::ClearGlobalParameterSource((ShaderParameterGroup)(i % MAX_SHADER_PARAMETER_GROUPS));
+            }
+        }
+
+        SetShaderParameter_OGL(VSP_CLIPPLANE, useClipPlane_ ? clipPlane_ : Vector4(0.0f, 0.0f, 0.0f, 1.0f));
+    }
+#endif
+
+    // Store shader combination if shader dumping in progress
+    if (shaderPrecache_)
+        shaderPrecache_->StoreShaders(vertexShader_, pixelShader_);
+
+    if (impl->shaderProgram_)
+    {
+        impl->usedVertexAttributes_ = impl->shaderProgram_->GetUsedVertexAttributes();
+        impl->vertexAttributes_ = &impl->shaderProgram_->GetVertexAttributes();
+    }
+    else
+    {
+        impl->usedVertexAttributes_ = 0;
+        impl->vertexAttributes_ = nullptr;
+    }
+
+    impl->vertexBuffersDirty_ = true;
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, const float* data, unsigned count)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->shaderProgram_)
+    {
+        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
+        if (info)
+        {
+            if (info->bufferPtr_)
+            {
+                ConstantBuffer* buffer = info->bufferPtr_;
+                if (!buffer->IsDirty())
+                    impl->dirtyConstantBuffers_.Push(buffer);
+                buffer->SetParameter(info->offset_, (unsigned)(count * sizeof(float)), data);
+                return;
+            }
+
+            switch (info->glType_)
+            {
+            case GL_FLOAT:
+                glUniform1fv(info->location_, count, data);
+                break;
+
+            case GL_FLOAT_VEC2:
+                glUniform2fv(info->location_, count / 2, data);
+                break;
+
+            case GL_FLOAT_VEC3:
+                glUniform3fv(info->location_, count / 3, data);
+                break;
+
+            case GL_FLOAT_VEC4:
+                glUniform4fv(info->location_, count / 4, data);
+                break;
+
+            case GL_FLOAT_MAT3:
+                glUniformMatrix3fv(info->location_, count / 9, GL_FALSE, data);
+                break;
+
+            case GL_FLOAT_MAT4:
+                glUniformMatrix4fv(info->location_, count / 16, GL_FALSE, data);
+                break;
+
+            default: break;
+            }
+        }
+    }
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, float value)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->shaderProgram_)
+    {
+        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
+        if (info)
+        {
+            if (info->bufferPtr_)
+            {
+                ConstantBuffer* buffer = info->bufferPtr_;
+                if (!buffer->IsDirty())
+                    impl->dirtyConstantBuffers_.Push(buffer);
+                buffer->SetParameter(info->offset_, sizeof(float), &value);
+                return;
+            }
+
+            glUniform1fv(info->location_, 1, &value);
+        }
+    }
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, int value)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->shaderProgram_)
+    {
+        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
+        if (info)
+        {
+            if (info->bufferPtr_)
+            {
+                ConstantBuffer* buffer = info->bufferPtr_;
+                if (!buffer->IsDirty())
+                    impl->dirtyConstantBuffers_.Push(buffer);
+                buffer->SetParameter(info->offset_, sizeof(int), &value);
+                return;
+            }
+
+            glUniform1i(info->location_, value);
+        }
+    }
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, bool value)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    // \todo Not tested
+    if (impl->shaderProgram_)
+    {
+        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
+        if (info)
+        {
+            if (info->bufferPtr_)
+            {
+                ConstantBuffer* buffer = info->bufferPtr_;
+                if (!buffer->IsDirty())
+                    impl->dirtyConstantBuffers_.Push(buffer);
+                buffer->SetParameter(info->offset_, sizeof(bool), &value);
+                return;
+            }
+
+            glUniform1i(info->location_, (int)value);
+        }
+    }
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, const Color& color)
+{
+    SetShaderParameter_OGL(param, color.Data(), 4);
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, const Vector2& vector)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->shaderProgram_)
+    {
+        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
+        if (info)
+        {
+            if (info->bufferPtr_)
+            {
+                ConstantBuffer* buffer = info->bufferPtr_;
+                if (!buffer->IsDirty())
+                    impl->dirtyConstantBuffers_.Push(buffer);
+                buffer->SetParameter(info->offset_, sizeof(Vector2), &vector);
+                return;
+            }
+
+            // Check the uniform type to avoid mismatch
+            switch (info->glType_)
+            {
+            case GL_FLOAT:
+                glUniform1fv(info->location_, 1, vector.Data());
+                break;
+
+            case GL_FLOAT_VEC2:
+                glUniform2fv(info->location_, 1, vector.Data());
+                break;
+
+            default: break;
+            }
+        }
+    }
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, const Matrix3& matrix)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->shaderProgram_)
+    {
+        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
+        if (info)
+        {
+            if (info->bufferPtr_)
+            {
+                ConstantBuffer* buffer = info->bufferPtr_;
+                if (!buffer->IsDirty())
+                    impl->dirtyConstantBuffers_.Push(buffer);
+                buffer->SetVector3ArrayParameter(info->offset_, 3, &matrix);
+                return;
+            }
+
+            glUniformMatrix3fv(info->location_, 1, GL_FALSE, matrix.Data());
+        }
+    }
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, const Vector3& vector)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->shaderProgram_)
+    {
+        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
+        if (info)
+        {
+            if (info->bufferPtr_)
+            {
+                ConstantBuffer* buffer = info->bufferPtr_;
+                if (!buffer->IsDirty())
+                    impl->dirtyConstantBuffers_.Push(buffer);
+                buffer->SetParameter(info->offset_, sizeof(Vector3), &vector);
+                return;
+            }
+
+            // Check the uniform type to avoid mismatch
+            switch (info->glType_)
+            {
+            case GL_FLOAT:
+                glUniform1fv(info->location_, 1, vector.Data());
+                break;
+
+            case GL_FLOAT_VEC2:
+                glUniform2fv(info->location_, 1, vector.Data());
+                break;
+
+            case GL_FLOAT_VEC3:
+                glUniform3fv(info->location_, 1, vector.Data());
+                break;
+
+            default: break;
+            }
+        }
+    }
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, const Matrix4& matrix)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->shaderProgram_)
+    {
+        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
+        if (info)
+        {
+            if (info->bufferPtr_)
+            {
+                ConstantBuffer* buffer = info->bufferPtr_;
+                if (!buffer->IsDirty())
+                    impl->dirtyConstantBuffers_.Push(buffer);
+                buffer->SetParameter(info->offset_, sizeof(Matrix4), &matrix);
+                return;
+            }
+
+            glUniformMatrix4fv(info->location_, 1, GL_FALSE, matrix.Data());
+        }
+    }
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, const Vector4& vector)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->shaderProgram_)
+    {
+        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
+        if (info)
+        {
+            if (info->bufferPtr_)
+            {
+                ConstantBuffer* buffer = info->bufferPtr_;
+                if (!buffer->IsDirty())
+                    impl->dirtyConstantBuffers_.Push(buffer);
+                buffer->SetParameter(info->offset_, sizeof(Vector4), &vector);
+                return;
+            }
+
+            // Check the uniform type to avoid mismatch
+            switch (info->glType_)
+            {
+            case GL_FLOAT:
+                glUniform1fv(info->location_, 1, vector.Data());
+                break;
+
+            case GL_FLOAT_VEC2:
+                glUniform2fv(info->location_, 1, vector.Data());
+                break;
+
+            case GL_FLOAT_VEC3:
+                glUniform3fv(info->location_, 1, vector.Data());
+                break;
+
+            case GL_FLOAT_VEC4:
+                glUniform4fv(info->location_, 1, vector.Data());
+                break;
+
+            default: break;
+            }
+        }
+    }
+}
+
+void Graphics::SetShaderParameter_OGL(StringHash param, const Matrix3x4& matrix)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->shaderProgram_)
+    {
+        const ShaderParameter* info = impl->shaderProgram_->GetParameter(param);
+        if (info)
+        {
+            // Expand to a full Matrix4
+            static Matrix4 fullMatrix;
+            fullMatrix.m00_ = matrix.m00_;
+            fullMatrix.m01_ = matrix.m01_;
+            fullMatrix.m02_ = matrix.m02_;
+            fullMatrix.m03_ = matrix.m03_;
+            fullMatrix.m10_ = matrix.m10_;
+            fullMatrix.m11_ = matrix.m11_;
+            fullMatrix.m12_ = matrix.m12_;
+            fullMatrix.m13_ = matrix.m13_;
+            fullMatrix.m20_ = matrix.m20_;
+            fullMatrix.m21_ = matrix.m21_;
+            fullMatrix.m22_ = matrix.m22_;
+            fullMatrix.m23_ = matrix.m23_;
+
+            if (info->bufferPtr_)
+            {
+                ConstantBuffer* buffer = info->bufferPtr_;
+                if (!buffer->IsDirty())
+                    impl->dirtyConstantBuffers_.Push(buffer);
+                buffer->SetParameter(info->offset_, sizeof(Matrix4), &fullMatrix);
+                return;
+            }
+
+            glUniformMatrix4fv(info->location_, 1, GL_FALSE, fullMatrix.Data());
+        }
+    }
+}
+
+bool Graphics::NeedParameterUpdate_OGL(ShaderParameterGroup group, const void* source)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+    return impl->shaderProgram_ ? impl->shaderProgram_->NeedParameterUpdate(group, source) : false;
+}
+
+bool Graphics::HasShaderParameter_OGL(StringHash param)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+    return impl->shaderProgram_ && impl->shaderProgram_->HasParameter(param);
+}
+
+bool Graphics::HasTextureUnit_OGL(TextureUnit unit)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+    return impl->shaderProgram_ && impl->shaderProgram_->HasTextureUnit(unit);
+}
+
+void Graphics::ClearParameterSource_OGL(ShaderParameterGroup group)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+    if (impl->shaderProgram_)
+        impl->shaderProgram_->ClearParameterSource(group);
+}
+
+void Graphics::ClearParameterSources_OGL()
+{
+    ShaderProgram_OGL::ClearParameterSources();
+}
+
+void Graphics::ClearTransformSources_OGL()
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+    if (impl->shaderProgram_)
+    {
+        impl->shaderProgram_->ClearParameterSource(SP_CAMERA);
+        impl->shaderProgram_->ClearParameterSource(SP_OBJECT);
+    }
+}
+
+void Graphics::SetTexture_OGL(unsigned index, Texture* texture)
+{
+    if (index >= MAX_TEXTURE_UNITS)
+        return;
+
+    // Check if texture is currently bound as a rendertarget. In that case, use its backup texture, or blank if not defined
+    if (texture)
+    {
+        if (renderTargets_[0] && renderTargets_[0]->GetParentTexture() == texture)
+            texture = texture->GetBackupTexture();
+        else
+        {
+            // Resolve multisampled texture now as necessary
+            if (texture->GetMultiSample() > 1 && texture->GetAutoResolve() && texture->IsResolveDirty())
+            {
+                if (texture->GetType() == Texture2D::GetTypeStatic())
+                    ResolveToTexture_OGL(static_cast<Texture2D*>(texture));
+                if (texture->GetType() == TextureCube::GetTypeStatic())
+                    ResolveToTexture_OGL(static_cast<TextureCube*>(texture));
+            }
+        }
+    }
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (textures_[index] != texture)
+    {
+        if (impl->activeTexture_ != index)
+        {
+            glActiveTexture(GL_TEXTURE0 + index);
+            impl->activeTexture_ = index;
+        }
+
+        if (texture)
+        {
+            unsigned glType = texture->GetTarget();
+            // Unbind old texture type if necessary
+            if (impl->textureTypes_[index] && impl->textureTypes_[index] != glType)
+                glBindTexture(impl->textureTypes_[index], 0);
+            glBindTexture(glType, texture->GetGPUObjectName());
+            impl->textureTypes_[index] = glType;
+
+            if (texture->GetParametersDirty())
+                texture->UpdateParameters();
+            if (texture->GetLevelsDirty())
+                texture->RegenerateLevels();
+        }
+        else if (impl->textureTypes_[index])
+        {
+            glBindTexture(impl->textureTypes_[index], 0);
+            impl->textureTypes_[index] = 0;
+        }
+
+        textures_[index] = texture;
+    }
+    else
+    {
+        if (texture && (texture->GetParametersDirty() || texture->GetLevelsDirty()))
+        {
+            if (impl->activeTexture_ != index)
+            {
+                glActiveTexture(GL_TEXTURE0 + index);
+                impl->activeTexture_ = index;
+            }
+
+            glBindTexture(texture->GetTarget(), texture->GetGPUObjectName());
+            if (texture->GetParametersDirty())
+                texture->UpdateParameters();
+            if (texture->GetLevelsDirty())
+                texture->RegenerateLevels();
+        }
+    }
+}
+
+void Graphics::SetTextureForUpdate_OGL(Texture* texture)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->activeTexture_ != 0)
+    {
+        glActiveTexture(GL_TEXTURE0);
+        impl->activeTexture_ = 0;
+    }
+
+    unsigned glType = texture->GetTarget();
+    // Unbind old texture type if necessary
+    if (impl->textureTypes_[0] && impl->textureTypes_[0] != glType)
+        glBindTexture(impl->textureTypes_[0], 0);
+    glBindTexture(glType, texture->GetGPUObjectName());
+    impl->textureTypes_[0] = glType;
+    textures_[0] = texture;
+}
+
+void Graphics::SetDefaultTextureFilterMode_OGL(TextureFilterMode mode)
+{
+    if (mode != defaultTextureFilterMode_)
+    {
+        defaultTextureFilterMode_ = mode;
+        SetTextureParametersDirty_OGL();
+    }
+}
+
+void Graphics::SetDefaultTextureAnisotropy_OGL(unsigned level)
+{
+    level = Max(level, 1U);
+
+    if (level != defaultTextureAnisotropy_)
+    {
+        defaultTextureAnisotropy_ = level;
+        SetTextureParametersDirty_OGL();
+    }
+}
+
+void Graphics::SetTextureParametersDirty_OGL()
+{
+    MutexLock lock(gpuObjectMutex_);
+
+    for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
+    {
+        auto* texture = dynamic_cast<Texture*>(*i);
+        if (texture)
+            texture->SetParametersDirty();
+    }
+}
+
+void Graphics::ResetRenderTargets_OGL()
+{
+    for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
+        SetRenderTarget_OGL(i, (RenderSurface*)nullptr);
+    SetDepthStencil_OGL((RenderSurface*)nullptr);
+    SetViewport_OGL(IntRect(0, 0, width_, height_));
+}
+
+void Graphics::ResetRenderTarget_OGL(unsigned index)
+{
+    SetRenderTarget_OGL(index, (RenderSurface*)nullptr);
+}
+
+void Graphics::ResetDepthStencil_OGL()
+{
+    SetDepthStencil_OGL((RenderSurface*)nullptr);
+}
+
+void Graphics::SetRenderTarget_OGL(unsigned index, RenderSurface* renderTarget)
+{
+    if (index >= MAX_RENDERTARGETS)
+        return;
+
+    if (renderTarget != renderTargets_[index])
+    {
+        renderTargets_[index] = renderTarget;
+
+        // If the rendertarget is also bound as a texture, replace with backup texture or null
+        if (renderTarget)
+        {
+            Texture* parentTexture = renderTarget->GetParentTexture();
+
+            for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+            {
+                if (textures_[i] == parentTexture)
+                    SetTexture_OGL(i, textures_[i]->GetBackupTexture());
+            }
+
+            // If multisampled, mark the texture & surface needing resolve
+            if (parentTexture->GetMultiSample() > 1 && parentTexture->GetAutoResolve())
+            {
+                parentTexture->SetResolveDirty(true);
+                renderTarget->SetResolveDirty(true);
+            }
+
+            // If mipmapped, mark the levels needing regeneration
+            if (parentTexture->GetLevels() > 1)
+                parentTexture->SetLevelsDirty();
+        }
+
+        GetImpl_OGL()->fboDirty_ = true;
+    }
+}
+
+void Graphics::SetRenderTarget_OGL(unsigned index, Texture2D* texture)
+{
+    RenderSurface* renderTarget = nullptr;
+    if (texture)
+        renderTarget = texture->GetRenderSurface();
+
+    SetRenderTarget_OGL(index, renderTarget);
+}
+
+void Graphics::SetDepthStencil_OGL(RenderSurface* depthStencil)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    // If we are using a rendertarget texture, it is required in OpenGL to also have an own depth-stencil
+    // Create a new depth-stencil texture as necessary to be able to provide similar behaviour as Direct3D9
+    // Only do this for non-multisampled rendertargets; when using multisampled target a similarly multisampled
+    // depth-stencil should also be provided (backbuffer depth isn't compatible)
+    if (renderTargets_[0] && renderTargets_[0]->GetMultiSample() == 1 && !depthStencil)
+    {
+        int width = renderTargets_[0]->GetWidth();
+        int height = renderTargets_[0]->GetHeight();
+
+        // Direct3D9 default depth-stencil can not be used when rendertarget is larger than the window.
+        // Check size similarly
+        if (width <= width_ && height <= height_)
+        {
+            unsigned searchKey = (width << 16u) | height;
+            HashMap<unsigned, SharedPtr<Texture2D> >::Iterator i = impl->depthTextures_.Find(searchKey);
+            if (i != impl->depthTextures_.End())
+                depthStencil = i->second_->GetRenderSurface();
+            else
+            {
+                SharedPtr<Texture2D> newDepthTexture(new Texture2D(context_));
+                newDepthTexture->SetSize(width, height, GetDepthStencilFormat_OGL(), TEXTURE_DEPTHSTENCIL);
+                impl->depthTextures_[searchKey] = newDepthTexture;
+                depthStencil = newDepthTexture->GetRenderSurface();
+            }
+        }
+    }
+
+    if (depthStencil != depthStencil_)
+    {
+        depthStencil_ = depthStencil;
+        impl->fboDirty_ = true;
+    }
+}
+
+void Graphics::SetDepthStencil_OGL(Texture2D* texture)
+{
+    RenderSurface* depthStencil = nullptr;
+    if (texture)
+        depthStencil = texture->GetRenderSurface();
+
+    SetDepthStencil_OGL(depthStencil);
+}
+
+void Graphics::SetViewport_OGL(const IntRect& rect)
+{
+    PrepareDraw_OGL();
+
+    IntVector2 rtSize = GetRenderTargetDimensions_OGL();
+
+    IntRect rectCopy = rect;
+
+    if (rectCopy.right_ <= rectCopy.left_)
+        rectCopy.right_ = rectCopy.left_ + 1;
+    if (rectCopy.bottom_ <= rectCopy.top_)
+        rectCopy.bottom_ = rectCopy.top_ + 1;
+    rectCopy.left_ = Clamp(rectCopy.left_, 0, rtSize.x_);
+    rectCopy.top_ = Clamp(rectCopy.top_, 0, rtSize.y_);
+    rectCopy.right_ = Clamp(rectCopy.right_, 0, rtSize.x_);
+    rectCopy.bottom_ = Clamp(rectCopy.bottom_, 0, rtSize.y_);
+
+    // Use Direct3D convention with the vertical coordinates ie. 0 is top
+    glViewport(rectCopy.left_, rtSize.y_ - rectCopy.bottom_, rectCopy.Width(), rectCopy.Height());
+    viewport_ = rectCopy;
+
+    // Disable scissor test, needs to be re-enabled by the user
+    SetScissorTest_OGL(false);
+}
+
+void Graphics::SetBlendMode_OGL(BlendMode mode, bool alphaToCoverage)
+{
+    if (mode != blendMode_)
+    {
+        if (mode == BLEND_REPLACE)
+            glDisable(GL_BLEND);
+        else
+        {
+            glEnable(GL_BLEND);
+            glBlendFunc(glSrcBlend[mode], glDestBlend[mode]);
+            glBlendEquation(glBlendOp[mode]);
+        }
+
+        blendMode_ = mode;
+    }
+
+    if (alphaToCoverage != alphaToCoverage_)
+    {
+        if (alphaToCoverage)
+            glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+        else
+            glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+
+        alphaToCoverage_ = alphaToCoverage;
+    }
+}
+
+void Graphics::SetColorWrite_OGL(bool enable)
+{
+    if (enable != colorWrite_)
+    {
+        if (enable)
+            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+        else
+            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+        colorWrite_ = enable;
+    }
+}
+
+void Graphics::SetCullMode_OGL(CullMode mode)
+{
+    if (mode != cullMode_)
+    {
+        if (mode == CULL_NONE)
+            glDisable(GL_CULL_FACE);
+        else
+        {
+            // Use Direct3D convention, ie. clockwise vertices define a front face
+            glEnable(GL_CULL_FACE);
+            glCullFace(mode == CULL_CCW ? GL_FRONT : GL_BACK);
+        }
+
+        cullMode_ = mode;
+    }
+}
+
+void Graphics::SetDepthBias_OGL(float constantBias, float slopeScaledBias)
+{
+    if (constantBias != constantDepthBias_ || slopeScaledBias != slopeScaledDepthBias_)
+    {
+#ifndef GL_ES_VERSION_2_0
+        if (slopeScaledBias != 0.0f)
+        {
+            // OpenGL constant bias is unreliable and dependent on depth buffer bitdepth, apply in the projection matrix instead
+            glEnable(GL_POLYGON_OFFSET_FILL);
+            glPolygonOffset(slopeScaledBias, 0.0f);
+        }
+        else
+            glDisable(GL_POLYGON_OFFSET_FILL);
+#endif
+
+        constantDepthBias_ = constantBias;
+        slopeScaledDepthBias_ = slopeScaledBias;
+        // Force update of the projection matrix shader parameter
+        ClearParameterSource_OGL(SP_CAMERA);
+    }
+}
+
+void Graphics::SetDepthTest_OGL(CompareMode mode)
+{
+    if (mode != depthTestMode_)
+    {
+        glDepthFunc(glCmpFunc[mode]);
+        depthTestMode_ = mode;
+    }
+}
+
+void Graphics::SetDepthWrite_OGL(bool enable)
+{
+    if (enable != depthWrite_)
+    {
+        glDepthMask(enable ? GL_TRUE : GL_FALSE);
+        depthWrite_ = enable;
+    }
+}
+
+void Graphics::SetFillMode_OGL(FillMode mode)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (mode != fillMode_)
+    {
+        glPolygonMode(GL_FRONT_AND_BACK, glFillMode[mode]);
+        fillMode_ = mode;
+    }
+#endif
+}
+
+void Graphics::SetLineAntiAlias_OGL(bool enable)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (enable != lineAntiAlias_)
+    {
+        if (enable)
+            glEnable(GL_LINE_SMOOTH);
+        else
+            glDisable(GL_LINE_SMOOTH);
+        lineAntiAlias_ = enable;
+    }
+#endif
+}
+
+void Graphics::SetScissorTest_OGL(bool enable, const Rect& rect, bool borderInclusive)
+{
+    // During some light rendering loops, a full rect is toggled on/off repeatedly.
+    // Disable scissor in that case to reduce state changes
+    if (rect.min_.x_ <= 0.0f && rect.min_.y_ <= 0.0f && rect.max_.x_ >= 1.0f && rect.max_.y_ >= 1.0f)
+        enable = false;
+
+    if (enable)
+    {
+        IntVector2 rtSize(GetRenderTargetDimensions_OGL());
+        IntVector2 viewSize(viewport_.Size());
+        IntVector2 viewPos(viewport_.left_, viewport_.top_);
+        IntRect intRect;
+        int expand = borderInclusive ? 1 : 0;
+
+        intRect.left_ = Clamp((int)((rect.min_.x_ + 1.0f) * 0.5f * viewSize.x_) + viewPos.x_, 0, rtSize.x_ - 1);
+        intRect.top_ = Clamp((int)((-rect.max_.y_ + 1.0f) * 0.5f * viewSize.y_) + viewPos.y_, 0, rtSize.y_ - 1);
+        intRect.right_ = Clamp((int)((rect.max_.x_ + 1.0f) * 0.5f * viewSize.x_) + viewPos.x_ + expand, 0, rtSize.x_);
+        intRect.bottom_ = Clamp((int)((-rect.min_.y_ + 1.0f) * 0.5f * viewSize.y_) + viewPos.y_ + expand, 0, rtSize.y_);
+
+        if (intRect.right_ == intRect.left_)
+            intRect.right_++;
+        if (intRect.bottom_ == intRect.top_)
+            intRect.bottom_++;
+
+        if (intRect.right_ < intRect.left_ || intRect.bottom_ < intRect.top_)
+            enable = false;
+
+        if (enable && scissorRect_ != intRect)
+        {
+            // Use Direct3D convention with the vertical coordinates ie. 0 is top
+            glScissor(intRect.left_, rtSize.y_ - intRect.bottom_, intRect.Width(), intRect.Height());
+            scissorRect_ = intRect;
+        }
+    }
+    else
+        scissorRect_ = IntRect::ZERO;
+
+    if (enable != scissorTest_)
+    {
+        if (enable)
+            glEnable(GL_SCISSOR_TEST);
+        else
+            glDisable(GL_SCISSOR_TEST);
+        scissorTest_ = enable;
+    }
+}
+
+void Graphics::SetScissorTest_OGL(bool enable, const IntRect& rect)
+{
+    IntVector2 rtSize(GetRenderTargetDimensions_OGL());
+    IntVector2 viewPos(viewport_.left_, viewport_.top_);
+
+    if (enable)
+    {
+        IntRect intRect;
+        intRect.left_ = Clamp(rect.left_ + viewPos.x_, 0, rtSize.x_ - 1);
+        intRect.top_ = Clamp(rect.top_ + viewPos.y_, 0, rtSize.y_ - 1);
+        intRect.right_ = Clamp(rect.right_ + viewPos.x_, 0, rtSize.x_);
+        intRect.bottom_ = Clamp(rect.bottom_ + viewPos.y_, 0, rtSize.y_);
+
+        if (intRect.right_ == intRect.left_)
+            intRect.right_++;
+        if (intRect.bottom_ == intRect.top_)
+            intRect.bottom_++;
+
+        if (intRect.right_ < intRect.left_ || intRect.bottom_ < intRect.top_)
+            enable = false;
+
+        if (enable && scissorRect_ != intRect)
+        {
+            // Use Direct3D convention with the vertical coordinates ie. 0 is top
+            glScissor(intRect.left_, rtSize.y_ - intRect.bottom_, intRect.Width(), intRect.Height());
+            scissorRect_ = intRect;
+        }
+    }
+    else
+        scissorRect_ = IntRect::ZERO;
+
+    if (enable != scissorTest_)
+    {
+        if (enable)
+            glEnable(GL_SCISSOR_TEST);
+        else
+            glDisable(GL_SCISSOR_TEST);
+        scissorTest_ = enable;
+    }
+}
+
+void Graphics::SetClipPlane_OGL(bool enable, const Plane& clipPlane, const Matrix3x4& view, const Matrix4& projection)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (enable != useClipPlane_)
+    {
+        if (enable)
+            glEnable(GL_CLIP_PLANE0);
+        else
+            glDisable(GL_CLIP_PLANE0);
+
+        useClipPlane_ = enable;
+    }
+
+    if (enable)
+    {
+        Matrix4 viewProj = projection * view;
+        clipPlane_ = clipPlane.Transformed(viewProj).ToVector4();
+
+        if (!gl3Support)
+        {
+            GLdouble planeData[4];
+            planeData[0] = clipPlane_.x_;
+            planeData[1] = clipPlane_.y_;
+            planeData[2] = clipPlane_.z_;
+            planeData[3] = clipPlane_.w_;
+
+            glClipPlane(GL_CLIP_PLANE0, &planeData[0]);
+        }
+    }
+#endif
+}
+
+void Graphics::SetStencilTest_OGL(bool enable, CompareMode mode, StencilOp pass, StencilOp fail, StencilOp zFail, unsigned stencilRef,
+    unsigned compareMask, unsigned writeMask)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (enable != stencilTest_)
+    {
+        if (enable)
+            glEnable(GL_STENCIL_TEST);
+        else
+            glDisable(GL_STENCIL_TEST);
+        stencilTest_ = enable;
+    }
+
+    if (enable)
+    {
+        if (mode != stencilTestMode_ || stencilRef != stencilRef_ || compareMask != stencilCompareMask_)
+        {
+            glStencilFunc(glCmpFunc[mode], stencilRef, compareMask);
+            stencilTestMode_ = mode;
+            stencilRef_ = stencilRef;
+            stencilCompareMask_ = compareMask;
+        }
+        if (writeMask != stencilWriteMask_)
+        {
+            glStencilMask(writeMask);
+            stencilWriteMask_ = writeMask;
+        }
+        if (pass != stencilPass_ || fail != stencilFail_ || zFail != stencilZFail_)
+        {
+            glStencilOp(glStencilOps[fail], glStencilOps[zFail], glStencilOps[pass]);
+            stencilPass_ = pass;
+            stencilFail_ = fail;
+            stencilZFail_ = zFail;
+        }
+    }
+#endif
+}
+
+bool Graphics::IsInitialized_OGL() const
+{
+    return window_ != nullptr;
+}
+
+bool Graphics::GetDither_OGL() const
+{
+    return glIsEnabled(GL_DITHER) ? true : false;
+}
+
+bool Graphics::IsDeviceLost_OGL() const
+{
+    // On iOS and tvOS treat window minimization as device loss, as it is forbidden to access OpenGL when minimized
+#if defined(IOS) || defined(TVOS)
+    if (window_ && (SDL_GetWindowFlags(window_) & SDL_WINDOW_MINIMIZED) != 0)
+        return true;
+#endif
+
+    return GetImpl_OGL()->context_ == nullptr;
+}
+
+PODVector<int> Graphics::GetMultiSampleLevels_OGL() const
+{
+    PODVector<int> ret;
+    // No multisampling always supported
+    ret.Push(1);
+
+#ifndef GL_ES_VERSION_2_0
+    int maxSamples = 0;
+    glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
+    for (int i = 2; i <= maxSamples && i <= 16; i *= 2)
+        ret.Push(i);
+#endif
+
+    return ret;
+}
+
+unsigned Graphics::GetFormat_OGL(CompressedFormat format) const
+{
+    switch (format)
+    {
+    case CF_RGBA:
+        return GL_RGBA;
+
+    case CF_DXT1:
+        return dxtTextureSupport_ ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : 0;
+
+#if !defined(GL_ES_VERSION_2_0) || defined(__EMSCRIPTEN__)
+    case CF_DXT3:
+        return dxtTextureSupport_ ? GL_COMPRESSED_RGBA_S3TC_DXT3_EXT : 0;
+
+    case CF_DXT5:
+        return dxtTextureSupport_ ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : 0;
+#endif
+#ifdef GL_ES_VERSION_2_0
+    case CF_ETC1:
+        return etcTextureSupport_ ? GL_ETC1_RGB8_OES : 0;
+
+    case CF_ETC2_RGB:
+        return etc2TextureSupport_ ? GL_ETC2_RGB8_OES : 0;
+
+    case CF_ETC2_RGBA:
+        return etc2TextureSupport_ ? GL_ETC2_RGBA8_OES : 0;
+
+    case CF_PVRTC_RGB_2BPP:
+        return pvrtcTextureSupport_ ? COMPRESSED_RGB_PVRTC_2BPPV1_IMG : 0;
+
+    case CF_PVRTC_RGB_4BPP:
+        return pvrtcTextureSupport_ ? COMPRESSED_RGB_PVRTC_4BPPV1_IMG : 0;
+
+    case CF_PVRTC_RGBA_2BPP:
+        return pvrtcTextureSupport_ ? COMPRESSED_RGBA_PVRTC_2BPPV1_IMG : 0;
+
+    case CF_PVRTC_RGBA_4BPP:
+        return pvrtcTextureSupport_ ? COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : 0;
+#endif
+
+    default:
+        return 0;
+    }
+}
+
+unsigned Graphics::GetMaxBones_OGL()
+{
+#ifdef RPI
+    // At the moment all RPI GPUs are low powered and only have limited number of uniforms
+    return 32;
+#else
+    return gl3Support ? 128 : 64;
+#endif
+}
+
+bool Graphics::GetGL3Support_OGL()
+{
+    return gl3Support;
+}
+
+ShaderVariation* Graphics::GetShader_OGL(ShaderType type, const String& name, const String& defines) const
+{
+    return GetShader_OGL(type, name.CString(), defines.CString());
+}
+
+ShaderVariation* Graphics::GetShader_OGL(ShaderType type, const char* name, const char* defines) const
+{
+    if (lastShaderName_ != name || !lastShader_)
+    {
+        auto* cache = GetSubsystem<ResourceCache>();
+
+        String fullShaderName = shaderPath_ + name + shaderExtension_;
+        // Try to reduce repeated error log prints because of missing shaders
+        if (lastShaderName_ == name && !cache->Exists(fullShaderName))
+            return nullptr;
+
+        lastShader_ = cache->GetResource<Shader>(fullShaderName);
+        lastShaderName_ = name;
+    }
+
+    return lastShader_ ? lastShader_->GetVariation(type, defines) : nullptr;
+}
+
+VertexBuffer* Graphics::GetVertexBuffer_OGL(unsigned index) const
+{
+    return index < MAX_VERTEX_STREAMS ? vertexBuffers_[index] : nullptr;
+}
+
+ShaderProgram_OGL* Graphics::GetShaderProgram_OGL() const
+{
+    return GetImpl_OGL()->shaderProgram_;
+}
+
+TextureUnit Graphics::GetTextureUnit_OGL(const String& name)
+{
+    HashMap<String, TextureUnit>::Iterator i = textureUnits_.Find(name);
+    if (i != textureUnits_.End())
+        return i->second_;
+    else
+        return MAX_TEXTURE_UNITS;
+}
+
+const String& Graphics::GetTextureUnitName_OGL(TextureUnit unit)
+{
+    for (HashMap<String, TextureUnit>::Iterator i = textureUnits_.Begin(); i != textureUnits_.End(); ++i)
+    {
+        if (i->second_ == unit)
+            return i->first_;
+    }
+    return String::EMPTY;
+}
+
+Texture* Graphics::GetTexture_OGL(unsigned index) const
+{
+    return index < MAX_TEXTURE_UNITS ? textures_[index] : nullptr;
+}
+
+RenderSurface* Graphics::GetRenderTarget_OGL(unsigned index) const
+{
+    return index < MAX_RENDERTARGETS ? renderTargets_[index] : nullptr;
+}
+
+IntVector2 Graphics::GetRenderTargetDimensions_OGL() const
+{
+    int width, height;
+
+    if (renderTargets_[0])
+    {
+        width = renderTargets_[0]->GetWidth();
+        height = renderTargets_[0]->GetHeight();
+    }
+    else if (depthStencil_)
+    {
+        width = depthStencil_->GetWidth();
+        height = depthStencil_->GetHeight();
+    }
+    else
+    {
+        width = width_;
+        height = height_;
+    }
+
+    return IntVector2(width, height);
+}
+
+void Graphics::OnWindowResized_OGL()
+{
+    if (!window_)
+        return;
+
+    int newWidth, newHeight;
+
+    SDL_GL_GetDrawableSize(window_, &newWidth, &newHeight);
+    if (newWidth == width_ && newHeight == height_)
+        return;
+
+    width_ = newWidth;
+    height_ = newHeight;
+
+    int logicalWidth, logicalHeight;
+    SDL_GetWindowSize(window_, &logicalWidth, &logicalHeight);
+    screenParams_.highDPI_ = (width_ != logicalWidth) || (height_ != logicalHeight);
+
+    // Reset rendertargets and viewport for the new screen size. Also clean up any FBO's, as they may be screen size dependent
+    CleanupFramebuffers_OGL();
+    ResetRenderTargets_OGL();
+
+    URHO3D_LOGDEBUGF("Window was resized to %dx%d", width_, height_);
+
+#ifdef __EMSCRIPTEN__
+    EM_ASM({
+        Module.SetRendererSize($0, $1);
+    }, width_, height_);
+#endif
+
+    using namespace ScreenMode;
+
+    VariantMap& eventData = GetEventDataMap();
+    eventData[P_WIDTH] = width_;
+    eventData[P_HEIGHT] = height_;
+    eventData[P_FULLSCREEN] = screenParams_.fullscreen_;
+    eventData[P_RESIZABLE] = screenParams_.resizable_;
+    eventData[P_BORDERLESS] = screenParams_.borderless_;
+    eventData[P_HIGHDPI] = screenParams_.highDPI_;
+    SendEvent(E_SCREENMODE, eventData);
+}
+
+void Graphics::OnWindowMoved_OGL()
+{
+    if (!window_ || screenParams_.fullscreen_)
+        return;
+
+    int newX, newY;
+
+    SDL_GetWindowPosition(window_, &newX, &newY);
+    if (newX == position_.x_ && newY == position_.y_)
+        return;
+
+    position_.x_ = newX;
+    position_.y_ = newY;
+
+    URHO3D_LOGTRACEF("Window was moved to %d,%d", position_.x_, position_.y_);
+
+    using namespace WindowPos;
+
+    VariantMap& eventData = GetEventDataMap();
+    eventData[P_X] = position_.x_;
+    eventData[P_Y] = position_.y_;
+    SendEvent(E_WINDOWPOS, eventData);
+}
+
+void Graphics::CleanupRenderSurface_OGL(RenderSurface* surface)
+{
+    if (!surface)
+        return;
+
+    // Flush pending FBO changes first if any
+    PrepareDraw_OGL();
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    unsigned currentFBO = impl->boundFBO_;
+
+    // Go through all FBOs and clean up the surface from them
+    for (HashMap<unsigned long long, FrameBufferObject>::Iterator i = impl->frameBuffers_.Begin();
+         i != impl->frameBuffers_.End(); ++i)
+    {
+        for (unsigned j = 0; j < MAX_RENDERTARGETS; ++j)
+        {
+            if (i->second_.colorAttachments_[j] == surface)
+            {
+                if (currentFBO != i->second_.fbo_)
+                {
+                    BindFramebuffer_OGL(i->second_.fbo_);
+                    currentFBO = i->second_.fbo_;
+                }
+                BindColorAttachment_OGL(j, GL_TEXTURE_2D, 0, false);
+                i->second_.colorAttachments_[j] = nullptr;
+                // Mark drawbuffer bits to need recalculation
+                i->second_.drawBuffers_ = M_MAX_UNSIGNED;
+            }
+        }
+        if (i->second_.depthAttachment_ == surface)
+        {
+            if (currentFBO != i->second_.fbo_)
+            {
+                BindFramebuffer_OGL(i->second_.fbo_);
+                currentFBO = i->second_.fbo_;
+            }
+            BindDepthAttachment_OGL(0, false);
+            BindStencilAttachment_OGL(0, false);
+            i->second_.depthAttachment_ = nullptr;
+        }
+    }
+
+    // Restore previously bound FBO now if needed
+    if (currentFBO != impl->boundFBO_)
+        BindFramebuffer_OGL(impl->boundFBO_);
+}
+
+void Graphics::CleanupShaderPrograms_OGL(ShaderVariation* variation)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    for (ShaderProgramMap_OGL::Iterator i = impl->shaderPrograms_.Begin(); i != impl->shaderPrograms_.End();)
+    {
+        if (i->second_->GetVertexShader() == variation || i->second_->GetPixelShader() == variation)
+            i = impl->shaderPrograms_.Erase(i);
+        else
+            ++i;
+    }
+
+    if (vertexShader_ == variation || pixelShader_ == variation)
+        impl->shaderProgram_ = nullptr;
+}
+
+ConstantBuffer* Graphics::GetOrCreateConstantBuffer_OGL(ShaderType type,  unsigned index, unsigned size)
+{
+    // Note: shaderType parameter is not used on OpenGL, instead binding index should already use the PS range
+    // for PS constant buffers
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    unsigned key = (index << 16u) | size;
+    HashMap<unsigned, SharedPtr<ConstantBuffer> >::Iterator i = impl->allConstantBuffers_.Find(key);
+    if (i == impl->allConstantBuffers_.End())
+    {
+        i = impl->allConstantBuffers_.Insert(MakePair(key, SharedPtr<ConstantBuffer>(new ConstantBuffer(context_))));
+        i->second_->SetSize(size);
+    }
+    return i->second_.Get();
+}
+
+void Graphics::Release_OGL(bool clearGPUObjects, bool closeWindow)
+{
+    if (!window_)
+        return;
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    {
+        MutexLock lock(gpuObjectMutex_);
+
+        if (clearGPUObjects)
+        {
+            // Shutting down: release all GPU objects that still exist
+            // Shader programs are also GPU objects; clear them first to avoid list modification during iteration
+            impl->shaderPrograms_.Clear();
+
+            for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
+                (*i)->Release();
+            gpuObjects_.Clear();
+        }
+        else
+        {
+            // We are not shutting down, but recreating the context: mark GPU objects lost
+            for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
+                (*i)->OnDeviceLost();
+
+            // In this case clear shader programs last so that they do not attempt to delete their OpenGL program
+            // from a context that may no longer exist
+            impl->shaderPrograms_.Clear();
+
+            SendEvent(E_DEVICELOST);
+        }
+    }
+
+    CleanupFramebuffers_OGL();
+    impl->depthTextures_.Clear();
+
+    // End fullscreen mode first to counteract transition and getting stuck problems on OS X
+#if defined(__APPLE__) && !defined(IOS) && !defined(TVOS)
+    if (closeWindow && screenParams_.fullscreen_ && !externalWindow_)
+        SDL_SetWindowFullscreen(window_, 0);
+#endif
+
+    if (impl->context_)
+    {
+        // Do not log this message if we are exiting
+        if (!clearGPUObjects)
+            URHO3D_LOGINFO("OpenGL context lost");
+
+        SDL_GL_DeleteContext(impl->context_);
+        impl->context_ = nullptr;
+    }
+
+    if (closeWindow)
+    {
+        SDL_ShowCursor(SDL_TRUE);
+
+        // Do not destroy external window except when shutting down
+        if (!externalWindow_ || clearGPUObjects)
+        {
+            SDL_DestroyWindow(window_);
+            window_ = nullptr;
+        }
+    }
+}
+
+void Graphics::Restore_OGL()
+{
+    if (!window_)
+        return;
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+#ifdef __ANDROID__
+    // On Android the context may be lost behind the scenes as the application is minimized
+    if (impl->context_ && !SDL_GL_GetCurrentContext())
+    {
+        impl->context_ = 0;
+        // Mark GPU objects lost without a current context. In this case they just mark their internal state lost
+        // but do not perform OpenGL commands to delete the GL objects
+        Release_OGL(false, false);
+    }
+#endif
+
+    // Ensure first that the context exists
+    if (!impl->context_)
+    {
+        impl->context_ = SDL_GL_CreateContext(window_);
+
+#ifndef GL_ES_VERSION_2_0
+        // If we're trying to use OpenGL 3, but context creation fails, retry with 2
+        if (!forceGL2_ && !impl->context_)
+        {
+            forceGL2_ = true;
+            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+            SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+            SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
+            impl->context_ = SDL_GL_CreateContext(window_);
+        }
+#endif
+
+#if defined(IOS) || defined(TVOS)
+        glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&impl->systemFBO_);
+#endif
+
+        if (!impl->context_)
+        {
+            URHO3D_LOGERRORF("Could not create OpenGL context, root cause '%s'", SDL_GetError());
+            return;
+        }
+
+        // Clear cached extensions string from the previous context
+        extensions.Clear();
+
+        // Initialize OpenGL extensions library (desktop only)
+#ifndef GL_ES_VERSION_2_0
+        GLenum err = glewInit();
+        if (GLEW_OK != err)
+        {
+            URHO3D_LOGERRORF("Could not initialize OpenGL extensions, root cause: '%s'", glewGetErrorString(err));
+            return;
+        }
+
+        if (!forceGL2_ && GLEW_VERSION_3_2)
+        {
+            gl3Support = true;
+            apiName_ = "GL3";
+
+            // Create and bind a vertex array object that will stay in use throughout
+            unsigned vertexArrayObject;
+            glGenVertexArrays(1, &vertexArrayObject);
+            glBindVertexArray(vertexArrayObject);
+        }
+        else if (GLEW_VERSION_2_0)
+        {
+            if (!GLEW_EXT_framebuffer_object || !GLEW_EXT_packed_depth_stencil)
+            {
+                URHO3D_LOGERROR("EXT_framebuffer_object and EXT_packed_depth_stencil OpenGL extensions are required");
+                return;
+            }
+
+            gl3Support = false;
+            apiName_ = "GL2";
+        }
+        else
+        {
+            URHO3D_LOGERROR("OpenGL 2.0 is required");
+            return;
+        }
+
+        // Enable seamless cubemap if possible
+        // Note: even though we check the extension, this can lead to software fallback on some old GPU's
+        // See https://github.com/urho3d/Urho3D/issues/1380 or
+        // http://distrustsimplicity.net/articles/gl_texture_cube_map_seamless-on-os-x/
+        // In case of trouble or for wanting maximum compatibility, simply remove the glEnable below.
+        if (gl3Support || GLEW_ARB_seamless_cube_map)
+            glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+#endif
+
+        // Set up texture data read/write alignment. It is important that this is done before uploading any texture data
+        glPixelStorei(GL_PACK_ALIGNMENT, 1);
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        ResetCachedState_OGL();
+    }
+
+    {
+        MutexLock lock(gpuObjectMutex_);
+
+        for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
+            (*i)->OnDeviceReset();
+    }
+
+    SendEvent(E_DEVICERESET);
+}
+
+void Graphics::MarkFBODirty_OGL()
+{
+    GetImpl_OGL()->fboDirty_ = true;
+}
+
+void Graphics::SetVBO_OGL(unsigned object)
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (impl->boundVBO_ != object)
+    {
+        if (object)
+            glBindBuffer(GL_ARRAY_BUFFER, object);
+        impl->boundVBO_ = object;
+    }
+}
+
+void Graphics::SetUBO_OGL(unsigned object)
+{
+#ifndef GL_ES_VERSION_2_0
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+    if (impl->boundUBO_ != object)
+    {
+        if (object)
+            glBindBuffer(GL_UNIFORM_BUFFER, object);
+        impl->boundUBO_ = object;
+    }
+#endif
+}
+
+unsigned Graphics::GetAlphaFormat_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    // Alpha format is deprecated on OpenGL 3+
+    if (gl3Support)
+        return GL_R8;
+#endif
+    return GL_ALPHA;
+}
+
+unsigned Graphics::GetLuminanceFormat_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    // Luminance format is deprecated on OpenGL 3+
+    if (gl3Support)
+        return GL_R8;
+#endif
+    return GL_LUMINANCE;
+}
+
+unsigned Graphics::GetLuminanceAlphaFormat_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    // Luminance alpha format is deprecated on OpenGL 3+
+    if (gl3Support)
+        return GL_RG8;
+#endif
+    return GL_LUMINANCE_ALPHA;
+}
+
+unsigned Graphics::GetRGBFormat_OGL()
+{
+    return GL_RGB;
+}
+
+unsigned Graphics::GetRGBAFormat_OGL()
+{
+    return GL_RGBA;
+}
+
+unsigned Graphics::GetRGBA16Format_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    return GL_RGBA16;
+#else
+    return GL_RGBA;
+#endif
+}
+
+unsigned Graphics::GetRGBAFloat16Format_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    return GL_RGBA16F_ARB;
+#else
+    return GL_RGBA;
+#endif
+}
+
+unsigned Graphics::GetRGBAFloat32Format_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    return GL_RGBA32F_ARB;
+#else
+    return GL_RGBA;
+#endif
+}
+
+unsigned Graphics::GetRG16Format_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    return GL_RG16;
+#else
+    return GL_RGBA;
+#endif
+}
+
+unsigned Graphics::GetRGFloat16Format_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    return GL_RG16F;
+#else
+    return GL_RGBA;
+#endif
+}
+
+unsigned Graphics::GetRGFloat32Format_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    return GL_RG32F;
+#else
+    return GL_RGBA;
+#endif
+}
+
+unsigned Graphics::GetFloat16Format_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    return GL_R16F;
+#else
+    return GL_LUMINANCE;
+#endif
+}
+
+unsigned Graphics::GetFloat32Format_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    return GL_R32F;
+#else
+    return GL_LUMINANCE;
+#endif
+}
+
+unsigned Graphics::GetLinearDepthFormat_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    // OpenGL 3 can use different color attachment formats
+    if (gl3Support)
+        return GL_R32F;
+#endif
+    // OpenGL 2 requires color attachments to have the same format, therefore encode deferred depth to RGBA manually
+    // if not using a readable hardware depth texture
+    return GL_RGBA;
+}
+
+unsigned Graphics::GetDepthStencilFormat_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    return GL_DEPTH24_STENCIL8_EXT;
+#else
+    return glesDepthStencilFormat;
+#endif
+}
+
+unsigned Graphics::GetReadableDepthFormat_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    return GL_DEPTH_COMPONENT24;
+#else
+    return glesReadableDepthFormat;
+#endif
+}
+
+unsigned Graphics::GetFormat_OGL(const String& formatName)
+{
+    String nameLower = formatName.ToLower().Trimmed();
+
+    if (nameLower == "a")
+        return GetAlphaFormat_OGL();
+    if (nameLower == "l")
+        return GetLuminanceFormat_OGL();
+    if (nameLower == "la")
+        return GetLuminanceAlphaFormat_OGL();
+    if (nameLower == "rgb")
+        return GetRGBFormat_OGL();
+    if (nameLower == "rgba")
+        return GetRGBAFormat_OGL();
+    if (nameLower == "rgba16")
+        return GetRGBA16Format_OGL();
+    if (nameLower == "rgba16f")
+        return GetRGBAFloat16Format_OGL();
+    if (nameLower == "rgba32f")
+        return GetRGBAFloat32Format_OGL();
+    if (nameLower == "rg16")
+        return GetRG16Format_OGL();
+    if (nameLower == "rg16f")
+        return GetRGFloat16Format_OGL();
+    if (nameLower == "rg32f")
+        return GetRGFloat32Format_OGL();
+    if (nameLower == "r16f")
+        return GetFloat16Format_OGL();
+    if (nameLower == "r32f" || nameLower == "float")
+        return GetFloat32Format_OGL();
+    if (nameLower == "lineardepth" || nameLower == "depth")
+        return GetLinearDepthFormat_OGL();
+    if (nameLower == "d24s8")
+        return GetDepthStencilFormat_OGL();
+    if (nameLower == "readabledepth" || nameLower == "hwdepth")
+        return GetReadableDepthFormat_OGL();
+
+    return GetRGBFormat_OGL();
+}
+
+void Graphics::CheckFeatureSupport_OGL()
+{
+    // Check supported features: light pre-pass, deferred rendering and hardware depth texture
+    lightPrepassSupport_ = false;
+    deferredSupport_ = false;
+
+#ifndef GL_ES_VERSION_2_0
+    int numSupportedRTs = 1;
+    if (gl3Support)
+    {
+        // Work around GLEW failure to check extensions properly from a GL3 context
+        instancingSupport_ = glDrawElementsInstanced != nullptr && glVertexAttribDivisor != nullptr;
+        dxtTextureSupport_ = true;
+        anisotropySupport_ = true;
+        sRGBSupport_ = true;
+        sRGBWriteSupport_ = true;
+
+        glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &numSupportedRTs);
+    }
+    else
+    {
+        instancingSupport_ = GLEW_ARB_instanced_arrays != 0;
+        dxtTextureSupport_ = GLEW_EXT_texture_compression_s3tc != 0;
+        anisotropySupport_ = GLEW_EXT_texture_filter_anisotropic != 0;
+        sRGBSupport_ = GLEW_EXT_texture_sRGB != 0;
+        sRGBWriteSupport_ = GLEW_EXT_framebuffer_sRGB != 0;
+
+        glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &numSupportedRTs);
+    }
+
+    // Must support 2 rendertargets for light pre-pass, and 4 for deferred
+    if (numSupportedRTs >= 2)
+        lightPrepassSupport_ = true;
+    if (numSupportedRTs >= 4)
+        deferredSupport_ = true;
+
+#if defined(__APPLE__) && !defined(IOS) && !defined(TVOS)
+    // On macOS check for an Intel driver and use shadow map RGBA dummy color textures, because mixing
+    // depth-only FBO rendering and backbuffer rendering will bug, resulting in a black screen in full
+    // screen mode, and incomplete shadow maps in windowed mode
+    String renderer((const char*)glGetString(GL_RENDERER));
+    if (renderer.Contains("Intel", false))
+        dummyColorFormat_ = GetRGBAFormat_OGL();
+#endif
+#else
+    // Check for supported compressed texture formats
+#ifdef __EMSCRIPTEN__
+    dxtTextureSupport_ = CheckExtension("WEBGL_compressed_texture_s3tc"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
+    etcTextureSupport_ = CheckExtension("WEBGL_compressed_texture_etc1"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/
+    pvrtcTextureSupport_ = CheckExtension("WEBGL_compressed_texture_pvrtc"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/
+    etc2TextureSupport_ = gl3Support || CheckExtension("WEBGL_compressed_texture_etc"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc/
+    // Instancing is in core in WebGL 2, so the extension may not be present anymore. In WebGL 1, find https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
+    // TODO: In the distant future, this may break if WebGL 3 is introduced, so either improve the GL_VERSION parsing here, or keep track of which WebGL version we attempted to initialize.
+    instancingSupport_ = (strstr((const char *)glGetString(GL_VERSION), "WebGL 2.") != 0) || CheckExtension("ANGLE_instanced_arrays");
+#else
+    dxtTextureSupport_ = CheckExtension("EXT_texture_compression_dxt1");
+    etcTextureSupport_ = CheckExtension("OES_compressed_ETC1_RGB8_texture");
+    etc2TextureSupport_ = gl3Support || CheckExtension("OES_compressed_ETC2_RGBA8_texture");
+    pvrtcTextureSupport_ = CheckExtension("IMG_texture_compression_pvrtc");
+#endif
+
+    // Check for best supported depth renderbuffer format for GLES2
+    if (CheckExtension("GL_OES_depth24"))
+        glesDepthStencilFormat = GL_DEPTH_COMPONENT24_OES;
+    if (CheckExtension("GL_OES_packed_depth_stencil"))
+        glesDepthStencilFormat = GL_DEPTH24_STENCIL8_OES;
+    #ifdef __EMSCRIPTEN__
+    if (!CheckExtension("WEBGL_depth_texture"))
+#else
+    if (!CheckExtension("GL_OES_depth_texture"))
+#endif
+    {
+        shadowMapFormat_ = 0;
+        hiresShadowMapFormat_ = 0;
+        glesReadableDepthFormat = 0;
+    }
+    else
+    {
+#if defined(IOS) || defined(TVOS)
+        // iOS hack: depth renderbuffer seems to fail, so use depth textures for everything if supported
+        glesDepthStencilFormat = GL_DEPTH_COMPONENT;
+#endif
+        shadowMapFormat_ = GL_DEPTH_COMPONENT;
+        hiresShadowMapFormat_ = 0;
+        // WebGL shadow map rendering seems to be extremely slow without an attached dummy color texture
+        #ifdef __EMSCRIPTEN__
+        dummyColorFormat_ = GetRGBAFormat_OGL();
+#endif
+    }
+#endif
+
+    // Consider OpenGL shadows always hardware sampled, if supported at all
+    hardwareShadowSupport_ = shadowMapFormat_ != 0;
+}
+
+void Graphics::PrepareDraw_OGL()
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+#ifndef GL_ES_VERSION_2_0
+    if (gl3Support)
+    {
+        for (PODVector<ConstantBuffer*>::Iterator i = impl->dirtyConstantBuffers_.Begin(); i != impl->dirtyConstantBuffers_.End(); ++i)
+            (*i)->Apply();
+        impl->dirtyConstantBuffers_.Clear();
+    }
+#endif
+
+    if (impl->fboDirty_)
+    {
+        impl->fboDirty_ = false;
+
+        // First check if no framebuffer is needed. In that case simply return to backbuffer rendering
+        bool noFbo = !depthStencil_;
+        if (noFbo)
+        {
+            for (auto& renderTarget : renderTargets_)
+            {
+                if (renderTarget)
+                {
+                    noFbo = false;
+                    break;
+                }
+            }
+        }
+
+        if (noFbo)
+        {
+            if (impl->boundFBO_ != impl->systemFBO_)
+            {
+                BindFramebuffer_OGL(impl->systemFBO_);
+                impl->boundFBO_ = impl->systemFBO_;
+            }
+
+#ifndef GL_ES_VERSION_2_0
+            // Disable/enable sRGB write
+            if (sRGBWriteSupport_)
+            {
+                bool sRGBWrite = sRGB_;
+                if (sRGBWrite != impl->sRGBWrite_)
+                {
+                    if (sRGBWrite)
+                        glEnable(GL_FRAMEBUFFER_SRGB_EXT);
+                    else
+                        glDisable(GL_FRAMEBUFFER_SRGB_EXT);
+                    impl->sRGBWrite_ = sRGBWrite;
+                }
+            }
+#endif
+
+            return;
+        }
+
+        // Search for a new framebuffer based on format & size, or create new
+        IntVector2 rtSize = Graphics::GetRenderTargetDimensions_OGL();
+        unsigned format = 0;
+        if (renderTargets_[0])
+            format = renderTargets_[0]->GetParentTexture()->GetFormat();
+        else if (depthStencil_)
+            format = depthStencil_->GetParentTexture()->GetFormat();
+
+        auto fboKey = (unsigned long long)format << 32u | rtSize.x_ << 16u | rtSize.y_;
+        HashMap<unsigned long long, FrameBufferObject>::Iterator i = impl->frameBuffers_.Find(fboKey);
+        if (i == impl->frameBuffers_.End())
+        {
+            FrameBufferObject newFbo;
+            newFbo.fbo_ = CreateFramebuffer_OGL();
+            i = impl->frameBuffers_.Insert(MakePair(fboKey, newFbo));
+        }
+
+        if (impl->boundFBO_ != i->second_.fbo_)
+        {
+            BindFramebuffer_OGL(i->second_.fbo_);
+            impl->boundFBO_ = i->second_.fbo_;
+        }
+
+#ifndef GL_ES_VERSION_2_0
+        // Setup readbuffers & drawbuffers if needed
+        if (i->second_.readBuffers_ != GL_NONE)
+        {
+            glReadBuffer(GL_NONE);
+            i->second_.readBuffers_ = GL_NONE;
+        }
+
+        // Calculate the bit combination of non-zero color rendertargets to first check if the combination changed
+        unsigned newDrawBuffers = 0;
+        for (unsigned j = 0; j < MAX_RENDERTARGETS; ++j)
+        {
+            if (renderTargets_[j])
+                newDrawBuffers |= 1u << j;
+        }
+
+        if (newDrawBuffers != i->second_.drawBuffers_)
+        {
+            // Check for no color rendertargets (depth rendering only)
+            if (!newDrawBuffers)
+                glDrawBuffer(GL_NONE);
+            else
+            {
+                int drawBufferIds[MAX_RENDERTARGETS];
+                unsigned drawBufferCount = 0;
+
+                for (unsigned j = 0; j < MAX_RENDERTARGETS; ++j)
+                {
+                    if (renderTargets_[j])
+                    {
+                        if (!gl3Support)
+                            drawBufferIds[drawBufferCount++] = GL_COLOR_ATTACHMENT0_EXT + j;
+                        else
+                            drawBufferIds[drawBufferCount++] = GL_COLOR_ATTACHMENT0 + j;
+                    }
+                }
+                glDrawBuffers(drawBufferCount, (const GLenum*)drawBufferIds);
+            }
+
+            i->second_.drawBuffers_ = newDrawBuffers;
+        }
+#endif
+
+        for (unsigned j = 0; j < MAX_RENDERTARGETS; ++j)
+        {
+            if (renderTargets_[j])
+            {
+                Texture* texture = renderTargets_[j]->GetParentTexture();
+
+                // Bind either a renderbuffer or texture, depending on what is available
+                unsigned renderBufferID = renderTargets_[j]->GetRenderBuffer();
+                if (!renderBufferID)
+                {
+                    // If texture's parameters are dirty, update before attaching
+                    if (texture->GetParametersDirty())
+                    {
+                        SetTextureForUpdate_OGL(texture);
+                        texture->UpdateParameters();
+                        SetTexture_OGL(0, nullptr);
+                    }
+
+                    if (i->second_.colorAttachments_[j] != renderTargets_[j])
+                    {
+                        BindColorAttachment_OGL(j, renderTargets_[j]->GetTarget(), texture->GetGPUObjectName(), false);
+                        i->second_.colorAttachments_[j] = renderTargets_[j];
+                    }
+                }
+                else
+                {
+                    if (i->second_.colorAttachments_[j] != renderTargets_[j])
+                    {
+                        BindColorAttachment_OGL(j, renderTargets_[j]->GetTarget(), renderBufferID, true);
+                        i->second_.colorAttachments_[j] = renderTargets_[j];
+                    }
+                }
+            }
+            else
+            {
+                if (i->second_.colorAttachments_[j])
+                {
+                    BindColorAttachment_OGL(j, GL_TEXTURE_2D, 0, false);
+                    i->second_.colorAttachments_[j] = nullptr;
+                }
+            }
+        }
+
+        if (depthStencil_)
+        {
+            // Bind either a renderbuffer or a depth texture, depending on what is available
+            Texture* texture = depthStencil_->GetParentTexture();
+#ifndef GL_ES_VERSION_2_0
+            bool hasStencil = texture->GetFormat() == GL_DEPTH24_STENCIL8_EXT;
+#else
+            bool hasStencil = texture->GetFormat() == GL_DEPTH24_STENCIL8_OES;
+#endif
+            unsigned renderBufferID = depthStencil_->GetRenderBuffer();
+            if (!renderBufferID)
+            {
+                // If texture's parameters are dirty, update before attaching
+                if (texture->GetParametersDirty())
+                {
+                    SetTextureForUpdate_OGL(texture);
+                    texture->UpdateParameters();
+                    SetTexture_OGL(0, nullptr);
+                }
+
+                if (i->second_.depthAttachment_ != depthStencil_)
+                {
+                    BindDepthAttachment_OGL(texture->GetGPUObjectName(), false);
+                    BindStencilAttachment_OGL(hasStencil ? texture->GetGPUObjectName() : 0, false);
+                    i->second_.depthAttachment_ = depthStencil_;
+                }
+            }
+            else
+            {
+                if (i->second_.depthAttachment_ != depthStencil_)
+                {
+                    BindDepthAttachment_OGL(renderBufferID, true);
+                    BindStencilAttachment_OGL(hasStencil ? renderBufferID : 0, true);
+                    i->second_.depthAttachment_ = depthStencil_;
+                }
+            }
+        }
+        else
+        {
+            if (i->second_.depthAttachment_)
+            {
+                BindDepthAttachment_OGL(0, false);
+                BindStencilAttachment_OGL(0, false);
+                i->second_.depthAttachment_ = nullptr;
+            }
+        }
+
+#ifndef GL_ES_VERSION_2_0
+        // Disable/enable sRGB write
+        if (sRGBWriteSupport_)
+        {
+            bool sRGBWrite = renderTargets_[0] ? renderTargets_[0]->GetParentTexture()->GetSRGB() : sRGB_;
+            if (sRGBWrite != impl->sRGBWrite_)
+            {
+                if (sRGBWrite)
+                    glEnable(GL_FRAMEBUFFER_SRGB_EXT);
+                else
+                    glDisable(GL_FRAMEBUFFER_SRGB_EXT);
+                impl->sRGBWrite_ = sRGBWrite;
+            }
+        }
+#endif
+    }
+
+    if (impl->vertexBuffersDirty_)
+    {
+        // Go through currently bound vertex buffers and set the attribute pointers that are available & required
+        // Use reverse order so that elements from higher index buffers will override lower index buffers
+        unsigned assignedLocations = 0;
+
+        for (unsigned i = MAX_VERTEX_STREAMS - 1; i < MAX_VERTEX_STREAMS; --i)
+        {
+            VertexBuffer* buffer = vertexBuffers_[i];
+            // Beware buffers with missing OpenGL objects, as binding a zero buffer object means accessing CPU memory for vertex data,
+            // in which case the pointer will be invalid and cause a crash
+            if (!buffer || !buffer->GetGPUObjectName() || !impl->vertexAttributes_)
+                continue;
+
+            const PODVector<VertexElement>& elements = buffer->GetElements();
+
+            for (PODVector<VertexElement>::ConstIterator j = elements.Begin(); j != elements.End(); ++j)
+            {
+                const VertexElement& element = *j;
+                HashMap<Pair<unsigned char, unsigned char>, unsigned>::ConstIterator k =
+                    impl->vertexAttributes_->Find(MakePair((unsigned char)element.semantic_, element.index_));
+
+                if (k != impl->vertexAttributes_->End())
+                {
+                    unsigned location = k->second_;
+                    unsigned locationMask = 1u << location;
+                    if (assignedLocations & locationMask)
+                        continue; // Already assigned by higher index vertex buffer
+                    assignedLocations |= locationMask;
+
+                    // Enable attribute if not enabled yet
+                    if (!(impl->enabledVertexAttributes_ & locationMask))
+                    {
+                        glEnableVertexAttribArray(location);
+                        impl->enabledVertexAttributes_ |= locationMask;
+                    }
+
+                    // Enable/disable instancing divisor as necessary
+                    unsigned dataStart = element.offset_;
+                    if (element.perInstance_)
+                    {
+                        dataStart += impl->lastInstanceOffset_ * buffer->GetVertexSize();
+                        if (!(impl->instancingVertexAttributes_ & locationMask))
+                        {
+                            SetVertexAttribDivisor_OGL(location, 1);
+                            impl->instancingVertexAttributes_ |= locationMask;
+                        }
+                    }
+                    else
+                    {
+                        if (impl->instancingVertexAttributes_ & locationMask)
+                        {
+                            SetVertexAttribDivisor_OGL(location, 0);
+                            impl->instancingVertexAttributes_ &= ~locationMask;
+                        }
+                    }
+
+                    SetVBO_OGL(buffer->GetGPUObjectName());
+                    glVertexAttribPointer(location, glElementComponents[element.type_], glElementTypes[element.type_],
+                        element.type_ == TYPE_UBYTE4_NORM ? GL_TRUE : GL_FALSE, (unsigned)buffer->GetVertexSize(),
+                        (const void *)(size_t)dataStart);
+                }
+            }
+        }
+
+        // Finally disable unnecessary vertex attributes
+        unsigned disableVertexAttributes = impl->enabledVertexAttributes_ & (~impl->usedVertexAttributes_);
+        unsigned location = 0;
+        while (disableVertexAttributes)
+        {
+            if (disableVertexAttributes & 1u)
+            {
+                glDisableVertexAttribArray(location);
+                impl->enabledVertexAttributes_ &= ~(1u << location);
+            }
+            ++location;
+            disableVertexAttributes >>= 1;
+        }
+
+        impl->vertexBuffersDirty_ = false;
+    }
+}
+
+void Graphics::CleanupFramebuffers_OGL()
+{
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    if (!IsDeviceLost_OGL())
+    {
+        BindFramebuffer_OGL(impl->systemFBO_);
+        impl->boundFBO_ = impl->systemFBO_;
+        impl->fboDirty_ = true;
+
+        for (HashMap<unsigned long long, FrameBufferObject>::Iterator i = impl->frameBuffers_.Begin();
+             i != impl->frameBuffers_.End(); ++i)
+            DeleteFramebuffer_OGL(i->second_.fbo_);
+
+        if (impl->resolveSrcFBO_)
+            DeleteFramebuffer_OGL(impl->resolveSrcFBO_);
+        if (impl->resolveDestFBO_)
+            DeleteFramebuffer_OGL(impl->resolveDestFBO_);
+    }
+    else
+        impl->boundFBO_ = 0;
+
+    impl->resolveSrcFBO_ = 0;
+    impl->resolveDestFBO_ = 0;
+
+    impl->frameBuffers_.Clear();
+}
+
+void Graphics::ResetCachedState_OGL()
+{
+    for (auto& vertexBuffer : vertexBuffers_)
+        vertexBuffer = nullptr;
+
+    GraphicsImpl_OGL* impl = GetImpl_OGL();
+
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+    {
+        textures_[i] = nullptr;
+        impl->textureTypes_[i] = 0;
+    }
+
+    for (auto& renderTarget : renderTargets_)
+        renderTarget = nullptr;
+
+    depthStencil_ = nullptr;
+    viewport_ = IntRect(0, 0, 0, 0);
+    indexBuffer_ = nullptr;
+    vertexShader_ = nullptr;
+    pixelShader_ = nullptr;
+    blendMode_ = BLEND_REPLACE;
+    alphaToCoverage_ = false;
+    colorWrite_ = true;
+    cullMode_ = CULL_NONE;
+    constantDepthBias_ = 0.0f;
+    slopeScaledDepthBias_ = 0.0f;
+    depthTestMode_ = CMP_ALWAYS;
+    depthWrite_ = false;
+    lineAntiAlias_ = false;
+    fillMode_ = FILL_SOLID;
+    scissorTest_ = false;
+    scissorRect_ = IntRect::ZERO;
+    stencilTest_ = false;
+    stencilTestMode_ = CMP_ALWAYS;
+    stencilPass_ = OP_KEEP;
+    stencilFail_ = OP_KEEP;
+    stencilZFail_ = OP_KEEP;
+    stencilRef_ = 0;
+    stencilCompareMask_ = M_MAX_UNSIGNED;
+    stencilWriteMask_ = M_MAX_UNSIGNED;
+    useClipPlane_ = false;
+    impl->shaderProgram_ = nullptr;
+    impl->lastInstanceOffset_ = 0;
+    impl->activeTexture_ = 0;
+    impl->enabledVertexAttributes_ = 0;
+    impl->usedVertexAttributes_ = 0;
+    impl->instancingVertexAttributes_ = 0;
+    impl->boundFBO_ = impl->systemFBO_;
+    impl->boundVBO_ = 0;
+    impl->boundUBO_ = 0;
+    impl->sRGBWrite_ = false;
+
+    // Set initial state to match Direct3D
+    if (impl->context_)
+    {
+        glEnable(GL_DEPTH_TEST);
+        SetCullMode_OGL(CULL_CCW);
+        SetDepthTest_OGL(CMP_LESSEQUAL);
+        SetDepthWrite_OGL(true);
+    }
+
+    for (auto& constantBuffer : impl->constantBuffers_)
+        constantBuffer = nullptr;
+    impl->dirtyConstantBuffers_.Clear();
+}
+
+void Graphics::SetTextureUnitMappings_OGL()
+{
+    textureUnits_["DiffMap"] = TU_DIFFUSE;
+    textureUnits_["DiffCubeMap"] = TU_DIFFUSE;
+    textureUnits_["AlbedoBuffer"] = TU_ALBEDOBUFFER;
+    textureUnits_["NormalMap"] = TU_NORMAL;
+    textureUnits_["NormalBuffer"] = TU_NORMALBUFFER;
+    textureUnits_["SpecMap"] = TU_SPECULAR;
+    textureUnits_["EmissiveMap"] = TU_EMISSIVE;
+    textureUnits_["EnvMap"] = TU_ENVIRONMENT;
+    textureUnits_["EnvCubeMap"] = TU_ENVIRONMENT;
+    textureUnits_["LightRampMap"] = TU_LIGHTRAMP;
+    textureUnits_["LightSpotMap"] = TU_LIGHTSHAPE;
+    textureUnits_["LightCubeMap"] = TU_LIGHTSHAPE;
+    textureUnits_["ShadowMap"] = TU_SHADOWMAP;
+#ifndef GL_ES_VERSION_2_0
+    textureUnits_["VolumeMap"] = TU_VOLUMEMAP;
+    textureUnits_["FaceSelectCubeMap"] = TU_FACESELECT;
+    textureUnits_["IndirectionCubeMap"] = TU_INDIRECTION;
+    textureUnits_["DepthBuffer"] = TU_DEPTHBUFFER;
+    textureUnits_["LightBuffer"] = TU_LIGHTBUFFER;
+    textureUnits_["ZoneCubeMap"] = TU_ZONE;
+    textureUnits_["ZoneVolumeMap"] = TU_ZONE;
+#endif
+}
+
+unsigned Graphics::CreateFramebuffer_OGL()
+{
+    unsigned newFbo = 0;
+#ifndef GL_ES_VERSION_2_0
+    if (!gl3Support)
+        glGenFramebuffersEXT(1, &newFbo);
+    else
+#endif
+        glGenFramebuffers(1, &newFbo);
+    return newFbo;
+}
+
+void Graphics::DeleteFramebuffer_OGL(unsigned fbo)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (!gl3Support)
+        glDeleteFramebuffersEXT(1, &fbo);
+    else
+#endif
+        glDeleteFramebuffers(1, &fbo);
+}
+
+void Graphics::BindFramebuffer_OGL(unsigned fbo)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (!gl3Support)
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
+    else
+#endif
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+}
+
+void Graphics::BindColorAttachment_OGL(unsigned index, unsigned target, unsigned object, bool isRenderBuffer)
+{
+    if (!object)
+        isRenderBuffer = false;
+
+#ifndef GL_ES_VERSION_2_0
+    if (!gl3Support)
+    {
+        if (!isRenderBuffer)
+            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, object, 0);
+        else
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_RENDERBUFFER_EXT, object);
+    }
+    else
+#endif
+    {
+        if (!isRenderBuffer)
+            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, target, object, 0);
+        else
+            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, GL_RENDERBUFFER, object);
+    }
+}
+
+void Graphics::BindDepthAttachment_OGL(unsigned object, bool isRenderBuffer)
+{
+    if (!object)
+        isRenderBuffer = false;
+
+#ifndef GL_ES_VERSION_2_0
+    if (!gl3Support)
+    {
+        if (!isRenderBuffer)
+            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, object, 0);
+        else
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, object);
+    }
+    else
+#endif
+    {
+        if (!isRenderBuffer)
+            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, object, 0);
+        else
+            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, object);
+    }
+}
+
+void Graphics::BindStencilAttachment_OGL(unsigned object, bool isRenderBuffer)
+{
+    if (!object)
+        isRenderBuffer = false;
+
+#ifndef GL_ES_VERSION_2_0
+    if (!gl3Support)
+    {
+        if (!isRenderBuffer)
+            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, object, 0);
+        else
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, object);
+    }
+    else
+#endif
+    {
+        if (!isRenderBuffer)
+            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, object, 0);
+        else
+            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, object);
+    }
+}
+
+bool Graphics::CheckFramebuffer_OGL()
+{
+#ifndef GL_ES_VERSION_2_0
+    if (!gl3Support)
+        return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT;
+    else
+#endif
+        return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
+}
+
+void Graphics::SetVertexAttribDivisor_OGL(unsigned location, unsigned divisor)
+{
+#ifndef GL_ES_VERSION_2_0
+    if (gl3Support && instancingSupport_)
+        glVertexAttribDivisor(location, divisor);
+    else if (instancingSupport_)
+        glVertexAttribDivisorARB(location, divisor);
+#else
+#ifdef __EMSCRIPTEN__
+    if (instancingSupport_)
+        glVertexAttribDivisorANGLE(location, divisor);
+#endif
+#endif
+}
+
+}

Some files were not shown because too many files changed in this diff