;; when working with OpenGL
;; extempore's mmul is pre mutipled (not post as in GLSL)
;; so the same matrix mul is post in GLSL and pre in XTM (i.e. here!)
(bind-func shader_update_matrices_lvs
  (let ((i:i32 0)
        (mlvpb:float* (alloc (* 10 16)))
        (bias:float* (alloc 16)))
    (pfill! bias
            0.5 0.0 0.0 0.0
            0.0 0.5 0.0 0.0
            0.0 0.0 0.5 0.0
            0.5 0.5 0.5 1.0)
    (lambda (shader:ShaderProgram* m:float* v p:float* lights:i32 lv:float*) ;; lv is lights
      ;; view
      (dotimes (i lights)
        (let ((mlv:float* (salloc 16))
              (mlvp:float* (salloc 16)))
          (mmmul m (pref-ptr lv (* i 16)) mlv)
          (mmmul mlv p mlvp)
          (mmmul mlvp bias (pref-ptr mlvpb (* i 16)))))
      (glUniformMatrix4fv (glGetUniformLocation (id shader) "LightModelViewProjectionMatrix")
                          lights GL_FALSE mlvpb)
      (let ((mv (salloc 48))
            (mvp (pref-ptr mv 16))
            (mn (pref-ptr mv 32)))
        (mmmul m v mv) ;; final mv set
        (mtrans mv 4 4 mn) ;; using mn as a temporary here!!
        (minverse mn 4 mvp) ;; using mvp as a temporary
        (mat4_to_mat3 mvp mn)  ;; final mn set
        (mmmul mv p mvp) ;; final mvp set
        (glUniformMatrix4fv (glGetUniformLocation (id shader) "ModelMatrix") 1 GL_FALSE m)
        (glUniformMatrix4fv (glGetUniformLocation (id shader) "ViewMatrix") 1 GL_FALSE v)
        (glUniformMatrix4fv (glGetUniformLocation (id shader) "ProjectionMatrix") 1 GL_FALSE p)
        (glUniformMatrix3fv (glGetUniformLocation (id shader) "NormalMatrix") 1 GL_FALSE mn)
        (glUniformMatrix4fv (glGetUniformLocation (id shader) "ModelViewMatrix") 1 GL_FALSE mv)
        (glUniformMatrix4fv (glGetUniformLocation (id shader) "ModelViewProjectionMatrix") 1 GL_FALSE mvp)
        void))))