Quellcode durchsuchen

Added triple buffering option. On OpenGL it is a no-op.
Removed the pass HashMap from Technique. Now it is just a static array.

Lasse Öörni vor 14 Jahren
Ursprung
Commit
40c8306691

+ 3 - 3
CMakeLists.txt

@@ -25,11 +25,11 @@ add_definitions (-DENABLE_PROFILING)
 # If not on Windows, enable use of OpenGL instead of Direct3D9 (so called "Turso3D" mode.) Setting
 # If not on Windows, enable use of OpenGL instead of Direct3D9 (so called "Turso3D" mode.) Setting
 # this on Windows is not recommended, as graphics card drivers are usually better optimized for
 # this on Windows is not recommended, as graphics card drivers are usually better optimized for
 # Direct3D.
 # Direct3D.
-if (NOT WIN32)
+#if (NOT WIN32)
     set (USE_OPENGL 1)
     set (USE_OPENGL 1)
     add_definitions (-DUSE_OPENGL)
     add_definitions (-DUSE_OPENGL)
-    add_definitions (-DUNIX)
-endif ()
+#    add_definitions (-DUNIX)
+#endif ()
 
 
 # Compiler-specific options
 # Compiler-specific options
 if (MSVC)
 if (MSVC)

+ 1 - 0
Docs/GettingStarted.dox

@@ -101,6 +101,7 @@ Urho3D.exe understands the following command line options:
 -y<res>     Vertical resolution
 -y<res>     Vertical resolution
 -m<level>   Enable hardware multisampling (*)
 -m<level>   Enable hardware multisampling (*)
 -v          Enable vertical sync
 -v          Enable vertical sync
+-t          Enable triple buffering
 -w          Start in windowed mode
 -w          Start in windowed mode
 -headless   Headless mode. No application window will be created
 -headless   Headless mode. No application window will be created
 -forward    Use forward rendering (default)
 -forward    Use forward rendering (default)

+ 3 - 2
Docs/ScriptAPI.dox

@@ -1396,7 +1396,7 @@ Properties:<br>
 - uint memoryUse (readonly)
 - uint memoryUse (readonly)
 - uint useTimer (readonly)
 - uint useTimer (readonly)
 - bool sm3
 - bool sm3
-- Pass@[] pass (readonly)
+- Pass@[] passes (readonly)
 
 
 
 
 Material
 Material
@@ -1957,7 +1957,7 @@ Properties:<br>
 Graphics
 Graphics
 
 
 Methods:<br>
 Methods:<br>
-- bool SetMode(RenderMode, int, int, bool, bool, int)
+- bool SetMode(RenderMode, int, int, bool, bool, bool, int)
 - bool SetMode(int, int)
 - bool SetMode(int, int)
 - bool SetMode(RenderMode)
 - bool SetMode(RenderMode)
 - bool ToggleFullscreen()
 - bool ToggleFullscreen()
@@ -1975,6 +1975,7 @@ Properties:<br>
 - int multiSample (readonly)
 - int multiSample (readonly)
 - bool fullscreen (readonly)
 - bool fullscreen (readonly)
 - bool vsync (readonly)
 - bool vsync (readonly)
+- bool tripleBuffer (readonly)
 - bool initialized (readonly)
 - bool initialized (readonly)
 - bool deviceLost (readonly)
 - bool deviceLost (readonly)
 - uint numPrimitives (readonly)
 - uint numPrimitives (readonly)

+ 6 - 1
Engine/Engine/Engine.cpp

@@ -79,6 +79,7 @@ bool Engine::Initialize(const String& windowTitle, const String& logName, const
     int mixRate = 44100;
     int mixRate = 44100;
     bool fullscreen = true;
     bool fullscreen = true;
     bool vsync = false;
     bool vsync = false;
+    bool tripleBuffer = false;
     bool forceSM2 = false;
     bool forceSM2 = false;
     bool shadows = true;
     bool shadows = true;
     bool sound = true;
     bool sound = true;
@@ -143,6 +144,10 @@ bool Engine::Initialize(const String& windowTitle, const String& logName, const
                     vsync = true;
                     vsync = true;
                     break;
                     break;
                     
                     
+                case 't':
+                    tripleBuffer = true;
+                    break;
+                    
                 case 'f':
                 case 'f':
                     fullscreen = true;
                     fullscreen = true;
                     break;
                     break;
@@ -192,7 +197,7 @@ bool Engine::Initialize(const String& windowTitle, const String& logName, const
         graphics->SetFlushGPU(flush);
         graphics->SetFlushGPU(flush);
         graphics->SetForceSM2(forceSM2);
         graphics->SetForceSM2(forceSM2);
         graphics->SetWindowTitle(windowTitle);
         graphics->SetWindowTitle(windowTitle);
-        if (!graphics->SetMode(mode, width, height, fullscreen, vsync, multiSample))
+        if (!graphics->SetMode(mode, width, height, fullscreen, vsync, tripleBuffer, multiSample))
             return false;
             return false;
         if (!shadows)
         if (!shadows)
             GetSubsystem<Renderer>()->SetDrawShadows(false);
             GetSubsystem<Renderer>()->SetDrawShadows(false);

+ 4 - 5
Engine/Engine/GraphicsAPI.cpp

@@ -301,9 +301,7 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterEnumValue("CullMode", "CULL_CCW", CULL_CCW);
     engine->RegisterEnumValue("CullMode", "CULL_CCW", CULL_CCW);
     engine->RegisterEnumValue("CullMode", "CULL_CW", CULL_CW);
     engine->RegisterEnumValue("CullMode", "CULL_CW", CULL_CW);
     
     
-    engine->RegisterObjectType("Pass", 0, asOBJ_REF);
-    engine->RegisterObjectBehaviour("Pass", asBEHAVE_ADDREF, "void f()", asFUNCTION(FakeAddRef), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectBehaviour("Pass", asBEHAVE_RELEASE, "void f()", asFUNCTION(FakeReleaseRef), asCALL_CDECL_OBJLAST);
+    RegisterRefCounted<Pass>(engine, "Pass");
     engine->RegisterObjectMethod("Pass", "void set_alphaMask(bool)", asMETHOD(Pass, SetAlphaMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_alphaMask(bool)", asMETHOD(Pass, SetAlphaMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "bool get_alphaMask() const", asMETHOD(Pass, GetAlphaMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "bool get_alphaMask() const", asMETHOD(Pass, GetAlphaMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_alphaTest(bool)", asMETHOD(Pass, SetAlphaTest), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_alphaTest(bool)", asMETHOD(Pass, SetAlphaTest), asCALL_THISCALL);
@@ -325,7 +323,7 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Technique", "bool HasPass(PassType) const", asMETHOD(Technique, HasPass), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool HasPass(PassType) const", asMETHOD(Technique, HasPass), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "void set_sm3(bool)", asMETHOD(Technique, SetIsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "void set_sm3(bool)", asMETHOD(Technique, SetIsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool get_sm3() const", asMETHOD(Technique, IsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool get_sm3() const", asMETHOD(Technique, IsSM3), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Technique", "Pass@+ get_pass(PassType)", asMETHOD(Technique, GetPass), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "Pass@+ get_passes(PassType)", asMETHOD(Technique, GetPass), asCALL_THISCALL);
     
     
     RegisterResource<Material>(engine, "Material");
     RegisterResource<Material>(engine, "Material");
     engine->RegisterObjectMethod("Material", "void SetUVTransform(const Vector2&in, float, const Vector2&in)", asMETHODPR(Material, SetUVTransform, (const Vector2&, float, const Vector2&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void SetUVTransform(const Vector2&in, float, const Vector2&in)", asMETHODPR(Material, SetUVTransform, (const Vector2&, float, const Vector2&), void), asCALL_THISCALL);
@@ -696,7 +694,7 @@ static void RegisterGraphics(asIScriptEngine* engine)
     engine->RegisterEnumValue("RenderMode", "RENDER_FORWARD", RENDER_FORWARD);
     engine->RegisterEnumValue("RenderMode", "RENDER_FORWARD", RENDER_FORWARD);
     
     
     RegisterObject<Graphics>(engine, "Graphics");
     RegisterObject<Graphics>(engine, "Graphics");
-    engine->RegisterObjectMethod("Graphics", "bool SetMode(RenderMode, int, int, bool, bool, int)", asMETHODPR(Graphics, SetMode, (RenderMode, int, int, bool, bool, int), bool), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Graphics", "bool SetMode(RenderMode, int, int, bool, bool, bool, int)", asMETHODPR(Graphics, SetMode, (RenderMode, int, int, bool, bool, bool, int), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool SetMode(int, int)", asMETHODPR(Graphics, SetMode, (int, int), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool SetMode(int, int)", asMETHODPR(Graphics, SetMode, (int, int), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool SetMode(RenderMode)", asMETHODPR(Graphics, SetMode, (RenderMode), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool SetMode(RenderMode)", asMETHODPR(Graphics, SetMode, (RenderMode), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool ToggleFullscreen()", asMETHOD(Graphics, ToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool ToggleFullscreen()", asMETHOD(Graphics, ToggleFullscreen), asCALL_THISCALL);
@@ -712,6 +710,7 @@ static void RegisterGraphics(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Graphics", "int get_multiSample() const", asMETHOD(Graphics, GetMultiSample), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "int get_multiSample() const", asMETHOD(Graphics, GetMultiSample), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_fullscreen() const", asMETHOD(Graphics, GetFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_fullscreen() const", asMETHOD(Graphics, GetFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_vsync() const", asMETHOD(Graphics, GetVSync), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_vsync() const", asMETHOD(Graphics, GetVSync), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Graphics", "bool get_tripleBuffer() const", asMETHOD(Graphics, GetTripleBuffer), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_initialized() const", asMETHOD(Graphics, IsInitialized), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_initialized() const", asMETHOD(Graphics, IsInitialized), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_deviceLost() const", asMETHOD(Graphics, IsDeviceLost), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_deviceLost() const", asMETHOD(Graphics, IsDeviceLost), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "uint get_numPrimitives() const", asMETHOD(Graphics, GetNumPrimitives), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "uint get_numPrimitives() const", asMETHOD(Graphics, GetNumPrimitives), asCALL_THISCALL);

+ 11 - 8
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -162,6 +162,7 @@ Graphics::Graphics(Context* context) :
     windowPosY_(0),
     windowPosY_(0),
     fullscreen_(false),
     fullscreen_(false),
     vsync_(false),
     vsync_(false),
+    tripleBuffer_(false),
     flushGPU_(true),
     flushGPU_(true),
     deviceLost_(false),
     deviceLost_(false),
     systemDepthStencil_(false),
     systemDepthStencil_(false),
@@ -238,7 +239,7 @@ void Graphics::SetWindowTitle(const String& windowTitle)
         SetWindowText(impl_->window_, windowTitle_.CString());
         SetWindowText(impl_->window_, windowTitle_.CString());
 }
 }
 
 
-bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen, bool vsync, int multiSample)
+bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen, bool vsync, bool tripleBuffer, int multiSample)
 {
 {
     PROFILE(SetScreenMode);
     PROFILE(SetScreenMode);
     
     
@@ -262,9 +263,10 @@ bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen,
     }
     }
     
     
     multiSample = Clamp(multiSample, 1, (int)D3DMULTISAMPLE_16_SAMPLES);
     multiSample = Clamp(multiSample, 1, (int)D3DMULTISAMPLE_16_SAMPLES);
-
-    if (mode == mode_ && width == width_ && height == height_ && fullscreen == fullscreen_ && vsync == vsync_
-        && multiSample == multiSample_)
+    
+    // If nothing changes, do not reset the device
+    if (mode == mode_ && width == width_ && height == height_ && fullscreen == fullscreen_ && vsync == vsync_ && tripleBuffer ==
+        tripleBuffer_ && multiSample == multiSample_)
         return true;
         return true;
     
     
     if (!impl_->window_)
     if (!impl_->window_)
@@ -340,7 +342,7 @@ bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen,
     
     
     impl_->presentParams_.BackBufferWidth            = width;
     impl_->presentParams_.BackBufferWidth            = width;
     impl_->presentParams_.BackBufferHeight           = height;
     impl_->presentParams_.BackBufferHeight           = height;
-    impl_->presentParams_.BackBufferCount            = 1;
+    impl_->presentParams_.BackBufferCount            = tripleBuffer ? 2 : 1;
     impl_->presentParams_.MultiSampleType            = multiSample > 1 ? (D3DMULTISAMPLE_TYPE)multiSample : D3DMULTISAMPLE_NONE;
     impl_->presentParams_.MultiSampleType            = multiSample > 1 ? (D3DMULTISAMPLE_TYPE)multiSample : D3DMULTISAMPLE_NONE;
     impl_->presentParams_.MultiSampleQuality         = 0;
     impl_->presentParams_.MultiSampleQuality         = 0;
     impl_->presentParams_.SwapEffect                 = D3DSWAPEFFECT_DISCARD;
     impl_->presentParams_.SwapEffect                 = D3DSWAPEFFECT_DISCARD;
@@ -359,6 +361,7 @@ bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen,
     height_ = height;
     height_ = height;
     fullscreen_ = fullscreen;
     fullscreen_ = fullscreen;
     vsync_ = vsync;
     vsync_ = vsync;
+    tripleBuffer_ = tripleBuffer;
     mode_ = mode;
     mode_ = mode;
     
     
     if (!impl_->device_)
     if (!impl_->device_)
@@ -407,17 +410,17 @@ bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen,
 
 
 bool Graphics::SetMode(int width, int height)
 bool Graphics::SetMode(int width, int height)
 {
 {
-    return SetMode(mode_, width, height, fullscreen_, vsync_, multiSample_);
+    return SetMode(mode_, width, height, fullscreen_, vsync_, tripleBuffer_, multiSample_);
 }
 }
 
 
 bool Graphics::SetMode(RenderMode mode)
 bool Graphics::SetMode(RenderMode mode)
 {
 {
-    return SetMode(mode, width_, height_, fullscreen_, vsync_, multiSample_);
+    return SetMode(mode, width_, height_, fullscreen_, vsync_, tripleBuffer_, multiSample_);
 }
 }
 
 
 bool Graphics::ToggleFullscreen()
 bool Graphics::ToggleFullscreen()
 {
 {
-    return SetMode(mode_, width_, height_, !fullscreen_, vsync_, multiSample_);
+    return SetMode(mode_, width_, height_, !fullscreen_, vsync_, tripleBuffer_, multiSample_);
 }
 }
 
 
 void Graphics::Close()
 void Graphics::Close()

+ 6 - 2
Engine/Graphics/Direct3D9/D3D9Graphics.h

@@ -74,7 +74,7 @@ public:
     /// %Set window title.
     /// %Set window title.
     void SetWindowTitle(const String& windowTitle);
     void SetWindowTitle(const String& windowTitle);
     /// %Set screen mode. In deferred rendering modes multisampling means edge filtering instead of MSAA.
     /// %Set screen mode. In deferred rendering modes multisampling means edge filtering instead of MSAA.
-    bool SetMode(RenderMode mode, int width, int height, bool fullscreen, bool vsync, int multiSample);
+    bool SetMode(RenderMode mode, int width, int height, bool fullscreen, bool vsync, bool tripleBuffer, int multiSample);
     /// %Set screen resolution only.
     /// %Set screen resolution only.
     bool SetMode(int width, int height);
     bool SetMode(int width, int height);
     /// %Set rendering mode only.
     /// %Set rendering mode only.
@@ -225,6 +225,8 @@ public:
     bool GetFullscreen() const { return fullscreen_; }
     bool GetFullscreen() const { return fullscreen_; }
     /// Return whether vertical sync is on.
     /// Return whether vertical sync is on.
     bool GetVSync() const { return vsync_; }
     bool GetVSync() const { return vsync_; }
+    /// Return whether triple buffering is enabled.
+    bool GetTripleBuffer() const { return tripleBuffer_; }
     /// Return whether GPU command queue is flushed at the end of each frame.
     /// Return whether GPU command queue is flushed at the end of each frame.
     bool GetFlushGPU() const { return flushGPU_; }
     bool GetFlushGPU() const { return flushGPU_; }
     /// Return whether Direct3D device is lost, and can not yet render. This happens during fullscreen resolution switching.
     /// Return whether Direct3D device is lost, and can not yet render. This happens during fullscreen resolution switching.
@@ -404,6 +406,8 @@ private:
     bool fullscreen_;
     bool fullscreen_;
     /// Vertical sync flag.
     /// Vertical sync flag.
     bool vsync_;
     bool vsync_;
+    /// Triple buffering flag.
+    bool tripleBuffer_;
     /// Flush GPU command queue flag.
     /// Flush GPU command queue flag.
     bool flushGPU_;
     bool flushGPU_;
     /// Direct3D device lost flag.
     /// Direct3D device lost flag.
@@ -426,7 +430,7 @@ private:
     bool hasSM3_;
     bool hasSM3_;
     /// Force Shader Model 2 flag.
     /// Force Shader Model 2 flag.
     bool forceSM2_;
     bool forceSM2_;
-    /// Query issued (used to flush the GPU command queue) flag.
+    /// Query (used to flush the GPU command queue) issued flags.
     bool queryIssued_[NUM_QUERIES];
     bool queryIssued_[NUM_QUERIES];
     /// Current query index
     /// Current query index
     unsigned queryIndex_;
     unsigned queryIndex_;

+ 10 - 10
Engine/Graphics/Material.cpp

@@ -200,6 +200,7 @@ bool Material::Load(Deserializer& source)
     SetMemoryUse(memoryUse);
     SetMemoryUse(memoryUse);
     CheckOcclusion();
     CheckOcclusion();
     CheckSpecular();
     CheckSpecular();
+    
     return true;
     return true;
 }
 }
 
 
@@ -393,18 +394,17 @@ void Material::CheckOcclusion()
     for (unsigned i = 0; i < techniques_.Size(); ++i)
     for (unsigned i = 0; i < techniques_.Size(); ++i)
     {
     {
         Technique* technique = techniques_[i].technique_;
         Technique* technique = techniques_[i].technique_;
-        if (!technique)
-            continue;
-        
-        const Map<PassType, Pass>& passes = technique->GetPasses();
-        if (!passes.Empty())
+        if (technique)
         {
         {
-            // If pass writes depth, enable occlusion
-            const Pass& pass = passes.Begin()->second_;
-            if (pass.GetDepthWrite())
-            {
+            // If pass writes depth, assume it occludes
+            Pass* pass = technique->GetPass(PASS_GBUFFER);
+            if (pass && pass->GetDepthWrite())
                 occlusion_ = true;
                 occlusion_ = true;
-                break;
+            else
+            {
+                pass = technique->GetPass(PASS_BASE);
+                if (pass && pass->GetDepthWrite())
+                    occlusion_ = true;
             }
             }
         }
         }
     }
     }

+ 8 - 6
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -127,6 +127,7 @@ Graphics::Graphics(Context* context_) :
     multiSample_(1),
     multiSample_(1),
     fullscreen_(false),
     fullscreen_(false),
     vsync_(false),
     vsync_(false),
+    tripleBuffer_(false),
     flushGPU_(true),
     flushGPU_(true),
     renderTargetSupport_(false),
     renderTargetSupport_(false),
     deferredSupport_(false),
     deferredSupport_(false),
@@ -173,19 +174,19 @@ void Graphics::SetWindowTitle(const String& windowTitle)
         glfwSetWindowTitle(impl_->window_, windowTitle_.CString());
         glfwSetWindowTitle(impl_->window_, windowTitle_.CString());
 }
 }
 
 
-bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen, bool vsync, int multiSample)
+bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen, bool vsync, bool tripleBuffer, int multiSample)
 {
 {
     PROFILE(SetScreenMode);
     PROFILE(SetScreenMode);
     
     
     multiSample = Clamp(multiSample, 1, 16);
     multiSample = Clamp(multiSample, 1, 16);
     
     
     if (IsInitialized() && mode == mode_ && width == width_ && height == height_ && fullscreen == fullscreen_ &&
     if (IsInitialized() && mode == mode_ && width == width_ && height == height_ && fullscreen == fullscreen_ &&
-        vsync == vsync_ && multiSample == multiSample_)
+        vsync == vsync_ && tripleBuffer == tripleBuffer_ && multiSample == multiSample_)
         return true;
         return true;
     
     
     // If only vsync changes, do not destroy/recreate the context
     // If only vsync changes, do not destroy/recreate the context
     if (IsInitialized() && mode == mode_ && width == width_ && height == height_ && fullscreen == fullscreen_ &&
     if (IsInitialized() && mode == mode_ && width == width_ && height == height_ && fullscreen == fullscreen_ &&
-        multiSample == multiSample_ && vsync != vsync_)
+        tripleBuffer == tripleBuffer_ && multiSample == multiSample_ && vsync != vsync_)
     {
     {
         glfwSwapInterval(vsync ? 1 : 0);
         glfwSwapInterval(vsync ? 1 : 0);
         vsync_ = vsync;
         vsync_ = vsync;
@@ -281,6 +282,7 @@ bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen,
     glfwGetWindowSize(impl_->window_, &width_, &height_);
     glfwGetWindowSize(impl_->window_, &width_, &height_);
     fullscreen_ = fullscreen;
     fullscreen_ = fullscreen;
     vsync_ = vsync;
     vsync_ = vsync;
+    tripleBuffer_ = tripleBuffer;
     mode_ = mode;
     mode_ = mode;
     multiSample_ = multiSample;
     multiSample_ = multiSample;
     
     
@@ -318,17 +320,17 @@ bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen,
 
 
 bool Graphics::SetMode(int width, int height)
 bool Graphics::SetMode(int width, int height)
 {
 {
-    return SetMode(mode_, width, height, fullscreen_, vsync_, multiSample_);
+    return SetMode(mode_, width, height, fullscreen_, vsync_, tripleBuffer_, multiSample_);
 }
 }
 
 
 bool Graphics::SetMode(RenderMode mode)
 bool Graphics::SetMode(RenderMode mode)
 {
 {
-    return SetMode(mode, width_, height_, fullscreen_, vsync_, multiSample_);
+    return SetMode(mode, width_, height_, fullscreen_, vsync_, tripleBuffer_, multiSample_);
 }
 }
 
 
 bool Graphics::ToggleFullscreen()
 bool Graphics::ToggleFullscreen()
 {
 {
-    return SetMode(mode_, width_, height_, !fullscreen_, vsync_, multiSample_);
+    return SetMode(mode_, width_, height_, !fullscreen_, vsync_, tripleBuffer_, multiSample_);
 }
 }
 
 
 void Graphics::Close()
 void Graphics::Close()

+ 9 - 3
Engine/Graphics/OpenGL/OGLGraphics.h

@@ -63,7 +63,7 @@ public:
     /// Set window title.
     /// Set window title.
     void SetWindowTitle(const String& windowTitle);
     void SetWindowTitle(const String& windowTitle);
     /// Set screen mode. In deferred rendering modes multisampling means edge filtering instead of MSAA.
     /// Set screen mode. In deferred rendering modes multisampling means edge filtering instead of MSAA.
-    bool SetMode(RenderMode mode, int width, int height, bool fullscreen, bool vsync, int multiSample);
+    bool SetMode(RenderMode mode, int width, int height, bool fullscreen, bool vsync, bool tripleBuffer, int multiSample);
     /// Set screen resolution only.
     /// Set screen resolution only.
     bool SetMode(int width, int height);
     bool SetMode(int width, int height);
     /// Set rendering mode only.
     /// Set rendering mode only.
@@ -217,6 +217,8 @@ public:
     bool GetFullscreen() const { return fullscreen_; }
     bool GetFullscreen() const { return fullscreen_; }
     /// Return whether vertical sync is on.
     /// Return whether vertical sync is on.
     bool GetVSync() const { return vsync_; }
     bool GetVSync() const { return vsync_; }
+    /// Return whether triple buffering is enabled.
+    bool GetTripleBuffer() const { return tripleBuffer_; }
     /// Return whether GPU command queue is flushed at the end of each frame.
     /// Return whether GPU command queue is flushed at the end of each frame.
     bool GetFlushGPU() const { return flushGPU_; }
     bool GetFlushGPU() const { return flushGPU_; }
     /// Return whether device is lost, and can not yet render. Always false on OpenGL.
     /// Return whether device is lost, and can not yet render. Always false on OpenGL.
@@ -241,8 +243,10 @@ public:
     bool GetDeferredSupport() const { return deferredSupport_; }
     bool GetDeferredSupport() const { return deferredSupport_; }
     /// Return whether Shader Model 3 is supported. Always false on OpenGL.
     /// Return whether Shader Model 3 is supported. Always false on OpenGL.
     bool GetSM3Support() const { return false; }
     bool GetSM3Support() const { return false; }
-    /// Return whether shadow map depth compare is done in hardware. Always false on OpenGL to avoid the HW suffix in shaders.
-    bool GetHardwareShadowSupport() const { return false; }
+    /// Return whether the hardware depth buffer can be sampled. Always true on OpenGL.
+    bool GetHardwareDepthSupport() const { return true; }
+    /// Return whether shadow map depth compare is done in hardware. Always true on OpenGL.
+    bool GetHardwareShadowSupport() const { return true; }
     /// Return whether 24-bit shadow maps are supported. Assume true on OpenGL.
     /// Return whether 24-bit shadow maps are supported. Assume true on OpenGL.
     bool GetHiresShadowSupport() const { return true; }
     bool GetHiresShadowSupport() const { return true; }
     /// Return whether stream offset is supported. Always false on OpenGL.
     /// Return whether stream offset is supported. Always false on OpenGL.
@@ -390,6 +394,8 @@ private:
     bool fullscreen_;
     bool fullscreen_;
     /// Vertical sync flag.
     /// Vertical sync flag.
     bool vsync_;
     bool vsync_;
+    /// Triple buffering flag.
+    bool tripleBuffer_;
     /// Flush GPU command queue flag.
     /// Flush GPU command queue flag.
     bool flushGPU_;
     bool flushGPU_;
     /// Texture render target support flag.
     /// Texture render target support flag.

+ 17 - 13
Engine/Graphics/Renderer.cpp

@@ -174,7 +174,12 @@ static const unsigned short spotLightIndexData[] =
 static const String hwVariations[] =
 static const String hwVariations[] =
 {
 {
     "",
     "",
+    // No specific hardware shadow compare variation on OpenGL, it is always supported
+    #ifdef USE_OPENGL
+    ""
+    #else
     "HW"
     "HW"
+    #endif
 };
 };
 
 
 static const String linearVariations[] =
 static const String linearVariations[] =
@@ -1067,20 +1072,20 @@ void Renderer::LoadMaterialShaders(Technique* technique)
         else
         else
         {
         {
             LoadPassShaders(technique, PASS_BASE);
             LoadPassShaders(technique, PASS_BASE);
-            // If shadow maps are not reused, transparencies can be rendered shadowed
+            // If shadow maps are not reused, forward lighting in deferred mode can render shadows
             LoadPassShaders(technique, PASS_LIGHT, !reuseShadowMaps_);
             LoadPassShaders(technique, PASS_LIGHT, !reuseShadowMaps_);
         }
         }
     }
     }
 }
 }
 
 
-void Renderer::LoadPassShaders(Technique* technique, PassType pass, bool allowShadows)
+void Renderer::LoadPassShaders(Technique* technique, PassType type, bool allowShadows)
 {
 {
-    Map<PassType, Pass>::Iterator i = technique->passes_.Find(pass);
-    if (i == technique->passes_.End())
+    Pass* pass = technique->GetPass(type);
+    if (!pass)
         return;
         return;
     
     
-    String vertexShaderName = i->second_.GetVertexShaderName();
-    String pixelShaderName = i->second_.GetPixelShaderName();
+    String vertexShaderName = pass->GetVertexShaderName();
+    String pixelShaderName = pass->GetPixelShaderName();
     
     
     // Check if the shader name is already a variation in itself
     // Check if the shader name is already a variation in itself
     if (vertexShaderName.Find('_') == String::NPOS)
     if (vertexShaderName.Find('_') == String::NPOS)
@@ -1090,14 +1095,14 @@ void Renderer::LoadPassShaders(Technique* technique, PassType pass, bool allowSh
     
     
     // If INTZ depth is used, do not write depth into a rendertarget in the G-buffer pass
     // If INTZ depth is used, do not write depth into a rendertarget in the G-buffer pass
     // Also check for fallback G-buffer (different layout)
     // Also check for fallback G-buffer (different layout)
-    if (pass == PASS_GBUFFER)
+    if (type == PASS_GBUFFER)
     {
     {
         unsigned depth = graphics_->GetHardwareDepthSupport() ? 0 : 1;
         unsigned depth = graphics_->GetHardwareDepthSupport() ? 0 : 1;
         pixelShaderName += depthVariations[depth];
         pixelShaderName += depthVariations[depth];
     }
     }
 
 
     // If ambient pass is transparent, and shadow maps are reused, do not load shadow variations
     // If ambient pass is transparent, and shadow maps are reused, do not load shadow variations
-    if (reuseShadowMaps_ && pass == PASS_LIGHT)
+    if (reuseShadowMaps_ && type == PASS_LIGHT)
     {
     {
         if (!technique->HasPass(PASS_BASE) || technique->GetPass(PASS_BASE)->GetBlendMode() != BLEND_REPLACE)
         if (!technique->HasPass(PASS_BASE) || technique->GetPass(PASS_BASE)->GetBlendMode() != BLEND_REPLACE)
             allowShadows = false;
             allowShadows = false;
@@ -1105,14 +1110,14 @@ void Renderer::LoadPassShaders(Technique* technique, PassType pass, bool allowSh
     
     
     unsigned hwShadows = graphics_->GetHardwareShadowSupport() ? 1 : 0;
     unsigned hwShadows = graphics_->GetHardwareShadowSupport() ? 1 : 0;
     
     
-    Vector<SharedPtr<ShaderVariation> >& vertexShaders = i->second_.GetVertexShaders();
-    Vector<SharedPtr<ShaderVariation> >& pixelShaders = i->second_.GetPixelShaders();
+    Vector<SharedPtr<ShaderVariation> >& vertexShaders = pass->GetVertexShaders();
+    Vector<SharedPtr<ShaderVariation> >& pixelShaders = pass->GetPixelShaders();
     
     
     // Forget all the old shaders
     // Forget all the old shaders
     vertexShaders.Clear();
     vertexShaders.Clear();
     pixelShaders.Clear();
     pixelShaders.Clear();
     
     
-    if (pass == PASS_LIGHT)
+    if (type == PASS_LIGHT)
     {
     {
         vertexShaders.Resize(MAX_GEOMETRYTYPES * MAX_LIGHT_VS_VARIATIONS);
         vertexShaders.Resize(MAX_GEOMETRYTYPES * MAX_LIGHT_VS_VARIATIONS);
         pixelShaders.Resize(MAX_LIGHT_PS_VARIATIONS);
         pixelShaders.Resize(MAX_LIGHT_PS_VARIATIONS);
@@ -1132,8 +1137,7 @@ void Renderer::LoadPassShaders(Technique* technique, PassType pass, bool allowSh
             if (variation == LPS_SHADOW || variation == LPS_SHADOWSPEC)
             if (variation == LPS_SHADOW || variation == LPS_SHADOWSPEC)
             {
             {
                 if (allowShadows)
                 if (allowShadows)
-                    pixelShaders[j] = GetPixelShader(pixelShaderName + lightPSVariations[j] +
-                        hwVariations[hwShadows]);
+                    pixelShaders[j] = GetPixelShader(pixelShaderName + lightPSVariations[j] + hwVariations[hwShadows]);
                 else
                 else
                     pixelShaders[j].Reset();
                     pixelShaders[j].Reset();
             }
             }

+ 1 - 1
Engine/Graphics/Renderer.h

@@ -309,7 +309,7 @@ private:
     /// Reload shaders for a material technique.
     /// Reload shaders for a material technique.
     void LoadMaterialShaders(Technique* technique);
     void LoadMaterialShaders(Technique* technique);
     /// Reload shaders for a material pass.
     /// Reload shaders for a material pass.
-    void LoadPassShaders(Technique* technique, PassType pass, bool allowShadows = true);
+    void LoadPassShaders(Technique* technique, PassType type, bool allowShadows = true);
     /// Release shaders used in materials.
     /// Release shaders used in materials.
     void ReleaseMaterialShaders();
     void ReleaseMaterialShaders();
     /// Reload textures.
     /// Reload textures.

+ 23 - 25
Engine/Graphics/Technique.cpp

@@ -65,10 +65,6 @@ static const String CompareModeNames[] =
     ""
     ""
 };
 };
 
 
-Pass::Pass()
-{
-}
-
 Pass::Pass(PassType type) :
 Pass::Pass(PassType type) :
     type_(type),
     type_(type),
     alphaMask_(false),
     alphaMask_(false),
@@ -172,37 +168,37 @@ bool Technique::Load(Deserializer& source)
         
         
         if (type != MAX_PASSES)
         if (type != MAX_PASSES)
         {
         {
-            Pass& newPass = *CreatePass(type);
+            Pass* newPass = CreatePass(type);
             
             
             if (passElem.HasAttribute("vs"))
             if (passElem.HasAttribute("vs"))
-                newPass.SetVertexShader(passElem.GetString("vs"));
+                newPass->SetVertexShader(passElem.GetString("vs"));
             
             
             if (passElem.HasAttribute("ps"))
             if (passElem.HasAttribute("ps"))
-                newPass.SetPixelShader(passElem.GetString("ps"));
+                newPass->SetPixelShader(passElem.GetString("ps"));
             
             
             if (passElem.HasAttribute("alphamask"))
             if (passElem.HasAttribute("alphamask"))
-                newPass.SetAlphaMask(passElem.GetBool("alphamask"));
+                newPass->SetAlphaMask(passElem.GetBool("alphamask"));
             
             
             if (passElem.HasAttribute("alphatest"))
             if (passElem.HasAttribute("alphatest"))
-                newPass.SetAlphaTest(passElem.GetBool("alphatest"));
+                newPass->SetAlphaTest(passElem.GetBool("alphatest"));
             
             
             if (passElem.HasAttribute("blend"))
             if (passElem.HasAttribute("blend"))
             {
             {
                 String blend = passElem.GetStringLower("blend");
                 String blend = passElem.GetStringLower("blend");
-                newPass.SetBlendMode((BlendMode)GetStringListIndex(blend, blendModeNames, BLEND_REPLACE));
+                newPass->SetBlendMode((BlendMode)GetStringListIndex(blend, blendModeNames, BLEND_REPLACE));
             }
             }
             
             
             if (passElem.HasAttribute("depthtest"))
             if (passElem.HasAttribute("depthtest"))
             {
             {
                 String depthTest = passElem.GetStringLower("depthtest");
                 String depthTest = passElem.GetStringLower("depthtest");
                 if (depthTest == "false")
                 if (depthTest == "false")
-                    newPass.SetDepthTestMode(CMP_ALWAYS);
+                    newPass->SetDepthTestMode(CMP_ALWAYS);
                 else
                 else
-                    newPass.SetDepthTestMode((CompareMode)GetStringListIndex(depthTest, CompareModeNames, CMP_LESSEQUAL));
+                    newPass->SetDepthTestMode((CompareMode)GetStringListIndex(depthTest, CompareModeNames, CMP_LESS));
             }
             }
             
             
             if (passElem.HasAttribute("depthwrite"))
             if (passElem.HasAttribute("depthwrite"))
-                newPass.SetDepthWrite(passElem.GetBool("depthwrite"));
+                newPass->SetDepthWrite(passElem.GetBool("depthwrite"));
         }
         }
         
         
         passElem = passElem.GetNext("pass");
         passElem = passElem.GetNext("pass");
@@ -211,8 +207,11 @@ bool Technique::Load(Deserializer& source)
     // Calculate memory use
     // Calculate memory use
     unsigned memoryUse = 0;
     unsigned memoryUse = 0;
     memoryUse += sizeof(Technique);
     memoryUse += sizeof(Technique);
-    for (Map<PassType, Pass>::ConstIterator j = passes_.Begin(); j != passes_.End(); ++j)
-        memoryUse += sizeof(Pass);
+    for (unsigned i = 0; i < MAX_PASSES; ++i)
+    {
+        if (passes_[i])
+            memoryUse += sizeof(Pass);
+    }
     
     
     SetMemoryUse(memoryUse);
     SetMemoryUse(memoryUse);
     return true;
     return true;
@@ -225,25 +224,24 @@ void Technique::SetIsSM3(bool enable)
 
 
 void Technique::ReleaseShaders()
 void Technique::ReleaseShaders()
 {
 {
-    for (Map<PassType, Pass>::Iterator i = passes_.Begin(); i != passes_.End(); ++i)
-        i->second_.ReleaseShaders();
+    for (unsigned i = 0; i < MAX_PASSES; ++i)
+    {
+        if (passes_[i])
+            passes_[i]->ReleaseShaders();
+    }
 }
 }
 
 
 Pass* Technique::CreatePass(PassType pass)
 Pass* Technique::CreatePass(PassType pass)
 {
 {
-    Pass* existing = GetPass(pass);
-    if (existing)
-        return existing;
-    
-    Pass newPass(pass);
-    passes_[pass] = newPass;
+    if (!passes_[pass])
+        passes_[pass] = new Pass(pass);
     
     
-    return GetPass(pass);
+    return passes_[pass];
 }
 }
 
 
 void Technique::RemovePass(PassType pass)
 void Technique::RemovePass(PassType pass)
 {
 {
-    passes_.Erase(pass);
+    passes_[pass].Reset();
 }
 }
 
 
 void Technique::MarkShadersLoaded(unsigned frameNumber)
 void Technique::MarkShadersLoaded(unsigned frameNumber)

+ 5 - 16
Engine/Graphics/Technique.h

@@ -29,12 +29,10 @@
 class ShaderVariation;
 class ShaderVariation;
 
 
 /// %Material rendering pass, which defines shaders and render state.
 /// %Material rendering pass, which defines shaders and render state.
-class Pass
+class Pass : public RefCounted
 {
 {
 public:
 public:
-    /// Construct with defaults.
-    Pass();
-    /// Construct with pass type.
+    /// Construct.
     Pass(PassType type);
     Pass(PassType type);
     /// Destruct.
     /// Destruct.
     ~Pass();
     ~Pass();
@@ -131,22 +129,13 @@ public:
     void MarkShadersLoaded(unsigned frameNumber);
     void MarkShadersLoaded(unsigned frameNumber);
     
     
     /// Return whether has a pass.
     /// Return whether has a pass.
-    bool HasPass(PassType pass) const { return passes_.Find(pass) != passes_.End(); }
+    bool HasPass(PassType pass) const { return passes_[pass] != 0; }
     
     
     /// Return a pass.
     /// Return a pass.
-    Pass* GetPass(PassType pass)
-    {
-        Map<PassType, Pass>::Iterator i = passes_.Find(pass);
-        if (i != passes_.End())
-            return &(i->second_);
-        else
-            return 0;
-    }
+    Pass* GetPass(PassType pass) const { return passes_[pass]; }
     
     
     /// Return whether requires Shader Model 3.
     /// Return whether requires Shader Model 3.
     bool IsSM3() const { return isSM3_; }
     bool IsSM3() const { return isSM3_; }
-    /// Return all passes.
-    const Map<PassType, Pass>& GetPasses() const { return passes_; }
     /// Return last shaders loaded frame number.
     /// Return last shaders loaded frame number.
     unsigned GetShadersLoadedFrameNumber() const { return shadersLoadedFrameNumber_; }
     unsigned GetShadersLoadedFrameNumber() const { return shadersLoadedFrameNumber_; }
     
     
@@ -159,5 +148,5 @@ private:
     /// Last shaders loaded frame number.
     /// Last shaders loaded frame number.
     unsigned shadersLoadedFrameNumber_;
     unsigned shadersLoadedFrameNumber_;
     /// Passes.
     /// Passes.
-    Map<PassType, Pass> passes_;
+    SharedPtr<Pass> passes_[MAX_PASSES];
 };
 };

+ 3 - 0
Engine/Math/Color.h

@@ -158,6 +158,9 @@ public:
     static const Color BLACK;
     static const Color BLACK;
 };
 };
 
 
+/// Multiply Color with a scalar.
+inline Color operator * (float lhs, const Color& rhs) { return rhs * lhs; }
+
 /// Color-time pair for color interpolation.
 /// Color-time pair for color interpolation.
 class ColorFade
 class ColorFade
 {
 {