;; note that xtlang mmmul is pre-multiplied! (not post as GLSL)
(bind-func xtm_project
  (lambda (pt_in:float* pt_out:float* model view projection)
    (let ((x (pref pt_in 0))
          (y (pref pt_in 1))
          (z (pref pt_in 2))
          (vp_x (i32tof xtm_render_x)) ;; viewport x
          (vp_y (i32tof xtm_render_y)) ;; viewport y
          (vp_w (i32tof xtm_render_w))
          (vp_h (i32tof xtm_render_h))
          (vp_n xtm_render_near)
          (vp_f xtm_render_far)
          (mvp:float* (salloc 16))
          (tmp:float* (salloc 16))
          (vec:float* (salloc 4)))
      (mmmul model view tmp)
      (mmmul tmp projection mvp)
      (mmmul pt_in 1 4 mvp 4 4 vec)
      (if (<> (pref vec 3) 0.0)
          (vsmul vec (/ 1.0 (pref vec 3)) 4 pt_out)) ;; normalize W!
      (pset! pt_out 0 (* (+ 1.0 (pref pt_out 0)) 0.5 vp_w))
      (pset! pt_out 1 (* (+ 1.0 (pref pt_out 1)) 0.5 vp_h))
      (pset! pt_out 2 (+ (* (pref pt_out 2) (- vp_f vp_n)) vp_n))
      void)))