diff --git a/light.lua b/light.lua
index 2dce32a647d040c7cba52f079953062ccc8a3c98..a5308182d61ab06e7cab8a6ffb7e1ac10b76466a 100644
--- a/light.lua
+++ b/light.lua
@@ -11,7 +11,7 @@ light.__index = light
 
 -- Creates a new light with transform t and RGB value diff and spec
 function light.new(t, diff, spec)
-  local l = {transform = t, diffuse = diff or {255, 255, 255}, specular = spec or {255, 255, 255}}
+  local l = {transform = t, diffuse = diff or vector.new(3, {255, 255, 255}), specular = spec or vector.new(3, {255, 255, 255})}
   setmetatable(l, light)
   return l
 end
diff --git a/shape.lua b/shape.lua
index c6f09c0cc0550964b875b3e1b145583a81f7ed8e..7ac113806206722b5c88b3b3aa37d91f25cd3554 100644
--- a/shape.lua
+++ b/shape.lua
@@ -2,7 +2,7 @@ require("kara3d.vector")
 require("kara3d.matrix")
 require("kara3d.quaternion")
 require("kara3d.transform")
-require("kara3d.lights")
+require("kara3d.light")
 require("kara3d.camera")
 require("utils")
 re = require("re")
@@ -20,11 +20,12 @@ material.__index = material
 
 
 
-function material.new(a, d, sp, sh)
-  local m = {ambient = a or vector.new(3, {1, 1, 1}), 
-            diffuse = d or vector.new(3, {1, 1, 1}),
-            specular = sp or vector.new(3, {1, 1, 1}),
-            shininess = sh or 1}
+function material.new(amb, diff, spec, sh, al)
+  local m = {ambient = vector.new(3, amb) or vector.new(3, {1, 1, 1}), 
+            diffuse = vector.new(3, diff) or vector.new(3, {1, 1, 1}),
+            specular = vector.new(3, spec) or vector.new(3, {1, 1, 1}),
+            shininess = sh or 1,
+            alpha = al or 0}
   setmetatable(m, material)
   return m
 end
@@ -38,46 +39,37 @@ function face.new(v, n, t)
   return f
 end
 
-function face:mean()
-  sum = vector.zero(3)
-  for i = 1, #self.vertices do
-    sum = sum + self.vertices[i]
-  end
-  return (1/(#self.vertices)) * sum
-end
 
 
-function face:shade(mat, lights, ambient)
+function face.shade(N, P, mat, lights, ambient, cam)
   local Ka = mat.ambient
   local Kd = mat.diffuse
   local Ks = mat.specular
   local shine = mat.shininess
-  
-  local N = self.normal:normalized()
-  local P = self:mean():normalized()
-  local V = vector.new(3, {0, 0, -1})
+
+  local V = (cam.transform:position(true) - P):normalized()
 
   local I = Ka * ambient
 
   for i = 1, #lights do
     local l = lights[i]
-    local L = (light.transform:position(true) - P):normalized()
-    local R = 2 * vector.dot(L, N) * N - L
+    local L = (l.transform:position(true) - P):normalized()
+    local R = 2 * math.max(vector.dot(L, N), 0) * N - L
 
     -- Diffuse component
-    I = I + Kd * vector.dot(L, N) * l.diffuse
+    I = I + Kd * math.max(vector.dot(L, N), 0) * l.diffuse
 
     -- Specular component
-    I = I + Ks * math.pow(vector.dot(R, V), shine) * l.specular
+    I = I + Ks * math.pow(math.max(vector.dot(R, V), 0), shine) * l.specular
   end
   
-  return I
+  return I:clamp(0, 255)
 end
 
 
 -- Creates a new shape with transform t and faces f
-function shape.new(t, f)
-  local s = {transform = t, faces = f or {}}
+function shape.new(t, f, mat)
+  local s = {transform = t, faces = f or {}, material = mat or material.new()}
   setmetatable(s, shape)
   return s
 end
@@ -90,10 +82,17 @@ end
 
 -- ********** INSTANCE FUNCTIONS **********
 
+function shape:set_material(mat)
+  self.material = mat
+  return self
+end
+
+
+
 -- Generates a line for each face of this shape, with the indicated tags
 -- The boolean cull determines if the faces facing away from the screen are
 -- drawn or not
-function shape:draw(subs, line, tags, cull, cam)
+function shape:draw(subs, line, tags, cull, cam, ambient, lights)
   local l = table.copy(line)
   local p = self.transform:position(true)
   local r = self.transform:rotation(true)
@@ -108,8 +107,8 @@ function shape:draw(subs, line, tags, cull, cam)
 
   for i = 1, #self.faces do
     local face = self.faces[i]
-    local n = quaternion.mul_vector(r, face.normal)
-    n = quaternion.mul_vector(cam_inv_rot, n)
+    local norm = quaternion.mul_vector(r, face.normal)
+    local n = quaternion.mul_vector(cam_inv_rot, norm)
 
     if not (cull and n:z() > 0) then
       local vs = face.vertices
@@ -129,7 +128,16 @@ function shape:draw(subs, line, tags, cull, cam)
         str = str .. "l " .. v:x() .. " " .. v:y() .. " "
       end
 
-      l.text = str
+      local P = (p + sum) * (1/#vs)
+      
+
+      local color = face.shade(n, P, self.material, lights, ambient, cam)
+      local colorstr = string.format("{\\c%s\\alpha%s}",
+        ass_color(color:x(), color:y(), color:z()),
+        ass_alpha(self.material.alpha)
+      )
+
+      l.text = colorstr .. str
       -- layers must be between 0 and 9999999999
       l.layer = 500000000 + math.floor((p + sum):z() / #vs)
       l.effect = "fx"
diff --git a/vector.lua b/vector.lua
index 60a4e6749c588be863a4b92549fce9d5a327257d..316bdfbb37ba9b7c12d4766a8e5bc53d0beadd02 100644
--- a/vector.lua
+++ b/vector.lua
@@ -139,6 +139,12 @@ function vector:y() return self.values[2] end
 function vector:z() return self.values[3] end
 function vector:w() return self.values[4] end
 
+-- Clamp vector values
+function vector:clamp(min, max)
+  for i = 1, self.size do self:set(i, clamp(self:get(i), min, max)) end 
+  return self
+end
+
 -- ********** OPERATOR OVERLOADING **********
 
 -- + binary operator overload