Przeglądaj źródła

Added elapsed time accumulation to Scene.
Added elapsed time shader uniform.

Lasse Öörni 13 lat temu
rodzic
commit
2ae05de8ca

+ 2 - 1
Bin/CoreData/Shaders/GLSL/Uniforms.frag

@@ -3,6 +3,7 @@
 #endif
 
 uniform vec3 cAmbientColor;
+uniform float cElapsedTimePS;
 uniform vec2 cFogParams;
 uniform vec3 cFogColor;
 uniform vec2 cGBufferInvSize;
@@ -18,4 +19,4 @@ uniform vec4 cShadowDepthFade;
 uniform vec2 cShadowIntensity;
 uniform vec2 cShadowMapInvSize;
 uniform vec4 cShadowSplits;
-uniform mat4 cLightMatricesPS[4];
+uniform mat4 cLightMatricesPS[4];

+ 5 - 4
Bin/CoreData/Shaders/GLSL/Uniforms.vert

@@ -4,6 +4,7 @@ uniform vec3 cCameraPos;
 uniform mat3 cCameraRot;
 uniform vec4 cDepthMode;
 uniform vec3 cFrustumSize;
+uniform float cElapsedTime;
 uniform vec4 cGBufferOffsets;
 uniform vec3 cLightDir;
 uniform vec4 cLightPos;
@@ -13,11 +14,11 @@ uniform vec4 cUOffset;
 uniform vec4 cVOffset;
 uniform vec3 cViewRightVector;
 uniform vec3 cViewUpVector;
-uniform mat4 cZone;
+uniform mat4 cZone;
 #ifndef GL_ES
-    uniform mat4 cLightMatrices[4];
-#else
-    uniform mat4 cLightMatrices[2];
+    uniform mat4 cLightMatrices[4];
+#else
+    uniform mat4 cLightMatrices[2];
 #endif
 uniform vec4 cSkinMatrices[64*3];
 uniform vec4 cVertexLights[4*3];

+ 2 - 0
Bin/CoreData/Shaders/HLSL/Uniforms.hlsl

@@ -4,6 +4,7 @@ uniform float3 cAmbientEndColor;
 uniform float3 cCameraPos;
 uniform float3x3 cCameraRot;
 uniform float4 cDepthMode;
+uniform float cElapsedTime;
 uniform float3 cFrustumSize;
 uniform float4 cGBufferOffsets;
 uniform float3 cLightDir;
@@ -21,6 +22,7 @@ uniform float4 cVertexLights[4*3];
 
 // Pixel shader uniforms
 uniform float3 cAmbientColor;
+uniform float cElapsedTimePS;
 uniform float2 cFogParams;
 uniform float3 cFogColor;
 uniform float2 cGBufferInvSize;

+ 2 - 0
Engine/Engine/SceneAPI.cpp

@@ -184,6 +184,8 @@ static void RegisterScene(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Scene", "bool get_active() const", asMETHOD(Scene, IsActive), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void set_timeScale(float)", asMETHOD(Scene, SetTimeScale), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "float get_timeScale() const", asMETHOD(Scene, GetTimeScale), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Scene", "void set_elapsedTime(float)", asMETHOD(Scene, SetElapsedTime), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Scene", "float get_elapsedTime() const", asMETHOD(Scene, GetElapsedTime), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void set_smoothingConstant(float)", asMETHOD(Scene, SetSmoothingConstant), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "float get_smoothingConstant() const", asMETHOD(Scene, GetSmoothingConstant), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void set_snapThreshold(float)", asMETHOD(Scene, SetSnapThreshold), asCALL_THISCALL);

+ 47 - 23
Engine/Graphics/Batch.cpp

@@ -30,6 +30,7 @@
 #include "Node.h"
 #include "Renderer.h"
 #include "Profiler.h"
+#include "Scene.h"
 #include "ShaderVariation.h"
 #include "Sort.h"
 #include "Technique.h"
@@ -172,11 +173,13 @@ void Batch::CalculateSortKey()
         (((unsigned long long)materialID) << 16) | geometryID;
 }
 
-void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransform) const
+void Batch::Prepare(View* view, bool setModelTransform) const
 {
     if (!vertexShader_ || !pixelShader_)
         return;
     
+    Graphics* graphics = view->GetGraphics();
+    Renderer* renderer = view->GetRenderer();
     Node* cameraNode = camera_ ? camera_->GetNode() : 0;
     
     // Set pass / material-specific renderstates
@@ -198,6 +201,18 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
     // Set shaders
     graphics->SetShaders(vertexShader_, pixelShader_);
     
+    // Set global frame parameters
+    if (graphics->NeedParameterUpdate(SP_FRAME, (void*)0))
+    {
+        Scene* scene = view->GetScene();
+        if (scene)
+        {
+            float elapsedTime = scene->GetElapsedTime();
+            graphics->SetShaderParameter(VSP_ELAPSEDTIME, elapsedTime);
+            graphics->SetShaderParameter(PSP_ELAPSEDTIME, elapsedTime);
+        }
+    }
+    
     // Set camera shader parameters
     unsigned cameraHash = overrideView_ ? (unsigned)camera_ + 4 : (unsigned)camera_;
     if (graphics->NeedParameterUpdate(SP_CAMERA, (void*)cameraHash))
@@ -598,19 +613,19 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
     }
 }
 
-void Batch::Draw(Graphics* graphics, Renderer* renderer) const
+void Batch::Draw(View* view) const
 {
     if (!geometry_->IsEmpty())
     {
-        Prepare(graphics, renderer);
-        geometry_->Draw(graphics);
+        Prepare(view);
+        geometry_->Draw(view->GetGraphics());
     }
 }
 
-void BatchGroup::SetTransforms(Renderer* renderer, void* lockedData, unsigned& freeIndex)
+void BatchGroup::SetTransforms(View* view, void* lockedData, unsigned& freeIndex)
 {
     // Do not use up buffer space if not going to draw as instanced
-    if (geometry_->GetIndexCount() > (unsigned)renderer->GetMaxInstanceTriangles() * 3)
+    if (geometry_->GetIndexCount() > (unsigned)view->GetRenderer()->GetMaxInstanceTriangles() * 3)
         return;
     
     startIndex_ = freeIndex;
@@ -623,15 +638,18 @@ void BatchGroup::SetTransforms(Renderer* renderer, void* lockedData, unsigned& f
     freeIndex += instances_.Size();
 }
 
-void BatchGroup::Draw(Graphics* graphics, Renderer* renderer) const
+void BatchGroup::Draw(View* view) const
 {
+    Graphics* graphics = view->GetGraphics();
+    Renderer* renderer = view->GetRenderer();
+    
     if (instances_.Size() && !geometry_->IsEmpty())
     {
         // Draw as individual objects if instancing not supported
         VertexBuffer* instanceBuffer = renderer->GetInstancingBuffer();
         if (!instanceBuffer || geometry_->GetIndexCount() > (unsigned)renderer->GetMaxInstanceTriangles() * 3)
         {
-            Batch::Prepare(graphics, renderer, false);
+            Batch::Prepare(view, false);
             
             graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
             graphics->SetVertexBuffers(geometry_->GetVertexBuffers(), geometry_->GetVertexElementMasks());
@@ -647,7 +665,7 @@ void BatchGroup::Draw(Graphics* graphics, Renderer* renderer) const
         }
         else
         {
-            Batch::Prepare(graphics, renderer, false);
+            Batch::Prepare(view, false);
             
             // Get the geometry vertex buffers, then add the instancing stream buffer
             // Hack: use a const_cast to avoid dynamic allocation of new temp vectors
@@ -864,16 +882,19 @@ void BatchQueue::SortFrontToBack2Pass(PODVector<Batch*>& batches)
     #endif
 }
 
-void BatchQueue::SetTransforms(Renderer* renderer, void* lockedData, unsigned& freeIndex)
+void BatchQueue::SetTransforms(View* view, void* lockedData, unsigned& freeIndex)
 {
     for (HashMap<BatchGroupKey, BatchGroup>::Iterator i = baseBatchGroups_.Begin(); i != baseBatchGroups_.End(); ++i)
-        i->second_.SetTransforms(renderer, lockedData, freeIndex);
+        i->second_.SetTransforms(view, lockedData, freeIndex);
     for (HashMap<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
-        i->second_.SetTransforms(renderer, lockedData, freeIndex);
+        i->second_.SetTransforms(view, lockedData, freeIndex);
 }
 
-void BatchQueue::Draw(Graphics* graphics, Renderer* renderer, bool useScissor, bool markToStencil) const
+void BatchQueue::Draw(View* view, bool useScissor, bool markToStencil) const
 {
+    Graphics* graphics = view->GetGraphics();
+    Renderer* renderer = view->GetRenderer();
+    
     graphics->SetScissorTest(false);
     
     // During G-buffer rendering, mark opaque pixels to stencil buffer
@@ -887,7 +908,7 @@ void BatchQueue::Draw(Graphics* graphics, Renderer* renderer, bool useScissor, b
         if (markToStencil)
             graphics->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, group->lightMask_);
         
-        group->Draw(graphics, renderer);
+        group->Draw(view);
     }
     // Base non-instanced
     for (PODVector<Batch*>::ConstIterator i = sortedBaseBatches_.Begin(); i != sortedBaseBatches_.End(); ++i)
@@ -896,7 +917,7 @@ void BatchQueue::Draw(Graphics* graphics, Renderer* renderer, bool useScissor, b
         if (markToStencil)
             graphics->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, batch->lightMask_);
         
-        batch->Draw(graphics, renderer);
+        batch->Draw(view);
     }
     
     // Non-base instanced
@@ -908,7 +929,7 @@ void BatchQueue::Draw(Graphics* graphics, Renderer* renderer, bool useScissor, b
         if (markToStencil)
             graphics->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, group->lightMask_);
         
-        group->Draw(graphics, renderer);
+        group->Draw(view);
     }
     // Non-base non-instanced
     for (PODVector<Batch*>::ConstIterator i = sortedBatches_.Begin(); i != sortedBatches_.End(); ++i)
@@ -924,12 +945,15 @@ void BatchQueue::Draw(Graphics* graphics, Renderer* renderer, bool useScissor, b
         if (markToStencil)
             graphics->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, batch->lightMask_);
         
-        batch->Draw(graphics, renderer);
+        batch->Draw(view);
     }
 }
 
-void BatchQueue::Draw(Light* light, Graphics* graphics, Renderer* renderer) const
+void BatchQueue::Draw(Light* light, View* view) const
 {
+    Graphics* graphics = view->GetGraphics();
+    Renderer* renderer = view->GetRenderer();
+    
     graphics->SetScissorTest(false);
     graphics->SetStencilTest(false);
     
@@ -937,13 +961,13 @@ void BatchQueue::Draw(Light* light, Graphics* graphics, Renderer* renderer) cons
     for (PODVector<BatchGroup*>::ConstIterator i = sortedBaseBatchGroups_.Begin(); i != sortedBaseBatchGroups_.End(); ++i)
     {
         BatchGroup* group = *i;
-        group->Draw(graphics, renderer);
+        group->Draw(view);
     }
     // Base non-instanced
     for (PODVector<Batch*>::ConstIterator i = sortedBaseBatches_.Begin(); i != sortedBaseBatches_.End(); ++i)
     {
         Batch* batch = *i;
-        batch->Draw(graphics, renderer);
+        batch->Draw(view);
     }
     
     // All base passes have been drawn. Optimize at this point by both stencil volume and scissor
@@ -959,7 +983,7 @@ void BatchQueue::Draw(Light* light, Graphics* graphics, Renderer* renderer) cons
             renderer->OptimizeLightByScissor(light, group->camera_);
             optimized = true;
         }
-        group->Draw(graphics, renderer);
+        group->Draw(view);
     }
     // Non-base non-instanced
     for (PODVector<Batch*>::ConstIterator i = sortedBatches_.Begin(); i != sortedBatches_.End(); ++i)
@@ -971,11 +995,11 @@ void BatchQueue::Draw(Light* light, Graphics* graphics, Renderer* renderer) cons
             renderer->OptimizeLightByScissor(light, batch->camera_);
             optimized = true;
         }
-        batch->Draw(graphics, renderer);
+        batch->Draw(view);
     }
 }
 
-unsigned BatchQueue::GetNumInstances(Renderer* renderer) const
+unsigned BatchQueue::GetNumInstances() const
 {
     unsigned total = 0;
     

+ 9 - 10
Engine/Graphics/Batch.h

@@ -35,15 +35,14 @@ namespace Urho3D
 class Camera;
 class Drawable;
 class Geometry;
-class Graphics;
 class Light;
 class Material;
 class Matrix3x4;
 class Pass;
-class Renderer;
 class ShaderVariation;
 class Texture2D;
 class VertexBuffer;
+class View;
 class Zone;
 struct LightBatchQueue;
 
@@ -75,9 +74,9 @@ struct Batch
     /// Calculate state sorting key, which consists of base pass flag, light, pass and geometry.
     void CalculateSortKey();
     /// Prepare for rendering.
-    void Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransform = true) const;
+    void Prepare(View* view, bool setModelTransform = true) const;
     /// Prepare and draw.
-    void Draw(Graphics* graphics, Renderer* renderer) const;
+    void Draw(View* view) const;
     
     /// State sorting key.
     unsigned long long sortKey_;
@@ -158,9 +157,9 @@ struct BatchGroup : public Batch
     }
     
     /// Pre-set the instance transforms. Buffer must be big enough to hold all transforms.
-    void SetTransforms(Renderer* renderer, void* lockedData, unsigned& freeIndex);
+    void SetTransforms(View* view, void* lockedData, unsigned& freeIndex);
     /// Prepare and draw.
-    void Draw(Graphics* graphics, Renderer* renderer) const;
+    void Draw(View* view) const;
     
     /// Instance data.
     PODVector<InstanceData> instances_;
@@ -219,13 +218,13 @@ public:
     /// Sort batches front to back while also maintaining state sorting.
     void SortFrontToBack2Pass(PODVector<Batch*>& batches);
     /// Pre-set instance transforms of all groups. The vertex buffer must be big enough to hold all transforms.
-    void SetTransforms(Renderer* renderer, void* lockedData, unsigned& freeIndex);
+    void SetTransforms(View* view, void* lockedData, unsigned& freeIndex);
     /// Draw.
-    void Draw(Graphics* graphics, Renderer* renderer, bool useScissor = false, bool markToStencil = false) const;
+    void Draw(View* view, bool useScissor = false, bool markToStencil = false) const;
     /// Draw with forward light optimizations.
-    void Draw(Light* light, Graphics* graphics, Renderer* renderer) const;
+    void Draw(Light* light, View* view) const;
     /// Return the combined amount of instances.
-    unsigned GetNumInstances(Renderer* renderer) const;
+    unsigned GetNumInstances() const;
     /// Return whether the batch group is empty.
     bool IsEmpty() const { return batches_.Empty() && baseBatchGroups_.Empty() && batchGroups_.Empty(); }
     

+ 2 - 0
Engine/Graphics/GraphicsDefs.cpp

@@ -35,6 +35,7 @@ StringHash VSP_AMBIENTENDCOLOR("AmbientEndColor");
 StringHash VSP_CAMERAPOS("CameraPos");
 StringHash VSP_CAMERAROT("CameraRot");
 StringHash VSP_DEPTHMODE("DepthMode");
+StringHash VSP_ELAPSEDTIME("ElapsedTime");
 StringHash VSP_FRUSTUMSIZE("FrustumSize");
 StringHash VSP_GBUFFEROFFSETS("GBufferOffsets");
 StringHash VSP_LIGHTDIR("LightDir");
@@ -50,6 +51,7 @@ StringHash VSP_LIGHTMATRICES("LightMatrices");
 StringHash VSP_SKINMATRICES("SkinMatrices");
 StringHash VSP_VERTEXLIGHTS("VertexLights");
 StringHash PSP_AMBIENTCOLOR("AmbientColor");
+StringHash PSP_ELAPSEDTIME("ElapsedTimePS");
 StringHash PSP_FOGCOLOR("FogColor");
 StringHash PSP_FOGPARAMS("FogParams");
 StringHash PSP_GBUFFERINVSIZE("GBufferInvSize");

+ 2 - 0
Engine/Graphics/GraphicsDefs.h

@@ -217,6 +217,7 @@ extern StringHash VSP_AMBIENTENDCOLOR;
 extern StringHash VSP_CAMERAPOS;
 extern StringHash VSP_CAMERAROT;
 extern StringHash VSP_DEPTHMODE;
+extern StringHash VSP_ELAPSEDTIME;
 extern StringHash VSP_FRUSTUMSIZE;
 extern StringHash VSP_GBUFFEROFFSETS;
 extern StringHash VSP_LIGHTDIR;
@@ -232,6 +233,7 @@ extern StringHash VSP_LIGHTMATRICES;
 extern StringHash VSP_SKINMATRICES;
 extern StringHash VSP_VERTEXLIGHTS;
 extern StringHash PSP_AMBIENTCOLOR;
+extern StringHash PSP_ELAPSEDTIME;
 extern StringHash PSP_FOGCOLOR;
 extern StringHash PSP_FOGPARAMS;
 extern StringHash PSP_GBUFFERINVSIZE;

+ 2 - 0
Engine/Graphics/Renderer.cpp

@@ -769,6 +769,8 @@ Geometry* Renderer::GetLightGeometry(Light* light)
     case LIGHT_POINT:
         return pointLightGeometry_;
     }
+    
+    return 0;
 }
 
 Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWidth, unsigned viewHeight)

+ 38 - 25
Engine/Graphics/View.cpp

@@ -259,6 +259,7 @@ View::View(Context* context) :
     Object(context),
     graphics_(GetSubsystem<Graphics>()),
     renderer_(GetSubsystem<Renderer>()),
+    scene_(0),
     octree_(0),
     camera_(0),
     cameraZone_(0),
@@ -294,6 +295,7 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
         return false;
     
     renderMode_ = renderer_->GetRenderMode();
+    scene_ = scene;
     octree_ = octree;
     camera_ = camera;
     cameraNode_ = camera->GetNode();
@@ -467,7 +469,8 @@ void View::Render()
         }
     }
     
-    // "Forget" the camera, octree and zone after rendering
+    // "Forget" the scene, camera, octree and zone after rendering
+    scene_ = 0;
     camera_ = 0;
     octree_ = 0;
     cameraZone_ = 0;
@@ -476,6 +479,16 @@ void View::Render()
     frame_.camera_ = 0;
 }
 
+Graphics* View::GetGraphics() const
+{
+    return graphics_;
+}
+
+Renderer* View::GetRenderer() const
+{
+    return renderer_;
+}
+
 void View::GetDrawables()
 {
     PROFILE(GetDrawables);
@@ -1162,7 +1175,7 @@ void View::RenderBatchesForward()
     if (!baseQueue_.IsEmpty())
     {
         PROFILE(RenderBase);
-        baseQueue_.Draw(graphics_, renderer_);
+        baseQueue_.Draw(this);
     }
     
     // Render shadow maps + opaque objects' additive lighting
@@ -1182,7 +1195,7 @@ void View::RenderBatchesForward()
                 graphics_->SetFillMode(camera_->GetFillMode());
             }
             
-            i->litBatches_.Draw(i->light_, graphics_, renderer_);
+            i->litBatches_.Draw(i->light_, this);
         }
     }
     
@@ -1211,21 +1224,21 @@ void View::RenderBatchesForward()
     if (!preAlphaQueue_.IsEmpty())
     {
         PROFILE(RenderPreAlpha);
-        preAlphaQueue_.Draw(graphics_, renderer_);
+        preAlphaQueue_.Draw(this);
     }
     
     // Render transparent objects (both base passes & additive lighting)
     if (!alphaQueue_.IsEmpty())
     {
         PROFILE(RenderAlpha);
-        alphaQueue_.Draw(graphics_, renderer_, true);
+        alphaQueue_.Draw(this, true);
     }
     
     // Render post-alpha custom pass
     if (!postAlphaQueue_.IsEmpty())
     {
         PROFILE(RenderPostAlpha);
-        postAlphaQueue_.Draw(graphics_, renderer_);
+        postAlphaQueue_.Draw(this);
     }
     
     graphics_->SetFillMode(FILL_SOLID);
@@ -1280,7 +1293,7 @@ void View::RenderBatchesDeferred()
     if (!gbufferQueue_.IsEmpty())
     {
         PROFILE(RenderGBuffer);
-        gbufferQueue_.Draw(graphics_, renderer_, false, true);
+        gbufferQueue_.Draw(this, false, true);
     }
     
     graphics_->SetFillMode(FILL_SOLID);
@@ -1331,7 +1344,7 @@ void View::RenderBatchesDeferred()
             for (unsigned j = 0; j < i->volumeBatches_.Size(); ++j)
             {
                 SetupLightVolumeBatch(i->volumeBatches_[j]);
-                i->volumeBatches_[j].Draw(graphics_, renderer_);
+                i->volumeBatches_[j].Draw(this);
             }
         }
     }
@@ -1367,7 +1380,7 @@ void View::RenderBatchesDeferred()
         PROFILE(RenderBase);
         
         graphics_->SetTexture(TU_LIGHTBUFFER, renderMode_ == RENDER_PREPASS ? albedoBuffer : 0);
-        baseQueue_.Draw(graphics_, renderer_);
+        baseQueue_.Draw(this);
         graphics_->SetTexture(TU_LIGHTBUFFER, 0);
     }
     
@@ -1375,21 +1388,21 @@ void View::RenderBatchesDeferred()
     if (!preAlphaQueue_.IsEmpty())
     {
         PROFILE(RenderPreAlpha);
-        preAlphaQueue_.Draw(graphics_, renderer_);
+        preAlphaQueue_.Draw(this);
     }
     
     // Render transparent objects (both base passes & additive lighting)
     if (!alphaQueue_.IsEmpty())
     {
         PROFILE(RenderAlpha);
-        alphaQueue_.Draw(graphics_, renderer_, true);
+        alphaQueue_.Draw(this, true);
     }
     
     // Render post-alpha custom pass
     if (!postAlphaQueue_.IsEmpty())
     {
         PROFILE(RenderPostAlpha);
-        postAlphaQueue_.Draw(graphics_, renderer_);
+        postAlphaQueue_.Draw(this);
     }
     
     graphics_->SetFillMode(FILL_SOLID);
@@ -1879,7 +1892,7 @@ bool View::IsShadowCasterVisible(Drawable* drawable, BoundingBox lightViewBox, C
     {
         // Extrude the light space bounding box up to the far edge of the frustum's light space bounding box
         lightViewBox.max_.z_ = Max(lightViewBox.max_.z_,lightViewFrustumBox.max_.z_);
-        return lightViewFrustum.IsInsideFast(lightViewBox);
+        return lightViewFrustum.IsInsideFast(lightViewBox) != OUTSIDE;
     }
     else
     {
@@ -1904,7 +1917,7 @@ bool View::IsShadowCasterVisible(Drawable* drawable, BoundingBox lightViewBox, C
         BoundingBox extrudedBox(newCenter - newHalfSize, newCenter + newHalfSize);
         lightViewBox.Merge(extrudedBox);
         
-        return lightViewFrustum.IsInsideFast(lightViewBox);
+        return lightViewFrustum.IsInsideFast(lightViewBox) != OUTSIDE;
     }
 }
 
@@ -2367,16 +2380,16 @@ void View::PrepareInstancingBuffer()
     
     unsigned totalInstances = 0;
     
-    totalInstances += baseQueue_.GetNumInstances(renderer_);
-    totalInstances += preAlphaQueue_.GetNumInstances(renderer_);
+    totalInstances += baseQueue_.GetNumInstances();
+    totalInstances += preAlphaQueue_.GetNumInstances();
     if (renderMode_ != RENDER_FORWARD)
-        totalInstances += gbufferQueue_.GetNumInstances(renderer_);
+        totalInstances += gbufferQueue_.GetNumInstances();
     
     for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
     {
         for (unsigned j = 0; j < i->shadowSplits_.Size(); ++j)
-            totalInstances += i->shadowSplits_[j].shadowBatches_.GetNumInstances(renderer_);
-        totalInstances += i->litBatches_.GetNumInstances(renderer_);
+            totalInstances += i->shadowSplits_[j].shadowBatches_.GetNumInstances();
+        totalInstances += i->litBatches_.GetNumInstances();
     }
     
     // If fail to set buffer size, fall back to per-group locking
@@ -2388,16 +2401,16 @@ void View::PrepareInstancingBuffer()
         if (!dest)
             return;
         
-        baseQueue_.SetTransforms(renderer_, dest, freeIndex);
-        preAlphaQueue_.SetTransforms(renderer_, dest, freeIndex);
+        baseQueue_.SetTransforms(this, dest, freeIndex);
+        preAlphaQueue_.SetTransforms(this, dest, freeIndex);
         if (renderMode_ != RENDER_FORWARD)
-            gbufferQueue_.SetTransforms(renderer_, dest, freeIndex);
+            gbufferQueue_.SetTransforms(this, dest, freeIndex);
         
         for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
         {
             for (unsigned j = 0; j < i->shadowSplits_.Size(); ++j)
-                i->shadowSplits_[j].shadowBatches_.SetTransforms(renderer_, dest, freeIndex);
-            i->litBatches_.SetTransforms(renderer_, dest, freeIndex);
+                i->shadowSplits_[j].shadowBatches_.SetTransforms(this, dest, freeIndex);
+            i->litBatches_.SetTransforms(this, dest, freeIndex);
         }
         
         instancingBuffer->Unlock();
@@ -2504,7 +2517,7 @@ void View::RenderShadowMap(const LightBatchQueue& queue)
         if (!shadowQueue.shadowBatches_.IsEmpty())
         {
             graphics_->SetViewport(shadowQueue.shadowViewport_);
-            shadowQueue.shadowBatches_.Draw(graphics_, renderer_);
+            shadowQueue.shadowBatches_.Draw(this);
         }
     }
     

+ 8 - 0
Engine/Graphics/View.h

@@ -91,6 +91,12 @@ public:
     /// Render batches.
     void Render();
     
+    /// Return graphics subsystem.
+    Graphics* GetGraphics() const;
+    /// Return renderer subsystem.
+    Renderer* GetRenderer() const;
+    /// Return scene.
+    Scene* GetScene() const { return scene_; }
     /// Return octree.
     Octree* GetOctree() const { return octree_; }
     /// Return camera.
@@ -176,6 +182,8 @@ private:
     WeakPtr<Graphics> graphics_;
     /// Renderer subsystem.
     WeakPtr<Renderer> renderer_;
+    /// Scene to use.
+    Scene* scene_;
     /// Octree to use.
     Octree* octree_;
     /// Camera to use.

+ 1 - 1
Engine/Graphics/Zone.cpp

@@ -188,7 +188,7 @@ bool Zone::IsInside(const Vector3& point) const
 {
     // Use an oriented bounding box test
     Vector3 localPoint(GetInverseWorldTransform() * point);
-    return boundingBox_.IsInside(localPoint);
+    return boundingBox_.IsInside(localPoint) != OUTSIDE;
 }
 
 void Zone::OnMarkedDirty(Node* node)

+ 9 - 0
Engine/Scene/Scene.cpp

@@ -58,6 +58,7 @@ Scene::Scene(Context* context) :
     timeScale_(1.0f),
     smoothingConstant_(DEFAULT_SMOOTHING_CONSTANT),
     snapThreshold_(DEFAULT_SNAP_THRESHOLD),
+    elapsedTime_(0),
     active_(true),
     asyncLoading_(false),
     threadedUpdate_(false)
@@ -92,6 +93,7 @@ void Scene::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(Scene, VAR_FLOAT, "Time Scale", GetTimeScale, SetTimeScale, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Scene, VAR_FLOAT, "Smoothing Constant", GetSmoothingConstant, SetSmoothingConstant, float, DEFAULT_SMOOTHING_CONSTANT, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Scene, VAR_FLOAT, "Snap Threshold", GetSnapThreshold, SetSnapThreshold, float, DEFAULT_SNAP_THRESHOLD, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(Scene, VAR_FLOAT, "Elapsed Time", GetElapsedTime, SetElapsedTime, float, 0.0f, AM_FILE);
     ATTRIBUTE(Scene, VAR_INT, "Next Replicated Node ID", replicatedNodeID_, FIRST_REPLICATED_ID, AM_FILE | AM_NOEDIT);
     ATTRIBUTE(Scene, VAR_INT, "Next Replicated Component ID", replicatedComponentID_, FIRST_REPLICATED_ID, AM_FILE | AM_NOEDIT);
     ATTRIBUTE(Scene, VAR_INT, "Next Local Node ID", localNodeID_, FIRST_LOCAL_ID, AM_FILE | AM_NOEDIT);
@@ -391,6 +393,11 @@ void Scene::SetSnapThreshold(float threshold)
     Node::MarkNetworkUpdate();
 }
 
+void Scene::SetElapsedTime(float time)
+{
+    elapsedTime_ = time;
+}
+
 void Scene::AddRequiredPackageFile(PackageFile* package)
 {
     // Do not add packages that failed to load
@@ -515,6 +522,8 @@ void Scene::Update(float timeStep)
     
     // Post-update variable timestep logic
     SendEvent(E_SCENEPOSTUPDATE, eventData);
+    
+    elapsedTime_ += timeStep;
 }
 
 void Scene::BeginThreadedUpdate()

+ 6 - 0
Engine/Scene/Scene.h

@@ -102,6 +102,8 @@ public:
     void SetActive(bool enable);
     /// Set update time scale. 1.0 = real time (default.)
     void SetTimeScale(float scale);
+    /// Set elapsed time in seconds. This can be used to prevent inaccuracy in the timer if the scene runs for a long time.
+    void SetElapsedTime(float time);
     /// Set network client motion smoothing constant.
     void SetSmoothingConstant(float constant);
     /// Set network client motion smoothing snap threshold.
@@ -133,6 +135,8 @@ public:
     unsigned GetChecksum() const { return checksum_; }
     /// Return update time scale.
     float GetTimeScale() const { return timeScale_; }
+    /// Return elapsed time in seconds.
+    float GetElapsedTime() const { return elapsedTime_; }
     /// Return motion smoothing constant.
     float GetSmoothingConstant() const { return smoothingConstant_; }
     /// Return motion smoothing snap threshold.
@@ -227,6 +231,8 @@ private:
     unsigned checksum_;
     /// Scene update time scale.
     float timeScale_;
+    /// Elapsed time accumulator.
+    float elapsedTime_;
     /// Motion smoothing constant.
     float smoothingConstant_;
     /// Motion smoothing snap threshold.