Files
jak-project/goal_src/jak2/engine/gfx/foreground/bones.gc
T
2022-11-30 22:36:09 -05:00

313 lines
11 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
;; name: bones.gc
;; name in dgo: bones
;; dgos: ENGINE, GAME
;; DECOMP BEGINS
;; todo check bad reference.
;; bones, joints, cspace, matrix, joint-anim-frames...
;; The "joints" define the structure of the skeleton, just storing a bind pose, and parent info. These don't change,
;; and are loaded as part of the skeleton. The actual joint objects are stored in the art-joint-geo.
;; The "do-joint-math" method of process-drawable is responsible for computing the joint-anim-frame and the bones.
;; The "cspace" system is used to compute bones from joint-anim-frames.
;; The "joint-anim-frame" is a list of transformqs for the relative transform between bones.
;; The "bones" are the world space transform of each 'bone'
;; The "do-joint-math" function does:
;; - call the generate-frame-function callback to generate a joint-anim-frame (does the joint anim decompress/blending)
;; - call the prebind-function which can modify the relative transforms (eg: joint-mods)
;; - walk the tree of joints, computing bones using the cspace
;; - call the postbind-function, for other effects.
;; The "bones" system creates matrices for foreground renderers from bones/joints.
;; The inputs are bones/joints, and the output is pris-mtx, which is a 4x4 "t-mtx" for transforming, and a 3x3 (stored in 3 vec4's)
;; n-mtx for rotating normals.
;; all matrices are calculated at once, and shared between merc/emerc/gmerc/shadow
;; this is done by a linked list of "bone calculations", which is stashed in the dma buffer.
;; list node for pending bone calculations. These are terminated by 0's.
(deftype bone-calculation-list (structure)
((first bone-calculation :offset-assert 0)
(next bone-calculation :offset-assert 4)
)
:method-count-assert 9
:size-assert #x8
:flag-assert #x900000008
)
;; head of bone calculation list
(define *bone-calculation-list* (new 'global 'bone-calculation-list))
(defun bone-list-init ()
"Reset bone calculation list to have nothing in it."
(let ((v1-0 *bone-calculation-list*))
(set! (-> v1-0 first) (the-as bone-calculation 0))
(set! (-> v1-0 next) (the-as bone-calculation 0))
)
0
0
(none)
)
;; clear list.
(bone-list-init)
;; VU0 microprogram for bone calculations.
(define bones-vu0-block (new 'static 'vu-function :length 54 :qlength 27))
(defun bones-set-sqwc ()
"Set the sqwc register so the DMA transfer of joints skips the metadata and just transfers the bind-pose."
(set! (-> (the-as dma-bank-control #x1000e000) sqwc) (new 'static 'dma-sqwc :sqwc #x1 :tqwc #x4))
(none)
)
(defun bones-reset-sqwc ()
"Reset sqwc so DMA works normally again (see bones-set-sqwc)"
(set! (-> (the-as dma-bank-control #x1000e000) sqwc) (new 'static 'dma-sqwc :sqwc #x1 :tqwc #x1))
(none)
)
(defun bones-init ((arg0 dma-buffer))
"Initialize scratchpad/vu0 for BONE MATH."
(let ((v1-1 (-> (scratchpad-object bone-memory) work)))
(+ #x70000000 0)
;; scratchpad layout of double-buffered bone calculation.
;; "joints", which are stripped of their metadata qw and are 4qw matrices
(set! (-> v1-1 layout joint 0) (-> (scratchpad-object bone-memory) buffer 0 joint))
(set! (-> v1-1 layout joint 1) (-> (scratchpad-object bone-memory) buffer 1 joint))
;; "bones", which are 5 qw transform + scale separately
(set! (-> v1-1 layout bone 0) (-> (scratchpad-object bone-memory) buffer 0 bone))
(set! (-> v1-1 layout bone 1) (-> (scratchpad-object bone-memory) buffer 1 bone))
;; "output" pris-mtx.
(set! (-> v1-1 layout output 0) (-> (scratchpad-object bone-memory) buffer 0 output))
(set! (-> v1-1 layout output 1) (-> (scratchpad-object bone-memory) buffer 1 output))
)
;; upload the bones vu0 block.
(unless PC_PORT
(let ((gp-0 *vu0-dma-list*))
(let ((v1-2 gp-0))
(set! (-> v1-2 base) (-> v1-2 data))
(set! (-> v1-2 end) (&-> v1-2 data-buffer (-> v1-2 allocated-length)))
)
(dma-buffer-add-vu-function gp-0 bones-vu0-block 0)
(let* ((v1-3 gp-0)
(a0-20 (the-as object (-> v1-3 base)))
)
(set! (-> (the-as dma-packet a0-20) dma) (new 'static 'dma-tag :id (dma-tag-id end)))
(set! (-> (the-as (pointer uint64) a0-20) 1) (the-as uint 0))
(set! (-> v1-3 base) (&+ (the-as pointer a0-20) 16))
)
(.sync.l)
(dma-buffer-send-chain (the-as dma-bank-source #x10008000) gp-0)
)
)
0
(none)
)
;; note that the original game doesn't quite use a normal calling convention here, so we cheat and pass an extra arg.
;; see the C++ code for more details.
(def-mips2c bones-mtx-calc (function (inline-array pris-mtx) (inline-array joint) (inline-array bone) uint object none))
(defun bones-mtx-calc-execute ()
"Execute all bone matrix calculations."
(rlet ((vf1 :class vf)
(vf25 :class vf)
(vf26 :class vf)
(vf27 :class vf)
(vf28 :class vf)
(vf29 :class vf)
(vf30 :class vf)
(vf31 :class vf)
(vf4 :class vf)
(vf5 :class vf)
(vf6 :class vf)
(vf7 :class vf)
(vf8 :class vf)
)
(with-profiler 'bones *profile-bones-color*
(reset! (-> *perf-stats* data (perf-stat-bucket bones)))
;; set up layout in scratchpad (again)
(let ((v1-24 (-> (scratchpad-object bone-memory) work)))
(set! (-> v1-24 layout joint 0) (-> (scratchpad-object bone-memory) buffer 0 joint))
(set! (-> v1-24 layout joint 1) (-> (scratchpad-object bone-memory) buffer 1 joint))
(set! (-> v1-24 layout bone 0) (-> (scratchpad-object bone-memory) buffer 0 bone))
(set! (-> v1-24 layout bone 1) (-> (scratchpad-object bone-memory) buffer 1 bone))
(set! (-> v1-24 layout output 0) (-> (scratchpad-object bone-memory) buffer 0 output))
(set! (-> v1-24 layout output 1) (-> (scratchpad-object bone-memory) buffer 1 output))
)
;; set sqwc to upload joints. This will skip the 1 qw of metadata and just grab the joint matrix.
;; (set! (-> (the-as dma-bank-control #x1000e000) sqwc) (new 'static 'dma-sqwc :sqwc #x1 :tqwc #x4))
;; loop over bone calculations:
(let* ((v1-26 *bone-calculation-list*)
(gp-1 *identity-matrix*)
(s5-1 (-> *math-camera* camera-rot))
(s4-1 (-> v1-26 first))
)
(while (nonzero? s4-1) ;; loop
;; pick correct matrix. The pris-mtx includes camera rotation, so all that's needed in the final
;; renderers is perspective. (unless you set no-cam-rot)
(let ((v1-29 (if (logtest? (-> s4-1 flags) (bone-calc-flags no-cam-rot))
gp-1
s5-1
)
)
)
(.lvf vf28 (&-> v1-29 quad 0))
(.lvf vf29 (&-> v1-29 quad 1))
(.lvf vf30 (&-> v1-29 quad 2))
(.lvf vf31 (&-> v1-29 trans quad))
(.lvf vf25 (&-> v1-29 quad 0))
(.lvf vf26 (&-> v1-29 quad 1))
(.lvf vf27 (&-> v1-29 quad 2))
;; calculate!
(bones-mtx-calc
(-> s4-1 matrix-area)
(-> s4-1 joints)
(-> s4-1 bones)
(-> s4-1 num-bones)
v1-29 ;; hack, to pass matrix to bones-mtx-calc in a better way.
)
)
;; there is an optional post-processing step for ripple.
(when (logtest? (-> s4-1 flags) (bone-calc-flags write-ripple-data))
(let* ((a2-1 s4-1)
(v1-34 (-> a2-1 num-bones))
(a0-26 (the-as pris-mtx (-> a2-1 matrix-area)))
(a1-11 (the-as pris-mtx (-> a2-1 ripple-area)))
)
(.lvf vf1 (&-> a2-1 ripple-vec quad))
(label cfg-15)
(.lvf vf5 (&-> a0-26 t-mtx quad 1))
(.lvf vf6 (&-> a0-26 t-mtx trans quad))
(.lvf vf7 (&-> a0-26 n-mtx quad 0))
(.lvf vf8 (&-> a0-26 n-mtx quad 2))
(.mul.x.vf vf4 vf5 vf1)
(.mul.y.vf vf5 vf5 vf1)
(let ((a3-1 (-> a0-26 t-mtx quad 0)))
(.mul.z.vf vf7 vf7 vf1)
(let ((a2-2 (-> a0-26 t-mtx quad 2)))
(.mul.z.vf vf8 vf8 vf1)
(set! (-> a1-11 t-mtx quad 0) a3-1)
(let ((a3-2 (-> a0-26 n-mtx quad 1)))
(.sub.vf vf6 vf6 vf4)
(set! (-> a1-11 t-mtx quad 2) a2-2)
(.svf (&-> a1-11 t-mtx quad 1) vf5)
(set! (-> a1-11 n-mtx quad 1) a3-2)
)
)
)
(+! v1-34 -1)
(.svf (&-> a1-11 n-mtx quad 0) vf7)
;; (.addiu a0-26 a0-26 128)
(&+! a0-26 128)
(.svf (&-> a1-11 t-mtx trans quad) vf6)
;; (.addiu a1-11 a1-11 128)
(&+! a1-11 128)
(b! (nonzero? v1-34) cfg-15 :delay (.svf (&-> (the (inline-array vector) a1-11) -2 quad) vf8))
)
0
)
(set! s4-1 (-> s4-1 next))
)
)
;; reset sqwc
;; (set! (-> (the-as dma-bank-control #x1000e000) sqwc) (new 'static 'dma-sqwc :sqwc #x1 :tqwc #x1))
;; clear bone list
(bone-list-init)
(read! (-> *perf-stats* data (perf-stat-bucket bones)))
)
0
(none)
)
)
(defun-debug dump-qword ((arg0 qword))
(let ((v1-0 arg0))
(format
0
"~8,'0X: ~8,'0X ~8,'0X ~8,'0X ~8,'0X~%"
v1-0
(-> v1-0 data 0)
(-> v1-0 data 1)
(-> v1-0 data 2)
(-> v1-0 data 3)
)
)
0
(none)
)
(defun-debug dump-mem ((arg0 pointer) (arg1 int))
(dotimes (s4-0 arg1)
(format
0
"~8,'0X: ~8,'0X ~8,'0X ~8,'0X ~8,'0X"
(&+ arg0 (* (* s4-0 4) 4))
(-> (the-as (pointer uint32) (&+ arg0 (* (* s4-0 4) 4))))
(-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 1) 4))))
(-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 2) 4))))
(-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 3) 4))))
)
(format
0
" ~F ~F ~F ~F ~%"
(-> (the-as (pointer uint32) (&+ arg0 (* (* s4-0 4) 4))))
(-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 1) 4))))
(-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 2) 4))))
(-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 3) 4))))
)
)
0
(none)
)
(defun-debug bones-debug ()
0
(none)
)
(defun-debug dump-bone-mem ()
(format 0 "== joints 0 ===========~%")
(dump-mem (the-as pointer (+ 80 #x70000000)) 64)
(format 0 "== bones 0 ============~%")
(dump-mem (the-as pointer (+ 1104 #x70000000)) 80)
(format 0 "== output 0 ===========~%")
(dump-mem (the-as pointer (+ 2384 #x70000000)) 128)
(format 0 "~%~%~%")
(format 0 "== joints 1 ===========~%")
(dump-mem (the-as pointer (+ 4432 #x70000000)) 64)
(format 0 "== bones 1 ============~%")
(dump-mem (the-as pointer (+ 5456 #x70000000)) 80)
(format 0 "== output 1 ===========~%")
(dump-mem (the-as pointer (+ 6736 #x70000000)) 128)
(format 0 "========================~%~%")
0
(none)
)