                        {(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))
 

(def u-light-angle
  (g/uniform "uLightAngle" :vec3))

(def program-diffuse-flat
  (p/program
   {:vertex-shader   {(g/gl-position) (-> u-p-matrix

        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)
                          :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
