Ver código fonte

More work on Lights

Marko Pintera 10 anos atrás
pai
commit
afca99b5e8

+ 0 - 16
BansheeCore/Include/BsCoreRenderer.h

@@ -82,22 +82,6 @@ namespace BansheeEngine
 		 */
 		virtual void _notifyCameraRemoved(const CameraHandlerCore* camera) { }
 
-		/**
-		 * @brief	Called whenever a new light is created.
-		 *
-		 * @note	Core thread.
-		 *			Internal method.
-		 */
-		virtual void _notifyLightAdded(const LightInternalCore* light) { }
-
-		/**
-		 * @brief	Called whenever a light is destroyed.
-		 *
-		 * @note	Core thread.
-		 *			Internal method.
-		 */
-		virtual void _notifyLightRemoved(const LightInternalCore* light) { }
-
 		/**
 		 * @brief	Creates a new empty renderer mesh data.
 		 *

+ 82 - 6
BansheeEngine/Include/BsLight.h

@@ -7,45 +7,121 @@
 namespace BansheeEngine 
 {
 	/**
-	 * @copydoc	LightInternal
+	 * @copydoc	Component wrapper for LightInternal
+	 *
+	 * @see	LightInternal
 	 */
     class BS_EXPORT Light : public Component
     {
     public:
 		Light(const HSceneObject& parent, LightType type = LightType::Point, Color color = Color::White, 
-			float luminousFlux = 100.0f, float range = 1.0f, bool castsShadows = false, Degree spotAngle = Degree(45));
+			float intensity = 100.0f, float range = 1.0f, bool castsShadows = false, Degree spotAngle = Degree(45), 
+			Degree spotFalloffAngle = Degree(40));
 
 		virtual ~Light();
 
+	    /**
+		 * @copydoc	Component::onInitialized
+	     */
+		void onInitialized() override;
+
+	    /**
+		 * @copydoc	Component::onDestroyed
+	     */
+		void onDestroyed() override;
+
+	    /**
+		 * @copydoc	LightInternal::getPosition
+	     */
 		Vector3 getPosition() const { return mInternal->getPosition(); }
+
+	    /**
+		 * @copydoc	LightInternal::setPosition
+	     */
 		void setPosition(const Vector3& position) { mInternal->setPosition(position); }
 
+	    /**
+		 * @copydoc	LightInternal::getRotation
+	     */
 		Quaternion getRotation() const { return mInternal->getRotation(); }
+
+	    /**
+		 * @copydoc	LightInternal::setRotation
+	     */
 		void setRotation(const Quaternion& rotation) { mInternal->setRotation(rotation); }
 
+	    /**
+		 * @copydoc	LightInternal::getType
+	     */
 		LightType getType() const { return mInternal->getType(); }
+
+	    /**
+		 * @copydoc	LightInternal::setType
+	     */
 		void setType(LightType type) { mInternal->setType(type); }
 
+	    /**
+		 * @copydoc	LightInternal::getCastsShadow
+	     */
 		bool getCastsShadow() const { return mInternal->getCastsShadow(); }
+
+	    /**
+		 * @copydoc	LightInternal::setCastsShadow
+	     */
 		void setCastsShadow(bool castsShadow) { mInternal->setCastsShadow(castsShadow); }
 
+	    /**
+		 * @copydoc	LightInternal::getColor
+	     */
 		Color getColor() const { return mInternal->getColor(); }
+
+	    /**
+		 * @copydoc	LightInternal::setColor
+	     */
 		void setColor(const Color& color) { mInternal->setColor(color); }
 
+	    /**
+		 * @copydoc	LightInternal::getRange
+	     */
 		float getRange() const { return mInternal->getRange(); }
+
+	    /**
+		 * @copydoc	LightInternal::setRange
+	     */
 		void setRange(float range) { mInternal->setRange(range);; }
 
-		float getLuminousFlux() const { return mInternal->getLuminousFlux(); }
-		void setLuminousFlux(float luminousFlux) { mInternal->setLuminousFlux(luminousFlux); }
+	    /**
+		 * @copydoc	LightInternal::getIntensity
+	     */
+		float getIntensity() const { return mInternal->getIntensity(); }
+
+	    /**
+		 * @copydoc	LightInternal::setIntensity
+	     */
+		void setIntensity(float intensity) { mInternal->setIntensity(intensity); }
 
+	    /**
+		 * @copydoc	LightInternal::getSpotAngle
+	     */
 		Degree getSpotAngle() const { return mInternal->getSpotAngle(); }
+
+	    /**
+		 * @copydoc	LightInternal::setSpotAngle
+	     */
 		void setSpotAngle(const Degree& spotAngle) { mInternal->setSpotAngle(spotAngle); }
 
+	    /**
+		 * @copydoc	LightInternal::getBounds
+	     */
+		Sphere getBounds() const;
+
+	    /**
+		 * @brief	Returns the light internals that this component wraps.
+	     */
 		SPtr<LightInternal> _getInternal() const { return mInternal; }
 
     protected:
 		mutable SPtr<LightInternal> mInternal;
-		mutable UINT32 mLastUpdateHash;
 
 		/************************************************************************/
 		/* 						COMPONENT OVERRIDES                      		*/
@@ -65,7 +141,7 @@ namespace BansheeEngine
 	public:
 		friend class LightRTTI;
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const;
+		virtual RTTITypeBase* getRTTI() const override;
 
 	protected:
 		Light() {} // Serialization only

+ 182 - 22
BansheeEngine/Include/BsLightInternal.h

@@ -5,6 +5,7 @@
 #include "BsVector3.h"
 #include "BsQuaternion.h"
 #include "BsColor.h"
+#include "BsSphere.h"
 #include "BsCoreObject.h"
 
 namespace BansheeEngine
@@ -20,58 +21,172 @@ namespace BansheeEngine
 		Spot
 	};
 
+	/**
+	 * @brief	Signals which portion of a LightInternal is dirty.
+	 */
+	enum class LightDirtyFlag
+	{
+		Transform = 0x01,
+		Everything = 0x02
+	};
+
 	class BS_EXPORT LightInternalBase
 	{
 	public:
 		LightInternalBase();
-		LightInternalBase(LightType type, Color color,
-			float luminousFlux, float range, bool castsShadows, Degree spotAngle);
+		LightInternalBase(LightType type, Color color, float intensity, float range, 
+			bool castsShadows, Degree spotAngle, Degree spotFalloffAngle);
 
 		virtual ~LightInternalBase() { }
 
+		/**
+		 * @brief	Returns the position of the light, in world space.
+		 */
 		Vector3 getPosition() const { return mPosition; }
-		void setPosition(const Vector3& position) { mPosition = position; _markCoreDirty(); }
 
+		/**
+		 * @brief	Sets the position of the light, in world space.
+		 */
+		void setPosition(const Vector3& position) { mPosition = position; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Returns the rotation of the light, in world space.
+		 */
 		Quaternion getRotation() const { return mRotation; }
-		void setRotation(const Quaternion& rotation) { mRotation = rotation; _markCoreDirty(); }
 
+		/**
+		 * @brief	Sets the rotation of the light, in world space.
+		 */
+		void setRotation(const Quaternion& rotation) { mRotation = rotation; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Returns the type of the light.
+		 */
 		LightType getType() const { return mType; }
-		void setType(LightType type) { mType = type; _markCoreDirty(); }
 
+		/**
+		 * @brief	Changes the type of the light.
+		 */
+		void setType(LightType type) { mType = type; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Checks does this light cast shadows when rendered.
+		 */
 		bool getCastsShadow() const { return mCastsShadows; }
+
+		/**
+		 * @brief	Sets whether this light will cast shadows when rendered.
+		 */
 		void setCastsShadow(bool castsShadow) { mCastsShadows = castsShadow; _markCoreDirty(); }
 
+		/**
+		 * @brief	Returns the color emitted from the light.
+		 */
 		Color getColor() const { return mColor; }
+
+		/**
+		 * @brief	Sets the color emitted from the light.
+		 */
 		void setColor(const Color& color) { mColor = color; _markCoreDirty(); }
 
+		/**
+		 * @brief	Returns the maximum range of the light. Light will not affect any geometry past that point.
+		 */
 		float getRange() const { return mRange; }
-		void setRange(float range) { mRange = range; _markCoreDirty(); }
 
-		float getLuminousFlux() const { return mLuminousFlux; }
-		void setLuminousFlux(float luminousFlux) { mLuminousFlux = luminousFlux; _markCoreDirty(); }
+		/**
+		 * @brief	Returns the maximum range of the light. Light will not affect any geometry past that point.
+		 *
+		 * @note	Normally you want to set this at a point where light intensity is too low due to attenuation.
+		 */
+		void setRange(float range) { mRange = range; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Gets the power of the light source. This will be luminous flux for point & spot lights, 
+		 *			and radiance for directional lights.
+		 */
+		float getIntensity() const { return mIntensity; }
+
+		/**
+		 * @brief	Sets the power of the light source. This will be luminous flux for point & spot lights, 
+		 *			and radiance for directional lights.
+		 */
+		void setIntensity(float intensity) { mIntensity = intensity; _markCoreDirty(); }
 
+		/**
+		 * @brief	Gets the total angle covered by a spot light.
+		 */
 		Degree getSpotAngle() const { return mSpotAngle; }
-		void setSpotAngle(const Degree& spotAngle) { mSpotAngle = spotAngle; _markCoreDirty(); }
+
+		/**
+		 * @brief	Sets the total angle covered by a spot light.
+		 */
+		void setSpotAngle(const Degree& spotAngle) { mSpotAngle = spotAngle; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Gets the falloff angle covered by a spot light. Falloff angle determines at what point does light intensity
+		 *			starts linearly falling off as the angle approaches the total spot angle.
+		 */
+		Degree getSpotFalloffAngle() const { return mSpotFalloffAngle; }
+
+		/**
+		 * @brief	Sets the falloff angle covered by a spot light. Falloff angle determines at what point does light intensity
+		 *			starts linearly falling off as the angle approaches the total spot angle.
+		 */
+		void setSpotFalloffAngle(const Degree& spotFallofAngle) { mSpotFalloffAngle = spotFallofAngle; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Returns world space bounds that completely encompass the lights area of influence.
+		 */
+		Sphere getBounds() const { return mBounds; }
+
+		/**
+		 * @brief	Returns the radiance of the light source. This is the value that should be used in lighting equations.
+		 *
+		 * @note	Ignores the light direction, therefore caller must ensure to properly handle non-uniform emitters like spot lights
+		 */
+		float getRadiance() const;
+
+		/**
+		 * @brief	Checks whether the light should be rendered or not.
+		 */
+		bool getIsActive() const { return mIsActive; }
+
+		/**
+		 * @brief	Sets whether the light should be rendered or not.
+		 */
+		void setIsActive(bool active) { mIsActive = active; _markCoreDirty(); }
 
 		/**
 		 * @copydoc	CoreObject::markCoreDirty
 		 */
-		virtual void _markCoreDirty() { }
+		virtual void _markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything) { }
 
 	protected:
+		/**
+		 * @brief	Updates the internal bounds for the light. Call this whenever a property affecting
+		 *			the bounds changes.
+		 */
+		void updateBounds();
+
 		Vector3 mPosition; /**< World space position. */
 		Quaternion mRotation; /**< World space rotation. */
 
 		LightType mType; /**< Type of light that determines how are the rest of the parameters interpreted. */
 		bool mCastsShadows; /**< Determines whether the light casts shadows. */
 		Color mColor; /**< Color of the light. */
-		float mRange; /**< Cut off range for the light when rendering. Visibly the light attenuation and intensity determines the range. */
-		float mLuminousFlux; /**< Intensity of the light source. */
-		Degree mSpotAngle; /**< Angle covered by a spot light. */
+		float mRange; /**< Cut off range for the light when rendering. */
+		float mIntensity; /**< Power of the light source. This will be luminous flux for point & spot lights, and radiance for directional lights. */
+		Degree mSpotAngle; /**< Total angle covered by a spot light. */
+		Degree mSpotFalloffAngle; /**< Spot light angle at which falloff starts. Must be smaller than total angle. */
+		bool mIsActive; /**< Whether the light should be rendered or not. */
+		Sphere mBounds; /**< Sphere that bounds the light area of influence. */
 	};
 
 	/**
-	 * @copydoc	LightInternalBase
+	 * @brief	Core thread usable version of a light.
+	 *
+	 * @see		LightInternalBase
 	 */
 	class BS_EXPORT LightInternalCore : public CoreObjectCore, public LightInternalBase
 	{
@@ -81,8 +196,8 @@ namespace BansheeEngine
 	protected:
 		friend class LightInternal;
 
-		LightInternalCore(LightType type, Color color,
-			float luminousFlux, float range, bool castsShadows, Degree spotAngle);
+		LightInternalCore(LightType type, Color color, float intensity, 
+			float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle);
 
 		/**
 		 * @copydoc	CoreObjectCore::initialize
@@ -96,19 +211,59 @@ namespace BansheeEngine
 	};
 
 	/**
-	 * @copydoc	CameraHandlerBase
+	 * @brief	Sim thread usable version of a light.
+	 *
+	 * @see		LightInternalBase
 	 */
 	class BS_EXPORT LightInternal : public IReflectable, public CoreObject, public LightInternalBase
 	{
 	public:
+		/**
+		 * @brief	Retrieves an implementation of a light usable only from the core thread.
+		 */
 		SPtr<LightInternalCore> getCore() const;
 
+		/**
+	     * @brief	Returns the hash value that can be used to identify if the internal data needs an update.
+		 *
+		 * @note	Internal method.
+		 */
+		UINT32 _getLastModifiedHash() const { return mLastUpdateHash; }
+
+		/**
+	     * @brief	Sets the hash value that can be used to identify if the internal data needs an update.
+		 *
+		 * @note	Internal method.
+		 */
+		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
+
+		/**
+		 * @brief	Updates internal transform values from the specified scene object, in case that scene
+		 *			object's transform changed since the last call.
+		 *
+		 * @note	Assumes the same scene object will be provided every time.
+		 */
+		void _updateTransform(const HSceneObject& parent);
+
+		/**
+		 * @brief	Creates a new light with provided settings.
+		 *
+		 * @param	type				Type of light that determines how are the rest of the parameters interpreted.
+		 * @param	color				Color of the light.
+		 * @param	intensity			Power of the light source. This will be luminous flux for point & spot lights, 
+		 *								and radiance for directional lights.
+		 * @param	range				Cut off range for the light when rendering.
+		 * @param	castsShadows		Determines whether the light casts shadows.
+		 * @param	spotAngle			Total angle covered by a spot light.
+		 * @param	spotFalloffAngle	Spot light angle at which falloff starts. Must be smaller than total angle.
+		 */
 		static SPtr<LightInternal> create(LightType type = LightType::Point, Color color = Color::White,
-			float luminousFlux = 100.0f, float range = 1.0f, bool castsShadows = false, Degree spotAngle = Degree(45));
+			float intensity = 100.0f, float range = 10.0f, bool castsShadows = false,
+			Degree spotAngle = Degree(45), Degree spotFalloffAngle = Degree(40));
 
 	protected:
-		LightInternal(LightType type, Color color,
-			float luminousFlux, float range, bool castsShadows, Degree spotAngle);
+		LightInternal(LightType type, Color color, float intensity, float range, 
+			bool castsShadows, Degree spotAngle, Degree spotFalloffAngle);
 
 		/**
 		 * @copydoc	CoreObject::createCore
@@ -118,15 +273,20 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	CoreObject::markCoreDirty
 		 */
-		void _markCoreDirty() override;
+		void _markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything) override;
 
 		/**
 		 * @copydoc	CoreObject::syncToCore
 		 */
 		CoreSyncData syncToCore(FrameAlloc* allocator) override;
 
+		/**
+		 * @brief	Creates a light with without initializing it. Used for serialization.
+		 */
 		static SPtr<LightInternal> createEmpty();
 
+		UINT32 mLastUpdateHash;
+
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/************************************************************************/
@@ -136,6 +296,6 @@ namespace BansheeEngine
 		virtual RTTITypeBase* getRTTI() const override;
 
 	protected:
-		LightInternal() {} // Serialization only
+		LightInternal(); // Serialization only
 	};
 }

+ 7 - 3
BansheeEngine/Include/BsLightInternalRTTI.h

@@ -27,11 +27,14 @@ namespace BansheeEngine
 		float& getRange(LightInternal* obj) { return obj->mRange; }
 		void setRange(LightInternal* obj, float& range) { obj->mRange = range; }
 
-		float& getLuminousFlux(LightInternal* obj) { return obj->mLuminousFlux; }
-		void setLuminousFlux(LightInternal* obj, float& luminousFlux) { obj->mLuminousFlux = luminousFlux; }
+		float& getIntensity(LightInternal* obj) { return obj->mIntensity; }
+		void setIntensity(LightInternal* obj, float& intensity) { obj->mIntensity = intensity; }
 
 		Degree& getSpotAngle(LightInternal* obj) { return obj->mSpotAngle; }
 		void setSpotAngle(LightInternal* obj, Degree& spotAngle) { obj->mSpotAngle = spotAngle; }
+
+		Degree& getSpotFalloffAngle(LightInternal* obj) { return obj->mSpotFalloffAngle; }
+		void setSpotFalloffAngle(LightInternal* obj, Degree& spotAngle) { obj->mSpotFalloffAngle = spotAngle; }
 	public:
 		LightInternalRTTI()
 		{
@@ -41,8 +44,9 @@ namespace BansheeEngine
 			addPlainField("mCastsShadow", 3, &LightInternalRTTI::getCastsShadow, &LightInternalRTTI::setCastsShadow);
 			addPlainField("mColor", 4, &LightInternalRTTI::getColor, &LightInternalRTTI::setColor);
 			addPlainField("mRange", 5, &LightInternalRTTI::getRange, &LightInternalRTTI::setRange);
-			addPlainField("mLuminousFlux", 6, &LightInternalRTTI::getLuminousFlux, &LightInternalRTTI::setLuminousFlux);
+			addPlainField("mIntensity", 6, &LightInternalRTTI::getIntensity, &LightInternalRTTI::setIntensity);
 			addPlainField("mSpotAngle", 7, &LightInternalRTTI::getSpotAngle, &LightInternalRTTI::setSpotAngle);
+			addPlainField("mSpotFalloffAngle", 8, &LightInternalRTTI::getSpotFalloffAngle, &LightInternalRTTI::setSpotFalloffAngle);
 		}
 
 		virtual void onDeserializationEnded(IReflectable* obj) override

+ 24 - 0
BansheeEngine/Include/BsRenderer.h

@@ -36,6 +36,30 @@ namespace BansheeEngine
 		 *			Internal method.
 		 */
 		virtual void _notifyRenderableRemoved(RenderableHandlerCore* renderable) { }
+
+		/**
+		 * @brief	Called whenever a new light is created.
+		 *
+		 * @note	Core thread.
+		 *			Internal method.
+		 */
+		virtual void _notifyLightAdded(const LightInternalCore* light) { }
+
+		/**
+		 * @brief	Called whenever a light is updated.
+		 *
+		 * @note	Core thread.
+		 *			Internal method.
+		 */
+		virtual void _notifyLightUpdated(const LightInternalCore* light) { }
+
+		/**
+		 * @brief	Called whenever a light is destroyed.
+		 *
+		 * @note	Core thread.
+		 *			Internal method.
+		 */
+		virtual void _notifyLightRemoved(const LightInternalCore* light) { }
 	};
 
 	/**

+ 30 - 0
BansheeEngine/Include/BsSceneManager.h

@@ -35,6 +35,21 @@ namespace BansheeEngine
 		HSceneObject sceneObject;
 	};
 
+	/**
+	 * @brief	Contains information about a light managed by the scene manager.
+	 */
+	struct SceneLightData
+	{
+		SceneLightData() { }
+
+		SceneLightData(const SPtr<LightInternal>& light, const HSceneObject& sceneObject)
+			:light(light), sceneObject(sceneObject)
+		{ }
+
+		SPtr<LightInternal> light;
+		HSceneObject sceneObject;
+	};
+
 	/**
 	 * @brief	Manages active SceneObjects and provides ways for querying
 	 *			and updating them or their components.
@@ -101,6 +116,20 @@ namespace BansheeEngine
 		 */
 		void _unregisterCamera(const SPtr<CameraHandler>& camera);
 
+		/**
+		 * @brief	Notifies the scene manager that a new light was created.
+		 *
+		 * @note	Internal method.
+		 */
+		void _registerLight(const SPtr<LightInternal>& light, const HSceneObject& so);
+
+		/**
+		 * @brief	Notifies the scene manager that a light was removed.
+		 *
+		 * @note	Internal method.
+		 */
+		void _unregisterLight(const SPtr<LightInternal>& light);
+
 		/**
 		 * @copydoc	CoreSceneManager::_updateCoreObjectTransforms
 		 */
@@ -119,6 +148,7 @@ namespace BansheeEngine
 	private:
 		Map<CameraHandler*, SceneCameraData> mCameras;
 		Map<RenderableHandler*, SceneRenderableData> mRenderables;
+		Map<LightInternal*, SceneLightData> mLights;
 
 		volatile static InitOnStart DoInitOnStart;
 	};

+ 22 - 3
BansheeEngine/Source/BsLight.cpp

@@ -1,13 +1,15 @@
 #include "BsLight.h"
 #include "BsLightRTTI.h"
+#include "BsSceneManager.h"
 
 namespace BansheeEngine
 {
 	Light::Light(const HSceneObject& parent, LightType type, Color color,
-		float luminousFlux, float range, bool castsShadows, Degree spotAngle)
-		: Component(parent), mLastUpdateHash(std::numeric_limits<UINT32>::max())
+		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
+		: Component(parent)
 	{
-		mInternal = LightInternal::create(type, color, luminousFlux, range, castsShadows, spotAngle);
+		mInternal = LightInternal::create(type, color, intensity, 
+			range, castsShadows, spotAngle, spotFalloffAngle);
 
 		setName("Light");
 	}
@@ -16,6 +18,23 @@ namespace BansheeEngine
 	{
 		mInternal->destroy();
 	}
+
+	Sphere Light::getBounds() const
+	{
+		mInternal->_updateTransform(SO());
+
+		return mInternal->getBounds();
+	}
+
+	void Light::onInitialized()
+	{
+		gSceneManager()._registerLight(mInternal, sceneObject());
+	}
+
+	void Light::onDestroyed()
+	{
+		gSceneManager()._unregisterLight(mInternal);
+	}
 	
 	RTTITypeBase* Light::getRTTIStatic()
 	{

+ 125 - 20
BansheeEngine/Source/BsLightInternal.cpp

@@ -2,40 +2,91 @@
 #include "BsRendererManager.h"
 #include "BsRenderer.h"
 #include "BsFrameAlloc.h"
+#include "BsSceneObject.h"
 #include "BsLightInternalRTTI.h"
 
 namespace BansheeEngine
 {
 	LightInternalBase::LightInternalBase()
 		:mType(LightType::Point), mCastsShadows(false), mRange(10.0f),
-		mLuminousFlux(100.0f), mSpotAngle(45), mColor(Color::White)
+		mIntensity(100.0f), mSpotAngle(45), mColor(Color::White), mIsActive(true)
 	{
-		
+		mBounds = Sphere(mPosition, mRange);
 	}
 
 	LightInternalBase::LightInternalBase(LightType type, Color color,
-		float luminousFlux, float range, bool castsShadows, Degree spotAngle)
-		:mType(type), mCastsShadows(castsShadows), mRange(range),
-		mLuminousFlux(luminousFlux), mSpotAngle(spotAngle), mColor(color)
+		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
+		:mType(type), mCastsShadows(castsShadows), mRange(range), mSpotFalloffAngle(spotFalloffAngle),
+		mIntensity(intensity), mSpotAngle(spotAngle), mColor(color), mIsActive(true)
 	{
-		
+		mBounds = Sphere(mPosition, mRange);
+	}
+
+	float LightInternalBase::getRadiance() const
+	{
+		switch (mType)
+		{
+		case LightType::Point:
+			return mIntensity / (4 * Math::PI);
+		case LightType::Spot:
+		{
+			float cosTotalAngle = Math::cos(mSpotAngle);
+			float cosFalloffAngle = Math::cos(mSpotFalloffAngle);
+
+			return mIntensity / (Math::TWO_PI * (1.0f - (cosFalloffAngle + cosTotalAngle) * 0.5f));
+		}
+		}
+
+		return mIntensity;
+	}
+
+	void LightInternalBase::updateBounds()
+	{
+		switch (mType)
+		{
+		case LightType::Directional:
+			mBounds = Sphere(mPosition, std::numeric_limits<float>::infinity());
+			break;
+		case LightType::Point:
+			mBounds = Sphere(mPosition, mRange);
+			break;
+		case LightType::Spot:
+		{
+			Degree angle = Math::clamp(mSpotAngle, Degree(-90), Degree(90));
+			float coneRadius = Math::tan(angle) * mRange;
+
+			float radius;
+			Vector3 offset;
+			if (coneRadius < mRange)
+			{
+				radius = (mRange * mRange + coneRadius * coneRadius) / (0.5f * mRange);
+				offset = Vector3(0, 0, -(mRange - coneRadius));
+			}
+			else
+				radius = coneRadius;
+
+			Vector3 center = mPosition + mRotation.rotate(offset);
+			mBounds = Sphere(center, radius);
+		}
+			break;
+		}
 	}
 
 	LightInternalCore::~LightInternalCore()
 	{
-		RendererManager::instance().getActive()->_notifyLightRemoved(this);
+		gRenderer()->_notifyLightRemoved(this);
 	}
 
 	LightInternalCore::LightInternalCore(LightType type, Color color,
-		float luminousFlux, float range, bool castsShadows, Degree spotAngle)
-		:LightInternalBase(type, color, luminousFlux, range, castsShadows, spotAngle)
+		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
+		:LightInternalBase(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle)
 	{
 
 	}
 
 	void LightInternalCore::initialize()
 	{
-		RendererManager::instance().getActive()->_notifyLightAdded(this);
+		gRenderer()->_notifyLightAdded(this);
 
 		CoreObjectCore::initialize();
 	}
@@ -44,19 +95,54 @@ namespace BansheeEngine
 	{
 		char* dataPtr = (char*)data.getBuffer();
 
+		UINT32 dirtyFlags = 0;
+		bool oldIsActive = mIsActive;
+
 		dataPtr = rttiReadElem(mPosition, dataPtr);
 		dataPtr = rttiReadElem(mRotation, dataPtr);
 		dataPtr = rttiReadElem(mType, dataPtr);
 		dataPtr = rttiReadElem(mCastsShadows, dataPtr);
 		dataPtr = rttiReadElem(mColor, dataPtr);
 		dataPtr = rttiReadElem(mRange, dataPtr);
-		dataPtr = rttiReadElem(mLuminousFlux, dataPtr);
+		dataPtr = rttiReadElem(mIntensity, dataPtr);
 		dataPtr = rttiReadElem(mSpotAngle, dataPtr);
+		dataPtr = rttiReadElem(mSpotFalloffAngle, dataPtr);
+		dataPtr = rttiReadElem(mIsActive, dataPtr);
+		dataPtr = rttiReadElem(dirtyFlags, dataPtr);
+		dataPtr = rttiReadElem(mBounds, dataPtr);
+
+		if (dirtyFlags == (UINT32)LightDirtyFlag::Transform)
+		{
+			if (mIsActive)
+				gRenderer()->_notifyLightUpdated(this);
+		}
+		else
+		{
+			if (oldIsActive != mIsActive)
+			{
+				if (mIsActive)
+					gRenderer()->_notifyLightAdded(this);
+				else
+					gRenderer()->_notifyLightRemoved(this);
+			}
+			else
+			{
+				gRenderer()->_notifyLightRemoved(this);
+				gRenderer()->_notifyLightAdded(this);
+			}
+		}
+	}
+
+	LightInternal::LightInternal()
+		:mLastUpdateHash(0)
+	{
+		
 	}
 
 	LightInternal::LightInternal(LightType type, Color color,
-		float luminousFlux, float range, bool castsShadows, Degree spotAngle)
-		:LightInternalBase(type, color, luminousFlux, range, castsShadows, spotAngle)
+		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
+		: LightInternalBase(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle),
+		mLastUpdateHash(0)
 	{
 
 	}
@@ -67,10 +153,10 @@ namespace BansheeEngine
 	}
 
 	SPtr<LightInternal> LightInternal::create(LightType type, Color color,
-		float luminousFlux, float range, bool castsShadows, Degree spotAngle)
+		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
 	{
 		LightInternal* handler = new (bs_alloc<LightInternal>()) 
-			LightInternal(type, color, luminousFlux, range, castsShadows, spotAngle);
+			LightInternal(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle);
 		SPtr<LightInternal> handlerPtr = bs_core_ptr<LightInternal, GenAlloc>(handler);
 		handlerPtr->_setThisPtr(handlerPtr);
 		handlerPtr->initialize();
@@ -90,7 +176,7 @@ namespace BansheeEngine
 	SPtr<CoreObjectCore> LightInternal::createCore() const
 	{
 		LightInternalCore* handler = new (bs_alloc<LightInternalCore>()) 
-			LightInternalCore(mType, mColor, mLuminousFlux, mRange, mCastsShadows, mSpotAngle);
+			LightInternalCore(mType, mColor, mIntensity, mRange, mCastsShadows, mSpotAngle, mSpotFalloffAngle);
 		SPtr<LightInternalCore> handlerPtr = bs_shared_ptr<LightInternalCore, GenAlloc>(handler);
 		handlerPtr->_setThisPtr(handlerPtr);
 
@@ -106,8 +192,12 @@ namespace BansheeEngine
 		size += rttiGetElemSize(mCastsShadows);
 		size += rttiGetElemSize(mColor);
 		size += rttiGetElemSize(mRange);
-		size += rttiGetElemSize(mLuminousFlux);
+		size += rttiGetElemSize(mIntensity);
 		size += rttiGetElemSize(mSpotAngle);
+		size += rttiGetElemSize(mIsActive);
+		size += rttiGetElemSize(mSpotFalloffAngle);
+		size += rttiGetElemSize(getCoreDirtyFlags());
+		size += rttiGetElemSize(mBounds);
 
 		UINT8* buffer = allocator->alloc(size);
 
@@ -118,15 +208,30 @@ namespace BansheeEngine
 		dataPtr = rttiWriteElem(mCastsShadows, dataPtr);
 		dataPtr = rttiWriteElem(mColor, dataPtr);
 		dataPtr = rttiWriteElem(mRange, dataPtr);
-		dataPtr = rttiWriteElem(mLuminousFlux, dataPtr);
+		dataPtr = rttiWriteElem(mIntensity, dataPtr);
 		dataPtr = rttiWriteElem(mSpotAngle, dataPtr);
+		dataPtr = rttiWriteElem(mSpotFalloffAngle, dataPtr);
+		dataPtr = rttiWriteElem(mIsActive, dataPtr);
+		dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
+		dataPtr = rttiWriteElem(mBounds, dataPtr);
 
 		return CoreSyncData(buffer, size);
 	}
 
-	void LightInternal::_markCoreDirty()
+	void LightInternal::_updateTransform(const HSceneObject& parent)
+	{
+		UINT32 curHash = parent->getTransformHash();
+		if (curHash != _getLastModifiedHash())
+		{
+			setPosition(parent->getWorldPosition());
+			setRotation(parent->getWorldRotation());
+			_setLastModifiedHash(curHash);
+		}
+	}
+
+	void LightInternal::_markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything)
 	{
-		markCoreDirty();
+		markCoreDirty((UINT32)flag);
 	}
 
 	RTTITypeBase* LightInternal::getRTTIStatic()

+ 26 - 0
BansheeEngine/Source/BsSceneManager.cpp

@@ -2,6 +2,7 @@
 #include "BsSceneObject.h"
 #include "BsRenderableHandler.h"
 #include "BsCameraHandler.h"
+#include "BsLightInternal.h"
 
 namespace BansheeEngine
 {
@@ -27,6 +28,16 @@ namespace BansheeEngine
 		mCameras.erase(camera.get());
 	}
 
+	void SceneManager::_registerLight(const SPtr<LightInternal>& light, const HSceneObject& so)
+	{
+		mLights[light.get()] = SceneLightData(light, so);
+	}
+
+	void SceneManager::_unregisterLight(const SPtr<LightInternal>& light)
+	{
+		mLights.erase(light.get());
+	}
+
 	void SceneManager::_updateCoreObjectTransforms()
 	{
 		for (auto& renderablePair : mRenderables)
@@ -61,6 +72,21 @@ namespace BansheeEngine
 				handler->_setLastModifiedHash(curHash);
 			}
 		}
+
+		for (auto& lightPair : mLights)
+		{
+			SPtr<LightInternal> handler = lightPair.second.light;
+			HSceneObject so = lightPair.second.sceneObject;
+
+			UINT32 curHash = so->getTransformHash();
+			if (curHash != handler->_getLastModifiedHash())
+			{
+				handler->setPosition(so->getWorldPosition());
+				handler->setRotation(so->getWorldRotation());
+
+				handler->_setLastModifiedHash(curHash);
+			}
+		}
 	}
 
 	SceneManager& SceneManager::instance()

+ 27 - 13
MBansheeEngine/Light.cs

@@ -18,62 +18,74 @@ namespace BansheeEngine
             get { return internalLight; }
         }
 
-        internal Vector3 Position
+        public Vector3 Position
         {
             get { return internalLight.Position; }
             set { internalLight.Position = value; serializableData.position = value; }
         }
 
-        internal Quaternion Rotation
+        public Quaternion Rotation
         {
             get { return internalLight.Rotation; }
             set { internalLight.Rotation = value; serializableData.rotation = value; }
         }
 
-        internal LightType Type
+        public LightType Type
         {
             get { return internalLight.Type; }
             set { internalLight.Type = value; serializableData.type = value; }
         }
 
-        internal Color Color
+        public Color Color
         {
             get { return internalLight.Color; }
             set { internalLight.Color = value; serializableData.color = value; }
         }
 
-        internal float Range
+        public float Range
         {
             get { return internalLight.Range; }
             set { internalLight.Range = value; serializableData.range = value; }
         }
 
-        internal float LuminousFlux
+        public float Intensity
         {
-            get { return internalLight.LuminousFlux; }
-            set { internalLight.LuminousFlux = value; serializableData.luminousFlux = value; }
+            get { return internalLight.Intensity; }
+            set { internalLight.Intensity = value; serializableData.intensity = value; }
         }
 
-        internal Degree SpotAngle
+        public Degree SpotAngle
         {
             get { return internalLight.SpotAngle; }
             set { internalLight.SpotAngle = value; serializableData.spotAngle = value; }
         }
 
-        internal bool CastsShadow
+        public Degree SpotFalloffAngle
+        {
+            get { return internalLight.SpotFalloffAngle; }
+            set { internalLight.SpotFalloffAngle = value; serializableData.spotFalloffAngle = value; }
+        }
+
+        public bool CastsShadow
         {
             get { return internalLight.CastsShadow; }
             set { internalLight.CastsShadow = value; serializableData.castShadows = value; }
         }
 
+        public Sphere Bounds
+        {
+            get { Internal.UpdateTransform(SceneObject); return Internal.Bounds; }
+        }
+
         private void OnInitialize()
         {
             serializableData.position = Vector3.zero;
             serializableData.rotation = Quaternion.identity;
             serializableData.color = Color.White;
             serializableData.spotAngle = new Degree(45);
+            serializableData.spotFalloffAngle = new Degree(40);
             serializableData.range = 10.0f;
-            serializableData.luminousFlux = 100.0f;
+            serializableData.intensity = 100.0f;
             serializableData.type = LightType.Point;
             serializableData.castShadows = false;
         }
@@ -90,8 +102,9 @@ namespace BansheeEngine
             internalLight.Rotation = serializableData.rotation;
             internalLight.Color = serializableData.color;
             internalLight.SpotAngle = serializableData.spotAngle;
+            internalLight.SpotFalloffAngle = serializableData.spotFalloffAngle;
             internalLight.Range = serializableData.range;
-            internalLight.LuminousFlux = serializableData.luminousFlux;
+            internalLight.Intensity = serializableData.intensity;
             internalLight.Type = serializableData.type;
             internalLight.CastsShadow = serializableData.castShadows;
         }
@@ -113,8 +126,9 @@ namespace BansheeEngine
             public Quaternion rotation;
             public Color color;
             public Degree spotAngle;
+            public Degree spotFalloffAngle;
             public float range;
-            public float luminousFlux;
+            public float intensity;
             public LightType type;
             public bool castShadows;
         }

+ 31 - 6
MBansheeEngine/LightInternal.cs

@@ -44,10 +44,10 @@ namespace BansheeEngine
             set { Internal_SetRange(mCachedPtr, value); }
         }
 
-        internal float LuminousFlux
+        internal float Intensity
         {
-            get { return Internal_GetLuminousFlux(mCachedPtr); }
-            set { Internal_SetLuminousFlux(mCachedPtr, value); }
+            get { return Internal_GetIntensity(mCachedPtr); }
+            set { Internal_SetIntensity(mCachedPtr, value); }
         }
 
         internal Degree SpotAngle
@@ -56,13 +56,24 @@ namespace BansheeEngine
             set { Internal_SetSpotAngle(mCachedPtr, value.Degrees); }
         }
 
+        internal Degree SpotFalloffAngle
+        {
+            get { return Internal_GetSpotFalloffAngle(mCachedPtr); }
+            set { Internal_SetSpotFalloffAngle(mCachedPtr, value.Degrees); }
+        }
+
         internal bool CastsShadow
         {
             get { return Internal_GetCastsShadow(mCachedPtr); }
             set { Internal_SetCastsShadow(mCachedPtr, value); }
         }
 
-        public LightInternal(SceneObject sceneObject)
+        internal Sphere Bounds
+        {
+            get { return Internal_GetBounds(mCachedPtr); }
+        }
+
+        internal LightInternal(SceneObject sceneObject)
         {
             IntPtr sceneObjPtr = IntPtr.Zero;
             if (sceneObject != null)
@@ -71,6 +82,12 @@ namespace BansheeEngine
             Internal_Create(this, sceneObjPtr);
         }
 
+        internal void UpdateTransform(SceneObject parentSO)
+        {
+            if (parentSO != null)
+                Internal_UpdateTransform(mCachedPtr, parentSO.GetCachedPtr());
+        }
+
         internal void OnDestroy()
         {
             Internal_OnDestroy(mCachedPtr);
@@ -96,9 +113,9 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetRange(IntPtr instance, float value);
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetLuminousFlux(IntPtr instance);
+        private static extern float Internal_GetIntensity(IntPtr instance);
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetLuminousFlux(IntPtr instance, float value);
+        private static extern void Internal_SetIntensity(IntPtr instance, float value);
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern Color Internal_GetColor(IntPtr instance);
         [MethodImpl(MethodImplOptions.InternalCall)]
@@ -111,7 +128,15 @@ namespace BansheeEngine
         private static extern float Internal_GetSpotAngle(IntPtr instance);
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetSpotAngle(IntPtr instance, float value);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetSpotFalloffAngle(IntPtr instance);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetSpotFalloffAngle(IntPtr instance, float value);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Sphere Internal_GetBounds(IntPtr instance);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_UpdateTransform(IntPtr instance, IntPtr parentSO);
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_OnDestroy(IntPtr thisPtr);
     }

+ 8 - 2
SBansheeEngine/Include/BsScriptLightInternal.h

@@ -41,12 +41,18 @@ namespace BansheeEngine
 		static float internal_getRange(ScriptLightInternal* thisPtr);
 		static void internal_setRange(ScriptLightInternal* thisPtr, float range);
 
-		static float internal_getLuminousFlux(ScriptLightInternal* thisPtr);
-		static void internal_setLuminousFlux(ScriptLightInternal* thisPtr, float luminousFlux);
+		static float internal_getIntensity(ScriptLightInternal* thisPtr);
+		static void internal_setIntensity(ScriptLightInternal* thisPtr, float intensity);
 
 		static Degree internal_getSpotAngle(ScriptLightInternal* thisPtr);
 		static void internal_setSpotAngle(ScriptLightInternal* thisPtr, Degree spotAngle);
 
+		static Degree internal_getSpotFalloffAngle(ScriptLightInternal* thisPtr);
+		static void internal_setSpotFalloffAngle(ScriptLightInternal* thisPtr, Degree spotFalloffAngle);
+
+		static Sphere internal_getBounds(ScriptLightInternal* thisPtr);
+
+		static void internal_updateTransform(ScriptLightInternal* thisPtr, ScriptSceneObject* parent);
 		static void internal_onDestroy(ScriptLightInternal* instance);
 
 		SPtr<LightInternal> mLightInternal;

+ 3 - 0
SBansheeEngine/Source/BsScriptCameraHandler.cpp

@@ -112,6 +112,9 @@ namespace BansheeEngine
 
 	void ScriptCameraHandler::updateView(const HSceneObject& parent)
 	{
+		if (parent.isDestroyed())
+			return;
+
 		UINT32 curHash = parent->getTransformHash();
 		if (curHash != mLastUpdateHash)
 		{

+ 37 - 6
SBansheeEngine/Source/BsScriptLightInternal.cpp

@@ -1,6 +1,8 @@
 #include "BsScriptLightInternal.h"
 #include "BsScriptSceneObject.h"
 #include "BsSceneObject.h"
+#include "BsScriptSceneObject.h"
+#include "BsSceneManager.h"
 
 namespace BansheeEngine
 {
@@ -8,6 +10,7 @@ namespace BansheeEngine
 		:ScriptObject(managedInstance), mLightInternal(nullptr), mLastUpdateHash(0)
 	{
 		mLightInternal = LightInternal::create();
+		gSceneManager()._registerLight(mLightInternal, parentSO);
 	}
 
 	ScriptLightInternal::~ScriptLightInternal()
@@ -31,10 +34,14 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_SetColor", &ScriptLightInternal::internal_setColor);
 		metaData.scriptClass->addInternalCall("Internal_GetRange", &ScriptLightInternal::internal_getRange);
 		metaData.scriptClass->addInternalCall("Internal_SetRange", &ScriptLightInternal::internal_setRange);
-		metaData.scriptClass->addInternalCall("Internal_GetLuminousFlux", &ScriptLightInternal::internal_getLuminousFlux);
-		metaData.scriptClass->addInternalCall("Internal_SetLuminousFlux", &ScriptLightInternal::internal_setLuminousFlux);
+		metaData.scriptClass->addInternalCall("Internal_GetIntensity", &ScriptLightInternal::internal_getIntensity);
+		metaData.scriptClass->addInternalCall("Internal_SetIntensity", &ScriptLightInternal::internal_setIntensity);
 		metaData.scriptClass->addInternalCall("Internal_GetSpotAngle", &ScriptLightInternal::internal_getSpotAngle);
 		metaData.scriptClass->addInternalCall("Internal_SetSpotAngle", &ScriptLightInternal::internal_setSpotAngle);
+		metaData.scriptClass->addInternalCall("Internal_GetSpotFalloffAngle", &ScriptLightInternal::internal_getSpotFalloffAngle);
+		metaData.scriptClass->addInternalCall("Internal_SetSpotFalloffAngle", &ScriptLightInternal::internal_setSpotFalloffAngle);
+		metaData.scriptClass->addInternalCall("Internal_GetBounds", &ScriptLightInternal::internal_getBounds);
+		metaData.scriptClass->addInternalCall("Internal_UpdateTransform", &ScriptLightInternal::internal_updateTransform);
 		metaData.scriptClass->addInternalCall("Internal_OnDestroy", &ScriptLightInternal::internal_onDestroy);
 	}
 
@@ -107,14 +114,14 @@ namespace BansheeEngine
 		thisPtr->getInternal()->setRange(range);
 	}
 
-	float ScriptLightInternal::internal_getLuminousFlux(ScriptLightInternal* thisPtr)
+	float ScriptLightInternal::internal_getIntensity(ScriptLightInternal* thisPtr)
 	{
-		return thisPtr->getInternal()->getLuminousFlux();
+		return thisPtr->getInternal()->getIntensity();
 	}
 
-	void ScriptLightInternal::internal_setLuminousFlux(ScriptLightInternal* thisPtr, float luminousFlux)
+	void ScriptLightInternal::internal_setIntensity(ScriptLightInternal* thisPtr, float intensity)
 	{
-		thisPtr->getInternal()->setLuminousFlux(luminousFlux);
+		thisPtr->getInternal()->setIntensity(intensity);
 	}
 
 	Degree ScriptLightInternal::internal_getSpotAngle(ScriptLightInternal* thisPtr)
@@ -127,8 +134,32 @@ namespace BansheeEngine
 		thisPtr->getInternal()->setSpotAngle(spotAngle);
 	}
 
+	Degree ScriptLightInternal::internal_getSpotFalloffAngle(ScriptLightInternal* thisPtr)
+	{
+		return thisPtr->getInternal()->getSpotFalloffAngle();
+	}
+
+	void ScriptLightInternal::internal_setSpotFalloffAngle(ScriptLightInternal* thisPtr, Degree spotFalloffAngle)
+	{
+		thisPtr->getInternal()->setSpotFalloffAngle(spotFalloffAngle);
+	}
+
+	Sphere ScriptLightInternal::internal_getBounds(ScriptLightInternal* thisPtr)
+	{
+		return thisPtr->getInternal()->getBounds();
+	}
+
+	void ScriptLightInternal::internal_updateTransform(ScriptLightInternal* thisPtr, ScriptSceneObject* parent)
+	{
+		HSceneObject parentSO = parent->getNativeSceneObject();
+
+		if (!parentSO.isDestroyed())
+			thisPtr->getInternal()->_updateTransform(parentSO);
+	}
+
 	void ScriptLightInternal::internal_onDestroy(ScriptLightInternal* instance)
 	{
+		gSceneManager()._unregisterLight(instance->getInternal());
 		instance->getInternal()->destroy();
 	}
 }

+ 26 - 3
TODO.txt

@@ -58,15 +58,33 @@ Code quality improvements:
 ----------------------------------------------------------------------
 Polish stage 1
 
-Handles:
-Check multi-select move/Rotate/scale
-Free rotation handle doesn't seem to be implemented
+Finish up profiler overlay:
+ - Add a way to add generic settings in EditorSettings.cs (e.g. key/value pairs)
+ - Hook that up to SceneWindow
+ - Add a shortcut (e.g. F12) to open/close profile overlay
+ - Test if profiler overlay works
+ - Continue with profiling the hang issue
 
 There's a large hang when doing certain operations like selecting a mesh in scene, or switching from center to pivot mode (possibly GC?)
 Crash on shutdown in mono_gchandle_free
 When selecting an gizmo icon the selection seems delayed and its gizmos flash for a frame before hiding (Can't reproduce atm but I saw it)
 ProjectLibrary seems to import some files on every start-up
 
+First screenshot work:
+- Inspector change contents on selection (and make sure the selected object/component looks okay)
+- Additional menu bar items: 
+ - File: Exit, Save Project, New Project, Open Project, Save Scene As
+ - Edit: Undo/Redo, Cut/Copy/Paste/Duplicate/Delete(need to make sure it works in Hierarchy, with shortcuts), Frame Selected, Preferences, Play/Pause/Step
+ - Assets (also add to context): Create(Folder, Material, Shader, Script, Prefab, GUI Skin), Show in explorer
+ - Game Object (also add to context): Create(Empty, Empty Child, Camera, Renderable, Point/Spot/Directional Light), Apply prefab, Break prefab, Revert prefab
+   - Possibly create helper objects: Cube, Sphere, Plane, Quad, Capsule, Cylinder
+ - Component (also add to inspector context): Camera, Renderable, Point/Spot/Directional light, all other components from scripts
+ - Help - About, API Reference (link to site)
+- Status bar with last console message
+- (Optionally) Console window
+
+-----------
+
 SceneTreeView
  - Hook up ping effect so it triggers when I select a resource or sceneobject
  - See if it needs other enhancements (rename, delete all work properly? etc.)
@@ -83,12 +101,16 @@ Need a way to add scene objects and components (and remove them)
 
 Add shortcut keys for view/move/rotate/scale
 Add "focus on object" key (F)
+Ortographic camera views (+ gizmo in scene view corner that shows camera orientation)
+Drag to select in scene view
 
 Will need a status bar:
  - Displays last error message
  - Opens up console on click
  - Indicator when compiling
 
+Make sure to persist EditorSettings
+
 Later:
  - I could record undo/redo per-property using the new diff system
  - When building game make sure to go over texture resources and ensure they are saved in the valid format
@@ -164,6 +186,7 @@ Scene View
 Test:
  - Custom handles from C#
  - Handle snapping
+ - Multi-select Move/Rotate/scale
 
 ----------------------------------------------------------------------
 Other

+ 23 - 14
TODOExperimentation.txt

@@ -1,25 +1,33 @@
 -------------------------
 Study shadow rendering implementations
 
-Add basic light type components and their core thread representations
- - Directional, Point, Spot light
- - Luminous flux - intensity
- - Color
- - Directional - direction
- - Spot - angle, direction, position
- - Point - range (or derive that from flux?), position
-
-Document all Light stutff
-Light bounding box
-Need to update light handler when parent component moves/rotates
-
+Implement light added/removed/updated in BansheeRenderer
 Load up and set up a test-bed with Ribek's scene
 
+Need cone to use when rendering spot light
+
 Create a basic GBuffer - albedo, normal, depth
  - Using HDR formats where needed
+ - Will need some kind of a pool that handles multiple viewports (each with its own gbuffer) and viewport resizing
 
 Implement deferred rendering (just basic lambert shading for now, only point light)
- - Then convert to tiled rendering
+ - Then convert to tiled rendering (will likely need normal deferred too as a fallback - and to be able to toggle and compare)
+
+Create SceneRenderTargets class:
+ - Allocate(Camera - call at start rendering with camera - Allocates gbuffer (for now, more later probably)
+  - Internally calls RenderTargetPool that returns available cached render targets
+   - Actually this probably isn't the best idea. It might be better to store gbuffer targets with CameraHandlerCore
+     so when it resizes or gets destroyed we can immediately change/destroy them. With a pool I cannot tell when to destroy the gbuffer.
+	  - ALTHOUGH if two cameras have same viewport size them I shouldn't allocate two sets of targets. So maybe a combination of the two.
+ - Free(Camera)
+ - BeginSceneRendering - Sets the color target and gbuffer targets for rendering
+ - ResolveSceneRendering (also ends scene rendering) - possibly resolves MSAA into normal buffer
+   - Allow SceneRenderTargets to have a resolve target. Avoid resolve if they're equal
+
+How to handle MSAA in deferred? - Should be trivial with MSAA textures. I do only plan to support SM4 and higher anyway (maybe even SM5?)
+Will likely need an easy way to determine supported feature set (likely just depending on shader model)
+Consider encapsulating shaders together with methods for setting their parameters (and possibly retrieving output)
+ - So that external code doesn't need to know about its internal and do less work
 
 -------------
 
@@ -43,6 +51,7 @@ Later:
  - Proper PBR materials with reflection
  - Post-processing system - FXAA, SSAO, Color correction, Depth of field (Bokeh)
  - Forward rendering for transparent objects
+ - Need a way to toggle texture filtering mode for all textures (Some kind of an override?)
 
 -----------------
 
@@ -51,7 +60,7 @@ SECOND STAGE(S)
  - GI
  - Volumetric lighting
  - SSR
- - Depth pre-pass
+ - Depth pre-pass - Make sure this can be toggled on and off as needed
  - HDR skybox, skylight stuff
 
 -----------------