mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 21:27:52 -04:00
dacb704ef6
- `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`
2524 lines
92 KiB
Common Lisp
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)
|