         height           (.-clientHeight node)
         driver           (make-driver gl)
         starting-program 0
-        programs         {:diffuse-flat  (gd/program driver program-diffuse-flat)
-                          :diffuse-light (gd/program driver program-diffuse-light)
-                          :texture-flat  (gd/program driver program-texture-flat)
-                          :texture-light (gd/program driver program-texture-light)
-                          :sky-box       (gd/program driver program-sky-box)}
+        programs         {:diffuse-flat               (gd/program driver program-diffuse-flat)
+                          :diffuse-light              (gd/program driver program-diffuse-light)
+                          :texture-flat               (gd/program driver program-texture-flat)
+                          :texture-light              (gd/program driver program-texture-light)
+                          :diffuse-per-fragment-light (gd/program driver program-diffuse-per-fragment)
+                          :texture-per-fragment-light (gd/program driver program-texture-per-fragment)
+                          :sky-box                    (gd/program driver program-sky-box)}
         now              (.getTime (js/Date.))
         app-state        (-> (app-state width height gl node now)
                              (update-in [:comms] merge {:controls controls

                                                                      (boolean vertices)
                                                                      (boolean normals)]))
  (let [[x y z] [(js/Math.sin now)
                 (js/Math.cos now)
                 (js/Math.sin (* now 2))]]
    {u-p-matrix           (object-array p)
     u-mv-matrix          (object-array mv)

                       {(g/gl-frag-color) l-color})
    :precision {:float :mediump}}))

(def program-diffuse-per-fragment
  (p/program
   {:vertex-shader   {v-position           (g/* u-mv-matrix (g/vec4 a-position 1))
                      (g/gl-position)      (g/* u-p-matrix v-position)
                      v-transformed-normal (g/* u-n-matrix a-vertex-normal)}
    :fragment-shader (let [light-direction           (g/normalize (g/- u-point-lighting-location (g/swizzle v-position :xyz)))
                           direction-light-weighting (g/max (g/dot (g/normalize v-transformed-normal) light-direction) 0)
                           light-weighting           (g/* (g/+ u-ambient-color u-point-lighting-color)
                                                          direction-light-weighting)
                           l-diffuse                 u-diffuse
                           a                         (g/swizzle l-diffuse :a)
                           rgb                       (g/* (g/swizzle l-diffuse :rgb) light-weighting)]
                       {(g/gl-frag-color) (g/vec4 rgb (g/swizzle l-diffuse :a))})
    :precision       {:float :mediump}}))

(def program-texture-per-fragment
  (p/program
   {:vertex-shader   {v-position           (g/* u-mv-matrix (g/vec4 a-position 1))
                      (g/gl-position)      (g/* u-p-matrix v-position)
                      v-texture-coord      a-tex-coord-0
                      v-transformed-normal (g/* u-n-matrix a-vertex-normal)}
    :fragment-shader (let [light-direction           (g/normalize (g/- u-point-lighting-location (g/swizzle v-position :xyz)))
                           direction-light-weighting (g/max (g/dot (g/normalize v-transformed-normal) light-direction) 0)
                           light-weighting           (g/* (g/+ u-ambient-color u-point-lighting-color)
                                                          direction-light-weighting)
                           texture-color             (g/texture2D u-sampler (g/vec2 (g/swizzle v-texture-coord :st)))
                           a                         (g/swizzle texture-color :a)
                           rgb                       (g/* (g/swizzle texture-color :rgb) light-weighting)]
                       {(g/gl-frag-color) (g/vec4 rgb (g/swizzle texture-color :a))})
    :precision {:float :mediump}}))

(def u-sky-box-inverse-mv-matrix
  (g/uniform "uSkyBoxInverseMVMatrix" :mat4))

