diff --git a/common/log/log.cpp b/common/log/log.cpp index 2620a2c126..aae99a8496 100644 --- a/common/log/log.cpp +++ b/common/log/log.cpp @@ -1,5 +1,6 @@ #include "log.h" +#include #include #include #include @@ -118,6 +119,8 @@ void log_vprintf(const char* format, va_list arg_list) { // We always immediately flush prints because since it has no associated level // it could be anything from a fatal error to a useless debug log. std::lock_guard lock(gLogger.mutex); + va_list arg_list_2; + va_copy(arg_list_2, arg_list); if (gLogger.fp) { // Log to File vfprintf(gLogger.fp, format, arg_list); @@ -125,7 +128,7 @@ void log_vprintf(const char* format, va_list arg_list) { } if (gLogger.stdout_log_level < lg::level::off_unless_die) { - vprintf(format, arg_list); + vprintf(format, arg_list_2); fflush(stdout); fflush(stderr); } @@ -133,8 +136,8 @@ void log_vprintf(const char* format, va_list arg_list) { } } // namespace internal -void printstd(const std::string& format, va_list arg_list) { - internal::log_vprintf(format.c_str(), arg_list); +void printstd(const char* format, va_list arg_list) { + internal::log_vprintf(format, arg_list); } // how many extra log files for a single program should be kept? diff --git a/common/log/log.h b/common/log/log.h index 661e392c6e..a80dc17134 100644 --- a/common/log/log.h +++ b/common/log/log.h @@ -77,7 +77,7 @@ void print(const fmt::text_style& ts, const std::string& format, Args&&... args) } // same as print but uses the C printf instead of fmt -void printstd(const std::string& format, va_list arg_list); +void printstd(const char* format, va_list arg_list); template void trace(const std::string& format, Args&&... args) { diff --git a/decompiler/analysis/mips2c.cpp b/decompiler/analysis/mips2c.cpp index f020f26e3b..86d9f0cdd2 100644 --- a/decompiler/analysis/mips2c.cpp +++ b/decompiler/analysis/mips2c.cpp @@ -228,7 +228,17 @@ struct Mips2C_Output { result += "void link() {\n"; // lookup all symbols for (auto& sym : symbol_cache) { - result += fmt::format(" cache.{} = intern_from_c(\"{}\").c();\n", goal_to_c_name(sym), sym); + switch (version) { + case GameVersion::Jak1: + case GameVersion::Jak2: + result += + fmt::format(" cache.{} = intern_from_c(\"{}\").c();\n", goal_to_c_name(sym), sym); + break; + case GameVersion::Jak3: + result += fmt::format(" cache.{} = intern_from_c(-1, 0, \"{}\").c();\n", + goal_to_c_name(sym), sym); + break; + } } // this adds us to a table for lookup later, and also allocates our trampoline. result += fmt::format(" gLinkedFunctionTable.reg(\"{}\", execute, PUT_STACK_SIZE_HERE);\n", diff --git a/decompiler/config/jak3/all-types.gc b/decompiler/config/jak3/all-types.gc index da85405bdb..20d67cb3e5 100644 --- a/decompiler/config/jak3/all-types.gc +++ b/decompiler/config/jak3/all-types.gc @@ -10481,7 +10481,22 @@ (defenum mem-usage-id :bitfield #f :type uint32 + + (joint 68) + + (joint-anim-compressed-control 70) + (joint-anim-fixed 71) + (joint-anim-frame 72) + + (art-group 74) + (art-mesh-anim 75) + (art-mesh-geo 76) + (art-joint-geo 77) + (art-joint-anim 78) + (texture 83) + + (eye-anim 112) ) (deftype memory-usage-info (structure) @@ -14097,9 +14112,10 @@ (:methods (login (_type_) _type_) ;; 9 (art-method-10 (_type_) _type_) ;; 10 - (get-art-by-name-method (_type_ string type) basic) ;; 11 - (get-art-idx-by-name-method (_type_ string type) int) ;; 12 - (needs-link? (_type_) symbol) ;; 13 + (get-art-by-name-method "Look inside this art for an art with the given name and type. Return #f if not found" (_type_ string type) basic) ;; 11 + (get-art-idx-by-name-method "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." (_type_ string type) int) ;; 12 + (contains-art-for-other-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?" (_type_) symbol) ;; 13 ) ) @@ -14116,7 +14132,7 @@ (deftype art-mesh-anim (art-element) "An unused mesh animation." - () + ((data basic :dynamic)) :flag-assert #xe00000030 ) @@ -14144,21 +14160,22 @@ ) :flag-assert #x1000000020 (:methods - (relocate (_type_ kheap (pointer uint8)) _type_ :replace) - (link-art! (_type_) art-group) + (relocate (_type_ kheap (pointer uint8)) none :replace) ;; 7 + (link-art-to-master (_type_) none) (unknown-1 () none) ) ) (deftype art-mesh-geo (art-element) "Unused art format for a mesh. This might have been for the renderer that came before merc." - () + ((data basic :dynamic :offset-assert 48) + ) :flag-assert #xe00000030 ) (deftype art-joint-geo (art-element) "Collection of joints for an actor." - ((data joint :dynamic :offset 48) + ((data joint :dynamic :offset-assert 48) ) :flag-assert #xe00000030 ) @@ -14200,11 +14217,11 @@ :flag-assert #xe00000430 (:methods (new (symbol type int) _type_) ;; 0 ;; (new (symbol type int) _type_) - (art-joint-anim-manager-method-9 () none) ;; 9 ;; (decompress (_type_ art-joint-anim) art-joint-anim) - (art-joint-anim-manager-method-10 () none) ;; 10 ;; (update-time-stamp (_type_ art-joint-anim) art-joint-anim) - (art-joint-anim-manager-method-11 () none) ;; 11 ;; (unload-from-slot (_type_ int) art-joint-anim) - (art-joint-anim-manager-method-12 () none) ;; 12 ;; (used-bytes-for-slot (_type_ int) int) - (art-joint-anim-manager-method-13 () none) ;; 13 ;; (unload-from-level (_type_ level) none) + (decompress "Decompress the given animation and store the decompressed data in this cache." (_type_ art-joint-anim) art-joint-anim) ;; 9 + (mark-anim-in-use "Inform the cache this animation is in used, so it is not evicted." (_type_ art-joint-anim) art-joint-anim) ;; 10 + (unload-from-slot "Remove the given animation from the cache." (_type_ int) art-joint-anim) ;; 11 + (used-bytes-for-slot "Get how many bytes of our heap are used by the given anim slot." (_type_ int) int) ;; 12 + (unload-from-heap "Remove all animations which have their original compressed data in the given heap." (_type_ kheap) none) ;; 13 ) ) @@ -16928,7 +16945,7 @@ ;(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read. (top-anim top-anim-joint-control :offset-assert 56) ;; guessed by decompiler (override (array float) :offset-assert 60) ;; guessed by decompiler - (channel joint-control-channel :dynamic :offset-assert 64) ;; guessed by decompiler + (channel joint-control-channel :dynamic :inline :offset-assert 64) ;; guessed by decompiler ;(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read. ) :method-count-assert 13 @@ -16936,10 +16953,10 @@ :flag-assert #xd00000040 ;; field joint-control-status is likely a value type. (:methods - (new (symbol type) _type_) ;; 0 ;; (new (symbol type int) _type_) + (new (symbol type int) _type_) ;; 0 (joint-control-method-9 () none) ;; 9 ;; (current-cycle-distance (_type_) float) (joint-control-method-10 () none) ;; 10 ;; (update-anim-data (_type_) none) - (joint-control-method-11 () none) ;; 11 ;; (debug-print-channels (_type_ symbol) int) + (debug-print-channels "Print the list of joint animations playing in the flattened blend tree." (_type_ symbol) int) ;; 11 (joint-control-method-12 () none) ;; 12 ) ) @@ -27542,16 +27559,16 @@ ;; collide-func ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; (define-extern raw-ray-sphere-intersect function) -;; (define-extern ray-sphere-intersect function) ;; (function vector vector vector float float) -;; (define-extern ray-circle-intersect function) ;; (function vector vector vector float float) -;; (define-extern ray-cylinder-intersect function) ;; (function vector vector vector vector float float vector float) -;; (define-extern ray-plane-intersect function) ;; (function vector vector vector vector vector vector vector float) -;; (define-extern ray-triangle-intersect function) -;; (define-extern collide-do-primitives function) -;; (define-extern moving-sphere-triangle-intersect function) ;; (function vector vector float collide-cache-tri vector vector float) -;; (define-extern moving-sphere-sphere-intersect function) -;; (define-extern moving-sphere-moving-sphere-intersect function) +(define-extern raw-ray-sphere-intersect function) +(define-extern ray-sphere-intersect (function vector vector vector float float)) +(define-extern ray-circle-intersect (function vector vector vector float float)) +(define-extern ray-cylinder-intersect (function vector vector vector vector float float vector float)) +(define-extern ray-plane-intersect (function vector vector vector vector vector vector vector float)) +; (define-extern ray-triangle-intersect function) +; (define-extern collide-do-primitives function) +(define-extern moving-sphere-triangle-intersect (function vector vector float collide-cache-tri vector vector float)) +; (define-extern moving-sphere-sphere-intersect function) +; (define-extern moving-sphere-moving-sphere-intersect function) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; joint ;; @@ -27576,49 +27593,75 @@ ) |# -;; (define-extern joint-anim-login function) ;; (function joint-anim-drawable joint-anim-drawable) -;; (define-extern joint-anim-inspect-elt function) ;; (function joint-anim float joint-anim) -;; (define-extern jacc-mem-usage function) ;; (function joint-anim-compressed-control memory-usage-block int joint-anim-compressed-control) -;; (define-extern joint-control-cleanup function) -;; (define-extern joint-control-channel-eval function) ;; (function joint-control-channel float :behavior process) -;; (define-extern joint-control-channel-eval! function) ;; (function joint-control-channel (function joint-control-channel float float float float) float :behavior process) -;; (define-extern joint-control-channel-group-eval! function) ;; (function joint-control-channel art-joint-anim (function joint-control-channel float float float float) int) -;; (define-extern joint-control-channel-group! function) ;; (function joint-control-channel art-joint-anim (function joint-control-channel float float float float) int) -;; (define-extern joint-control-copy! function) ;; (function joint-control joint-control joint-control) -;; (define-extern joint-control-remap! function) ;; (function joint-control art-group art-group pair int string symbol) -;; (define-extern flatten-joint-control-to-spr function) ;; (function joint-control int) -;; (define-extern matrix-from-joint-anim-frame function) ;; (function joint-anim-compressed-control int int matrix) -;; (define-extern matrix-from-control-channel! function) ;; (function matrix joint joint-control-channel matrix) -;; (define-extern matrix-from-control-pair! function) ;; (function matrix matrix joint int matrix) -;; (define-extern matrix-from-control! function) ;; (function matrix-stack joint joint-control symbol matrix) -;; (define-extern cspace<-cspace! function) ;; (function cspace cspace matrix) -;; (define-extern cspace<-cspace-normalized! function) ;; (function cspace cspace matrix) -;; (define-extern cspace<-parent-joint! function) ;; (function cspace (pointer process-drawable) int matrix) -;; (define-extern cspace<-rot-yxy! function) ;; (function cspace transform matrix) -;; (define-extern cspace<-transform-yxy! function) ;; (function cspace transform matrix) -(define-extern cspace<-transformq! (function cspace transformq matrix)) -;; (define-extern cspace<-transformq+trans! function) ;; (function cspace transformq vector matrix) -;; (define-extern cspace<-transformq+world-trans! function) ;; (function cspace transformq vector matrix) -;; (define-extern cspace<-transformq+rot-offset! function) ;; (function cspace transformq vector matrix) -;; (define-extern cspace-calc-total-matrix! function) ;; (function cspace matrix matrix) -;; (define-extern cspace<-matrix-no-push-joint! function) ;; (function cspace joint-control matrix) -;; (define-extern cspace<-matrix-joint! function) ;; (function cspace matrix matrix) -;; (define-extern cspace<-parented-matrix-joint! function) ;; (function cspace matrix matrix) -;; (define-extern cspace<-parented-matrix-mirror! function) ;; (function cspace matrix matrix) -;; (define-extern cspace<-parented-matrix-joint-flip-z! function) ;; (function cspace matrix matrix) -;; (define-extern cspace<-matrix-joint-flip-z! function) ;; (function cspace matrix none) -(define-extern cspace<-parented-transformq-joint! (function cspace transformq none)) -;; (define-extern cspace<-parented-transformq-joint-flip-z! function) ;; (function cspace transformq none) +(define-extern joint-anim-login "Login a joint-anim-drawable by calling login on all drawables" (function joint-anim-drawable joint-anim-drawable)) +(define-extern joint-anim-inspect-elt "Inspect an uncompressed anim (unused)" (function joint-anim float joint-anim)) +(define-extern jacc-mem-usage "Compute memory usage stats for a compressed joint anim." (function joint-anim-compressed-control memory-usage-block int joint-anim-compressed-control)) +(define-extern joint-control-cleanup "Remove all animations that are stored on the given heap and return those slots to a safe default." (function joint-control kheap art-joint-anim none)) +(define-extern joint-control-channel-eval "Run the num-func to produce the current frame for this channel." (function joint-control-channel float :behavior process)) +(define-extern joint-control-channel-eval! "Update the num-func for this channel and evaluate it." (function joint-control-channel (function joint-control-channel float float float float) float :behavior process)) +(define-extern joint-control-channel-group-eval! (function joint-control-channel art-joint-anim (function joint-control-channel float float float float) int)) +(define-extern joint-control-channel-group! (function joint-control-channel art-joint-anim (function joint-control-channel float float float float) int)) +(define-extern joint-control-copy! "Copy all settings and channels from one joint-control to another." (function joint-control joint-control joint-control)) +(define-extern joint-control-remap! + "Map animation from parent to child using the given animation mapping. + This is used to animate daxter based on the animation of jak." + (function joint-control art-group art-group pair int string symbol)) +(define-extern flatten-joint-control-to-spr "Walk the blend tree and compute interpolation weights, prepare animation upload info." (function joint-control int)) +(define-extern matrix-from-joint-anim-frame "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."(function joint-anim-compressed-control int int matrix)) +(define-extern matrix-from-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." (function matrix joint joint-control-channel matrix)) +(define-extern matrix-from-control-pair! "Modify the matrix to add in a blended animation for the given channel." + (function matrix joint-control-channel joint int matrix)) +(define-extern matrix-from-control! + "Compute a matrix for a given joint (must be 0 or 1) given the entire joint-control. + This walks the blend tree." + (function matrix-stack joint joint-control symbol matrix)) +(define-extern cspace<-cspace! "Set one cspace's bone from another" (function cspace cspace matrix)) +(define-extern cspace<-cspace-normalized! "Set one cspace's bone from another, and normalize the rows of the matrix." (function cspace cspace matrix)) +(define-extern cspace<-parent-joint! "Set one cspace's bone to another from the given process-drawable" (function cspace (pointer process-drawable) int matrix)) +(define-extern cspace<-rot-yxy! "Set one cspace's bone to a yxy rotation and scale." (function cspace transform matrix)) +(define-extern cspace<-transform-yxy! "Set one cspace's bone to yxy rotation, translation, and scale" (function cspace transform matrix)) +(define-extern cspace<-transformq! "Set one cspace's from a transformq" (function cspace transformq matrix)) +(define-extern cspace<-transformq+trans! "Set one cspace from a transformq and an additional local translation." (function cspace transformq vector matrix)) +(define-extern cspace<-transformq+world-trans! "Set one cspace from a transformq and an additional world translation." (function cspace transformq vector matrix)) +(define-extern cspace<-transformq+rot-offset! "Set one cspace from a transformq and an additional rotate." (function cspace transformq vector matrix)) +(define-extern cspace-calc-total-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" + (function cspace matrix matrix)) +(define-extern cspace<-matrix-no-push-joint! "Compute animated matrix, using the special 'no-push mode." (function cspace joint-control matrix)) +(define-extern cspace<-matrix-joint! "Set the cspace from a matrix." (function cspace matrix matrix)) +(define-extern cspace<-parented-matrix-joint! + "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)" + (function cspace matrix matrix)) +(define-extern cspace<-parented-matrix-mirror! + "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." + (function cspace matrix matrix)) +(define-extern cspace<-parented-matrix-joint-flip-z! + "Compute the bone matrix from the parent bone and joint, but flip the z-axis of the joint frame." + (function cspace matrix matrix)) +(define-extern cspace<-matrix-joint-flip-z! + "Set the bone matrix directly from the joint matrix, flipping z." + (function cspace matrix none)) +(define-extern cspace<-parented-transformq-joint! + "Main function for doing skeletal animation from decompressed transformq's. + Sets the cspace bone to the parent bone, plus the transformq." + (function cspace transformq none)) +(define-extern cspace<-parented-transformq-joint-flip-z! "Unused, but would flip the z-axis of the transformq and do a normal parented joint transform." (function cspace transformq none)) ;; (define-extern clear-frame-accumulator function) ;; (define-extern normalize-frame-quaternions function) ;; (define-extern decompress-fixed-data-to-accumulator function) ;; function ;; (define-extern decompress-frame-data-to-accumulator function) ;; function ;; (define-extern decompress-frame-data-pair-to-accumulator function) ;; function -;; (define-extern make-joint-jump-tables function) ;; (function int) -;; (define-extern calc-animation-from-spr function) ;; (function joint-anim-frame int none) -;; (define-extern create-interpolated-joint-animation-frame function) ;; (function joint-anim-frame int joint-control int) -;; (define-extern create-interpolated2-joint-animation-frame function) ;; (function joint-anim-frame int joint-control int) -;; (define-extern *anim-manager* object) ;; art-joint-anim-manager +(define-extern make-joint-jump-tables (function int)) +(define-extern calc-animation-from-spr (function joint-anim-frame int none)) +(define-extern create-interpolated-joint-animation-frame (function joint-anim-frame int joint-control int)) +(define-extern create-interpolated2-joint-animation-frame (function joint-anim-frame int joint-control int)) +(define-extern *anim-manager* art-joint-anim-manager) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; joint-mod ;; @@ -28748,7 +28791,7 @@ ;; (define-extern unpack-comp-rle function) ;; (function (pointer int8) (pointer int8) (pointer int8)) ;; (define-extern unpack-comp-huf function) ;; (function (pointer uint8) (pointer uint8) uint huf-dictionary-node none) -;; (define-extern unpack-comp-lzo function) ;; (function (pointer uint8) (pointer uint8) none) +(define-extern unpack-comp-lzo (function (pointer uint8) (pointer uint8) none)) ;; (define-extern pack-comp-rle function) ;; (function (pointer uint8) (pointer uint8) int int (pointer uint8)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -35730,7 +35773,7 @@ ;; memory-usage-block is already defined! -;; (define-extern mem-size function) ;; (function basic symbol int int) +(define-extern mem-size (function basic symbol int int)) ;; (define-extern *max-dma* object) ;; int ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/decompiler/config/jak3/ntsc_v1/type_casts.jsonc b/decompiler/config/jak3/ntsc_v1/type_casts.jsonc index 2ce8db7be5..282ae2d240 100644 --- a/decompiler/config/jak3/ntsc_v1/type_casts.jsonc +++ b/decompiler/config/jak3/ntsc_v1/type_casts.jsonc @@ -322,6 +322,9 @@ [15, "gp", "collide-shape-moving"], [35, "gp", "collide-shape-moving"] ], + "joint-mod-rotate-world-callback": [ + [[0, 24], "s3", "joint-mod-rotate-world"] + ], "joint-mod-set-local-callback": [[[1, 24], "v1", "joint-mod-set-local"]], "joint-mod-add-local-callback": [[[1, 37], "s4", "joint-mod-add-local"]], "joint-mod-set-world-callback": [[[1, 4], "v1", "joint-mod-set-local"]], @@ -423,6 +426,7 @@ ], "ear-trans": [[32, "s5", "process-focusable"]], "loader-test-command": [[[5, 10], "v1", "sound-rpc-test-cmd"]], + "(method 11 connection)": [[5, "a1", "pointer"]], "update-light-hash": [ [[234, 239], "a1", "light-hash-bucket"], [[207, 211], "a0", "light-hash-bucket"] @@ -524,5 +528,61 @@ "merc-vu1-init-buffer": [[[90, 92], "v1", "dma-packet"]], "texture-usage-init": [[27, "a1", "vector"]], "(method 9 art)": [[9, "v1", "pointer"]], - "(code pov-camera-start-playing pov-camera)": [[24, "v0", "joint"]] + "(code pov-camera-start-playing pov-camera)": [[24, "v0", "joint"]], + "(method 9 art)": [[9, "v1", "pointer"]], + "(method 9 art-mesh-geo)": [ + [20, "s4", "(pointer int16)"], + [[14, 19], "a0", "drawable"], + [10, "v1", "(pointer art)"], + [14, "v1", "(pointer art)"] + ], + "(method 9 art-joint-anim)": [[9, "v1", "pointer"]], + "joint-control-copy!": [ + [8, "a0", "uint"], + [8, "v1", "uint"] + ], + "joint-control-remap!": [ + [127, "t9", "(function joint-control joint-control-channel int object)"], + [181, "t9", "(function joint-control joint-control-channel int object)"], + ["_stack_", 60, "basic"] + ], + "flatten-joint-control-to-spr": [ + [[201, 203], "a1", "terrain-context"], + [[131, 133], "a0", "terrain-context"], + [[182, 184], "a1", "terrain-context"], + [[164, 166], "a0", "terrain-context"], + [195, "v1", "terrain-context"], + [65, "a3", "(pointer float)"], + [67, "a3", "(pointer float)"], + [[18, 47], "a2", "(inline-array vector)"], + [47, "a2", "pointer"], + [[48, 118], "a2", "(inline-array vector)"], + [118, "a2", "pointer"], + [24, "a3", "(pointer float)"], + [17, "a2", "int"] + ], + "(method 12 art-joint-anim-manager)": [ + [15, "a0", "pointer"], + [15, "v1", "pointer"], + [21, "a0", "pointer"], + [21, "v1", "pointer"] + ], + "(method 11 art-joint-anim-manager)": [ + [54, "v1", "uint"], + [54, "s2", "uint"], + [60, "s2", "uint"], + [66, "s2", "uint"], + [72, "s2", "uint"], + [88, "a1", "uint"], + [95, "a2", "uint"] + ], + "(method 2 art-joint-anim-manager-slot)": [ + [21, "s2", "uint"], + [21, "v1", "uint"] + ], + "create-interpolated2-joint-animation-frame": [ + [[48, 125], "v1", "joint-anim-frame"], + [[62, 67], "t2", "(inline-array vector)"], + [[67, 71], "a2", "(inline-array vector)"] + ] } diff --git a/decompiler/config/jak3/ntsc_v1/var_names.jsonc b/decompiler/config/jak3/ntsc_v1/var_names.jsonc index ada60d7ed7..4b3c0da9af 100644 --- a/decompiler/config/jak3/ntsc_v1/var_names.jsonc +++ b/decompiler/config/jak3/ntsc_v1/var_names.jsonc @@ -1174,6 +1174,260 @@ "vars": { "v0-0": ["this", "align-control"] } + }, +"flatten-joint-control-to-spr": { + "args": ["jc"], + "vars": { + "s5-0": "chan-count", + "f0-0": "one", + "v1-2": "chan-float-offset", + "a2-0": ["chan-vector-ptr", "(inline-array vector)"], + "a0-2": "interp2-selected-idx", + "a1-0": "chan-idx", + "a3-2": "chan", + "a3-3": ["flt1", "(pointer float)"], + "f1-0": "interp2-selected-weight1", + "a2-1": ["prev-chan-ptr", "(inline-array vector)"], + "f2-2": "interp2-selected-weight2", + "f1-2": "one-minus-interp2", + "a2-2": ["chans-to-stack", "(inline-array vector)"], + "s4-0": "upload-count", + "s3-0": "upload-chan-idx", + "v1-11": "upload-chan", + "s2-0": "anim", + "f0-2": "frame-num", + "s1-0": "int-frame-num", + "f30-0": "frame-frac", + "s0-0": "last-frame", + "v1-20": "upload" + } + }, + "matrix-from-joint-anim-frame": { + "args": ["jacc", "joint-idx", "frame-idx"], + "vars": { + "v1-1": "fixed-matrix", + "v0-0": "frame-matrix" + } + }, + "matrix-from-control-channel!": { + "args": ["dest-mat", "requested-joint", "chan"], + "vars": { + "s4-0": "jacc", + "s5-0": "joint-num", + "f30-0": "frame-num", + "a2-3": "mat", + "s3-1": "first-mat", + "a2-7": "second-mat", + "f0-9": "mat-blend" + } + }, + "joint-anim-login": { + "args": [ + "jad" + ] + }, + "joint-anim-inspect-elt": { + "args": [ + "ja", + "frame" + ] + }, + "jacc-mem-usage": { + "args": [ + "jacc", + "mem-block", + "flags" + ] + }, + "joint-control-cleanup": { + "args": [ + "jc", + "heap", + "ja" + ] + }, + "joint-control-channel-eval": { + "args": [ + "jcc" + ] + }, + "joint-control-channel-eval!": { + "args": [ + "jcc", + "num-func" + ] + }, + "joint-control-channel-group-eval!": { + "args": [ + "jcc", + "ja", + "num-func" + ] + }, + "joint-control-channel-group!": { + // "args": [ + // "jcc", + // "ja", + // "num-func" + // ] + }, + "joint-control-copy!": { + "args": [ + "dst", + "src" + ] + }, + "joint-control-remap!": { + "args": [ + "jc", + "dst-art-group", + "parent-art-group", + "remap-list", + "seed", + "prefix" + ] + }, + "matrix-from-control-pair!": { + "args": [ + "matrix-to-modify", + "jcc", + "jnt", + "active-frame-interp" + ] + }, + "matrix-from-control!": { + "args": [ + "mat-stack", + "jnt", + "jc", + "mode" + ] + }, + "cspace<-cspace!": { + "args": [ + "dst", + "src" + ] + }, + "cspace<-cspace-normalized!": { + "args": [ + "dst", + "src" + ] + }, + "cspace<-parent-joint!": { + "args": [ + "dst", + "proc", + "parent-idx" + ] + }, + "cspace<-rot-yxy!": { + "args": [ + "dst", + "src" + ] + }, + "cspace<-transform-yxy!": { + "args": [ + "dst", + "src" + ] + }, + "cspace<-transformq!": { + "args": [ + "dst", + "src" + ] + }, + "cspace<-transformq+trans!": { + "args": [ + "dst", + "src", + "extra-trans" + ] + }, + "cspace<-transformq+world-trans!": { + "args": [ + "dst", + "src", + "extra-trans" + ] + }, + "cspace<-transformq+rot-offset!": { + "args": [ + "dst", + "src", + "extra-rot" + ] + }, + "cspace-calc-total-matrix!": { + "args": [ + "csp", + "dst" + ] + }, + "cspace<-matrix-no-push-joint!": { + "args": [ + "dst", + "jc" + ] + }, + "cspace<-matrix-joint!": { + "args": [ + "dst", + "src" + ] + }, + "cspace<-parented-matrix-joint!": { + "args": [ + "dst", + "joint-mat" + ] + }, + "cspace<-parented-matrix-mirror!": { + "args": [ + "dst", + "joint-mat" + ] + }, + "cspace<-parented-matrix-joint-flip-z!": { + "args": [ + "dst", + "joint-mat" + ] + }, + "cspace<-matrix-joint-flip-z!": { + "args": [ + "dst", + "src" + ] + }, + "cspace<-parented-transformq-joint!": { + "args": [ + "dst", + "joint-transformq" + ] + }, + "cspace<-parented-transformq-joint-flip-z!": { + "args": [ + "dst", + "joint-transformq" + ] + }, + "create-interpolated-joint-animation-frame": { + "args": [ + "dst", + "num-joints", + "jc" + ] + }, + "create-interpolated2-joint-animation-frame": { + "args": [ + "dst", + "num-joints", + "jc" + ] }, "(method 37 cloth-system)": { "args": ["this", "command"], diff --git a/decompiler/types2/ForwardProp.cpp b/decompiler/types2/ForwardProp.cpp index d5f5feced3..66006206e8 100644 --- a/decompiler/types2/ForwardProp.cpp +++ b/decompiler/types2/ForwardProp.cpp @@ -1961,7 +1961,19 @@ bool load_var_op_determine_type(types2::Type& type_out, // normal virtual method access. // first check special cases if (type_name == "art" || type_name == "art-group") { - if (method_id == 10) { + int art_get_by_name_method_id = -1; + switch (dts.version()) { + case GameVersion::Jak1: + case GameVersion::Jak2: + art_get_by_name_method_id = 10; + break; + case GameVersion::Jak3: + art_get_by_name_method_id = 11; + break; + default: + ASSERT_NOT_REACHED(); + } + if (method_id == art_get_by_name_method_id) { type_out.type = TP_Type::make_get_art_by_name(method_type, TypeSpec(type_name), method_id); return true; diff --git a/docs/progress-notes/joint-decompressor.md b/docs/progress-notes/joint-decompressor.md new file mode 100644 index 0000000000..29d5ac5598 --- /dev/null +++ b/docs/progress-notes/joint-decompressor.md @@ -0,0 +1,1684 @@ +This is an explanation of reverse engineering and porting the Jak joint decompressor from PS2 assembly to higher-level OpenGOAL code. It's the same from all three games. I made this document as an example of how to approach this type of reverse engineering. + +# What is `joint.gc`? + +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. + +The focus of this documentation is the function that computes joint transforms. + +There are three: + +1. `create-interpolated-joint-animation-frame`, which is the most standard one. It takes a `joint-control`, a number of joints (since low lod versions might not need them all), and produces a `joint-anim-frame` - a list of joint transforms. +2. `create-interpolated2-joint-animation-frame`, which is the same, but uses the "interp2" system described later. +3. `cspace<-matrix-no-push-joint!` which computes a single joint transform. The joint must be one of the first two, and it uses a special `no-push` mode. More on this later. + +Reading the top of `joint.gc` has a lot more details, if you are curious about the details of the blending, etc. That was written before touching the actually decompressor assembly. Figuring all this out first can be really helpful. + +# Background information + +The end result of this routine is to compute a `joint-anim-frame`: +```lisp +(deftype joint-anim-frame (structure) + ((matrices matrix 2 :inline) + (data transformq :inline :dynamic) + ) + (:methods + (new (symbol type int) _type_) + ) + ) +``` +which is all the joint transforms for a interpolated frame. Note that there is interpolation in both time (in between frames) and between different animations (blending). + +This is the code that is used to generate a `joint-anim-frame`: +```lisp +(defun create-interpolated-joint-animation-frame ((dst joint-anim-frame) (num-joints int) (jc joint-control)) + (flatten-joint-control-to-spr jc) + (make-joint-jump-tables) + (calc-animation-from-spr dst num-joints) + 0 + ) +``` + +# Flattening the Joint Control + +The `flatten-joint-control-to-spr` function is written in plain GOAL, so I've decompiled/annotated it here. +The first part of the function is iterating through `joint-control-channel`s, and computing blend weights from a blend tree. This computation acts like a stack machine. There is a `push` operation to push a new stack frame, with all channels zero except for the specified animation. There is a `stack` operation which takes the two most top things on the stack, then adds them together with the given weights (effectively `pop`ing back 1 stack frame in the end). Finally, there is a `blend` operation, which modifies the top of the animation stack to be a blend of multiple animations. I imagine this can stay almost the same in the new decompressor, other than scratchpad use. + +The second part builds a list of "uploads". This is a list of data that should be uploaded to the scratchpad. Each animation has some "fixed" data, which is a chunk of common data needed to produce any frame. + +There is also "frame" data, one for each frame in the animation. If we need to interpolate between two frames, we upload 2 frames worth of data. Otherwise, if we want an exact frame, we just upload the one. + +```lisp + +(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 + ) + ) + +``` + + +# Make Joint Jump Tables + +This function is building a number of jump tables like this: +``` + lw v1, decompress-fixed-data-to-accumulator(s7) ;; get address of function + addiu a0, r0, 301 ;; offset into instruction (in instructions) + dsll a0, a0, 2 ;; convert offset to bytes + daddu v1, v1, a0 ;; get pointer to inside of function + lui a0, 28672 ;; store into the jump table (in the scratchpad) + sw v1, 1632(a0) +``` +This is likely some strange macro, as I think the GOAL compiler would normally have constant propagated the `addiu`/`dsll` pair. + +We can see the layout of the scratchpad here: +```lisp +(deftype joint-work (structure) + ;; used in cspace<-matrix-no-push-joint!, which is not asm + ((temp-mtx matrix :inline :offset-assert 0) + (joint-stack matrix-stack :inline :offset-assert 64) + + ;; the jump tables. seems like there's 3 different modes: fix (fixed), frm (frame), pair (2x frame) + (fix-jmp-table (function none) 16 :offset-assert 1616) ;; guessed by decompiler + (frm-jmp-table (function none) 16 :offset-assert 1680) ;; guessed by decompiler + (pair-jmp-table (function none) 16 :offset-assert 1744) ;; guessed by decompiler + + ;; upload records generated in the `flatten-joint-control-to-spr` function above + (uploads channel-upload-info 24 :inline :offset-assert 1808) ;; guessed by decompiler + (num-uploads int32 :offset-assert 2384) + + ;; "accumulators", which I believe will eventually contain the full transforms + (mtx-acc matrix 2 :inline :offset-assert 2400) ;; guessed by decompiler + (tq-acc transformq 100 :inline :offset-assert 2528) ;; guessed by decompiler + + ;; ?? likely destination for uploads + (jacp-hdr joint-anim-compressed-hdr :inline :offset-assert 7328) + (fixed-data joint-anim-compressed-fixed :inline :offset-assert 7392) + (frame-data joint-anim-compressed-frame 2 :inline :offset-assert 9600) ;; guessed by decompiler + + ;; used during the flatten-joint-control-to-spr function + (flatten-array float 576 :offset 2400) ;; guessed by decompiler + (flattened vector 24 :inline :offset 2400) ;; guessed by decompiler + ) +``` + +and the upload type: +``` +(deftype channel-upload-info (structure) + "Information about an upload of animation data to a single joint channel." + ((fixed joint-anim-compressed-fixed :offset-assert 0) + (fixed-qwc int32 :offset-assert 4) + (frame joint-anim-compressed-frame :offset-assert 8) + (frame-qwc int32 :offset-assert 12) + (amount float :offset-assert 16) + (interp float :offset-assert 20) + ) +``` + +I did not learn much from staring at this yet, so I am going to move on to `calc-animation-from-spr`, and revisit once I find the actual jumps. + +# `calc-animation-from-spr` + + +This function is entirely assembly. I approach these by adding a comment to each line: +```python +# a0 = dst-joint-anim-frame +# a1 = num-joints + or v1, a1, r0 # v1 = num-joint + + # backup registers + daddiu sp, sp, -192 + sq s0, 0(sp) + sq s1, 16(sp) + sq s2, 32(sp) + sq s3, 48(sp) + sq s4, 64(sp) + sq s5, 80(sp) + sq s6, 96(sp) + sq t8, 112(sp) + sq t9, 128(sp) + sq gp, 144(sp) + sq fp, 160(sp) + sq ra, 176(sp) + + daddiu sp, sp, -16 # allocate another 16 bytes on the stack + + qmtc2.i vf15, r0 # vf15 = 0 + sw a1, 0(sp) # 0(sp) = num-joints + lui v1, 28672 + lw s1, 2384(v1) # s1 = num-uploads + daddiu t7, v1, 1808 # t7 = uploads + lui s0, 4096 # generating some constant here, likely DMA register + daddiu t1, v1, 7328 # t1 = jacp-hdr + beq s1, r0, L53 # early return if we don't have any uploads + ori s0, s0, 54272 # more DMA register constant stuff + +B1: + lw t2, 0(t7) # t2 = fixed + addiu t3, r0, 7392 # t3 = fixed-data + lw t4, 4(t7) # t4 = fixed-qwc + addiu v1, r0, 256 # DMA constant? + sw t2, 16(s0) # DMA setup + vaddw.xyzw vf14, vf15, vf0 # vf14 = 1, 1, 1, 1 + sw t3, 128(s0) # DMA setup + sll r0, r0, 0 # + sw t4, 32(s0) # DMA setup QWC + sync.l + sw v1, 0(s0) # DMA GO!! + sync.l + lw t9, clear-frame-accumulator(s7) # t9 = this function + vadd.yz vf14, vf14, vf14 # vf14 = [1, 2, 2, 1] + lw s2, 0(sp) # s2 = num-joint + sll r0, r0, 0 + jalr ra, t9 # call! + vadd.yz vf14, vf14, vf14 # vf14 = [1, 4, 4, 1] + +B2: +L49: + lw v1, 0(s0) # wait on DMA + sll r0, r0, 0 + andi v1, v1, 256 + sll r0, r0, 0 + sll r0, r0, 0 + sll r0, r0, 0 + bne v1, r0, L49 + sll r0, r0, 0 + +B3: + lw t2, 8(t7) # t2 = frame + addiu t3, r0, 9600 # t3 = frame-data + lw t4, 12(t7) # t4 = frame-qwc + addiu v1, r0, 256 # dma constant + sw t2, 16(s0) # dma (src addr) + sll r0, r0, 0 + sw t3, 128(s0) # dma (dst addr) + sll r0, r0, 0 + sw t4, 32(s0) # dma (qwc) + sync.l + sw v1, 0(s0) # dma (start) + sync.l + lw a2, 16(t7) + lui a1, 28672 + lw t9, decompress-fixed-data-to-accumulator(s7) + daddiu a1, a1, 7392 # a1 = fixed-data + jalr ra, t9 + daddiu s1, s1, -1 # decrement upload counter + +B4: +L50: + lw v1, 0(s0) # wait on frame data dma + sll r0, r0, 0 + andi v1, v1, 256 + sll r0, r0, 0 + sll r0, r0, 0 + sll r0, r0, 0 + bne v1, r0, L50 + sll r0, r0, 0 + +B5: + beq s1, r0, L51 # jump over next dma start if there's nothing next + sll r0, r0, 0 + +B6: + lw t2, 24(t7) # dma the next upload + addiu t3, r0, 7392 + lw t4, 28(t7) + addiu v1, r0, 256 + sw t2, 16(s0) + sll r0, r0, 0 + sw t3, 128(s0) + sll r0, r0, 0 + sw t4, 32(s0) + sync.l + sw v1, 0(s0) + sync.l +B7: +L51: + lw t0, 20(t7) # t0 = interp (between consecutive frames) + lui a1, 28672 + lw a2, 16(t7) # a2 = amount (weight) + daddiu a1, a1, 9600 # a1 = frame-data + beq t0, r0, L52 # if interp is 0, take the non-pair case, just one frame + sll r0, r0, 0 + +B8: + lw a3, 12(t7) # a3 = frame-qwc + sll r0, r0, 0 + lw t9, decompress-frame-data-pair-to-accumulator(s7) + sll r0, r0, 0 + jalr ra, t9 + sll a3, a3, 3 + + bne s1, r0, L49 + daddiu t7, t7, 24 + +B9: + lw t9, normalize-frame-quaternions(s7) + sll r0, r0, 0 + lw s2, 0(sp) + sll r0, r0, 0 + jalr ra, t9 + sll r0, r0, 0 + + daddiu sp, sp, 16 + sll r0, r0, 0 + lq s0, 0(sp) + lq s1, 16(sp) + lq s2, 32(sp) + lq s3, 48(sp) + lq s4, 64(sp) + lq s5, 80(sp) + lq s6, 96(sp) + lq t8, 112(sp) + lq t9, 128(sp) + lq gp, 144(sp) + lq ra, 176(sp) + lq fp, 160(sp) + jr ra + daddiu sp, sp, 192 + +B10: +L52: + lw t9, decompress-frame-data-to-accumulator(s7) + sll r0, r0, 0 + jalr ra, t9 + sll r0, r0, 0 + + bne s1, r0, L49 + daddiu t7, t7, 24 + +B11: + lw t9, normalize-frame-quaternions(s7) + sll r0, r0, 0 + lw s2, 0(sp) + sll r0, r0, 0 + jalr ra, t9 + sll r0, r0, 0 + +B12: +L53: + daddiu sp, sp, 16 + sll r0, r0, 0 + lq s0, 0(sp) + lq s1, 16(sp) + lq s2, 32(sp) + lq s3, 48(sp) + lq s4, 64(sp) + lq s5, 80(sp) + lq s6, 96(sp) + lq t8, 112(sp) + lq t9, 128(sp) + lq gp, 144(sp) + lq ra, 176(sp) + lq fp, 160(sp) + jr ra + daddiu sp, sp, 192 + + jr ra + daddu sp, sp, r0 +``` + +The basic operation is: +- call `clear-frame-accumulator`, to zero out the tq and matrix accumulators +- for each upload + - DMA the fixed data, then `decompress-fixed-data-to-accumulator` + - DMA the fixed data + - Call `decompress-frame-data-pair-to-accumulator` or `decompress-frame-data-to-accumulator`. Use the `pair` one if interp is nonzero, meaning we need to combine two consecutive frames + - Call `normalize-frame-quaternions` + + +# `clear-frame-accumulator` +Just sets the accumulator to 0. The first two joints are matrices and zeroed entirely. The remaining ones are `transformq` (position, quaternion, scale). The pos/quat are zeroed, but not the scale. + +# `normalize-frame-quaternion` +This function simply sets `trans.w = 1`, `scale.w = 1`, and normalizes the quaternions. +The quaternions may be slightly off due to the blending or decompression. + +```python +# s2 = num-joints +L91: + daddiu sp, sp, -16 +B0: + daddiu s2, s2, -2 # subtract off first two matrix joints + sw a0, 0(sp) + daddiu a0, a0, 128 # seek past matrices in the accumulator +B1: +L92: # per transformq loop + lqc2 vf4, 16(a0) # vf4 = quat + lqc2 vf1, 0(a0) # vf1 = trans + lqc2 vf7, 32(a0) # vf7 = scale + vmul.xyzw vf10, vf4, vf4 # vf10 = x^2, y^2, z^2, w^2 + vmove.w vf1, vf0 # vf1.w = 1 + vmove.w vf7, vf0 # vf7.w = 1 + vmulaw.xyzw acc, vf0, vf10 # sum up x^2, y^2, z^2, w^2 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + sqc2 vf1, 0(a0) # store fixed trans + sqc2 vf7, 32(a0) # store fixed scale + daddiu a0, a0, 48 # advance tq ptr + vrsqrt Q, vf0.w, vf10.w # get length + vwaitq + vmulq.xyzw vf4, vf4, Q # multiply by inverse length to normalize + daddiu s2, s2, -1 # dec count + bne s2, r0, L92 + sqc2 vf4, -32(a0) # store fixed quat. + +B2: + lw a0, 0(sp) + sll r0, r0, 0 + jr ra + daddiu sp, sp, 16 + + jr ra + daddu sp, sp, r0 +``` + +# `decompress-fixed-data-to-accumulator` + +Useful types +```lisp +(deftype joint-anim-compressed-hdr (structure) + "Header for the compressed joint animation format." + ((control-bits uint32 14 :offset-assert 0) ;; guessed by decompiler + (num-joints uint32 :offset-assert 56) + (matrix-bits uint32 :offset-assert 60) + ) + :method-count-assert 9 + :size-assert #x40 + :flag-assert #x900000040 + ) + +(deftype joint-anim-compressed-fixed (structure) + ((hdr joint-anim-compressed-hdr :inline :offset-assert 0) + (offset-64 uint32 :offset-assert 64) + (offset-32 uint32 :offset-assert 68) + (offset-16 uint32 :offset-assert 72) + (reserved uint32 :offset-assert 76) + (data vector 133 :inline :offset-assert 80) ;; guessed by decompiler + ) +``` + +```python +# a0 = accumulator +# a1 = fixed data (joint-anim-compressed-fixed) +# a2 = amount +# t1 = jacp-header (unset when we get here) +# s2 = num-joints +# vf14 = [1, 4, 4, 1] + +L79: + # copy the header to the jacp-header (i think, so we can continue using in frame functions + # even when dma'ing the next upload's fixed to here) + lq t4, 0(a1) # t4 = fixed.hdr.quad[0] + daddiu sp, sp, -16 + lq t5, 16(a1) # t4 = fixed.hdr.quad[1] + sll r0, r0, 0 + sq t4, 0(t1) # move to jacp header + sll r0, r0, 0 + sq t5, 16(t1) # move to jacp header + sll r0, r0, 0 + lq t4, 32(a1) # quad2 + sll r0, r0, 0 + lq t5, 48(a1) # quad3 + sll r0, r0, 0 + sq t4, 32(t1) + sll r0, r0, 0 + sq t5, 48(t1) + + sll r0, r0, 0 + sq a0, 0(sp) # backup acc pointer + sll r0, r0, 0 + qmtc2.i vf13, a2 # vf13.x = amount + lui t2, 28672 # scratchpad addr + lw t4, 64(a1) # t4 = fixed.offset-64 + daddiu v1, a1, 80 # v1 = fixed.data + lw t5, 68(a1) # t4 = fixed.offset-32 + daddu s5, t1, r0 # s5 = control-bits-ptr + lw t6, 72(a1) # t6 = fixed.offset-16 + daddu t4, t4, v1 # t4 = fixed.data + fixed.offset-64 + vmulx.xyzw vf13, vf14, vf13 # vf13 = [amt, 4*amt, 4*amt, amt] + daddiu t2, t2, 1616 # t2 = fix-jmp-table + lw s2, 56(t1) # hdr.num_joints = num-joints + daddu t5, t5, v1 # t5 = fixed.data + fixed.offset-32 + lw s4, 60(t1) # s4 = matrix-bits + daddu t6, t6, v1 # t6 = fixed.data + fixed.offset-16 + addiu s3, r0, 8 # s3 = 8 + daddiu s5, s5, 4 # s5 (control-bits-ptr) += 4 bytes + andi t3, s4, 1 # t3 = matrix-bits & 1 + sll r0, r0, 0 + bne t3, r0, L80 + sll r0, r0, 0 + +B1: # if (matrix-bits & 1) == 0 + lqc2 vf1, 0(t4) # load matrix from offset-64 data (1, 2, 4, 4) + lqc2 vf2, 16(t4) + lqc2 vf3, 32(t4) + lqc2 vf4, 48(t4) + lqc2 vf9, 0(a0) # load matrix from accumulator + daddiu t4, t4, 64 # increment data-64 ptr + lqc2 vf10, 16(a0) + sll r0, r0, 0 + lqc2 vf11, 32(a0) + lqc2 vf12, 48(a0) + vmulaw.xyzw acc, vf9, vf0 # acc = existing + vmaddx.xyzw vf9, vf1, vf13 # existing += amount * new + vmulaw.xyzw acc, vf10, vf0 + vmaddx.xyzw vf10, vf2, vf13 + vmulaw.xyzw acc, vf11, vf0 + vmaddx.xyzw vf11, vf3, vf13 + vmulaw.xyzw acc, vf12, vf0 + vmaddx.xyzw vf12, vf4, vf13 + sqc2 vf9, 0(a0) # store back modified matrix. + sqc2 vf10, 16(a0) + sqc2 vf11, 32(a0) + sqc2 vf12, 48(a0) +B2: +L80: # endif + andi t3, s4, 2 # check matrix bit + daddiu a0, a0, 64 # increment acc ptr to second matrix + bne t3, r0, L81 + sll r0, r0, 0 + +B3: # if (matrix-bits & 2) == 0 + # same stuff as for the first matrix. + lqc2 vf1, 0(t4) + lqc2 vf2, 16(t4) + lqc2 vf3, 32(t4) + lqc2 vf4, 48(t4) + lqc2 vf9, 0(a0) + daddiu t4, t4, 64 + lqc2 vf10, 16(a0) + sll r0, r0, 0 + lqc2 vf11, 32(a0) + lqc2 vf12, 48(a0) + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf1, vf13 + vmulaw.xyzw acc, vf10, vf0 + vmaddx.xyzw vf10, vf2, vf13 + vmulaw.xyzw acc, vf11, vf0 + vmaddx.xyzw vf11, vf3, vf13 + vmulaw.xyzw acc, vf12, vf0 + vmaddx.xyzw vf12, vf4, vf13 + sqc2 vf9, 0(a0) + sqc2 vf10, 16(a0) + sqc2 vf11, 32(a0) + sqc2 vf12, 48(a0) +B4: +L81: + lw s4, -4(s5) # load control-bits-ptr[-1] + daddiu a0, a0, 64 # increment to first TQ +B5: +L82: + andi t3, s4, 15 # grab lower 4 bits of the control bits + sra s4, s4, 4 # shift in next 4 + sll t3, t3, 2 # multiply by 4 (ah - this tells us which case!) + daddiu s3, s3, -1 # count down if we need to load the next u32 control bits or not. + daddu t3, t3, t2 # look up in the jump table + daddiu s2, s2, -1 # count down joints + lw t3, 0(t3) # load from jump table! + sll r0, r0, 0 + sll r0, r0, 0 + sll r0, r0, 0 + jr t3 + sll r0, r0, 0 + +B6: # JUMP TABLE 7 and 15, also used to advance +L83: + beq s2, r0, L90 # if out of joints, end. + daddiu a0, a0, 48 # increment acc ptr. + +B7: + bne s3, r0, L82 # see if we need to load a new control word or not. + sll r0, r0, 0 + +B8: + lw s4, 0(s5) # load up new control word + daddiu s5, s5, 4 + beq r0, r0, L82 + addiu s3, r0, 8 # back to the beginning! + +B9: # JUMP TABLE 0 + ld t9, 0(t4) # load one uint64 from data64 + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) # vf6 = acc.quat + pextlh t9, t9, r0 # expand to uint32's (upper) + psraw t9, t9, 16 # treat as signed s16 + qmtc2.i vf4, t9 # vf4 = new_data (sext) + lw s6, 0(t5) # load one uint32 from data32 + daddiu t5, t5, 4 + lh gp, 0(t6) # load one uint16 from data16 + daddiu t6, t6, 2 + lqc2 vf3, 0(a0) # vf3 = acc.trans + vitof15.xyzw vf4, vf4 # quat int -> float + pextlw s6, gp, s6 # s6 = [XX, XX, u16, u32] + pextlh s6, s6, r0 # s6 = [XX, u16, u32[1], u32[0]] + psraw s6, s6, 16 # sext + vmul.xyzw vf10, vf4, vf6 # elementwise quat product + qmtc2.i vf1, s6 # vf1 = the first triple + lw t8, 0(t5) # load another uint32, uint16 + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + vmulaw.xyzw acc, vf10, vf0 # add up quaternions (dot product) + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + + vitof0.xyzw vf1, vf1 # first triple to float (trans) + lqc2 vf9, 32(a0) # acc scale + pextlw t8, fp, t8 # triple stuff + qmfc2.i t9, vf10 # quat dot to grp + pextlh t8, t8, r0 # triple stuff + psraw t8, t8, 16 # triple sext + qmtc2.i vf7, t8 # second triple + pcpyud t9, t9, r0 # check sign of quaternion + bltzl t9, L84 +B10: + vsub.xyzw vf4, vf15, vf4 # flip quaternion if dot product is negative. + +B11: +L84: + vitof12.xyzw vf7, vf7 # second triple (scale) + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 # vf6 = acc.quat + amount * decompressed_quat + vmulaw.xyzw acc, vf3, vf0 + vmaddy.xyzw vf3, vf1, vf13 # vf3 = acc.trans + amount * 4 * decompressed_trans + vmulaw.xyzw acc, vf9, vf0 # vf9 = acc.scale + amount * decompressed_scale + vmaddx.xyzw vf9, vf7, vf13 + sqc2 vf3, 0(a0) + sqc2 vf6, 16(a0) + sqc2 vf9, 32(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B12: # JUMP TABLE 8 + ld t9, 8(t4) # one ahead data64 load?? + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) # vf6 = acc.quat + pextlh t9, t9, r0 # + psraw t9, t9, 16 + qmtc2.i vf4, t9 # quat expand + ld s6, -8(t4) # now load the previous data64 + daddiu t4, t4, 8 + lw gp, 0(t5) # load one uint32 from data32 + daddiu t5, t5, 4 + lqc2 vf3, 0(a0) # vf3 = acc.trans + vitof15.xyzw vf4, vf4 # quat int->float + pcpyld s6, gp, s6 # trans combingin ints + vmul.xyzw vf10, vf4, vf6 # quat dot + qmtc2.i vf1, s6 # trans int + lw t8, 0(t5) # scale load + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + vmulaw.xyzw acc, vf10, vf0 # quat dot add + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + lqc2 vf9, 32(a0) # existing scale + pextlw t8, fp, t8 + qmfc2.i t9, vf10 + pextlh t8, t8, r0 + psraw t8, t8, 16 + qmtc2.i vf7, t8 + pcpyud t9, t9, r0 + bltzl t9, L85 +B13: + vsub.xyzw vf4, vf15, vf4 + +B14: +L85: + vitof12.xyzw vf7, vf7 + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + vmulaw.xyzw acc, vf3, vf0 + vmaddx.xyzw vf3, vf1, vf13 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + sqc2 vf3, 0(a0) + sqc2 vf6, 16(a0) + sqc2 vf9, 32(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B15: # JUMP 1, 9 + ld t9, 0(t4) # 64 load for quat + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) # vf6 = acc.quat + pextlh t9, t9, r0 + psraw t9, t9, 16 + qmtc2.i vf4, t9 # vf4 = quat expand int + lw t8, 0(t5) # load a 32-16 + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf9, 32(a0) # vf9 = acc.scale + vitof15.xyzw vf4, vf4 + pextlw t8, fp, t8 + pextlh t8, t8, r0 + psraw t8, t8, 16 # scale expand + vmul.xyzw vf10, vf4, vf6 + qmtc2.i vf7, t8 # vf7 = scale + vmulaw.xyzw acc, vf10, vf0 + vitof12.xyzw vf7, vf7 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + qmfc2.i t9, vf10 + pcpyud t9, t9, r0 + bltzl t9, L86 +B16: + vsub.xyzw vf4, vf15, vf4 + +B17: +L86: + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + sqc2 vf6, 16(a0) + sqc2 vf9, 32(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B18: # JUMP 2 + lw s6, 0(t5) # load 32, 16 + daddiu t5, t5, 4 + lh gp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf3, 0(a0) # old trans + pextlw s6, gp, s6 + pextlh s6, s6, r0 + psraw s6, s6, 16 + qmtc2.i vf1, s6 + lw t8, 0(t5) # load 32, 16 + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf9, 32(a0) + vitof0.xyzw vf1, vf1 + pextlw t8, fp, t8 + pextlh t8, t8, r0 + psraw t8, t8, 16 + qmtc2.i vf7, t8 + vmulaw.xyzw acc, vf3, vf0 + vmaddy.xyzw vf3, vf1, vf13 + vitof12.xyzw vf7, vf7 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + sqc2 vf3, 0(a0) + sqc2 vf9, 32(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B19: # JUMP 10 + ld s6, 0(t4) + daddiu t4, t4, 8 + lw gp, 0(t5) + daddiu t5, t5, 4 + lqc2 vf3, 0(a0) + pcpyld s6, gp, s6 + qmtc2.i vf1, s6 + lw t8, 0(t5) + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf9, 32(a0) + pextlw t8, fp, t8 + pextlh t8, t8, r0 + psraw t8, t8, 16 + qmtc2.i vf7, t8 + vmulaw.xyzw acc, vf3, vf0 + vmaddx.xyzw vf3, vf1, vf13 + vitof12.xyzw vf7, vf7 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + sqc2 vf3, 0(a0) + sqc2 vf9, 32(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B20: # JUMP 3, 11 + lw t8, 0(t5) + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf9, 32(a0) + pextlw t8, fp, t8 + pextlh t8, t8, r0 + psraw t8, t8, 16 + qmtc2.i vf7, t8 + vitof12.xyzw vf7, vf7 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + sqc2 vf9, 32(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B21: # JUMP 4 + ld t9, 0(t4) + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) + pextlh t9, t9, r0 + psraw t9, t9, 16 + qmtc2.i vf4, t9 + lw s6, 0(t5) + daddiu t5, t5, 4 + lh gp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf3, 0(a0) + vitof15.xyzw vf4, vf4 + pextlw s6, gp, s6 + pextlh s6, s6, r0 + psraw s6, s6, 16 + vmul.xyzw vf10, vf4, vf6 + qmtc2.i vf1, s6 + vmulaw.xyzw acc, vf10, vf0 + vitof0.xyzw vf1, vf1 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + vmulaw.xyzw acc, vf3, vf0 + vmaddy.xyzw vf3, vf1, vf13 + qmfc2.i t9, vf10 + pcpyud t9, t9, r0 + bltzl t9, L87 +B22: + vsub.xyzw vf4, vf15, vf4 + +B23: +L87: + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + sqc2 vf3, 0(a0) + sqc2 vf6, 16(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B24: # JUMP 12 + ld t9, 8(t4) + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) + pextlh t9, t9, r0 + psraw t9, t9, 16 + qmtc2.i vf4, t9 + ld s6, -8(t4) + daddiu t4, t4, 8 + lw gp, 0(t5) + daddiu t5, t5, 4 + lqc2 vf3, 0(a0) + vitof15.xyzw vf4, vf4 + pcpyld s6, gp, s6 + vmul.xyzw vf10, vf4, vf6 + qmtc2.i vf1, s6 + vmulaw.xyzw acc, vf10, vf0 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + vmulaw.xyzw acc, vf3, vf0 + vmaddx.xyzw vf3, vf1, vf13 + qmfc2.i t9, vf10 + pcpyud t9, t9, r0 + bltzl t9, L88 +B25: + vsub.xyzw vf4, vf15, vf4 + +B26: +L88: + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + sqc2 vf3, 0(a0) + sqc2 vf6, 16(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B27: # JUMP 5, 13 + ld t9, 0(t4) + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) + pextlh t9, t9, r0 + psraw t9, t9, 16 + qmtc2.i vf4, t9 + vitof15.xyzw vf4, vf4 + vmul.xyzw vf10, vf4, vf6 + vmulaw.xyzw acc, vf10, vf0 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + qmfc2.i t9, vf10 + pcpyud t9, t9, r0 + bltzl t9, L89 +B28: + vsub.xyzw vf4, vf15, vf4 + +B29: +L89: + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + sqc2 vf6, 16(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B30: # JUMP 6 + lw s6, 0(t5) + daddiu t5, t5, 4 + lh gp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf3, 0(a0) + pextlw s6, gp, s6 + pextlh s6, s6, r0 + psraw s6, s6, 16 + qmtc2.i vf1, s6 + vitof0.xyzw vf1, vf1 + vmulaw.xyzw acc, vf3, vf0 + vmaddy.xyzw vf3, vf1, vf13 + sqc2 vf3, 0(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B31: + ld s6, 0(t4) + daddiu t4, t4, 8 + lw gp, 0(t5) + daddiu t5, t5, 4 + lqc2 vf3, 0(a0) + pcpyld s6, gp, s6 + qmtc2.i vf1, s6 + vmulaw.xyzw acc, vf3, vf0 + vmaddx.xyzw vf3, vf1, vf13 + sqc2 vf3, 0(a0) + beq r0, r0, L83 + sll r0, r0, 0 + +B32: +L90: + lq a0, 0(sp) + sll r0, r0, 0 + jr ra + daddiu sp, sp, 16 + + jr ra + daddu sp, sp, r0 +``` + +Explanation: +```python +# set up pointers +data64 = data + offset_64 +data32 = data + offset_32 +data16 = data + offset_16 + +# do matrices +if (matrix_bits & 1) == 0: + acc.matrix[0] += amount * Matrix(data64) + data64 += sizeof(Matrix) + +if (matrix_bits & 2) == 0: + acc.matrix[1] += amount * Matrix(data64) + data64 += sizeof(Matrix) + +# decomp helpers +def unpack_quat_s16s_from_d64(): + data = S16x4(data64) + data64++ + quat_ints = [data[0], data[1], data[2], data[3]] + +# the control words have 4-bits per joint + +for joint_idx in range(num_joints): + control = control_words.extract_4bits(joint_idx) + if control == 0: + # quat is packed as 4x s16's in data64, scale is 32768 + # dot product is checked before lerping. + # trans is packed as 2x s16's in data32, 1x s16 in data16, scale is 4 + # scale is packed as 2x s16's in data32, 1x s16 in data16, scale is 4096 + + if control == 7: + pass # nothing to do! + if control == 8: + # trans is packed as 2x s32's in data64, 1x s32 in data32, scale is 1 + # quat is packed as 4x s16's in data64, scale is 32768 + # dot product is checked before lerping. + # scale is packed as 2x s16's in data32, 1x s16 in data16, scale is 4096 + if control == 15: + pass # nothing to do! + +``` + +Control Modes: + +0. FIXED has `trans-32-16-4`, `quat-64-32768`, `scale-32-16-4096`, FRAME has nothing +1. FIXED has `trans-0`, `quat-64-32768`, `scale-32-16-4096`, FRAME has trans (small) +2. FIXED has `trans-32-16-4`, `quat-0`, `scale-32-16-4096`, FRAME has quat +3. FIXED has `trans-0`, `quat-0`, `scale-32-16-4096` +4. FIXED has `trans-32-16-4`, `quat-64-32768`, `scale-0` +5. FIXED has `trans-0`, `quat-64-32768`, `scale-0` +6. FIXED has `trans-32-16-4`, `quat-0`, `scale-0` +7. FIXED 0 +8. FIXED as `trans-64-32-1`, `quat-64-32768`, `scale-32-16-4096`, FRAME has nothing +9. FIXED has `trans-0`, `quat-64-32768`, `scale-32-16-4096`, FRAME has trans (large) +10. FIXED has `trans-64-32-1`, `quat-0`, `scale-32-16-4096` +11. FIXED has `trans-0`, `quat-0`, `scale-32-16-4096`, FRAME HAS QUAT +12. FIXED has `trans-64-32-1`, `quat-64-32768`, `scale-0` +13. FIXED has `trans-0`, `quat-64-32768`, `scale-0` +14. FIXED has `trans-64-32-1`, `quat-0`, `scale-0` +15. FIXED 0 + +So bits are: +control: + +0. frame-trans +1. frame-quat +2. frame-scale +4. big-trans + +matrix: + +0. matrix 0 from frame +1. matrix 1 from frame + +# `decompress-frame-data-to-accumulator` + +```lisp +(deftype joint-anim-compressed-frame (structure) + ((offset-64 uint32 :offset-assert 0) + (offset-32 uint32 :offset-assert 4) + (offset-16 uint32 :offset-assert 8) + (reserved uint32 :offset-assert 12) + (data vector 133 :inline :offset-assert 16) ;; guessed by decompiler + ) + :method-count-assert 9 + :size-assert #x860 + :flag-assert #x900000860 + ) +``` + +```python +# a2 = amount (weight) +# a1 = frame-data + + qmtc2.i vf13, a2 # vf13 = amount + sq a0, 0(sp) # back up accumulator + lui t2, 28672 # t2 = spad + lw t4, 0(a1) # t4 = offset64 + daddiu v1, a1, 16 # v1 = data + lw t5, 4(a1) # offset32 + daddu s5, t1, r0 # control bits ptr + lw t6, 8(a1) # offset16 + daddu t4, t4, v1 # t4 = data64 + vmulx.xyzw vf13, vf14, vf13 # usual [amt, 4*amt, 4*amt, amt] stuff + daddiu t2, t2, 1680 # t2 = jump table + lw s2, 56(t1) # s2 = num-joints + daddu t5, t5, v1 # t5 = data32 + lw s4, 60(t1) # s4 = matrix-bits + daddu t6, t6, v1 # t6 = data16 + addiu s3, r0, 8 # load next u32 word counter + daddiu s5, s5, 4 # control word ptr + andi t3, s4, 1 # check matrix bit + sll r0, r0, 0 + beq t3, r0, L68 + sll r0, r0, 0 + +B1: # if matrix bit is set: + lqc2 vf1, 0(t4) + lqc2 vf2, 16(t4) + lqc2 vf3, 32(t4) + lqc2 vf4, 48(t4) + lqc2 vf9, 0(a0) + daddiu t4, t4, 64 + lqc2 vf10, 16(a0) + sll r0, r0, 0 + lqc2 vf11, 32(a0) + lqc2 vf12, 48(a0) + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf1, vf13 + vmulaw.xyzw acc, vf10, vf0 + vmaddx.xyzw vf10, vf2, vf13 + vmulaw.xyzw acc, vf11, vf0 + vmaddx.xyzw vf11, vf3, vf13 + vmulaw.xyzw acc, vf12, vf0 + vmaddx.xyzw vf12, vf4, vf13 + sqc2 vf9, 0(a0) + sqc2 vf10, 16(a0) + sqc2 vf11, 32(a0) + sqc2 vf12, 48(a0) +B2: +L68: + andi t3, s4, 2 + daddiu a0, a0, 64 + beq t3, r0, L69 + sll r0, r0, 0 + +B3: + lqc2 vf1, 0(t4) + lqc2 vf2, 16(t4) + lqc2 vf3, 32(t4) + lqc2 vf4, 48(t4) + lqc2 vf9, 0(a0) + daddiu t4, t4, 64 + lqc2 vf10, 16(a0) + sll r0, r0, 0 + lqc2 vf11, 32(a0) + lqc2 vf12, 48(a0) + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf1, vf13 + vmulaw.xyzw acc, vf10, vf0 + vmaddx.xyzw vf10, vf2, vf13 + vmulaw.xyzw acc, vf11, vf0 + vmaddx.xyzw vf11, vf3, vf13 + vmulaw.xyzw acc, vf12, vf0 + vmaddx.xyzw vf12, vf4, vf13 + sqc2 vf9, 0(a0) + sqc2 vf10, 16(a0) + sqc2 vf11, 32(a0) + sqc2 vf12, 48(a0) +B4: +L69: + lw s4, -4(s5) + daddiu a0, a0, 64 +B5: +L70: + andi t3, s4, 15 + sra s4, s4, 4 + sll t3, t3, 2 + daddiu s3, s3, -1 + daddu t3, t3, t2 + daddiu s2, s2, -1 + lw t3, 0(t3) + sll r0, r0, 0 + sll r0, r0, 0 + sll r0, r0, 0 + jr t3 + sll r0, r0, 0 + +B6: # JUMP 0, 8 +L71: + beq s2, r0, L78 + daddiu a0, a0, 48 + +B7: + bne s3, r0, L70 + sll r0, r0, 0 + +B8: + lw s4, 0(s5) + daddiu s5, s5, 4 + beq r0, r0, L70 + addiu s3, r0, 8 + +B9: # JUMP 1 + lw s6, 0(t5) + daddiu t5, t5, 4 + lh gp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf3, 0(a0) + pextlw s6, gp, s6 + pextlh s6, s6, r0 + psraw s6, s6, 16 + qmtc2.i vf1, s6 + vitof0.xyzw vf1, vf1 + vmulaw.xyzw acc, vf3, vf0 + vmaddy.xyzw vf3, vf1, vf13 + sqc2 vf3, 0(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B10: # JUMP 9 + ld s6, 0(t4) + daddiu t4, t4, 8 + lw gp, 0(t5) + daddiu t5, t5, 4 + lqc2 vf3, 0(a0) + pcpyld s6, gp, s6 + qmtc2.i vf1, s6 + vmulaw.xyzw acc, vf3, vf0 + vmaddx.xyzw vf3, vf1, vf13 + sqc2 vf3, 0(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B11: + ld t9, 0(t4) + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) + pextlh t9, t9, r0 + psraw t9, t9, 16 + qmtc2.i vf4, t9 + vitof15.xyzw vf4, vf4 + vmul.xyzw vf10, vf4, vf6 + vmulaw.xyzw acc, vf10, vf0 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + qmfc2.i t9, vf10 + pcpyud t9, t9, r0 + bltzl t9, L72 +B12: + vsub.xyzw vf4, vf15, vf4 + +B13: +L72: + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + sqc2 vf6, 16(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B14: + ld t9, 0(t4) + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) + pextlh t9, t9, r0 + psraw t9, t9, 16 + qmtc2.i vf4, t9 + lw s6, 0(t5) + daddiu t5, t5, 4 + lh gp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf3, 0(a0) + vitof15.xyzw vf4, vf4 + pextlw s6, gp, s6 + pextlh s6, s6, r0 + psraw s6, s6, 16 + vmul.xyzw vf10, vf4, vf6 + qmtc2.i vf1, s6 + vmulaw.xyzw acc, vf10, vf0 + vitof0.xyzw vf1, vf1 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + vmulaw.xyzw acc, vf3, vf0 + vmaddy.xyzw vf3, vf1, vf13 + qmfc2.i t9, vf10 + pcpyud t9, t9, r0 + bltzl t9, L73 +B15: + vsub.xyzw vf4, vf15, vf4 + +B16: +L73: + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + sqc2 vf3, 0(a0) + sqc2 vf6, 16(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B17: + ld t9, 8(t4) + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) + pextlh t9, t9, r0 + psraw t9, t9, 16 + qmtc2.i vf4, t9 + ld s6, -8(t4) + daddiu t4, t4, 8 + lw gp, 0(t5) + daddiu t5, t5, 4 + lqc2 vf3, 0(a0) + vitof15.xyzw vf4, vf4 + pcpyld s6, gp, s6 + vmul.xyzw vf10, vf4, vf6 + qmtc2.i vf1, s6 + vmulaw.xyzw acc, vf10, vf0 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + vmulaw.xyzw acc, vf3, vf0 + vmaddx.xyzw vf3, vf1, vf13 + qmfc2.i t9, vf10 + pcpyud t9, t9, r0 + bltzl t9, L74 +B18: + vsub.xyzw vf4, vf15, vf4 + +B19: +L74: + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + sqc2 vf3, 0(a0) + sqc2 vf6, 16(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B20: + lw t8, 0(t5) + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf9, 32(a0) + pextlw t8, fp, t8 + pextlh t8, t8, r0 + psraw t8, t8, 16 + qmtc2.i vf7, t8 + vitof12.xyzw vf7, vf7 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + sqc2 vf9, 32(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B21: + lw s6, 0(t5) + daddiu t5, t5, 4 + lh gp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf3, 0(a0) + pextlw s6, gp, s6 + pextlh s6, s6, r0 + psraw s6, s6, 16 + qmtc2.i vf1, s6 + lw t8, 0(t5) + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf9, 32(a0) + vitof0.xyzw vf1, vf1 + pextlw t8, fp, t8 + pextlh t8, t8, r0 + psraw t8, t8, 16 + qmtc2.i vf7, t8 + vmulaw.xyzw acc, vf3, vf0 + vmaddy.xyzw vf3, vf1, vf13 + vitof12.xyzw vf7, vf7 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + sqc2 vf3, 0(a0) + sqc2 vf9, 32(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B22: + ld s6, 0(t4) + daddiu t4, t4, 8 + lw gp, 0(t5) + daddiu t5, t5, 4 + lqc2 vf3, 0(a0) + pcpyld s6, gp, s6 + qmtc2.i vf1, s6 + lw t8, 0(t5) + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf9, 32(a0) + pextlw t8, fp, t8 + pextlh t8, t8, r0 + psraw t8, t8, 16 + qmtc2.i vf7, t8 + vmulaw.xyzw acc, vf3, vf0 + vmaddx.xyzw vf3, vf1, vf13 + vitof12.xyzw vf7, vf7 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + sqc2 vf3, 0(a0) + sqc2 vf9, 32(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B23: + ld t9, 0(t4) + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) + pextlh t9, t9, r0 + psraw t9, t9, 16 + qmtc2.i vf4, t9 + lw t8, 0(t5) + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf9, 32(a0) + vitof15.xyzw vf4, vf4 + pextlw t8, fp, t8 + pextlh t8, t8, r0 + psraw t8, t8, 16 + vmul.xyzw vf10, vf4, vf6 + qmtc2.i vf7, t8 + vmulaw.xyzw acc, vf10, vf0 + vitof12.xyzw vf7, vf7 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + qmfc2.i t9, vf10 + pcpyud t9, t9, r0 + bltzl t9, L75 +B24: + vsub.xyzw vf4, vf15, vf4 + +B25: +L75: + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + sqc2 vf6, 16(a0) + sqc2 vf9, 32(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B26: + ld t9, 0(t4) + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) + pextlh t9, t9, r0 + psraw t9, t9, 16 + qmtc2.i vf4, t9 + lw s6, 0(t5) + daddiu t5, t5, 4 + lh gp, 0(t6) + daddiu t6, t6, 2 + lqc2 vf3, 0(a0) + vitof15.xyzw vf4, vf4 + pextlw s6, gp, s6 + pextlh s6, s6, r0 + psraw s6, s6, 16 + vmul.xyzw vf10, vf4, vf6 + qmtc2.i vf1, s6 + lw t8, 0(t5) + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + vmulaw.xyzw acc, vf10, vf0 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + vitof0.xyzw vf1, vf1 + lqc2 vf9, 32(a0) + pextlw t8, fp, t8 + qmfc2.i t9, vf10 + pextlh t8, t8, r0 + psraw t8, t8, 16 + qmtc2.i vf7, t8 + pcpyud t9, t9, r0 + bltzl t9, L76 +B27: + vsub.xyzw vf4, vf15, vf4 + +B28: +L76: + vitof12.xyzw vf7, vf7 + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + vmulaw.xyzw acc, vf3, vf0 + vmaddy.xyzw vf3, vf1, vf13 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + sqc2 vf3, 0(a0) + sqc2 vf6, 16(a0) + sqc2 vf9, 32(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B29: + ld t9, 8(t4) + daddiu t4, t4, 8 + lqc2 vf6, 16(a0) + pextlh t9, t9, r0 + psraw t9, t9, 16 + qmtc2.i vf4, t9 + ld s6, -8(t4) + daddiu t4, t4, 8 + lw gp, 0(t5) + daddiu t5, t5, 4 + lqc2 vf3, 0(a0) + vitof15.xyzw vf4, vf4 + pcpyld s6, gp, s6 + vmul.xyzw vf10, vf4, vf6 + qmtc2.i vf1, s6 + lw t8, 0(t5) + daddiu t5, t5, 4 + lh fp, 0(t6) + daddiu t6, t6, 2 + vmulaw.xyzw acc, vf10, vf0 + vmaddaz.xyzw acc, vf0, vf10 + vmadday.xyzw acc, vf0, vf10 + vmaddx.xyzw vf10, vf0, vf10 + lqc2 vf9, 32(a0) + pextlw t8, fp, t8 + qmfc2.i t9, vf10 + pextlh t8, t8, r0 + psraw t8, t8, 16 + qmtc2.i vf7, t8 + pcpyud t9, t9, r0 + bltzl t9, L77 +B30: + vsub.xyzw vf4, vf15, vf4 + +B31: +L77: + vitof12.xyzw vf7, vf7 + vmulaw.xyzw acc, vf6, vf0 + vmaddx.xyzw vf6, vf4, vf13 + vmulaw.xyzw acc, vf3, vf0 + vmaddx.xyzw vf3, vf1, vf13 + vmulaw.xyzw acc, vf9, vf0 + vmaddx.xyzw vf9, vf7, vf13 + sqc2 vf3, 0(a0) + sqc2 vf6, 16(a0) + sqc2 vf9, 32(a0) + beq r0, r0, L71 + sll r0, r0, 0 + +B32: +L78: + lq a0, 0(sp) + sll r0, r0, 0 + jr ra + daddiu sp, sp, 16 + + jr ra + daddu sp, sp, r0 +``` \ No newline at end of file diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index f459a0debe..caeb585a8a 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -186,6 +186,7 @@ set(RUNTIME_SOURCE mips2c/jak2_functions/squid.cpp mips2c/jak2_functions/texture.cpp mips2c/jak2_functions/vortex.cpp + mips2c/jak3_functions/collide_func.cpp mips2c/jak3_functions/lights.cpp mips2c/mips2c_table.cpp overlord/common/dma.cpp diff --git a/game/mips2c/jak3_functions/collide_func.cpp b/game/mips2c/jak3_functions/collide_func.cpp new file mode 100644 index 0000000000..11f94fa0a6 --- /dev/null +++ b/game/mips2c/jak3_functions/collide_func.cpp @@ -0,0 +1,506 @@ + +//--------------------------MIPS2C--------------------- +// clang-format off +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/jak3/kscheme.h" +using ::jak3::intern_from_c; +namespace Mips2C::jak3 { +namespace moving_sphere_triangle_intersect { +struct Cache { + void* collide_do_primitives; // collide-do-primitives +} cache; + +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + u32 call_addr = 0; + c->daddiu(sp, sp, -16); // daddiu sp, sp, -16 + c->sd(ra, 0, sp); // sd ra, 0(sp) + c->lqc2(vf14, 0, a0); // lqc2 vf14, 0(a0) + c->lqc2(vf15, 0, a1); // lqc2 vf15, 0(a1) + c->lqc2(vf11, 0, a3); // lqc2 vf11, 0(a3) + c->lqc2(vf12, 16, a3); // lqc2 vf12, 16(a3) + c->lqc2(vf13, 32, a3); // lqc2 vf13, 32(a3) + c->mov128_vf_gpr(vf1, a2); // qmtc2.i vf1, a2 + c->vadd(DEST::xyzw, vf6, vf14, vf15); // vadd.xyzw vf6, vf14, vf15 + c->vsub(DEST::xyzw, vf11, vf11, vf12); // vsub.xyzw vf11, vf11, vf12 + c->vsub(DEST::xyzw, vf13, vf13, vf12); // vsub.xyzw vf13, vf13, vf12 + c->vsub(DEST::xyzw, vf14, vf14, vf12); // vsub.xyzw vf14, vf14, vf12 + c->vsub(DEST::xyzw, vf6, vf6, vf12); // vsub.xyzw vf6, vf6, vf12 + c->vmini(DEST::xyzw, vf2, vf11, vf0); // vmini.xyzw vf2, vf11, vf0 + c->vopmula(vf13, vf11); // vopmula.xyz acc, vf13, vf11 + c->vopmsub(vf16, vf11, vf13); // vopmsub.xyz vf16, vf11, vf13 + c->vmax(DEST::xyzw, vf3, vf11, vf0); // vmax.xyzw vf3, vf11, vf0 + c->vmini(DEST::xyzw, vf4, vf14, vf6); // vmini.xyzw vf4, vf14, vf6 + c->vmax(DEST::xyzw, vf5, vf14, vf6); // vmax.xyzw vf5, vf14, vf6 + c->vmul(DEST::xyzw, vf7, vf16, vf16); // vmul.xyzw vf7, vf16, vf16 + c->vmini(DEST::xyzw, vf2, vf2, vf13); // vmini.xyzw vf2, vf2, vf13 + c->vmax(DEST::xyzw, vf3, vf3, vf13); // vmax.xyzw vf3, vf3, vf13 + c->vsub_bc(DEST::xyzw, BC::x, vf4, vf4, vf1); // vsubx.xyzw vf4, vf4, vf1 + c->vadd_bc(DEST::x, BC::y, vf7, vf7, vf7); // vaddy.x vf7, vf7, vf7 + c->vadd_bc(DEST::xyzw, BC::x, vf5, vf5, vf1); // vaddx.xyzw vf5, vf5, vf1 + // nop // sll r0, r0, 0 + c->vsub(DEST::xyzw, vf3, vf3, vf4); // vsub.xyzw vf3, vf3, vf4 + c->vadd_bc(DEST::x, BC::z, vf7, vf7, vf7); // vaddz.x vf7, vf7, vf7 + c->vsub(DEST::xyzw, vf5, vf5, vf2); // vsub.xyzw vf5, vf5, vf2 + // nop // sll r0, r0, 0 + c->mov128_gpr_vf(t2, vf3); // qmfc2.i t2, vf3 + c->mov128_gpr_vf(v1, vf5); // qmfc2.i v1, vf5 + c->vrsqrt(vf0, BC::w, vf7, BC::x); // vrsqrt Q, vf0.w, vf7.x + c->or_(v1, t2, v1); // or v1, t2, v1 + c->pcgtw(v1, r0, v1); // pcgtw v1, r0, v1 + c->ppach(v1, r0, v1); // ppach v1, r0, v1 + c->dsll(v1, v1, 16); // dsll v1, v1, 16 + bc = c->sgpr64(v1) != 0; // bne v1, r0, L14 + // nop // sll r0, r0, 0 + if (bc) {goto block_14;} // branch non-likely + + c->vmul(DEST::xyzw, vf2, vf16, vf15); // vmul.xyzw vf2, vf16, vf15 + c->vmul(DEST::xyzw, vf3, vf16, vf14); // vmul.xyzw vf3, vf16, vf14 + c->vadd_bc(DEST::x, BC::y, vf2, vf2, vf2); // vaddy.x vf2, vf2, vf2 + c->vsub_bc(DEST::y, BC::y, vf3, vf0, vf3); // vsuby.y vf3, vf0, vf3 + c->vadd_bc(DEST::x, BC::z, vf2, vf2, vf2); // vaddz.x vf2, vf2, vf2 + c->vsub_bc(DEST::y, BC::x, vf3, vf3, vf3); // vsubx.y vf3, vf3, vf3 + c->vsub_bc(DEST::y, BC::z, vf3, vf3, vf3); // vsubz.y vf3, vf3, vf3 + c->vadd_bc(DEST::x, BC::x, vf3, vf0, vf0); // vaddx.x vf3, vf0, vf0 + c->vadd_bc(DEST::x, BC::x, vf4, vf0, vf0); // vaddx.x vf4, vf0, vf0 + c->vwaitq(); // vwaitq + c->vmulq(DEST::xyzw, vf16, vf16); // vmulq.xyzw vf16, vf16, Q + c->vmove(DEST::w, vf16, vf0); // vmove.w vf16, vf0 + c->vmulq(DEST::xyzw, vf2, vf2); // vmulq.xyzw vf2, vf2, Q + c->vmulq(DEST::xyzw, vf4, vf3); // vmulq.xyzw vf4, vf3, Q + c->vmulq(DEST::xyzw, vf3, vf3); // vmulq.xyzw vf3, vf3, Q + c->sqc2(vf16, 0, t1); // sqc2 vf16, 0(t1) + // nop // vnop + // nop // vnop + c->vdiv(vf0, BC::w, vf2, BC::x); // vdiv Q, vf0.w, vf2.x + c->vadd_bc(DEST::y, BC::x, vf3, vf3, vf1); // vaddx.y vf3, vf3, vf1 + c->vsub_bc(DEST::y, BC::x, vf4, vf4, vf1); // vsubx.y vf4, vf4, vf1 + c->vwaitq(); // vwaitq + c->vmulq(DEST::xyzw, vf3, vf3); // vmulq.xyzw vf3, vf3, Q + c->vmulq(DEST::xyzw, vf4, vf4); // vmulq.xyzw vf4, vf4, Q + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + c->mov128_gpr_vf(v1, vf3); // qmfc2.i v1, vf3 + c->mov128_gpr_vf(t1, vf4); // qmfc2.i t1, vf4 + bc = ((s64)c->sgpr64(v1)) < 0; // bltz v1, L12 + // nop // sll r0, r0, 0 + if (bc) {goto block_11;} // branch non-likely + + bc = ((s64)c->sgpr64(t1)) < 0; // bltz t1, L13 + // nop // sll r0, r0, 0 + if (bc) {goto block_12;} // branch non-likely + + c->dsubu(v1, v1, t1); // dsubu v1, v1, t1 + bc = ((s64)c->sgpr64(v1)) < 0; // bltz v1, L9 + // nop // sll r0, r0, 0 + if (bc) {goto block_6;} // branch non-likely + + c->vsub_bc(DEST::xyzw, BC::w, vf2, vf4, vf0); // vsubw.xyzw vf2, vf4, vf0 + c->mov128_gpr_vf(v1, vf2); // qmfc2.i v1, vf2 + bc = ((s64)c->sgpr64(v1)) >= 0; // bgez v1, L14 + // nop // sll r0, r0, 0 + if (bc) {goto block_14;} // branch non-likely + + c->mov128_gpr_vf(v0, vf4); // qmfc2.i v0, vf4 + c->vmula_bc(DEST::xyzw, BC::w, vf14, vf0); // vmulaw.xyzw acc, vf14, vf0 + c->vmadd_bc(DEST::xyzw, BC::y, vf8, vf15, vf4); // vmaddy.xyzw vf8, vf15, vf4 + //beq r0, r0, L10 // beq r0, r0, L10 + // nop // sll r0, r0, 0 + goto block_8; // branch always + + +block_6: + c->vsub_bc(DEST::xyzw, BC::w, vf2, vf3, vf0); // vsubw.xyzw vf2, vf3, vf0 + c->mov128_gpr_vf(v1, vf2); // qmfc2.i v1, vf2 + bc = ((s64)c->sgpr64(v1)) >= 0; // bgez v1, L14 + // nop // sll r0, r0, 0 + if (bc) {goto block_14;} // branch non-likely + + c->vmula_bc(DEST::xyzw, BC::w, vf14, vf0); // vmulaw.xyzw acc, vf14, vf0 + c->vmadd_bc(DEST::xyzw, BC::y, vf8, vf15, vf3); // vmaddy.xyzw vf8, vf15, vf3 + c->mov128_gpr_vf(v0, vf3); // qmfc2.i v0, vf3 + +block_8: + c->dsra32(v0, v0, 0); // dsra32 v0, v0, 0 + c->vsub(DEST::xyzw, vf9, vf8, vf13); // vsub.xyzw vf9, vf8, vf13 + c->vsub(DEST::xyzw, vf10, vf8, vf11); // vsub.xyzw vf10, vf8, vf11 + c->vopmula(vf13, vf8); // vopmula.xyz acc, vf13, vf8 + c->vopmsub(vf5, vf8, vf13); // vopmsub.xyz vf5, vf8, vf13 + c->vopmula(vf8, vf11); // vopmula.xyz acc, vf8, vf11 + c->vopmsub(vf6, vf11, vf8); // vopmsub.xyz vf6, vf11, vf8 + c->vopmula(vf9, vf10); // vopmula.xyz acc, vf9, vf10 + c->vopmsub(vf7, vf10, vf9); // vopmsub.xyz vf7, vf10, vf9 + c->vmul(DEST::xyzw, vf5, vf5, vf16); // vmul.xyzw vf5, vf5, vf16 + c->vmul(DEST::xyzw, vf6, vf6, vf16); // vmul.xyzw vf6, vf6, vf16 + c->vmul(DEST::xyzw, vf7, vf7, vf16); // vmul.xyzw vf7, vf7, vf16 + c->vadd_bc(DEST::y, BC::x, vf5, vf5, vf5); // vaddx.y vf5, vf5, vf5 + c->vadd_bc(DEST::y, BC::x, vf6, vf6, vf6); // vaddx.y vf6, vf6, vf6 + c->vadd_bc(DEST::y, BC::x, vf7, vf7, vf7); // vaddx.y vf7, vf7, vf7 + c->vadd_bc(DEST::y, BC::z, vf5, vf5, vf5); // vaddz.y vf5, vf5, vf5 + c->vadd_bc(DEST::y, BC::z, vf6, vf6, vf6); // vaddz.y vf6, vf6, vf6 + c->vadd_bc(DEST::y, BC::z, vf7, vf7, vf7); // vaddz.y vf7, vf7, vf7 + c->mov128_gpr_vf(t1, vf5); // qmfc2.i t1, vf5 + c->mov128_gpr_vf(t2, vf6); // qmfc2.i t2, vf6 + c->mov128_gpr_vf(v1, vf7); // qmfc2.i v1, vf7 + c->or_(t1, t1, t2); // or t1, t1, t2 + c->or_(v1, t1, v1); // or v1, t1, v1 + bc = ((s64)c->sgpr64(v1)) < 0; // bltz v1, L11 + // nop // sll r0, r0, 0 + if (bc) {goto block_10;} // branch non-likely + + c->vopmula(vf8, vf16); // vopmula.xyz acc, vf8, vf16 + c->vopmsub(vf5, vf16, vf8); // vopmsub.xyz vf5, vf16, vf8 + c->vopmula(vf16, vf5); // vopmula.xyz acc, vf16, vf5 + c->vopmsub(vf5, vf5, vf16); // vopmsub.xyz vf5, vf5, vf16 + c->vadd(DEST::xyzw, vf5, vf5, vf12); // vadd.xyzw vf5, vf5, vf12 + c->sqc2(vf5, 0, t0); // sqc2 vf5, 0(t0) + //beq r0, r0, L15 // beq r0, r0, L15 + // nop // sll r0, r0, 0 + goto block_15; // branch always + + +block_10: + c->load_symbol2(t9, cache.collide_do_primitives); // lw t9, collide-do-primitives(s7) + call_addr = c->gprs[t9].du32[0]; // function call: + c->sll(v0, ra, 0); // sll v0, ra, 0 + c->jalr(call_addr); // jalr ra, t9 + c->mov64(v1, v0); // or v1, v0, r0 + //beq r0, r0, L15 // beq r0, r0, L15 + // nop // sll r0, r0, 0 + goto block_15; // branch always + + +block_11: + bc = ((s64)c->sgpr64(t1)) < 0; // bltz t1, L14 + // nop // sll r0, r0, 0 + if (bc) {goto block_14;} // branch non-likely + + +block_12: + c->vsub(DEST::xyzw, vf9, vf14, vf13); // vsub.xyzw vf9, vf14, vf13 + c->vsub(DEST::xyzw, vf10, vf14, vf11); // vsub.xyzw vf10, vf14, vf11 + c->vopmula(vf13, vf14); // vopmula.xyz acc, vf13, vf14 + c->vopmsub(vf5, vf14, vf13); // vopmsub.xyz vf5, vf14, vf13 + c->vopmula(vf14, vf11); // vopmula.xyz acc, vf14, vf11 + c->vopmsub(vf6, vf11, vf14); // vopmsub.xyz vf6, vf11, vf14 + c->vopmula(vf9, vf10); // vopmula.xyz acc, vf9, vf10 + c->vopmsub(vf7, vf10, vf9); // vopmsub.xyz vf7, vf10, vf9 + c->vmul(DEST::xyzw, vf5, vf5, vf16); // vmul.xyzw vf5, vf5, vf16 + c->vmul(DEST::xyzw, vf6, vf6, vf16); // vmul.xyzw vf6, vf6, vf16 + c->vmul(DEST::xyzw, vf7, vf7, vf16); // vmul.xyzw vf7, vf7, vf16 + c->vadd_bc(DEST::y, BC::x, vf5, vf5, vf5); // vaddx.y vf5, vf5, vf5 + c->vadd_bc(DEST::y, BC::x, vf6, vf6, vf6); // vaddx.y vf6, vf6, vf6 + c->vadd_bc(DEST::y, BC::x, vf7, vf7, vf7); // vaddx.y vf7, vf7, vf7 + c->vadd_bc(DEST::y, BC::z, vf5, vf5, vf5); // vaddz.y vf5, vf5, vf5 + c->vadd_bc(DEST::y, BC::z, vf6, vf6, vf6); // vaddz.y vf6, vf6, vf6 + c->vadd_bc(DEST::y, BC::z, vf7, vf7, vf7); // vaddz.y vf7, vf7, vf7 + c->mov128_gpr_vf(t1, vf5); // qmfc2.i t1, vf5 + c->mov128_gpr_vf(t2, vf6); // qmfc2.i t2, vf6 + c->mov128_gpr_vf(v1, vf7); // qmfc2.i v1, vf7 + c->or_(t1, t1, t2); // or t1, t1, t2 + c->or_(v1, t1, v1); // or v1, t1, v1 + bc = ((s64)c->sgpr64(v1)) < 0; // bltz v1, L11 + // nop // sll r0, r0, 0 + if (bc) {goto block_10;} // branch non-likely + + c->vopmula(vf14, vf16); // vopmula.xyz acc, vf14, vf16 + c->vopmsub(vf5, vf16, vf14); // vopmsub.xyz vf5, vf16, vf14 + c->vopmula(vf16, vf5); // vopmula.xyz acc, vf16, vf5 + c->vopmsub(vf5, vf5, vf16); // vopmsub.xyz vf5, vf5, vf16 + c->vadd(DEST::xyzw, vf5, vf5, vf12); // vadd.xyzw vf5, vf5, vf12 + c->sqc2(vf5, 0, t0); // sqc2 vf5, 0(t0) + //beq r0, r0, L15 // beq r0, r0, L15 + c->addiu(v0, r0, 0); // addiu v0, r0, 0 + goto block_15; // branch always + + +block_14: + c->lui(v0, -13122); // lui v0, -13122 + c->ori(v0, v0, 48160); // ori v0, v0, 48160 + +block_15: + c->ld(ra, 0, sp); // ld ra, 0(sp) + //jr ra // jr ra + c->daddiu(sp, sp, 16); // daddiu sp, sp, 16 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 +end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + cache.collide_do_primitives = intern_from_c(-1, 0, "collide-do-primitives").c(); + gLinkedFunctionTable.reg("moving-sphere-triangle-intersect", execute, 512); +} + +} // namespace moving_sphere_triangle_intersect +} // namespace Mips2C +// add moving_sphere_triangle_intersect::link to the link callback table for the object file. +// FWD DEC: +namespace moving_sphere_triangle_intersect { extern void link(); } + +//--------------------------MIPS2C--------------------- +// clang-format off +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/jak3/kscheme.h" +using ::jak3::intern_from_c; +namespace Mips2C::jak3 { +namespace collide_do_primitives { +struct Cache { + void* ray_cylinder_intersect; // ray-cylinder-intersect + void* ray_sphere_intersect; // ray-sphere-intersect +} cache; + +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + u32 call_addr = 0; + bool cop1_bc = false; + c->daddiu(sp, sp, -144); // daddiu sp, sp, -144 + c->sd(ra, 0, sp); // sd ra, 0(sp) + c->sq(s1, 32, sp); // sq s1, 32(sp) + c->sq(s2, 48, sp); // sq s2, 48(sp) + c->sq(s3, 64, sp); // sq s3, 64(sp) + c->sq(s4, 80, sp); // sq s4, 80(sp) + c->sq(s5, 96, sp); // sq s5, 96(sp) + c->sq(gp, 112, sp); // sq gp, 112(sp) + c->swc1(f28, 128, sp); // swc1 f28, 128(sp) + c->swc1(f30, 132, sp); // swc1 f30, 132(sp) + c->mov64(s4, a0); // or s4, a0, r0 + c->mov64(s3, a1); // or s3, a1, r0 + c->mov64(s1, a2); // or s1, a2, r0 + c->mov64(s5, a3); // or s5, a3, r0 + c->mov64(gp, t0); // or gp, t0, r0 + c->daddiu(s2, sp, 16); // daddiu s2, sp, 16 + c->lui(v1, 16384); // lui v1, 16384 + c->mtc1(f31, v1); // mtc1 f31, v1 + c->mtc1(f28, r0); // mtc1 f28, r0 + c->load_symbol2(t9, cache.ray_sphere_intersect); // lw t9, ray-sphere-intersect(s7) + c->mov64(a0, s4); // or a0, s4, r0 + c->mov64(a1, s3); // or a1, s3, r0 + c->daddu(a2, r0, s5); // daddu a2, r0, s5 + c->mov64(a3, s1); // or a3, s1, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->sll(v0, ra, 0); // sll v0, ra, 0 + c->jalr(call_addr); // jalr ra, t9 + c->mov64(v1, v0); // or v1, v0, r0 + c->mtc1(f30, v0); // mtc1 f30, v0 + cop1_bc = c->fprs[f30] < c->fprs[f28]; // c.lt.s f30, f28 + bc = cop1_bc; // bc1t L17 + // nop // sll r0, r0, 0 + if (bc) {goto block_2;} // branch non-likely + + c->mtc1(f31, v0); // mtc1 f31, v0 + c->lqc2(vf31, 0, s5); // lqc2 vf31, 0(s5) + +block_2: + c->load_symbol2(t9, cache.ray_sphere_intersect); // lw t9, ray-sphere-intersect(s7) + c->mov64(a0, s4); // or a0, s4, r0 + c->mov64(a1, s3); // or a1, s3, r0 + c->daddiu(a2, s5, 16); // daddiu a2, s5, 16 + c->mov64(a3, s1); // or a3, s1, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->sll(v0, ra, 0); // sll v0, ra, 0 + c->jalr(call_addr); // jalr ra, t9 + c->mov64(v1, v0); // or v1, v0, r0 + c->mtc1(f30, v0); // mtc1 f30, v0 + cop1_bc = c->fprs[f30] < c->fprs[f28]; // c.lt.s f30, f28 + bc = cop1_bc; // bc1t L18 + cop1_bc = c->fprs[f30] < c->fprs[f31]; // c.lt.s f30, f31 + if (bc) {goto block_5;} // branch non-likely + + bc = !cop1_bc; // bc1f L18 + // nop // sll r0, r0, 0 + if (bc) {goto block_5;} // branch non-likely + + c->mtc1(f31, v0); // mtc1 f31, v0 + c->lqc2(vf31, 16, s5); // lqc2 vf31, 16(s5) + +block_5: + c->load_symbol2(t9, cache.ray_sphere_intersect); // lw t9, ray-sphere-intersect(s7) + c->mov64(a0, s4); // or a0, s4, r0 + c->mov64(a1, s3); // or a1, s3, r0 + c->daddiu(a2, s5, 32); // daddiu a2, s5, 32 + c->mov64(a3, s1); // or a3, s1, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->sll(v0, ra, 0); // sll v0, ra, 0 + c->jalr(call_addr); // jalr ra, t9 + c->mov64(v1, v0); // or v1, v0, r0 + c->mtc1(f30, v0); // mtc1 f30, v0 + cop1_bc = c->fprs[f30] < c->fprs[f28]; // c.lt.s f30, f28 + bc = cop1_bc; // bc1t L19 + cop1_bc = c->fprs[f30] < c->fprs[f31]; // c.lt.s f30, f31 + if (bc) {goto block_8;} // branch non-likely + + bc = !cop1_bc; // bc1f L19 + // nop // sll r0, r0, 0 + if (bc) {goto block_8;} // branch non-likely + + c->mtc1(f31, v0); // mtc1 f31, v0 + c->lqc2(vf31, 32, s5); // lqc2 vf31, 32(s5) + +block_8: + c->lqc2(vf1, 0, s5); // lqc2 vf1, 0(s5) + c->lqc2(vf2, 16, s5); // lqc2 vf2, 16(s5) + c->vsub(DEST::xyzw, vf2, vf2, vf1); // vsub.xyzw vf2, vf2, vf1 + c->vmul(DEST::xyzw, vf3, vf2, vf2); // vmul.xyzw vf3, vf2, vf2 + c->vadd_bc(DEST::x, BC::y, vf3, vf3, vf3); // vaddy.x vf3, vf3, vf3 + c->vadd_bc(DEST::x, BC::z, vf3, vf3, vf3); // vaddz.x vf3, vf3, vf3 + c->vrsqrt(vf0, BC::w, vf3, BC::x); // vrsqrt Q, vf0.w, vf3.x + c->mov128_gpr_vf(v1, vf3); // qmfc2.i v1, vf3 + c->mtc1(f30, v1); // mtc1 f30, v1 + c->sqrts(f30, f30); // sqrt.s f30, f30 + c->vwaitq(); // vwaitq + c->vmulq(DEST::xyzw, vf2, vf2); // vmulq.xyzw vf2, vf2, Q + c->sqc2(vf2, 0, s2); // sqc2 vf2, 0(s2) + c->mfc1(t1, f30); // mfc1 t1, f30 + c->load_symbol2(t9, cache.ray_cylinder_intersect);// lw t9, ray-cylinder-intersect(s7) + c->mov64(a0, s4); // or a0, s4, r0 + c->mov64(a1, s3); // or a1, s3, r0 + c->daddu(a2, r0, s5); // daddu a2, r0, s5 + c->mov64(a3, s2); // or a3, s2, r0 + c->mov64(t0, s1); // or t0, s1, r0 + c->mov64(t2, gp); // or t2, gp, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->sll(v0, ra, 0); // sll v0, ra, 0 + c->jalr(call_addr); // jalr ra, t9 + c->mov64(v1, v0); // or v1, v0, r0 + c->mtc1(f30, v0); // mtc1 f30, v0 + cop1_bc = c->fprs[f30] < c->fprs[f28]; // c.lt.s f30, f28 + bc = cop1_bc; // bc1t L20 + cop1_bc = c->fprs[f30] < c->fprs[f31]; // c.lt.s f30, f31 + if (bc) {goto block_11;} // branch non-likely + + bc = !cop1_bc; // bc1f L20 + // nop // sll r0, r0, 0 + if (bc) {goto block_11;} // branch non-likely + + c->mtc1(f31, v0); // mtc1 f31, v0 + c->lqc2(vf31, 0, gp); // lqc2 vf31, 0(gp) + +block_11: + c->lqc2(vf1, 16, s5); // lqc2 vf1, 16(s5) + c->lqc2(vf2, 32, s5); // lqc2 vf2, 32(s5) + c->vsub(DEST::xyzw, vf2, vf2, vf1); // vsub.xyzw vf2, vf2, vf1 + c->vmul(DEST::xyzw, vf3, vf2, vf2); // vmul.xyzw vf3, vf2, vf2 + c->vadd_bc(DEST::x, BC::y, vf3, vf3, vf3); // vaddy.x vf3, vf3, vf3 + c->vadd_bc(DEST::x, BC::z, vf3, vf3, vf3); // vaddz.x vf3, vf3, vf3 + c->vrsqrt(vf0, BC::w, vf3, BC::x); // vrsqrt Q, vf0.w, vf3.x + c->mov128_gpr_vf(v1, vf3); // qmfc2.i v1, vf3 + c->mtc1(f30, v1); // mtc1 f30, v1 + c->sqrts(f30, f30); // sqrt.s f30, f30 + c->vwaitq(); // vwaitq + c->vmulq(DEST::xyzw, vf2, vf2); // vmulq.xyzw vf2, vf2, Q + c->sqc2(vf2, 0, s2); // sqc2 vf2, 0(s2) + c->mfc1(t1, f30); // mfc1 t1, f30 + c->load_symbol2(t9, cache.ray_cylinder_intersect);// lw t9, ray-cylinder-intersect(s7) + c->mov64(a0, s4); // or a0, s4, r0 + c->mov64(a1, s3); // or a1, s3, r0 + c->daddiu(a2, s5, 16); // daddiu a2, s5, 16 + c->mov64(a3, s2); // or a3, s2, r0 + c->mov64(t0, s1); // or t0, s1, r0 + c->mov64(t2, gp); // or t2, gp, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->sll(v0, ra, 0); // sll v0, ra, 0 + c->jalr(call_addr); // jalr ra, t9 + c->mov64(v1, v0); // or v1, v0, r0 + c->mtc1(f30, v0); // mtc1 f30, v0 + cop1_bc = c->fprs[f30] < c->fprs[f28]; // c.lt.s f30, f28 + bc = cop1_bc; // bc1t L21 + cop1_bc = c->fprs[f30] < c->fprs[f31]; // c.lt.s f30, f31 + if (bc) {goto block_14;} // branch non-likely + + bc = !cop1_bc; // bc1f L21 + // nop // sll r0, r0, 0 + if (bc) {goto block_14;} // branch non-likely + + c->mtc1(f31, v0); // mtc1 f31, v0 + c->lqc2(vf31, 0, gp); // lqc2 vf31, 0(gp) + +block_14: + c->lqc2(vf1, 32, s5); // lqc2 vf1, 32(s5) + c->lqc2(vf2, 0, s5); // lqc2 vf2, 0(s5) + c->vsub(DEST::xyzw, vf2, vf2, vf1); // vsub.xyzw vf2, vf2, vf1 + c->vmul(DEST::xyzw, vf3, vf2, vf2); // vmul.xyzw vf3, vf2, vf2 + c->vadd_bc(DEST::x, BC::y, vf3, vf3, vf3); // vaddy.x vf3, vf3, vf3 + c->vadd_bc(DEST::x, BC::z, vf3, vf3, vf3); // vaddz.x vf3, vf3, vf3 + c->vrsqrt(vf0, BC::w, vf3, BC::x); // vrsqrt Q, vf0.w, vf3.x + c->mov128_gpr_vf(v1, vf3); // qmfc2.i v1, vf3 + c->mtc1(f30, v1); // mtc1 f30, v1 + c->sqrts(f30, f30); // sqrt.s f30, f30 + c->vwaitq(); // vwaitq + c->vmulq(DEST::xyzw, vf2, vf2); // vmulq.xyzw vf2, vf2, Q + c->sqc2(vf2, 0, s2); // sqc2 vf2, 0(s2) + c->mfc1(t1, f30); // mfc1 t1, f30 + c->load_symbol2(t9, cache.ray_cylinder_intersect);// lw t9, ray-cylinder-intersect(s7) + c->daddiu(a2, s5, 32); // daddiu a2, s5, 32 + c->mov64(t2, gp); // or t2, gp, r0 + c->mov64(a0, s4); // or a0, s4, r0 + c->mov64(a1, s3); // or a1, s3, r0 + c->mov64(a3, s2); // or a3, s2, r0 + c->mov64(t0, s1); // or t0, s1, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->sll(v0, ra, 0); // sll v0, ra, 0 + c->jalr(call_addr); // jalr ra, t9 + c->mov64(v1, v0); // or v1, v0, r0 + c->mtc1(f30, v0); // mtc1 f30, v0 + cop1_bc = c->fprs[f30] < c->fprs[f28]; // c.lt.s f30, f28 + bc = cop1_bc; // bc1t L22 + cop1_bc = c->fprs[f30] < c->fprs[f31]; // c.lt.s f30, f31 + if (bc) {goto block_17;} // branch non-likely + + bc = !cop1_bc; // bc1f L22 + // nop // sll r0, r0, 0 + if (bc) {goto block_17;} // branch non-likely + + c->mtc1(f31, v0); // mtc1 f31, v0 + c->lqc2(vf31, 0, gp); // lqc2 vf31, 0(gp) + +block_17: + c->lui(v1, 16256); // lui v1, 16256 + c->mtc1(f0, v1); // mtc1 f0, v1 + c->lui(v1, -13122); // lui v1, -13122 + c->ori(v1, v1, 48160); // ori v1, v1, 48160 + cop1_bc = c->fprs[f0] < c->fprs[f31]; // c.lt.s f0, f31 + if (cop1_bc) { // bc1tl L23 + c->mtc1(f31, v1); // mtc1 f31, v1 + goto block_19; + } + +block_19: + c->mfc1(v0, f31); // mfc1 v0, f31 + c->sqc2(vf31, 0, gp); // sqc2 vf31, 0(gp) + c->ld(ra, 0, sp); // ld ra, 0(sp) + c->lwc1(f30, 132, sp); // lwc1 f30, 132(sp) + c->lwc1(f28, 128, sp); // lwc1 f28, 128(sp) + c->lq(gp, 112, sp); // lq gp, 112(sp) + c->lq(s5, 96, sp); // lq s5, 96(sp) + c->lq(s4, 80, sp); // lq s4, 80(sp) + c->lq(s3, 64, sp); // lq s3, 64(sp) + c->lq(s2, 48, sp); // lq s2, 48(sp) + c->lq(s1, 32, sp); // lq s1, 32(sp) + //jr ra // jr ra + c->daddiu(sp, sp, 144); // daddiu sp, sp, 144 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 +end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + cache.ray_cylinder_intersect = intern_from_c(-1, 0, "ray-cylinder-intersect").c(); + cache.ray_sphere_intersect = intern_from_c(-1, 0, "ray-sphere-intersect").c(); + gLinkedFunctionTable.reg("collide-do-primitives", execute, 512); +} + +} // namespace collide_do_primitives +} // namespace Mips2C +// add collide_do_primitives::link to the link callback table for the object file. +// FWD DEC: +namespace collide_do_primitives { extern void link(); } \ No newline at end of file diff --git a/goal_src/jak1/engine/anim/joint.gc b/goal_src/jak1/engine/anim/joint.gc index f22939e728..c91a6acbae 100644 --- a/goal_src/jak1/engine/anim/joint.gc +++ b/goal_src/jak1/engine/anim/joint.gc @@ -8,6 +8,491 @@ ;; a joint is just used to store the tree structure of a skeleton + bind pose. ;; it's mostly used as a more user-friendly interface +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; experimental new joint decompressor +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define *use-new-decompressor* #t) + +;; this was re-written in GOAL. Despite being not well optimized, it ends up being faster +;; than the original. + +;; 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) + ) + ) + +(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!" + + ;; 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)) + (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) + + (('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. + (('blend 'push1) + (let* ((sf (-> this blend-stack (- stack-top 1))) ;; modify most recent stack frame + (new-weight (-> chan 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. + (('stack) + (let* ((sf0 (-> this blend-stack (- stack-top 1))) + (sf1 (-> this blend-stack (- stack-top 2))) + (weight0 (-> chan 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))) + (dotimes (chan-idx num-channels) + (set! (-> jc channel chan-idx inspector-amount) (-> 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))) + (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 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 + (matrix-copy! (-> output-frame matrices 0) (the matrix data64)) + (&+! data64 64) + ) + + (when (zero? (logand mbits 2)) + ;; matrix comes from fixed data + (matrix-copy! (-> output-frame matrices 1) (the matrix data64)) + (&+! 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)) + (tq (-> (the (inline-array transformq) (-> 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 + (matrix-copy! (-> output-frame matrices 0) (the matrix data64)) + (&+! data64 64) + ) + + (when (nonzero? (logand mbits 2)) + ;; matrix comes from fixed data + (matrix-copy! (-> output-frame matrices 1) (the matrix data64)) + (&+! 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)) + (tq (-> (the (inline-array transformq) (-> 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" + + ;; 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 (-> (the (inline-array transformq) (-> output-frame data)) tqi))) + (set! (-> tq trans w) 1.0) + (set! (-> tq scale w) 1.0) + (quaternion-normalize! (-> tq quat)) + ) + ) + (none) + ) + + ;; DECOMP BEGINS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -975,6 +1460,7 @@ (defun matrix-from-control! ((arg0 matrix-stack) (arg1 joint) (arg2 joint-control) (arg3 symbol)) (set! (-> arg0 top) (the-as matrix (-> arg0 data))) + ;(set! arg3 'a) (dotimes (s2-0 (-> arg2 active-channels)) (let* ((a2-1 (-> arg2 channel s2-0)) (v1-4 (-> a2-1 command)) @@ -1006,6 +1492,7 @@ ((= v1-4 'push) (matrix-from-control-channel! (-> arg0 top) arg1 a2-1) (set! (-> arg0 top) (the-as matrix (+ (the-as uint (-> arg0 top)) s1-0))) + ;(return (-> arg0 data 0)) ) ((or (= v1-4 'blend) (= v1-4 'push1)) (matrix-from-control-pair! @@ -1456,8 +1943,17 @@ (def-mips2c calc-animation-from-spr (function (inline-array vector) int none)) (defun create-interpolated-joint-animation-frame ((arg0 (inline-array vector)) (arg1 int) (arg2 process-drawable)) - (flatten-joint-control-to-spr (-> arg2 skel)) - (make-joint-jump-tables) - (calc-animation-from-spr arg0 arg1) + + (cond + (*use-new-decompressor* + (new-joint-decompressor (the joint-anim-frame arg0) arg1 (-> arg2 skel)) + ) + (else + (flatten-joint-control-to-spr (-> arg2 skel)) + (make-joint-jump-tables) + (calc-animation-from-spr arg0 arg1) + ) + ) + 0 ) diff --git a/goal_src/jak1/engine/ps2/timer.gc b/goal_src/jak1/engine/ps2/timer.gc index 3ba7663e56..54b1fa82e3 100644 --- a/goal_src/jak1/engine/ps2/timer.gc +++ b/goal_src/jak1/engine/ps2/timer.gc @@ -181,7 +181,7 @@ ) ) -(defglobalconstant EE_SECONDS_PER_TICK (/ 1.0 3000000)) ;; 300MHz is a "decent enough" estimate +(defglobalconstant EE_SECONDS_PER_TICK (/ 1.0 300000000)) ;; 300MHz is a "decent enough" estimate (defmacro cpu-ticks-to-seconds (ticks) `(* ,EE_SECONDS_PER_TICK ,ticks) ) diff --git a/goal_src/jak2/engine/anim/joint.gc b/goal_src/jak2/engine/anim/joint.gc index c9c09432b6..bbf88d1532 100644 --- a/goal_src/jak2/engine/anim/joint.gc +++ b/goal_src/jak2/engine/anim/joint.gc @@ -8,6 +8,512 @@ (define-extern create-interpolated-joint-animation-frame (function joint-anim-frame int joint-control int)) (define-extern *anim-manager* art-joint-anim-manager) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; experimental new joint decompressor +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define *use-new-decompressor* #t) + +;; this was re-written in GOAL. Despite being not well optimized, it ends up being faster +;; than the original when decompiled with MIPS2C. + +;; request to decompress data from an animation +(deftype joint-decomp-request (structure) + ((jacc joint-anim-compressed-control) + (frame int) + (frame-interp float) + (amount float)) + ) + +(deftype blend-tree-stack-frame (structure) + ((weights float 24) + (quads vector 6 :inline :overlay-at weights)) + ) + +(deftype new-joint-decompressor-work (structure) + ((requests joint-decomp-request 24 :inline) + (num-requests int32) + (blend-stack blend-tree-stack-frame 4 :inline) + ) + (:methods + (eval-blend-tree! (_type_ joint-control) none) + (output-blend-tree! (_type_ joint-control) none) + (build-requests! (_type_ joint-control) none) + (init-frame! (_type_ joint-anim-frame int) none) + (process-request! (_type_ joint-decomp-request joint-anim-frame int) none) + (process-requests! (_type_ joint-anim-frame int) none) + (finalize-frame! (_type_ joint-anim-frame int) none) + ) + ) + +(deftype new-joint-decompressor-stats (structure) + ((num-calls int32) + (num-anims int32) + (num-joints int32) + (total-time int32) + ) + (:methods + (reset! (_type_) none) + ) + ) + +(defmethod reset! ((this new-joint-decompressor-stats)) + (set! (-> this num-calls) 0) + (set! (-> this num-anims) 0) + (set! (-> this num-joints) 0) + (set! (-> this total-time) 0) + (none) + ) + +(define *new-joint-decompressor-stats* (new 'global 'new-joint-decompressor-stats)) +(define *new-joint-decompressor-work* (new 'global 'new-joint-decompressor-work)) + +(defun new-joint-decompressor ((dst joint-anim-frame) (num-joints int) (jc joint-control)) + "Decompress a joint animation!" + (+! (-> *new-joint-decompressor-stats* num-calls) 1) + ;; determine anim weights, write them out to the joint-control for other stuff to see. + (eval-blend-tree! *new-joint-decompressor-work* jc) + (output-blend-tree! *new-joint-decompressor-work* jc) + + ;; figure out which animations need decompression + (build-requests! *new-joint-decompressor-work* jc) + + ;; run the decompression + (init-frame! *new-joint-decompressor-work* dst num-joints) + (process-requests! *new-joint-decompressor-work* dst num-joints) + (finalize-frame! *new-joint-decompressor-work* dst num-joints) + + (none) + ) + +(defmethod eval-blend-tree! ((this new-joint-decompressor-work) (jc joint-control)) + "Evaluate weights of all channels, producing the final per-animation weights in the first stack-frame." + + (let ((num-channels (+ (-> jc active-channels) (-> jc float-channels))) + (stack-top 0) + ) + (when (> num-channels 24) + (break!) ;; insufficient weights per stack frame + ) + + ;; loop over channels + (dotimes (chan-idx num-channels) + (let ((chan (-> jc channel chan-idx))) + (case (-> chan command) + + (((joint-control-command push)) ;; push new anim to stack frame + (when (> stack-top 4) + (break!) ;; insufficient stack frames. + ) + + ;; init all weights to zero: + (let ((new-frame (-> this blend-stack stack-top))) + (vector-zero! (-> new-frame quads 0)) + (vector-zero! (-> new-frame quads 1)) + (vector-zero! (-> new-frame quads 2)) + (vector-zero! (-> new-frame quads 3)) + (vector-zero! (-> new-frame quads 4)) + (vector-zero! (-> new-frame quads 5)) + ;; except for this channel + (set! (-> new-frame weights chan-idx) 1.0) + ) + (+! stack-top 1) ;; bump stack pointer! + ) + + ;; blend case: note that push1/stack1 always are a pair, so we can treat push1 as blend and ignore + ;; the stack1 as an optimization. + (((joint-control-command blend) (joint-control-command push1) (joint-control-command float)) + (let* ((sf (-> this blend-stack (- stack-top 1))) ;; modify most recent stack frame + (new-weight (-> chan frame-interp (-> jc active-frame-interp))) + (old-weight (- 1.0 new-weight))) + + ;; do the multiplies: + (rlet ((temp :class vf) + (weight-vec :class vf)) + (.mov weight-vec old-weight) + (dotimes (i 6) + (.lvf temp (&-> sf quads i quad)) + (.mul.x.vf temp temp weight-vec) + (.svf (&-> sf quads i quad) temp) + ) + (+! (-> sf weights chan-idx) new-weight) + ) + ) + ) + + ;; stack case: pop two frames, add together, push result. + (((joint-control-command stack)) + (let* ((sf0 (-> this blend-stack (- stack-top 1))) + (sf1 (-> this blend-stack (- stack-top 2))) + (weight0 (-> chan frame-interp (-> jc active-frame-interp))) + (weight1 (- 1.0 weight0))) + + + (rlet ((temp0 :class vf) + (temp1 :class vf) + (weight0-vec :class vf) + (weight1-vec :class vf)) + (.mov weight0-vec weight0) + (.mov weight1-vec weight1) + (dotimes (i 6) + (.lvf temp0 (&-> sf0 quads i quad)) + (.lvf temp1 (&-> sf1 quads i quad)) + (.mul.x.vf temp0 temp0 weight0-vec) + (.mul.x.vf temp1 temp1 weight1-vec) + (.add.vf temp0 temp0 temp1) + (.svf (&-> sf1 quads i quad) temp0) + ) + ) + (-! stack-top 1) ;; pop stack frame + ) + ) + + ) + ) + ) + ) + + (none) + ) + +(defmethod output-blend-tree! ((this new-joint-decompressor-work) (jc joint-control)) + "Copy result of the blend tree evaluation into the joint-control." + (let ((num-channels (+ (-> jc active-channels) (-> jc float-channels)))) + (dotimes (chan-idx num-channels) + (set! (-> jc channel chan-idx inspector-amount) + (the int (* 255.0 (-> this blend-stack 0 weights chan-idx)))) + ) + ) + (none) + ) + +(defmethod build-requests! ((this new-joint-decompressor-work) (jc joint-control)) + "Use the anim weights computed by eval-blend-tree! to build decompression requests" + + (set! (-> this num-requests) 0) + + (let ((num-channels (+ (-> jc active-channels) (-> jc float-channels)))) + (dotimes (chan-idx num-channels) + (let ((weight (-> this blend-stack 0 weights chan-idx)) + (chan (-> jc channel chan-idx))) + (when (> weight 0.001) ;; only both if weight is nonzero + (let* ((req (-> this requests (-> this num-requests))) ;; request to create + (jacc (-> chan frame-group frames)) ;; compressed animation + (frame-num (-> chan frame-num)) ;; floating-point frame (eg 1.23) + (base-frame (the int frame-num)) ;; integer round-down frame (eg 1) + (frac-frame (- frame-num (the float base-frame))) ;; interp to next frame (eg 0.23) + (last-frame (the int (- (-> jacc num-frames) 1))) + ) + (+! (-> this num-requests) 1) + + ;; check our frame group is valid + ;; TODO + + ;; make sure we didn't go off the end of the animation: + (when (>= base-frame last-frame) + (set! frac-frame 0.0) + (set! base-frame last-frame) + ) + + ;; set up request + (set! (-> req jacc) jacc) + (set! (-> req frame) base-frame) + (set! (-> req frame-interp) frac-frame) + (set! (-> req amount) weight) + ) + ) + ) + ) + ) + (none) + ) + +(defmethod init-frame! ((this new-joint-decompressor-work) (output-frame joint-anim-frame) (num-joints int)) + "Initialize an output frame by zeroing the data." + (let ((num-qwc 8) ;; 2x matrix, each 4 qw + (data (the (pointer uint128) output-frame))) + (when (> num-joints 2) ;; we have transformq's + (+! num-qwc (* 3 (- num-joints 2))) + ) + + (let ((data-end (&+ data (* num-qwc 16)))) + (rlet ((zero :class vf)) + (.xor.vf zero zero zero) + (while (!= data data-end) ;; this loop is 5 instructions :) + (.svf data zero) + (&+! data 16) + ) + ) + ) + + ) + (none) + ) + +(defmethod process-requests! ((this new-joint-decompressor-work) (output-frame joint-anim-frame) (num-joints int)) + "Decompress all pending animation requests." + (dotimes (i (-> this num-requests)) + (process-request! this (-> this requests i) output-frame num-joints) + ) + (set! (-> this num-requests) 0) + (none) + ) + +(defmacro fderef-s16 (ptr) + `(the float (-> (the (pointer int16) ,ptr))) + ) + +(defmacro deref-f32 (ptr) + `(-> (the (pointer float) ,ptr)) + ) + +(defconstant QUAT_SCALE 0.000030517578125) +(defconstant SCALE_SCALE 0.000244140625) + +(defun 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 + (matrix-copy! (-> output-frame matrices 0) (the matrix data64)) + (&+! data64 64) + ) + + (when (zero? (logand mbits 2)) + ;; matrix comes from fixed data + (matrix-copy! (-> output-frame matrices 1) (the matrix data64)) + (&+! 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 + (matrix-copy! (-> output-frame matrices 0) (the matrix data64)) + (&+! data64 64) + ) + + (when (nonzero? (logand mbits 2)) + ;; matrix comes from fixed data + (matrix-copy! (-> output-frame matrices 1) (the matrix data64)) + (&+! data64 64) + ) + + ;; process tq's + (dotimes (tqi num-joints) ;; TODO - not sure if this is too many?? + (let* ((ctrl-idx (/ tqi 8)) + (ctrl-shift (* 4 (mod tqi 8))) + (ctrl (logand #b1111 (sar (-> ctrl-ptr ctrl-idx) ctrl-shift))) + (tq (-> output-frame data tqi)) + ) + + ;; TRANS + (when (nonzero? (logand ctrl #b0001)) + ;; we have trans + (cond + ((nonzero? (logand ctrl #b1000)) + ;; big trans + (+! (-> tq trans x) (* amount (deref-f32 data64))) + (&+! data64 4) + (+! (-> tq trans y) (* amount (deref-f32 data64))) + (&+! data64 4) + (+! (-> tq trans z) (* amount (deref-f32 data32))) + (&+! data32 4) + ) + (else + ;; little trans + (+! (-> tq trans x) (* amount (fderef-s16 data32) 4.)) + (&+! data32 2) + (+! (-> tq trans y) (* amount (fderef-s16 data32) 4.)) + (&+! data32 2) + (+! (-> tq trans z) (* amount (fderef-s16 data16) 4.)) + (&+! data16 2) + ) + ) + ) + ;; QUAT + (when (nonzero? (logand ctrl #b0010)) + (let ((temp (new 'stack-no-clear 'vector))) + + (set! (-> temp x) (fderef-s16 data64)) (&+! data64 2) + (set! (-> temp y) (fderef-s16 data64)) (&+! data64 2) + (set! (-> temp z) (fderef-s16 data64)) (&+! data64 2) + (set! (-> temp w) (fderef-s16 data64)) (&+! data64 2) + + (let ((dot (+ (* (-> temp x) (-> tq quat x)) + (* (-> temp y) (-> tq quat y)) + (* (-> temp z) (-> tq quat z)) + (* (-> temp w) (-> tq quat w))))) + (when (< dot 0.0) + (*! (-> temp x) -1.) + (*! (-> temp y) -1.) + (*! (-> temp z) -1.) + (*! (-> temp w) -1.) + ) + (+! (-> tq quat x) (* amount (-> temp x) QUAT_SCALE)) + (+! (-> tq quat y) (* amount (-> temp y) QUAT_SCALE)) + (+! (-> tq quat z) (* amount (-> temp z) QUAT_SCALE)) + (+! (-> tq quat w) (* amount (-> temp w) QUAT_SCALE)) + ) + ) + ) + ;; SCALE + (when (nonzero? (logand ctrl #b0100)) + (+! (-> tq scale x) (* amount (fderef-s16 data32) SCALE_SCALE)) + (&+! data32 2) + (+! (-> tq scale y) (* amount (fderef-s16 data32) SCALE_SCALE)) + (&+! data32 2) + (+! (-> tq scale z) (* amount (fderef-s16 data16) SCALE_SCALE)) + (&+! data16 2) + ) + ) + ) + ) + + (none) + ) + +(defmethod process-request! ((this new-joint-decompressor-work) (request joint-decomp-request) (output-frame joint-anim-frame) (num-joints int)) + "Decompress a single animation, adding to accumulator" + + (+! (-> *new-joint-decompressor-stats* num-anims) 1) + (+! (-> *new-joint-decompressor-stats* num-joints) (+ num-joints 2)) + + + ;; first, the fixed part + (decomp-fixed output-frame num-joints (-> request jacc fixed) (-> request amount)) + + ;; base frame + (decomp-frame + output-frame + num-joints + (-> request jacc data (-> request frame)) + (* (- 1.0 (-> request frame-interp)) (-> request amount)) + (-> request jacc fixed hdr) + ) + + ;; interpolate to next frame + (cond + ((!= 0.0 (-> request frame-interp)) + (decomp-frame + output-frame + num-joints + (-> request jacc data (+ 1 (-> request frame))) + (* (-> request frame-interp) (-> request amount)) + (-> request jacc fixed hdr)) + ) + (else + ) + ) + + (none) + ) + +(defmethod finalize-frame! ((this new-joint-decompressor-work) (output-frame joint-anim-frame) (num-joints int)) + (when (<= num-joints 2) + (return #f) + ) + + (dotimes (tqi (- num-joints 2)) + (let ((tq (-> output-frame data tqi))) + (set! (-> tq trans w) 1.0) + (set! (-> tq scale w) 1.0) + (quaternion-normalize! (-> tq quat)) + ) + ) + (none) + ) + + ;; DECOMP BEGINS (defmethod print ((this joint)) @@ -1537,10 +2043,25 @@ (def-mips2c calc-animation-from-spr (function joint-anim-frame int none)) -(defun create-interpolated-joint-animation-frame ((arg0 joint-anim-frame) (arg1 int) (arg2 joint-control)) - (flatten-joint-control-to-spr arg2) - (make-joint-jump-tables) - (calc-animation-from-spr arg0 arg1) + +(defun create-interpolated-joint-animation-frame ((output-frame joint-anim-frame) (arg1 int) (arg2 joint-control)) + (let ((start (get-cpu-clock))) + (cond + (*use-new-decompressor* + + (new-joint-decompressor output-frame arg1 arg2) + + ) + (else + (flatten-joint-control-to-spr arg2) + (make-joint-jump-tables) + (calc-animation-from-spr output-frame arg1) + ) + ) + (+! (-> *new-joint-decompressor-stats* total-time) + (the int (* 1000000. (cpu-ticks-to-seconds (- (get-cpu-clock) start)))) + ) + ) 0 ) @@ -1549,9 +2070,10 @@ (return (create-interpolated-joint-animation-frame arg0 arg1 arg2)) ) (set! (-> arg2 active-frame-interp) (the-as uint 1)) - (flatten-joint-control-to-spr arg2) - (make-joint-jump-tables) - (calc-animation-from-spr arg0 arg1) + (create-interpolated-joint-animation-frame arg0 arg1 arg2) + ;(flatten-joint-control-to-spr arg2) + ;(make-joint-jump-tables) + ;(calc-animation-from-spr arg0 arg1) ;; happens during gun stuff, seems to work. ; (format 0 "create-interpolated2-joint-animation-frame: untested copy~%") (ultimate-memcpy (the-as pointer *gsf-buffer*) (the-as pointer arg0) (the-as uint (+ (* 48 arg1) 128))) @@ -1562,9 +2084,11 @@ ; #f ; ) (set! (-> arg2 active-frame-interp) (the-as uint 0)) - (flatten-joint-control-to-spr arg2) - (make-joint-jump-tables) - (calc-animation-from-spr arg0 arg1) + ;(flatten-joint-control-to-spr arg2) + ;(make-joint-jump-tables) + ;;(calc-animation-from-spr arg0 arg1) + (create-interpolated-joint-animation-frame arg0 arg1 arg2) + (let ((v1-9 (the-as joint-anim-frame *gsf-buffer*))) (let ((a0-8 (-> arg2 interp-select 0))) (dotimes (a1-5 2) diff --git a/goal_src/jak2/engine/debug/default-menu.gc b/goal_src/jak2/engine/debug/default-menu.gc index d3e25cbab3..76a58f07ac 100644 --- a/goal_src/jak2/engine/debug/default-menu.gc +++ b/goal_src/jak2/engine/debug/default-menu.gc @@ -3501,6 +3501,7 @@ (flag "Blerc" *stats-blerc* dm-boolean-toggle-pick-func) (flag "Profile bars" *stats-profile-bars* dm-boolean-toggle-pick-func) (flag "Perf" *stats-perf* dm-boolean-toggle-pick-func) + (flag "Joint" *stats-joint* dm-boolean-toggle-pick-func) (menu "Memory Stats" (flag "Enable" *stats-memory* dm-boolean-toggle-pick-func) diff --git a/goal_src/jak2/engine/draw/drawable.gc b/goal_src/jak2/engine/draw/drawable.gc index 589bede23e..0114095d72 100644 --- a/goal_src/jak2/engine/draw/drawable.gc +++ b/goal_src/jak2/engine/draw/drawable.gc @@ -1647,6 +1647,14 @@ (if (and (!= *master-mode* 'menu) *stats-collide*) (print-collide-stats) ) + (when (and (!= *master-mode* 'menu) *stats-joint*) + (format *stdcon* "joint calls: ~D~%" (-> *new-joint-decompressor-stats* num-calls)) + (format *stdcon* "joint anims: ~D~%" (-> *new-joint-decompressor-stats* num-anims)) + (format *stdcon* "joint joints: ~D~%" (-> *new-joint-decompressor-stats* num-joints)) + (format *stdcon* "joint time us: ~D~%" (-> *new-joint-decompressor-stats* total-time)) + + (reset! *new-joint-decompressor-stats*) + ) ) (start-perf-stat-collection) diff --git a/goal_src/jak2/engine/game/main-h.gc b/goal_src/jak2/engine/game/main-h.gc index 227674b856..ea6a9fc2e6 100644 --- a/goal_src/jak2/engine/game/main-h.gc +++ b/goal_src/jak2/engine/game/main-h.gc @@ -124,6 +124,9 @@ (define-extern set-blackout-frames (function time-frame none)) +;; added + +(define *stats-joint* #f) ;; DECOMP BEGINS diff --git a/goal_src/jak2/engine/math/matrix-h.gc b/goal_src/jak2/engine/math/matrix-h.gc index ff126f2584..a92bc473a0 100644 --- a/goal_src/jak2/engine/math/matrix-h.gc +++ b/goal_src/jak2/engine/math/matrix-h.gc @@ -47,6 +47,7 @@ (defun matrix-copy! ((arg0 matrix) (arg1 matrix)) "Copy arg1 to arg0" + (declare (inline)) (let ((v1-0 (-> arg1 quad 0)) (a2-0 (-> arg1 quad 1)) (a3-0 (-> arg1 quad 2)) diff --git a/goal_src/jak2/engine/ps2/timer.gc b/goal_src/jak2/engine/ps2/timer.gc index b925d661fd..5182b7f1cc 100644 --- a/goal_src/jak2/engine/ps2/timer.gc +++ b/goal_src/jak2/engine/ps2/timer.gc @@ -171,7 +171,7 @@ ) ) -(defglobalconstant EE_SECONDS_PER_TICK (/ 1.0 3000000)) ;; 300MHz is a "decent enough" estimate +(defglobalconstant EE_SECONDS_PER_TICK (/ 1.0 300000000)) ;; 300MHz is a "decent enough" estimate (defmacro cpu-ticks-to-seconds (ticks) `(* ,EE_SECONDS_PER_TICK ,ticks) ) diff --git a/goal_src/jak3/engine/anim/joint-h.gc b/goal_src/jak3/engine/anim/joint-h.gc index 46cc6d7612..63ca28b161 100644 --- a/goal_src/jak3/engine/anim/joint-h.gc +++ b/goal_src/jak3/engine/anim/joint-h.gc @@ -108,13 +108,13 @@ Multiple channels are used to blend animations together." (interp-select int64 2) (top-anim top-anim-joint-control) (override (array float)) - (channel joint-control-channel :dynamic) + (channel joint-control-channel :inline :dynamic) ) (:methods - (new (symbol type) _type_) + (new (symbol type int) _type_) (joint-control-method-9 () none) (joint-control-method-10 () none) - (joint-control-method-11 () none) + (debug-print-channels (_type_ symbol) int) (joint-control-method-12 () none) ) ) diff --git a/goal_src/jak3/engine/anim/joint.gc b/goal_src/jak3/engine/anim/joint.gc index 1118367fc2..523d83f2d5 100644 --- a/goal_src/jak3/engine/anim/joint.gc +++ b/goal_src/jak3/engine/anim/joint.gc @@ -5,5 +5,2512 @@ ;; 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 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 + (matrix-copy! (-> output-frame matrices 0) (the matrix data64)) + (&+! data64 64) + ) + + (when (zero? (logand mbits 2)) + ;; matrix comes from fixed data + (matrix-copy! (-> output-frame matrices 1) (the matrix data64)) + (&+! 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 + (matrix-copy! (-> output-frame matrices 0) (the matrix data64)) + (&+! data64 64) + ) + + (when (nonzero? (logand mbits 2)) + ;; matrix comes from fixed data + (matrix-copy! (-> output-frame matrices 1) (the matrix data64)) + (&+! 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 "#") + (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) (load-buffer-mode medium)) + ) + (cond + ((and s5-1 (= (-> s5-1 name) 'default) (not *print-login*)) + (format + 0 + "ERROR: illegal login of art ~A (in level ~A) to level ~A~%" + this + (get-level-by-heap-ptr-and-status *level* (the-as pointer this) 'loading) + s5-1 + ) + (break!) + 0 + ) + ((or (not s5-1) (= (-> s5-1 name) 'default)) + ) + ((!= (get-level-by-heap-ptr-and-status *level* (the-as pointer this) 'loading) s5-1) + (format + 0 + "ERROR: illegal login of art ~A (in level ~A) to level ~A~%" + this + (get-level-by-heap-ptr-and-status *level* (the-as pointer this) 'loading) + s5-1 + ) + (break!) + 0 + ) + ) + (when (or (not s5-1) (= (-> s5-1 name) 'default)) + ;; 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)) + ) + (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) + #t + ) + ) + ) + ) + (none) + ) + +(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 rvec))) + (t2-0 (the-as (inline-array vector) (-> v1-9 matrices a1-5 rvec))) + (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 "#") + (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) diff --git a/goal_src/jak3/engine/collide/collide-func.gc b/goal_src/jak3/engine/collide/collide-func.gc index 79ab86de41..20426631c5 100644 --- a/goal_src/jak3/engine/collide/collide-func.gc +++ b/goal_src/jak3/engine/collide/collide-func.gc @@ -5,5 +5,401 @@ ;; name in dgo: collide-func ;; dgos: GAME -;; DECOMP BEGINS +;; Note: this file is entirely identical from jak 2 and copied from there - +;; this is heavily modified from the original implementation and this shouldn't be updated by the decompiler. +#|@file +This file contains the primitive intersection functions used for collision. +Most take a description of primitive and a "probe" +The probe has an origin and a direction. The length of the direction vector is the length +of the probe. + +Generally, collision functions will return the fraction of the probe to reach the primitive. +For example, if the probe is 5.0 long, and hits the primitive 2.0 away from the probe origin, +the return value (u) would be 0.4. + +If (u) would be > 1.0, then it counts as "not intersecting" (object too far away) +If (u) would be < 0.0, then it counts as "not intersecting" (object behind probe) +If there's a miss, return COLLISION_MISS, a large negative number. +If we are inside of the primitive, return 0.0 +|# + +(defconstant COLLISION_MISS -100000000.0) + + +(defun raw-ray-sphere-intersect ((arg0 float)) + "DANGER: this function takes two arguments by vf registers. + As a result, it doesn't work properly in OpenGOAL. See the functions below." + (local-vars + (v1-1 float) + (v1-2 float) + (v1-4 number) + (a0-1 float) + (a0-2 float) + (a0-3 int) + (a1-0 float) + ) + (crash!) + (rlet ((Q :class vf) + (vf0 :class vf) + (vf1 :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) + ) + (init-vf0-vector) + (.mov vf3 arg0) ;; vf3 = radius + ;; sphere is at the origin, vf1 is source of the ray (o) + ;; vf2 is the ray's unit vector (u) + (.mul.vf vf4 vf2 vf2) ;; vf4 = u.^2 + (.mul.vf vf3 vf3 vf3) ;; vf3 = r^2 + (.mul.vf vf6 vf1 vf1) ;; vf6 = o.^2 + (.mul.vf vf5 vf2 vf1) ;; vf5 = u . o + (.add.y.vf vf4 vf4 vf4 :mask #b1) + (let ((result (the-as float 0))) + (.add.x.vf vf6 vf6 vf6 :mask #b10) + (.sub.x.vf vf6 vf6 vf3 :mask #b100) + (.add.z.vf vf4 vf4 vf4 :mask #b1) + (.add.x.vf vf5 vf5 vf5 :mask #b10) + (let ((v1-0 (the-as float 0))) + (.add.z.vf vf6 vf6 vf6 :mask #b10) + (.div.vf Q vf0 vf4 :fsf #b11 :ftf #b0) + (.add.z.vf vf5 vf5 vf5 :mask #b10) + (.mov a0-1 vf4) + (.mul.x.vf vf7 vf6 vf4) + (.mov a1-0 vf6) + (.mul.vf vf8 vf5 vf5) + (b! (< (the-as int a1-0) 0) cfg-7 :delay (set! a0-2 a0-1)) + (.mul.vf vf4 vf0 Q :mask #b1000) + (.sub.vf vf9 vf8 vf7) + (b! (= a0-2 v1-0) cfg-6 :delay (.mov v1-1 vf5)) + ) + (.sqrt.vf Q vf9 :ftf #b1) + (b! (>= (the-as int v1-1) 0) cfg-6 :delay (.mov v1-2 vf9)) + (b! (< (the-as int v1-2) 0) cfg-6 :delay 1.0) + (.add.x.vf vf6 vf5 vf4) + (.mov v1-4 vf6) + (.mul.vf vf6 vf6 vf6) + (.mul.vf vf9 vf0 Q :mask #b1000) + (.sub.vf vf6 vf9 vf6) + (.add.w.vf vf9 vf5 vf9 :mask #b10) + (.mov a0-3 vf6) + (.mul.w.vf vf9 vf9 vf4 :mask #b10) + (b! + (< (logand (the-as uint v1-4) (the-as uint a0-3)) 0) + cfg-6 + :delay + (.sub.y.vf vf4 vf0 vf9) + ) + (b! #t cfg-7 :delay (.mov result vf4)) + (label cfg-6) + (set! result -100000000.0) + (label cfg-7) + (the-as float result) + ) + ) + ) + +(defmacro pc-port-do-raw-ray-sphere-intersect (rad vf1-val vf2-val) + "Calls to raw-ray-sphere-intersect should be replaced with this macro, + and this should be given vf1, vf2, which contain the origin and direction of the probe." + `(let ((vf1-storage (new 'stack-no-clear 'vector)) + (vf2-storage (new 'stack-no-clear 'vector)) + ) + (.svf (&-> vf1-storage quad) ,vf1-val) + (.svf (&-> vf2-storage quad) ,vf2-val) + (pc-port-raw-ray-sphere-implementation ,rad vf1-storage vf2-storage) + ) + ) + + +(defun pc-port-raw-ray-sphere-implementation ((rad float) (vf1-val vector) (vf2-val vector)) + "This is one of the main primitives for collision. + Assumes a sphere of radius rad is at the origin. + Handles: + - miss (return MISS) + - behind (return MISS) + - too far away (return MISS) + - inside (return 0) + " + (local-vars + (v1-1 int) + (v1-2 int) + (v1-4 int) + (a0-1 float) + (a0-2 float) + (a0-3 int) + (a1-0 int) + ) + (rlet ((Q :class vf) + (vf0 :class vf) + (vf1 :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) + ) + (init-vf0-vector) + (.lvf vf1 (&-> vf1-val quad)) + (.lvf vf2 (&-> vf2-val quad)) + (.mov vf3 rad) + (.mul.vf vf4 vf2 vf2) + (.mul.vf vf3 vf3 vf3) + (.mul.vf vf6 vf1 vf1) + (.mul.vf vf5 vf2 vf1) + (.add.y.vf vf4 vf4 vf4 :mask #b1) + (let ((result (the-as float 0))) + (.add.x.vf vf6 vf6 vf6 :mask #b10) + (.sub.x.vf vf6 vf6 vf3 :mask #b100) + (.add.z.vf vf4 vf4 vf4 :mask #b1) + (.add.x.vf vf5 vf5 vf5 :mask #b10) + (let ((v1-0 (the-as float 0))) + (.add.z.vf vf6 vf6 vf6 :mask #b10) + (.div.vf Q vf0 vf4 :fsf #b11 :ftf #b0) + (.add.z.vf vf5 vf5 vf5 :mask #b10) + (.mov a0-1 vf4) + (.mul.x.vf vf7 vf6 vf4) + (.mov a1-0 vf6) + (.mul.vf vf8 vf5 vf5) + (b! (< (the-as int a1-0) 0) cfg-7 :delay (set! a0-2 a0-1)) ;; in the sphere + (.mul.vf vf4 vf0 Q :mask #b1000) + (.sub.vf vf9 vf8 vf7) + (b! (= a0-2 v1-0) cfg-6 :delay (.mov v1-1 vf5)) ;; bad denominator in division + ) + (.sqrt.vf Q vf9 :ftf #b1) + (b! (>= (the-as int v1-1) 0) cfg-6 :delay (.mov v1-2 vf9)) ;; wrong dir + (b! (< (the-as int v1-2) 0) cfg-6 :delay 1.0) ;; bad sqrt + (.add.x.vf vf6 vf5 vf4) + (.mov v1-4 vf6) + (.mul.vf vf6 vf6 vf6) + (.mul.vf vf9 vf0 Q :mask #b1000) + (.sub.vf vf6 vf9 vf6) + (.add.w.vf vf9 vf5 vf9 :mask #b10) + (.mov a0-3 vf6) + (.mul.w.vf vf9 vf9 vf4 :mask #b10) + + ;; too far. + (b! (< (logand (the-as int v1-4) (the-as int a0-3)) 0) + cfg-6 + :delay (.sub.y.vf vf4 vf0 vf9) + ) + (b! #t cfg-7 :delay (.mov result vf4)) + (label cfg-6) + (set! result -100000000.0) + (label cfg-7) + (the-as float result) + ) + ) + ) + + +(defun ray-sphere-intersect ((ray-origin vector) (ray-dir vector) (sph-origin vector) (radius float)) + "Intersect a ray and sphere. Will return 0 if you are in the sphere, -huge number if you don't hit it. + Returns the length of the ray to the first intersection." + + ;; offset stuff as if the sphere is at the origin. + (rlet ((vf1 :class vf) + (vf2 :class vf) + ) + (.lvf vf1 (&-> ray-origin quad)) + (.lvf vf2 (&-> sph-origin quad)) + (.sub.vf vf1 vf1 vf2) ;; the sphere is at the origin in the actual intersection. + (.lvf vf2 (&-> ray-dir quad)) + ;;(raw-ray-sphere-intersect radius) + (pc-port-do-raw-ray-sphere-intersect radius vf1 vf2) + ) + ) + +(defun ray-circle-intersect ((ray-origin vector) (ray-dir vector) (circle-origin vector) (radius float)) + "Intersect ray with circle. Circle is on the y plane and this throws out the y components + of ray-origin, circle-origin, and ray-dir" + (rlet ((vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> ray-origin quad)) + (.mov.vf vf1 vf0 :mask #b10) + (.lvf vf2 (&-> circle-origin quad)) + (.mov.vf vf2 vf0 :mask #b10) + (.sub.vf vf1 vf1 vf2) + (.lvf vf2 (&-> ray-dir quad)) + (.mov.vf vf2 vf0 :mask #b10) + ;;(raw-ray-sphere-intersect radius) + (pc-port-do-raw-ray-sphere-intersect radius vf1 vf2) + ) + ) + +(defun ray-cylinder-intersect ((ray-origin vector) (ray-dir vector) (cyl-origin vector) (cyl-axis vector) (cyl-rad float) (cyl-len float) (pt-out vector)) + "Intersect with a cylinder. + Currently this is untested." + (local-vars + (v0-1 float) + (v1-0 int) + (v1-2 int) + (a0-1 int) + (a0-2 int) + (a0-4 int) + (a0-5 int) + ) + (rlet ((vf1 :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) + (vf2 :class vf) + (vf20 :class vf) + (vf21 :class vf) + ) + (.lvf vf10 (&-> ray-origin quad)) + (.lvf vf12 (&-> cyl-origin quad)) + (.sub.vf vf15 vf10 vf12) + (.lvf vf11 (&-> ray-dir quad)) + (.lvf vf13 (&-> cyl-axis quad)) + (.mov vf14 cyl-len) + (.mul.vf vf16 vf15 vf13) + (.mul.vf vf17 vf11 vf13) + (.add.x.vf vf16 vf16 vf16 :mask #b10) + (.add.x.vf vf17 vf17 vf17 :mask #b10) + (.add.z.vf vf16 vf16 vf16 :mask #b10) + (.add.z.vf vf17 vf17 vf17 :mask #b10) + (.mul.y.vf vf1 vf13 vf16) + (.add.vf vf18 vf17 vf16) + (.sub.x.vf vf19 vf16 vf14) + (.mul.y.vf vf2 vf13 vf17) + (.mov v1-0 vf16) + (.sub.x.vf vf20 vf18 vf14) + (.mov a0-1 vf18) + (let ((v1-1 (logand v1-0 (the-as uint a0-1)))) + (.sub.vf vf1 vf15 vf1) + (b! (< v1-1 0) cfg-6 :delay (.sub.vf vf2 vf11 vf2)) + ) + (.mov v1-2 vf19) + (.mov a0-2 vf20) + (b! (>= (the-as int (logior v1-2 (the-as uint a0-2))) 0) cfg-6 :delay (nop!)) + ;;(let ((v1-4 (raw-ray-sphere-intersect cyl-rad))) + (let ((v1-4 (pc-port-do-raw-ray-sphere-intersect cyl-rad vf1 vf2))) + (b! (< (the-as int v1-4) 0) cfg-6 :delay (.mov vf21 v1-4)) + (.mul.x.vf vf17 vf17 vf21) + (.add.vf vf16 vf16 vf17) + (.mul.y.vf vf13 vf13 vf16) + (.sub.x.vf vf19 vf16 vf14) + (.mov a0-4 vf16) + (b! + (< (the-as int a0-4) 0) + cfg-6 + :delay + (.add.vf vf12 vf12 vf13 :mask #b111) + ) + (.mov a0-5 vf19) + (b! (>= (the-as int a0-5) 0) cfg-6 :delay (.svf (&-> pt-out quad) vf12)) + (b! #t cfg-7 :delay (set! v0-1 v1-4)) + ) + (label cfg-6) + (set! v0-1 -100000000.0) + (label cfg-7) + v0-1 + ) + ) + +(defun ray-plane-intersect ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector) (arg4 vector) (arg5 vector) (arg6 vector)) + "Unused." + (local-vars (v1-0 float) (v1-1 float) (a2-1 float)) + (rlet ((acc :class vf) + (Q :class vf) + (vf0 :class vf) + (vf1 :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) + ) + (init-vf0-vector) + (.lvf vf3 (&-> arg5 quad)) + (.lvf vf1 (&-> arg4 quad)) + (.lvf vf2 (&-> arg6 quad)) + (.sub.vf vf1 vf3 vf1) + (.sub.vf vf2 vf3 vf2) + (.lvf vf6 (&-> arg2 quad)) + (.lvf vf7 (&-> arg3 quad)) + (.sub.vf vf8 vf3 vf6) + (.outer.product.a.vf acc vf2 vf1) + (.outer.product.b.vf vf4 vf1 vf2 acc) + (.mul.vf vf8 vf8 vf4) + (.mul.vf vf9 vf7 vf4) + (.mul.vf vf5 vf4 vf4) + (.add.y.vf vf8 vf8 vf8 :mask #b1) + (.add.y.vf vf9 vf9 vf9 :mask #b1) + (.add.y.vf vf5 vf5 vf5 :mask #b1) + (.add.z.vf vf8 vf8 vf8 :mask #b1) + (.add.z.vf vf9 vf9 vf9 :mask #b1) + (.add.z.vf vf5 vf5 vf5 :mask #b1) + (.mov v1-0 vf9) + (.mov a2-1 vf8) + (.isqrt.vf Q vf0 vf5 :fsf #b11 :ftf #b0) + (let ((f1-0 a2-1) + (f2-0 v1-0) + ) + (cond + ((!= f2-0 0.0) + (let ((f1-1 (/ f1-0 f2-0))) + (.mov.vf vf4 vf0 :mask #b1000) + (.wait.vf) + (.mul.vf vf4 vf4 Q :mask #b111) + (let ((v0-0 f1-1)) + (.mov vf8 v0-0) + (.svf (&-> arg1 quad) vf4) + (.mul.x.vf acc vf7 vf8) + (.add.mul.w.vf vf7 vf6 vf0 acc :mask #b111) + (.svf (&-> arg0 quad) vf7) + (.mov v1-1 vf7) + v0-0 + ) + ) + ) + (else + -100000000.0 + ) + ) + ) + ) + ) + +;; ray-triangle-intersect (unused) +;; collide-do-primitives (used in moving-sphere-triangle-intersect) +(def-mips2c collide-do-primitives (function float)) +;; moving-sphere-triangle-intersect (used in cam) +(def-mips2c moving-sphere-triangle-intersect (function vector vector float collide-cache-tri vector vector float)) +;; moving-sphere-sphere-intersect (used in collide) +(defun moving-sphere-sphere-intersect ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (let ((f30-0 (ray-sphere-intersect arg0 arg1 arg2 (+ (-> arg0 w) (-> arg2 w))))) + (when (>= f30-0 0.0) + (let ((s3-1 (vector-normalize! (vector-! (new-stack-vector0) arg2 arg0) (-> arg0 w)))) + (vector+*! arg3 arg0 arg1 f30-0) + (vector+! arg3 arg3 s3-1) + ) + ) + f30-0 + ) + ) + +;; moving-sphere-moving-sphere-intersect (unused) diff --git a/goal_src/jak3/engine/data/art-h.gc b/goal_src/jak3/engine/data/art-h.gc index 4c30c31cc1..0712c1cf21 100644 --- a/goal_src/jak3/engine/data/art-h.gc +++ b/goal_src/jak3/engine/data/art-h.gc @@ -160,7 +160,7 @@ This can be either an art container containing more arts, or an actual art thing (art-method-10 (_type_) _type_) (get-art-by-name-method (_type_ string type) basic) (get-art-idx-by-name-method (_type_ string type) int) - (needs-link? (_type_) symbol) + (contains-art-for-other-group? (_type_) symbol) ) ) @@ -176,7 +176,8 @@ This can be either an art container containing more arts, or an actual art thing (deftype art-mesh-anim (art-element) "An unused mesh animation." - () + ((data basic :dynamic) + ) ) (deftype art-joint-anim (art-element) @@ -198,20 +199,21 @@ actor, like the mesh, animations, shadow mesh, skeleton, etc." (data art-element :dynamic :offset 32) ) (:methods - (relocate (_type_ kheap (pointer uint8)) _type_ :replace) - (link-art! (_type_) art-group) + (relocate (_type_ kheap (pointer uint8)) none :replace) + (link-art-to-master (_type_) none) (unknown-1 () none) ) ) (deftype art-mesh-geo (art-element) "Unused art format for a mesh. This might have been for the renderer that came before merc." - () + ((data basic :dynamic) + ) ) (deftype art-joint-geo (art-element) "Collection of joints for an actor." - ((data joint :dynamic :offset 48) + ((data joint :dynamic) ) ) @@ -249,11 +251,11 @@ This is used for short, commonly used animations that always remain in RAM." ) (:methods (new (symbol type int) _type_) - (art-joint-anim-manager-method-9 () none) - (art-joint-anim-manager-method-10 () none) - (art-joint-anim-manager-method-11 () none) - (art-joint-anim-manager-method-12 () none) - (art-joint-anim-manager-method-13 () none) + (decompress (_type_ art-joint-anim) art-joint-anim) + (mark-anim-in-use (_type_ art-joint-anim) art-joint-anim) + (unload-from-slot (_type_ int) art-joint-anim) + (used-bytes-for-slot (_type_ int) int) + (unload-from-heap (_type_ kheap) none) ) ) @@ -462,4 +464,4 @@ Each process-drawable has a draw-control." ) (import "goal_src/jak3/engine/data/art-elts.gc") -;; (import "goal_src/jak3/engine/data/joint-nodes.gc") \ No newline at end of file +;; (import "goal_src/jak3/engine/data/joint-nodes.gc") diff --git a/goal_src/jak3/engine/level/level-h.gc b/goal_src/jak3/engine/level/level-h.gc index 04da995ef9..51f17867da 100644 --- a/goal_src/jak3/engine/level/level-h.gc +++ b/goal_src/jak3/engine/level/level-h.gc @@ -16,6 +16,7 @@ (define-extern *level* level-group) (define-extern *draw-index* int) (define-extern *level-index* int) +(define-extern *print-login* symbol) (define-extern level-remap-texture (function texture-id texture-id)) diff --git a/goal_src/jak3/engine/load/decomp-h.gc b/goal_src/jak3/engine/load/decomp-h.gc index 82ebd46df2..499fc7f755 100644 --- a/goal_src/jak3/engine/load/decomp-h.gc +++ b/goal_src/jak3/engine/load/decomp-h.gc @@ -5,6 +5,8 @@ ;; name in dgo: decomp-h ;; dgos: GAME +(define-extern unpack-comp-lzo (function (pointer uint8) (pointer uint8) none)) + ;; DECOMP BEGINS (deftype decomp-work (structure) diff --git a/goal_src/jak3/engine/math/transformq-h.gc b/goal_src/jak3/engine/math/transformq-h.gc index b182aeeeb4..437600bd28 100644 --- a/goal_src/jak3/engine/math/transformq-h.gc +++ b/goal_src/jak3/engine/math/transformq-h.gc @@ -8,6 +8,9 @@ (declare-type transformq structure) (define-extern matrix<-transformq! (function matrix transformq matrix)) (define-extern matrix<-parented-transformq! (function matrix transformq vector matrix)) +(define-extern matrix<-transformq+trans! (function matrix transformq vector matrix)) +(define-extern matrix<-transformq+world-trans! (function matrix transformq vector matrix)) +(define-extern matrix<-transformq+rot-offset! (function matrix transformq vector matrix)) ;; DECOMP BEGINS diff --git a/goal_src/jak3/engine/process-drawable/process-drawable-h.gc b/goal_src/jak3/engine/process-drawable/process-drawable-h.gc index 7d8f79d1af..32201eb869 100644 --- a/goal_src/jak3/engine/process-drawable/process-drawable-h.gc +++ b/goal_src/jak3/engine/process-drawable/process-drawable-h.gc @@ -107,8 +107,8 @@ (let ((a1-5 (/ (&- (the-as pointer chan) (the-as uint (the-as pointer (-> v1-0 channel)))) 64))) (if (< a1-5 (the-as int (+ (-> v1-0 active-channels) (-> v1-0 float-channels)))) (qmem-copy<-! - (the-as pointer (+ (+ (* a1-5 64) 60) (the-as int v1-0))) - (the-as pointer (+ (+ (* (+ a1-5 1) 64) 60) (the-as int v1-0))) + (the-as pointer (-> v1-0 channel a1-5)) + (the-as pointer (-> v1-0 channel (+ a1-5 1))) (the-as int (* (-> v1-0 float-channels) 64)) ) ) diff --git a/goal_src/jak3/engine/ps2/timer.gc b/goal_src/jak3/engine/ps2/timer.gc index 0ee32f9c99..5c45f8b980 100644 --- a/goal_src/jak3/engine/ps2/timer.gc +++ b/goal_src/jak3/engine/ps2/timer.gc @@ -164,7 +164,7 @@ ) ) -(defglobalconstant EE_SECONDS_PER_TICK (/ 1.0 3000000)) ;; 300MHz is a "decent enough" estimate +(defglobalconstant EE_SECONDS_PER_TICK (/ 1.0 300000000)) ;; 300MHz is a "decent enough" estimate (defmacro cpu-ticks-to-seconds (ticks) `(* ,EE_SECONDS_PER_TICK ,ticks) ) diff --git a/test/decompiler/reference/jak3/engine/anim/joint-h_REF.gc b/test/decompiler/reference/jak3/engine/anim/joint-h_REF.gc index 3b514d410a..12342f09d6 100644 --- a/test/decompiler/reference/jak3/engine/anim/joint-h_REF.gc +++ b/test/decompiler/reference/jak3/engine/anim/joint-h_REF.gc @@ -157,13 +157,13 @@ Multiple channels are used to blend animations together." (interp-select int64 2) (top-anim top-anim-joint-control) (override (array float)) - (channel joint-control-channel :dynamic) + (channel joint-control-channel :inline :dynamic) ) (:methods - (new (symbol type) _type_) + (new (symbol type int) _type_) (joint-control-method-9 () none) (joint-control-method-10 () none) - (joint-control-method-11 () none) + (debug-print-channels (_type_ symbol) int) (joint-control-method-12 () none) ) ) @@ -232,7 +232,7 @@ Multiple channels are used to blend animations together." (format #t "~1Toverride: ~A~%" (-> this override)) (format #t "~1Tchannel[0] @ #x~X~%" (-> this channel)) (dotimes (s5-2 (the-as int (-> this active-channels))) - (format #t "~T [~D]~1Tchannel: ~`joint-control-channel`P~%" s5-2 (+ (+ (* s5-2 64) 60) (the-as int this))) + (format #t "~T [~D]~1Tchannel: ~`joint-control-channel`P~%" s5-2 (-> this channel s5-2)) ) (label cfg-32) this diff --git a/test/decompiler/reference/jak3/engine/anim/joint_REF.gc b/test/decompiler/reference/jak3/engine/anim/joint_REF.gc new file mode 100644 index 0000000000..702e5300ca --- /dev/null +++ b/test/decompiler/reference/jak3/engine/anim/joint_REF.gc @@ -0,0 +1,2306 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for method 2 of type joint +(defmethod print ((this joint)) + (format #t "#<~A ~S ~D @ #x~X>" (-> this type) (-> this name) (-> this number) this) + this + ) + +;; definition for method 8 of type joint +(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 + ) + +;; definition for method 2 of type joint-anim +(defmethod print ((this joint-anim)) + (format #t "#<~A ~S ~D [~D] @ #x~X>" (-> this type) (-> this name) (-> this number) (-> this length) this) + this + ) + +;; definition for method 4 of type joint-anim +(defmethod length ((this joint-anim)) + (-> this length) + ) + +;; definition for method 5 of type joint-anim-matrix +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this joint-anim-matrix)) + (the-as int (+ (-> joint-anim-matrix size) (* (-> this length) 64))) + ) + +;; definition for method 5 of type joint-anim-transformq +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this joint-anim-transformq)) + (the-as int (+ (-> joint-anim-transformq size) (* 48 (-> this length)))) + ) + +;; definition for method 5 of type joint-anim-drawable +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this joint-anim-drawable)) + (the-as int (+ (-> joint-anim-drawable size) (* (-> this length) 4))) + ) + +;; definition for function joint-anim-login +(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 + ) + +;; definition for function joint-anim-inspect-elt +(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 + ) + +;; definition for method 8 of type joint-anim-drawable +(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 + ) + +;; definition for function jacc-mem-usage +(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 + ) + +;; definition for method 2 of type joint-control-channel +(defmethod print ((this joint-control-channel)) + (let ((t9-0 format) + (a0-1 #t) + (a1-0 "#") + (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 + ) + +;; definition for method 5 of type joint-control +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this joint-control)) + (the-as int (+ (-> this type size) (* (-> this allocated-length) 64))) + ) + +;; definition for method 0 of type joint-control +(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 + ) + ) + +;; definition for method 11 of type joint-control +(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 + ) + +;; definition for method 13 of type art +(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 + ) + +;; definition for method 11 of type art +;; 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) + ) + +;; definition for method 12 of type art +;; 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) + ) + +;; definition for method 2 of type art +(defmethod print ((this art)) + (format #t "#<~A ~S :length ~D @ #x~X>" (-> this type) (-> this name) (-> this length) this) + this + ) + +;; definition for method 4 of type art +(defmethod length ((this art)) + (-> this length) + ) + +;; definition for method 9 of type art +(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 + ) + +;; definition for method 10 of type art +(defmethod art-method-10 ((this art)) + this + ) + +;; definition for method 8 of type art-mesh-anim +(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 + ) + +;; definition for method 8 of type art-joint-anim +(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 + ) + +;; definition for method 5 of type art-joint-anim +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this art-joint-anim)) + (the-as int (+ (-> art size) (* (-> this length) 4))) + ) + +;; definition for method 3 of type art-group +(defmethod inspect ((this art-group)) + (format #t "[~8x] ~A~%" this (-> this type)) + (format #t "~Tinfo: ~A~%" (-> this info)) + (format #t "~Tlength: ~D~%" (-> this length)) + (format #t "~Tname: ~A~%" (-> this name)) + (format #t "~Textra: ~A~%" (-> this extra)) + (format #t "~Tdata[~D]: @ #x~X~%" (-> this length) (-> this data)) + (dotimes (s5-0 (-> this length)) + (if (-> this data s5-0) + (format #t "~T [~D] ~A (~D bytes)~%" s5-0 (-> this data s5-0) (mem-size (-> this data s5-0) #f 0)) + (format #t "~T [~D] ~A (~D bytes)~%" s5-0 (-> this data s5-0) 0) + ) + ) + this + ) + +;; definition for method 13 of type art-group +(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))) + ) + ) + +;; definition for method 11 of type art-group +;; 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) + ) + ) + ) + +;; definition for method 12 of type art-group +(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) + ) + ) + ) + +;; definition for method 9 of type art-group +(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 + ) + +;; definition for method 10 of type art-group +(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 + ) + +;; definition for method 8 of type art-group +(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 + ) + +;; definition for method 7 of type art-group +;; 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) (load-buffer-mode medium)) + ) + (cond + ((and s5-1 (= (-> s5-1 name) 'default) (not *print-login*)) + (format + 0 + "ERROR: illegal login of art ~A (in level ~A) to level ~A~%" + this + (get-level-by-heap-ptr-and-status *level* (the-as pointer this) 'loading) + s5-1 + ) + (break!) + 0 + ) + ((or (not s5-1) (= (-> s5-1 name) 'default)) + ) + ((!= (get-level-by-heap-ptr-and-status *level* (the-as pointer this) 'loading) s5-1) + (format + 0 + "ERROR: illegal login of art ~A (in level ~A) to level ~A~%" + this + (get-level-by-heap-ptr-and-status *level* (the-as pointer this) 'loading) + s5-1 + ) + (break!) + 0 + ) + ) + (when (or (not s5-1) (= (-> s5-1 name) 'default)) + (login this) + (if (contains-art-for-other-group? this) + (link-art-to-master this) + ) + ) + (if s5-1 + (set-loaded-art (-> s5-1 art-group) this) + ) + ) + this + ) + ) + ) + ) + (none) + ) + +;; definition for method 5 of type art-mesh-geo +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this art-mesh-geo)) + (the-as int (+ (-> art size) (* (-> this length) 4))) + ) + +;; definition for method 8 of type art-mesh-geo +(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 + ) + +;; definition for method 9 of type art-mesh-geo +(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 + ) + +;; definition for method 9 of type art-joint-anim +(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 + ) + +;; definition for method 5 of type art-joint-geo +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this art-joint-geo)) + (the-as int (+ (-> art size) (* (-> this length) 4))) + ) + +;; definition for method 11 of type art-joint-geo +;; 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) + ) + ) + ) + +;; definition for method 12 of type art-joint-geo +(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) + ) + ) + ) + +;; definition for method 8 of type art-joint-geo +(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 + ) + +;; definition for function joint-control-cleanup +;; 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)) + ) + (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) + #t + ) + ) + ) + ) + (none) + ) + +;; definition for function joint-control-channel-eval +(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 + ) + ) + +;; definition for function joint-control-channel-eval! +(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 + ) + ) + +;; definition for function joint-control-channel-group-eval! +(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! (-> jcc num-func) num-func) + (cond + ((= (-> jcc command) (joint-control-command stack)) + ) + (else + (if ja + (set! (-> jcc frame-group) ja) + ) + (num-func jcc (-> jcc param 0) (-> jcc param 1) (-> jcc param 2)) + (set! (-> jcc eval-time) (the-as uint (current-time))) + ) + ) + 0 + ) + +;; definition for function joint-control-channel-group! +(defun joint-control-channel-group! ((arg0 joint-control-channel) + (arg1 art-joint-anim) + (arg2 (function joint-control-channel float float float float)) + ) + (set! (-> arg0 num-func) arg2) + (cond + ((= (-> arg0 command) (joint-control-command stack)) + ) + (arg1 + (set! (-> arg0 frame-group) arg1) + ) + ) + 0 + ) + +;; definition for function joint-control-copy! +(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 + ) + +;; definition for function joint-control-remap! +;; INFO: Used lq/sq +(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 + ) + +;; definition for function flatten-joint-control-to-spr +;; INFO: Used lq/sq +(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) + ) + (let ((chan-count (+ (-> jc active-channels) (-> jc float-channels)))) + (let ((one 1.0) + (chan-float-offset 0) + (chan-vector-ptr (the-as (inline-array vector) #x70000960)) + (interp2-selected-idx (-> jc active-frame-interp)) + ) + (dotimes (chan-idx (the-as int chan-count)) + (let ((chan (-> jc channel chan-idx))) + (case (-> chan command) + (((joint-control-command push)) + (let ((flt1 (the-as (pointer float) (+ (the-as int chan-vector-ptr) chan-float-offset)))) + (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)) + (set! (-> flt1 0) one) + ) + (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)) + (let ((interp2-selected-weight1 (-> chan frame-interp interp2-selected-idx))) + (let ((a3-5 (- one interp2-selected-weight1))) + (.mov vf1 a3-5) + ) + (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) + (.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) + (+! (-> (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)) + (let* ((interp2-selected-weight2 (-> chan frame-interp interp2-selected-idx)) + (one-minus-interp2 (- one interp2-selected-weight2)) + (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) + ) + (.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)) + (.mul.x.vf vf3 vf3 vf2) + (.mul.x.vf vf4 vf4 vf2) + (.mul.x.vf vf5 vf5 vf2) + (.mul.x.vf vf6 vf6 vf2) + (.mul.x.vf vf7 vf7 vf2) + (.mul.x.vf vf8 vf8 vf2) + (.lvf vf9 (&-> 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)) + (.mul.x.vf vf9 vf9 vf1) + (.mul.x.vf vf10 vf10 vf1) + (.mul.x.vf vf11 vf11 vf1) + (.mul.x.vf vf12 vf12 vf1) + (.mul.x.vf vf13 vf13 vf1) + (.mul.x.vf vf14 vf14 vf1) + (.add.vf vf3 vf3 vf9) + (.add.vf vf4 vf4 vf10) + (.add.vf vf5 vf5 vf11) + (.add.vf vf6 vf6 vf12) + (.add.vf vf7 vf7 vf13) + (.add.vf vf8 vf8 vf14) + (.svf (&-> 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) + (set! chan-vector-ptr (the-as (inline-array vector) (&+ (the-as pointer chans-to-stack) 96))) + ) + ) + ) + ) + (+! chan-float-offset 4) + ) + ) + (let ((upload-count 0)) + (dotimes (upload-chan-idx (the-as int chan-count)) + (when (< 0.001 (-> (the-as terrain-context #x70000000) work foreground joint-work flatten-array upload-chan-idx)) + (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) + ) + (when (>= int-frame-num (the-as int last-frame)) + (set! frame-frac 0.0) + (set! int-frame-num (the-as int last-frame)) + ) + ) + (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)) + (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) + ) + (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 + ) + ) + +;; definition for function matrix-from-joint-anim-frame +;; 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) + ) + ) + +;; definition for function matrix-from-control-channel! +;; INFO: Used lq/sq +(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) + ) + ) + ) + ) + ) + ) + +;; definition for function matrix-from-control-pair! +(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! (the-as matrix (+ #x70000000 0)) jnt jcc))) + (matrix-lerp! matrix-to-modify matrix-to-modify a2-3 f30-0) + ) + ) + ) + ) + ) + +;; definition for function matrix-from-control! +;; INFO: Used lq/sq +;; 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! (- (-> 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) (- (-> mat-stack top) (the-as uint s1-0))) + (let* ((v1-9 (- (-> 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-as uint (-> mat-stack top)) s1-0)) + ) + ((logtest? v1-3 (joint-control-command blend)) + (matrix-from-control-pair! + (- (-> 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) (- (-> mat-stack top) (the-as uint s1-0))) + (let ((a1-11 (- (-> 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)) + ) + +;; definition for method 9 of type cspace +(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 + ) + +;; definition for method 0 of type cspace +(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) + ) + ) + +;; definition for function cspace<-cspace! +;; INFO: Used lq/sq +(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 + ) + ) + +;; definition for function cspace<-cspace-normalized! +;; INFO: Used lq/sq +(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 + ) + ) + +;; definition for function cspace<-parent-joint! +;; INFO: Used lq/sq +(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 + ) + ) + +;; definition for function cspace<-rot-yxy! +(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) + ) + ) + +;; definition for function cspace<-transform-yxy! +(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) + ) + ) + +;; definition for function cspace<-transformq! +(defun cspace<-transformq! ((dst cspace) (src transformq)) + "Set one cspace's from a transformq" + (matrix<-transformq! (-> dst bone transform) src) + ) + +;; definition for function cspace<-transformq+trans! +(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) + ) + +;; definition for function cspace<-transformq+world-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) + ) + +;; definition for function cspace<-transformq+rot-offset! +(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) + ) + +;; definition for function cspace-calc-total-matrix! +(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)) + ) + +;; definition for function cspace<-matrix-no-push-joint! +;; INFO: Used lq/sq +(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! (the-as matrix-stack (+ 64 #x70000000)) (-> 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 + ) + ) + +;; definition for function cspace<-matrix-joint! +;; INFO: Used lq/sq +(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 + ) + ) + +;; definition for function cspace<-parented-matrix-joint! +(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 + ) + ) + ) + +;; definition for function cspace<-parented-matrix-mirror! +(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) + ) + ) + +;; definition for function cspace<-parented-matrix-joint-flip-z! +(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 + ) + ) + ) + +;; definition for function cspace<-matrix-joint-flip-z! +;; WARN: Return type mismatch int vs none. +(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) + ) + ) + +;; definition for function cspace<-parented-transformq-joint! +;; ERROR: Function may read a register that is not set: ra +;; ERROR: Unsupported inline assembly instruction kind - [jr ra] +;; ERROR: Unsupported inline assembly instruction kind - [jr ra] +(defun cspace<-parented-transformq-joint! ((dst cspace) (joint-transformq transformq)) + "Main function for doing skeletal animation from decompressed transformq's. + Sets the cspace bone to the parent bone, plus the transformq." + (local-vars (t1-1 uint128) (ra-0 none) (f4-2 float)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf10 :class vf) + (vf11 :class vf) + (vf12 :class vf) + (vf13 :class vf) + (vf14 :class vf) + (vf15 :class vf) + (vf16 :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) + ) + (init-vf0-vector) + (nop!) + (let ((a3-0 (-> dst parent)) + (v1-0 1.0) + ) + (.lvf vf5 (&-> joint-transformq quat quad)) + (let ((f0-0 v1-0) + (t0-0 (-> a3-0 bone)) + ) + (nop!) + (let ((a2-0 (-> dst bone))) + (.add.vf vf6 vf5 vf5) + (let ((f1-0 (-> t0-0 scale x))) + (.add.w.vf vf2 vf0 vf5 :mask #b1) + (.lvf vf15 (&-> joint-transformq trans quad)) + (.add.z.vf vf2 vf0 vf5 :mask #b10) + (.lvf vf1 (&-> joint-transformq scale quad)) + (let ((f4-0 (/ f0-0 f1-0))) + (.lvf vf7 (&-> t0-0 transform rvec quad)) + (.sub.y.vf vf2 vf0 vf5 :mask #b100) + (.lvf vf8 (&-> t0-0 transform uvec quad)) + (.sub.w.vf vf2 vf0 vf0 :mask #b1000) + (.lvf vf9 (&-> t0-0 transform fvec quad)) + (.sub.z.vf vf3 vf0 vf5 :mask #b1) + (.lvf vf10 (&-> t0-0 transform trans quad)) + (.add.w.vf vf3 vf0 vf5 :mask #b10) + (let ((f2-0 (-> t0-0 scale y))) + (.add.x.vf vf3 vf0 vf5 :mask #b100) + (.svf (&-> a2-0 scale quad) vf1) + (.sub.w.vf vf3 vf0 vf0 :mask #b1000) + (let ((f3-0 (-> t0-0 scale z))) + (.add.y.vf vf4 vf0 vf5 :mask #b1) + (let ((v1-1 (-> t0-0 scale w))) + (.sub.x.vf vf4 vf0 vf5 :mask #b10) + (let ((t1-0 (the-as uint128 f4-0))) + (.add.w.vf vf4 vf0 vf5 :mask #b100) + (let ((f4-1 (/ f0-0 f2-0))) + (.sub.w.vf vf4 vf0 vf0 :mask #b1000) + (.outer.product.a.vf acc vf6 vf2) + (.outer.product.b.vf vf2 vf2 vf6 acc) + (.outer.product.a.vf acc vf6 vf3) + (.outer.product.b.vf vf3 vf3 vf6 acc) + (.outer.product.a.vf acc vf6 vf4) + (.outer.product.b.vf vf4 vf4 vf6 acc) + (.add.w.vf vf2 vf2 vf0 :mask #b1) + (.add.w.vf vf3 vf3 vf0 :mask #b10) + (.add.w.vf vf4 vf4 vf0 :mask #b100) + (let ((t2-0 (the-as uint128 f4-1))) + (b! (nonzero? v1-1) cfg-2 :delay (set! f4-2 (/.s f0-0 f3-0))) + (.mul.x.vf vf2 vf2 vf1) + (.mul.y.vf vf3 vf3 vf1) + (.mul.z.vf vf4 vf4 vf1) + (.mul.x.vf acc vf7 vf2) + (.add.mul.y.vf acc vf8 vf2 acc) + (.add.mul.z.vf acc vf9 vf2 acc) + (.add.mul.w.vf vf11 vf10 vf2 acc) + (.mul.x.vf acc vf7 vf3) + (.add.mul.y.vf acc vf8 vf3 acc) + (.add.mul.z.vf acc vf9 vf3 acc) + (.add.mul.w.vf vf12 vf10 vf3 acc) + (.mul.x.vf acc vf7 vf4) + (.add.mul.y.vf acc vf8 vf4 acc) + (.add.mul.z.vf acc vf9 vf4 acc) + (.add.mul.w.vf vf13 vf10 vf4 acc) + (.mul.x.vf acc vf7 vf15) + (.add.mul.y.vf acc vf8 vf15 acc) + (.add.mul.z.vf acc vf9 vf15 acc) + (.add.mul.w.vf vf14 vf10 vf0 acc) + (.svf (&-> a2-0 transform rvec quad) vf11) + (.svf (&-> a2-0 transform uvec quad) vf12) + (.svf (&-> a2-0 transform fvec quad) vf13) + (.svf (&-> a2-0 transform trans quad) vf14) + (.jr ra-0) + (nop!) + (label cfg-2) + (.pextlw t1-1 t2-0 t1-0) + ) + ) + ) + ) + ) + ) + ) + ) + (.mul.x.vf vf2 vf2 vf1) + (.mul.y.vf vf3 vf3 vf1) + (.mul.z.vf vf4 vf4 vf1) + (let ((t1-2 (make-u128 f4-2 (the-as int t1-1)))) + (.mov vf16 t1-2) + ) + (.mul.vf vf2 vf2 vf16) + (.mul.vf vf3 vf3 vf16) + (.mul.vf vf4 vf4 vf16) + (.mul.x.vf acc vf7 vf2) + (.add.mul.y.vf acc vf8 vf2 acc) + (.add.mul.z.vf acc vf9 vf2 acc) + (.add.mul.w.vf vf11 vf10 vf2 acc) + (.mul.x.vf acc vf7 vf3) + (.add.mul.y.vf acc vf8 vf3 acc) + (.add.mul.z.vf acc vf9 vf3 acc) + (.add.mul.w.vf vf12 vf10 vf3 acc) + (.mul.x.vf acc vf7 vf4) + (.add.mul.y.vf acc vf8 vf4 acc) + (.add.mul.z.vf acc vf9 vf4 acc) + (.add.mul.w.vf vf13 vf10 vf4 acc) + (.mul.x.vf acc vf7 vf15) + (.add.mul.y.vf acc vf8 vf15 acc) + (.add.mul.z.vf acc vf9 vf15 acc) + (.add.mul.w.vf vf14 vf10 vf0 acc) + (.svf (&-> a2-0 transform rvec quad) vf11) + (.svf (&-> a2-0 transform uvec quad) vf12) + (.svf (&-> a2-0 transform fvec quad) vf13) + (.svf (&-> a2-0 transform trans quad) vf14) + ) + ) + ) + (.jr ra-0) + (nop!) + (none) + ) + ) + +;; definition for function cspace<-parented-transformq-joint-flip-z! +;; WARN: Return type mismatch int vs 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) + ) + +;; definition for function clear-frame-accumulator +;; ERROR: function has no type analysis. Cannot decompile. + +;; definition for function normalize-frame-quaternions +;; ERROR: function has no type analysis. Cannot decompile. + +;; definition for function decompress-fixed-data-to-accumulator +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function decompress-frame-data-to-accumulator +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function decompress-frame-data-pair-to-accumulator +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function make-joint-jump-tables +;; ERROR: Failed store: (s.w! (+ a0-2 1616) v1-1) at op 5 +;; ERROR: Failed store: (s.w! (+ a0-5 1620) v1-3) at op 11 +;; ERROR: Failed store: (s.w! (+ a0-8 1624) v1-5) at op 17 +;; ERROR: Failed store: (s.w! (+ a0-11 1628) v1-7) at op 23 +;; ERROR: Failed store: (s.w! (+ a0-14 1632) v1-9) at op 29 +;; ERROR: Failed store: (s.w! (+ a0-17 1636) v1-11) at op 35 +;; ERROR: Failed store: (s.w! (+ a0-20 1640) v1-13) at op 41 +;; ERROR: Failed store: (s.w! (+ a0-23 1644) v1-15) at op 47 +;; ERROR: Failed store: (s.w! (+ a0-26 1648) v1-17) at op 53 +;; ERROR: Failed store: (s.w! (+ a0-29 1652) v1-19) at op 59 +;; ERROR: Failed store: (s.w! (+ a0-32 1656) v1-21) at op 65 +;; ERROR: Failed store: (s.w! (+ a0-35 1660) v1-23) at op 71 +;; ERROR: Failed store: (s.w! (+ a0-38 1664) v1-25) at op 77 +;; ERROR: Failed store: (s.w! (+ a0-41 1668) v1-27) at op 83 +;; ERROR: Failed store: (s.w! (+ a0-44 1672) v1-29) at op 89 +;; ERROR: Failed store: (s.w! (+ a0-47 1676) v1-31) at op 95 +;; ERROR: Failed store: (s.w! (+ a0-50 1680) v1-33) at op 101 +;; ERROR: Failed store: (s.w! (+ a0-53 1684) v1-35) at op 107 +;; ERROR: Failed store: (s.w! (+ a0-56 1688) v1-37) at op 113 +;; ERROR: Failed store: (s.w! (+ a0-59 1692) v1-39) at op 119 +;; ERROR: Failed store: (s.w! (+ a0-62 1696) v1-41) at op 125 +;; ERROR: Failed store: (s.w! (+ a0-65 1700) v1-43) at op 131 +;; ERROR: Failed store: (s.w! (+ a0-68 1704) v1-45) at op 137 +;; ERROR: Failed store: (s.w! (+ a0-71 1708) v1-47) at op 143 +;; ERROR: Failed store: (s.w! (+ a0-74 1712) v1-49) at op 149 +;; ERROR: Failed store: (s.w! (+ a0-77 1716) v1-51) at op 155 +;; ERROR: Failed store: (s.w! (+ a0-80 1720) v1-53) at op 161 +;; ERROR: Failed store: (s.w! (+ a0-83 1724) v1-55) at op 167 +;; ERROR: Failed store: (s.w! (+ a0-86 1728) v1-57) at op 173 +;; ERROR: Failed store: (s.w! (+ a0-89 1732) v1-59) at op 179 +;; ERROR: Failed store: (s.w! (+ a0-92 1736) v1-61) at op 185 +;; ERROR: Failed store: (s.w! (+ a0-95 1740) v1-63) at op 191 +;; ERROR: Failed store: (s.w! (+ a0-98 1744) v1-65) at op 197 +;; ERROR: Failed store: (s.w! (+ a0-101 1748) v1-67) at op 203 +;; ERROR: Failed store: (s.w! (+ a0-104 1752) v1-69) at op 209 +;; ERROR: Failed store: (s.w! (+ a0-107 1756) v1-71) at op 215 +;; ERROR: Failed store: (s.w! (+ a0-110 1760) v1-73) at op 221 +;; ERROR: Failed store: (s.w! (+ a0-113 1764) v1-75) at op 227 +;; ERROR: Failed store: (s.w! (+ a0-116 1768) v1-77) at op 233 +;; ERROR: Failed store: (s.w! (+ a0-119 1772) v1-79) at op 239 +;; ERROR: Failed store: (s.w! (+ a0-122 1776) v1-81) at op 245 +;; ERROR: Failed store: (s.w! (+ a0-125 1780) v1-83) at op 251 +;; ERROR: Failed store: (s.w! (+ a0-128 1784) v1-85) at op 257 +;; ERROR: Failed store: (s.w! (+ a0-131 1788) v1-87) at op 263 +;; ERROR: Failed store: (s.w! (+ a0-134 1792) v1-89) at op 269 +;; ERROR: Failed store: (s.w! (+ a0-137 1796) v1-91) at op 275 +;; ERROR: Failed store: (s.w! (+ a0-140 1800) v1-93) at op 281 +;; ERROR: Failed store: (s.w! (+ a0-143 1804) v1-95) at op 287 +(defun make-joint-jump-tables () + (let ((v1-1 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 108 4))) + (a0-2 #x70000000) + ) + (s.w! (+ a0-2 1616) v1-1) + ) + (let ((v1-3 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 199 4))) + (a0-5 #x70000000) + ) + (s.w! (+ a0-5 1620) v1-3) + ) + (let ((v1-5 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 233 4))) + (a0-8 #x70000000) + ) + (s.w! (+ a0-8 1624) v1-5) + ) + (let ((v1-7 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 286 4))) + (a0-11 #x70000000) + ) + (s.w! (+ a0-11 1628) v1-7) + ) + (let ((v1-9 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 301 4))) + (a0-14 #x70000000) + ) + (s.w! (+ a0-14 1632) v1-9) + ) + (let ((v1-11 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 366 4))) + (a0-17 #x70000000) + ) + (s.w! (+ a0-17 1636) v1-11) + ) + (let ((v1-13 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 387 4))) + (a0-20 #x70000000) + ) + (s.w! (+ a0-20 1640) v1-13) + ) + (let ((v1-15 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 100 4))) + (a0-23 #x70000000) + ) + (s.w! (+ a0-23 1644) v1-15) + ) + (let ((v1-17 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 155 4))) + (a0-26 #x70000000) + ) + (s.w! (+ a0-26 1648) v1-17) + ) + (let ((v1-19 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 199 4))) + (a0-29 #x70000000) + ) + (s.w! (+ a0-29 1652) v1-19) + ) + (let ((v1-21 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 261 4))) + (a0-32 #x70000000) + ) + (s.w! (+ a0-32 1656) v1-21) + ) + (let ((v1-23 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 286 4))) + (a0-35 #x70000000) + ) + (s.w! (+ a0-35 1660) v1-23) + ) + (let ((v1-25 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 335 4))) + (a0-38 #x70000000) + ) + (s.w! (+ a0-38 1664) v1-25) + ) + (let ((v1-27 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 366 4))) + (a0-41 #x70000000) + ) + (s.w! (+ a0-41 1668) v1-27) + ) + (let ((v1-29 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 402 4))) + (a0-44 #x70000000) + ) + (s.w! (+ a0-44 1672) v1-29) + ) + (let ((v1-31 (+ (the-as uint decompress-fixed-data-to-accumulator) (* 100 4))) + (a0-47 #x70000000) + ) + (s.w! (+ a0-47 1676) v1-31) + ) + (let ((v1-33 (+ (the-as uint decompress-frame-data-to-accumulator) (* 84 4))) + (a0-50 #x70000000) + ) + (s.w! (+ a0-50 1680) v1-33) + ) + (let ((v1-35 (+ (the-as uint decompress-frame-data-to-accumulator) (* 92 4))) + (a0-53 #x70000000) + ) + (s.w! (+ a0-53 1684) v1-35) + ) + (let ((v1-37 (+ (the-as uint decompress-frame-data-to-accumulator) (* 119 4))) + (a0-56 #x70000000) + ) + (s.w! (+ a0-56 1688) v1-37) + ) + (let ((v1-39 (+ (the-as uint decompress-frame-data-to-accumulator) (* 140 4))) + (a0-59 #x70000000) + ) + (s.w! (+ a0-59 1692) v1-39) + ) + (let ((v1-41 (+ (the-as uint decompress-frame-data-to-accumulator) (* 205 4))) + (a0-62 #x70000000) + ) + (s.w! (+ a0-62 1696) v1-41) + ) + (let ((v1-43 (+ (the-as uint decompress-frame-data-to-accumulator) (* 220 4))) + (a0-65 #x70000000) + ) + (s.w! (+ a0-65 1700) v1-43) + ) + (let ((v1-45 (+ (the-as uint decompress-frame-data-to-accumulator) (* 273 4))) + (a0-68 #x70000000) + ) + (s.w! (+ a0-68 1704) v1-45) + ) + (let ((v1-47 (+ (the-as uint decompress-frame-data-to-accumulator) (* 307 4))) + (a0-71 #x70000000) + ) + (s.w! (+ a0-71 1708) v1-47) + ) + (let ((v1-49 (+ (the-as uint decompress-frame-data-to-accumulator) (* 84 4))) + (a0-74 #x70000000) + ) + (s.w! (+ a0-74 1712) v1-49) + ) + (let ((v1-51 (+ (the-as uint decompress-frame-data-to-accumulator) (* 107 4))) + (a0-77 #x70000000) + ) + (s.w! (+ a0-77 1716) v1-51) + ) + (let ((v1-53 (+ (the-as uint decompress-frame-data-to-accumulator) (* 119 4))) + (a0-80 #x70000000) + ) + (s.w! (+ a0-80 1720) v1-53) + ) + (let ((v1-55 (+ (the-as uint decompress-frame-data-to-accumulator) (* 174 4))) + (a0-83 #x70000000) + ) + (s.w! (+ a0-83 1724) v1-55) + ) + (let ((v1-57 (+ (the-as uint decompress-frame-data-to-accumulator) (* 205 4))) + (a0-86 #x70000000) + ) + (s.w! (+ a0-86 1728) v1-57) + ) + (let ((v1-59 (+ (the-as uint decompress-frame-data-to-accumulator) (* 248 4))) + (a0-89 #x70000000) + ) + (s.w! (+ a0-89 1732) v1-59) + ) + (let ((v1-61 (+ (the-as uint decompress-frame-data-to-accumulator) (* 273 4))) + (a0-92 #x70000000) + ) + (s.w! (+ a0-92 1736) v1-61) + ) + (let ((v1-63 (+ (the-as uint decompress-frame-data-to-accumulator) (* 354 4))) + (a0-95 #x70000000) + ) + (s.w! (+ a0-95 1740) v1-63) + ) + (let ((v1-65 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 117 4))) + (a0-98 #x70000000) + ) + (s.w! (+ a0-98 1744) v1-65) + ) + (let ((v1-67 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 125 4))) + (a0-101 #x70000000) + ) + (s.w! (+ a0-101 1748) v1-67) + ) + (let ((v1-69 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 169 4))) + (a0-104 #x70000000) + ) + (s.w! (+ a0-104 1752) v1-69) + ) + (let ((v1-71 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 197 4))) + (a0-107 #x70000000) + ) + (s.w! (+ a0-107 1756) v1-71) + ) + (let ((v1-73 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 293 4))) + (a0-110 #x70000000) + ) + (s.w! (+ a0-110 1760) v1-73) + ) + (let ((v1-75 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 318 4))) + (a0-113 #x70000000) + ) + (s.w! (+ a0-113 1764) v1-75) + ) + (let ((v1-77 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 408 4))) + (a0-116 #x70000000) + ) + (s.w! (+ a0-116 1768) v1-77) + ) + (let ((v1-79 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 459 4))) + (a0-119 #x70000000) + ) + (s.w! (+ a0-119 1772) v1-79) + ) + (let ((v1-81 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 117 4))) + (a0-122 #x70000000) + ) + (s.w! (+ a0-122 1776) v1-81) + ) + (let ((v1-83 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 150 4))) + (a0-125 #x70000000) + ) + (s.w! (+ a0-125 1780) v1-83) + ) + (let ((v1-85 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 169 4))) + (a0-128 #x70000000) + ) + (s.w! (+ a0-128 1784) v1-85) + ) + (let ((v1-87 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 248 4))) + (a0-131 #x70000000) + ) + (s.w! (+ a0-131 1788) v1-87) + ) + (let ((v1-89 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 293 4))) + (a0-134 #x70000000) + ) + (s.w! (+ a0-134 1792) v1-89) + ) + (let ((v1-91 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 366 4))) + (a0-137 #x70000000) + ) + (s.w! (+ a0-137 1796) v1-91) + ) + (let ((v1-93 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 408 4))) + (a0-140 #x70000000) + ) + (s.w! (+ a0-140 1800) v1-93) + ) + (let ((v1-95 (+ (the-as uint decompress-frame-data-pair-to-accumulator) (* 533 4))) + (a0-143 #x70000000) + ) + (s.w! (+ a0-143 1804) v1-95) + ) + 0 + ) + +;; definition for function calc-animation-from-spr +;; INFO: function output is handled by mips2c +(def-mips2c calc-animation-from-spr (function joint-anim-frame int none)) + +;; definition for function create-interpolated-joint-animation-frame +(defun create-interpolated-joint-animation-frame ((dst joint-anim-frame) (num-joints int) (jc joint-control)) + (flatten-joint-control-to-spr jc) + (make-joint-jump-tables) + (calc-animation-from-spr dst num-joints) + 0 + ) + +;; definition for function create-interpolated2-joint-animation-frame +;; INFO: Used lq/sq +(defun create-interpolated2-joint-animation-frame ((dst joint-anim-frame) (num-joints int) (jc joint-control)) + (flush-cache 0) + (if (and (zero? (-> jc interp-select 0)) (zero? (-> jc interp-select 1))) + (return (create-interpolated-joint-animation-frame dst num-joints jc)) + ) + (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) + (dma-send-from-spr-no-flush + (the-as uint *gsf-buffer*) + (the-as uint dst) + (the-as uint (/ (+ (* 48 num-joints) 128) 16)) + #f + ) + (set! (-> jc active-frame-interp) (the-as uint 0)) + (flatten-joint-control-to-spr jc) + (make-joint-jump-tables) + (calc-animation-from-spr dst num-joints) + (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 rvec))) + (t2-0 (the-as (inline-array vector) (-> v1-9 matrices a1-5 rvec))) + (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 + ) + +;; definition for method 2 of type art-joint-anim-manager-slot +(defmethod print ((this art-joint-anim-manager-slot)) + (let* ((gp-0 format) + (s5-0 #t) + (s4-0 "#") + (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 + ) + +;; definition for method 12 of type art-joint-anim-manager +(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)))) + ) + ) + ) + +;; definition for method 11 of type art-joint-anim-manager +(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) (&- (-> 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 + ) + ) + +;; definition for method 10 of type art-joint-anim-manager +(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 + ) + +;; definition for method 9 of type art-joint-anim-manager +(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 + ) + +;; definition for method 13 of type art-joint-anim-manager +;; WARN: Return type mismatch int vs none. +(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) + ) + +;; failed to figure out what this is: +(kmemopen global "anim-manager") + +;; definition for symbol *anim-manager*, type art-joint-anim-manager +(define *anim-manager* (new 'global 'art-joint-anim-manager #x30000)) + +;; failed to figure out what this is: +(kmemclose) + + + + diff --git a/test/decompiler/reference/jak3/engine/data/art-h_REF.gc b/test/decompiler/reference/jak3/engine/data/art-h_REF.gc index 97528ddb4b..088558d24a 100644 --- a/test/decompiler/reference/jak3/engine/data/art-h_REF.gc +++ b/test/decompiler/reference/jak3/engine/data/art-h_REF.gc @@ -234,7 +234,7 @@ This can be either an art container containing more arts, or an actual art thing (art-method-10 (_type_) _type_) (get-art-by-name-method (_type_ string type) basic) (get-art-idx-by-name-method (_type_ string type) int) - (needs-link? (_type_) symbol) + (contains-art-for-other-group? (_type_) symbol) ) ) @@ -280,7 +280,8 @@ This can be either an art container containing more arts, or an actual art thing ;; definition of type art-mesh-anim (deftype art-mesh-anim (art-element) "An unused mesh animation." - () + ((data basic :dynamic) + ) ) ;; definition of type art-joint-anim @@ -325,8 +326,8 @@ actor, like the mesh, animations, shadow mesh, skeleton, etc." (data art-element :dynamic :offset 32) ) (:methods - (relocate (_type_ kheap (pointer uint8)) _type_ :replace) - (link-art! (_type_) art-group) + (relocate (_type_ kheap (pointer uint8)) none :replace) + (link-art-to-master (_type_) none) (unknown-1 () none) ) ) @@ -334,13 +335,14 @@ actor, like the mesh, animations, shadow mesh, skeleton, etc." ;; definition of type art-mesh-geo (deftype art-mesh-geo (art-element) "Unused art format for a mesh. This might have been for the renderer that came before merc." - () + ((data basic :dynamic) + ) ) ;; definition of type art-joint-geo (deftype art-joint-geo (art-element) "Collection of joints for an actor." - ((data joint :dynamic :offset 48) + ((data joint :dynamic) ) ) @@ -417,11 +419,11 @@ This is used for short, commonly used animations that always remain in RAM." ) (:methods (new (symbol type int) _type_) - (art-joint-anim-manager-method-9 () none) - (art-joint-anim-manager-method-10 () none) - (art-joint-anim-manager-method-11 () none) - (art-joint-anim-manager-method-12 () none) - (art-joint-anim-manager-method-13 () none) + (decompress (_type_ art-joint-anim) art-joint-anim) + (mark-anim-in-use (_type_ art-joint-anim) art-joint-anim) + (unload-from-slot (_type_ int) art-joint-anim) + (used-bytes-for-slot (_type_ int) int) + (unload-from-heap (_type_ kheap) none) ) ) diff --git a/test/decompiler/reference/jak3/engine/process-drawable/process-drawable-h_REF.gc b/test/decompiler/reference/jak3/engine/process-drawable/process-drawable-h_REF.gc index 5954109546..f0375d886f 100644 --- a/test/decompiler/reference/jak3/engine/process-drawable/process-drawable-h_REF.gc +++ b/test/decompiler/reference/jak3/engine/process-drawable/process-drawable-h_REF.gc @@ -108,8 +108,8 @@ (let ((a1-5 (/ (&- (the-as pointer chan) (the-as uint (the-as pointer (-> v1-0 channel)))) 64))) (if (< a1-5 (the-as int (+ (-> v1-0 active-channels) (-> v1-0 float-channels)))) (qmem-copy<-! - (the-as pointer (+ (+ (* a1-5 64) 60) (the-as int v1-0))) - (the-as pointer (+ (+ (* (+ a1-5 1) 64) 60) (the-as int v1-0))) + (the-as pointer (-> v1-0 channel a1-5)) + (the-as pointer (-> v1-0 channel (+ a1-5 1))) (the-as int (* (-> v1-0 float-channels) 64)) ) ) @@ -187,7 +187,3 @@ ;; failed to figure out what this is: 0 - - - - diff --git a/test/offline/config/jak3/config.jsonc b/test/offline/config/jak3/config.jsonc index deee48daca..315bbec9c2 100644 --- a/test/offline/config/jak3/config.jsonc +++ b/test/offline/config/jak3/config.jsonc @@ -6,7 +6,8 @@ "skip_compile_files": [ "types-h", // weird array of types. - "hfrag-h" // weird duplicate type + "hfrag-h", // weird duplicate type + "joint" ], "skip_compile_functions": [