jak-project/goal_src/jak3/engine/anim/joint.gc
Hat Kid dacb704ef6
decomp3: more engine stuff, fix ja macro detection for jak 2/3, unmerged let matcher, part-tracker-spawn macro (#3436)
- `aligner`
- `effect-control`
- `pov-camera`
- `powerups`
- `los-control-h`
- `airlock`
- `water-anim`
- `blocking-plane`
- `proc-focusable-spawner`
- `idle-control`
- `enemy-h`
- `nav-enemy-h`
- `enemy`
- `enemy-states`
- `particle-curves`
- `base-plat`
- `plat`
- `bouncer`
- `elevator`
- `rigid-body`
- `rigid-body-queue`
- `process-taskable`
- `scene-actor`
- `warp-gate`
- `guard-projectile`
- `metalhead-projectile`
- `los-control`
- `joint-exploder`
- `ragdoll-test`
- `debris`
- `shield-sphere`
- `text`
- `target-launch`
2024-03-30 10:28:02 -04:00

2524 lines
92 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
;; name: joint.gc
;; name in dgo: joint
;; dgos: GAME
;; sorry - this file has a lot of inline modifiations/comments.
;; it's probably better to update this one manually!
;; The "joint" system is used to play back animations.
;; At a very high level, the process to animate a character:
;; - the gameplay code uses the `ja` macros to set up joint animations.
;; - the process-drawable system updates the animation metadata in joint-control. This is responsible for
;; producing an array of joint-control-channel. The channels are arranged into a blend tree, and each
;; channel has a frame number (possibly in between frames) and interpolation weight for the blend tree.
;; - This file, joint.gc looks at those animations, frame numbers, blend weights, and tree structure, then
;; produces the relative transform between bones, called "joint transforms"
;; - The process-drawable system uses the joint transforms to compute bone transforms.
;; - The gameplay code and collision code use the bone transforms to determine world-space positions/rotations.
;; - The "bones.gc" system builds rendering matrices for the foreground renderer
;; - The merc, mercneric, and shadow renderers consume these matrices for their skinning calculations.
;; --- Joint, bone, and cspace ---
;; A "bone" is simply the world space transformation of a character's bone.
;; These "bones" are eventually used to position collision geometry, and compute the skinning matrices for rendering.
;; Note that bones matrices can include per-axis scaling too, to allow animated characters to appear squashed/stretched.
;; "joint" refers the parent-child relation of bones. Like a real skeleton, moving one bone will cause all the
;; bones "below" it in the tree to move too. The "joint transform" refers to the relative transformation between bones.
;; The actual "joint" type is a node in this tree, and simply stores name/indexing information. (it also stores the mesh bind pose,
;; but this is _not_ used at all by the joint system - only renderers! the bind-pose is a property of the meshes and how they are exported,
;; not the actual skeleton/bone locations.
;; "cspace" is a mysterious term. There is a cspace for each bone, and it tells you how to control the bone.
;; By default, the bone is controlled from the animation, in the normal way. It is possible to override this
;; by providing your own callback. This might modify the animation (for example, scale something for big-head mode, mirror something)
;; or completely override it (for example, adjust the transformation to move some disconnected part of a character, spin
;; the propeller on a zoomer).
;; The joint-mod system internally sets the cspace to apply modifications to a joint.
;; the cspace stores a reference to the bone, and often times the game will just pass around the cspace in places
;; where they just want the bone.
;; Note on the cspace bone matrix: when extracting the translation, they use vector<-cspace!, which divides by the w,w component...
;; I have no idea why this is done. It happens in all 3 games. It seems like this value is almost exactly 1 in all cases.
;; ---- Compression and streaming ----
;; Animations from cutscenes are streamed in chunks. This chunking happens a level above this file, and this file just
;; sees short, several second long animations.
;; Animations for jak (walking, jumping, etc) are not streamed since there would be too much latency to wait for the DVD drive.
;; Some of these animations are wrapped in LZO compression. This requires decompressing the entire animation to access it.
;; To avoid redoing the LZO compression on every frame, there is a LZO animation decompression cache. Ideally, the animation
;; is decompressed once on the first frame its used, then remains in the cache while it's in use.
;; Additionally, all animations have their own inner compression format. This format is designed for speed and ease of decompression,
;; and is designed so you can seek to an arbitrary frame. The decompressor is stateless - if frame n + 1 is decompressed after frame n,
;; there is no benefit or reused information.
;; ---- Blending animations ----
;; Multiple animations are played at the same time, using a tree structure. Each animation runs on a separate "channel".
;; There are a few different ways this is specified in gameplay code. The most common way is simply using `ja-channel-push!` calls.
;; The tree operates as a stack machine, consisting of push, blend, and stack operations.
;; The "push" operation creates a new entry on the stack, consisting of an animation.
;; The "blend" operation blends against the last thing on the stack.
;; The "stack" operation adds together the last two things, with the given weight.
;; This is best observed with an example:
;; PUSH(A)
;; a = 1
;; BLEND(B, 0.5)
;; a = 0.5, b = 0.5
;; PUSH(C)
;; a = 0.5, b = 0.5
;; c = 1.0
;; STACK(0.25)
;; a = 0.125, b = 0.125, c = 0.75
;; ---- Stack1 and Push1 ----
;; There are two strange operations: stack1 and push1.
;; My current understanding is that this is simply an optimization.
;; Basically, if the last two joint channels are a "push", then "stack", it is effectively blending "everything before these"
;; with "this last pushed channel".
;; In this case, the engine will set these to push1 and stack1. The "push1" behaves like a blend, and the stack1 is ignored.
;; This has the same behavior, but two advantages: it is okay to completely ignore the stack1, and it reduces the stack depth by one.
;; with our example
;; PUSH(A)
;; a = 1
;; BLEND(B, 0.5)
;; a = 0.5, b = 0.5
;; PUSH1(C, 0.25) ;; note: this needs the weight!
;; a = 0.125, b = 0.125, c = 0.75
;; STACK1(0.25) ;; does nothing, can be left out.
;; a = 0.125, b = 0.125, c = 0.75
;; You might wonder: why both having push1/stack1? Couldn't the code doing animation just request a `blend`,
;; and then we wouldn't have to special-case push1/stack1 here?
;; The reason is probably the no-push feature below
;; ---- no-push -----
;; if "no-push" mode is active, then the stack machine acts like "pushing" just overwrites the top of the stack, and
;; stacking does nothing
;; PUSH(A)
;; a = 1
;; BLEND(B, 0.5)
;; a = 0.5, b = 0.5
;; PUSH(C)
;; c = 1.0
;; STACK(0.25)
;; c = 1.0
;; however, the actual implementation is that pushes work as normal, and stacking always takes the most recent.
;; PUSH(A)
;; a = 1
;; BLEND(B, 0.5)
;; a = 0.5, b = 0.5
;; PUSH(C)
;; a = 0.5, b = 0.5
;; c = 1.0
;; STACK(0.25) ;; the weight is ignored
;; c = 1.0
;; and, in no-push mode, the push1/stack1 _don't_ act like a blend! and the implementation is so you can
;; skip the stack1 entirely.
;; PUSH(A)
;; a = 1
;; BLEND(B, 0.5)
;; a = 0.5, b = 0.5
;; PUSH1(C, 0.25) ;; note: weight is ignored
;; c = 1.0
;; STACK1(0.25) ;; does nothing, can be left out.
;; c = 1.0
;; (note: no-push mode is only supported by the matrix-from-control! function
;; which is used to implement cspace<-matrix-no-push-joint!, which grabs a single joint's matrix
;; for the aligner - more on this later.)
;; ---- Interp2 mode ----
;; Jak 2 introduced a new interpolation system, which runs on top of the blending system described above.
;; They key feature of this new system is that it can mask animations per joint. For example, they apply "gun" animations
;; only to the upper body of jak, while keeping the lower body animated normally. Some joints in the middle of jak are a blend
;; of the two.
;; The important part is that this runs at the joint transform level, not the bone tranform level.
;; Internally, this works by running the entire animation system twice, then blending the joint transform results.
;; --- The first three cspaces/bones ---
;; (this is how it gets set up by default. individual actors can always override.)
;; The first cspace is a special one without a joint. It is "root", and is simply a copy of the actors "root" position.
;; This is what makes all animations relative to the actor's position. There's no joint for this.
;; The second cspace is the "align" cspace. This joint is an animated matrix rather than a transformq.
;; This is used to move the process drawable root. Why would you want to do that? It means the an animation actually moves
;; the process, so if the animation is cancelled, the actor stays in the same spot. The aligner also populates the transv
;; (velocity) based on the speed of the align, so you can use accurate velocities in physics/collision queries.
;; The third cspace is the "prejoint" cspace. This is always the parent of all bones which are associated with meshes.
;; So you can modify the prejoint to move the entire visible actor (without moving the process root trans).
;; Like the second cpsace, it is an animated matrix rather than a transformq.
;; All other joints are animated transformqs, but I'm not sure why.
;; ---- Inner decompression format ----
;; The compressed format is relatively simple.
;; There is a "fixed" data for an entire animation, and "frame data": one for each frame.
;; Each data has some u64's, u32's, and u16's.
;; For the two matrix joints, there is a bit which indicates if the matrix is varying. If so, the matrix is stored
;; in the frame data (so there is a different matrix for each frame), and if not, it is stored in the fixed data (one
;; matrix for the entire animation).
;; For the transformq joints, there are 4-bits of "control" per joint, stored in the control-bits array (packed)
;; the first bit indicates if the trans is varying, quat is varying, scale is varying, and the format of the trans.
;; If the data is varying, it can be found in the frame data, otherwise it is in the fixed data.
;; If the trans format bit is not set, the trans is stored as int16's. The x, y are stored in a single u32, and the z
;; is stored in a single u16. (the reason for this is to avoid unaligned loads and ps2 instruction specific optimization)
;; The trans should be multiplied by 4 to get meters.
;; If the trans format bit is set, the trans is stored as floats. The x, y are stored in a single u64, and the z is
;; stored in a single u32. There is no scaling or int/float conversion needed.
;; The quaternion is stored as 4 int16's packed into a single u64. The value should be divided by 32768.
;; Note that the decompressor handles "flipped" quaternions (all elements multiplied by -1) in interpolation so there should
;; be no assumptions about the quaternion convention of animations (of both the compressed data, and the output of the decompressor)
;; The scale is stored as 3 int16's. The x, y are stored in a single u32, and the z is stored in a single u16.
;; The scale should be divided by 4096.
(define-extern create-interpolated-joint-animation-frame (function joint-anim-frame int joint-control int))
(define-extern *anim-manager* art-joint-anim-manager)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; new joint decompressor - now in GOAL!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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
;;;;;;;;;;;;;;;;;;
;; basic methods
;;;;;;;;;;;;;;;;;;
(defmethod print ((this joint))
(format #t "#<~A ~S ~D @ #x~X>" (-> this type) (-> this name) (-> this number) this)
this
)
(defmethod mem-usage ((this joint) (usage memory-usage-block) (flags int))
(set! (-> usage length) (max 69 (-> usage length)))
(set! (-> usage data 68 name) "joint")
(+! (-> usage data 68 count) 1)
(let ((v1-6 (asize-of this)))
(+! (-> usage data 68 used) v1-6)
(+! (-> usage data 68 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 ((jad joint-anim-drawable))
"Login a joint-anim-drawable by calling login on all drawables"
(dotimes (s5-0 (-> jad length))
(if (-> jad data s5-0)
(login (-> jad data s5-0))
)
)
jad
)
(defun joint-anim-inspect-elt ((ja joint-anim) (frame float))
"Inspect an uncompressed anim (unused)"
(case (-> ja type)
((joint-anim-matrix)
((method-of-type matrix inspect) (the-as matrix (+ (+ (* (the int frame) 64) 12) (the-as int ja))))
)
((joint-anim-transformq)
(format #t "~`transform`P~%" (+ (+ (* 48 (the int frame)) 12) (the-as int ja)))
)
)
ja
)
(defmethod mem-usage ((this joint-anim-drawable) (usage memory-usage-block) (flags int))
(set! (-> usage length) (max 81 (-> usage length)))
(set! (-> usage data 80 name) "joint-anim-drawable")
(+! (-> usage data 80 count) 1)
(let ((v1-6 (asize-of this)))
(+! (-> usage data 80 used) v1-6)
(+! (-> usage data 80 total) (logand -16 (+ v1-6 15)))
)
(dotimes (s3-0 (-> this length))
(mem-usage (-> this data s3-0) usage flags)
)
this
)
(defun jacc-mem-usage ((jacc joint-anim-compressed-control) (mem-block memory-usage-block) (flags int))
"Compute memory usage stats for a compressed joint anim."
(set! (-> mem-block length) (max 71 (-> mem-block length)))
(set! (-> mem-block data 70 name) "joint-anim-compressed-control")
(+! (-> mem-block data 70 count) 1)
(let ((v1-7 (+ (* (-> jacc num-frames) 4) 16)))
(+! (-> mem-block data 70 used) v1-7)
(+! (-> mem-block data 70 total) (logand -16 (+ v1-7 15)))
)
(set! (-> mem-block length) (max 72 (-> mem-block length)))
(set! (-> mem-block data 71 name) "joint-anim-fixed")
(+! (-> mem-block data 71 count) 1)
(let ((v1-17 (+ (-> jacc fixed-qwc) 16)))
(+! (-> mem-block data 71 used) v1-17)
(+! (-> mem-block data 71 total) (logand -16 (+ v1-17 15)))
)
(dotimes (v1-21 (the-as int (-> jacc num-frames)))
(set! (-> mem-block length) (max 73 (-> mem-block length)))
(set! (-> mem-block data 72 name) "joint-anim-frame")
(+! (-> mem-block data 72 count) 1)
(let ((a2-15 (* (-> jacc frame-qwc) 16)))
(+! (-> mem-block data 72 used) a2-15)
(+! (-> mem-block data 72 total) (logand -16 (+ a2-15 15)))
)
)
jacc
)
(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))
"Print the list of joint animations playing in the flattened blend tree."
(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 contains-art-for-other-group? ((this art))
"Some art groups have placeholder #f's for some art that will be loaded separately as needed.
Does this art group contain art that needs to be added to another group?"
#f
)
;; WARN: Return type mismatch symbol vs basic.
(defmethod get-art-by-name-method ((this art) (arg0 string) (arg1 type))
"Look inside this art for an art with the given name and type. Return #f if not found"
(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))
"Look inside this art for an art with the given name and type and return the index of the art. Return #f if not found."
(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 art-method-10 ((this art))
this
)
(defmethod mem-usage ((this art-mesh-anim) (usage memory-usage-block) (flags int))
(set! (-> usage length) (max 76 (-> usage length)))
(set! (-> usage data 75 name) "art-mesh-anim")
(+! (-> usage data 75 count) 1)
(let ((v1-6 (asize-of this)))
(+! (-> usage data 75 used) v1-6)
(+! (-> usage data 75 total) (logand -16 (+ v1-6 15)))
)
(if (-> this extra)
(mem-usage (-> this extra) usage (logior flags 512))
)
(dotimes (s3-0 (-> this length))
(mem-usage (-> this data s3-0) usage flags)
)
this
)
(defmethod mem-usage ((this art-joint-anim) (usage memory-usage-block) (flags int))
(set! (-> usage length) (max 79 (-> usage length)))
(set! (-> usage data 78 name) "art-joint-anim")
(+! (-> usage data 78 count) 1)
(let ((v1-6 (asize-of this)))
(+! (-> usage data 78 used) v1-6)
(+! (-> usage data 78 total) (logand -16 (+ v1-6 15)))
)
(if (-> this extra)
(mem-usage (-> this extra) usage (logior flags 512))
)
(jacc-mem-usage (-> this frames) usage flags)
(when (and (nonzero? (-> this eye-anim)) (-> this eye-anim))
(set! (-> usage length) (max 113 (-> usage length)))
(set! (-> usage data 112 name) "eye-anim")
(+! (-> usage data 112 count) 1)
(let ((v1-26 (* (* (+ (-> this eye-anim max-frame) 1) 2) 8)))
(+! (-> usage data 112 used) v1-26)
(+! (-> usage data 112 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 contains-art-for-other-group? ((this art-group))
"Some art groups have placeholder #f's for some art that will be loaded separately as needed.
Does this art group contain art that needs to be added to another group?"
(and (nonzero? (-> this length))
(type? (-> this data 0) art-element)
(not (string= (-> this name) (-> 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))
"Look inside this art for an art with the given name and type. Return #f if not found"
(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))
"Look inside this art for an art with the given name and type and return the index of the art. Return #f if not found."
(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))
(set! (-> *kernel-context* login-art-group) this)
(dotimes (s5-0 (-> this length))
(if (-> this data s5-0)
(set! (-> this data s5-0) (login (-> this data s5-0)))
)
)
(set! (-> *kernel-context* login-art-group) #f)
this
)
(defmethod art-method-10 ((this art-group))
(dotimes (s5-0 (-> this length))
(if (-> this data s5-0)
(set! (-> this data s5-0) (art-method-10 (-> this data s5-0)))
)
)
this
)
(defmethod mem-usage ((this art-group) (usage memory-usage-block) (flags int))
(set! (-> usage length) (max 75 (-> usage length)))
(set! (-> usage data 74 name) "art-group")
(+! (-> usage data 74 count) 1)
(let ((v1-6 (asize-of this)))
(+! (-> usage data 74 used) v1-6)
(+! (-> usage data 74 total) (logand -16 (+ v1-6 15)))
)
(if (-> this extra)
(mem-usage (-> this extra) usage (logior flags 512))
)
(dotimes (s3-0 (-> this length))
(if (-> this data s3-0)
(mem-usage (-> this data s3-0) usage flags)
)
)
this
)
;; WARN: Return type mismatch art-group vs none.
(defmethod relocate ((this art-group) (heap kheap) (name (pointer uint8)))
(let ((s4-0 (clear *temp-string*)))
(string<-charp s4-0 name)
(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) (level-memory-mode tiny-edge))
)
(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))
;; not an art-group for a level, so we log it in here.
;; levels will log in their art group in their load function.
(login this)
;; if needed, give this art to the art-group that needs it.
(if (contains-art-for-other-group? this)
(link-art-to-master this)
)
)
;; give to level
(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) (usage memory-usage-block) (flags int))
(set! (-> usage length) (max 77 (-> usage length)))
(set! (-> usage data 76 name) "art-mesh-geo")
(+! (-> usage data 76 count) 1)
(let ((v1-6 (asize-of this)))
(+! (-> usage data 76 used) v1-6)
(+! (-> usage data 76 total) (logand -16 (+ v1-6 15)))
)
(if (-> this extra)
(mem-usage (-> this extra) usage (logior flags 512))
)
(dotimes (s3-0 (-> this length))
(mem-usage (-> this data s3-0) usage flags)
)
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))
"Look inside this art for an art with the given name and type. Return #f if not found"
(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))
"Look inside this art for an art with the given name and type and return the index of the art. Return #f if not found."
(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) (usage memory-usage-block) (flags int))
(set! (-> usage length) (max 78 (-> usage length)))
(set! (-> usage data 77 name) "art-joint-geo")
(+! (-> usage data 77 count) 1)
(let ((v1-6 (asize-of this)))
(+! (-> usage data 77 used) v1-6)
(+! (-> usage data 77 total) (logand -16 (+ v1-6 15)))
)
(if (-> this extra)
(mem-usage (-> this extra) usage (logior flags 512))
)
(dotimes (s3-0 (-> this length))
(mem-usage (-> this data s3-0) usage flags)
)
this
)
;; WARN: Return type mismatch symbol vs none.
(defun joint-control-cleanup ((jc joint-control) (heap kheap) (ja art-joint-anim))
"Remove all animations that are stored on the given heap and return those slots to a safe default."
(let ((v1-0 (-> heap base))
(a1-1 (-> heap top-base))
(v0-0 #f)
)
(countdown (a3-1 (+ (-> jc active-channels) (-> jc float-channels)))
(let ((t0-3 (-> jc channel a3-1)))
(when (and (>= (the-as int (-> t0-3 frame-group)) (the-as int v1-0))
(< (the-as int (-> t0-3 frame-group)) (the-as int a1-1))
)
(set! (-> t0-3 frame-group) ja)
(set! (-> t0-3 frame-num) 0.0)
(set! (-> t0-3 num-func) num-func-identity)
(set! v0-0 #t)
)
)
)
v0-0
)
)
(defbehavior joint-control-channel-eval process ((jcc joint-control-channel))
"Run the num-func to produce the current frame for this channel."
(let ((f0-3 ((-> jcc num-func) jcc (-> jcc param 0) (-> jcc param 1) (-> jcc param 2))))
(set! (-> jcc eval-time) (the-as uint (current-time)))
f0-3
)
)
(defbehavior joint-control-channel-eval! process ((jcc joint-control-channel) (num-func (function joint-control-channel float float float float)))
"Update the num-func for this channel and evaluate it."
(set! (-> jcc num-func) num-func)
(let ((f0-3 (num-func jcc (-> jcc param 0) (-> jcc param 1) (-> jcc param 2))))
(set! (-> jcc eval-time) (the-as uint (current-time)))
f0-3
)
)
(defun joint-control-channel-group-eval! ((jcc joint-control-channel)
(ja art-joint-anim)
(num-func (function joint-control-channel float float float float))
)
"Set the num-func and anim for the given channel, then eval it. If ja = #f, don't change it."
(set! (-> jcc num-func) num-func)
(cond
((= (-> jcc command) (joint-control-command stack))
;; stack commands don't have an animation, they just add together previous ones.
)
(else
;; set anim
(if ja
(set! (-> jcc frame-group) ja)
)
;; initialize num-func.
(num-func jcc (-> jcc param 0) (-> jcc param 1) (-> jcc param 2))
(set! (-> jcc 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 the num-func and anim for the channel. If ja = #f, don't change it."
;; update num-func
(set! (-> arg0 num-func) arg2)
(cond
((= (-> arg0 command) (joint-control-command stack))
;; stack commands don't have an animation, they just add together previous ones.
)
(arg1
(set! (-> arg0 frame-group) arg1)
)
)
0
)
(defun joint-control-copy! ((dst joint-control) (src joint-control))
"Copy all settings and channels from one joint-control to another."
(set! (-> dst blend-index) (-> src blend-index))
(set! (-> dst active-channels) (-> src active-channels))
(set! (-> dst float-channels) (the-as uint 0))
(set! (-> dst root-channel)
(the-as
(inline-array joint-control-channel)
(-> dst
channel
(/ (the-as int (- (the-as uint (-> src root-channel)) (the-as uint (the-as uint (-> src channel))))) 64)
)
)
)
(let ((v1-10 (min (the-as int (-> dst allocated-length)) (the-as int (-> src active-channels)))))
(mem-copy! (the-as pointer (-> dst channel)) (the-as pointer (-> src channel)) (* v1-10 64))
)
(dotimes (v1-12 (the-as int (-> dst allocated-length)))
(set! (-> dst channel v1-12 parent) dst)
)
dst
)
(defun joint-control-remap! ((jc joint-control)
(dst-art-group art-group)
(parent-art-group art-group)
(remap-list pair)
(seed int)
(prefix string)
)
"Map animation from parent to child using the given animation mapping.
This is used to animate daxter based on the animation of jak."
(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 (-> parent-art-group name)) 1))
(set! sv-24 #t)
(set! sv-32 seed)
(set! sv-40 2)
(while (and (< sv-40 (-> dst-art-group length))
(or (not (-> dst-art-group data sv-40)) (!= (-> dst-art-group data sv-40 type) art-joint-anim))
)
(set! sv-40 (+ sv-40 1))
)
(dotimes (s2-1 (the-as int (+ (-> jc active-channels) (-> jc float-channels))))
(set! sv-48 (-> jc channel s2-1))
(set! sv-52 (the-as basic #f))
(when (-> sv-48 frame-group)
(format (clear *temp-string*) "~S~G" prefix (&+ (-> sv-48 frame-group name data) sv-16))
(when (not (null? remap-list))
(set! sv-56 (nassoc *temp-string* remap-list))
(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) jc sv-48 0)))
(s1-3 s0-0 sv-80 a2-4)
)
)
)
)
)
)
(set! sv-64 (get-art-by-name dst-art-group *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) jc sv-48 1)
)
)
(else
(set! (-> sv-48 frame-group) (the-as art-joint-anim (-> dst-art-group data sv-40)))
(set! (-> sv-48 frame-num) 0.0)
(set! sv-24 (the-as symbol #f))
)
)
)
)
sv-24
)
;; NOTE: this function is not used with the new decompressor, but it's interesting to read.
(defun flatten-joint-control-to-spr ((jc joint-control))
"Walk the blend tree and compute interpolation weights, prepare animation upload info."
(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)
)
;; We assume a maximum of 4 * 6 = 24 channels.
(let ((chan-count (+ (-> jc active-channels) (-> jc float-channels))))
(let ((one 1.0) ;; constant
(chan-float-offset 0) ;; which channel's weight to adjust.
(chan-vector-ptr (the-as (inline-array vector) #x70000960)) ;; stack pointer
(interp2-selected-idx (-> jc active-frame-interp)) ;; interp2 0 or 1 selector.
)
;; loop over channels
(dotimes (chan-idx (the-as int chan-count))
(let ((chan (-> jc channel chan-idx)))
(case (-> chan command)
(((joint-control-command push))
;; push a new stack frame with this anim set to 1.
(let ((flt1 (the-as (pointer float) (+ (the-as int chan-vector-ptr) chan-float-offset))))
;; initialize all channels in this frame to 0
(set! (-> chan-vector-ptr 0 quad) (the-as uint128 0))
(set! (-> chan-vector-ptr 1 quad) (the-as uint128 0))
(set! (-> chan-vector-ptr 2 quad) (the-as uint128 0))
(set! (-> chan-vector-ptr 3 quad) (the-as uint128 0))
(set! (-> chan-vector-ptr 4 quad) (the-as uint128 0))
(set! (-> chan-vector-ptr 5 quad) (the-as uint128 0))
;; then, set the weight of this animation to 1.
(set! (-> flt1 0) one)
)
;; advance stack pointer.
(set! chan-vector-ptr (the-as (inline-array vector) (-> chan-vector-ptr 6)))
)
(((joint-control-command blend) (joint-control-command push1) (joint-control-command float))
;; determine the blend factor for this animation.
(let ((interp2-selected-weight1 (-> chan frame-interp interp2-selected-idx)))
;; one - blend_factor gives us the blend weight for the previous thing in the frame
(let ((a3-5 (- one interp2-selected-weight1)))
(.mov vf1 a3-5)
)
;; modify the previous thing in the stack to reduce weight:
(let ((prev-chan-ptr (the-as (inline-array vector) (-> chan-vector-ptr -6))))
(.lvf vf2 (&-> prev-chan-ptr 0 quad))
(let ((a3-6 (&+ (the-as pointer prev-chan-ptr) chan-float-offset)))
(.lvf vf3 (&-> prev-chan-ptr 1 quad))
(.lvf vf4 (&-> prev-chan-ptr 2 quad))
(.lvf vf5 (&-> prev-chan-ptr 3 quad))
(.lvf vf6 (&-> prev-chan-ptr 4 quad))
(.lvf vf7 (&-> prev-chan-ptr 5 quad))
(.mul.x.vf vf2 vf2 vf1) ;; multiply all weights by (1 - push_blend)
(.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 (&-> prev-chan-ptr 0 quad) vf2)
(.svf (&-> prev-chan-ptr 1 quad) vf3)
(.svf (&-> prev-chan-ptr 2 quad) vf4)
(.svf (&-> prev-chan-ptr 3 quad) vf5)
(.svf (&-> prev-chan-ptr 4 quad) vf6)
(.svf (&-> prev-chan-ptr 5 quad) vf7)
;; but, modify our channel to add in the push_blend
(+! (-> (the-as (pointer float) a3-6) 0) interp2-selected-weight1)
)
(set! chan-vector-ptr (the-as (inline-array vector) (-> prev-chan-ptr 6)))
)
)
)
(((joint-control-command stack))
;; add together the last two stack frames, using the given weight.
(let* ((interp2-selected-weight2 (-> chan frame-interp interp2-selected-idx))
(one-minus-interp2 (- one interp2-selected-weight2))
;; back up 2 stack frames, to add them.
(chans-to-stack (the-as (inline-array vector) (-> chan-vector-ptr -12)))
)
(let ((a3-8 interp2-selected-weight2))
(.mov vf1 a3-8)
)
(let ((a3-9 one-minus-interp2))
(.mov vf2 a3-9)
)
;; load first stack frame
(.lvf vf3 (&-> chans-to-stack 0 quad))
(.lvf vf4 (&-> chans-to-stack 1 quad))
(.lvf vf5 (&-> chans-to-stack 2 quad))
(.lvf vf6 (&-> chans-to-stack 3 quad))
(.lvf vf7 (&-> chans-to-stack 4 quad))
(.lvf vf8 (&-> chans-to-stack 5 quad))
;; multiply by blend weight
(.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)
;; load second stack frame
(.lvf vf9 (&-> chans-to-stack 6 quad))
(.lvf vf10 (&-> chans-to-stack 7 quad))
(.lvf vf11 (&-> chans-to-stack 8 quad))
(.lvf vf12 (&-> chans-to-stack 9 quad))
(.lvf vf13 (&-> chans-to-stack 10 quad))
(.lvf vf14 (&-> chans-to-stack 11 quad))
;; multiply by blend weight
(.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)
;; the add!
(.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)
;; overwrite the first
(.svf (&-> chans-to-stack 0 quad) vf3)
(.svf (&-> chans-to-stack 1 quad) vf4)
(.svf (&-> chans-to-stack 2 quad) vf5)
(.svf (&-> chans-to-stack 3 quad) vf6)
(.svf (&-> chans-to-stack 4 quad) vf7)
(.svf (&-> chans-to-stack 5 quad) vf8)
;; this ends up moving the stack pointer back 1 stack frame (went back 2, then fwd 1)
(set! chan-vector-ptr (the-as (inline-array vector) (&+ (the-as pointer chans-to-stack) 96)))
)
)
)
)
;; advance channel
(+! chan-float-offset 4)
)
)
;; now we have figured out all the weights for each channel - we need to figure out which animations need decompressing.
(let ((upload-count 0))
(dotimes (upload-chan-idx (the-as int chan-count))
;; only upload if the weight is nonzero.
(when (< 0.001 (-> (the-as terrain-context #x70000000) work foreground joint-work flatten-array upload-chan-idx))
;; determine integer frame we need
(let* ((upload-chan (-> jc channel upload-chan-idx))
(anim (-> upload-chan frame-group frames))
(frame-num (-> upload-chan frame-num))
(int-frame-num (the int frame-num))
(frame-frac (- frame-num (the float int-frame-num)))
)
(let ((last-frame (+ (-> anim num-frames) -1)))
(if (not (-> upload-chan frame-group))
(format 0 "Channel ~D skel ~A frame-group is #f!!!~%" upload-chan-idx jc)
)
;; if we're past the end, clamp
(when (>= int-frame-num (the-as int last-frame))
(set! frame-frac 0.0)
(set! int-frame-num (the-as int last-frame))
)
)
;; set up the upload:
(let ((upload (-> (the-as terrain-context #x70000000) work foreground joint-work uploads upload-count)))
(set! (-> upload fixed) (-> anim fixed))
(set! (-> upload fixed-qwc) (the-as int (-> anim fixed-qwc)))
(set! (-> upload frame) (-> anim data int-frame-num))
;; if we are a fractional frame, upload 2 frames so we can interpolate from the next.
(set! (-> upload frame-qwc) (the-as int (if (= frame-frac 0.0)
(-> anim frame-qwc)
(* (-> anim frame-qwc) 2)
)
)
)
(set! (-> upload amount)
(-> (the-as terrain-context #x70000000) work foreground joint-work flatten-array upload-chan-idx)
)
(set! (-> upload interp) frame-frac)
)
)
(+! upload-count 1)
)
)
(set! (-> (the-as terrain-context #x70000000) work foreground joint-work num-uploads) upload-count)
)
;; record amounts in the channel so we can print it for debug.
(dotimes (v1-26 (the-as int chan-count))
(set! (-> jc channel v1-26 inspector-amount)
(the-as
uint
(the int (* 255.0 (-> (the-as terrain-context #x70000000) work foreground joint-work flatten-array v1-26)))
)
)
)
)
0
)
)
;; WARN: Return type mismatch object vs matrix.
(defun matrix-from-joint-anim-frame ((jacc joint-anim-compressed-control) (joint-idx int) (frame-idx int))
"Get a matrix from a joint-animation at a given (integer) frame.
This only works on the first two joints, since those are the only ones that store matrices."
(let ((fixed-matrix (the-as object (-> jacc fixed data)))
(frame-matrix (the-as object (-> jacc data frame-idx data)))
)
(cond
((not (logtest? (-> jacc fixed hdr matrix-bits) 1))
(set! fixed-matrix (cond
((zero? joint-idx)
(return (the-as matrix fixed-matrix))
fixed-matrix
)
(else
(-> (the-as (inline-array vector) fixed-matrix) 4)
)
)
)
)
((zero? joint-idx)
(return (the-as matrix frame-matrix))
)
(else
(set! frame-matrix (-> (the-as (inline-array vector) frame-matrix) 4))
)
)
(if (not (logtest? (-> jacc fixed hdr matrix-bits) 2))
(return (the-as matrix fixed-matrix))
)
(the-as matrix frame-matrix)
)
)
(defun matrix-from-control-channel! ((dest-mat matrix) (requested-joint joint) (chan joint-control-channel))
"Get a matrix for a joint (must be 0 or 1) for the animation specified by the channel.
Will interpolate if we are in between animation frames.
This does not apply any frame-interp blending."
(let ((jacc (-> chan frame-group))
(joint-num (-> requested-joint number))
)
(if (>= joint-num 2)
(format 0 "ERROR: Call to matrix-from-control-channel! on joint ~D~%" joint-num)
)
(let* ((frame-num (fmax 0.0 (fmin (-> chan frame-num) (the float (+ (-> jacc frames num-frames) -1)))))
(f0-1 frame-num)
)
(cond
((= (the float (the int f0-1)) f0-1)
(let* ((mat (matrix-from-joint-anim-frame (-> jacc frames) joint-num (the int frame-num)))
(v1-7 (-> mat rvec quad))
(a0-3 (-> mat uvec quad))
(a1-3 (-> mat fvec quad))
(a2-4 (-> mat trans quad))
)
(set! (-> dest-mat rvec quad) v1-7)
(set! (-> dest-mat uvec quad) a0-3)
(set! (-> dest-mat fvec quad) a1-3)
(set! (-> dest-mat trans quad) a2-4)
)
dest-mat
)
(else
(let ((first-mat (matrix-from-joint-anim-frame (-> jacc frames) joint-num (the int frame-num)))
(second-mat (matrix-from-joint-anim-frame (-> jacc frames) joint-num (+ (the int frame-num) 1)))
(mat-blend (- frame-num (the float (the int frame-num))))
)
(matrix-lerp! dest-mat first-mat second-mat mat-blend)
)
)
)
)
)
)
(defun matrix-from-control-pair! ((matrix-to-modify matrix) (jcc joint-control-channel) (jnt joint) (active-frame-interp int))
"Modify the matrix to add in a blended animation for the given channel."
(let ((f30-0 (-> jcc frame-interp active-frame-interp)))
(cond
((>= 0.0 f30-0)
(empty)
matrix-to-modify
)
((>= f30-0 1.0)
(matrix-from-control-channel! matrix-to-modify jnt jcc)
)
(else
(let ((a2-3 (matrix-from-control-channel! (scratchpad-object matrix) jnt jcc)))
(matrix-lerp! matrix-to-modify matrix-to-modify a2-3 f30-0)
)
)
)
)
)
;; WARN: Return type mismatch (inline-array matrix) vs matrix.
(defun matrix-from-control! ((mat-stack matrix-stack) (jnt joint) (jc joint-control) (mode symbol))
"Compute a matrix for a given joint (must be 0 or 1) given the entire joint-control.
This walks the blend tree."
(set! (-> mat-stack top) (the-as matrix (-> mat-stack data)))
(dotimes (s2-0 (the-as int (+ (-> jc active-channels) (-> jc float-channels))))
(let* ((a2-1 (-> jc channel s2-0))
(v1-3 (-> a2-1 command))
(s1-0 64)
)
(cond
((and (= mode 'no-push) (= v1-3 (joint-control-command push1)))
(matrix-from-control-channel! (the matrix (&- (-> mat-stack top) (the-as uint s1-0))) jnt a2-1)
)
((and (= mode 'no-push) (= v1-3 (joint-control-command stack)))
(set! (-> mat-stack top) (the matrix (&- (-> mat-stack top) (the-as uint s1-0))))
(let* ((v1-9 (the matrix (&- (-> mat-stack top) (the-as uint s1-0))))
(a3-1 (-> mat-stack top))
(a0-8 (-> a3-1 rvec quad))
(a1-6 (-> a3-1 uvec quad))
(a2-2 (-> a3-1 fvec quad))
(a3-2 (-> a3-1 trans quad))
)
(set! (-> v1-9 rvec quad) a0-8)
(set! (-> v1-9 uvec quad) a1-6)
(set! (-> v1-9 fvec quad) a2-2)
(set! (-> v1-9 trans quad) a3-2)
)
)
((and (= mode 'no-push) (= v1-3 (joint-control-command float)))
)
((= v1-3 (joint-control-command push))
(matrix-from-control-channel! (-> mat-stack top) jnt a2-1)
(set! (-> mat-stack top) (the matrix (+ (the-as uint (-> mat-stack top)) s1-0)))
)
((logtest? v1-3 (joint-control-command blend))
(matrix-from-control-pair!
(the matrix (&- (-> mat-stack top) (the-as uint s1-0)))
a2-1
jnt
(the-as int (-> jc active-frame-interp))
)
)
((= v1-3 (joint-control-command stack))
(set! (-> mat-stack top) (the matrix (&- (-> mat-stack top) (the-as uint s1-0))))
(let ((a1-11 (the matrix (&- (-> mat-stack top) (the-as uint s1-0))))
(v1-19 (-> mat-stack top))
(f0-0 (-> a2-1 frame-interp (-> jc active-frame-interp)))
)
(matrix-lerp! a1-11 a1-11 v1-19 f0-0)
)
)
)
)
)
(the-as matrix (-> mat-stack 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! ((dst cspace) (src cspace))
"Set one cspace's bone from another"
(let ((v0-0 (-> dst bone transform)))
(let* ((a2-0 (-> src bone transform))
(v1-2 (-> a2-0 rvec quad))
(a0-1 (-> a2-0 uvec quad))
(a1-1 (-> a2-0 fvec quad))
(a2-1 (-> a2-0 trans quad))
)
(set! (-> v0-0 rvec quad) v1-2)
(set! (-> v0-0 uvec quad) a0-1)
(set! (-> v0-0 fvec quad) a1-1)
(set! (-> v0-0 trans quad) a2-1)
)
v0-0
)
)
(defun cspace<-cspace-normalized! ((dst cspace) (src cspace))
"Set one cspace's bone from another, and normalize the rows of the matrix."
(let ((gp-0 (-> dst bone transform)))
(let* ((a2-0 (-> src bone transform))
(v1-2 (-> a2-0 rvec quad))
(a0-1 (-> a2-0 uvec quad))
(a1-1 (-> a2-0 fvec quad))
(a2-1 (-> a2-0 trans quad))
)
(set! (-> gp-0 rvec quad) v1-2)
(set! (-> gp-0 uvec quad) a0-1)
(set! (-> gp-0 fvec quad) a1-1)
(set! (-> gp-0 trans quad) a2-1)
)
(vector-normalize! (-> gp-0 rvec) 1.0)
(vector-normalize! (-> gp-0 uvec) 1.0)
(vector-normalize! (-> gp-0 fvec) 1.0)
gp-0
)
)
(defun cspace<-parent-joint! ((dst cspace) (proc (pointer process-drawable)) (parent-idx int))
"Set one cspace's bone to another from the given process-drawable"
(let ((v0-0 (-> dst bone transform)))
(let* ((a2-1 (-> proc 0 node-list data parent-idx bone transform))
(v1-5 (-> a2-1 rvec quad))
(a0-2 (-> a2-1 uvec quad))
(a1-1 (-> a2-1 fvec quad))
(a2-2 (-> a2-1 trans quad))
)
(set! (-> v0-0 rvec quad) v1-5)
(set! (-> v0-0 uvec quad) a0-2)
(set! (-> v0-0 fvec quad) a1-1)
(set! (-> v0-0 trans quad) a2-2)
)
v0-0
)
)
(defun cspace<-rot-yxy! ((dst cspace) (src transform))
"Set one cspace's bone to a yxy rotation and scale."
(let ((s5-0 (-> dst bone transform)))
(matrix-rotate-yxy! s5-0 (-> src rot))
(scale-matrix! s5-0 (-> src scale) s5-0)
)
)
(defun cspace<-transform-yxy! ((dst cspace) (src transform))
"Set one cspace's bone to yxy rotation, translation, and scale"
(let ((s4-0 (-> dst bone transform))
(s5-0 (new 'stack-no-clear 'matrix))
(s3-0 (new 'stack-no-clear 'matrix))
)
(matrix-identity! s4-0)
(matrix-translate! s4-0 (-> src trans))
(matrix-rotate-yxy! s5-0 (-> src rot))
(matrix*! s3-0 s5-0 s4-0)
(scale-matrix! s4-0 (-> src scale) s3-0)
)
)
(defun cspace<-transformq! ((dst cspace) (src transformq))
"Set one cspace's from a transformq"
(matrix<-transformq! (-> dst bone transform) src)
)
(defun cspace<-transformq+trans! ((dst cspace) (src transformq) (extra-trans vector))
"Set one cspace from a transformq and an additional local translation."
(matrix<-transformq+trans! (-> dst bone transform) src extra-trans)
)
(defun cspace<-transformq+world-trans! ((dst cspace) (src transformq) (extra-trans vector))
"Set one cspace from a transformq and an additional world translation."
(matrix<-transformq+world-trans! (-> dst bone transform) src extra-trans)
)
(defun cspace<-transformq+rot-offset! ((dst cspace) (src transformq) (extra-rot vector))
"Set one cspace from a transformq and an additional rotate."
(matrix<-transformq+rot-offset! (-> dst bone transform) src extra-rot)
)
(defun cspace-calc-total-matrix! ((csp cspace) (dst matrix))
"Combine the bone matrix and camera matrix.
This is not actually a useful matrix since it does not include the inverse bind pose, but
is close to the rendering matrices computed by bones.gc"
(matrix*! dst (-> csp bone transform) (-> *math-camera* camera-temp))
)
(defun cspace<-matrix-no-push-joint! ((dst cspace) (jc joint-control))
"Compute animated matrix, using the special 'no-push mode."
(let ((v1-2 (matrix-from-control! (scratchpad-object matrix-stack :offset 64) (-> dst joint) jc 'no-push))
(v0-1 (-> dst bone transform))
)
(let ((a0-4 (-> v1-2 rvec quad))
(a1-2 (-> v1-2 uvec quad))
(a2-1 (-> v1-2 fvec quad))
(v1-3 (-> v1-2 trans quad))
)
(set! (-> v0-1 rvec quad) a0-4)
(set! (-> v0-1 uvec quad) a1-2)
(set! (-> v0-1 fvec quad) a2-1)
(set! (-> v0-1 trans quad) v1-3)
)
v0-1
)
)
(defun cspace<-matrix-joint! ((dst cspace) (src matrix))
"Set the cspace from a matrix."
(let ((v0-0 (-> dst bone transform)))
(let* ((a2-0 src)
(v1-1 (-> a2-0 rvec quad))
(a0-1 (-> a2-0 uvec quad))
(a1-1 (-> a2-0 fvec quad))
(a2-1 (-> a2-0 trans quad))
)
(set! (-> v0-0 rvec quad) v1-1)
(set! (-> v0-0 uvec quad) a0-1)
(set! (-> v0-0 fvec quad) a1-1)
(set! (-> v0-0 trans quad) a2-1)
)
v0-0
)
)
(defun cspace<-parented-matrix-joint! ((dst cspace) (joint-mat matrix))
"Compute the bone matrix of a cspace from combining the transform of the parent bone and the given joint matrix.
This computes world-space bones from a tree of bones (skeleton)"
(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 (-> dst bone transform)))
(let ((v1-1 joint-mat))
(let ((a0-3 (-> dst parent bone transform)))
(.lvf vf10 (&-> v1-1 rvec quad))
(.lvf vf14 (&-> a0-3 rvec quad))
(.lvf vf15 (&-> a0-3 uvec quad))
(.lvf vf16 (&-> a0-3 fvec quad))
(.lvf vf17 (&-> a0-3 trans quad))
)
(.lvf vf11 (&-> v1-1 uvec quad))
(.lvf vf12 (&-> v1-1 fvec quad))
(.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 rvec quad) vf18)
(.svf (&-> v0-0 uvec quad) vf19)
(.svf (&-> v0-0 fvec quad) vf20)
(.svf (&-> v0-0 trans quad) vf21)
v0-0
)
)
)
(defun cspace<-parented-matrix-mirror! ((dst cspace) (joint-mat matrix))
"Mirror the provided matrix (using cspace param1,2 as the normal/tangent dirs) as the joint matrix
This is similar to cspace<-parented-matrix-joint!, but essentially mirrors the joint."
(let ((gp-0
(matrix-mirror! (new 'stack-no-clear 'matrix) (the-as vector (-> dst param1)) (the-as vector (-> dst param2)))
)
)
(cspace<-parented-matrix-joint! dst joint-mat)
(matrix*! (-> dst bone transform) (-> dst bone transform) gp-0)
)
)
(defun cspace<-parented-matrix-joint-flip-z! ((dst cspace) (joint-mat matrix))
"Compute the bone matrix from the parent bone and joint, but flip the z-axis of the joint frame."
(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 (-> dst bone transform)))
(let ((v1-1 joint-mat))
(let ((a0-3 (-> dst parent bone transform)))
(.lvf vf10 (&-> v1-1 rvec quad))
(.lvf vf14 (&-> a0-3 rvec quad))
(.lvf vf15 (&-> a0-3 uvec quad))
(.lvf vf16 (&-> a0-3 fvec quad))
(.lvf vf17 (&-> a0-3 trans quad))
)
(.lvf vf11 (&-> v1-1 uvec quad))
(.lvf vf12 (&-> v1-1 fvec quad))
(.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 rvec quad) vf18)
(.svf (&-> v0-0 uvec quad) vf19)
(.svf (&-> v0-0 fvec quad) vf20)
(.svf (&-> v0-0 trans quad) vf21)
v0-0
)
)
)
(defun cspace<-matrix-joint-flip-z! ((dst cspace) (src matrix))
"Set the bone matrix directly from the joint matrix, flipping z."
(local-vars (v1-2 float))
(rlet ((vf0 :class vf)
(vf30 :class vf)
(vf31 :class vf)
)
(init-vf0-vector)
(let ((v1-1 (-> dst bone transform)))
(.sub.vf vf31 vf0 vf0)
(.lvf vf30 (&-> v1-1 rvec quad))
(.sub.vf vf30 vf31 vf30)
(.svf (&-> v1-1 rvec quad) vf30)
)
(.mov v1-2 vf30)
0
(none)
)
)
(def-mips2c cspace<-parented-transformq-joint! (function cspace transformq none))
(defun cspace<-parented-transformq-joint-flip-z! ((dst cspace) (joint-transformq transformq))
"Unused, but would flip the z-axis of the transformq and do a normal parented joint transform."
(cspace<-parented-transformq-joint! dst joint-transformq)
(cspace<-matrix-joint-flip-z! dst (-> dst bone transform))
0
(none)
)
;; make-joint-jump-tables: not needed
;; calc-animation-from-spr: not needed
;; (def-mips2c calc-animation-from-spr (function joint-anim-frame int none))
(defun create-interpolated-joint-animation-frame ((dst joint-anim-frame) (num-joints int) (jc joint-control))
"Compute the entire joint frame by evaluating the blend tree, decompressing animations, and blending them."
(new-joint-decompressor dst num-joints jc)
; (flatten-joint-control-to-spr jc)
; (make-joint-jump-tables)
; (calc-animation-from-spr dst num-joints)
0
)
(defun create-interpolated2-joint-animation-frame ((dst joint-anim-frame) (num-joints int) (jc joint-control))
"Compute the entire joint frame twice, then blend those two 'sub frames' together.
This uses interp-select bitmask to pick which sub frames are applied to each joint."
(flush-cache 0)
;; if the user has not set any bits, fall back to the normal system.
(if (and (zero? (-> jc interp-select 0)) (zero? (-> jc interp-select 1)))
(return (create-interpolated-joint-animation-frame dst num-joints jc))
)
;; run the second 'sub frame'
(set! (-> jc active-frame-interp) (the-as uint 1))
;(flatten-joint-control-to-spr jc)
;(make-joint-jump-tables)
;(calc-animation-from-spr dst num-joints)
(create-interpolated-joint-animation-frame dst num-joints jc)
;; copy this sub-frame to temporary buffer
;; changed for PC!
(ultimate-memcpy (the-as pointer *gsf-buffer*) (the-as pointer dst) (the-as uint (+ (* 48 num-joints) 128)))
; (dma-send-from-spr-no-flush
; (the-as uint *gsf-buffer*)
; (the-as uint dst)
; (the-as uint (/ (+ (* 48 num-joints) 128) 16))
; #f
; )
;; run the first sub-frame.
(set! (-> jc active-frame-interp) (the-as uint 0))
(create-interpolated-joint-animation-frame dst num-joints jc)
; (flatten-joint-control-to-spr jc)
; (make-joint-jump-tables)
; (calc-animation-from-spr dst num-joints)
;; interpolate the result.
(let ((v1-9 (the-as joint-anim-frame *gsf-buffer*)))
(let ((a0-9 (-> jc interp-select 0)))
(dotimes (a1-5 2)
(when (logtest? a0-9 1)
(let* ((a2-7 (the-as object (-> dst matrices a1-5)))
(t2-0 (the-as (inline-array vector) (-> v1-9 matrices a1-5)))
(a3-3 (-> t2-0 0 quad))
(t0-0 (-> t2-0 1 quad))
(t1-0 (-> t2-0 2 quad))
(t2-1 (-> t2-0 3 quad))
)
(set! (-> (the-as (inline-array vector) a2-7) 0 quad) a3-3)
(set! (-> (the-as (inline-array vector) a2-7) 1 quad) t0-0)
(set! (-> (the-as (inline-array vector) a2-7) 2 quad) t1-0)
(set! (-> (the-as (inline-array vector) a2-7) 3 quad) t2-1)
)
)
(set! a0-9 (shr a0-9 1))
)
(let ((a1-9 (min 62 (+ num-joints -2))))
(dotimes (a2-9 a1-9)
(when (logtest? a0-9 1)
(let* ((a3-9 (-> dst 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-9 (shr a0-9 1))
)
)
)
(let ((a0-13 (min 64 (+ num-joints -64)))
(a1-11 (-> jc interp-select 1))
)
(dotimes (a2-10 a0-13)
(when (logtest? a1-11 1)
(let* ((a3-15 (-> dst 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))
"Get how many bytes of our heap are used by the given anim slot."
(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 heap current)) (the-as uint (the-as pointer (-> v1-2 anim frames fixed))))
)
)
)
(defmethod unload-from-slot ((this art-joint-anim-manager) (arg0 int))
"Remove the given animation from the cache."
(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 heap current) (the-as uint (+ (the-as uint s2-0) s1-0)))))
(if #t
(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-21 s0-0)
(let ((a0-21 (-> this slot (+ arg0 v1-21) 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 heap current) (the pointer (&- (-> this heap current) (the-as uint s1-0))))
)
)
(else
(set! (-> this heap 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 mark-anim-in-use ((this art-joint-anim-manager) (arg0 art-joint-anim))
"Inform the cache this animation is in used, so it is not evicted."
(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))
"Decompress the given animation and store the decompressed data in this cache."
(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 heap top) (the-as uint (-> this heap 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 heap) (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-heap ((this art-joint-anim-manager) (arg0 kheap))
"Remove all animations which have their original compressed data in the given heap."
(let ((s5-0 (-> arg0 base))
(s4-0 (-> arg0 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)