Przeglądaj źródła

More work on Lights

Marko Pintera 10 lat temu
rodzic
commit
afca99b5e8

+ 0 - 16
BansheeCore/Include/BsCoreRenderer.h

@@ -82,22 +82,6 @@ namespace BansheeEngine
 		 */
 		 */
 		virtual void _notifyCameraRemoved(const CameraHandlerCore* camera) { }
 		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.
 		 * @brief	Creates a new empty renderer mesh data.
 		 *
 		 *

+ 82 - 6
BansheeEngine/Include/BsLight.h

@@ -7,45 +7,121 @@
 namespace BansheeEngine 
 namespace BansheeEngine 
 {
 {
 	/**
 	/**
-	 * @copydoc	LightInternal
+	 * @copydoc	Component wrapper for LightInternal
+	 *
+	 * @see	LightInternal
 	 */
 	 */
     class BS_EXPORT Light : public Component
     class BS_EXPORT Light : public Component
     {
     {
     public:
     public:
 		Light(const HSceneObject& parent, LightType type = LightType::Point, Color color = Color::White, 
 		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();
 		virtual ~Light();
 
 
+	    /**
+		 * @copydoc	Component::onInitialized
+	     */
+		void onInitialized() override;
+
+	    /**
+		 * @copydoc	Component::onDestroyed
+	     */
+		void onDestroyed() override;
+
+	    /**
+		 * @copydoc	LightInternal::getPosition
+	     */
 		Vector3 getPosition() const { return mInternal->getPosition(); }
 		Vector3 getPosition() const { return mInternal->getPosition(); }
+
+	    /**
+		 * @copydoc	LightInternal::setPosition
+	     */
 		void setPosition(const Vector3& position) { mInternal->setPosition(position); }
 		void setPosition(const Vector3& position) { mInternal->setPosition(position); }
 
 
+	    /**
+		 * @copydoc	LightInternal::getRotation
+	     */
 		Quaternion getRotation() const { return mInternal->getRotation(); }
 		Quaternion getRotation() const { return mInternal->getRotation(); }
+
+	    /**
+		 * @copydoc	LightInternal::setRotation
+	     */
 		void setRotation(const Quaternion& rotation) { mInternal->setRotation(rotation); }
 		void setRotation(const Quaternion& rotation) { mInternal->setRotation(rotation); }
 
 
+	    /**
+		 * @copydoc	LightInternal::getType
+	     */
 		LightType getType() const { return mInternal->getType(); }
 		LightType getType() const { return mInternal->getType(); }
+
+	    /**
+		 * @copydoc	LightInternal::setType
+	     */
 		void setType(LightType type) { mInternal->setType(type); }
 		void setType(LightType type) { mInternal->setType(type); }
 
 
+	    /**
+		 * @copydoc	LightInternal::getCastsShadow
+	     */
 		bool getCastsShadow() const { return mInternal->getCastsShadow(); }
 		bool getCastsShadow() const { return mInternal->getCastsShadow(); }
+
+	    /**
+		 * @copydoc	LightInternal::setCastsShadow
+	     */
 		void setCastsShadow(bool castsShadow) { mInternal->setCastsShadow(castsShadow); }
 		void setCastsShadow(bool castsShadow) { mInternal->setCastsShadow(castsShadow); }
 
 
+	    /**
+		 * @copydoc	LightInternal::getColor
+	     */
 		Color getColor() const { return mInternal->getColor(); }
 		Color getColor() const { return mInternal->getColor(); }
+
+	    /**
+		 * @copydoc	LightInternal::setColor
+	     */
 		void setColor(const Color& color) { mInternal->setColor(color); }
 		void setColor(const Color& color) { mInternal->setColor(color); }
 
 
+	    /**
+		 * @copydoc	LightInternal::getRange
+	     */
 		float getRange() const { return mInternal->getRange(); }
 		float getRange() const { return mInternal->getRange(); }
+
+	    /**
+		 * @copydoc	LightInternal::setRange
+	     */
 		void setRange(float range) { mInternal->setRange(range);; }
 		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(); }
 		Degree getSpotAngle() const { return mInternal->getSpotAngle(); }
+
+	    /**
+		 * @copydoc	LightInternal::setSpotAngle
+	     */
 		void setSpotAngle(const Degree& spotAngle) { mInternal->setSpotAngle(spotAngle); }
 		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; }
 		SPtr<LightInternal> _getInternal() const { return mInternal; }
 
 
     protected:
     protected:
 		mutable SPtr<LightInternal> mInternal;
 		mutable SPtr<LightInternal> mInternal;
-		mutable UINT32 mLastUpdateHash;
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 						COMPONENT OVERRIDES                      		*/
 		/* 						COMPONENT OVERRIDES                      		*/
@@ -65,7 +141,7 @@ namespace BansheeEngine
 	public:
 	public:
 		friend class LightRTTI;
 		friend class LightRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const;
+		virtual RTTITypeBase* getRTTI() const override;
 
 
 	protected:
 	protected:
 		Light() {} // Serialization only
 		Light() {} // Serialization only

+ 182 - 22
BansheeEngine/Include/BsLightInternal.h

@@ -5,6 +5,7 @@
 #include "BsVector3.h"
 #include "BsVector3.h"
 #include "BsQuaternion.h"
 #include "BsQuaternion.h"
 #include "BsColor.h"
 #include "BsColor.h"
+#include "BsSphere.h"
 #include "BsCoreObject.h"
 #include "BsCoreObject.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -20,58 +21,172 @@ namespace BansheeEngine
 		Spot
 		Spot
 	};
 	};
 
 
+	/**
+	 * @brief	Signals which portion of a LightInternal is dirty.
+	 */
+	enum class LightDirtyFlag
+	{
+		Transform = 0x01,
+		Everything = 0x02
+	};
+
 	class BS_EXPORT LightInternalBase
 	class BS_EXPORT LightInternalBase
 	{
 	{
 	public:
 	public:
 		LightInternalBase();
 		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() { }
 		virtual ~LightInternalBase() { }
 
 
+		/**
+		 * @brief	Returns the position of the light, in world space.
+		 */
 		Vector3 getPosition() const { return mPosition; }
 		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; }
 		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; }
 		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; }
 		bool getCastsShadow() const { return mCastsShadows; }
+
+		/**
+		 * @brief	Sets whether this light will cast shadows when rendered.
+		 */
 		void setCastsShadow(bool castsShadow) { mCastsShadows = castsShadow; _markCoreDirty(); }
 		void setCastsShadow(bool castsShadow) { mCastsShadows = castsShadow; _markCoreDirty(); }
 
 
+		/**
+		 * @brief	Returns the color emitted from the light.
+		 */
 		Color getColor() const { return mColor; }
 		Color getColor() const { return mColor; }
+
+		/**
+		 * @brief	Sets the color emitted from the light.
+		 */
 		void setColor(const Color& color) { mColor = color; _markCoreDirty(); }
 		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; }
 		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; }
 		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
 		 * @copydoc	CoreObject::markCoreDirty
 		 */
 		 */
-		virtual void _markCoreDirty() { }
+		virtual void _markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything) { }
 
 
 	protected:
 	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. */
 		Vector3 mPosition; /**< World space position. */
 		Quaternion mRotation; /**< World space rotation. */
 		Quaternion mRotation; /**< World space rotation. */
 
 
 		LightType mType; /**< Type of light that determines how are the rest of the parameters interpreted. */
 		LightType mType; /**< Type of light that determines how are the rest of the parameters interpreted. */
 		bool mCastsShadows; /**< Determines whether the light casts shadows. */
 		bool mCastsShadows; /**< Determines whether the light casts shadows. */
 		Color mColor; /**< Color of the light. */
 		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
 	class BS_EXPORT LightInternalCore : public CoreObjectCore, public LightInternalBase
 	{
 	{
@@ -81,8 +196,8 @@ namespace BansheeEngine
 	protected:
 	protected:
 		friend class LightInternal;
 		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
 		 * @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
 	class BS_EXPORT LightInternal : public IReflectable, public CoreObject, public LightInternalBase
 	{
 	{
 	public:
 	public:
+		/**
+		 * @brief	Retrieves an implementation of a light usable only from the core thread.
+		 */
 		SPtr<LightInternalCore> getCore() const;
 		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,
 		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:
 	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
 		 * @copydoc	CoreObject::createCore
@@ -118,15 +273,20 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @copydoc	CoreObject::markCoreDirty
 		 * @copydoc	CoreObject::markCoreDirty
 		 */
 		 */
-		void _markCoreDirty() override;
+		void _markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything) override;
 
 
 		/**
 		/**
 		 * @copydoc	CoreObject::syncToCore
 		 * @copydoc	CoreObject::syncToCore
 		 */
 		 */
 		CoreSyncData syncToCore(FrameAlloc* allocator) override;
 		CoreSyncData syncToCore(FrameAlloc* allocator) override;
 
 
+		/**
+		 * @brief	Creates a light with without initializing it. Used for serialization.
+		 */
 		static SPtr<LightInternal> createEmpty();
 		static SPtr<LightInternal> createEmpty();
 
 
+		UINT32 mLastUpdateHash;
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/
 		/************************************************************************/
 		/************************************************************************/
@@ -136,6 +296,6 @@ namespace BansheeEngine
 		virtual RTTITypeBase* getRTTI() const override;
 		virtual RTTITypeBase* getRTTI() const override;
 
 
 	protected:
 	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; }
 		float& getRange(LightInternal* obj) { return obj->mRange; }
 		void setRange(LightInternal* obj, float& range) { obj->mRange = range; }
 		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; }
 		Degree& getSpotAngle(LightInternal* obj) { return obj->mSpotAngle; }
 		void setSpotAngle(LightInternal* obj, Degree& spotAngle) { obj->mSpotAngle = spotAngle; }
 		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:
 	public:
 		LightInternalRTTI()
 		LightInternalRTTI()
 		{
 		{
@@ -41,8 +44,9 @@ namespace BansheeEngine
 			addPlainField("mCastsShadow", 3, &LightInternalRTTI::getCastsShadow, &LightInternalRTTI::setCastsShadow);
 			addPlainField("mCastsShadow", 3, &LightInternalRTTI::getCastsShadow, &LightInternalRTTI::setCastsShadow);
 			addPlainField("mColor", 4, &LightInternalRTTI::getColor, &LightInternalRTTI::setColor);
 			addPlainField("mColor", 4, &LightInternalRTTI::getColor, &LightInternalRTTI::setColor);
 			addPlainField("mRange", 5, &LightInternalRTTI::getRange, &LightInternalRTTI::setRange);
 			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("mSpotAngle", 7, &LightInternalRTTI::getSpotAngle, &LightInternalRTTI::setSpotAngle);
+			addPlainField("mSpotFalloffAngle", 8, &LightInternalRTTI::getSpotFalloffAngle, &LightInternalRTTI::setSpotFalloffAngle);
 		}
 		}
 
 
 		virtual void onDeserializationEnded(IReflectable* obj) override
 		virtual void onDeserializationEnded(IReflectable* obj) override

+ 24 - 0
BansheeEngine/Include/BsRenderer.h

@@ -36,6 +36,30 @@ namespace BansheeEngine
 		 *			Internal method.
 		 *			Internal method.
 		 */
 		 */
 		virtual void _notifyRenderableRemoved(RenderableHandlerCore* renderable) { }
 		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;
 		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
 	 * @brief	Manages active SceneObjects and provides ways for querying
 	 *			and updating them or their components.
 	 *			and updating them or their components.
@@ -101,6 +116,20 @@ namespace BansheeEngine
 		 */
 		 */
 		void _unregisterCamera(const SPtr<CameraHandler>& camera);
 		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
 		 * @copydoc	CoreSceneManager::_updateCoreObjectTransforms
 		 */
 		 */
@@ -119,6 +148,7 @@ namespace BansheeEngine
 	private:
 	private:
 		Map<CameraHandler*, SceneCameraData> mCameras;
 		Map<CameraHandler*, SceneCameraData> mCameras;
 		Map<RenderableHandler*, SceneRenderableData> mRenderables;
 		Map<RenderableHandler*, SceneRenderableData> mRenderables;
+		Map<LightInternal*, SceneLightData> mLights;
 
 
 		volatile static InitOnStart DoInitOnStart;
 		volatile static InitOnStart DoInitOnStart;
 	};
 	};

+ 22 - 3
BansheeEngine/Source/BsLight.cpp

@@ -1,13 +1,15 @@
 #include "BsLight.h"
 #include "BsLight.h"
 #include "BsLightRTTI.h"
 #include "BsLightRTTI.h"
+#include "BsSceneManager.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	Light::Light(const HSceneObject& parent, LightType type, Color color,
 	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");
 		setName("Light");
 	}
 	}
@@ -16,6 +18,23 @@ namespace BansheeEngine
 	{
 	{
 		mInternal->destroy();
 		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()
 	RTTITypeBase* Light::getRTTIStatic()
 	{
 	{

+ 125 - 20
BansheeEngine/Source/BsLightInternal.cpp

@@ -2,40 +2,91 @@
 #include "BsRendererManager.h"
 #include "BsRendererManager.h"
 #include "BsRenderer.h"
 #include "BsRenderer.h"
 #include "BsFrameAlloc.h"
 #include "BsFrameAlloc.h"
+#include "BsSceneObject.h"
 #include "BsLightInternalRTTI.h"
 #include "BsLightInternalRTTI.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	LightInternalBase::LightInternalBase()
 	LightInternalBase::LightInternalBase()
 		:mType(LightType::Point), mCastsShadows(false), mRange(10.0f),
 		: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,
 	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()
 	LightInternalCore::~LightInternalCore()
 	{
 	{
-		RendererManager::instance().getActive()->_notifyLightRemoved(this);
+		gRenderer()->_notifyLightRemoved(this);
 	}
 	}
 
 
 	LightInternalCore::LightInternalCore(LightType type, Color color,
 	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()
 	void LightInternalCore::initialize()
 	{
 	{
-		RendererManager::instance().getActive()->_notifyLightAdded(this);
+		gRenderer()->_notifyLightAdded(this);
 
 
 		CoreObjectCore::initialize();
 		CoreObjectCore::initialize();
 	}
 	}
@@ -44,19 +95,54 @@ namespace BansheeEngine
 	{
 	{
 		char* dataPtr = (char*)data.getBuffer();
 		char* dataPtr = (char*)data.getBuffer();
 
 
+		UINT32 dirtyFlags = 0;
+		bool oldIsActive = mIsActive;
+
 		dataPtr = rttiReadElem(mPosition, dataPtr);
 		dataPtr = rttiReadElem(mPosition, dataPtr);
 		dataPtr = rttiReadElem(mRotation, dataPtr);
 		dataPtr = rttiReadElem(mRotation, dataPtr);
 		dataPtr = rttiReadElem(mType, dataPtr);
 		dataPtr = rttiReadElem(mType, dataPtr);
 		dataPtr = rttiReadElem(mCastsShadows, dataPtr);
 		dataPtr = rttiReadElem(mCastsShadows, dataPtr);
 		dataPtr = rttiReadElem(mColor, dataPtr);
 		dataPtr = rttiReadElem(mColor, dataPtr);
 		dataPtr = rttiReadElem(mRange, dataPtr);
 		dataPtr = rttiReadElem(mRange, dataPtr);
-		dataPtr = rttiReadElem(mLuminousFlux, dataPtr);
+		dataPtr = rttiReadElem(mIntensity, dataPtr);
 		dataPtr = rttiReadElem(mSpotAngle, 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,
 	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,
 	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* 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);
 		SPtr<LightInternal> handlerPtr = bs_core_ptr<LightInternal, GenAlloc>(handler);
 		handlerPtr->_setThisPtr(handlerPtr);
 		handlerPtr->_setThisPtr(handlerPtr);
 		handlerPtr->initialize();
 		handlerPtr->initialize();
@@ -90,7 +176,7 @@ namespace BansheeEngine
 	SPtr<CoreObjectCore> LightInternal::createCore() const
 	SPtr<CoreObjectCore> LightInternal::createCore() const
 	{
 	{
 		LightInternalCore* handler = new (bs_alloc<LightInternalCore>()) 
 		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);
 		SPtr<LightInternalCore> handlerPtr = bs_shared_ptr<LightInternalCore, GenAlloc>(handler);
 		handlerPtr->_setThisPtr(handlerPtr);
 		handlerPtr->_setThisPtr(handlerPtr);
 
 
@@ -106,8 +192,12 @@ namespace BansheeEngine
 		size += rttiGetElemSize(mCastsShadows);
 		size += rttiGetElemSize(mCastsShadows);
 		size += rttiGetElemSize(mColor);
 		size += rttiGetElemSize(mColor);
 		size += rttiGetElemSize(mRange);
 		size += rttiGetElemSize(mRange);
-		size += rttiGetElemSize(mLuminousFlux);
+		size += rttiGetElemSize(mIntensity);
 		size += rttiGetElemSize(mSpotAngle);
 		size += rttiGetElemSize(mSpotAngle);
+		size += rttiGetElemSize(mIsActive);
+		size += rttiGetElemSize(mSpotFalloffAngle);
+		size += rttiGetElemSize(getCoreDirtyFlags());
+		size += rttiGetElemSize(mBounds);
 
 
 		UINT8* buffer = allocator->alloc(size);
 		UINT8* buffer = allocator->alloc(size);
 
 
@@ -118,15 +208,30 @@ namespace BansheeEngine
 		dataPtr = rttiWriteElem(mCastsShadows, dataPtr);
 		dataPtr = rttiWriteElem(mCastsShadows, dataPtr);
 		dataPtr = rttiWriteElem(mColor, dataPtr);
 		dataPtr = rttiWriteElem(mColor, dataPtr);
 		dataPtr = rttiWriteElem(mRange, dataPtr);
 		dataPtr = rttiWriteElem(mRange, dataPtr);
-		dataPtr = rttiWriteElem(mLuminousFlux, dataPtr);
+		dataPtr = rttiWriteElem(mIntensity, dataPtr);
 		dataPtr = rttiWriteElem(mSpotAngle, 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);
 		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()
 	RTTITypeBase* LightInternal::getRTTIStatic()

+ 26 - 0
BansheeEngine/Source/BsSceneManager.cpp

@@ -2,6 +2,7 @@
 #include "BsSceneObject.h"
 #include "BsSceneObject.h"
 #include "BsRenderableHandler.h"
 #include "BsRenderableHandler.h"
 #include "BsCameraHandler.h"
 #include "BsCameraHandler.h"
+#include "BsLightInternal.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -27,6 +28,16 @@ namespace BansheeEngine
 		mCameras.erase(camera.get());
 		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()
 	void SceneManager::_updateCoreObjectTransforms()
 	{
 	{
 		for (auto& renderablePair : mRenderables)
 		for (auto& renderablePair : mRenderables)
@@ -61,6 +72,21 @@ namespace BansheeEngine
 				handler->_setLastModifiedHash(curHash);
 				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()
 	SceneManager& SceneManager::instance()

+ 27 - 13
MBansheeEngine/Light.cs

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

+ 31 - 6
MBansheeEngine/LightInternal.cs

@@ -44,10 +44,10 @@ namespace BansheeEngine
             set { Internal_SetRange(mCachedPtr, value); }
             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
         internal Degree SpotAngle
@@ -56,13 +56,24 @@ namespace BansheeEngine
             set { Internal_SetSpotAngle(mCachedPtr, value.Degrees); }
             set { Internal_SetSpotAngle(mCachedPtr, value.Degrees); }
         }
         }
 
 
+        internal Degree SpotFalloffAngle
+        {
+            get { return Internal_GetSpotFalloffAngle(mCachedPtr); }
+            set { Internal_SetSpotFalloffAngle(mCachedPtr, value.Degrees); }
+        }
+
         internal bool CastsShadow
         internal bool CastsShadow
         {
         {
             get { return Internal_GetCastsShadow(mCachedPtr); }
             get { return Internal_GetCastsShadow(mCachedPtr); }
             set { Internal_SetCastsShadow(mCachedPtr, value); }
             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;
             IntPtr sceneObjPtr = IntPtr.Zero;
             if (sceneObject != null)
             if (sceneObject != null)
@@ -71,6 +82,12 @@ namespace BansheeEngine
             Internal_Create(this, sceneObjPtr);
             Internal_Create(this, sceneObjPtr);
         }
         }
 
 
+        internal void UpdateTransform(SceneObject parentSO)
+        {
+            if (parentSO != null)
+                Internal_UpdateTransform(mCachedPtr, parentSO.GetCachedPtr());
+        }
+
         internal void OnDestroy()
         internal void OnDestroy()
         {
         {
             Internal_OnDestroy(mCachedPtr);
             Internal_OnDestroy(mCachedPtr);
@@ -96,9 +113,9 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetRange(IntPtr instance, float value);
         private static extern void Internal_SetRange(IntPtr instance, float value);
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetLuminousFlux(IntPtr instance);
+        private static extern float Internal_GetIntensity(IntPtr instance);
         [MethodImpl(MethodImplOptions.InternalCall)]
         [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)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern Color Internal_GetColor(IntPtr instance);
         private static extern Color Internal_GetColor(IntPtr instance);
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
@@ -111,7 +128,15 @@ namespace BansheeEngine
         private static extern float Internal_GetSpotAngle(IntPtr instance);
         private static extern float Internal_GetSpotAngle(IntPtr instance);
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetSpotAngle(IntPtr instance, float value);
         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)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_OnDestroy(IntPtr thisPtr);
         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 float internal_getRange(ScriptLightInternal* thisPtr);
 		static void internal_setRange(ScriptLightInternal* thisPtr, float range);
 		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 Degree internal_getSpotAngle(ScriptLightInternal* thisPtr);
 		static void internal_setSpotAngle(ScriptLightInternal* thisPtr, Degree spotAngle);
 		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);
 		static void internal_onDestroy(ScriptLightInternal* instance);
 
 
 		SPtr<LightInternal> mLightInternal;
 		SPtr<LightInternal> mLightInternal;

+ 3 - 0
SBansheeEngine/Source/BsScriptCameraHandler.cpp

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

+ 37 - 6
SBansheeEngine/Source/BsScriptLightInternal.cpp

@@ -1,6 +1,8 @@
 #include "BsScriptLightInternal.h"
 #include "BsScriptLightInternal.h"
 #include "BsScriptSceneObject.h"
 #include "BsScriptSceneObject.h"
 #include "BsSceneObject.h"
 #include "BsSceneObject.h"
+#include "BsScriptSceneObject.h"
+#include "BsSceneManager.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -8,6 +10,7 @@ namespace BansheeEngine
 		:ScriptObject(managedInstance), mLightInternal(nullptr), mLastUpdateHash(0)
 		:ScriptObject(managedInstance), mLightInternal(nullptr), mLastUpdateHash(0)
 	{
 	{
 		mLightInternal = LightInternal::create();
 		mLightInternal = LightInternal::create();
+		gSceneManager()._registerLight(mLightInternal, parentSO);
 	}
 	}
 
 
 	ScriptLightInternal::~ScriptLightInternal()
 	ScriptLightInternal::~ScriptLightInternal()
@@ -31,10 +34,14 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_SetColor", &ScriptLightInternal::internal_setColor);
 		metaData.scriptClass->addInternalCall("Internal_SetColor", &ScriptLightInternal::internal_setColor);
 		metaData.scriptClass->addInternalCall("Internal_GetRange", &ScriptLightInternal::internal_getRange);
 		metaData.scriptClass->addInternalCall("Internal_GetRange", &ScriptLightInternal::internal_getRange);
 		metaData.scriptClass->addInternalCall("Internal_SetRange", &ScriptLightInternal::internal_setRange);
 		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_GetSpotAngle", &ScriptLightInternal::internal_getSpotAngle);
 		metaData.scriptClass->addInternalCall("Internal_SetSpotAngle", &ScriptLightInternal::internal_setSpotAngle);
 		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);
 		metaData.scriptClass->addInternalCall("Internal_OnDestroy", &ScriptLightInternal::internal_onDestroy);
 	}
 	}
 
 
@@ -107,14 +114,14 @@ namespace BansheeEngine
 		thisPtr->getInternal()->setRange(range);
 		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)
 	Degree ScriptLightInternal::internal_getSpotAngle(ScriptLightInternal* thisPtr)
@@ -127,8 +134,32 @@ namespace BansheeEngine
 		thisPtr->getInternal()->setSpotAngle(spotAngle);
 		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)
 	void ScriptLightInternal::internal_onDestroy(ScriptLightInternal* instance)
 	{
 	{
+		gSceneManager()._unregisterLight(instance->getInternal());
 		instance->getInternal()->destroy();
 		instance->getInternal()->destroy();
 	}
 	}
 }
 }

+ 26 - 3
TODO.txt

@@ -58,15 +58,33 @@ Code quality improvements:
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Polish stage 1
 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?)
 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
 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)
 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
 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
 SceneTreeView
  - Hook up ping effect so it triggers when I select a resource or sceneobject
  - 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.)
  - 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 shortcut keys for view/move/rotate/scale
 Add "focus on object" key (F)
 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:
 Will need a status bar:
  - Displays last error message
  - Displays last error message
  - Opens up console on click
  - Opens up console on click
  - Indicator when compiling
  - Indicator when compiling
 
 
+Make sure to persist EditorSettings
+
 Later:
 Later:
  - I could record undo/redo per-property using the new diff system
  - 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
  - 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:
 Test:
  - Custom handles from C#
  - Custom handles from C#
  - Handle snapping
  - Handle snapping
+ - Multi-select Move/Rotate/scale
 
 
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Other
 Other

+ 23 - 14
TODOExperimentation.txt

@@ -1,25 +1,33 @@
 -------------------------
 -------------------------
 Study shadow rendering implementations
 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
 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
 Create a basic GBuffer - albedo, normal, depth
  - Using HDR formats where needed
  - 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)
 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
  - Proper PBR materials with reflection
  - Post-processing system - FXAA, SSAO, Color correction, Depth of field (Bokeh)
  - Post-processing system - FXAA, SSAO, Color correction, Depth of field (Bokeh)
  - Forward rendering for transparent objects
  - 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
  - GI
  - Volumetric lighting
  - Volumetric lighting
  - SSR
  - SSR
- - Depth pre-pass
+ - Depth pre-pass - Make sure this can be toggled on and off as needed
  - HDR skybox, skylight stuff
  - HDR skybox, skylight stuff
 
 
 -----------------
 -----------------