;;-*-Lisp-*-
(in-package goal)

;; name: joint.gc
;; name in dgo: joint
;; dgos: ENGINE, GAME

(define-extern create-interpolated-joint-animation-frame (function joint-anim-frame int joint-control int))
(define-extern *anim-manager* art-joint-anim-manager)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; experimental new joint decompressor
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define *use-new-decompressor* #t)

;; this was re-written in GOAL. Despite being not well optimized, it ends up being faster
;; than the original when decompiled with MIPS2C.

;; request to decompress data from an animation
(deftype joint-decomp-request (structure)
  ((jacc joint-anim-compressed-control)
   (frame int)
   (frame-interp float)
   (amount float))
  )

(deftype blend-tree-stack-frame (structure)
  ((weights float 24)
   (quads   vector 6 :inline :overlay-at weights))
  )

(deftype new-joint-decompressor-work (structure)
  ((requests joint-decomp-request 24 :inline)
   (num-requests int32)
   (blend-stack blend-tree-stack-frame 4 :inline)
   )
  (:methods
   (eval-blend-tree! (_type_ joint-control) none)
   (output-blend-tree! (_type_ joint-control) none)
   (build-requests! (_type_ joint-control) none)
   (init-frame! (_type_ joint-anim-frame int) none)
   (process-request! (_type_ joint-decomp-request joint-anim-frame int) none)
   (process-requests! (_type_ joint-anim-frame int) none)
   (finalize-frame! (_type_ joint-anim-frame int) none)
   )
  )

(deftype new-joint-decompressor-stats (structure)
  ((num-calls int32)
   (num-anims int32)
   (num-joints int32)
   (total-time int32)
   )
  (:methods
    (reset! (_type_) none)
    )
  )

(defmethod reset! ((this new-joint-decompressor-stats))
  (set! (-> this num-calls) 0)
  (set! (-> this num-anims) 0)
  (set! (-> this num-joints) 0)
  (set! (-> this total-time) 0)
  (none)
  )

(define *new-joint-decompressor-stats* (new 'global 'new-joint-decompressor-stats))
(define *new-joint-decompressor-work* (new 'global 'new-joint-decompressor-work))

(defun new-joint-decompressor ((dst joint-anim-frame) (num-joints int) (jc joint-control))
  "Decompress a joint animation!"
  (+! (-> *new-joint-decompressor-stats* num-calls) 1)
  ;; determine anim weights, write them out to the joint-control for other stuff to see.
  (eval-blend-tree! *new-joint-decompressor-work* jc)
  (output-blend-tree! *new-joint-decompressor-work* jc)

  ;; figure out which animations need decompression
  (build-requests! *new-joint-decompressor-work* jc)

  ;; run the decompression
  (init-frame! *new-joint-decompressor-work* dst num-joints)
  (process-requests! *new-joint-decompressor-work* dst num-joints)
  (finalize-frame! *new-joint-decompressor-work* dst num-joints)

  (none)
  )

(defmethod eval-blend-tree! ((this new-joint-decompressor-work) (jc joint-control))
  "Evaluate weights of all channels, producing the final per-animation weights in the first stack-frame."

  (let ((num-channels (+ (-> jc active-channels) (-> jc float-channels)))
        (stack-top 0)
        )
    (when (> num-channels 24)
      (break!) ;; insufficient weights per stack frame
      )

    ;; loop over channels
    (dotimes (chan-idx num-channels)
      (let ((chan (-> jc channel chan-idx)))
        (case (-> chan command)

          (((joint-control-command push)) ;; push new anim to stack frame
           (when (> stack-top 4)
             (break!) ;; insufficient stack frames.
             )

           ;; init all weights to zero:
           (let ((new-frame (-> this blend-stack stack-top)))
             (vector-zero! (-> new-frame quads 0))
             (vector-zero! (-> new-frame quads 1))
             (vector-zero! (-> new-frame quads 2))
             (vector-zero! (-> new-frame quads 3))
             (vector-zero! (-> new-frame quads 4))
             (vector-zero! (-> new-frame quads 5))
             ;; except for this channel
             (set! (-> new-frame weights chan-idx) 1.0)
             )
           (+! stack-top 1) ;; bump stack pointer!
           )

          ;; blend case: note that push1/stack1 always are a pair, so we can treat push1 as blend and ignore
          ;; the stack1 as an optimization.
          (((joint-control-command blend) (joint-control-command push1) (joint-control-command float))
           (let* ((sf (-> this blend-stack (- stack-top 1))) ;; modify most recent stack frame
                  (new-weight (-> chan frame-interp (-> jc active-frame-interp)))
                  (old-weight (- 1.0 new-weight)))

             ;; do the multiplies:
             (rlet ((temp :class vf)
                    (weight-vec :class vf))
               (.mov weight-vec old-weight)
               (dotimes (i 6)
                 (.lvf temp (&-> sf quads i quad))
                 (.mul.x.vf temp temp weight-vec)
                 (.svf (&-> sf quads i quad) temp)
                 )
               (+! (-> sf weights chan-idx) new-weight)
               )
             )
           )

          ;; stack case: pop two frames, add together, push result.
          (((joint-control-command stack))
           (let* ((sf0 (-> this blend-stack (- stack-top 1)))
                  (sf1 (-> this blend-stack (- stack-top 2)))
                  (weight0 (-> chan frame-interp (-> jc active-frame-interp)))
                  (weight1 (- 1.0 weight0)))


             (rlet ((temp0 :class vf)
                    (temp1 :class vf)
                    (weight0-vec :class vf)
                    (weight1-vec :class vf))
               (.mov weight0-vec weight0)
               (.mov weight1-vec weight1)
               (dotimes (i 6)
                 (.lvf temp0 (&-> sf0 quads i quad))
                 (.lvf temp1 (&-> sf1 quads i quad))
                 (.mul.x.vf temp0 temp0 weight0-vec)
                 (.mul.x.vf temp1 temp1 weight1-vec)
                 (.add.vf temp0 temp0 temp1)
                 (.svf (&-> sf1 quads i quad) temp0)
                 )
               )
             (-! stack-top 1) ;; pop stack frame
             )
           )

          )
        )
      )
    )

  (none)
  )

(defmethod output-blend-tree! ((this new-joint-decompressor-work) (jc joint-control))
  "Copy result of the blend tree evaluation into the joint-control."
  (let ((num-channels (+ (-> jc active-channels) (-> jc float-channels))))
    (dotimes (chan-idx num-channels)
      (set! (-> jc channel chan-idx inspector-amount)
            (the int (* 255.0 (-> this blend-stack 0 weights chan-idx))))
      )
    )
  (none)
  )

(defmethod build-requests! ((this new-joint-decompressor-work) (jc joint-control))
  "Use the anim weights computed by eval-blend-tree! to build decompression requests"

  (set! (-> this num-requests) 0)

  (let ((num-channels (+ (-> jc active-channels) (-> jc float-channels))))
    (dotimes (chan-idx num-channels)
      (let ((weight (-> this blend-stack 0 weights chan-idx))
            (chan (-> jc channel chan-idx)))
        (when (> weight 0.001) ;; only both if weight is nonzero
          (let* ((req (-> this requests (-> this num-requests))) ;; request to create
                 (jacc (-> chan frame-group frames))             ;; compressed animation
                 (frame-num (-> chan frame-num))                 ;; floating-point frame (eg 1.23)
                 (base-frame (the int frame-num))                ;; integer round-down frame (eg 1)
                 (frac-frame (- frame-num (the float base-frame))) ;; interp to next frame (eg 0.23)
                 (last-frame (the int (- (-> jacc num-frames) 1)))
                 )
            (+! (-> this num-requests) 1)

            ;; check our frame group is valid
            ;; TODO

            ;; make sure we didn't go off the end of the animation:
            (when (>= base-frame last-frame)
              (set! frac-frame 0.0)
              (set! base-frame last-frame)
              )

            ;; set up request
            (set! (-> req jacc) jacc)
            (set! (-> req frame) base-frame)
            (set! (-> req frame-interp) frac-frame)
            (set! (-> req amount) weight)
            )
          )
        )
      )
    )
  (none)
  )

(defmethod init-frame! ((this new-joint-decompressor-work) (output-frame joint-anim-frame) (num-joints int))
  "Initialize an output frame by zeroing the data."
  (let ((num-qwc 8) ;; 2x matrix, each 4 qw
        (data (the (pointer uint128) output-frame)))
    (when (> num-joints 2) ;; we have transformq's
      (+! num-qwc (* 3 (- num-joints 2)))
      )

    (let ((data-end (&+ data (* num-qwc 16))))
      (rlet ((zero :class vf))
        (.xor.vf zero zero zero)
        (while (!= data data-end) ;; this loop is 5 instructions :)
          (.svf data zero)
          (&+! data 16)
          )
        )
      )

    )
  (none)
  )

(defmethod process-requests! ((this new-joint-decompressor-work) (output-frame joint-anim-frame) (num-joints int))
  "Decompress all pending animation requests."
  (dotimes (i (-> this num-requests))
    (process-request! this (-> this requests i) output-frame num-joints)
    )
  (set! (-> this num-requests) 0)
  (none)
  )

(defmacro fderef-s16 (ptr)
  `(the float (-> (the (pointer int16) ,ptr)))
  )

(defmacro deref-f32 (ptr)
  `(-> (the (pointer float) ,ptr))
  )

(defconstant QUAT_SCALE 0.000030517578125)
(defconstant SCALE_SCALE 0.000244140625)

(defun add-scaled-matrix! ((dest matrix) (src matrix) (scale float))
  (dotimes (i 16)
    (+! (-> dest data i) (* scale (-> src data i)))
    )
  )

(defun decomp-fixed ((output-frame joint-anim-frame) (num-joints int) (anim joint-anim-compressed-fixed) (amount float))
  "Decompress the fixed part."

  (let* ((mbits (-> anim hdr matrix-bits))
         (data (the pointer (&-> anim data 0 quad)))
         (data64 (the (pointer uint64) (&+ data (-> anim offset-64))))
         (data32 (the (pointer uint32) (&+ data (-> anim offset-32))))
         (data16 (the (pointer uint16) (&+ data (-> anim offset-16))))
         (ctrl-ptr (-> anim hdr control-bits))
         )
    ;; process matrix:
    (when (zero? (logand mbits 1))
      ;; matrix comes from fixed data
      (add-scaled-matrix! (-> output-frame matrices 0) (the matrix data64) amount)
      (&+! data64 64)
      )

    (when (zero? (logand mbits 2))
      ;; matrix comes from fixed data
      (add-scaled-matrix! (-> output-frame matrices 1) (the matrix data64) amount)
      (&+! data64 64)
      )

    ;; process tq's
    (dotimes (tqi num-joints) ;; TODO - not sure if this is too many??
      (let* ((ctrl-idx (/ tqi 8))
             (ctrl-shift (* 4 (mod tqi 8)))
             (ctrl (logand #b1111 (sar (-> ctrl-ptr ctrl-idx) ctrl-shift)))
             (tq (-> output-frame data tqi))
             )
        ;; TRANS
        (when (zero? (logand ctrl #b0001))
          ;; we have trans
          (cond
            ((nonzero? (logand ctrl #b1000))
             ;; big trans
             (+! (-> tq trans x) (* amount (deref-f32 data64)))
             (&+! data64 4)
             (+! (-> tq trans y) (* amount (deref-f32 data64)))
             (&+! data64 4)
             (+! (-> tq trans z) (* amount (deref-f32 data32)))
             (&+! data32 4)
             )
            (else
             ;; little trans
             (+! (-> tq trans x) (* amount (fderef-s16 data32) 4.))
             (&+! data32 2)
             (+! (-> tq trans y) (* amount (fderef-s16 data32) 4.))
             (&+! data32 2)
             (+! (-> tq trans z) (* amount (fderef-s16 data16) 4.))
             (&+! data16 2)
             )
            )
          )
        ;; QUAT
        (when (zero? (logand ctrl #b0010))
          (let ((temp (new 'stack-no-clear 'vector)))
            (set! (-> temp x) (fderef-s16 data64)) (&+! data64 2)
            (set! (-> temp y) (fderef-s16 data64)) (&+! data64 2)
            (set! (-> temp z) (fderef-s16 data64)) (&+! data64 2)
            (set! (-> temp w) (fderef-s16 data64)) (&+! data64 2)

            (let ((dot (+ (* (-> temp x) (-> tq quat x))
                          (* (-> temp y) (-> tq quat y))
                          (* (-> temp z) (-> tq quat z))
                          (* (-> temp w) (-> tq quat w)))))
              (when (< dot 0.0)
                (*! (-> temp x) -1.)
                (*! (-> temp y) -1.)
                (*! (-> temp z) -1.)
                (*! (-> temp w) -1.)
                )
              (+! (-> tq quat x) (* amount (-> temp x) QUAT_SCALE))
              (+! (-> tq quat y) (* amount (-> temp y) QUAT_SCALE))
              (+! (-> tq quat z) (* amount (-> temp z) QUAT_SCALE))
              (+! (-> tq quat w) (* amount (-> temp w) QUAT_SCALE))
              )
            )
          )
        ;; SCALE
        (when (zero? (logand ctrl #b0100))
          (+! (-> tq scale x) (* amount (fderef-s16 data32) SCALE_SCALE))
          (&+! data32 2)
          (+! (-> tq scale y) (* amount (fderef-s16 data32) SCALE_SCALE))
          (&+! data32 2)
          (+! (-> tq scale z) (* amount (fderef-s16 data16) SCALE_SCALE))
          (&+! data16 2)
          )
        )
      )
    )

  (none)
  )

(defun decomp-frame ((output-frame joint-anim-frame) (num-joints int) (anim joint-anim-compressed-frame) (amount float) (hdr joint-anim-compressed-hdr))
  "Decompress the fixed part."

  (let* ((mbits (-> hdr matrix-bits))
         (data (the pointer (-> anim data)))
         (data64 (the (pointer uint64) (&+ data (-> anim offset-64))))
         (data32 (the (pointer uint32) (&+ data (-> anim offset-32))))
         (data16 (the (pointer uint16) (&+ data (-> anim offset-16))))
         (ctrl-ptr (-> hdr control-bits))
         )
    ;; process matrix:
    (when (nonzero? (logand mbits 1))
      ;; matrix comes from fixed data
      (add-scaled-matrix! (-> output-frame matrices 0) (the matrix data64) amount)
      (&+! data64 64)
      )

    (when (nonzero? (logand mbits 2))
      ;; matrix comes from fixed data
      (add-scaled-matrix! (-> output-frame matrices 1) (the matrix data64) amount)
      (&+! data64 64)
      )

    ;; process tq's
    (dotimes (tqi num-joints) ;; TODO - not sure if this is too many??
      (let* ((ctrl-idx (/ tqi 8))
             (ctrl-shift (* 4 (mod tqi 8)))
             (ctrl (logand #b1111 (sar (-> ctrl-ptr ctrl-idx) ctrl-shift)))
             (tq (-> output-frame data tqi))
             )

        ;; TRANS
        (when (nonzero? (logand ctrl #b0001))
          ;; we have trans
          (cond
            ((nonzero? (logand ctrl #b1000))
             ;; big trans
             (+! (-> tq trans x) (* amount (deref-f32 data64)))
             (&+! data64 4)
             (+! (-> tq trans y) (* amount (deref-f32 data64)))
             (&+! data64 4)
             (+! (-> tq trans z) (* amount (deref-f32 data32)))
             (&+! data32 4)
             )
            (else
             ;; little trans
             (+! (-> tq trans x) (* amount (fderef-s16 data32) 4.))
             (&+! data32 2)
             (+! (-> tq trans y) (* amount (fderef-s16 data32) 4.))
             (&+! data32 2)
             (+! (-> tq trans z) (* amount (fderef-s16 data16) 4.))
             (&+! data16 2)
             )
            )
          )
        ;; QUAT
        (when (nonzero? (logand ctrl #b0010))
          (let ((temp (new 'stack-no-clear 'vector)))

            (set! (-> temp x) (fderef-s16 data64)) (&+! data64 2)
            (set! (-> temp y) (fderef-s16 data64)) (&+! data64 2)
            (set! (-> temp z) (fderef-s16 data64)) (&+! data64 2)
            (set! (-> temp w) (fderef-s16 data64)) (&+! data64 2)

            (let ((dot (+ (* (-> temp x) (-> tq quat x))
                          (* (-> temp y) (-> tq quat y))
                          (* (-> temp z) (-> tq quat z))
                          (* (-> temp w) (-> tq quat w)))))
              (when (< dot 0.0)
                (*! (-> temp x) -1.)
                (*! (-> temp y) -1.)
                (*! (-> temp z) -1.)
                (*! (-> temp w) -1.)
                )
              (+! (-> tq quat x) (* amount (-> temp x) QUAT_SCALE))
              (+! (-> tq quat y) (* amount (-> temp y) QUAT_SCALE))
              (+! (-> tq quat z) (* amount (-> temp z) QUAT_SCALE))
              (+! (-> tq quat w) (* amount (-> temp w) QUAT_SCALE))
              )
            )
          )
        ;; SCALE
        (when (nonzero? (logand ctrl #b0100))
          (+! (-> tq scale x) (* amount (fderef-s16 data32) SCALE_SCALE))
          (&+! data32 2)
          (+! (-> tq scale y) (* amount (fderef-s16 data32) SCALE_SCALE))
          (&+! data32 2)
          (+! (-> tq scale z) (* amount (fderef-s16 data16) SCALE_SCALE))
          (&+! data16 2)
          )
        )
      )
    )

  (none)
  )

(defmethod process-request! ((this new-joint-decompressor-work) (request joint-decomp-request) (output-frame joint-anim-frame) (num-joints int))
  "Decompress a single animation, adding to accumulator"

  (+! (-> *new-joint-decompressor-stats* num-anims) 1)
  (+! (-> *new-joint-decompressor-stats* num-joints) (+ num-joints 2))


  ;; first, the fixed part
  (decomp-fixed output-frame num-joints (-> request jacc fixed) (-> request amount))

  ;; base frame
  (decomp-frame
   output-frame
   num-joints
   (-> request jacc data (-> request frame))
   (* (- 1.0 (-> request frame-interp)) (-> request amount))
   (-> request jacc fixed hdr)
   )

  ;; interpolate to next frame
  (cond
    ((!= 0.0 (-> request frame-interp))
     (decomp-frame
      output-frame
      num-joints
      (-> request jacc data (+ 1 (-> request frame)))
      (* (-> request frame-interp) (-> request amount))
      (-> request jacc fixed hdr))
     )
    (else
     )
    )

  (none)
  )

(defmethod finalize-frame! ((this new-joint-decompressor-work) (output-frame joint-anim-frame) (num-joints int))
  (when (<= num-joints 2)
    (return #f)
    )

  (dotimes (tqi (- num-joints 2))
    (let ((tq (-> output-frame data tqi)))
      (set! (-> tq trans w) 1.0)
      (set! (-> tq scale w) 1.0)
      (quaternion-normalize! (-> tq quat))
      )
    )
  (none)
  )


;; DECOMP BEGINS

(defmethod print ((this joint))
  (format #t "#<~A ~S ~D @ #x~X>" (-> this type) (-> this name) (-> this number) this)
  this
  )

(defmethod mem-usage ((this joint) (arg0 memory-usage-block) (arg1 int))
  (set! (-> arg0 length) (max 68 (-> arg0 length)))
  (set! (-> arg0 data 67 name) "joint")
  (+! (-> arg0 data 67 count) 1)
  (let ((v1-6 (asize-of this)))
    (+! (-> arg0 data 67 used) v1-6)
    (+! (-> arg0 data 67 total) (logand -16 (+ v1-6 15)))
    )
  this
  )

(defmethod print ((this joint-anim))
  (format #t "#<~A ~S ~D [~D] @ #x~X>" (-> this type) (-> this name) (-> this number) (-> this length) this)
  this
  )

(defmethod length ((this joint-anim))
  (-> this length)
  )

;; WARN: Return type mismatch uint vs int.
(defmethod asize-of ((this joint-anim-matrix))
  (the-as int (+ (-> joint-anim-matrix size) (* (-> this length) 64)))
  )

;; WARN: Return type mismatch uint vs int.
(defmethod asize-of ((this joint-anim-transformq))
  (the-as int (+ (-> joint-anim-transformq size) (* 48 (-> this length))))
  )

;; WARN: Return type mismatch uint vs int.
(defmethod asize-of ((this joint-anim-drawable))
  (the-as int (+ (-> joint-anim-drawable size) (* (-> this length) 4)))
  )

(defun joint-anim-login ((arg0 joint-anim-drawable))
  (dotimes (s5-0 (-> arg0 length))
    (if (-> arg0 data s5-0)
        (login (-> arg0 data s5-0))
        )
    )
  arg0
  )

(defun joint-anim-inspect-elt ((arg0 joint-anim) (arg1 float))
  (case (-> arg0 type)
    ((joint-anim-matrix)
     (inspect (-> (the-as joint-anim-matrix arg0) data (the int arg1)))
     )
    ((joint-anim-transformq)
     (format #t "~`transform`P~%" (-> (the-as joint-anim-transformq arg0) data (the int arg1)))
     )
    )
  arg0
  )

(defmethod mem-usage ((this joint-anim-drawable) (arg0 memory-usage-block) (arg1 int))
  (set! (-> arg0 length) (max 80 (-> arg0 length)))
  (set! (-> arg0 data 79 name) "joint-anim-drawable")
  (+! (-> arg0 data 79 count) 1)
  (let ((v1-6 (asize-of this)))
    (+! (-> arg0 data 79 used) v1-6)
    (+! (-> arg0 data 79 total) (logand -16 (+ v1-6 15)))
    )
  (dotimes (s3-0 (-> this length))
    (mem-usage (-> this data s3-0) arg0 arg1)
    )
  this
  )

(defun jacc-mem-usage ((arg0 joint-anim-compressed-control) (arg1 memory-usage-block) (arg2 int))
  (set! (-> arg1 length) (max 70 (-> arg1 length)))
  (set! (-> arg1 data 69 name) "joint-anim-compressed-control")
  (+! (-> arg1 data 69 count) 1)
  (let ((v1-7 (+ (* (-> arg0 num-frames) 4) 16)))
    (+! (-> arg1 data 69 used) v1-7)
    (+! (-> arg1 data 69 total) (logand -16 (+ v1-7 15)))
    )
  (set! (-> arg1 length) (max 71 (-> arg1 length)))
  (set! (-> arg1 data 70 name) "joint-anim-fixed")
  (+! (-> arg1 data 70 count) 1)
  (let ((v1-17 (+ (-> arg0 fixed-qwc) 16)))
    (+! (-> arg1 data 70 used) v1-17)
    (+! (-> arg1 data 70 total) (logand -16 (+ v1-17 15)))
    )
  (dotimes (v1-21 (the-as int (-> arg0 num-frames)))
    (set! (-> arg1 length) (max 72 (-> arg1 length)))
    (set! (-> arg1 data 71 name) "joint-anim-frame")
    (+! (-> arg1 data 71 count) 1)
    (let ((a2-15 (* (-> arg0 frame-qwc) 16)))
      (+! (-> arg1 data 71 used) a2-15)
      (+! (-> arg1 data 71 total) (logand -16 (+ a2-15 15)))
      )
    )
  arg0
  )

(defmethod print ((this joint-control-channel))
  (let ((t9-0 format)
        (a0-1 #t)
        (a1-0 "#<joint-control-channel ~A ~A ~F @ #x~X>")
        (v1-0 (-> this command))
        )
    (t9-0
      a0-1
      a1-0
      (cond
        ((= v1-0 (joint-control-command stack1))
         "stack1"
         )
        ((= v1-0 (joint-control-command push))
         "push"
         )
        ((= v1-0 (joint-control-command blend))
         "blend"
         )
        ((= v1-0 (joint-control-command push1))
         "push1"
         )
        ((= v1-0 (joint-control-command float))
         "float"
         )
        ((= v1-0 (joint-control-command stack))
         "stack"
         )
        (else
          "*unknown*"
          )
        )
      (-> this frame-group)
      (-> this frame-num)
      this
      )
    )
  this
  )

;; WARN: Return type mismatch uint vs int.
(defmethod asize-of ((this joint-control))
  (the-as int (+ (-> this type size) (* (-> this allocated-length) 64)))
  )

(defmethod new joint-control ((allocation symbol) (type-to-make type) (arg0 int))
  (let ((v0-0 (object-new allocation type-to-make (the-as int (+ (-> type-to-make size) (* arg0 64))))))
    (set! (-> v0-0 allocated-length) (the-as uint arg0))
    (set! (-> v0-0 active-channels) (the-as uint 0))
    (set! (-> v0-0 float-channels) (the-as uint 0))
    (set! (-> v0-0 root-channel) (-> v0-0 channel))
    (set! (-> v0-0 generate-frame-function) create-interpolated-joint-animation-frame)
    (set! (-> v0-0 prebind-function) #f)
    (set! (-> v0-0 postbind-function) #f)
    (set! (-> v0-0 effect) #f)
    (set! (-> v0-0 top-anim) #f)
    (set! (-> v0-0 override) #f)
    (dotimes (v1-4 arg0)
      (set! (-> v0-0 channel v1-4 parent) v0-0)
      )
    (set! (-> v0-0 blend-index) (the-as uint -1))
    v0-0
    )
  )

(defmethod debug-print-channels ((this joint-control) (arg0 symbol))
  (format arg0 "~0K")
  (dotimes (s4-0 (the-as int (+ (-> this active-channels) (-> this float-channels))))
    (let* ((s3-0 (-> this channel s4-0))
           (s2-0 (if (and (-> s3-0 frame-group) (nonzero? (-> s3-0 frame-group)))
                     (-> s3-0 frame-group)
                     )
                 )
           )
      (let* ((t9-1 format)
             (a0-3 arg0)
             (a1-2 "~S~2d ~C ~-35S ")
             (a2-0 (if (= (-> this root-channel) s3-0)
                       "~3Lch:~0L"
                       "ch:"
                       )
                   )
             (a3-0 s4-0)
             (v1-6 (-> s3-0 command))
             (t0-2 (cond
                     ((= v1-6 (joint-control-command push))
                      80
                      )
                     ((= v1-6 (joint-control-command push1))
                      112
                      )
                     ((= v1-6 (joint-control-command blend))
                      66
                      )
                     ((= v1-6 (joint-control-command stack))
                      83
                      )
                     ((= v1-6 (joint-control-command stack1))
                      115
                      )
                     ((= v1-6 (joint-control-command float))
                      102
                      )
                     )
                   )
             )
        (t9-1 a0-3 a1-2 a2-0 a3-0 t0-2 (if s2-0
                                           (-> s2-0 name)
                                           "(none)"
                                           )
              )
        )
      (if (and (= (-> s3-0 frame-interp 0) 0.0) (!= (-> s3-0 frame-interp 1) 0.0))
          (format
            arg0
            "f: ~6,,2f  ~1L~4,,2f~0L ~4,,2f%~%"
            (+ (* (-> s3-0 frame-num) (if s2-0
                                          (-> s2-0 artist-step)
                                          1.0
                                          )
                  )
               (if s2-0
                   (-> s2-0 artist-base)
                   0.0
                   )
               )
            (-> s3-0 frame-interp 1)
            (* 0.003921569 (the float (-> s3-0 inspector-amount)))
            )
          (format
            arg0
            "f: ~6,,2f  ~4,,2f ~4,,2f%~%"
            (+ (* (-> s3-0 frame-num) (if s2-0
                                          (-> s2-0 artist-step)
                                          1.0
                                          )
                  )
               (if s2-0
                   (-> s2-0 artist-base)
                   0.0
                   )
               )
            (-> s3-0 frame-interp (-> this active-frame-interp))
            (* 0.003921569 (the float (-> s3-0 inspector-amount)))
            )
          )
      )
    )
  (format arg0 "~1K")
  0
  )

(defmethod needs-link? ((this art))
  #f
  )

;; WARN: Return type mismatch symbol vs basic.
(defmethod get-art-by-name-method ((this art) (arg0 string) (arg1 type))
  (the-as basic #f)
  )

;; og:preserve-this added macro
(defmacro get-art-by-name (this name type)
  "Helper macro for casting the result of get-art-by-name-method. Generated by decompiler."
  `(the-as ,type (get-art-by-name-method ,this ,name ,type))
  )

;; WARN: Return type mismatch symbol vs int.
(defmethod get-art-idx-by-name-method ((this art) (arg0 string) (arg1 type))
  (the-as int #f)
  )

(defmethod print ((this art))
  (format #t "#<~A ~S :length ~D @ #x~X>" (-> this type) (-> this name) (-> this length) this)
  this
  )

(defmethod length ((this art))
  (-> this length)
  )

(defmethod login ((this art))
  (if (and (-> this extra) (zero? (-> this extra tag)))
      (set! (-> this extra tag) (the-as (pointer res-tag) (&+ (the-as pointer (-> this extra)) 28)))
      )
  this
  )

(defmethod mem-usage ((this art-mesh-anim) (arg0 memory-usage-block) (arg1 int))
  (set! (-> arg0 length) (max 75 (-> arg0 length)))
  (set! (-> arg0 data 74 name) "art-mesh-anim")
  (+! (-> arg0 data 74 count) 1)
  (let ((v1-6 (asize-of this)))
    (+! (-> arg0 data 74 used) v1-6)
    (+! (-> arg0 data 74 total) (logand -16 (+ v1-6 15)))
    )
  (if (-> this extra)
      (mem-usage (-> this extra) arg0 (logior arg1 512))
      )
  (dotimes (s3-0 (-> this length))
    (mem-usage (-> this data s3-0) arg0 arg1)
    )
  this
  )

(defmethod mem-usage ((this art-joint-anim) (arg0 memory-usage-block) (arg1 int))
  (set! (-> arg0 length) (max 78 (-> arg0 length)))
  (set! (-> arg0 data 77 name) "art-joint-anim")
  (+! (-> arg0 data 77 count) 1)
  (let ((v1-6 (asize-of this)))
    (+! (-> arg0 data 77 used) v1-6)
    (+! (-> arg0 data 77 total) (logand -16 (+ v1-6 15)))
    )
  (if (-> this extra)
      (mem-usage (-> this extra) arg0 (logior arg1 512))
      )
  (jacc-mem-usage (-> this frames) arg0 arg1)
  (when (and (nonzero? (-> this eye-anim)) (-> this eye-anim))
    (set! (-> arg0 length) (max 112 (-> arg0 length)))
    (set! (-> arg0 data 111 name) "eye-anim")
    (+! (-> arg0 data 111 count) 1)
    (let ((v1-26 (* (* (+ (-> this eye-anim max-frame) 1) 2) 8)))
      (+! (-> arg0 data 111 used) v1-26)
      (+! (-> arg0 data 111 total) (logand -16 (+ v1-26 15)))
      )
    )
  this
  )

;; WARN: Return type mismatch uint vs int.
(defmethod asize-of ((this art-joint-anim))
  (the-as int (+ (-> art size) (* (-> this length) 4)))
  )

(defmethod inspect art-group ((this art-group))
  (format #t "[~8x] ~A~%" this (-> this type))
  (format #t "~Tinfo: ~A~%" (-> this info))
  (format #t "~Tlength: ~D~%" (-> this length))
  (format #t "~Tname: ~A~%" (-> this name))
  (format #t "~Textra: ~A~%" (-> this extra))
  (format #t "~Tdata[~D]: @ #x~X~%" (-> this length) (-> this data))
  (dotimes (s5-0 (-> this length))
    (if (-> this data s5-0)
        (format #t "~T  [~D] ~A  (~D bytes)~%" s5-0 (-> this data s5-0) (mem-size (-> this data s5-0) #f 0))
        (format #t "~T  [~D] ~A  (~D bytes)~%" s5-0 (-> this data s5-0) 0)
        )
    )
  this
  )

(defmethod needs-link? ((this art-group))
  (and (nonzero? (-> this length))
       (type? (-> this data 0) art-joint-anim)
       (!= (-> this name) (-> (the-as art-joint-anim (-> this data 0)) master-art-group-name))
       )
  )

;; WARN: Return type mismatch art-element vs basic.
(defmethod get-art-by-name-method ((this art-group) (arg0 string) (arg1 type))
  (cond
    (arg1
      (let ((s3-0 (+ (length (-> this name)) 1)))
        (dotimes (s2-0 (-> this length))
          (if (and (-> this data s2-0)
                   (= (-> this data s2-0 type) arg1)
                   (or (name= arg0 (-> this data s2-0 name)) (string-charp= arg0 (&-> (-> this data s2-0 name) data s3-0)))
                   )
              (return (the-as basic (-> this data s2-0)))
              )
          )
        )
      (the-as art-element #f)
      )
    (else
      (dotimes (s4-1 (-> this length))
        (if (and (-> this data s4-1) (name= arg0 (-> this data s4-1 name)))
            (return (the-as basic (-> this data s4-1)))
            )
        )
      (the-as art-element #f)
      )
    )
  )

(defmethod get-art-idx-by-name-method ((this art-group) (arg0 string) (arg1 type))
  (cond
    (arg1
      (let ((s3-0 (+ (length (-> this name)) 1)))
        (dotimes (s2-0 (-> this length))
          (if (and (-> this data s2-0)
                   (= (-> this data s2-0 type) arg1)
                   (or (name= arg0 (-> this data s2-0 name)) (string-charp= arg0 (&-> (-> this data s2-0 name) data s3-0)))
                   )
              (return s2-0)
              )
          )
        )
      (the-as int #f)
      )
    (else
      (dotimes (s4-1 (-> this length))
        (if (and (-> this data s4-1) (name= arg0 (-> this data s4-1 name)))
            (return s4-1)
            )
        )
      (the-as int #f)
      )
    )
  )

(defmethod login ((this art-group))
  (dotimes (s5-0 (-> this length))
    (if (-> this data s5-0)
        (set! (-> this data s5-0) (login (-> this data s5-0)))
        )
    )
  this
  )

(defmethod mem-usage ((this art-group) (arg0 memory-usage-block) (arg1 int))
  (set! (-> arg0 length) (max 74 (-> arg0 length)))
  (set! (-> arg0 data 73 name) "art-group")
  (+! (-> arg0 data 73 count) 1)
  (let ((v1-6 (asize-of this)))
    (+! (-> arg0 data 73 used) v1-6)
    (+! (-> arg0 data 73 total) (logand -16 (+ v1-6 15)))
    )
  (if (-> this extra)
      (mem-usage (-> this extra) arg0 (logior arg1 512))
      )
  (dotimes (s3-0 (-> this length))
    (if (-> this data s3-0)
        (mem-usage (-> this data s3-0) arg0 arg1)
        )
    )
  this
  )

;; WARN: Return type mismatch art-group vs none.
(defmethod relocate ((this art-group) (arg0 kheap) (arg1 (pointer uint8)))
  (let ((s4-0 (clear *temp-string*)))
    (string<-charp s4-0 arg1)
    (set! this
          (cond
            ((not this)
             (format 0 "ERROR: art-group ~A is not a valid file.~%" s4-0)
             (the-as art-group #f)
             )
            ((not (type? this art-group))
             (format 0 "ERROR: art-group ~A is not a art-group.~%" s4-0)
             (the-as art-group #f)
             )
            ((not (file-info-correct-version? (-> this info) (file-kind art-group) 0))
             (the-as art-group #f)
             )
            (else
              (let ((s5-1 (-> *level* loading-level)))
                (if (and (nonzero? (-> s5-1 code-memory-end)) (< (the-as uint (-> s5-1 load-buffer-mode)) (the-as uint 2)))
                    (set! (-> s5-1 load-buffer-mode) (load-buffer-mode medium))
                    )
                (cond
                  ((and s5-1 (= (-> s5-1 name) 'default) (not *print-login*))
                   (format
                     0
                     "ERROR: illegal login of art ~A (in level ~A) to level ~A~%"
                     this
                     (get-level-by-heap-ptr-and-status *level* (the-as pointer this) 'loading)
                     s5-1
                     )
                   (break!)
                   0
                   )
                  ((or (not s5-1) (= (-> s5-1 name) 'default))
                   )
                  ((!= (get-level-by-heap-ptr-and-status *level* (the-as pointer this) 'loading) s5-1)
                   (format
                     0
                     "ERROR: illegal login of art ~A (in level ~A) to level ~A~%"
                     this
                     (get-level-by-heap-ptr-and-status *level* (the-as pointer this) 'loading)
                     s5-1
                     )
                   (break!)
                   0
                   )
                  )
                (when (or (not s5-1) (= (-> s5-1 name) 'default))
                  (login this)
                  (if (needs-link? this)
                      (link-art! this)
                      )
                  )
                (if s5-1
                    (set-loaded-art (-> s5-1 art-group) this)
                    )
                )
              this
              )
            )
          )
    )
  (none)
  )

;; WARN: Return type mismatch uint vs int.
(defmethod asize-of ((this art-mesh-geo))
  (the-as int (+ (-> art size) (* (-> this length) 4)))
  )

(defmethod mem-usage ((this art-mesh-geo) (arg0 memory-usage-block) (arg1 int))
  (set! (-> arg0 length) (max 76 (-> arg0 length)))
  (set! (-> arg0 data 75 name) "art-mesh-geo")
  (+! (-> arg0 data 75 count) 1)
  (let ((v1-6 (asize-of this)))
    (+! (-> arg0 data 75 used) v1-6)
    (+! (-> arg0 data 75 total) (logand -16 (+ v1-6 15)))
    )
  (if (-> this extra)
      (mem-usage (-> this extra) arg0 (logior arg1 512))
      )
  (dotimes (s3-0 (-> this length))
    (mem-usage (-> this data s3-0) arg0 arg1)
    )
  this
  )

(defmethod login ((this art-mesh-geo))
  (dotimes (s5-0 (-> this length))
    (let ((s4-0 (the-as object (-> this data s5-0))))
      (dotimes (s3-0 (-> (the-as (pointer int16) s4-0) 3))
        (if (-> (the-as (pointer art) (+ (* s3-0 4) (the-as int s4-0))) 2)
            (login (the-as drawable (-> (the-as (pointer art) (+ (* s3-0 4) (the-as int s4-0))) 2)))
            )
        )
      )
    )
  this
  )

(defmethod login ((this art-joint-anim))
  (if (and (-> this extra) (zero? (-> this extra tag)))
      (set! (-> this extra tag) (the-as (pointer res-tag) (&+ (the-as pointer (-> this extra)) 28)))
      )
  this
  )

;; WARN: Return type mismatch uint vs int.
(defmethod asize-of ((this art-joint-geo))
  (the-as int (+ (-> art size) (* (-> this length) 4)))
  )

;; WARN: Return type mismatch joint vs basic.
(defmethod get-art-by-name-method ((this art-joint-geo) (arg0 string) (arg1 type))
  (cond
    (arg1
      (dotimes (s3-0 (-> this length))
        (if (and (= (-> this data s3-0 type) arg1) (name= arg0 (-> this data s3-0 name)))
            (return (the-as basic (-> this data s3-0)))
            )
        )
      (the-as joint #f)
      )
    (else
      (dotimes (s4-1 (-> this length))
        (if (name= arg0 (-> this data s4-1 name))
            (return (the-as basic (-> this data s4-1)))
            )
        )
      (the-as joint #f)
      )
    )
  )

(defmethod get-art-idx-by-name-method ((this art-joint-geo) (arg0 string) (arg1 type))
  (cond
    (arg1
      (dotimes (s3-0 (-> this length))
        (if (and (= (-> this data s3-0 type) arg1) (name= arg0 (-> this data s3-0 name)))
            (return s3-0)
            )
        )
      (the-as int #f)
      )
    (else
      (dotimes (s4-1 (-> this length))
        (if (name= arg0 (-> this data s4-1 name))
            (return s4-1)
            )
        )
      (the-as int #f)
      )
    )
  )

(defmethod mem-usage ((this art-joint-geo) (arg0 memory-usage-block) (arg1 int))
  (set! (-> arg0 length) (max 77 (-> arg0 length)))
  (set! (-> arg0 data 76 name) "art-joint-geo")
  (+! (-> arg0 data 76 count) 1)
  (let ((v1-6 (asize-of this)))
    (+! (-> arg0 data 76 used) v1-6)
    (+! (-> arg0 data 76 total) (logand -16 (+ v1-6 15)))
    )
  (if (-> this extra)
      (mem-usage (-> this extra) arg0 (logior arg1 512))
      )
  (dotimes (s3-0 (-> this length))
    (mem-usage (-> this data s3-0) arg0 arg1)
    )
  this
  )

(defbehavior joint-control-channel-eval process ((arg0 joint-control-channel))
  (let ((f0-3 ((-> arg0 num-func) arg0 (-> arg0 param 0) (-> arg0 param 1) (-> arg0 param 2))))
    (set! (-> arg0 eval-time) (the-as uint (current-time)))
    f0-3
    )
  )

(defbehavior joint-control-channel-eval! process ((arg0 joint-control-channel) (arg1 (function joint-control-channel float float float float)))
  (set! (-> arg0 num-func) arg1)
  (let ((f0-3 (arg1 arg0 (-> arg0 param 0) (-> arg0 param 1) (-> arg0 param 2))))
    (set! (-> arg0 eval-time) (the-as uint (current-time)))
    f0-3
    )
  )

(defun joint-control-channel-group-eval! ((arg0 joint-control-channel)
                                 (arg1 art-joint-anim)
                                 (arg2 (function joint-control-channel float float float float))
                                 )
  (set! (-> arg0 num-func) arg2)
  (cond
    ((= (-> arg0 command) (joint-control-command stack))
     )
    (else
      (if arg1
          (set! (-> arg0 frame-group) arg1)
          )
      (arg2 arg0 (-> arg0 param 0) (-> arg0 param 1) (-> arg0 param 2))
      (set! (-> arg0 eval-time) (the-as uint (current-time)))
      )
    )
  0
  )

(defun joint-control-channel-group! ((arg0 joint-control-channel)
                            (arg1 art-joint-anim)
                            (arg2 (function joint-control-channel float float float float))
                            )
  (set! (-> arg0 num-func) arg2)
  (cond
    ((= (-> arg0 command) (joint-control-command stack))
     )
    (arg1
      (set! (-> arg0 frame-group) arg1)
      )
    )
  0
  )

(defun joint-control-copy! ((arg0 joint-control) (arg1 joint-control))
  (set! (-> arg0 blend-index) (-> arg1 blend-index))
  (set! (-> arg0 active-channels) (-> arg1 active-channels))
  (set! (-> arg0 float-channels) (the-as uint 0))
  (set! (-> arg0 root-channel)
        (the-as
          (inline-array joint-control-channel)
          (-> arg0
              channel
              (/ (the-as int (- (the-as uint (-> arg1 root-channel)) (the-as uint (the-as uint (-> arg1 channel))))) 64)
              )
          )
        )
  (let ((v1-10 (min (the-as int (-> arg0 allocated-length)) (the-as int (-> arg1 active-channels)))))
    (mem-copy! (the-as pointer (-> arg0 channel)) (the-as pointer (-> arg1 channel)) (* v1-10 64))
    )
  (dotimes (v1-12 (the-as int (-> arg0 allocated-length)))
    (set! (-> arg0 channel v1-12 parent) arg0)
    )
  arg0
  )

;; WARN: Using new Jak 2 rtype-of
(defun joint-control-remap! ((arg0 joint-control) (arg1 art-group) (arg2 art-group) (arg3 pair) (arg4 int) (arg5 string))
  (local-vars
    (sv-16 int)
    (sv-24 symbol)
    (sv-32 int)
    (sv-40 int)
    (sv-48 joint-control-channel)
    (sv-52 basic)
    (sv-56 object)
    (sv-60 basic)
    (sv-64 art-joint-anim)
    (sv-80 string)
    )
  (set! sv-16 (+ (length (-> arg2 name)) 1))
  (set! sv-24 #t)
  (set! sv-32 arg4)
  (set! sv-40 2)
  (while (and (< sv-40 (-> arg1 length)) (or (not (-> arg1 data sv-40)) (!= (-> arg1 data sv-40 type) art-joint-anim)))
    (set! sv-40 (+ sv-40 1))
    )
  (dotimes (s2-1 (the-as int (+ (-> arg0 active-channels) (-> arg0 float-channels))))
    (set! sv-48 (-> arg0 channel s2-1))
    (set! sv-52 (the-as basic #f))
    (when (-> sv-48 frame-group)
      (format (clear *temp-string*) "~S~G" arg5 (&+ (-> sv-48 frame-group name data) sv-16))
      (when (not (null? arg3))
        (set! sv-56 (nassoc *temp-string* arg3))
        (when sv-56
          (let* ((s1-1 sv-32)
                 (a0-8 sv-56)
                 (v1-36 (mod s1-1 (+ ((method-of-type (rtype-of a0-8) length) a0-8) -1)))
                 )
            (set! sv-60 (the-as basic (ref sv-56 (+ v1-36 1))))
            )
          (cond
            ((= (-> sv-60 type) string)
             (format (clear *temp-string*) "~S" sv-60)
             )
            ((= (-> sv-60 type) function)
             (set! sv-52 sv-60)
             (let ((s1-3 format)
                   (s0-0 (clear *temp-string*))
                   )
               (set! sv-80 "~S")
               (let ((a2-4 ((the-as (function joint-control joint-control-channel int object) sv-52) arg0 sv-48 0)))
                 (s1-3 s0-0 sv-80 a2-4)
                 )
               )
             )
            )
          )
        )
      (set! sv-64 (get-art-by-name arg1 *temp-string* art-joint-anim))
      (cond
        (sv-64
          (let* ((v1-46 (-> sv-48 frame-group))
                 (f0-2 (+ (* (-> sv-48 frame-num) (-> v1-46 artist-step)) (-> v1-46 artist-base)))
                 )
            (set! (-> sv-48 frame-group) sv-64)
            (set! (-> sv-48 frame-num) (/ (- f0-2 (-> sv-64 artist-base)) (-> sv-64 artist-step)))
            )
          (set! (-> sv-48 frame-num)
                (fmax 0.0 (fmin (-> sv-48 frame-num) (the float (+ (-> sv-64 frames num-frames) -1))))
                )
          (if sv-52
              ((the-as (function joint-control joint-control-channel int object) sv-52) arg0 sv-48 1)
              )
          )
        (else
          (set! (-> sv-48 frame-group) (the-as art-joint-anim (-> arg1 data sv-40)))
          (set! (-> sv-48 frame-num) 0.0)
          (set! sv-24 (the-as symbol #f))
          )
        )
      )
    )
  sv-24
  )

;; ERROR: Failed load: (set! vf2 (l.vf (the-as int a2-1))) at op 46
(defun flatten-joint-control-to-spr ((arg0 joint-control))
  (rlet ((vf1 :class vf)
         (vf10 :class vf)
         (vf11 :class vf)
         (vf12 :class vf)
         (vf13 :class vf)
         (vf14 :class vf)
         (vf2 :class vf)
         (vf3 :class vf)
         (vf4 :class vf)
         (vf5 :class vf)
         (vf6 :class vf)
         (vf7 :class vf)
         (vf8 :class vf)
         (vf9 :class vf)
         )
    (let ((s5-0 (+ (-> arg0 active-channels) (-> arg0 float-channels))))
      (let ((f0-0 1.0)
            (v1-2 0)
            ;(a2-0 (the-as object #x70000960))
            (a2-0 (scratchpad-object object :offset #x960)) ;; flattened array.
            (a0-2 (-> arg0 active-frame-interp))
            )
        (dotimes (a1-0 (the-as int s5-0))
          (let ((a3-2 (-> arg0 channel a1-0)))
            (case (-> a3-2 command)
              (((joint-control-command push))
               (let ((a3-3 (the-as object (+ (the-as int a2-0) v1-2))))
                 (set! (-> (the-as (inline-array vector) a2-0) 0 quad) (the-as uint128 0))
                 (set! (-> (the-as (inline-array vector) a2-0) 1 quad) (the-as uint128 0))
                 (set! (-> (the-as (inline-array vector) a2-0) 2 quad) (the-as uint128 0))
                 (set! (-> (the-as (inline-array vector) a2-0) 3 quad) (the-as uint128 0))
                 (set! (-> (the-as (inline-array vector) a2-0) 4 quad) (the-as uint128 0))
                 (set! (-> (the-as (inline-array vector) a2-0) 5 quad) (the-as uint128 0))
                 (set! (-> (the-as (pointer float) a3-3) 0) f0-0)
                 )
               (set! a2-0 (+ (the-as int a2-0) 96))
               )
              (((joint-control-command blend) (joint-control-command push1) (joint-control-command float))
               (let ((f1-0 (-> a3-2 frame-interp a0-2)))
                 (let ((a3-5 (- f0-0 f1-0)))
                   (.mov vf1 a3-5)
                   )
                 (let ((a2-1 (the-as object (+ (the-as int a2-0) -96))))
                   (.lvf vf2 (the-as int a2-1))
                   (let ((a3-6 (the-as object (+ (the-as int a2-1) v1-2))))
                     (.lvf vf3 (+ (the-as int a2-1) 16))
                     (.lvf vf4 (+ (the-as int a2-1) 32))
                     (.lvf vf5 (+ (the-as int a2-1) 48))
                     (.lvf vf6 (+ (the-as int a2-1) 64))
                     (.lvf vf7 (+ (the-as int a2-1) 80))
                     (.mul.x.vf vf2 vf2 vf1)
                     (.mul.x.vf vf3 vf3 vf1)
                     (.mul.x.vf vf4 vf4 vf1)
                     (.mul.x.vf vf5 vf5 vf1)
                     (.mul.x.vf vf6 vf6 vf1)
                     (.mul.x.vf vf7 vf7 vf1)
                     (.svf (&-> (the-as (inline-array vector) a2-1) 0 quad) vf2)
                     (.svf (&-> (the-as (inline-array vector) a2-1) 1 quad) vf3)
                     (.svf (&-> (the-as (inline-array vector) a2-1) 2 quad) vf4)
                     (.svf (&-> (the-as (inline-array vector) a2-1) 3 quad) vf5)
                     (.svf (&-> (the-as (inline-array vector) a2-1) 4 quad) vf6)
                     (.svf (&-> (the-as (inline-array vector) a2-1) 5 quad) vf7)
                     (+! (-> (the-as (pointer float) a3-6) 0) f1-0)
                     )
                   (set! a2-0 (+ (the-as int a2-1) 96))
                   )
                 )
               )
              (((joint-control-command stack))
               (let* ((f2-2 (-> a3-2 frame-interp a0-2))
                      (f1-2 (- f0-0 f2-2))
                      (a2-2 (the-as object (+ (the-as int a2-0) -192)))
                      )
                 (let ((a3-8 f2-2))
                   (.mov vf1 a3-8)
                   )
                 (let ((a3-9 f1-2))
                   (.mov vf2 a3-9)
                   )
                 (.lvf vf3 (the-as int a2-2))
                 (.lvf vf4 (+ (the-as int a2-2) 16))
                 (.lvf vf5 (+ (the-as int a2-2) 32))
                 (.lvf vf6 (+ (the-as int a2-2) 48))
                 (.lvf vf7 (+ (the-as int a2-2) 64))
                 (.lvf vf8 (+ (the-as int a2-2) 80))
                 (.mul.x.vf vf3 vf3 vf2)
                 (.mul.x.vf vf4 vf4 vf2)
                 (.mul.x.vf vf5 vf5 vf2)
                 (.mul.x.vf vf6 vf6 vf2)
                 (.mul.x.vf vf7 vf7 vf2)
                 (.mul.x.vf vf8 vf8 vf2)
                 (.lvf vf9 (+ (the-as int a2-2) 96))
                 (.lvf vf10 (+ (the-as int a2-2) 112))
                 (.lvf vf11 (+ (the-as int a2-2) 128))
                 (.lvf vf12 (+ (the-as int a2-2) 144))
                 (.lvf vf13 (+ (the-as int a2-2) 160))
                 (.lvf vf14 (+ (the-as int a2-2) 176))
                 (.mul.x.vf vf9 vf9 vf1)
                 (.mul.x.vf vf10 vf10 vf1)
                 (.mul.x.vf vf11 vf11 vf1)
                 (.mul.x.vf vf12 vf12 vf1)
                 (.mul.x.vf vf13 vf13 vf1)
                 (.mul.x.vf vf14 vf14 vf1)
                 (.add.vf vf3 vf3 vf9)
                 (.add.vf vf4 vf4 vf10)
                 (.add.vf vf5 vf5 vf11)
                 (.add.vf vf6 vf6 vf12)
                 (.add.vf vf7 vf7 vf13)
                 (.add.vf vf8 vf8 vf14)
                 (.svf (&-> (the-as (inline-array vector) a2-2) 0 quad) vf3)
                 (.svf (&-> (the-as (inline-array vector) a2-2) 1 quad) vf4)
                 (.svf (&-> (the-as (inline-array vector) a2-2) 2 quad) vf5)
                 (.svf (&-> (the-as (inline-array vector) a2-2) 3 quad) vf6)
                 (.svf (&-> (the-as (inline-array vector) a2-2) 4 quad) vf7)
                 (.svf (&-> (the-as (inline-array vector) a2-2) 5 quad) vf8)
                 (set! a2-0 (+ (the-as int a2-2) 96))
                 )
               )
              )
            )
          (+! v1-2 4)
          )
        )
      (let ((s4-0 0))
        (dotimes (s3-0 (the-as int s5-0))
          (when (< 0.001 (-> (scratchpad-object terrain-context) work foreground joint-work flatten-array s3-0))
            (let* ((v1-11 (-> arg0 channel s3-0))
                   (s2-0 (-> v1-11 frame-group frames))
                   (f0-2 (-> v1-11 frame-num))
                   (s1-0 (the int f0-2))
                   (f30-0 (- f0-2 (the float s1-0)))
                   )
              (let ((s0-0 (+ (-> s2-0 num-frames) -1)))
                (if (not (-> v1-11 frame-group))
                    (format 0 "Channel ~D skel ~A frame-group is #f!!!~%" s3-0 arg0)
                    )
                (when (>= s1-0 (the-as int s0-0))
                  (set! f30-0 0.0)
                  (set! s1-0 (the-as int s0-0))
                  )
                )
              (let ((v1-20 (-> (scratchpad-object terrain-context) work foreground joint-work uploads s4-0)))
                (set! (-> v1-20 fixed) (-> s2-0 fixed))
                (set! (-> v1-20 fixed-qwc) (the-as int (-> s2-0 fixed-qwc)))
                (set! (-> v1-20 frame) (-> s2-0 data s1-0))
                (set! (-> v1-20 frame-qwc) (the-as int (if (= f30-0 0.0)
                                                           (-> s2-0 frame-qwc)
                                                           (* (-> s2-0 frame-qwc) 2)
                                                           )
                                                   )
                      )
                (set! (-> v1-20 amount)
                      (-> (scratchpad-object terrain-context) work foreground joint-work flatten-array s3-0)
                      )
                (set! (-> v1-20 interp) f30-0)
                )
              )
            (+! s4-0 1)
            )
          )
        (set! (-> (scratchpad-object terrain-context) work foreground joint-work num-uploads) s4-0)
        )
      (dotimes (v1-26 (the-as int s5-0))
        (set! (-> arg0 channel v1-26 inspector-amount)
              (the-as
                uint
                (the int (* 255.0 (-> (scratchpad-object terrain-context) work foreground joint-work flatten-array v1-26)))
                )
              )
        )
      )
    0
    )
  )

;; WARN: Return type mismatch object vs matrix.
(defun matrix-from-joint-anim-frame ((arg0 joint-anim-compressed-control) (arg1 int) (arg2 int))
  (let ((v1-1 (the-as object (-> arg0 fixed data)))
        (v0-0 (the-as object (-> arg0 data arg2 data)))
        )
    (cond
      ((not (logtest? (-> arg0 fixed hdr matrix-bits) 1))
       (set! v1-1 (cond
                    ((zero? arg1)
                     (return (the-as matrix v1-1))
                     v1-1
                     )
                    (else
                      (-> (the-as (inline-array vector) v1-1) 4)
                      )
                    )
             )
       )
      ((zero? arg1)
       (return (the-as matrix v0-0))
       )
      (else
        (set! v0-0 (-> (the-as (inline-array vector) v0-0) 4))
        )
      )
    (if (not (logtest? (-> arg0 fixed hdr matrix-bits) 2))
        (return (the-as matrix v1-1))
        )
    (the-as matrix v0-0)
    )
  )

(defun matrix-from-control-channel! ((arg0 matrix) (arg1 joint) (arg2 joint-control-channel))
  (let ((s4-0 (-> arg2 frame-group))
        (s5-0 (-> arg1 number))
        )
    (if (>= s5-0 2)
        (format 0 "ERROR: Call to matrix-from-control-channel! on joint ~D~%" s5-0)
        )
    (let* ((f30-0 (fmax 0.0 (fmin (-> arg2 frame-num) (the float (+ (-> s4-0 frames num-frames) -1)))))
           (f0-1 f30-0)
           )
      (cond
        ((= (the float (the int f0-1)) f0-1)
         (let* ((a2-3 (matrix-from-joint-anim-frame (-> s4-0 frames) s5-0 (the int f30-0)))
                (v1-7 (-> a2-3 quad 0))
                (a0-3 (-> a2-3 quad 1))
                (a1-3 (-> a2-3 quad 2))
                (a2-4 (-> a2-3 trans quad))
                )
           (set! (-> arg0 quad 0) v1-7)
           (set! (-> arg0 quad 1) a0-3)
           (set! (-> arg0 quad 2) a1-3)
           (set! (-> arg0 trans quad) a2-4)
           )
         arg0
         )
        (else
          (let ((s3-1 (matrix-from-joint-anim-frame (-> s4-0 frames) s5-0 (the int f30-0)))
                (a2-7 (matrix-from-joint-anim-frame (-> s4-0 frames) s5-0 (+ (the int f30-0) 1)))
                (f0-9 (- f30-0 (the float (the int f30-0))))
                )
            (matrix-lerp! arg0 s3-1 a2-7 f0-9)
            )
          )
        )
      )
    )
  )

(defun matrix-from-control-pair! ((arg0 matrix) (arg1 matrix) (arg2 joint) (arg3 int))
  (let ((f30-0 (-> arg1 vector 2 data arg3)))
    (cond
      ((>= 0.0 f30-0)
       (empty)
       arg0
       )
      ((>= f30-0 1.0)
       (matrix-from-control-channel! arg0 arg2 (the-as joint-control-channel arg1))
       )
      (else
        (let ((a2-3
                (matrix-from-control-channel! (scratchpad-object matrix) arg2 (the-as joint-control-channel arg1))
                )
              )
          (matrix-lerp! arg0 arg0 a2-3 f30-0)
          )
        )
      )
    )
  )

;; WARN: Return type mismatch (inline-array matrix) vs matrix.
(defun matrix-from-control! ((arg0 matrix-stack) (arg1 joint) (arg2 joint-control) (arg3 symbol))
  (set! (-> arg0 top) (the-as matrix (-> arg0 data)))
  (dotimes (s2-0 (the-as int (+ (-> arg2 active-channels) (-> arg2 float-channels))))
    (let* ((a2-1 (-> arg2 channel s2-0))
           (v1-3 (-> a2-1 command))
           (s1-0 64)
           )
      (cond
        ((and (= arg3 'no-push) (= v1-3 (joint-control-command push1)))
         (matrix-from-control-channel!
           (the-as matrix (&- (the-as pointer (-> arg0 top)) (the-as uint s1-0)))
           arg1
           a2-1
           )
         )
        ((and (= arg3 'no-push) (= v1-3 (joint-control-command stack)))
         (set! (-> arg0 top) (the-as matrix (&- (the-as pointer (-> arg0 top)) (the-as uint s1-0))))
         (let* ((v1-9 (the-as object (&- (the-as pointer (-> arg0 top)) (the-as uint s1-0))))
                (a3-1 (-> arg0 top))
                (a0-8 (-> a3-1 quad 0))
                (a1-6 (-> a3-1 quad 1))
                (a2-2 (-> a3-1 quad 2))
                (a3-2 (-> a3-1 trans quad))
                )
           (set! (-> (the-as matrix v1-9) quad 0) a0-8)
           (set! (-> (the-as matrix v1-9) quad 1) a1-6)
           (set! (-> (the-as matrix v1-9) quad 2) a2-2)
           (set! (-> (the-as matrix v1-9) trans quad) a3-2)
           )
         )
        ((and (= arg3 'no-push) (= v1-3 (joint-control-command float)))
         )
        ((= v1-3 (joint-control-command push))
         (matrix-from-control-channel! (-> arg0 top) arg1 a2-1)
         (set! (-> arg0 top) (the-as matrix (&+ (the-as pointer (-> arg0 top)) s1-0)))
         )
        ((logtest? v1-3 (joint-control-command blend))
         (matrix-from-control-pair!
           (the-as matrix (&- (the-as pointer (-> arg0 top)) (the-as uint s1-0)))
           (the-as matrix a2-1)
           arg1
           (the-as int (-> arg2 active-frame-interp))
           )
         )
        ((= v1-3 (joint-control-command stack))
         (set! (-> arg0 top) (the-as matrix (&- (the-as pointer (-> arg0 top)) (the-as uint s1-0))))
         (let ((a1-11 (&- (the-as pointer (-> arg0 top)) (the-as uint s1-0)))
               (v1-19 (-> arg0 top))
               (f0-0 (-> a2-1 frame-interp (-> arg2 active-frame-interp)))
               )
           (matrix-lerp! (the-as matrix a1-11) (the-as matrix a1-11) v1-19 f0-0)
           )
         )
        )
      )
    )
  (the-as matrix (-> arg0 data))
  )

(defmethod reset-and-assign-geo! ((this cspace) (arg0 drawable))
  (set! (-> this parent) #f)
  (set! (-> this joint) #f)
  (set! (-> this geo) arg0)
  (set! (-> this param0) #f)
  (set! (-> this param1) #f)
  (set! (-> this param2) #f)
  this
  )

(defmethod new cspace ((allocation symbol) (type-to-make type) (arg0 drawable))
  (let ((t9-0 (method-of-type structure new))
        (v1-1 type-to-make)
        )
    (-> type-to-make size)
    ((method-of-type cspace reset-and-assign-geo!) (the-as cspace (t9-0 allocation v1-1)) arg0)
    )
  )

(defun cspace<-cspace! ((arg0 cspace) (arg1 cspace))
  (let ((v0-0 (-> arg0 bone transform)))
    (let* ((a2-0 (-> arg1 bone transform))
           (v1-2 (-> a2-0 quad 0))
           (a0-1 (-> a2-0 quad 1))
           (a1-1 (-> a2-0 quad 2))
           (a2-1 (-> a2-0 trans quad))
           )
      (set! (-> v0-0 quad 0) v1-2)
      (set! (-> v0-0 quad 1) a0-1)
      (set! (-> v0-0 quad 2) a1-1)
      (set! (-> v0-0 trans quad) a2-1)
      )
    v0-0
    )
  )

(defun cspace<-cspace-normalized! ((arg0 cspace) (arg1 cspace))
  (let ((gp-0 (-> arg0 bone transform)))
    (let* ((a2-0 (-> arg1 bone transform))
           (v1-2 (-> a2-0 quad 0))
           (a0-1 (-> a2-0 quad 1))
           (a1-1 (-> a2-0 quad 2))
           (a2-1 (-> a2-0 trans quad))
           )
      (set! (-> gp-0 quad 0) v1-2)
      (set! (-> gp-0 quad 1) a0-1)
      (set! (-> gp-0 quad 2) a1-1)
      (set! (-> gp-0 trans quad) a2-1)
      )
    (vector-normalize! (the-as vector (-> gp-0 vector)) 1.0)
    (vector-normalize! (-> gp-0 vector 1) 1.0)
    (vector-normalize! (-> gp-0 vector 2) 1.0)
    gp-0
    )
  )

(defun cspace<-parent-joint! ((arg0 cspace) (arg1 (pointer process-drawable)) (arg2 int))
  (let ((v0-0 (-> arg0 bone transform)))
    (let* ((a2-1 (-> arg1 0 node-list data arg2 bone transform))
           (v1-5 (-> a2-1 quad 0))
           (a0-2 (-> a2-1 quad 1))
           (a1-1 (-> a2-1 quad 2))
           (a2-2 (-> a2-1 trans quad))
           )
      (set! (-> v0-0 quad 0) v1-5)
      (set! (-> v0-0 quad 1) a0-2)
      (set! (-> v0-0 quad 2) a1-1)
      (set! (-> v0-0 trans quad) a2-2)
      )
    v0-0
    )
  )

(defun cspace<-rot-yxy! ((arg0 cspace) (arg1 transform))
  (let ((s5-0 (-> arg0 bone transform)))
    (matrix-rotate-yxy! s5-0 (-> arg1 rot))
    (scale-matrix! s5-0 (-> arg1 scale) s5-0)
    )
  )

(defun cspace<-transform-yxy! ((arg0 cspace) (arg1 transform))
  (let ((s4-0 (-> arg0 bone transform))
        (s5-0 (new 'stack-no-clear 'matrix))
        (s3-0 (new 'stack-no-clear 'matrix))
        )
    (matrix-identity! s4-0)
    (matrix-translate! s4-0 (-> arg1 trans))
    (matrix-rotate-yxy! s5-0 (-> arg1 rot))
    (matrix*! s3-0 s5-0 s4-0)
    (scale-matrix! s4-0 (-> arg1 scale) s3-0)
    )
  )

(defun cspace<-transformq! ((arg0 cspace) (arg1 transformq))
  (matrix<-transformq! (-> arg0 bone transform) arg1)
  )

(defun cspace<-transformq+trans! ((arg0 cspace) (arg1 transformq) (arg2 vector))
  (matrix<-transformq+trans! (-> arg0 bone transform) arg1 arg2)
  )

(defun cspace<-transformq+world-trans! ((arg0 cspace) (arg1 transformq) (arg2 vector))
  (matrix<-transformq+world-trans! (-> arg0 bone transform) arg1 arg2)
  )

(defun cspace<-transformq+rot-offset! ((arg0 cspace) (arg1 transformq) (arg2 vector))
  (matrix<-transformq+rot-offset! (-> arg0 bone transform) arg1 arg2)
  )

(defun cspace-calc-total-matrix! ((arg0 cspace) (arg1 matrix))
  (matrix*! arg1 (-> arg0 bone transform) (-> *math-camera* camera-temp))
  )

(defun cspace<-matrix-no-push-joint! ((arg0 cspace) (arg1 joint-control))
  (let ((v1-2 (matrix-from-control! (scratchpad-object matrix-stack :offset 64) (-> arg0 joint) arg1 'no-push))
        (v0-1 (-> arg0 bone transform))
        )
    (let ((a0-4 (-> v1-2 quad 0))
          (a1-2 (-> v1-2 quad 1))
          (a2-1 (-> v1-2 quad 2))
          (v1-3 (-> v1-2 trans quad))
          )
      (set! (-> v0-1 quad 0) a0-4)
      (set! (-> v0-1 quad 1) a1-2)
      (set! (-> v0-1 quad 2) a2-1)
      (set! (-> v0-1 trans quad) v1-3)
      )
    v0-1
    )
  )

(defun cspace<-matrix-joint! ((arg0 cspace) (arg1 matrix))
  (let ((v0-0 (-> arg0 bone transform)))
    (let* ((a2-0 arg1)
           (v1-1 (-> a2-0 quad 0))
           (a0-1 (-> a2-0 quad 1))
           (a1-1 (-> a2-0 quad 2))
           (a2-1 (-> a2-0 trans quad))
           )
      (set! (-> v0-0 quad 0) v1-1)
      (set! (-> v0-0 quad 1) a0-1)
      (set! (-> v0-0 quad 2) a1-1)
      (set! (-> v0-0 trans quad) a2-1)
      )
    v0-0
    )
  )

(defun cspace<-parented-matrix-joint! ((arg0 cspace) (arg1 matrix))
  (rlet ((acc :class vf)
         (vf10 :class vf)
         (vf11 :class vf)
         (vf12 :class vf)
         (vf13 :class vf)
         (vf14 :class vf)
         (vf15 :class vf)
         (vf16 :class vf)
         (vf17 :class vf)
         (vf18 :class vf)
         (vf19 :class vf)
         (vf20 :class vf)
         (vf21 :class vf)
         )
    (let ((v0-0 (-> arg0 bone transform)))
      (let ((v1-1 arg1))
        (let ((a0-3 (-> arg0 parent bone transform)))
          (.lvf vf10 (&-> v1-1 quad 0))
          (.lvf vf14 (&-> a0-3 quad 0))
          (.lvf vf15 (&-> a0-3 quad 1))
          (.lvf vf16 (&-> a0-3 quad 2))
          (.lvf vf17 (&-> a0-3 trans quad))
          )
        (.lvf vf11 (&-> v1-1 quad 1))
        (.lvf vf12 (&-> v1-1 quad 2))
        (.lvf vf13 (&-> v1-1 trans quad))
        )
      (.mul.x.vf acc vf14 vf10)
      (.add.mul.y.vf acc vf15 vf10 acc)
      (.add.mul.z.vf acc vf16 vf10 acc)
      (.add.mul.w.vf vf18 vf17 vf10 acc)
      (.mul.x.vf acc vf14 vf11)
      (.add.mul.y.vf acc vf15 vf11 acc)
      (.add.mul.z.vf acc vf16 vf11 acc)
      (.add.mul.w.vf vf19 vf17 vf11 acc)
      (.mul.x.vf acc vf14 vf12)
      (.add.mul.y.vf acc vf15 vf12 acc)
      (.add.mul.z.vf acc vf16 vf12 acc)
      (.add.mul.w.vf vf20 vf17 vf12 acc)
      (.mul.x.vf acc vf14 vf13)
      (.add.mul.y.vf acc vf15 vf13 acc)
      (.add.mul.z.vf acc vf16 vf13 acc)
      (.add.mul.w.vf vf21 vf17 vf13 acc)
      (.svf (&-> v0-0 quad 0) vf18)
      (.svf (&-> v0-0 quad 1) vf19)
      (.svf (&-> v0-0 quad 2) vf20)
      (.svf (&-> v0-0 trans quad) vf21)
      v0-0
      )
    )
  )

(defun cspace<-parented-matrix-mirror! ((arg0 cspace) (arg1 matrix))
  (let ((gp-0 (matrix-mirror!
                (new 'stack-no-clear 'matrix)
                (the-as vector (-> arg0 param1))
                (the-as vector (-> arg0 param2))
                )
              )
        )
    (cspace<-parented-matrix-joint! arg0 arg1)
    (matrix*! (-> arg0 bone transform) (-> arg0 bone transform) gp-0)
    )
  )

(defun cspace<-parented-matrix-joint-flip-z! ((arg0 cspace) (arg1 matrix))
  (rlet ((acc :class vf)
         (vf0 :class vf)
         (vf10 :class vf)
         (vf11 :class vf)
         (vf12 :class vf)
         (vf13 :class vf)
         (vf14 :class vf)
         (vf15 :class vf)
         (vf16 :class vf)
         (vf17 :class vf)
         (vf18 :class vf)
         (vf19 :class vf)
         (vf20 :class vf)
         (vf21 :class vf)
         (vf31 :class vf)
         )
    (init-vf0-vector)
    (let ((v0-0 (-> arg0 bone transform)))
      (let ((v1-1 arg1))
        (let ((a0-3 (-> arg0 parent bone transform)))
          (.lvf vf10 (&-> v1-1 quad 0))
          (.lvf vf14 (&-> a0-3 quad 0))
          (.lvf vf15 (&-> a0-3 quad 1))
          (.lvf vf16 (&-> a0-3 quad 2))
          (.lvf vf17 (&-> a0-3 trans quad))
          )
        (.lvf vf11 (&-> v1-1 quad 1))
        (.lvf vf12 (&-> v1-1 quad 2))
        (.lvf vf13 (&-> v1-1 trans quad))
        )
      (.sub.vf vf31 vf0 vf0)
      (.mul.x.vf acc vf14 vf10)
      (.add.mul.y.vf acc vf15 vf10 acc)
      (.add.mul.z.vf acc vf16 vf10 acc)
      (.add.mul.w.vf vf18 vf17 vf10 acc)
      (.mul.x.vf acc vf14 vf12)
      (.add.mul.y.vf acc vf15 vf12 acc)
      (.add.mul.z.vf acc vf16 vf12 acc)
      (.add.mul.w.vf vf20 vf17 vf12 acc)
      (.mul.x.vf acc vf14 vf11)
      (.add.mul.y.vf acc vf15 vf11 acc)
      (.add.mul.z.vf acc vf16 vf11 acc)
      (.add.mul.w.vf vf19 vf17 vf11 acc)
      (.sub.vf vf18 vf31 vf18)
      (.mul.x.vf acc vf14 vf13)
      (.add.mul.y.vf acc vf15 vf13 acc)
      (.add.mul.z.vf acc vf16 vf13 acc)
      (.add.mul.w.vf vf21 vf17 vf13 acc)
      (.svf (&-> v0-0 quad 0) vf18)
      (.svf (&-> v0-0 quad 1) vf19)
      (.svf (&-> v0-0 quad 2) vf20)
      (.svf (&-> v0-0 trans quad) vf21)
      v0-0
      )
    )
  )

(defun cspace<-matrix-joint-flip-z! ((arg0 cspace) (arg1 matrix))
  (local-vars (v1-2 float))
  (rlet ((vf0 :class vf)
         (vf30 :class vf)
         (vf31 :class vf)
         )
    (init-vf0-vector)
    (let ((v1-1 (-> arg0 bone transform)))
      (.sub.vf vf31 vf0 vf0)
      (.lvf vf30 (&-> v1-1 quad 0))
      (.sub.vf vf30 vf31 vf30)
      (.svf (&-> v1-1 quad 0) vf30)
      )
    (.mov v1-2 vf30)
    0
    (none)
    )
  )

(def-mips2c cspace<-parented-transformq-joint! (function cspace transformq none))

(defun cspace<-parented-transformq-joint-flip-z! ((arg0 cspace) (arg1 transformq))
  (cspace<-parented-transformq-joint! arg0 arg1)
  (cspace<-matrix-joint-flip-z! arg0 (-> arg0 bone transform))
  0
  (none)
  )

;; definition for function clear-frame-accumulator

;; definition for function normalize-frame-quaternions

;; definition for function decompress-fixed-data-to-accumulator

;; definition for function decompress-frame-data-to-accumulator

;; definition for function decompress-frame-data-pair-to-accumulator

;; definition for function make-joint-jump-tables
(defun make-joint-jump-tables ()
#|
    #x3ee6b6f9, // = 9 ^ 1055307504
    #x3ee6b6ff, // = 15 ^ 1055307504
    #x3ee6b6e2, // = 18 ^ 1055307504
    #x3ee6b6e4, // = 20 ^ 1055307504
    #x3ee6b6e5, // = 21 ^ 1055307504
    #x3ee6b6eb, // = 27 ^ 1055307504
    #x3ee6b6ee, // = 30 ^ 1055307504
    #x3ee6b6f6, // = 6 ^ 1055307504
    #x3ee6b6fc, // = 12 ^ 1055307504
    #x3ee6b6ff, // = 15 ^ 1055307504
    #x3ee6b6e3, // = 19 ^ 1055307504
    #x3ee6b6e4, // = 20 ^ 1055307504
    #x3ee6b6e8, // = 24 ^ 1055307504
    #x3ee6b6eb, // = 27 ^ 1055307504
    #x3ee6b6ef, // = 31 ^ 1055307504
    #x3ee6b6f6, // = 6 ^ 1055307504
    |#
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 0)
        (the-as (function none) (+ 0 #x3ee6b6f9))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 1)
        (the-as (function none) (+ 0 #x3ee6b6ff))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 2)
        (the-as (function none) (+ 0 #x3ee6b6e2))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 3)
        (the-as (function none) (+ 0 #x3ee6b6e4))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 4)
        (the-as (function none) (+ 0 #x3ee6b6e5))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 5)
        (the-as (function none) (+ 0 #x3ee6b6eb))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 6)
        (the-as (function none) (+ 0 #x3ee6b6ee))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 7)
        (the-as (function none) (+ 0 #x3ee6b6f6))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 8)
        (the-as (function none) (+ 0 #x3ee6b6fc))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 9)
        (the-as (function none) (+ 0 #x3ee6b6ff))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 10)
        (the-as (function none) (+ 0 #x3ee6b6e3))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 11)
        (the-as (function none) (+ 0 #x3ee6b6e4))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 12)
        (the-as (function none) (+ 0 #x3ee6b6e8))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 13)
        (the-as (function none) (+ 0 #x3ee6b6eb))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 14)
        (the-as (function none) (+ 0 #x3ee6b6ef))
        )
  (set! (-> (scratchpad-object terrain-context) work foreground joint-work fix-jmp-table 15)
        (the-as (function none) (+ 0 #x3ee6b6f6))
        )


  (let ((arr (new 'static 'array uint32 16
                  #x7b2191b ;; = 6 ^ 129112349
                  #x7b21914 ;; = 9 ^ 129112349
                  #x7b21916 ;; = 11 ^ 129112349
                  #x7b21913 ;; = 14 ^ 129112349
                  #x7b21909 ;; = 20 ^ 129112349
                  #x7b21908 ;; = 21 ^ 129112349
                  #x7b2190a ;; = 23 ^ 129112349
                  #x7b21907 ;; = 26 ^ 129112349
                  #x7b2191b ;; = 6 ^ 129112349
                  #x7b21917 ;; = 10 ^ 129112349
                  #x7b21916 ;; = 11 ^ 129112349
                  #x7b2190c ;; = 17 ^ 129112349
                  #x7b21909 ;; = 20 ^ 129112349
                  #x7b2190b ;; = 22 ^ 129112349
                  #x7b2190a ;; = 23 ^ 129112349
                  #x7b21900 ;; = 29 ^ 129112349
                  )))
    (dotimes (i 16)
      (set! (-> (scratchpad-object terrain-context) work foreground joint-work frm-jmp-table i)
            (the-as (function none) (-> arr i))
            )
      )
    )

  (let ((arr (new 'static 'array uint32 16
                  #x4d7666df ;; = 6 ^ 1299605209
                  #x4d7666d0 ;; = 9 ^ 1299605209
                  #x4d7666d2 ;; = 11 ^ 1299605209
                  #x4d7666d7 ;; = 14 ^ 1299605209
                  #x4d7666cd ;; = 20 ^ 1299605209
                  #x4d7666cc ;; = 21 ^ 1299605209
                  #x4d7666ce ;; = 23 ^ 1299605209
                  #x4d7666c3 ;; = 26 ^ 1299605209
                  #x4d7666df ;; = 6 ^ 1299605209
                  #x4d7666d3 ;; = 10 ^ 1299605209
                  #x4d7666d2 ;; = 11 ^ 1299605209
                  #x4d7666c8 ;; = 17 ^ 1299605209
                  #x4d7666cd ;; = 20 ^ 1299605209
                  #x4d7666cf ;; = 22 ^ 1299605209
                  #x4d7666ce ;; = 23 ^ 1299605209
                  #x4d7666c4 ;; = 29 ^ 1299605209
                  )))
    (dotimes (i 16)
      (set! (-> (scratchpad-object terrain-context) work foreground joint-work pair-jmp-table i)
            (the-as (function none) (-> arr i))
            )
      )
    )
  0
  )

(def-mips2c calc-animation-from-spr (function joint-anim-frame int none))


(defun create-interpolated-joint-animation-frame ((output-frame joint-anim-frame) (arg1 int) (arg2 joint-control))
  (let ((start (get-cpu-clock)))
    (cond
      (*use-new-decompressor*

        (new-joint-decompressor output-frame arg1 arg2)

        )
      (else
        (flatten-joint-control-to-spr arg2)
        (make-joint-jump-tables)
        (calc-animation-from-spr output-frame arg1)
        )
      )
    (+! (-> *new-joint-decompressor-stats* total-time)
        (the int (* 1000000. (cpu-ticks-to-seconds (- (get-cpu-clock) start))))
        )
    )
  0
  )

(defun create-interpolated2-joint-animation-frame ((arg0 joint-anim-frame) (arg1 int) (arg2 joint-control))
  (if (and (zero? (-> arg2 interp-select 0)) (zero? (-> arg2 interp-select 1)))
      (return (create-interpolated-joint-animation-frame arg0 arg1 arg2))
      )
  (set! (-> arg2 active-frame-interp) (the-as uint 1))
  (create-interpolated-joint-animation-frame arg0 arg1 arg2)
  ;(flatten-joint-control-to-spr arg2)
  ;(make-joint-jump-tables)
  ;(calc-animation-from-spr arg0 arg1)
  ;; happens during gun stuff, seems to work.
  ; (format 0 "create-interpolated2-joint-animation-frame: untested copy~%")
  (ultimate-memcpy (the-as pointer *gsf-buffer*) (the-as pointer arg0) (the-as uint (+ (* 48 arg1) 128)))
  ; (dma-send-from-spr-no-flush
  ;   (the-as uint *gsf-buffer*)
  ;   (the-as uint arg0)
  ;   (the-as uint (/ (+ (* 48 arg1) 128) 16))
  ;   #f
  ;   )
  (set! (-> arg2 active-frame-interp) (the-as uint 0))
  ;(flatten-joint-control-to-spr arg2)
  ;(make-joint-jump-tables)
  ;;(calc-animation-from-spr arg0 arg1)
  (create-interpolated-joint-animation-frame arg0 arg1 arg2)

  (let ((v1-9 (the-as joint-anim-frame *gsf-buffer*)))
    (let ((a0-8 (-> arg2 interp-select 0)))
      (dotimes (a1-5 2)
        (when (logtest? a0-8 1)
          (let* ((a2-7 (-> arg0 matrices a1-5))
                 (t2-0 (-> v1-9 matrices a1-5))
                 (a3-3 (-> t2-0 quad 0))
                 (t0-0 (-> t2-0 quad 1))
                 (t1-0 (-> t2-0 quad 2))
                 (t2-1 (-> t2-0 trans quad))
                 )
            (set! (-> a2-7 quad 0) a3-3)
            (set! (-> a2-7 quad 1) t0-0)
            (set! (-> a2-7 quad 2) t1-0)
            (set! (-> a2-7 trans quad) t2-1)
            )
          )
        (set! a0-8 (shr a0-8 1))
        )
      (let ((a1-9 (min 62 (+ arg1 -2))))
        (dotimes (a2-9 a1-9)
          (when (logtest? a0-8 1)
            (let* ((a3-9 (-> arg0 data a2-9))
                   (t2-2 (-> v1-9 data a2-9))
                   (t0-4 (-> t2-2 trans quad))
                   (t1-1 (-> t2-2 quat quad))
                   (t2-3 (-> t2-2 scale quad))
                   )
              (set! (-> a3-9 trans quad) t0-4)
              (set! (-> a3-9 quat quad) t1-1)
              (set! (-> a3-9 scale quad) t2-3)
              )
            )
          (set! a0-8 (shr a0-8 1))
          )
        )
      )
    (let ((a0-12 (min 64 (+ arg1 -64)))
          (a1-11 (-> arg2 interp-select 1))
          )
      (dotimes (a2-10 a0-12)
        (when (logtest? a1-11 1)
          (let* ((a3-15 (-> arg0 data (+ a2-10 62)))
                 (t2-4 (-> v1-9 data (+ a2-10 62)))
                 (t0-9 (-> t2-4 trans quad))
                 (t1-3 (-> t2-4 quat quad))
                 (t2-5 (-> t2-4 scale quad))
                 )
            (set! (-> a3-15 trans quad) t0-9)
            (set! (-> a3-15 quat quad) t1-3)
            (set! (-> a3-15 scale quad) t2-5)
            )
          )
        (set! a1-11 (shr a1-11 1))
        )
      )
    )
  0
  )

(defmethod print ((this art-joint-anim-manager-slot))
  (let* ((gp-0 format)
         (s5-0 #t)
         (s4-0 "#<slot ~48S #x~8X #x~8X ~4DK ~D>")
         (v1-0 (-> this anim))
         (s3-0 (if v1-0
                   (-> v1-0 name)
                   )
               )
         (s1-0 (-> this comp-data))
         (v1-1 (-> this anim))
         )
    (gp-0
      s5-0
      s4-0
      s3-0
      s1-0
      (if v1-1
          (-> v1-1 frames fixed)
          0
          )
      (if (-> this anim)
          (sar
            (used-bytes-for-slot
              *anim-manager*
              (the-as int (/ (the-as int (- (the-as uint this) (the-as uint (the-as uint (-> *anim-manager* slot))))) 16))
              )
            10
            )
          0
          )
      (-> this time-stamp)
      )
    )
  this
  )

(defmethod used-bytes-for-slot ((this art-joint-anim-manager) (arg0 int))
  (let ((v1-2 (-> this slot arg0)))
    (if (< arg0 (+ (-> this free-index) -1))
        (&-
          (the-as pointer (-> this slot (+ arg0 1) anim frames fixed))
          (the-as uint (the-as pointer (-> v1-2 anim frames fixed)))
          )
        (&- (the-as pointer (-> this kheap current)) (the-as uint (the-as pointer (-> v1-2 anim frames fixed))))
        )
    )
  )

(defmethod unload-from-slot ((this art-joint-anim-manager) (arg0 int))
  (let* ((s3-0 (-> this slot arg0))
         (s5-0 (-> s3-0 anim))
         )
    (let ((s2-0 (the-as object (-> s5-0 frames fixed))))
      (if (= (-> *display* base-clock frame-counter) (-> s3-0 time-stamp))
          (format 0 "ERROR: anim-decomp: removing cache entry for ~A, but it is still in use.~%" s5-0)
          )
      (let ((a0-5 (-> s3-0 comp-data))
            (v1-6 (-> s5-0 frames))
            )
        (set! (-> v1-6 fixed) (the-as joint-anim-compressed-fixed a0-5))
        (dotimes (a1-2 (the-as int (-> v1-6 num-frames)))
          (set! (-> v1-6 data a1-2)
                (the-as
                  joint-anim-compressed-frame
                  (+ a0-5 (* (+ (-> v1-6 fixed-qwc) (* (the-as uint a1-2) (-> v1-6 frame-qwc))) 16))
                  )
                )
          )
        (logior! (-> v1-6 flags) 1)
        (logand! (-> v1-6 flags) -3)
        )
      (cond
        ((< arg0 (+ (-> this free-index) -1))
         (let ((s1-0 (- (the-as uint (-> this slot (+ arg0 1) anim frames fixed)) (the-as uint s2-0))))
           (let ((s0-0 (+ (- -1 arg0) (-> this free-index))))
             (let ((a2-6 (&- (-> this kheap current) (the-as uint (+ (the-as uint s2-0) s1-0)))))
               (if (< (the-as int a2-6) 2560)
                   (qmem-copy<-! (the-as pointer s2-0) (the-as pointer (+ (the-as uint s2-0) s1-0)) (the-as int a2-6))
                   (ultimate-memcpy (the-as pointer s2-0) (the-as pointer (+ (the-as uint s2-0) s1-0)) (the-as uint a2-6))
                   )
               )
             (qmem-copy<-! (the-as pointer s3-0) (the-as pointer (&+ s3-0 16)) (* s0-0 16))
             (dotimes (v1-20 s0-0)
               (let ((a0-21 (-> this slot (+ arg0 v1-20) anim frames)))
                 (set! (-> a0-21 fixed) (the-as joint-anim-compressed-fixed (- (the-as uint (-> a0-21 fixed)) s1-0)))
                 (dotimes (a1-9 (the-as int (-> a0-21 num-frames)))
                   (set! (-> a0-21 data a1-9) (the-as joint-anim-compressed-frame (- (the-as uint (-> a0-21 data a1-9)) s1-0)))
                   )
                 )
               )
             )
           (set! s3-0 (-> this slot (+ (-> this free-index) -1)))
           (set! (-> this kheap current) (the pointer (- (the uint (-> this kheap current)) (the-as uint s1-0))))
           )
         )
        (else
          (set! (-> this kheap current) (the-as pointer s2-0))
          )
        )
      )
    (+! (-> this free-index) -1)
    (set! (-> s3-0 anim) #f)
    (set! (-> s3-0 time-stamp) (the-as uint 0))
    (set! (-> s3-0 comp-data) (the-as uint 0))
    s5-0
    )
  )

(defmethod update-time-stamp ((this art-joint-anim-manager) (arg0 art-joint-anim))
  (countdown (v1-0 (-> this free-index))
    (when (= arg0 (-> this slot v1-0 anim))
      (set! (-> this slot v1-0 time-stamp) (the-as uint (-> *display* base-clock frame-counter)))
      (return arg0)
      )
    )
  arg0
  )

(defmethod decompress ((this art-joint-anim-manager) (arg0 art-joint-anim))
  (let* ((s5-0 (-> arg0 frames))
         (s3-0 (* (+ (-> s5-0 fixed-qwc) (* (-> s5-0 num-frames) (-> s5-0 frame-qwc))) 16))
         )
    (while (or (< (the-as uint (&- (-> this kheap top) (the-as uint (-> this kheap current)))) (+ s3-0 64))
               (>= (-> this free-index) 64)
               )
      (let ((a1-2 -1))
        (let ((a0-3 0))
          (dotimes (v1-2 (-> this free-index))
            (when (or (< a1-2 0) (< (the-as int (-> this slot v1-2 time-stamp)) a0-3))
              (set! a0-3 (the-as int (-> this slot v1-2 time-stamp)))
              (set! a1-2 v1-2)
              )
            )
          )
        (unload-from-slot this a1-2)
        )
      )
    (let ((v1-15 (-> this slot (-> this free-index))))
      0
      (+! (-> this free-index) 1)
      (set! (-> v1-15 anim) arg0)
      (set! (-> v1-15 time-stamp) (the-as uint (-> *display* base-clock frame-counter)))
      (set! (-> v1-15 comp-data) (the-as uint (-> s5-0 fixed)))
      )
    (let ((s4-1 (kmalloc (-> this kheap) (the-as int s3-0) (kmalloc-flags) "malloc")))
      (unpack-comp-lzo (the-as (pointer uint8) s4-1) (the-as (pointer uint8) (-> s5-0 fixed)))
      (logand! (-> s5-0 flags) -2)
      (logior! (-> s5-0 flags) 2)
      (set! (-> s5-0 fixed) (the-as joint-anim-compressed-fixed s4-1))
      (dotimes (v1-22 (the-as int (-> s5-0 num-frames)))
        (set! (-> s5-0 data v1-22)
              (the-as
                joint-anim-compressed-frame
                (&+ s4-1 (* (+ (-> s5-0 fixed-qwc) (* (the-as uint v1-22) (-> s5-0 frame-qwc))) 16))
                )
              )
        )
      )
    )
  (flush-cache 0)
  arg0
  )

(defmethod unload-from-level ((this art-joint-anim-manager) (arg0 level))
  (let ((s5-0 (-> arg0 heap base))
        (s4-0 (-> arg0 heap top-base))
        )
    (countdown (s3-0 (-> this free-index))
      (if (and (>= (the-as int (-> this slot s3-0 anim)) (the-as int s5-0))
               (< (the-as int (-> this slot s3-0 anim)) (the-as int s4-0))
               )
          (unload-from-slot this s3-0)
          )
      )
    )
  0
  (none)
  )

(kmemopen global "anim-manager")

(define *anim-manager* (new 'global 'art-joint-anim-manager #x30000))

(kmemclose)
