Quellcode durchsuchen

Dock overlay properly renders once again

BearishSun vor 10 Jahren
Ursprung
Commit
260f25eb34

+ 7 - 6
BansheeEditor/Source/BsDockManager.cpp

@@ -849,12 +849,13 @@ namespace BansheeEngine
 	void DockManager::updateDropOverlay(INT32 x, INT32 y, UINT32 width, UINT32 height)
 	{
 		const static int spacing = 10;
-		const static float innerScale = 0.75f;
+		const static float innerScale = 0.15f;
 
 		UINT32 outWidth = std::max(0, (INT32)width - spacing * 2);
 		UINT32 outHeight = std::max(0, (INT32)height - spacing * 2);
-		UINT32 inWidth = (UINT32)Math::floorToInt(innerScale * outWidth);
-		UINT32 inHeight = (UINT32)Math::floorToInt(innerScale * outHeight);
+		UINT32 innerOffset = outWidth > outHeight ? Math::floorToInt(innerScale * outHeight) : Math::floorToInt(innerScale * outWidth);
+		UINT32 inWidth = outWidth - innerOffset;
+		UINT32 inHeight = outHeight - innerOffset;
 		INT32 inXOffset = Math::floorToInt((outWidth - inWidth) * 0.5f);
 		INT32 inYOffset = Math::floorToInt((outHeight - inHeight) * 0.5f);
 
@@ -1140,7 +1141,7 @@ namespace BansheeEngine
 		if (mCamera != nullptr)
 		{
 			CoreRendererPtr activeRenderer = RendererManager::instance().getActive();
-			activeRenderer->_unregisterRenderCallback(mCamera.get(), -20);
+			activeRenderer->_unregisterRenderCallback(mCamera.get(), 40);
 		}
 	}
 
@@ -1156,10 +1157,10 @@ namespace BansheeEngine
 		{
 			CoreRendererPtr activeRenderer = RendererManager::instance().getActive();
 			if (mCamera != nullptr)
-				activeRenderer->_unregisterRenderCallback(mCamera.get(), -20);
+				activeRenderer->_unregisterRenderCallback(mCamera.get(), 40);
 
 			if (camera != nullptr)
-				activeRenderer->_registerRenderCallback(camera.get(), -20, std::bind(&DockOverlayRenderer::render, this));
+				activeRenderer->_registerRenderCallback(camera.get(), 40, std::bind(&DockOverlayRenderer::render, this), true);
 		}
 
 		mCamera = camera;

+ 3 - 3
BansheeEngine/Source/BsGUIManager.cpp

@@ -1658,7 +1658,7 @@ namespace BansheeEngine
 	{
 		CoreRendererPtr activeRenderer = RendererManager::instance().getActive();
 		for (auto& cameraData : mPerCameraData)
-			activeRenderer->_unregisterRenderCallback(cameraData.first.get(), -30);
+			activeRenderer->_unregisterRenderCallback(cameraData.first.get(), 30);
 	}
 
 	void GUIManagerCore::updateData(const UnorderedMap<SPtr<CameraCore>, Vector<GUIManager::GUICoreRenderData>>& newPerCameraData)
@@ -1692,7 +1692,7 @@ namespace BansheeEngine
 					auto insertedData = mPerCameraData.insert(std::make_pair(newCameraData.first, Vector<RenderData>()));
 					renderData = &insertedData.first->second;
 
-					activeRenderer->_registerRenderCallback(camera.get(), -30, std::bind(&GUIManagerCore::render, this, camera), true);
+					activeRenderer->_registerRenderCallback(camera.get(), 30, std::bind(&GUIManagerCore::render, this, camera), true);
 					validCameras.insert(camera);
 				}
 
@@ -1722,7 +1722,7 @@ namespace BansheeEngine
 
 			for (auto& camera : cameraToRemove)
 			{
-				activeRenderer->_unregisterRenderCallback(camera.get(), -30);
+				activeRenderer->_unregisterRenderCallback(camera.get(), 30);
 				mPerCameraData.erase(camera);
 			}
 		}

+ 977 - 974
RenderBeast/Source/BsRenderBeast.cpp

@@ -1,975 +1,978 @@
-#include "BsRenderBeast.h"
-#include "BsCCamera.h"
-#include "BsSceneObject.h"
-#include "BsSceneManager.h"
-#include "BsCRenderable.h"
-#include "BsMaterial.h"
-#include "BsMesh.h"
-#include "BsPass.h"
-#include "BsBlendState.h"
-#include "BsRasterizerState.h"
-#include "BsDepthStencilState.h"
-#include "BsSamplerState.h"
-#include "BsCoreApplication.h"
-#include "BsViewport.h"
-#include "BsRenderTarget.h"
-#include "BsRenderQueue.h"
-#include "BsGUIManager.h"
-#include "BsCoreThread.h"
-#include "BsGpuParams.h"
-#include "BsProfilerCPU.h"
-#include "BsShader.h"
-#include "BsTechnique.h"
-#include "BsHardwareBufferManager.h"
-#include "BsGpuParamBlockBuffer.h"
-#include "BsShader.h"
-#include "BsStaticRenderableHandler.h"
-#include "BsTime.h"
-#include "BsRenderableElement.h"
-#include "BsFrameAlloc.h"
-#include "BsCoreObjectManager.h"
-#include "BsRenderBeastOptions.h"
-#include "BsSamplerOverrides.h"
-#include "BsLight.h"
-#include "BsRenderTexturePool.h"
-#include "BsRenderTargets.h"
-#include "BsRendererUtility.h"
-
-using namespace std::placeholders;
-
-namespace BansheeEngine
-{
-	RenderBeast::RenderBeast()
-		:mOptions(bs_shared_ptr_new<RenderBeastOptions>()), mOptionsDirty(true), mStaticHandler(nullptr),
-		mDefaultMaterial(nullptr), mPointLightMat(nullptr), mDirLightMat(nullptr)
-	{
-
-	}
-
-	const StringID& RenderBeast::getName() const
-	{
-		static StringID name = "RenderBeast";
-		return name;
-	}
-
-	void RenderBeast::initialize()
-	{
-		CoreRenderer::initialize();
-
-		CoreThread::instance().queueCommand(std::bind(&RenderBeast::initializeCore, this));
-	}
-
-	void RenderBeast::destroy()
-	{
-		CoreRenderer::destroy();
-
-		gCoreAccessor().queueCommand(std::bind(&RenderBeast::destroyCore, this));
-		gCoreAccessor().submitToCoreThread(true);
-	}
-
-	void RenderBeast::initializeCore()
-	{
-		RendererUtility::startUp();
-
-		mCoreOptions = bs_shared_ptr_new<RenderBeastOptions>();
-		mStaticHandler = bs_new<StaticRenderableHandler>();
-
-		mDefaultMaterial = bs_new<DefaultMaterial>();
-		mPointLightMat = bs_new<PointLightMat>();
-		mDirLightMat = bs_new<DirectionalLightMat>();
-
-		RenderTexturePool::startUp();
-	}
-
-	void RenderBeast::destroyCore()
-	{
-		if (mStaticHandler != nullptr)
-			bs_delete(mStaticHandler);
-
-		mRenderTargets.clear();
-		mCameraData.clear();
-		mRenderables.clear();
-
-		RenderTexturePool::shutDown();
-
-		bs_delete(mDefaultMaterial);
-		bs_delete(mPointLightMat);
-		bs_delete(mDirLightMat);
-
-		RendererUtility::shutDown();
-
-		assert(mSamplerOverrides.empty());
-	}
-
-	void RenderBeast::_notifyRenderableAdded(RenderableCore* renderable)
-	{
-		UINT32 renderableId = (UINT32)mRenderables.size();
-
-		renderable->setRendererId(renderableId);
-
-		mRenderables.push_back(RenderableData());
-		mRenderableShaderData.push_back(RenderableShaderData());
-		mWorldBounds.push_back(renderable->getBounds());
-
-		RenderableData& renderableData = mRenderables.back();
-		renderableData.renderable = renderable;
-
-		RenderableShaderData& shaderData = mRenderableShaderData.back();
-		shaderData.worldTransform = renderable->getTransform();
-		shaderData.invWorldTransform = shaderData.worldTransform.inverseAffine();
-		shaderData.worldNoScaleTransform = renderable->getTransformNoScale();
-		shaderData.invWorldNoScaleTransform = shaderData.worldNoScaleTransform.inverseAffine();
-		shaderData.worldDeterminantSign = shaderData.worldTransform.determinant3x3() >= 0.0f ? 1.0f : -1.0f;
-
-		if (renderable->getRenderableType() == RenType_LitTextured)
-			renderableData.controller = mStaticHandler;
-		else
-			renderableData.controller = nullptr;
-
-		SPtr<MeshCore> mesh = renderable->getMesh();
-		if (mesh != nullptr)
-		{
-			const MeshProperties& meshProps = mesh->getProperties();
-			SPtr<VertexDeclarationCore> vertexDecl = mesh->getVertexData()->vertexDeclaration;
-
-			for (UINT32 i = 0; i < meshProps.getNumSubMeshes(); i++)
-			{
-				renderableData.elements.push_back(BeastRenderableElement());
-				BeastRenderableElement& renElement = renderableData.elements.back();
-
-				renElement.mesh = mesh;
-				renElement.subMesh = meshProps.getSubMesh(i);
-				renElement.renderableId = renderableId;
-
-				renElement.material = renderable->getMaterial(i);
-				if (renElement.material == nullptr)
-					renElement.material = renderable->getMaterial(0);
-
-				if (renElement.material != nullptr && renElement.material->getShader() == nullptr)
-					renElement.material = nullptr;
-
-				// Validate mesh <-> shader vertex bindings
-				if (renElement.material != nullptr)
-				{
-					UINT32 numPasses = renElement.material->getNumPasses();
-					for (UINT32 j = 0; j < numPasses; j++)
-					{
-						SPtr<PassCore> pass = renElement.material->getPass(j);
-
-						SPtr<VertexDeclarationCore> shaderDecl = pass->getVertexProgram()->getInputDeclaration();
-						if (!vertexDecl->isCompatible(shaderDecl))
-						{
-							Vector<VertexElement> missingElements = vertexDecl->getMissingElements(shaderDecl);
-
-							StringStream wrnStream;
-							wrnStream << "Provided mesh is missing required vertex attributes to render with the provided shader. Missing elements: " << std::endl;
-
-							for (auto& entry : missingElements)
-								wrnStream << "\t" << toString(entry.getSemantic()) << entry.getSemanticIdx() << std::endl;
-
-							LOGWRN(wrnStream.str());
-							break;
-						}
-					}
-				}
-
-				// If no material use the default material
-				if (renElement.material == nullptr)
-					renElement.material = mDefaultMaterial->getMaterial();
-
-				auto iterFind = mSamplerOverrides.find(renElement.material);
-				if (iterFind != mSamplerOverrides.end())
-				{
-					renElement.samplerOverrides = iterFind->second;
-					iterFind->second->refCount++;
-				}
-				else
-				{
-					MaterialSamplerOverrides* samplerOverrides = SamplerOverrideUtility::generateSamplerOverrides(renElement.material, mCoreOptions);
-					mSamplerOverrides[renElement.material] = samplerOverrides;
-
-					renElement.samplerOverrides = samplerOverrides;
-					samplerOverrides->refCount++;
-				}
-
-				if (renderableData.controller != nullptr)
-					renderableData.controller->initializeRenderElem(renElement);
-			}
-		}
-	}
-
-	void RenderBeast::_notifyRenderableRemoved(RenderableCore* renderable)
-	{
-		UINT32 renderableId = renderable->getRendererId();
-		RenderableCore* lastRenerable = mRenderables.back().renderable;
-		UINT32 lastRenderableId = lastRenerable->getRendererId();
-
-		Vector<BeastRenderableElement>& elements = mRenderables[renderableId].elements;
-		for (auto& element : elements)
-		{
-			auto iterFind = mSamplerOverrides.find(element.material);
-			assert(iterFind != mSamplerOverrides.end());
-
-			MaterialSamplerOverrides* samplerOverrides = iterFind->second;
-			samplerOverrides->refCount--;
-			if (samplerOverrides->refCount == 0)
-			{
-				SamplerOverrideUtility::destroySamplerOverrides(samplerOverrides);
-				mSamplerOverrides.erase(iterFind);
-			}
-
-			element.samplerOverrides = nullptr;
-		}
-
-		if (renderableId != lastRenderableId)
-		{
-			// Swap current last element with the one we want to erase
-			std::swap(mRenderables[renderableId], mRenderables[lastRenderableId]);
-			std::swap(mWorldBounds[renderableId], mWorldBounds[lastRenderableId]);
-			std::swap(mRenderableShaderData[renderableId], mRenderableShaderData[lastRenderableId]);
-
-			lastRenerable->setRendererId(renderableId);
-
-			Vector<BeastRenderableElement>& lastRenderableElements = mRenderables[renderableId].elements;
-			for (auto& element : elements)
-				element.renderableId = renderableId;
-		}
-
-		// Last element is the one we want to erase
-		mRenderables.erase(mRenderables.end() - 1);
-		mWorldBounds.erase(mWorldBounds.end() - 1);
-		mRenderableShaderData.erase(mRenderableShaderData.end() - 1);
-	}
-
-	void RenderBeast::_notifyRenderableUpdated(RenderableCore* renderable)
-	{
-		UINT32 renderableId = renderable->getRendererId();
-
-		RenderableShaderData& shaderData = mRenderableShaderData[renderableId];
-		shaderData.worldTransform = renderable->getTransform();
-		shaderData.invWorldTransform = shaderData.worldTransform.inverseAffine();
-		shaderData.worldNoScaleTransform = renderable->getTransformNoScale();
-		shaderData.invWorldNoScaleTransform = shaderData.worldNoScaleTransform.inverseAffine();
-		shaderData.worldDeterminantSign = shaderData.worldTransform.determinant3x3() >= 0.0f ? 1.0f : -1.0f;
-
-		mWorldBounds[renderableId] = renderable->getBounds();
-	}
-
-	void RenderBeast::_notifyLightAdded(LightCore* light)
-	{
-		if (light->getType() == LightType::Directional)
-		{
-			UINT32 lightId = (UINT32)mDirectionalLights.size();
-			light->setRendererId(lightId);
-
-			mDirectionalLights.push_back(LightData());
-
-			LightData& lightData = mDirectionalLights.back();
-			lightData.internal = light;
-		}
-		else
-		{
-			UINT32 lightId = (UINT32)mPointLights.size();
-
-			light->setRendererId(lightId);
-
-			mPointLights.push_back(LightData());
-			mLightWorldBounds.push_back(light->getBounds());
-
-			LightData& lightData = mPointLights.back();
-			lightData.internal = light;
-		}
-	}
-
-	void RenderBeast::_notifyLightUpdated(LightCore* light)
-	{
-		UINT32 lightId = light->getRendererId();
-
-		if (light->getType() != LightType::Directional)
-			mLightWorldBounds[lightId] = light->getBounds();
-	}
-
-	void RenderBeast::_notifyLightRemoved(LightCore* light)
-	{
-		UINT32 lightId = light->getRendererId();
-		if (light->getType() == LightType::Directional)
-		{
-			LightCore* lastLight = mDirectionalLights.back().internal;
-			UINT32 lastLightId = lastLight->getRendererId();
-
-			if (lightId != lastLightId)
-			{
-				// Swap current last element with the one we want to erase
-				std::swap(mDirectionalLights[lightId], mDirectionalLights[lastLightId]);
-				lastLight->setRendererId(lightId);
-			}
-
-			// Last element is the one we want to erase
-			mDirectionalLights.erase(mDirectionalLights.end() - 1);
-		}
-		else
-		{
-			LightCore* lastLight = mPointLights.back().internal;
-			UINT32 lastLightId = lastLight->getRendererId();
-
-			if (lightId != lastLightId)
-			{
-				// Swap current last element with the one we want to erase
-				std::swap(mPointLights[lightId], mPointLights[lastLightId]);
-				std::swap(mLightWorldBounds[lightId], mLightWorldBounds[lastLightId]);
-
-				lastLight->setRendererId(lightId);
-			}
-
-			// Last element is the one we want to erase
-			mPointLights.erase(mPointLights.end() - 1);
-			mLightWorldBounds.erase(mLightWorldBounds.end() - 1);
-		}
-	}
-
-	void RenderBeast::_notifyCameraAdded(const CameraCore* camera)
-	{
-		SPtr<RenderTargetCore> renderTarget = camera->getViewport()->getTarget();
-		if (renderTarget == nullptr)
-			return;
-
-		CameraData& camData = mCameraData[camera];
-		camData.opaqueQueue = bs_shared_ptr_new<RenderQueue>(mCoreOptions->stateReductionMode);
-
-		StateReduction transparentStateReduction = mCoreOptions->stateReductionMode;
-		if (transparentStateReduction == StateReduction::Material)
-			transparentStateReduction = StateReduction::Distance; // Transparent object MUST be sorted by distance
-
-		camData.transparentQueue = bs_shared_ptr_new<RenderQueue>(transparentStateReduction);
-
-		// Register in render target list
-		auto findIter = std::find_if(mRenderTargets.begin(), mRenderTargets.end(), 
-			[&](const RenderTargetData& x) { return x.target == renderTarget; });
-
-		if (findIter != mRenderTargets.end())
-		{
-			findIter->cameras.push_back(camera);
-		}
-		else
-		{
-			mRenderTargets.push_back(RenderTargetData());
-			RenderTargetData& renderTargetData = mRenderTargets.back();
-
-			renderTargetData.target = renderTarget;
-			renderTargetData.cameras.push_back(camera);
-		}
-
-		// Sort render targets based on priority
-		auto cameraComparer = [&](const CameraCore* a, const CameraCore* b) { return a->getPriority() > b->getPriority(); };
-		auto renderTargetInfoComparer = [&](const RenderTargetData& a, const RenderTargetData& b)
-		{ return a.target->getProperties().getPriority() > b.target->getProperties().getPriority(); };
-		std::sort(begin(mRenderTargets), end(mRenderTargets), renderTargetInfoComparer);
-
-		for (auto& camerasPerTarget : mRenderTargets)
-		{
-			Vector<const CameraCore*>& cameras = camerasPerTarget.cameras;
-
-			std::sort(begin(cameras), end(cameras), cameraComparer);
-		}
-	}
-
-	void RenderBeast::_notifyCameraRemoved(const CameraCore* camera)
-	{
-		mCameraData.erase(camera);
-
-		// Remove from render target list
-		for (auto iterTarget = mRenderTargets.begin(); iterTarget != mRenderTargets.end(); ++iterTarget)
-		{
-			RenderTargetData& target = *iterTarget;
-			for (auto iterCam = target.cameras.begin(); iterCam != target.cameras.end(); ++iterCam)
-			{
-				if (camera == *iterCam)
-				{
-					target.cameras.erase(iterCam);
-					break;
-				}
-			}
-
-			if (target.cameras.empty())
-			{
-				mRenderTargets.erase(iterTarget);
-				break;
-			}
-		}
-	}
-
-	void RenderBeast::setOptions(const SPtr<CoreRendererOptions>& options)
-	{
-		mOptions = std::static_pointer_cast<RenderBeastOptions>(options);
-		mOptionsDirty = true;
-	}
-
-	SPtr<CoreRendererOptions> RenderBeast::getOptions() const
-	{
-		return mOptions;
-	}
-
-	void RenderBeast::renderAll() 
-	{
-		// Sync all dirty sim thread CoreObject data to core thread
-		CoreObjectManager::instance().syncToCore(gCoreAccessor());
-
-		if (mOptionsDirty)
-		{
-			gCoreAccessor().queueCommand(std::bind(&RenderBeast::syncRenderOptions, this, *mOptions));
-			mOptionsDirty = false;
-		}
-
-		gCoreAccessor().queueCommand(std::bind(&RenderBeast::renderAllCore, this, gTime().getTime()));
-	}
-
-	void RenderBeast::syncRenderOptions(const RenderBeastOptions& options)
-	{
-		bool filteringChanged = mCoreOptions->filtering != options.filtering;
-		if (options.filtering == RenderBeastFiltering::Anisotropic)
-			filteringChanged |= mCoreOptions->anisotropyMax != options.anisotropyMax;
-
-		if (filteringChanged)
-			refreshSamplerOverrides(true);
-
-		*mCoreOptions = options;
-
-		for (auto& cameraData : mCameraData)
-		{
-			cameraData.second.opaqueQueue->setStateReduction(mCoreOptions->stateReductionMode);
-
-			StateReduction transparentStateReduction = mCoreOptions->stateReductionMode;
-			if (transparentStateReduction == StateReduction::Material)
-				transparentStateReduction = StateReduction::Distance; // Transparent object MUST be sorted by distance
-
-			cameraData.second.transparentQueue->setStateReduction(transparentStateReduction);
-		}
-	}
-
-	void RenderBeast::renderAllCore(float time)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		gProfilerCPU().beginSample("renderAllCore");
-
-		// Note: I'm iterating over all sampler states every frame. If this ends up being a performance
-		// issue consider handling this internally in MaterialCore which can only do it when sampler states
-		// are actually modified after sync
-		refreshSamplerOverrides();
-
-		// Update global per-frame hardware buffers
-		mStaticHandler->updatePerFrameBuffers(time);
-
-		// Generate render queues per camera
-		for (auto& cameraData : mCameraData)
-		{
-			const CameraCore* camera = cameraData.first;
-			determineVisible(*camera);
-		}
-
-		// Render everything, target by target
-		for (auto& renderTargetData : mRenderTargets)
-		{
-			SPtr<RenderTargetCore> target = renderTargetData.target;
-			Vector<const CameraCore*>& cameras = renderTargetData.cameras;
-
-			RenderAPICore::instance().beginFrame();
-
-			UINT32 numCameras = (UINT32)cameras.size();
-			for (UINT32 i = 0; i < numCameras; i++)
-				render(renderTargetData, i);
-
-			RenderAPICore::instance().endFrame();
-			RenderAPICore::instance().swapBuffers(target);
-		}
-
-		gProfilerCPU().endSample("renderAllCore");
-	}
-
-	void RenderBeast::render(RenderTargetData& rtData, UINT32 camIdx)
-	{
-		gProfilerCPU().beginSample("Render");
-
-		const CameraCore* camera = rtData.cameras[camIdx];
-		CameraData& camData = mCameraData[camera];
-
-		SPtr<ViewportCore> viewport = camera->getViewport();
-		CameraShaderData cameraShaderData = getCameraShaderData(*camera);
-
-		mStaticHandler->updatePerCameraBuffers(cameraShaderData);
-
-		// Render scene objects to g-buffer
-		bool hasGBuffer = ((UINT32)camera->getFlags() & (UINT32)CameraFlags::Overlay) == 0;
-
-		if (hasGBuffer)
-		{
-			bool createGBuffer = camData.target == nullptr ||
-				camData.target->getHDR() != mCoreOptions->hdr ||
-				camData.target->getNumSamples() != mCoreOptions->msaa;
-
-			if (createGBuffer)
-				camData.target = RenderTargets::create(viewport, mCoreOptions->hdr, mCoreOptions->msaa);
-
-			camData.target->allocate();
-			camData.target->bindGBuffer();
-		}
-		else
-			camData.target = nullptr;
-
-		// Trigger pre-scene callbacks
-		auto iterCameraCallbacks = mRenderCallbacks.find(camera);
-		if (iterCameraCallbacks != mRenderCallbacks.end())
-		{
-			for (auto& callbackPair : iterCameraCallbacks->second)
-			{
-				const RenderCallbackData& callbackData = callbackPair.second;
-
-				if (callbackData.overlay || callbackPair.first >= 0)
-					break;
-
-				callbackData.callback();
-			}
-		}
-		
-		if (hasGBuffer)
-		{
-			// Render base pass
-			const Vector<RenderQueueElement>& opaqueElements = camData.opaqueQueue->getSortedElements();
-			for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
-			{
-				BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
-				SPtr<MaterialCore> material = renderElem->material;
-
-				UINT32 rendererId = renderElem->renderableId;
-				Matrix4 worldViewProjMatrix = cameraShaderData.viewProj * mRenderableShaderData[rendererId].worldTransform;
-
-				mStaticHandler->updatePerObjectBuffers(*renderElem, mRenderableShaderData[rendererId], worldViewProjMatrix);
-				mStaticHandler->bindGlobalBuffers(*renderElem); // Note: If I can keep global buffer slot indexes the same between shaders I could only bind these once
-				mStaticHandler->bindPerObjectBuffers(*renderElem);
-
-				if (iter->applyPass)
-				{
-					SPtr<PassCore> pass = material->getPass(iter->passIdx);
-					setPass(pass);
-				}
-
-				SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
-
-				if (renderElem->samplerOverrides != nullptr)
-					setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
-				else
-					setPassParams(passParams, nullptr);
-
-				gRendererUtility().draw(iter->renderElem->mesh, iter->renderElem->subMesh);
-			}
-
-			camData.target->bindSceneColor();
-
-			// Render light pass
-			SPtr<MaterialCore> dirMaterial = mDirLightMat->getMaterial();
-			SPtr<PassCore> dirPass = dirMaterial->getPass(0);
-
-			setPass(dirPass);
-			mDirLightMat->setGBuffer(camData.target);
-
-			for (auto& light : mDirectionalLights)
-			{
-				if (!light.internal->getIsActive())
-					continue;
-
-				mDirLightMat->setParameters(light.internal);
-
-				// TODO - Bind parameters to the pipeline manually as I don't need to re-bind gbuffer textures for every light
-				setPassParams(dirMaterial->getPassParameters(0), nullptr);
-				gRendererUtility().drawScreenQuad(*viewport);
-			}
-
-			SPtr<MaterialCore> pointMaterial = mPointLightMat->getMaterial();
-			SPtr<PassCore> pointPass = pointMaterial->getPass(0);
-
-			setPass(pointPass);
-			mPointLightMat->setGBuffer(camData.target);
-
-			// TODO - Cull lights based on visibility, right now I just iterate over all of them. 
-			for (auto& light : mPointLights)
-			{
-				if (!light.internal->getIsActive())
-					continue;
-
-				mPointLightMat->setParameters(light.internal);
-
-				// TODO - Bind parameters to the pipeline manually as I don't need to re-bind gbuffer textures for every light
-				setPassParams(dirMaterial->getPassParameters(0), nullptr);
-				SPtr<MeshCore> mesh = light.internal->getMesh();
-				gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
-			}
-		}
-
-		// Render transparent objects (TODO - No lighting yet)
-		const Vector<RenderQueueElement>& transparentElements = camData.transparentQueue->getSortedElements();
-		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
-		{
-			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
-			SPtr<MaterialCore> material = renderElem->material;
-
-			UINT32 rendererId = renderElem->renderableId;
-			Matrix4 worldViewProjMatrix = cameraShaderData.viewProj * mRenderableShaderData[rendererId].worldTransform;
-
-			mStaticHandler->updatePerObjectBuffers(*renderElem, mRenderableShaderData[rendererId], worldViewProjMatrix);
-			mStaticHandler->bindGlobalBuffers(*renderElem); // Note: If I can keep global buffer slot indexes the same between shaders I could only bind these once
-			mStaticHandler->bindPerObjectBuffers(*renderElem);
-
-			if (iter->applyPass)
-			{
-				SPtr<PassCore> pass = material->getPass(iter->passIdx);
-				setPass(pass);
-			}
-
-			SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
-
-			if (renderElem->samplerOverrides != nullptr)
-				setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
-			else
-				setPassParams(passParams, nullptr);
-
-			gRendererUtility().draw(iter->renderElem->mesh, iter->renderElem->subMesh);
-		}
-
-		camData.opaqueQueue->clear();
-		camData.transparentQueue->clear();
-
-		// Render non-overlay post-scene callbacks
-		if (iterCameraCallbacks != mRenderCallbacks.end())
-		{
-			for (auto& callbackPair : iterCameraCallbacks->second)
-			{
-				const RenderCallbackData& callbackData = callbackPair.second;
-
-				if (callbackData.overlay || callbackPair.first < 0)
-					break;
-
-				callbackData.callback();
-			}
-		}
-
-		if (hasGBuffer)
-		{
-			// TODO - Instead of doing a separate resolve here I could potentially perform a resolve directly in the
-			// light pass.
-			camData.target->resolve();
-		}
-		else
-		{
-			// Prepare final render target
-			SPtr<RenderTargetCore> target = rtData.target;
-
-			RenderAPICore::instance().setRenderTarget(target);
-			RenderAPICore::instance().setViewport(viewport->getNormArea());
-
-			// If first camera in render target, prepare the render target
-			if (camIdx == 0)
-			{
-				UINT32 clearBuffers = 0;
-				if (viewport->getRequiresColorClear())
-					clearBuffers |= FBT_COLOR;
-
-				if (viewport->getRequiresDepthClear())
-					clearBuffers |= FBT_DEPTH;
-
-				if (viewport->getRequiresStencilClear())
-					clearBuffers |= FBT_STENCIL;
-
-				if (clearBuffers != 0)
-				{
-					RenderAPICore::instance().clearViewport(clearBuffers, viewport->getClearColor(),
-						viewport->getClearDepthValue(), viewport->getClearStencilValue());
-				}
-			}
-		}
-
-		// Render overlay post-scene callbacks
-		if (iterCameraCallbacks != mRenderCallbacks.end())
-		{
-			for (auto& callbackPair : iterCameraCallbacks->second)
-			{
-				const RenderCallbackData& callbackData = callbackPair.second;
-
-				if (!callbackData.overlay)
-					break;
-
-				callbackData.callback();
-			}
-		}
-
-		if (hasGBuffer)
-			camData.target->release();
-
-		gProfilerCPU().endSample("Render");
-	}
-	
-	void RenderBeast::determineVisible(const CameraCore& camera)
-	{
-		CameraData& cameraData = mCameraData[&camera];
-
-		UINT64 cameraLayers = camera.getLayers();
-		ConvexVolume worldFrustum = camera.getWorldFrustum();
-
-		// Update per-object param buffers and queue render elements
-		for (auto& renderableData : mRenderables)
-		{
-			RenderableCore* renderable = renderableData.renderable;
-			RenderableHandler* controller = renderableData.controller;
-			UINT32 renderableType = renderable->getRenderableType();
-			UINT32 rendererId = renderable->getRendererId();
-
-			if ((renderable->getLayer() & cameraLayers) == 0)
-				continue;
-
-			// Do frustum culling
-			// TODO - This is bound to be a bottleneck at some point. When it is ensure that intersect
-			// methods use vector operations, as it is trivial to update them.
-			const Sphere& boundingSphere = mWorldBounds[rendererId].getSphere();
-			if (worldFrustum.intersects(boundingSphere))
-			{
-				// More precise with the box
-				const AABox& boundingBox = mWorldBounds[rendererId].getBox();
-
-				if (worldFrustum.intersects(boundingBox))
-				{
-					float distanceToCamera = (camera.getPosition() - boundingBox.getCenter()).length();
-
-					for (auto& renderElem : renderableData.elements)
-					{
-						bool isTransparent = (renderElem.material->getShader()->getFlags() & (UINT32)ShaderFlags::Transparent) != 0;
-
-						if (isTransparent)
-							cameraData.transparentQueue->add(&renderElem, distanceToCamera);
-						else
-							cameraData.opaqueQueue->add(&renderElem, distanceToCamera);
-					}
-
-				}
-			}
-		}
-
-		cameraData.opaqueQueue->sort();
-		cameraData.transparentQueue->sort();
-	}
-
-	Vector2 RenderBeast::getDeviceZTransform(const Matrix4& projMatrix)
-	{
-		Vector2 output;
-		output.x = 1.0f / projMatrix[2][2];
-		output.y = projMatrix[2][3] / projMatrix[2][2];
-
-		return output;
-	}
-
-	CameraShaderData RenderBeast::getCameraShaderData(const CameraCore& camera)
-	{
-		CameraShaderData data;
-		data.proj = camera.getProjectionMatrixRS();
-		data.view = camera.getViewMatrix();
-		data.viewProj = data.proj * data.view;
-		data.invProj = data.proj.inverse();
-		data.viewDir = camera.getForward();
-		data.viewOrigin = camera.getPosition();
-		data.deviceZToWorldZ = getDeviceZTransform(data.proj);
-
-		SPtr<ViewportCore> viewport = camera.getViewport();
-		SPtr<RenderTargetCore> rt = viewport->getTarget();
-
-		float halfWidth = viewport->getWidth() / 2.0f;
-		float halfHeight = viewport->getHeight() / 2.0f;
-
-		float rtWidth = (float)rt->getProperties().getWidth();
-		float rtHeight = (float)rt->getProperties().getHeight();
-
-		RenderAPICore& rapi = RenderAPICore::instance();
-
-		data.clipToUVScaleOffset.x = (halfWidth / 2.0f) / rtWidth;
-		data.clipToUVScaleOffset.y = (halfHeight / 2.0f) / rtHeight;
-		data.clipToUVScaleOffset.z = (viewport->getX() + halfWidth + rapi.getHorizontalTexelOffset()) / rtWidth;
-		data.clipToUVScaleOffset.w = (viewport->getY() + halfHeight + rapi.getHorizontalTexelOffset()) / rtHeight;
-
-		return data;
-	}
-
-	void RenderBeast::refreshSamplerOverrides(bool force)
-	{
-		for (auto& entry : mSamplerOverrides)
-		{
-			SPtr<MaterialCore> material = entry.first;
-
-			if (force)
-			{
-				SamplerOverrideUtility::destroySamplerOverrides(entry.second);
-				entry.second = SamplerOverrideUtility::generateSamplerOverrides(material, mCoreOptions);
-			}
-			else
-			{
-				MaterialSamplerOverrides* materialOverrides = entry.second;
-				UINT32 numPasses = material->getNumPasses();
-
-				assert(numPasses == materialOverrides->numPasses);
-				for (UINT32 i = 0; i < numPasses; i++)
-				{
-					SPtr<PassParametersCore> passParams = material->getPassParameters(i);
-					PassSamplerOverrides& passOverrides = materialOverrides->passes[i];
-
-					for (UINT32 j = 0; j < PassParametersCore::NUM_PARAMS; j++)
-					{
-						StageSamplerOverrides& stageOverrides = passOverrides.stages[j];
-
-						SPtr<GpuParamsCore> params = passParams->getParamByIdx(j);
-						if (params == nullptr)
-							continue;
-
-						const GpuParamDesc& paramDesc = params->getParamDesc();
-
-						for (auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
-						{
-							UINT32 slot = iter->second.slot;
-							SPtr<SamplerStateCore> samplerState = params->getSamplerState(slot);
-
-							assert(stageOverrides.numStates > slot);
-
-							if (samplerState != stageOverrides.stateOverrides[slot])
-							{
-								if (samplerState != nullptr)
-									stageOverrides.stateOverrides[slot] = SamplerOverrideUtility::generateSamplerOverride(samplerState, mCoreOptions);
-								else
-									stageOverrides.stateOverrides[slot] = SamplerOverrideUtility::generateSamplerOverride(SamplerStateCore::getDefault(), mCoreOptions);;
-							}	
-						}
-					}
-				}
-			}
-		}
-	}
-
-	void RenderBeast::setPass(const SPtr<PassCore>& pass)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		RenderAPICore& rs = RenderAPICore::instance();
-
-		struct StageData
-		{
-			GpuProgramType type;
-			bool enable;
-			SPtr<GpuProgramCore> program;
-		};
-
-		const UINT32 numStages = 6;
-		StageData stages[numStages] =
-		{
-			{ GPT_VERTEX_PROGRAM, pass->hasVertexProgram(), pass->getVertexProgram() },
-			{ GPT_FRAGMENT_PROGRAM, pass->hasFragmentProgram(), pass->getFragmentProgram() },
-			{ GPT_GEOMETRY_PROGRAM, pass->hasGeometryProgram(), pass->getGeometryProgram() },
-			{ GPT_HULL_PROGRAM, pass->hasHullProgram(), pass->getHullProgram() },
-			{ GPT_DOMAIN_PROGRAM, pass->hasDomainProgram(), pass->getDomainProgram() },
-			{ GPT_COMPUTE_PROGRAM, pass->hasComputeProgram(), pass->getComputeProgram() }
-		};
-
-		for (UINT32 i = 0; i < numStages; i++)
-		{
-			const StageData& stage = stages[i];
-
-			if (stage.enable)
-				rs.bindGpuProgram(stage.program);
-			else
-				rs.unbindGpuProgram(stage.type);
-		}
-
-		// Set up non-texture related pass settings
-		if (pass->getBlendState() != nullptr)
-			rs.setBlendState(pass->getBlendState());
-		else
-			rs.setBlendState(BlendStateCore::getDefault());
-
-		if (pass->getDepthStencilState() != nullptr)
-			rs.setDepthStencilState(pass->getDepthStencilState(), pass->getStencilRefValue());
-		else
-			rs.setDepthStencilState(DepthStencilStateCore::getDefault(), pass->getStencilRefValue());
-
-		if (pass->getRasterizerState() != nullptr)
-			rs.setRasterizerState(pass->getRasterizerState());
-		else
-			rs.setRasterizerState(RasterizerStateCore::getDefault());
-	}
-
-	void RenderBeast::setPassParams(const SPtr<PassParametersCore>& passParams, const PassSamplerOverrides* samplerOverrides)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		RenderAPICore& rs = RenderAPICore::instance();
-
-		struct StageData
-		{
-			GpuProgramType type;
-			SPtr<GpuParamsCore> params;
-		};
-
-		const UINT32 numStages = 6;
-		StageData stages[numStages] =
-		{
-			{ GPT_VERTEX_PROGRAM, passParams->mVertParams },
-			{ GPT_FRAGMENT_PROGRAM, passParams->mFragParams },
-			{ GPT_GEOMETRY_PROGRAM, passParams->mGeomParams },
-			{ GPT_HULL_PROGRAM, passParams->mHullParams },
-			{ GPT_DOMAIN_PROGRAM, passParams->mDomainParams },
-			{ GPT_COMPUTE_PROGRAM, passParams->mComputeParams }
-		};
-
-		for (UINT32 i = 0; i < numStages; i++)
-		{
-			const StageData& stage = stages[i];
-
-			SPtr<GpuParamsCore> params = stage.params;
-			if (params == nullptr)
-				continue;
-
-			const GpuParamDesc& paramDesc = params->getParamDesc();
-
-			for (auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
-			{
-				SPtr<SamplerStateCore> samplerState;
-
-				if (samplerOverrides != nullptr)
-					samplerState = samplerOverrides->stages[i].stateOverrides[iter->second.slot];
-				else
-					samplerState = params->getSamplerState(iter->second.slot);
-
-				if (samplerState == nullptr)
-					rs.setSamplerState(stage.type, iter->second.slot, SamplerStateCore::getDefault());
-				else
-					rs.setSamplerState(stage.type, iter->second.slot, samplerState);
-			}
-
-			for (auto iter = paramDesc.textures.begin(); iter != paramDesc.textures.end(); ++iter)
-			{
-				SPtr<TextureCore> texture = params->getTexture(iter->second.slot);
-
-				if (!params->isLoadStoreTexture(iter->second.slot))
-				{
-					if (texture == nullptr)
-						rs.setTexture(stage.type, iter->second.slot, false, nullptr);
-					else
-						rs.setTexture(stage.type, iter->second.slot, true, texture);
-				}
-				else
-				{
-					const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
-
-					if (texture == nullptr)
-						rs.setLoadStoreTexture(stage.type, iter->second.slot, false, nullptr, surface);
-					else
-						rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface);
-				}
-			}
-
-			rs.setConstantBuffers(stage.type, params);
-		}
-	}
+#include "BsRenderBeast.h"
+#include "BsCCamera.h"
+#include "BsSceneObject.h"
+#include "BsSceneManager.h"
+#include "BsCRenderable.h"
+#include "BsMaterial.h"
+#include "BsMesh.h"
+#include "BsPass.h"
+#include "BsBlendState.h"
+#include "BsRasterizerState.h"
+#include "BsDepthStencilState.h"
+#include "BsSamplerState.h"
+#include "BsCoreApplication.h"
+#include "BsViewport.h"
+#include "BsRenderTarget.h"
+#include "BsRenderQueue.h"
+#include "BsGUIManager.h"
+#include "BsCoreThread.h"
+#include "BsGpuParams.h"
+#include "BsProfilerCPU.h"
+#include "BsShader.h"
+#include "BsTechnique.h"
+#include "BsHardwareBufferManager.h"
+#include "BsGpuParamBlockBuffer.h"
+#include "BsShader.h"
+#include "BsStaticRenderableHandler.h"
+#include "BsTime.h"
+#include "BsRenderableElement.h"
+#include "BsFrameAlloc.h"
+#include "BsCoreObjectManager.h"
+#include "BsRenderBeastOptions.h"
+#include "BsSamplerOverrides.h"
+#include "BsLight.h"
+#include "BsRenderTexturePool.h"
+#include "BsRenderTargets.h"
+#include "BsRendererUtility.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	RenderBeast::RenderBeast()
+		:mOptions(bs_shared_ptr_new<RenderBeastOptions>()), mOptionsDirty(true), mStaticHandler(nullptr),
+		mDefaultMaterial(nullptr), mPointLightMat(nullptr), mDirLightMat(nullptr)
+	{
+
+	}
+
+	const StringID& RenderBeast::getName() const
+	{
+		static StringID name = "RenderBeast";
+		return name;
+	}
+
+	void RenderBeast::initialize()
+	{
+		CoreRenderer::initialize();
+
+		CoreThread::instance().queueCommand(std::bind(&RenderBeast::initializeCore, this));
+	}
+
+	void RenderBeast::destroy()
+	{
+		CoreRenderer::destroy();
+
+		gCoreAccessor().queueCommand(std::bind(&RenderBeast::destroyCore, this));
+		gCoreAccessor().submitToCoreThread(true);
+	}
+
+	void RenderBeast::initializeCore()
+	{
+		RendererUtility::startUp();
+
+		mCoreOptions = bs_shared_ptr_new<RenderBeastOptions>();
+		mStaticHandler = bs_new<StaticRenderableHandler>();
+
+		mDefaultMaterial = bs_new<DefaultMaterial>();
+		mPointLightMat = bs_new<PointLightMat>();
+		mDirLightMat = bs_new<DirectionalLightMat>();
+
+		RenderTexturePool::startUp();
+	}
+
+	void RenderBeast::destroyCore()
+	{
+		if (mStaticHandler != nullptr)
+			bs_delete(mStaticHandler);
+
+		mRenderTargets.clear();
+		mCameraData.clear();
+		mRenderables.clear();
+
+		RenderTexturePool::shutDown();
+
+		bs_delete(mDefaultMaterial);
+		bs_delete(mPointLightMat);
+		bs_delete(mDirLightMat);
+
+		RendererUtility::shutDown();
+
+		assert(mSamplerOverrides.empty());
+	}
+
+	void RenderBeast::_notifyRenderableAdded(RenderableCore* renderable)
+	{
+		UINT32 renderableId = (UINT32)mRenderables.size();
+
+		renderable->setRendererId(renderableId);
+
+		mRenderables.push_back(RenderableData());
+		mRenderableShaderData.push_back(RenderableShaderData());
+		mWorldBounds.push_back(renderable->getBounds());
+
+		RenderableData& renderableData = mRenderables.back();
+		renderableData.renderable = renderable;
+
+		RenderableShaderData& shaderData = mRenderableShaderData.back();
+		shaderData.worldTransform = renderable->getTransform();
+		shaderData.invWorldTransform = shaderData.worldTransform.inverseAffine();
+		shaderData.worldNoScaleTransform = renderable->getTransformNoScale();
+		shaderData.invWorldNoScaleTransform = shaderData.worldNoScaleTransform.inverseAffine();
+		shaderData.worldDeterminantSign = shaderData.worldTransform.determinant3x3() >= 0.0f ? 1.0f : -1.0f;
+
+		if (renderable->getRenderableType() == RenType_LitTextured)
+			renderableData.controller = mStaticHandler;
+		else
+			renderableData.controller = nullptr;
+
+		SPtr<MeshCore> mesh = renderable->getMesh();
+		if (mesh != nullptr)
+		{
+			const MeshProperties& meshProps = mesh->getProperties();
+			SPtr<VertexDeclarationCore> vertexDecl = mesh->getVertexData()->vertexDeclaration;
+
+			for (UINT32 i = 0; i < meshProps.getNumSubMeshes(); i++)
+			{
+				renderableData.elements.push_back(BeastRenderableElement());
+				BeastRenderableElement& renElement = renderableData.elements.back();
+
+				renElement.mesh = mesh;
+				renElement.subMesh = meshProps.getSubMesh(i);
+				renElement.renderableId = renderableId;
+
+				renElement.material = renderable->getMaterial(i);
+				if (renElement.material == nullptr)
+					renElement.material = renderable->getMaterial(0);
+
+				if (renElement.material != nullptr && renElement.material->getShader() == nullptr)
+					renElement.material = nullptr;
+
+				// Validate mesh <-> shader vertex bindings
+				if (renElement.material != nullptr)
+				{
+					UINT32 numPasses = renElement.material->getNumPasses();
+					for (UINT32 j = 0; j < numPasses; j++)
+					{
+						SPtr<PassCore> pass = renElement.material->getPass(j);
+
+						SPtr<VertexDeclarationCore> shaderDecl = pass->getVertexProgram()->getInputDeclaration();
+						if (!vertexDecl->isCompatible(shaderDecl))
+						{
+							Vector<VertexElement> missingElements = vertexDecl->getMissingElements(shaderDecl);
+
+							StringStream wrnStream;
+							wrnStream << "Provided mesh is missing required vertex attributes to render with the provided shader. Missing elements: " << std::endl;
+
+							for (auto& entry : missingElements)
+								wrnStream << "\t" << toString(entry.getSemantic()) << entry.getSemanticIdx() << std::endl;
+
+							LOGWRN(wrnStream.str());
+							break;
+						}
+					}
+				}
+
+				// If no material use the default material
+				if (renElement.material == nullptr)
+					renElement.material = mDefaultMaterial->getMaterial();
+
+				auto iterFind = mSamplerOverrides.find(renElement.material);
+				if (iterFind != mSamplerOverrides.end())
+				{
+					renElement.samplerOverrides = iterFind->second;
+					iterFind->second->refCount++;
+				}
+				else
+				{
+					MaterialSamplerOverrides* samplerOverrides = SamplerOverrideUtility::generateSamplerOverrides(renElement.material, mCoreOptions);
+					mSamplerOverrides[renElement.material] = samplerOverrides;
+
+					renElement.samplerOverrides = samplerOverrides;
+					samplerOverrides->refCount++;
+				}
+
+				if (renderableData.controller != nullptr)
+					renderableData.controller->initializeRenderElem(renElement);
+			}
+		}
+	}
+
+	void RenderBeast::_notifyRenderableRemoved(RenderableCore* renderable)
+	{
+		UINT32 renderableId = renderable->getRendererId();
+		RenderableCore* lastRenerable = mRenderables.back().renderable;
+		UINT32 lastRenderableId = lastRenerable->getRendererId();
+
+		Vector<BeastRenderableElement>& elements = mRenderables[renderableId].elements;
+		for (auto& element : elements)
+		{
+			auto iterFind = mSamplerOverrides.find(element.material);
+			assert(iterFind != mSamplerOverrides.end());
+
+			MaterialSamplerOverrides* samplerOverrides = iterFind->second;
+			samplerOverrides->refCount--;
+			if (samplerOverrides->refCount == 0)
+			{
+				SamplerOverrideUtility::destroySamplerOverrides(samplerOverrides);
+				mSamplerOverrides.erase(iterFind);
+			}
+
+			element.samplerOverrides = nullptr;
+		}
+
+		if (renderableId != lastRenderableId)
+		{
+			// Swap current last element with the one we want to erase
+			std::swap(mRenderables[renderableId], mRenderables[lastRenderableId]);
+			std::swap(mWorldBounds[renderableId], mWorldBounds[lastRenderableId]);
+			std::swap(mRenderableShaderData[renderableId], mRenderableShaderData[lastRenderableId]);
+
+			lastRenerable->setRendererId(renderableId);
+
+			Vector<BeastRenderableElement>& lastRenderableElements = mRenderables[renderableId].elements;
+			for (auto& element : elements)
+				element.renderableId = renderableId;
+		}
+
+		// Last element is the one we want to erase
+		mRenderables.erase(mRenderables.end() - 1);
+		mWorldBounds.erase(mWorldBounds.end() - 1);
+		mRenderableShaderData.erase(mRenderableShaderData.end() - 1);
+	}
+
+	void RenderBeast::_notifyRenderableUpdated(RenderableCore* renderable)
+	{
+		UINT32 renderableId = renderable->getRendererId();
+
+		RenderableShaderData& shaderData = mRenderableShaderData[renderableId];
+		shaderData.worldTransform = renderable->getTransform();
+		shaderData.invWorldTransform = shaderData.worldTransform.inverseAffine();
+		shaderData.worldNoScaleTransform = renderable->getTransformNoScale();
+		shaderData.invWorldNoScaleTransform = shaderData.worldNoScaleTransform.inverseAffine();
+		shaderData.worldDeterminantSign = shaderData.worldTransform.determinant3x3() >= 0.0f ? 1.0f : -1.0f;
+
+		mWorldBounds[renderableId] = renderable->getBounds();
+	}
+
+	void RenderBeast::_notifyLightAdded(LightCore* light)
+	{
+		if (light->getType() == LightType::Directional)
+		{
+			UINT32 lightId = (UINT32)mDirectionalLights.size();
+			light->setRendererId(lightId);
+
+			mDirectionalLights.push_back(LightData());
+
+			LightData& lightData = mDirectionalLights.back();
+			lightData.internal = light;
+		}
+		else
+		{
+			UINT32 lightId = (UINT32)mPointLights.size();
+
+			light->setRendererId(lightId);
+
+			mPointLights.push_back(LightData());
+			mLightWorldBounds.push_back(light->getBounds());
+
+			LightData& lightData = mPointLights.back();
+			lightData.internal = light;
+		}
+	}
+
+	void RenderBeast::_notifyLightUpdated(LightCore* light)
+	{
+		UINT32 lightId = light->getRendererId();
+
+		if (light->getType() != LightType::Directional)
+			mLightWorldBounds[lightId] = light->getBounds();
+	}
+
+	void RenderBeast::_notifyLightRemoved(LightCore* light)
+	{
+		UINT32 lightId = light->getRendererId();
+		if (light->getType() == LightType::Directional)
+		{
+			LightCore* lastLight = mDirectionalLights.back().internal;
+			UINT32 lastLightId = lastLight->getRendererId();
+
+			if (lightId != lastLightId)
+			{
+				// Swap current last element with the one we want to erase
+				std::swap(mDirectionalLights[lightId], mDirectionalLights[lastLightId]);
+				lastLight->setRendererId(lightId);
+			}
+
+			// Last element is the one we want to erase
+			mDirectionalLights.erase(mDirectionalLights.end() - 1);
+		}
+		else
+		{
+			LightCore* lastLight = mPointLights.back().internal;
+			UINT32 lastLightId = lastLight->getRendererId();
+
+			if (lightId != lastLightId)
+			{
+				// Swap current last element with the one we want to erase
+				std::swap(mPointLights[lightId], mPointLights[lastLightId]);
+				std::swap(mLightWorldBounds[lightId], mLightWorldBounds[lastLightId]);
+
+				lastLight->setRendererId(lightId);
+			}
+
+			// Last element is the one we want to erase
+			mPointLights.erase(mPointLights.end() - 1);
+			mLightWorldBounds.erase(mLightWorldBounds.end() - 1);
+		}
+	}
+
+	void RenderBeast::_notifyCameraAdded(const CameraCore* camera)
+	{
+		SPtr<RenderTargetCore> renderTarget = camera->getViewport()->getTarget();
+		if (renderTarget == nullptr)
+			return;
+
+		CameraData& camData = mCameraData[camera];
+		camData.opaqueQueue = bs_shared_ptr_new<RenderQueue>(mCoreOptions->stateReductionMode);
+
+		StateReduction transparentStateReduction = mCoreOptions->stateReductionMode;
+		if (transparentStateReduction == StateReduction::Material)
+			transparentStateReduction = StateReduction::Distance; // Transparent object MUST be sorted by distance
+
+		camData.transparentQueue = bs_shared_ptr_new<RenderQueue>(transparentStateReduction);
+
+		// Register in render target list
+		auto findIter = std::find_if(mRenderTargets.begin(), mRenderTargets.end(), 
+			[&](const RenderTargetData& x) { return x.target == renderTarget; });
+
+		if (findIter != mRenderTargets.end())
+		{
+			findIter->cameras.push_back(camera);
+		}
+		else
+		{
+			mRenderTargets.push_back(RenderTargetData());
+			RenderTargetData& renderTargetData = mRenderTargets.back();
+
+			renderTargetData.target = renderTarget;
+			renderTargetData.cameras.push_back(camera);
+		}
+
+		// Sort render targets based on priority
+		auto cameraComparer = [&](const CameraCore* a, const CameraCore* b) { return a->getPriority() > b->getPriority(); };
+		auto renderTargetInfoComparer = [&](const RenderTargetData& a, const RenderTargetData& b)
+		{ return a.target->getProperties().getPriority() > b.target->getProperties().getPriority(); };
+		std::sort(begin(mRenderTargets), end(mRenderTargets), renderTargetInfoComparer);
+
+		for (auto& camerasPerTarget : mRenderTargets)
+		{
+			Vector<const CameraCore*>& cameras = camerasPerTarget.cameras;
+
+			std::sort(begin(cameras), end(cameras), cameraComparer);
+		}
+	}
+
+	void RenderBeast::_notifyCameraRemoved(const CameraCore* camera)
+	{
+		mCameraData.erase(camera);
+
+		// Remove from render target list
+		for (auto iterTarget = mRenderTargets.begin(); iterTarget != mRenderTargets.end(); ++iterTarget)
+		{
+			RenderTargetData& target = *iterTarget;
+			for (auto iterCam = target.cameras.begin(); iterCam != target.cameras.end(); ++iterCam)
+			{
+				if (camera == *iterCam)
+				{
+					target.cameras.erase(iterCam);
+					break;
+				}
+			}
+
+			if (target.cameras.empty())
+			{
+				mRenderTargets.erase(iterTarget);
+				break;
+			}
+		}
+	}
+
+	void RenderBeast::setOptions(const SPtr<CoreRendererOptions>& options)
+	{
+		mOptions = std::static_pointer_cast<RenderBeastOptions>(options);
+		mOptionsDirty = true;
+	}
+
+	SPtr<CoreRendererOptions> RenderBeast::getOptions() const
+	{
+		return mOptions;
+	}
+
+	void RenderBeast::renderAll() 
+	{
+		// Sync all dirty sim thread CoreObject data to core thread
+		CoreObjectManager::instance().syncToCore(gCoreAccessor());
+
+		if (mOptionsDirty)
+		{
+			gCoreAccessor().queueCommand(std::bind(&RenderBeast::syncRenderOptions, this, *mOptions));
+			mOptionsDirty = false;
+		}
+
+		gCoreAccessor().queueCommand(std::bind(&RenderBeast::renderAllCore, this, gTime().getTime()));
+	}
+
+	void RenderBeast::syncRenderOptions(const RenderBeastOptions& options)
+	{
+		bool filteringChanged = mCoreOptions->filtering != options.filtering;
+		if (options.filtering == RenderBeastFiltering::Anisotropic)
+			filteringChanged |= mCoreOptions->anisotropyMax != options.anisotropyMax;
+
+		if (filteringChanged)
+			refreshSamplerOverrides(true);
+
+		*mCoreOptions = options;
+
+		for (auto& cameraData : mCameraData)
+		{
+			cameraData.second.opaqueQueue->setStateReduction(mCoreOptions->stateReductionMode);
+
+			StateReduction transparentStateReduction = mCoreOptions->stateReductionMode;
+			if (transparentStateReduction == StateReduction::Material)
+				transparentStateReduction = StateReduction::Distance; // Transparent object MUST be sorted by distance
+
+			cameraData.second.transparentQueue->setStateReduction(transparentStateReduction);
+		}
+	}
+
+	void RenderBeast::renderAllCore(float time)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		gProfilerCPU().beginSample("renderAllCore");
+
+		// Note: I'm iterating over all sampler states every frame. If this ends up being a performance
+		// issue consider handling this internally in MaterialCore which can only do it when sampler states
+		// are actually modified after sync
+		refreshSamplerOverrides();
+
+		// Update global per-frame hardware buffers
+		mStaticHandler->updatePerFrameBuffers(time);
+
+		// Generate render queues per camera
+		for (auto& cameraData : mCameraData)
+		{
+			const CameraCore* camera = cameraData.first;
+			determineVisible(*camera);
+		}
+
+		// Render everything, target by target
+		for (auto& renderTargetData : mRenderTargets)
+		{
+			SPtr<RenderTargetCore> target = renderTargetData.target;
+			Vector<const CameraCore*>& cameras = renderTargetData.cameras;
+
+			RenderAPICore::instance().beginFrame();
+
+			UINT32 numCameras = (UINT32)cameras.size();
+			for (UINT32 i = 0; i < numCameras; i++)
+				render(renderTargetData, i);
+
+			RenderAPICore::instance().endFrame();
+			RenderAPICore::instance().swapBuffers(target);
+		}
+
+		gProfilerCPU().endSample("renderAllCore");
+	}
+
+	void RenderBeast::render(RenderTargetData& rtData, UINT32 camIdx)
+	{
+		gProfilerCPU().beginSample("Render");
+
+		const CameraCore* camera = rtData.cameras[camIdx];
+		CameraData& camData = mCameraData[camera];
+
+		SPtr<ViewportCore> viewport = camera->getViewport();
+		CameraShaderData cameraShaderData = getCameraShaderData(*camera);
+
+		mStaticHandler->updatePerCameraBuffers(cameraShaderData);
+
+		// Render scene objects to g-buffer
+		bool hasGBuffer = ((UINT32)camera->getFlags() & (UINT32)CameraFlags::Overlay) == 0;
+
+		if (hasGBuffer)
+		{
+			bool createGBuffer = camData.target == nullptr ||
+				camData.target->getHDR() != mCoreOptions->hdr ||
+				camData.target->getNumSamples() != mCoreOptions->msaa;
+
+			if (createGBuffer)
+				camData.target = RenderTargets::create(viewport, mCoreOptions->hdr, mCoreOptions->msaa);
+
+			camData.target->allocate();
+			camData.target->bindGBuffer();
+		}
+		else
+			camData.target = nullptr;
+
+		// Trigger pre-scene callbacks
+		auto iterCameraCallbacks = mRenderCallbacks.find(camera);
+		if (iterCameraCallbacks != mRenderCallbacks.end())
+		{
+			for (auto& callbackPair : iterCameraCallbacks->second)
+			{
+				const RenderCallbackData& callbackData = callbackPair.second;
+
+				if (callbackData.overlay)
+					continue;
+
+				if (callbackPair.first >= 0)
+					break;
+
+				callbackData.callback();
+			}
+		}
+		
+		if (hasGBuffer)
+		{
+			// Render base pass
+			const Vector<RenderQueueElement>& opaqueElements = camData.opaqueQueue->getSortedElements();
+			for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
+			{
+				BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
+				SPtr<MaterialCore> material = renderElem->material;
+
+				UINT32 rendererId = renderElem->renderableId;
+				Matrix4 worldViewProjMatrix = cameraShaderData.viewProj * mRenderableShaderData[rendererId].worldTransform;
+
+				mStaticHandler->updatePerObjectBuffers(*renderElem, mRenderableShaderData[rendererId], worldViewProjMatrix);
+				mStaticHandler->bindGlobalBuffers(*renderElem); // Note: If I can keep global buffer slot indexes the same between shaders I could only bind these once
+				mStaticHandler->bindPerObjectBuffers(*renderElem);
+
+				if (iter->applyPass)
+				{
+					SPtr<PassCore> pass = material->getPass(iter->passIdx);
+					setPass(pass);
+				}
+
+				SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
+
+				if (renderElem->samplerOverrides != nullptr)
+					setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
+				else
+					setPassParams(passParams, nullptr);
+
+				gRendererUtility().draw(iter->renderElem->mesh, iter->renderElem->subMesh);
+			}
+
+			camData.target->bindSceneColor();
+
+			// Render light pass
+			SPtr<MaterialCore> dirMaterial = mDirLightMat->getMaterial();
+			SPtr<PassCore> dirPass = dirMaterial->getPass(0);
+
+			setPass(dirPass);
+			mDirLightMat->setGBuffer(camData.target);
+
+			for (auto& light : mDirectionalLights)
+			{
+				if (!light.internal->getIsActive())
+					continue;
+
+				mDirLightMat->setParameters(light.internal);
+
+				// TODO - Bind parameters to the pipeline manually as I don't need to re-bind gbuffer textures for every light
+				setPassParams(dirMaterial->getPassParameters(0), nullptr);
+				gRendererUtility().drawScreenQuad(*viewport);
+			}
+
+			SPtr<MaterialCore> pointMaterial = mPointLightMat->getMaterial();
+			SPtr<PassCore> pointPass = pointMaterial->getPass(0);
+
+			setPass(pointPass);
+			mPointLightMat->setGBuffer(camData.target);
+
+			// TODO - Cull lights based on visibility, right now I just iterate over all of them. 
+			for (auto& light : mPointLights)
+			{
+				if (!light.internal->getIsActive())
+					continue;
+
+				mPointLightMat->setParameters(light.internal);
+
+				// TODO - Bind parameters to the pipeline manually as I don't need to re-bind gbuffer textures for every light
+				setPassParams(dirMaterial->getPassParameters(0), nullptr);
+				SPtr<MeshCore> mesh = light.internal->getMesh();
+				gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
+			}
+		}
+		else
+		{
+			// Prepare final render target
+			SPtr<RenderTargetCore> target = rtData.target;
+
+			RenderAPICore::instance().setRenderTarget(target);
+			RenderAPICore::instance().setViewport(viewport->getNormArea());
+
+			// If first camera in render target, prepare the render target
+			if (camIdx == 0)
+			{
+				UINT32 clearBuffers = 0;
+				if (viewport->getRequiresColorClear())
+					clearBuffers |= FBT_COLOR;
+
+				if (viewport->getRequiresDepthClear())
+					clearBuffers |= FBT_DEPTH;
+
+				if (viewport->getRequiresStencilClear())
+					clearBuffers |= FBT_STENCIL;
+
+				if (clearBuffers != 0)
+				{
+					RenderAPICore::instance().clearViewport(clearBuffers, viewport->getClearColor(),
+						viewport->getClearDepthValue(), viewport->getClearStencilValue());
+				}
+			}
+		}
+
+		// Render transparent objects (TODO - No lighting yet)
+		const Vector<RenderQueueElement>& transparentElements = camData.transparentQueue->getSortedElements();
+		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
+		{
+			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
+			SPtr<MaterialCore> material = renderElem->material;
+
+			UINT32 rendererId = renderElem->renderableId;
+			Matrix4 worldViewProjMatrix = cameraShaderData.viewProj * mRenderableShaderData[rendererId].worldTransform;
+
+			mStaticHandler->updatePerObjectBuffers(*renderElem, mRenderableShaderData[rendererId], worldViewProjMatrix);
+			mStaticHandler->bindGlobalBuffers(*renderElem); // Note: If I can keep global buffer slot indexes the same between shaders I could only bind these once
+			mStaticHandler->bindPerObjectBuffers(*renderElem);
+
+			if (iter->applyPass)
+			{
+				SPtr<PassCore> pass = material->getPass(iter->passIdx);
+				setPass(pass);
+			}
+
+			SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
+
+			if (renderElem->samplerOverrides != nullptr)
+				setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
+			else
+				setPassParams(passParams, nullptr);
+
+			gRendererUtility().draw(iter->renderElem->mesh, iter->renderElem->subMesh);
+		}
+
+		camData.opaqueQueue->clear();
+		camData.transparentQueue->clear();
+
+		// Render non-overlay post-scene callbacks
+		if (iterCameraCallbacks != mRenderCallbacks.end())
+		{
+			for (auto& callbackPair : iterCameraCallbacks->second)
+			{
+				const RenderCallbackData& callbackData = callbackPair.second;
+
+				if (callbackData.overlay || callbackPair.first < 0)
+					continue;
+
+				callbackData.callback();
+			}
+		}
+
+		if (hasGBuffer)
+		{
+			// TODO - Instead of doing a separate resolve here I could potentially perform a resolve directly in the
+			// light pass.
+			camData.target->resolve();
+		}
+
+		// Render overlay post-scene callbacks
+		if (iterCameraCallbacks != mRenderCallbacks.end())
+		{
+			for (auto& callbackPair : iterCameraCallbacks->second)
+			{
+				const RenderCallbackData& callbackData = callbackPair.second;
+
+				if (!callbackData.overlay)
+					continue;
+
+				callbackData.callback();
+			}
+		}
+
+		if (hasGBuffer)
+			camData.target->release();
+
+		gProfilerCPU().endSample("Render");
+	}
+	
+	void RenderBeast::determineVisible(const CameraCore& camera)
+	{
+		CameraData& cameraData = mCameraData[&camera];
+
+		UINT64 cameraLayers = camera.getLayers();
+		ConvexVolume worldFrustum = camera.getWorldFrustum();
+
+		// Update per-object param buffers and queue render elements
+		for (auto& renderableData : mRenderables)
+		{
+			RenderableCore* renderable = renderableData.renderable;
+			RenderableHandler* controller = renderableData.controller;
+			UINT32 renderableType = renderable->getRenderableType();
+			UINT32 rendererId = renderable->getRendererId();
+
+			if ((renderable->getLayer() & cameraLayers) == 0)
+				continue;
+
+			// Do frustum culling
+			// TODO - This is bound to be a bottleneck at some point. When it is ensure that intersect
+			// methods use vector operations, as it is trivial to update them.
+			const Sphere& boundingSphere = mWorldBounds[rendererId].getSphere();
+			if (worldFrustum.intersects(boundingSphere))
+			{
+				// More precise with the box
+				const AABox& boundingBox = mWorldBounds[rendererId].getBox();
+
+				if (worldFrustum.intersects(boundingBox))
+				{
+					float distanceToCamera = (camera.getPosition() - boundingBox.getCenter()).length();
+
+					for (auto& renderElem : renderableData.elements)
+					{
+						bool isTransparent = (renderElem.material->getShader()->getFlags() & (UINT32)ShaderFlags::Transparent) != 0;
+
+						if (isTransparent)
+							cameraData.transparentQueue->add(&renderElem, distanceToCamera);
+						else
+							cameraData.opaqueQueue->add(&renderElem, distanceToCamera);
+					}
+
+				}
+			}
+		}
+
+		cameraData.opaqueQueue->sort();
+		cameraData.transparentQueue->sort();
+	}
+
+	Vector2 RenderBeast::getDeviceZTransform(const Matrix4& projMatrix)
+	{
+		Vector2 output;
+		output.x = 1.0f / projMatrix[2][2];
+		output.y = projMatrix[2][3] / projMatrix[2][2];
+
+		return output;
+	}
+
+	CameraShaderData RenderBeast::getCameraShaderData(const CameraCore& camera)
+	{
+		CameraShaderData data;
+		data.proj = camera.getProjectionMatrixRS();
+		data.view = camera.getViewMatrix();
+		data.viewProj = data.proj * data.view;
+		data.invProj = data.proj.inverse();
+		data.viewDir = camera.getForward();
+		data.viewOrigin = camera.getPosition();
+		data.deviceZToWorldZ = getDeviceZTransform(data.proj);
+
+		SPtr<ViewportCore> viewport = camera.getViewport();
+		SPtr<RenderTargetCore> rt = viewport->getTarget();
+
+		float halfWidth = viewport->getWidth() / 2.0f;
+		float halfHeight = viewport->getHeight() / 2.0f;
+
+		float rtWidth = (float)rt->getProperties().getWidth();
+		float rtHeight = (float)rt->getProperties().getHeight();
+
+		RenderAPICore& rapi = RenderAPICore::instance();
+
+		data.clipToUVScaleOffset.x = (halfWidth / 2.0f) / rtWidth;
+		data.clipToUVScaleOffset.y = (halfHeight / 2.0f) / rtHeight;
+		data.clipToUVScaleOffset.z = (viewport->getX() + halfWidth + rapi.getHorizontalTexelOffset()) / rtWidth;
+		data.clipToUVScaleOffset.w = (viewport->getY() + halfHeight + rapi.getHorizontalTexelOffset()) / rtHeight;
+
+		return data;
+	}
+
+	void RenderBeast::refreshSamplerOverrides(bool force)
+	{
+		for (auto& entry : mSamplerOverrides)
+		{
+			SPtr<MaterialCore> material = entry.first;
+
+			if (force)
+			{
+				SamplerOverrideUtility::destroySamplerOverrides(entry.second);
+				entry.second = SamplerOverrideUtility::generateSamplerOverrides(material, mCoreOptions);
+			}
+			else
+			{
+				MaterialSamplerOverrides* materialOverrides = entry.second;
+				UINT32 numPasses = material->getNumPasses();
+
+				assert(numPasses == materialOverrides->numPasses);
+				for (UINT32 i = 0; i < numPasses; i++)
+				{
+					SPtr<PassParametersCore> passParams = material->getPassParameters(i);
+					PassSamplerOverrides& passOverrides = materialOverrides->passes[i];
+
+					for (UINT32 j = 0; j < PassParametersCore::NUM_PARAMS; j++)
+					{
+						StageSamplerOverrides& stageOverrides = passOverrides.stages[j];
+
+						SPtr<GpuParamsCore> params = passParams->getParamByIdx(j);
+						if (params == nullptr)
+							continue;
+
+						const GpuParamDesc& paramDesc = params->getParamDesc();
+
+						for (auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
+						{
+							UINT32 slot = iter->second.slot;
+							SPtr<SamplerStateCore> samplerState = params->getSamplerState(slot);
+
+							assert(stageOverrides.numStates > slot);
+
+							if (samplerState != stageOverrides.stateOverrides[slot])
+							{
+								if (samplerState != nullptr)
+									stageOverrides.stateOverrides[slot] = SamplerOverrideUtility::generateSamplerOverride(samplerState, mCoreOptions);
+								else
+									stageOverrides.stateOverrides[slot] = SamplerOverrideUtility::generateSamplerOverride(SamplerStateCore::getDefault(), mCoreOptions);;
+							}	
+						}
+					}
+				}
+			}
+		}
+	}
+
+	void RenderBeast::setPass(const SPtr<PassCore>& pass)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		RenderAPICore& rs = RenderAPICore::instance();
+
+		struct StageData
+		{
+			GpuProgramType type;
+			bool enable;
+			SPtr<GpuProgramCore> program;
+		};
+
+		const UINT32 numStages = 6;
+		StageData stages[numStages] =
+		{
+			{ GPT_VERTEX_PROGRAM, pass->hasVertexProgram(), pass->getVertexProgram() },
+			{ GPT_FRAGMENT_PROGRAM, pass->hasFragmentProgram(), pass->getFragmentProgram() },
+			{ GPT_GEOMETRY_PROGRAM, pass->hasGeometryProgram(), pass->getGeometryProgram() },
+			{ GPT_HULL_PROGRAM, pass->hasHullProgram(), pass->getHullProgram() },
+			{ GPT_DOMAIN_PROGRAM, pass->hasDomainProgram(), pass->getDomainProgram() },
+			{ GPT_COMPUTE_PROGRAM, pass->hasComputeProgram(), pass->getComputeProgram() }
+		};
+
+		for (UINT32 i = 0; i < numStages; i++)
+		{
+			const StageData& stage = stages[i];
+
+			if (stage.enable)
+				rs.bindGpuProgram(stage.program);
+			else
+				rs.unbindGpuProgram(stage.type);
+		}
+
+		// Set up non-texture related pass settings
+		if (pass->getBlendState() != nullptr)
+			rs.setBlendState(pass->getBlendState());
+		else
+			rs.setBlendState(BlendStateCore::getDefault());
+
+		if (pass->getDepthStencilState() != nullptr)
+			rs.setDepthStencilState(pass->getDepthStencilState(), pass->getStencilRefValue());
+		else
+			rs.setDepthStencilState(DepthStencilStateCore::getDefault(), pass->getStencilRefValue());
+
+		if (pass->getRasterizerState() != nullptr)
+			rs.setRasterizerState(pass->getRasterizerState());
+		else
+			rs.setRasterizerState(RasterizerStateCore::getDefault());
+	}
+
+	void RenderBeast::setPassParams(const SPtr<PassParametersCore>& passParams, const PassSamplerOverrides* samplerOverrides)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		RenderAPICore& rs = RenderAPICore::instance();
+
+		struct StageData
+		{
+			GpuProgramType type;
+			SPtr<GpuParamsCore> params;
+		};
+
+		const UINT32 numStages = 6;
+		StageData stages[numStages] =
+		{
+			{ GPT_VERTEX_PROGRAM, passParams->mVertParams },
+			{ GPT_FRAGMENT_PROGRAM, passParams->mFragParams },
+			{ GPT_GEOMETRY_PROGRAM, passParams->mGeomParams },
+			{ GPT_HULL_PROGRAM, passParams->mHullParams },
+			{ GPT_DOMAIN_PROGRAM, passParams->mDomainParams },
+			{ GPT_COMPUTE_PROGRAM, passParams->mComputeParams }
+		};
+
+		for (UINT32 i = 0; i < numStages; i++)
+		{
+			const StageData& stage = stages[i];
+
+			SPtr<GpuParamsCore> params = stage.params;
+			if (params == nullptr)
+				continue;
+
+			const GpuParamDesc& paramDesc = params->getParamDesc();
+
+			for (auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter)
+			{
+				SPtr<SamplerStateCore> samplerState;
+
+				if (samplerOverrides != nullptr)
+					samplerState = samplerOverrides->stages[i].stateOverrides[iter->second.slot];
+				else
+					samplerState = params->getSamplerState(iter->second.slot);
+
+				if (samplerState == nullptr)
+					rs.setSamplerState(stage.type, iter->second.slot, SamplerStateCore::getDefault());
+				else
+					rs.setSamplerState(stage.type, iter->second.slot, samplerState);
+			}
+
+			for (auto iter = paramDesc.textures.begin(); iter != paramDesc.textures.end(); ++iter)
+			{
+				SPtr<TextureCore> texture = params->getTexture(iter->second.slot);
+
+				if (!params->isLoadStoreTexture(iter->second.slot))
+				{
+					if (texture == nullptr)
+						rs.setTexture(stage.type, iter->second.slot, false, nullptr);
+					else
+						rs.setTexture(stage.type, iter->second.slot, true, texture);
+				}
+				else
+				{
+					const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
+
+					if (texture == nullptr)
+						rs.setLoadStoreTexture(stage.type, iter->second.slot, false, nullptr, surface);
+					else
+						rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface);
+				}
+			}
+
+			rs.setConstantBuffers(stage.type, params);
+		}
+	}
 }