jak-project/goal_src/jak3/engine/anim/joint-mod-h.gc
2024-02-11 13:53:29 -05:00

694 lines
24 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
;; name: joint-mod-h.gc
;; name in dgo: joint-mod-h
;; dgos: GAME
;; The joint-mod system is used to animate parts of a character from gameplay code.
;; For example, rotating the neck to make a character look at something.
;; This works by installing callbacks in the cspace of the joints, which are used by process-drawable to compute bones.
;; The default callbacks just read and apply transforms from the animation.
;; Generally, the use doesn't install the callback themselves, and uses a utility class from this file.
;; This is a little inconsistent and there's 3 patterns:
;; - using the `joint-mod` class, which can manage many different types of callbacks (no inheritance)
;; - using a class based on `joint-mod-base`, which is a new base class for new types of joint callbacks (joint-mod-blend-world)
;; - using a class that is just a standalone class (joint-mod-polar-look-at, for example)
;; the `joint-mod-base` was added in jak 3.
(defenum joint-mod-mode
:bitfield #t
:type uint32
(flex-blend)
(look-at)
(world-look-at)
(rotate)
(joint-set)
(joint-set*)
(rotate2) ;; ??
(reset)
(polar-look-at)
(joint-set*-world)
(gun-look-at)
(foot-rot)
(joint-set-world)
)
;; +++joint-mod-h:track-mode
(defenum track-mode
:bitfield #t
:type uint16
(track-on 0) ;; 1
(track-x 1) ;; 2
(track-y 2) ;; 4
(lock-on 3) ;; 8
(no-trans 4) ;; 16
(no-rotate 5) ;; 32
(no-scale 6) ;; 64
)
;; ---joint-mod-h:track-mode
(defenum joint-mod-ik-flags
:bitfield #t
:type uint32
(enable)
(elbow-trans-neg)
(elbow-rot-neg)
)
(defenum joint-mod-base-flags
:bitfield #t
:type uint16
(attached 0)
(trans 1)
(quat 2)
(scale 3)
)
(defenum joint-mod-polar-flags
:type uint32
:bitfield #t
(no-z-rot 0)
(blending-to-zero 1)
(negate-nose 2)
(negate-ear 3)
(negate-up 4)
)
(deftype joint-mod-blend-world-work (structure)
((mat1 matrix :inline)
(mat2 matrix :inline)
(quat quaternion :inline)
(vec vector :inline))
)
;; DECOMP BEGINS
(deftype joint-mod (basic)
"Utility to modify a joint transform from code, rather than just getting it from animation.
This is used to make jak look toward an enemy, for example."
((mode joint-mod-mode)
(process process-drawable)
(joint cspace)
(target vector :inline)
(twist vector :inline)
(twist-max vector :inline)
(extra-twist degrees :overlay-at (-> twist data 2))
(track-mode track-mode :overlay-at (-> twist data 3))
(look-at-count uint16 :offset 46)
(twist-range-x meters :overlay-at (-> twist-max data 2))
(twist-range-y meters :overlay-at (-> twist-max data 3))
(twist-speed-x float)
(twist-speed-y float)
(trans vector :inline)
(smushy-old float :overlay-at (-> trans data 0))
(smushy-off float :overlay-at (-> trans data 1))
(smushyv float :overlay-at (-> trans data 2))
(quat quaternion :inline)
(scale vector :inline)
(notice-time time-frame)
(flex-blend float)
(blend float)
(old-blend float)
(max-dist meters)
(ignore-angle degrees)
(up uint8)
(nose uint8)
(ear uint8)
(base-joint uint8)
(base-nose uint8)
(shutting-down? symbol)
(parented-scale? symbol)
)
(:methods
(new (symbol type joint-mod-mode process-drawable int) _type_)
(mode-set! (_type_ joint-mod-mode) none)
(target-set! (_type_ vector) none)
(look-at! (_type_ vector symbol process) none)
(reset-blend! (_type_) _type_)
(twist-set! (_type_ float float float) vector)
(trs-set! (_type_ vector quaternion vector) none)
(shut-down (_type_) none)
)
)
(deftype try-to-look-at-info (basic)
((who handle)
(horz float)
(vert float)
)
)
(defun-debug joint-mod-debug-draw ((jmod joint-mod))
"Debug draw the bone transform for the associated bone of a joint-mod"
(add-debug-matrix #t (bucket-id debug-no-zbuf1) (-> jmod joint bone transform) (meters 2))
0
(none)
)
(defmethod reset-blend! ((this joint-mod))
"Set the blend to 0."
(set! (-> this blend) 0.0)
this
)
(deftype joint-mod-spinner (basic)
"Control a joint by just spinning it around an axis."
((spin-axis vector :inline)
(angle float)
(spin-rate float)
(enable symbol)
)
(:methods
(new (symbol type process-drawable int vector float) _type_)
)
)
(defun joint-mod-spinner-callback ((bone-cspace cspace) (joint-transform transformq))
"cspace callback for joint-mod-spinner. Update the cspace's bone from the parent transformq, plus the rotation from this spinner."
(let ((gp-0 (the-as joint-mod-spinner (-> bone-cspace param1))))
(when (-> gp-0 enable)
(let ((f30-0
(the float (sar (shl (the int (+ (-> gp-0 angle) (* (-> gp-0 spin-rate) (seconds-per-frame)))) 48) 48))
)
)
(quaternion-vector-angle! (-> joint-transform quat) (-> gp-0 spin-axis) f30-0)
(set! (-> gp-0 angle) f30-0)
)
)
)
(cspace<-parented-transformq-joint! bone-cspace joint-transform)
(none)
)
(defmethod new joint-mod-spinner ((allocation symbol) (type-to-make type) (proc process-drawable) (bone-idx int) (axis vector) (rate float))
"Create and attach a joint-mod-spinner to a joint."
(let ((v0-0 (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
(set! (-> v0-0 spin-axis quad) (-> axis quad))
(set! (-> v0-0 spin-rate) rate)
(set! (-> v0-0 enable) #t)
(set! (-> v0-0 angle) 0.0)
(let ((a0-3 (-> proc node-list data bone-idx)))
(set! (-> a0-3 param0) joint-mod-spinner-callback)
(set! (-> a0-3 param1) v0-0)
)
v0-0
)
)
(deftype joint-mod-base (structure)
"Base type for most joint-mods"
((flags joint-mod-base-flags)
(node-index int16)
(proc (pointer process-drawable))
(callback (function cspace transformq none))
)
(:methods
(init (_type_ process-drawable uint joint-mod-base-flags) none)
(attach-callback (_type_) none)
(remove-callback (_type_) none)
)
)
(defmethod attach-callback ((this joint-mod-base))
"Take control of the specified joint by modifying the cspace callback."
(let ((a1-3 (-> this proc 0 node-list data (-> this node-index))))
(set! (-> a1-3 param0) (-> this callback))
(set! (-> a1-3 param1) (the-as basic this))
)
(logior! (-> this flags) (joint-mod-base-flags attached))
0
(none)
)
(defmethod remove-callback ((this joint-mod-base))
"Remove this callback and set param0 to #f to use the default (animated joint)"
(set! (-> this proc 0 node-list data (-> this node-index) param0) #f)
(logclear! (-> this flags) (joint-mod-base-flags attached))
0
(none)
)
(defmethod init ((this joint-mod-base) (proc process-drawable) (bone-idx uint) (flags joint-mod-base-flags))
"Set up this joint-mod to modify the given joint of the given process. Will attach automatically if attached flag is set."
(set! (-> this flags) flags)
(set! (-> this node-index) (the-as int bone-idx))
(set! (-> this proc) (the-as (pointer process-drawable) (process->ppointer proc)))
(if (logtest? flags (joint-mod-base-flags attached))
(attach-callback this)
)
0
(none)
)
(deftype joint-mod-rotate-local (joint-mod-base)
((rotation quaternion :inline)
)
(:methods
(new (symbol type) _type_)
)
)
(defun joint-mod-rotate-local-callback ((bone-cspace cspace) (joint-transform transformq))
"Apply an additional rotation to the transform (left side quaternion multiplication"
(let ((v1-0 (the-as joint-mod-rotate-local (-> bone-cspace param1))))
(quaternion*! (-> joint-transform quat) (-> joint-transform quat) (-> v1-0 rotation))
)
(cspace<-parented-transformq-joint! bone-cspace joint-transform)
(none)
)
(defmethod init ((this joint-mod-rotate-local) (arg0 process-drawable) (arg1 uint) (arg2 joint-mod-base-flags))
"Set up this joint-mod to modify the given joint of the given process. Will attach automatically if attached flag is set."
(set! (-> this callback) joint-mod-rotate-local-callback)
(quaternion-identity! (-> this rotation))
((method-of-type joint-mod-base init) this arg0 arg1 arg2)
(none)
)
(deftype joint-mod-rotate-world (joint-mod-base)
"Add an additional rotation to a joint (right multiply)"
((rotation quaternion :inline)
)
)
(defun vector<-cspace2! ((output-vec vector) (input-cspace cspace))
"Same as vector<-cspace! Convert a bone matrix from a cspace to the origin of the bone frame."
(rlet ((Q :class vf)
(vf0 :class vf)
(vf2 :class vf)
)
(init-vf0-vector)
(.lvf vf2 (&-> (-> input-cspace bone) transform trans quad))
(.div.vf Q vf0 vf2 :fsf #b11 :ftf #b11)
(.wait.vf)
(.mul.vf vf2 vf2 Q :mask #b111)
(.nop.vf)
(.nop.vf)
(.mov.vf vf2 vf0 :mask #b1000)
(.svf (&-> output-vec quad) vf2)
output-vec
)
)
;; WARN: Return type mismatch matrix vs none.
(defun joint-mod-rotate-world-callback ((bone-cspace cspace) (joint-transform transformq))
"Callback for joint-mod-rotate-world. See comment on that type."
(let ((s3-0 (the-as joint-mod-rotate-world (-> bone-cspace param1))))
(cspace<-parented-transformq-joint! bone-cspace joint-transform)
(let ((s4-0 (vector<-cspace2! (new 'stack-no-clear 'vector) bone-cspace)))
(quaternion*! (-> joint-transform quat) (-> joint-transform quat) (-> s3-0 rotation))
(set! (-> joint-transform trans quad) (-> s4-0 quad))
)
)
(cspace<-transformq! bone-cspace joint-transform)
(none)
)
(defmethod init ((this joint-mod-rotate-world) (arg0 process-drawable) (arg1 uint) (arg2 joint-mod-base-flags))
"Set up this joint-mod to modify the given joint of the given process. Will attach automatically if attached flag is set."
(set! (-> this callback) joint-mod-rotate-world-callback)
(quaternion-identity! (-> this rotation))
((method-of-type joint-mod-base init) this arg0 arg1 arg2)
(none)
)
(deftype joint-mod-set-local (joint-mod-base)
"Override the trans, quat, and scale of the joint transform. The component to override is selected by the flag."
((transform transformq :inline)
)
(:methods
(new (symbol type) _type_)
)
)
(defun joint-mod-set-local-callback ((bone-cspace cspace) (joint-transform transformq))
"Callback for joint-mod-rotate-local. See comment on that type."
(let ((v1-0 (the-as joint-mod-set-local (-> bone-cspace param1))))
(if (not (logtest? (-> v1-0 flags) (joint-mod-base-flags trans)))
(set! (-> v1-0 transform trans quad) (-> joint-transform trans quad))
)
(if (not (logtest? (-> v1-0 flags) (joint-mod-base-flags quat)))
(set! (-> v1-0 transform quat quad) (-> joint-transform quat quad))
)
(if (not (logtest? (-> v1-0 flags) (joint-mod-base-flags scale)))
(set! (-> v1-0 transform scale quad) (-> joint-transform scale quad))
)
(cspace<-parented-transformq-joint! bone-cspace (-> v1-0 transform))
)
(none)
)
(defmethod init ((this joint-mod-set-local) (arg0 process-drawable) (arg1 uint) (arg2 joint-mod-base-flags))
"Set up this joint-mod to modify the given joint of the given process. Will attach automatically if attached flag is set."
(rlet ((vf0 :class vf))
(init-vf0-vector)
(set! (-> this callback) joint-mod-set-local-callback)
(.svf (&-> (-> this transform) trans quad) vf0)
(quaternion-identity! (-> this transform quat))
(vector-identity! (-> this transform scale))
((method-of-type joint-mod-base init) this arg0 arg1 arg2)
(none)
)
)
(deftype joint-mod-add-local (joint-mod-base)
"Add to the trans, rotate the quat, and multiply the scale of the joint transform. The components can be selected by the flag.
Unlike jak 2, this actually multiplies the scale, instead of adding."
((transform transformq :inline)
)
(:methods
(new (symbol type) _type_)
)
)
(defun joint-mod-add-local-callback ((bone-cspace cspace) (joint-transform transformq))
"Callback for joint-mod-add-local. See comment on that type."
(rlet ((vf0 :class vf)
(vf4 :class vf)
(vf5 :class vf)
(vf6 :class vf)
)
(init-vf0-vector)
(let ((s4-0 (the-as joint-mod-add-local (-> bone-cspace param1))))
(if (logtest? (-> s4-0 flags) (joint-mod-base-flags trans))
(vector+! (-> joint-transform trans) (-> joint-transform trans) (the-as vector (-> s4-0 transform)))
)
(when (logtest? (-> s4-0 flags) (joint-mod-base-flags quat))
(quaternion*! (-> joint-transform quat) (-> joint-transform quat) (-> s4-0 transform quat))
(quaternion-normalize! (-> joint-transform quat))
)
(when (logtest? (-> s4-0 flags) (joint-mod-base-flags scale))
(let ((a0-4 (-> joint-transform scale)))
(let ((v1-11 (-> joint-transform scale))
(a1-4 (-> s4-0 transform scale))
)
(.lvf vf4 (&-> v1-11 quad))
(.lvf vf5 (&-> a1-4 quad))
)
(.add.x.vf vf6 vf0 vf0 :mask #b1000)
(.mul.vf vf6 vf4 vf5 :mask #b111)
(.svf (&-> a0-4 quad) vf6)
)
)
)
(cspace<-parented-transformq-joint! bone-cspace joint-transform)
(none)
)
)
(defmethod init ((this joint-mod-add-local) (arg0 process-drawable) (arg1 uint) (arg2 joint-mod-base-flags))
"Set up this joint-mod to modify the given joint of the given process. Will attach automatically if attached flag is set."
(rlet ((vf0 :class vf))
(init-vf0-vector)
(set! (-> this callback) joint-mod-add-local-callback)
(.svf (&-> (-> this transform) trans quad) vf0)
(quaternion-identity! (-> this transform quat))
(set-vector! (-> this transform scale) 1.0 1.0 1.0 1.0)
((method-of-type joint-mod-base init) this arg0 arg1 arg2)
(none)
)
)
(deftype joint-mod-set-world (joint-mod-base)
"Directly overwrite the _bone_ transform (ignoring the parent entirely).
This does not pay attention to the flags."
((transform transformq :inline)
)
(:methods
(new (symbol type) _type_)
)
)
;; WARN: Return type mismatch matrix vs none.
(defun joint-mod-set-world-callback ((bone-cspace cspace) (joint-trasnform transformq))
"Callback for joint-mod-set-world. See comment on that type."
(let ((v1-0 (the-as joint-mod-set-local (-> bone-cspace param1))))
(cspace<-transformq! bone-cspace (-> v1-0 transform))
)
(none)
)
(defmethod init ((this joint-mod-set-world) (arg0 process-drawable) (arg1 uint) (arg2 joint-mod-base-flags))
"Set up this joint-mod to modify the given joint of the given process. Will attach automatically if attached flag is set."
(rlet ((vf0 :class vf))
(init-vf0-vector)
(set! (-> this callback) joint-mod-set-world-callback)
(.svf (&-> (-> this transform) trans quad) vf0)
(quaternion-identity! (-> this transform quat))
(vector-identity! (-> this transform scale))
((method-of-type joint-mod-base init) this arg0 arg1 arg2)
(none)
)
)
(deftype joint-mod-set-world-no-trans (joint-mod-base)
"Set the rotation and scale of the _bone_ directly to the values from this transform.
The translation is kept from the result of the normal parented value."
((transform transformq :inline)
)
)
;; WARN: Return type mismatch vector vs none.
(defun joint-mod-set-world-no-trans-callback ((bone-cspace cspace) (joint-transform transformq))
"Callback for joint-mod-set-world-no-trans. See comment on that type."
(let ((s4-0 (the-as joint-mod-set-world-no-trans (-> bone-cspace param1)))
(gp-0 (new 'stack-no-clear 'matrix))
)
(cspace<-parented-transformq-joint! bone-cspace joint-transform)
(matrix<-transformq! gp-0 (-> s4-0 transform))
(set! (-> bone-cspace bone transform rvec quad) (-> gp-0 rvec quad))
(set! (-> bone-cspace bone transform uvec quad) (-> gp-0 uvec quad))
(set! (-> bone-cspace bone transform fvec quad) (-> gp-0 fvec quad))
)
(none)
)
(defmethod init ((this joint-mod-set-world-no-trans) (arg0 process-drawable) (arg1 uint) (arg2 joint-mod-base-flags))
"Set up this joint-mod to modify the given joint of the given process. Will attach automatically if attached flag is set."
(rlet ((vf0 :class vf))
(init-vf0-vector)
(set! (-> this callback) joint-mod-set-world-no-trans-callback)
(.svf (&-> (-> this transform) trans quad) vf0)
(quaternion-identity! (-> this transform quat))
(vector-identity! (-> this transform scale))
((method-of-type joint-mod-base init) this arg0 arg1 arg2)
(none)
)
)
(deftype joint-mod-blend-local (joint-mod-base)
"Blend the _joint_ transform between this transform and the animated one.
Then, apply the normal parented transform."
((transform transformq :inline)
(blend-transform transformq :inline)
(blend float)
)
(:methods
(new (symbol type) _type_)
)
)
(defun joint-mod-blend-local-callback ((bone-cspace cspace) (joint-transform transformq))
"Callback for joint-mod-blend-local. See comment on that type."
(let ((gp-0 (the-as joint-mod-blend-local (-> bone-cspace param1))))
(vector-lerp!
(the-as vector (-> gp-0 blend-transform))
(-> joint-transform trans)
(the-as vector (-> gp-0 transform))
(-> gp-0 blend)
)
(vector-lerp!
(-> gp-0 blend-transform scale)
(-> joint-transform scale)
(-> gp-0 transform scale)
(-> gp-0 blend)
)
(quaternion-slerp!
(-> gp-0 blend-transform quat)
(-> joint-transform quat)
(-> gp-0 transform quat)
(-> gp-0 blend)
)
(cspace<-parented-transformq-joint! bone-cspace (-> gp-0 blend-transform))
)
(none)
)
(defmethod init ((this joint-mod-blend-local) (arg0 process-drawable) (arg1 uint) (arg2 joint-mod-base-flags))
"Set up this joint-mod to modify the given joint of the given process. Will attach automatically if attached flag is set."
(rlet ((vf0 :class vf))
(init-vf0-vector)
(set! (-> this callback) joint-mod-blend-local-callback)
(.svf (&-> (-> this transform) trans quad) vf0)
(quaternion-identity! (-> this transform quat))
(vector-identity! (-> this transform scale))
(set! (-> this blend) 0.0)
((method-of-type joint-mod-base init) this arg0 arg1 arg2)
(none)
)
)
(deftype joint-mod-blend-world (joint-mod-base)
"Blend the _bone_ transform between this one and the animated one."
((transform transformq :inline)
(blend-transform transformq :inline)
(blend float)
)
(:methods
(new (symbol type) _type_)
)
)
;; WARN: Return type mismatch matrix vs none.
(defun joint-mod-blend-world-callback ((bone-cspace cspace) (joint-transform transformq))
"Callback for joint-mod-blend-world. See comment on that type."
(rlet ((vf0 :class vf)
(vf4 :class vf)
(vf5 :class vf)
(vf6 :class vf)
)
(init-vf0-vector)
(let ((gp-0 (the-as joint-mod-blend-world (-> bone-cspace param1))))
(let ((f30-0 (if (logtest? (-> gp-0 flags) (joint-mod-base-flags trans))
(-> gp-0 blend)
0.0
)
)
(f28-0 (if (logtest? (-> gp-0 flags) (joint-mod-base-flags quat))
(-> gp-0 blend)
0.0
)
)
(f26-0 (if (logtest? (-> gp-0 flags) (joint-mod-base-flags scale))
(-> gp-0 blend)
0.0
)
)
(s3-0 (new 'stack-no-clear 'joint-mod-blend-world-work))
)
(if (= (-> bone-cspace parent bone scale w) 0.0)
(matrix<-transformq! (-> s3-0 mat1) joint-transform)
(matrix<-parented-transformq! (-> s3-0 mat1) joint-transform (-> bone-cspace parent bone scale))
)
(matrix*! (-> s3-0 mat2) (-> s3-0 mat1) (-> bone-cspace parent bone transform))
(set-vector!
(-> s3-0 vec)
(vector-length (the-as vector (-> s3-0 mat2)))
(vector-length (-> s3-0 mat2 uvec))
(vector-length (-> s3-0 mat2 fvec))
1.0
)
(let ((a0-11 (-> gp-0 blend-transform scale)))
(let ((v1-18 (-> s3-0 vec))
(a1-4 (-> joint-transform scale))
)
(.lvf vf4 (&-> v1-18 quad))
(.lvf vf5 (&-> a1-4 quad))
)
(.add.x.vf vf6 vf0 vf0 :mask #b1000)
(.mul.vf vf6 vf4 vf5 :mask #b111)
(.svf (&-> a0-11 quad) vf6)
)
(vector-lerp!
(the-as vector (-> gp-0 blend-transform))
(-> s3-0 mat2 trans)
(the-as vector (-> gp-0 transform))
f30-0
)
(vector-lerp! (-> gp-0 blend-transform scale) (-> gp-0 blend-transform scale) (-> gp-0 transform scale) f26-0)
(quaternion-slerp!
(-> gp-0 blend-transform quat)
(matrix->quat (-> s3-0 mat2) (-> s3-0 quat))
(-> gp-0 transform quat)
f28-0
)
)
(cspace<-transformq! bone-cspace (-> gp-0 blend-transform))
)
(none)
)
)
(defmethod init ((this joint-mod-blend-world) (arg0 process-drawable) (arg1 uint) (arg2 joint-mod-base-flags))
"Set up this joint-mod to modify the given joint of the given process. Will attach automatically if attached flag is set."
(rlet ((vf0 :class vf))
(init-vf0-vector)
(set! (-> this callback) joint-mod-blend-world-callback)
(.svf (&-> (-> this transform) trans quad) vf0)
(quaternion-identity! (-> this transform quat))
(vector-identity! (-> this transform scale))
(set! (-> this blend) 0.0)
((method-of-type joint-mod-base init) this arg0 arg1 arg2)
(none)
)
)
(deftype joint-mod-ik (basic)
((flags joint-mod-ik-flags)
(process process-drawable)
(hand-dist float)
(handle-pos vector :inline)
(elbow-pole-vector-axis uint32)
(elbow-rotation-axis uint32)
(user-position vector :inline)
(user-normal vector :inline)
(user-blend float)
(user-float float)
(callback (function joint-mod-ik matrix matrix vector object))
(shoulder-matrix-no-ik matrix :inline)
(elbow-matrix-no-ik matrix :inline)
(blend float)
(blend-interp float)
)
(:methods
(new (symbol type process-drawable int float) _type_)
(set-ik-target! (_type_ vector) none)
(enable-set! (_type_ symbol) none)
)
)
(deftype ik-limb-setup (structure)
((elbow-index int32)
(hand-dist float)
)
)
(deftype joint-mod-polar-look-at (basic)
((flags joint-mod-polar-flags)
(ear int8)
(up int8)
(nose int8)
(polar-internal-tilt-max float)
(polar-internal-radius float)
(polar-external-tilt-max float)
(polar-external-radius float)
(upward-tilt float)
(downward-tilt float)
(forward-twist float)
(backward-twist float)
(target vector :inline)
(blend-duration time-frame)
(blend-start-time time-frame)
(blend-start-value float)
(blend-max float)
)
(:methods
(initialize (_type_ process-drawable int) none)
(set-target! (_type_ vector) none)
(set-both-targets! (_type_ joint-mod-polar-look-at vector) none)
(blend-on! (_type_ time-frame float symbol) none)
(blend-to-off! (_type_ time-frame symbol) none)
(get-start-blend! (_type_) float)
)
)