Browse Source

Fixing bugs & work on light exporter

Panagiotis Christopoulos Charitos 11 years ago
parent
commit
d2ebf6fc00

+ 0 - 1
include/anki/collision/CompoundShape.h

@@ -75,7 +75,6 @@ private:
 		(void)count;
 	}
 };
-
 /// @}
 
 } // end namespace anki

+ 22 - 28
include/anki/collision/Frustum.h

@@ -42,18 +42,13 @@ public:
 		COUNT ///< Number of planes
 	};
 
-	/// @name Constructors
-	/// @{
 	Frustum(Type type)
 	:	m_type(type)
 	{}
 
 	virtual ~Frustum()
 	{}
-	/// @}
 
-	/// @name Accessors
-	/// @{
 	Type getType() const
 	{
 		return m_type;
@@ -83,7 +78,18 @@ public:
 	{
 		return m_trf;
 	}
-	/// @}
+
+	/// Override CompoundShape::accept
+	void accept(MutableVisitor& v) override;
+
+	/// Override CompoundShape::accept
+	void accept(ConstVisitor& v) const override;
+
+	/// Override CompoundShape::testPlane
+	F32 testPlane(const Plane& p) const override;
+
+	/// Override CompoundShape::testPlane computeAabb
+	void computeAabb(Aabb&) const override;
 
 	/// Override CompoundShape::transform
 	void transform(const Transform& trf) override;
@@ -107,13 +113,15 @@ protected:
 	/// Used to check against the frustum
 	Array<Plane, (U)PlaneType::COUNT> m_planes;
 
-	Transform m_trf = Transform::getIdentity(); ///< Keep the transformation
+	/// Keep the transformation.
+	Transform m_trf = Transform::getIdentity(); 
 
 	/// It's true when the frustum changed
 	Bool8 m_frustumDirty = true;
 
 	/// Called when a viewing variable changes. It recalculates the planes and
-	/// the other variables
+	/// the other variables.
+	/// @note It's const because it must be called on const methods.
 	virtual void recalculate() = 0;
 
 	/// Copy
@@ -127,29 +135,23 @@ private:
 class PerspectiveFrustum: public Frustum
 {
 public:
-	/// @name Constructors
-	/// @{
-
 	/// Default
 	PerspectiveFrustum();
 
 	/// Copy
 	PerspectiveFrustum(const PerspectiveFrustum& b)
-		: PerspectiveFrustum()
+	:	PerspectiveFrustum()
 	{
 		*this = b;
 	}
 
 	/// Set all
 	PerspectiveFrustum(F32 fovX, F32 fovY, F32 near, F32 far)
-		: PerspectiveFrustum()
+	:	PerspectiveFrustum()
 	{
 		setAll(fovX, fovY, near, far);
 	}
-	/// @}
 
-	/// @name Accessors
-	/// @{
 	F32 getFovX() const
 	{
 		return m_fovX;
@@ -173,6 +175,7 @@ public:
 	/// Set all the parameters and recalculate the planes and shape
 	void setAll(F32 fovX, F32 fovY, F32 near, F32 far)
 	{
+		ANKI_ASSERT(far > near);
 		m_fovX = fovX;
 		m_fovY = fovY,
 		m_near = near;
@@ -184,7 +187,6 @@ public:
 	{
 		return m_segments;
 	}
-	/// @}
 
 	/// Copy
 	PerspectiveFrustum& operator=(const PerspectiveFrustum& b);
@@ -215,16 +217,13 @@ private:
 	/// Implements Frustum::recalculate. Recalculates:
 	/// @li planes
 	/// @li line segments
-	void recalculate();
+	void recalculate() override;
 };
 
 /// Frustum shape for orthographic cameras
 class OrthographicFrustum: public Frustum
 {
 public:
-	/// @name Constructors
-	/// @{
-
 	/// Default
 	OrthographicFrustum();
 
@@ -242,10 +241,7 @@ public:
 	{
 		setAll(left, right, near, far, top, bottom);
 	}
-	/// @}
 
-	/// @name Accessors
-	/// @{
 	F32 getLeft() const
 	{
 		return m_left;
@@ -304,7 +300,6 @@ public:
 	{
 		return m_obb;
 	}
-	/// @}
 
 	/// Copy
 	OrthographicFrustum& operator=(const OrthographicFrustum& b);
@@ -331,9 +326,8 @@ private:
 	Obb m_obb; ///< Including shape
 	/// @}
 
-	/// Implements Frustum::recalculate. Recalculate @a planes and
-	/// @a obb
-	void recalculate();
+	/// Implements Frustum::recalculate. Recalculate @a m_planes and @a m_obb
+	void recalculate() override;
 };
 /// @}
 

+ 2 - 1
include/anki/scene/Camera.h

@@ -19,7 +19,8 @@ namespace anki {
 /// Camera SceneNode interface class
 class Camera: public SceneNode
 {
-	friend class FeedbackComponent;
+	friend class MoveFeedbackComponent;
+	friend class FrustumFeedbackComponent;
 
 public:
 	/// @note Don't EVER change the order

+ 2 - 1
include/anki/scene/FrustumComponent.h

@@ -33,7 +33,8 @@ public:
 	/// Pass the frustum here so we can avoid the virtuals
 	FrustumComponent(SceneNode* node, Frustum* frustum)
 	:	SceneComponent(Type::FRUSTUM, node), 
-		m_frustum(frustum)
+		m_frustum(frustum),
+		m_flags(0)
 	{
 		// WARNING: Never touch m_frustum in constructor
 		ANKI_ASSERT(frustum);

+ 5 - 0
include/anki/scene/Light.h

@@ -89,6 +89,11 @@ public:
 		return m_innerAngleCos;
 	}
 
+	F32 getInnerAngle() const
+	{
+		return m_innerAngle;
+	}
+
 	void setOuterAngle(F32 ang)
 	{
 		m_outerAngleCos = cos(ang / 2.0);

+ 1 - 1
src/collision/CompoundShape.cpp

@@ -11,7 +11,7 @@ namespace anki {
 
 //==============================================================================
 CompoundShape::CompoundShape()
-	: CollisionShape(Type::COMPOUND)
+:	CollisionShape(Type::COMPOUND)
 {
 	memset(&m_dflt, 0, sizeof(m_dflt));
 }

+ 59 - 8
src/collision/Frustum.cpp

@@ -27,15 +27,66 @@ Frustum& Frustum::operator=(const Frustum& b)
 }
 
 //==============================================================================
-Bool Frustum::insideFrustum(const CollisionShape& b)
+void Frustum::accept(MutableVisitor& v)
 {
 	if(m_frustumDirty)
 	{
-		m_frustumDirty = false;
-		recalculate();
+		// Force recalculation and tranform
+		resetTransform(m_trf);
+	}
+
+	CompoundShape::accept(v);
+}
+
+//==============================================================================
+void Frustum::accept(ConstVisitor& v) const
+{
+	Frustum& self = *const_cast<Frustum*>(this);
 
-		// recalculate() reset the tranformations so re-transform
-		transform(m_trf);
+	if(self.m_frustumDirty)
+	{
+		// Force recalculation and tranform
+		self.resetTransform(m_trf);
+	}
+
+	CompoundShape::accept(v);
+}
+
+//==============================================================================
+F32 Frustum::testPlane(const Plane& p) const
+{
+	Frustum& self = *const_cast<Frustum*>(this);
+
+	if(self.m_frustumDirty)
+	{
+		// Force recalculation and tranform
+		self.resetTransform(m_trf);
+	}
+
+	return CompoundShape::testPlane(p);
+}
+
+//==============================================================================
+void Frustum::computeAabb(Aabb& aabb) const
+{
+	Frustum& self = *const_cast<Frustum*>(this);
+
+	if(self.m_frustumDirty)
+	{
+		// Force recalculation and tranform
+		self.resetTransform(m_trf);
+	}
+
+	CompoundShape::computeAabb(aabb);
+}
+
+//==============================================================================
+Bool Frustum::insideFrustum(const CollisionShape& b)
+{
+	if(m_frustumDirty)
+	{
+		// Force recalculation and tranform
+		resetTransform(m_trf);
 	}
 
 	for(const Plane& plane : m_planes)
@@ -100,7 +151,7 @@ void Frustum::resetTransform(const Transform& trf)
 
 //==============================================================================
 PerspectiveFrustum::PerspectiveFrustum()
-	: Frustum(Type::PERSPECTIVE)
+:	Frustum(Type::PERSPECTIVE)
 {
 	for(LineSegment& ls : m_segments)
 	{
@@ -163,7 +214,7 @@ void PerspectiveFrustum::recalculate()
 //==============================================================================
 Mat4 PerspectiveFrustum::calculateProjectionMatrix() const
 {
-	ANKI_ASSERT(m_fovX != 0.0 && m_fovY != 0.0);
+	ANKI_ASSERT(m_fovX != 0.0 && m_fovY != 0.0 && m_near != 0.0);
 	Mat4 projectionMat;
 	F32 g = m_near - m_far;
 
@@ -214,7 +265,7 @@ Mat4 PerspectiveFrustum::calculateProjectionMatrix() const
 
 //==============================================================================
 OrthographicFrustum::OrthographicFrustum()
-	: Frustum(Type::ORTHOGRAPHIC)
+:	Frustum(Type::ORTHOGRAPHIC)
 {
 	addShape(&m_obb);
 }

+ 37 - 13
src/scene/Camera.cpp

@@ -8,14 +8,14 @@
 namespace anki {
 
 //==============================================================================
-// FeedbackComponent                                                           =
+// MoveFeedbackComponent                                                       =
 //==============================================================================
 
 /// Feedback component.
-class FeedbackComponent: public SceneComponent
+class MoveFeedbackComponent: public SceneComponent
 {
 public:
-	FeedbackComponent(Camera* node)
+	MoveFeedbackComponent(Camera* node)
 	:	SceneComponent(SceneComponent::Type::NONE, node)
 	{}
 
@@ -31,6 +31,27 @@ public:
 			cam.onMoveComponentUpdate(move);
 		}
 
+		return ErrorCode::NONE;
+	}
+};
+
+//==============================================================================
+// FrustumFeedbackComponent                                                    =
+//==============================================================================
+
+/// Feedback component.
+class FrustumFeedbackComponent: public SceneComponent
+{
+public:
+	FrustumFeedbackComponent(Camera* node)
+	:	SceneComponent(SceneComponent::Type::NONE, node)
+	{}
+
+	ANKI_USE_RESULT Error update(
+		SceneNode& node, F32, F32, Bool& updated)
+	{
+		updated = false;
+
 		FrustumComponent& fr = node.getComponent<FrustumComponent>();
 		if(fr.getTimestamp() == getGlobTimestamp())
 		{
@@ -64,33 +85,36 @@ Error Camera::create(const CString& name, Frustum* frustum)
 	comp = getSceneAllocator().newInstance<MoveComponent>(this);
 	if(comp == nullptr) return ErrorCode::OUT_OF_MEMORY;
 
-	err = addComponent(comp);
+	err = addComponent(comp, true);
+	if(err) return err;
+
+	// Feedback component
+	comp = getSceneAllocator().newInstance<MoveFeedbackComponent>(this);
+	if(comp == nullptr) return ErrorCode::OUT_OF_MEMORY;
+
+	err = addComponent(comp, true);
 	if(err) return err;
-	comp->setAutomaticCleanup(true);
 
 	// Frustum component
 	comp = getSceneAllocator().newInstance<FrustumComponent>(this, frustum);
 	if(comp == nullptr) return ErrorCode::OUT_OF_MEMORY;
 
-	err = addComponent(comp);
+	err = addComponent(comp, true);
 	if(err) return err;
-	comp->setAutomaticCleanup(true);
 
-	// Feedback component
-	comp = getSceneAllocator().newInstance<FeedbackComponent>(this);
+	// Feedback component #2
+	comp = getSceneAllocator().newInstance<FrustumFeedbackComponent>(this);
 	if(comp == nullptr) return ErrorCode::OUT_OF_MEMORY;
 
-	err = addComponent(comp);
+	err = addComponent(comp, true);
 	if(err) return err;
-	comp->setAutomaticCleanup(true);
 
 	// Spatial component
 	comp = getSceneAllocator().newInstance<SpatialComponent>(this, frustum);
 	if(comp == nullptr) return ErrorCode::OUT_OF_MEMORY;
 
-	err = addComponent(comp);
+	err = addComponent(comp, true);
 	if(err) return err;
-	comp->setAutomaticCleanup(true);
 
 	return err;
 }

+ 3 - 4
src/scene/Light.cpp

@@ -308,16 +308,15 @@ Error SpotLight::create(const CString& name)
 void SpotLight::onMoveUpdate(MoveComponent& move)
 {
 	onMoveUpdateCommon(move);
-	m_frustum.resetTransform(move.getWorldTransform());
 }
 
 //==============================================================================
 void SpotLight::onShapeUpdate(LightComponent& light)
 {
 	onShapeUpdateCommon(light);
-	m_frustum.setFovX(light.getOuterAngle());
-	m_frustum.setFovY(light.getOuterAngle());
-	m_frustum.setFar(light.getDistance());
+	m_frustum.setAll(
+		light.getOuterAngle(), light.getOuterAngle(), 
+		0.5, light.getDistance());
 }
 
 } // end namespace anki

+ 838 - 0
src/script/Scene.cpp

@@ -298,6 +298,556 @@ static inline void wrapMoveComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
+//==============================================================================
+// LightComponent                                                              =
+//==============================================================================
+
+//==============================================================================
+static const char* classnameLightComponent = "LightComponent";
+
+template<>
+I64 LuaBinder::getWrappedTypeSignature<LightComponent>()
+{
+	return 7940823622056993903;
+}
+
+template<>
+const char* LuaBinder::getWrappedTypeName<LightComponent>()
+{
+	return classnameLightComponent;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::setDiffuseColor.
+static inline int pwrapLightComponentsetDiffuseColor(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 2);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	if(LuaBinder::checkUserData(l, 2, "Vec4", 6804478823655046386, ud)) return -1;
+	Vec4* iarg0 = static_cast<Vec4*>(ud->m_data);
+	const Vec4& arg0(*iarg0);
+	
+	// Call the method
+	self->setDiffuseColor(arg0);
+	
+	return 0;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::setDiffuseColor.
+static int wrapLightComponentsetDiffuseColor(lua_State* l)
+{
+	int res = pwrapLightComponentsetDiffuseColor(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::getDiffuseColor.
+static inline int pwrapLightComponentgetDiffuseColor(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	const Vec4& ret = self->getDiffuseColor();
+	
+	// Push return value
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "Vec4");
+	ud->m_data = const_cast<void*>(static_cast<const void*>(&ret));
+	ud->m_gc = false;
+	ud->m_sig = 6804478823655046386;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::getDiffuseColor.
+static int wrapLightComponentgetDiffuseColor(lua_State* l)
+{
+	int res = pwrapLightComponentgetDiffuseColor(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::setSpecularColor.
+static inline int pwrapLightComponentsetSpecularColor(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 2);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	if(LuaBinder::checkUserData(l, 2, "Vec4", 6804478823655046386, ud)) return -1;
+	Vec4* iarg0 = static_cast<Vec4*>(ud->m_data);
+	const Vec4& arg0(*iarg0);
+	
+	// Call the method
+	self->setSpecularColor(arg0);
+	
+	return 0;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::setSpecularColor.
+static int wrapLightComponentsetSpecularColor(lua_State* l)
+{
+	int res = pwrapLightComponentsetSpecularColor(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::getSpecularColor.
+static inline int pwrapLightComponentgetSpecularColor(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	const Vec4& ret = self->getSpecularColor();
+	
+	// Push return value
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "Vec4");
+	ud->m_data = const_cast<void*>(static_cast<const void*>(&ret));
+	ud->m_gc = false;
+	ud->m_sig = 6804478823655046386;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::getSpecularColor.
+static int wrapLightComponentgetSpecularColor(lua_State* l)
+{
+	int res = pwrapLightComponentgetSpecularColor(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::setRadius.
+static inline int pwrapLightComponentsetRadius(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 2);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	F32 arg0;
+	if(LuaBinder::checkNumber(l, 2, arg0)) return -1;
+	
+	// Call the method
+	self->setRadius(arg0);
+	
+	return 0;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::setRadius.
+static int wrapLightComponentsetRadius(lua_State* l)
+{
+	int res = pwrapLightComponentsetRadius(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::getRadius.
+static inline int pwrapLightComponentgetRadius(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	F32 ret = self->getRadius();
+	
+	// Push return value
+	lua_pushnumber(l, ret);
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::getRadius.
+static int wrapLightComponentgetRadius(lua_State* l)
+{
+	int res = pwrapLightComponentgetRadius(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::setDistance.
+static inline int pwrapLightComponentsetDistance(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 2);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	F32 arg0;
+	if(LuaBinder::checkNumber(l, 2, arg0)) return -1;
+	
+	// Call the method
+	self->setDistance(arg0);
+	
+	return 0;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::setDistance.
+static int wrapLightComponentsetDistance(lua_State* l)
+{
+	int res = pwrapLightComponentsetDistance(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::getDistance.
+static inline int pwrapLightComponentgetDistance(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	F32 ret = self->getDistance();
+	
+	// Push return value
+	lua_pushnumber(l, ret);
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::getDistance.
+static int wrapLightComponentgetDistance(lua_State* l)
+{
+	int res = pwrapLightComponentgetDistance(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::setInnerAngle.
+static inline int pwrapLightComponentsetInnerAngle(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 2);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	F32 arg0;
+	if(LuaBinder::checkNumber(l, 2, arg0)) return -1;
+	
+	// Call the method
+	self->setInnerAngle(arg0);
+	
+	return 0;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::setInnerAngle.
+static int wrapLightComponentsetInnerAngle(lua_State* l)
+{
+	int res = pwrapLightComponentsetInnerAngle(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::getInnerAngle.
+static inline int pwrapLightComponentgetInnerAngle(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	F32 ret = self->getInnerAngle();
+	
+	// Push return value
+	lua_pushnumber(l, ret);
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::getInnerAngle.
+static int wrapLightComponentgetInnerAngle(lua_State* l)
+{
+	int res = pwrapLightComponentgetInnerAngle(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::setOuterAngle.
+static inline int pwrapLightComponentsetOuterAngle(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 2);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	F32 arg0;
+	if(LuaBinder::checkNumber(l, 2, arg0)) return -1;
+	
+	// Call the method
+	self->setOuterAngle(arg0);
+	
+	return 0;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::setOuterAngle.
+static int wrapLightComponentsetOuterAngle(lua_State* l)
+{
+	int res = pwrapLightComponentsetOuterAngle(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::getOuterAngle.
+static inline int pwrapLightComponentgetOuterAngle(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	F32 ret = self->getOuterAngle();
+	
+	// Push return value
+	lua_pushnumber(l, ret);
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::getOuterAngle.
+static int wrapLightComponentgetOuterAngle(lua_State* l)
+{
+	int res = pwrapLightComponentgetOuterAngle(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::setShadowEnabled.
+static inline int pwrapLightComponentsetShadowEnabled(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 2);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	Bool arg0;
+	if(LuaBinder::checkNumber(l, 2, arg0)) return -1;
+	
+	// Call the method
+	self->setShadowEnabled(arg0);
+	
+	return 0;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::setShadowEnabled.
+static int wrapLightComponentsetShadowEnabled(lua_State* l)
+{
+	int res = pwrapLightComponentsetShadowEnabled(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method LightComponent::getShadowEnabled.
+static inline int pwrapLightComponentgetShadowEnabled(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameLightComponent, 7940823622056993903, ud)) return -1;
+	LightComponent* self = static_cast<LightComponent*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	Bool ret = self->getShadowEnabled();
+	
+	// Push return value
+	lua_pushboolean(l, ret);
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method LightComponent::getShadowEnabled.
+static int wrapLightComponentgetShadowEnabled(lua_State* l)
+{
+	int res = pwrapLightComponentgetShadowEnabled(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Wrap class LightComponent.
+static inline void wrapLightComponent(lua_State* l)
+{
+	LuaBinder::createClass(l, classnameLightComponent);
+	LuaBinder::pushLuaCFuncMethod(l, "setDiffuseColor", wrapLightComponentsetDiffuseColor);
+	LuaBinder::pushLuaCFuncMethod(l, "getDiffuseColor", wrapLightComponentgetDiffuseColor);
+	LuaBinder::pushLuaCFuncMethod(l, "setSpecularColor", wrapLightComponentsetSpecularColor);
+	LuaBinder::pushLuaCFuncMethod(l, "getSpecularColor", wrapLightComponentgetSpecularColor);
+	LuaBinder::pushLuaCFuncMethod(l, "setRadius", wrapLightComponentsetRadius);
+	LuaBinder::pushLuaCFuncMethod(l, "getRadius", wrapLightComponentgetRadius);
+	LuaBinder::pushLuaCFuncMethod(l, "setDistance", wrapLightComponentsetDistance);
+	LuaBinder::pushLuaCFuncMethod(l, "getDistance", wrapLightComponentgetDistance);
+	LuaBinder::pushLuaCFuncMethod(l, "setInnerAngle", wrapLightComponentsetInnerAngle);
+	LuaBinder::pushLuaCFuncMethod(l, "getInnerAngle", wrapLightComponentgetInnerAngle);
+	LuaBinder::pushLuaCFuncMethod(l, "setOuterAngle", wrapLightComponentsetOuterAngle);
+	LuaBinder::pushLuaCFuncMethod(l, "getOuterAngle", wrapLightComponentgetOuterAngle);
+	LuaBinder::pushLuaCFuncMethod(l, "setShadowEnabled", wrapLightComponentsetShadowEnabled);
+	LuaBinder::pushLuaCFuncMethod(l, "getShadowEnabled", wrapLightComponentgetShadowEnabled);
+	lua_settop(l, 0);
+}
+
 //==============================================================================
 // SceneNode                                                                   =
 //==============================================================================
@@ -444,6 +994,52 @@ static int wrapSceneNodegetMoveComponent(lua_State* l)
 	return 0;
 }
 
+//==============================================================================
+/// Pre-wrap method SceneNode::tryGetComponent<LightComponent>.
+static inline int pwrapSceneNodegetLightComponent(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameSceneNode, -2220074417980276571, ud)) return -1;
+	SceneNode* self = static_cast<SceneNode*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	LightComponent* ret = self->tryGetComponent<LightComponent>();
+	
+	// Push return value
+	if(ANKI_UNLIKELY(ret == nullptr))
+	{
+		lua_pushstring(l, "Glue code returned nullptr");
+		return -1;
+	}
+	
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "LightComponent");
+	ud->m_data = static_cast<void*>(ret);
+	ud->m_gc = false;
+	ud->m_sig = 7940823622056993903;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method SceneNode::tryGetComponent<LightComponent>.
+static int wrapSceneNodegetLightComponent(lua_State* l)
+{
+	int res = pwrapSceneNodegetLightComponent(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
 //==============================================================================
 /// Wrap class SceneNode.
 static inline void wrapSceneNode(lua_State* l)
@@ -452,6 +1048,7 @@ static inline void wrapSceneNode(lua_State* l)
 	LuaBinder::pushLuaCFuncMethod(l, "getName", wrapSceneNodegetName);
 	LuaBinder::pushLuaCFuncMethod(l, "addChild", wrapSceneNodeaddChild);
 	LuaBinder::pushLuaCFuncMethod(l, "getMoveComponent", wrapSceneNodegetMoveComponent);
+	LuaBinder::pushLuaCFuncMethod(l, "getLightComponent", wrapSceneNodegetLightComponent);
 	lua_settop(l, 0);
 }
 
@@ -591,6 +1188,142 @@ static inline void wrapInstanceNode(lua_State* l)
 	lua_settop(l, 0);
 }
 
+//==============================================================================
+// PointLight                                                                  =
+//==============================================================================
+
+//==============================================================================
+static const char* classnamePointLight = "PointLight";
+
+template<>
+I64 LuaBinder::getWrappedTypeSignature<PointLight>()
+{
+	return 3561037663389896020;
+}
+
+template<>
+const char* LuaBinder::getWrappedTypeName<PointLight>()
+{
+	return classnamePointLight;
+}
+
+//==============================================================================
+/// Pre-wrap method PointLight::getSceneNodeBase.
+static inline int pwrapPointLightgetSceneNodeBase(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnamePointLight, 3561037663389896020, ud)) return -1;
+	PointLight* self = static_cast<PointLight*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	SceneNode& ret = *self;
+	
+	// Push return value
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "SceneNode");
+	ud->m_data = static_cast<void*>(&ret);
+	ud->m_gc = false;
+	ud->m_sig = -2220074417980276571;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method PointLight::getSceneNodeBase.
+static int wrapPointLightgetSceneNodeBase(lua_State* l)
+{
+	int res = pwrapPointLightgetSceneNodeBase(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Wrap class PointLight.
+static inline void wrapPointLight(lua_State* l)
+{
+	LuaBinder::createClass(l, classnamePointLight);
+	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapPointLightgetSceneNodeBase);
+	lua_settop(l, 0);
+}
+
+//==============================================================================
+// SpotLight                                                                   =
+//==============================================================================
+
+//==============================================================================
+static const char* classnameSpotLight = "SpotLight";
+
+template<>
+I64 LuaBinder::getWrappedTypeSignature<SpotLight>()
+{
+	return 7940385212889719421;
+}
+
+template<>
+const char* LuaBinder::getWrappedTypeName<SpotLight>()
+{
+	return classnameSpotLight;
+}
+
+//==============================================================================
+/// Pre-wrap method SpotLight::getSceneNodeBase.
+static inline int pwrapSpotLightgetSceneNodeBase(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 1);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameSpotLight, 7940385212889719421, ud)) return -1;
+	SpotLight* self = static_cast<SpotLight*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Call the method
+	SceneNode& ret = *self;
+	
+	// Push return value
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "SceneNode");
+	ud->m_data = static_cast<void*>(&ret);
+	ud->m_gc = false;
+	ud->m_sig = -2220074417980276571;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method SpotLight::getSceneNodeBase.
+static int wrapSpotLightgetSceneNodeBase(lua_State* l)
+{
+	int res = pwrapSpotLightgetSceneNodeBase(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Wrap class SpotLight.
+static inline void wrapSpotLight(lua_State* l)
+{
+	LuaBinder::createClass(l, classnameSpotLight);
+	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapSpotLightgetSceneNodeBase);
+	lua_settop(l, 0);
+}
+
 //==============================================================================
 // SceneGraph                                                                  =
 //==============================================================================
@@ -713,6 +1446,106 @@ static int wrapSceneGraphnewInstanceNode(lua_State* l)
 	return 0;
 }
 
+//==============================================================================
+/// Pre-wrap method SceneGraph::newPointLight.
+static inline int pwrapSceneGraphnewPointLight(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 2);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameSceneGraph, -7754439619132389154, ud)) return -1;
+	SceneGraph* self = static_cast<SceneGraph*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	const char* arg0;
+	if(LuaBinder::checkString(l, 2, arg0)) return -1;
+	
+	// Call the method
+	PointLight* ret = newSceneNode<PointLight>(self, arg0);
+	
+	// Push return value
+	if(ANKI_UNLIKELY(ret == nullptr))
+	{
+		lua_pushstring(l, "Glue code returned nullptr");
+		return -1;
+	}
+	
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "PointLight");
+	ud->m_data = static_cast<void*>(ret);
+	ud->m_gc = false;
+	ud->m_sig = 3561037663389896020;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method SceneGraph::newPointLight.
+static int wrapSceneGraphnewPointLight(lua_State* l)
+{
+	int res = pwrapSceneGraphnewPointLight(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
+//==============================================================================
+/// Pre-wrap method SceneGraph::newSpotLight.
+static inline int pwrapSceneGraphnewSpotLight(lua_State* l)
+{
+	UserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	
+	LuaBinder::checkArgsCount(l, 2);
+	
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, classnameSceneGraph, -7754439619132389154, ud)) return -1;
+	SceneGraph* self = static_cast<SceneGraph*>(ud->m_data);
+	ANKI_ASSERT(self != nullptr);
+	
+	// Pop arguments
+	const char* arg0;
+	if(LuaBinder::checkString(l, 2, arg0)) return -1;
+	
+	// Call the method
+	SpotLight* ret = newSceneNode<SpotLight>(self, arg0);
+	
+	// Push return value
+	if(ANKI_UNLIKELY(ret == nullptr))
+	{
+		lua_pushstring(l, "Glue code returned nullptr");
+		return -1;
+	}
+	
+	voidp = lua_newuserdata(l, sizeof(UserData));
+	ud = static_cast<UserData*>(voidp);
+	luaL_setmetatable(l, "SpotLight");
+	ud->m_data = static_cast<void*>(ret);
+	ud->m_gc = false;
+	ud->m_sig = 7940385212889719421;
+	
+	return 1;
+}
+
+//==============================================================================
+/// Wrap method SceneGraph::newSpotLight.
+static int wrapSceneGraphnewSpotLight(lua_State* l)
+{
+	int res = pwrapSceneGraphnewSpotLight(l);
+	if(res >= 0) return res;
+	lua_error(l);
+	return 0;
+}
+
 //==============================================================================
 /// Wrap class SceneGraph.
 static inline void wrapSceneGraph(lua_State* l)
@@ -720,6 +1553,8 @@ static inline void wrapSceneGraph(lua_State* l)
 	LuaBinder::createClass(l, classnameSceneGraph);
 	LuaBinder::pushLuaCFuncMethod(l, "newModelNode", wrapSceneGraphnewModelNode);
 	LuaBinder::pushLuaCFuncMethod(l, "newInstanceNode", wrapSceneGraphnewInstanceNode);
+	LuaBinder::pushLuaCFuncMethod(l, "newPointLight", wrapSceneGraphnewPointLight);
+	LuaBinder::pushLuaCFuncMethod(l, "newSpotLight", wrapSceneGraphnewSpotLight);
 	lua_settop(l, 0);
 }
 
@@ -769,9 +1604,12 @@ static int wrapgetSceneGraph(lua_State* l)
 void wrapModuleScene(lua_State* l)
 {
 	wrapMoveComponent(l);
+	wrapLightComponent(l);
 	wrapSceneNode(l);
 	wrapModelNode(l);
 	wrapInstanceNode(l);
+	wrapPointLight(l);
+	wrapSpotLight(l);
 	wrapSceneGraph(l);
 	LuaBinder::pushLuaCFunc(l, "getSceneGraph", wrapgetSceneGraph);
 }

+ 94 - 1
src/script/Scene.xml

@@ -33,7 +33,7 @@ static T* newSceneNode(SceneGraph* scene, CString name, TArgs... args)
 //==============================================================================
 static SceneGraph* getSceneGraph(lua_State* l)
 {
-	LuaBinder* binder = reinterpret_cast<LuaBinder*>(lua_getuserdata(l));
+	LuaBinder* binder = static_cast<LuaBinder*>(lua_getuserdata(l));
 
 	ScriptManager* scriptManager = 
 		reinterpret_cast<ScriptManager*>(binder->getParent());
@@ -70,6 +70,66 @@ static SceneGraph* getSceneGraph(lua_State* l)
 				</method>
 			</methods>
 		</class>
+		<class name="LightComponent">
+			<methods>
+				<method name="setDiffuseColor">
+					<args>
+						<arg>const Vec4&amp;</arg>
+					</args>
+				</method>
+				<method name="getDiffuseColor">
+					<return>const Vec4&amp;</return>
+				</method>
+				<method name="setSpecularColor">
+					<args>
+						<arg>const Vec4&amp;</arg>
+					</args>
+				</method>
+				<method name="getSpecularColor">
+					<return>const Vec4&amp;</return>
+				</method>
+				<method name="setRadius">
+					<args>
+						<arg>F32</arg>
+					</args>
+				</method>
+				<method name="getRadius">
+					<return>F32</return>
+				</method>
+				<method name="setDistance">
+					<args>
+						<arg>F32</arg>
+					</args>
+				</method>
+				<method name="getDistance">
+					<return>F32</return>
+				</method>
+				<method name="setInnerAngle">
+					<args>
+						<arg>F32</arg>
+					</args>
+				</method>
+				<method name="getInnerAngle">
+					<return>F32</return>
+				</method>
+				<method name="setOuterAngle">
+					<args>
+						<arg>F32</arg>
+					</args>
+				</method>
+				<method name="getOuterAngle">
+					<return>F32</return>
+				</method>
+				<method name="setShadowEnabled">
+					<args>
+						<arg>Bool</arg>
+					</args>
+				</method>
+				<method name="getShadowEnabled">
+					<return>Bool</return>
+				</method>
+			</methods>
+		</class>
 		<class name="SceneNode">
 			<methods>
 				<method name="getName">
@@ -84,6 +144,9 @@ static SceneGraph* getSceneGraph(lua_State* l)
 				<method name="tryGetComponent&lt;MoveComponent&gt;" alias="getMoveComponent">
 					<return>MoveComponent*</return>
 				</method>
+				<method name="tryGetComponent&lt;LightComponent&gt;" alias="getLightComponent">
+					<return>LightComponent*</return>
+				</method>
 			</methods>
 		</class>
 		<class name="ModelNode">
@@ -102,6 +165,22 @@ static SceneGraph* getSceneGraph(lua_State* l)
 				</method>
 			</methods>
 		</class>
+		<class name="PointLight">
+			<methods>
+				<method name="getSceneNodeBase">
+					<overrideCall>SceneNode&amp; ret = *self;</overrideCall>
+					<return>SceneNode&amp;</return>
+				</method>
+			</methods>
+		</class>
+		<class name="SpotLight">
+			<methods>
+				<method name="getSceneNodeBase">
+					<overrideCall>SceneNode&amp; ret = *self;</overrideCall>
+					<return>SceneNode&amp;</return>
+				</method>
+			</methods>
+		</class>
 		<class name="SceneGraph">
 			<methods>
 				<method name="newModelNode">
@@ -119,6 +198,20 @@ static SceneGraph* getSceneGraph(lua_State* l)
 					</args>
 					<return>InstanceNode*</return>
 				</method>
+				<method name="newPointLight">
+					<overrideCall><![CDATA[PointLight* ret = newSceneNode<PointLight>(self, arg0);]]></overrideCall>
+					<args>
+						<arg>const CString&amp;</arg>
+					</args>
+					<return>PointLight*</return>
+				</method>
+				<method name="newSpotLight">
+					<overrideCall><![CDATA[SpotLight* ret = newSceneNode<SpotLight>(self, arg0);]]></overrideCall>
+					<args>
+						<arg>const CString&amp;</arg>
+					</args>
+					<return>SpotLight*</return>
+				</method>
 			</methods>
 		</class>
 	</classes>

+ 70 - 20
tools/scene/Light.cpp

@@ -6,61 +6,111 @@
 #include "Common.h"
 #include <cassert>
 
+//==============================================================================
+static const aiNode* findNodeWithName(
+	const std::string& name, 
+	const aiNode* node)
+{
+	if(node == nullptr || node->mName.C_Str() == name)
+	{
+		return node;
+	}
+
+	const aiNode* out = nullptr;
+
+	// Go to children
+	for(uint32_t i = 0; i < node->mNumChildren; i++)
+	{
+		out = findNodeWithName(name, node->mChildren[i]);
+		if(out)
+		{
+			break;
+		}
+	}
+
+	return out;
+}
+
 //==============================================================================
 void exportLight(
 	const Exporter& exporter,
 	const aiLight& light, 
 	std::ofstream& file)
 {
-	if(light.mType != aiLightSource_POINT || light.mType != aiLightSource_SPOT)
+	if(light.mType != aiLightSource_POINT && light.mType != aiLightSource_SPOT)
+	{
+		LOGW("Skipping light %s. Unsupported type (0x%x)\n", 
+			light.mName.C_Str(), light.mType);
+		return;
+	}
+
+	if(light.mAttenuationLinear != 0.0)
 	{
-		LOGW("Skipping light %s. Unsupported type\n", light.mName.C_Str());
+		LOGW("Skipping light %s. Linear attenuation is not 0.0\n", 
+			light.mName.C_Str());
 		return;
 	}
 
 	file << "node = scene:new" 
-		<< ((light.mType != aiLightSource_POINT) ? "Point" : "Spot") 
-		<< "(\"" << light.mName.C_Str() << "\")\n";
+		<< ((light.mType == aiLightSource_POINT) ? "Point" : "Spot") 
+		<< "Light(\"" << light.mName.C_Str() << "\")\n";
 	
 	file << "lcomp = node:getLightComponent()\n";
 
+	// Colors
 	file << "lcomp:setDiffuseColor(" 
 		<< light.mColorDiffuse[0] << ", " 
 		<< light.mColorDiffuse[1] << ", " 
 		<< light.mColorDiffuse[2] << ", " 
-		<< light.mColorDiffuse[3]
-		<< ")\n";
+		<< "1.0)\n";
 
 	file << "lcomp:setSpecularColor(" 
 		<< light.mColorSpecular[0] << ", " 
 		<< light.mColorSpecular[1] << ", " 
 		<< light.mColorSpecular[2] << ", " 
-		<< light.mColorSpecular[3]
-		<< ")\n";
+		<< "1.0)\n";
 
-	aiMatrix4x4 trf;
-	aiMatrix4x4::Translation(light.mPosition, trf);
-	writeNodeTransform(exporter, file, "node", trf);
+	// Geometry
+	aiVector3D direction(0.0, 0.0, 1.0);
 
 	switch(light.mType)
 	{
 	case aiLightSource_POINT:
 		{
-			file << "\t\t<type>point</type>\n";
-
 			// At this point I want the radius and have the attenuation factors
 			// att = Ac + Al*d + Aq*d^2. When d = r then att = 0.0. Also if we 
-			// assume that Ac is 0 then:
-			// 0 = Al*r + Aq*r^2. Solving by r is easy
-			float r = -light.mAttenuationLinear / light.mAttenuationQuadratic;
-			file << "\t\t<radius>" << r << "</radius>\n";
-			break;
+			// assume that Al is 0 then:
+			// 0 = Ac + Aq*r^2. Solving by r is easy
+			float r = 
+				sqrt(light.mAttenuationConstant / light.mAttenuationQuadratic);
+			file << "lcomp:setRadius(" << r << ")\n";
 		}
-	case aiLightSource_SPOT:
-		file << "\t\t<type>spot</type>\n";
 		break;
+	case aiLightSource_SPOT:
+		{
+			float dist = 
+				sqrt(light.mAttenuationConstant / light.mAttenuationQuadratic);
+
+			file << "lcomp:setInnerAngle(" << light.mAngleInnerCone << ")\n"
+				<< "lcomp:setOuterAngle(" << light.mAngleOuterCone << ")\n"
+				<< "lcomp:setDistance(" << dist << ")\n";
+
+			direction = light.mDirection;
+			break;
+		}
 	default:
 		assert(0);
 		break;
 	}
+
+	// Transform
+	const aiNode* node = 
+		findNodeWithName(light.mName.C_Str(), exporter.scene->mRootNode);
+	
+	if(node == nullptr)
+	{
+		ERROR("Couldn't find node for light %s", light.mName.C_Str());
+	}
+
+	writeNodeTransform(exporter, file, "node", node->mTransformation);
 }

+ 8 - 0
tools/scene/Main.cpp

@@ -240,6 +240,14 @@ static void exportScene(Exporter& exporter)
 		}
 	}
 
+	//
+	// Lights
+	//
+	for(unsigned i = 0; i < exporter.scene->mNumLights; i++)
+	{
+		exportLight(exporter, *exporter.scene->mLights[i], file);
+	}
+
 	//
 	// Animations
 	//