From 90d6ee74511364faf1b276e5fe3958973883f29a Mon Sep 17 00:00:00 2001 From: water111 Date: Mon, 10 Aug 2026 00:28:14 -0700 Subject: [PATCH] clean up to entity-h --- decompiler/IR2/AtomicOpForm.cpp | 3 +- decompiler/IR2/Env.cpp | 27 ++++ decompiler/IR2/FormExpressionAnalysis.cpp | 7 +- decompiler/config/jak1/all-types.gc | 29 ++-- goal_src/jak1/engine/anim/joint-mod-h.gc | 95 +++++++------ goal_src/jak1/engine/camera/pov-camera-h.gc | 5 +- .../jak1/engine/collide/collide-cache-h.gc | 14 +- .../jak1/engine/collide/collide-frag-h.gc | 5 +- .../jak1/engine/collide/collide-func-h.gc | 2 +- goal_src/jak1/engine/collide/collide-h.gc | 2 + .../jak1/engine/collide/collide-mesh-h.gc | 16 +-- .../jak1/engine/collide/collide-shape-h.gc | 77 ++++++----- .../jak1/engine/collide/collide-target-h.gc | 17 +-- goal_src/jak1/engine/collide/pat-h.gc | 16 +-- goal_src/jak1/engine/collide/surface-h.gc | 21 ++- .../jak1/engine/common-obs/generic-obs-h.gc | 14 +- .../engine/common-obs/process-drawable-h.gc | 46 +++---- goal_src/jak1/engine/debug/debug-h.gc | 12 +- goal_src/jak1/engine/debug/stats-h.gc | 6 +- goal_src/jak1/engine/engine/engines.gc | 3 +- goal_src/jak1/engine/entity/entity-h.gc | 49 +++---- goal_src/jak1/engine/entity/res.gc | 36 +++-- goal_src/jak1/engine/game/effect-control-h.gc | 7 +- goal_src/jak1/engine/game/fact-h.gc | 4 +- goal_src/jak1/engine/game/game-h.gc | 16 +-- goal_src/jak1/engine/game/projectiles-h.gc | 8 +- .../engine/gfx/background/background-h.gc | 8 +- .../jak1/engine/gfx/background/subdivide-h.gc | 2 + goal_src/jak1/engine/gfx/depth-cue-h.gc | 5 + goal_src/jak1/engine/gfx/lights.gc | 9 +- goal_src/jak1/engine/gfx/shrub/shrubbery-h.gc | 72 ++++------ goal_src/jak1/engine/gfx/tfrag/tfrag-h.gc | 125 ++++++------------ goal_src/jak1/engine/gfx/tie/tie-h.gc | 73 ++++------ goal_src/jak1/engine/level/bsp-h.gc | 118 ++++++++++++++--- goal_src/jak1/engine/level/bsp.gc | 4 +- goal_src/jak1/engine/level/level.gc | 6 +- goal_src/jak1/engine/physics/dynamics-h.gc | 2 +- goal_src/jak1/engine/target/target-h.gc | 15 +-- goal_src/jak1/engine/util/sync-info-h.gc | 14 +- 39 files changed, 501 insertions(+), 489 deletions(-) diff --git a/decompiler/IR2/AtomicOpForm.cpp b/decompiler/IR2/AtomicOpForm.cpp index 62d5351fab..607c4cd3b0 100644 --- a/decompiler/IR2/AtomicOpForm.cpp +++ b/decompiler/IR2/AtomicOpForm.cpp @@ -63,7 +63,8 @@ FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const { pool.alloc_single_element_form( nullptr, GenericOperator::make_fixed(FixedOperatorKind::ADDRESS_OF), pool.alloc_single_element_form( - nullptr, -1, offset, make_stack_slot_access(offset), false)), + nullptr, -1, offset, env.get_stack_slot_access_for_op(m_my_idx, offset), + false)), true, env.stack_slot_entries.at(offset).typespec); } } else { diff --git a/decompiler/IR2/Env.cpp b/decompiler/IR2/Env.cpp index 295c71473a..9773a76301 100644 --- a/decompiler/IR2/Env.cpp +++ b/decompiler/IR2/Env.cpp @@ -685,6 +685,21 @@ RegisterAccess Env::get_stack_slot_access_for_op(int op_id, int offset) const { return make_stack_slot_access(offset, it->second); } +namespace { + +std::optional stack_slot_address_offset(const AtomicOp* op) { + const auto* set = dynamic_cast(op); + if (!set || set->src().kind() != SimpleExpression::Kind::ADD || set->src().args() != 2 || + !set->src().get_arg(0).is_var() || + set->src().get_arg(0).var().reg() != Register(Reg::GPR, Reg::SP) || + !set->src().get_arg(1).is_int()) { + return {}; + } + return set->src().get_arg(1).get_int(); +} + +} // namespace + void Env::disable_def(const RegisterAccess& access, DecompWarnings& warnings) { if (is_stack_slot_access(access)) { // Stack-slot use/def info is intentionally immutable during expression building. @@ -732,6 +747,9 @@ void Env::rebuild_stack_slot_use_def_info() { offsets.insert(store->offset()); } else if (auto* load = dynamic_cast(ops.ops.at(op_id).get())) { offsets.insert(load->offset()); + } else if (auto address_offset = stack_slot_address_offset(ops.ops.at(op_id).get()); + address_offset && stack_slot_entries.contains(*address_offset)) { + offsets.insert(*address_offset); } } @@ -755,6 +773,8 @@ void Env::rebuild_stack_slot_use_def_info() { writes.at(block_id) = true; seen_write = true; } + } else if (stack_slot_address_offset(op) == offset && !seen_write) { + reads_before_write.at(block_id) = true; } } } @@ -817,6 +837,13 @@ void Env::rebuild_stack_slot_use_def_info() { auto& info = m_stack_slot_use_def_info[RegId(Register(Reg::GPR, Reg::SP), current_var)]; info.defs.push_back({op_id, block_id, AccessMode::WRITE, false}); info.ssa_vars.insert(current_var); + } else if (stack_slot_address_offset(op) == offset) { + ASSERT(current_var != -1); + m_stack_slot_var_by_op[op_id] = current_var; + access_ops.push_back(op_id); + auto& info = m_stack_slot_use_def_info[RegId(Register(Reg::GPR, Reg::SP), current_var)]; + info.uses.push_back({op_id, block_id, AccessMode::READ, false}); + info.ssa_vars.insert(current_var); } } diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 077d29ab03..fc5a1330b1 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -7283,8 +7283,7 @@ void ArrayFieldAccess::update_with_val(Form* new_val, // Reverse field lookup may already have rewritten the address expression into a dereference. // If its trailing tokens instantiate the indexed prefix of this access, retain that typed prefix // and append the fields which belong to the load itself. - if (auto* existing = dynamic_cast(new_val->try_as_single_active_element()); - existing && !existing->is_addr_of()) { + if (auto* existing = dynamic_cast(new_val->try_as_single_active_element())) { const auto& existing_tokens = existing->tokens(); for (size_t overlap = std::min(existing_tokens.size(), m_deref_tokens.size()); overlap > 0; --overlap) { @@ -7321,8 +7320,8 @@ void ArrayFieldAccess::update_with_val(Form* new_val, auto combined_tokens = existing_tokens; combined_tokens.insert(combined_tokens.end(), m_deref_tokens.begin() + overlap, m_deref_tokens.end()); - result->push_back(pool.alloc_element(existing->base(), existing->is_addr_of(), - combined_tokens)); + result->push_back( + pool.alloc_element(existing->base(), false, combined_tokens)); return; } } diff --git a/decompiler/config/jak1/all-types.gc b/decompiler/config/jak1/all-types.gc index 9deff7865d..ee8230cfb0 100644 --- a/decompiler/config/jak1/all-types.gc +++ b/decompiler/config/jak1/all-types.gc @@ -13029,6 +13029,15 @@ buffer as two allocations in the collide-mesh category.") ;; - Types +(defenum collide-prim-id + :type int8 + (invalid -2) + (sphere -1) + (group 0) + (fg-mesh 1) + (bg-mesh 2) + ) + (declare-type collide-shape-prim basic) (deftype collide-sticky-rider (structure) ((rider-handle handle :offset-assert 0) @@ -13227,21 +13236,12 @@ past the end of the movement step." (_type_ vector) symbol) ;; 9 (indestructible 4) ;; can't attack it. ) -(defenum collide-prim-type - :type int8 - :bitfield #t - (bad -2) - (unk0 0) - (unk1 1) - ) - - (deftype collide-prim-core (structure) ((world-sphere vector :inline :offset-assert 0) (collide-as collide-kind :offset-assert 16) (action collide-action :offset-assert 24) (offense collide-offense :offset-assert 28) - (prim-type int8 :offset-assert 29) + (prim-type collide-prim-id :offset-assert 29) (extra uint8 2 :offset-assert 30) (quad uint128 2 :offset 0) ) @@ -13264,7 +13264,7 @@ past the end of the movement step." (_type_ vector) symbol) ;; 9 (collide-as collide-kind :offset 32) (action collide-action :offset 40) (offense collide-offense :offset 44) - (prim-type int8 :offset 45) + (prim-type collide-prim-id :offset 45) (radius meters :offset 60) ) :method-count-assert 28 @@ -14921,6 +14921,7 @@ when hand placement and hanging clearance succeed." ;; - Types + (deftype bsp-node (structure) ;; A plane selects front when dot(position, plane.xyz) - plane.w is nonnegative. Positive ;; children are bsp-node pointers; nonpositive children identify terminal sides. Visibility @@ -14945,7 +14946,7 @@ when hand placement and hanging clearance succeed." (all-visible-list (pointer uint16) :offset-assert 32) (visible-list-length int32 :offset-assert 36) (drawable-trees drawable-tree-array :offset-assert 40) - (pat pointer :offset-assert 44) + (pat (pointer pat-surface) :offset-assert 44) (pat-length int32 :offset-assert 48) ;; some sort of texture remapping info @@ -14972,8 +14973,8 @@ when hand placement and hanging clearance succeed." ;; Packed neighboring-level flags from the terminal BSP side containing the camera. (current-bsp-back-flags uint32 :offset-assert 152) (ambients drawable-inline-array-ambient :offset-assert 156) - (unk-data-4 float :offset-assert 160) - (unk-data-5 float :offset-assert 164) + (subdivide-close-distance meters :offset-assert 160) + (subdivide-far-distance meters :offset-assert 164) (adgifs adgif-shader-array :offset-assert 168) (actor-birth-order (pointer uint32) :offset-assert 172) (split-box-indices (pointer uint16) :offset-assert 176) diff --git a/goal_src/jak1/engine/anim/joint-mod-h.gc b/goal_src/jak1/engine/anim/joint-mod-h.gc index 9358efb7c2..faaf473167 100644 --- a/goal_src/jak1/engine/anim/joint-mod-h.gc +++ b/goal_src/jak1/engine/anim/joint-mod-h.gc @@ -17,13 +17,9 @@ ;; variation into an animation. (define-extern joint-mod-look-at-handler (function cspace transformq none)) - (define-extern joint-mod-world-look-at-handler (function cspace transformq none)) - (define-extern joint-mod-rotate-handler (function cspace transformq none)) - (define-extern joint-mod-joint-set-handler (function cspace transformq none)) - (define-extern joint-mod-joint-set*-handler (function cspace transformq none)) ;; There are several modes available for joint-mod. @@ -179,12 +175,15 @@ (defmethod set-target! ((this joint-mod) (target-trans vector)) "Set the joint-mod to look-at if we aren't in a mode, and look at the given target-trans." ;; set mode, if we aren't in one. - (if (= (-> this mode) (joint-mod-handler-mode reset)) (set-mode! this (joint-mod-handler-mode look-at))) + (if (= (-> this mode) (joint-mod-handler-mode reset)) + (set-mode! this (joint-mod-handler-mode look-at))) ;; how far are we from the target? (let ((distance (vector-vector-distance (-> this process root trans) target-trans))) (set! (-> this shutting-down?) #f) (vector-copy! (-> this target) target-trans) - (if (< distance (-> this max-dist)) (set! (-> this blend) 1.0) (set! (-> this blend) 0.0))) + (if (< distance (-> this max-dist)) + (set! (-> this blend) 1.0) + (set! (-> this blend) 0.0))) 0 (none)) @@ -246,36 +245,42 @@ (f0-1 (deg-diff f30-0 f0-0))) (if (< (-> gp-0 ignore-angle) (fabs f0-1)) (set! f0-1 0.0)) (let ((f30-1 (fmax (fmin (* f0-1 (-> gp-0 blend) (-> gp-0 flex-blend)) (-> gp-0 twist-max y)) (- (-> gp-0 twist-max y))))) - (if (and (-> gp-0 shutting-down?) (= (-> gp-0 twist y) f30-1)) (set-mode! gp-0 (joint-mod-handler-mode reset))) + (if (and (-> gp-0 shutting-down?) (= (-> gp-0 twist y) f30-1)) + (set-mode! gp-0 (joint-mod-handler-mode reset))) (set! (-> gp-0 twist y) (deg-seek (-> gp-0 twist y) f30-1 (* 0.1 (fabs (deg-diff f30-1 (-> gp-0 twist y)))))))) (let ((v1-15 (-> gp-0 up))) (cond - ((zero? v1-15) (quaternion-rotate-x! (-> xform quat) (-> xform quat) (-> gp-0 twist y))) - ((= v1-15 1) (quaternion-rotate-local-y! (-> xform quat) (-> xform quat) (-> gp-0 twist y))) - (else (quaternion-rotate-z! (-> xform quat) (-> xform quat) (-> gp-0 twist y))))) - (let* ((s3-1 (vector-normalize-copy! (new 'stack-no-clear 'vector) - (the-as vector (-> gp-0 process node-list data 0 bone transform)) - 1.0)) + ((zero? v1-15) + (quaternion-rotate-x! (-> xform quat) (-> xform quat) (-> gp-0 twist y))) + ((= v1-15 1) + (quaternion-rotate-local-y! (-> xform quat) (-> xform quat) (-> gp-0 twist y))) + (else + (quaternion-rotate-z! (-> xform quat) (-> xform quat) (-> gp-0 twist y))))) + (let* ((s3-1 (vector-normalize-copy! (new 'stack-no-clear 'vector) (-> gp-0 process node-list data 0 bone transform vector 0) 1.0)) (f30-2 (vector-x-angle sv-52)) (s3-2 (vector-flatten! (new-stack-vector0) sv-56 s3-1)) (f0-15 (vector-x-angle s3-2)) (f0-21 (fmax (fmin (* (- (deg-diff f30-2 f0-15)) (-> gp-0 blend) (-> gp-0 flex-blend)) (-> gp-0 twist-max x)) (- (-> gp-0 twist-max x))))) - (if (< (vector-dot s3-2 sv-52) 0.1) (set! f0-21 0.0)) + (if (< (vector-dot s3-2 sv-52) 0.1) + (set! f0-21 0.0)) (set! (-> gp-0 twist x) (deg-seek (-> gp-0 twist x) f0-21 (* 0.1 (fabs (deg-diff f0-21 (-> gp-0 twist x)))))))) (let ((v1-27 (-> gp-0 ear))) (cond - ((zero? v1-27) (quaternion-rotate-x! (-> xform quat) (-> xform quat) (-> gp-0 twist x))) - ((= v1-27 1) (quaternion-rotate-local-y! (-> xform quat) (-> xform quat) (-> gp-0 twist x))) - (else (quaternion-rotate-z! (-> xform quat) (-> xform quat) (-> gp-0 twist x))))) + ((zero? v1-27) + (quaternion-rotate-x! (-> xform quat) (-> xform quat) (-> gp-0 twist x))) + ((= v1-27 1) + (quaternion-rotate-local-y! (-> xform quat) (-> xform quat) (-> gp-0 twist x))) + (else + (quaternion-rotate-z! (-> xform quat) (-> xform quat) (-> gp-0 twist x))))) (cspace<-parented-transformq-joint! csp xform) (if (and (= (-> gp-0 process type) target) (!= (-> gp-0 blend) 0.0)) - (add-debug-text-sphere *display-target-marks* - (bucket-id debug-no-zbuf) - (-> gp-0 target) - 819.2 - "look" - (new 'static 'rgba :r #xff :g #xff :a #x80)))) + (add-debug-text-sphere *display-target-marks* + (bucket-id debug-no-zbuf) + (-> gp-0 target) + 819.2 + "look" + (new 'static 'rgba :r #xff :g #xff :a #x80)))) 0 (none)) @@ -299,32 +304,34 @@ (s4-2 (-> s5-0 vector 3 quad))) (matrix*! s5-0 s5-0 a2-3) (set! (-> s5-0 vector 3 quad) s4-2))) - (let* ((s4-3 (vector-normalize-copy! (new 'stack-no-clear 'vector) - (the-as vector (-> gp-0 process node-list data 0 bone transform)) - 1.0)) + (let* ((s4-3 (vector-normalize-copy! (new 'stack-no-clear 'vector) (-> gp-0 process node-list data 0 bone transform vector 0) 1.0)) (f30-2 (vector-x-angle sv-52)) (s4-4 (vector-flatten! (new-stack-vector0) sv-56 s4-3)) (f0-14 (vector-x-angle s4-4)) (f0-20 (fmax (fmin (* (- (deg-diff f30-2 f0-14)) (-> gp-0 blend) (-> gp-0 flex-blend)) (-> gp-0 twist-max x)) (- (-> gp-0 twist-max x))))) - (if (< (vector-dot s4-4 sv-52) 0.1) (set! f0-20 0.0)) + (if (< (vector-dot s4-4 sv-52) 0.1) + (set! f0-20 0.0)) (set! (-> gp-0 twist x) (deg-seek (-> gp-0 twist x) f0-20 (fmax 1.0 (* 0.1 (fabs (deg-diff f0-20 (-> gp-0 twist x))))))))) (when (!= (-> gp-0 twist x) 0.0) (let* ((v1-20 (-> gp-0 ear)) (a1-17 ((cond - ((zero? v1-20) matrix-rotate-x!) - ((= v1-20 1) matrix-rotate-y!) - (else matrix-rotate-z!)) + ((zero? v1-20) + matrix-rotate-x!) + ((= v1-20 1) + matrix-rotate-y!) + (else + matrix-rotate-z!)) (new 'stack-no-clear 'matrix) (-> gp-0 twist x)))) (matrix*! s5-0 a1-17 s5-0)))) (if (and (= (-> gp-0 process type) target) (!= (-> gp-0 blend) 0.0)) - (add-debug-text-sphere *display-target-marks* - (bucket-id debug-no-zbuf) - (-> gp-0 target) - 819.2 - "look" - (new 'static 'rgba :r #xff :g #xff :a #x80)))) + (add-debug-text-sphere *display-target-marks* + (bucket-id debug-no-zbuf) + (-> gp-0 target) + 819.2 + "look" + (new 'static 'rgba :r #xff :g #xff :a #x80)))) 0 (none)) @@ -380,7 +387,8 @@ (quaternion-normalize! (quaternion*! (-> local-transform quat) (-> local-transform quat) (-> s5-0 quat))) (vector*! (-> local-transform scale) (-> local-transform scale) (-> s5-0 scale)) (cspace<-parented-transformq-joint! node local-transform) - (if (-> s5-0 max-dist) (set-vector! (-> node bone scale) 1.0 1.0 1.0 1.0))) + (if (-> s5-0 max-dist) + (set-vector! (-> node bone scale) 1.0 1.0 1.0 1.0))) 0 (none)) @@ -461,13 +469,18 @@ (let ((v1-0 (the-as joint-mod-set-local (-> node param1)))) (cond ((-> v1-0 enable) - (if (not (-> v1-0 set-translation)) (vector-copy! (-> v1-0 transform trans) (-> local-transform trans))) - (if (not (-> v1-0 set-rotation)) (set! (-> v1-0 transform quat vec quad) (-> local-transform quat vec quad))) - (if (not (-> v1-0 set-scale)) (vector-copy! (-> v1-0 transform scale) (-> local-transform scale))) + (if (not (-> v1-0 set-translation)) + (vector-copy! (-> v1-0 transform trans) (-> local-transform trans))) + (if (not (-> v1-0 set-rotation)) + (vector-copy! (-> v1-0 transform quat vec) (-> local-transform quat vec))) + (if (not (-> v1-0 set-scale)) + (vector-copy! (-> v1-0 transform scale) (-> local-transform scale))) (cspace<-parented-transformq-joint! node (-> v1-0 transform))) - (else (cspace<-parented-transformq-joint! node local-transform)))) + (else + (cspace<-parented-transformq-joint! node local-transform)))) (none)) + (defmethod new joint-mod-set-local ((allocation symbol) (type-to-make type) (process process-drawable) diff --git a/goal_src/jak1/engine/camera/pov-camera-h.gc b/goal_src/jak1/engine/camera/pov-camera-h.gc index 642a80aba7..234de5ef36 100644 --- a/goal_src/jak1/engine/camera/pov-camera-h.gc +++ b/goal_src/jak1/engine/camera/pov-camera-h.gc @@ -2,6 +2,7 @@ (in-package goal) (bundles "ENGINE.CGO" "GAME.CGO") (require "engine/game/game-h.gc") + (defenum pov-camera-flag :bitfield #t :type int32 @@ -31,7 +32,7 @@ ;; streamed animation. The broad basic type on anim-name is required to hold ;; either form. (deftype pov-camera (process-drawable) - (;; The animated camera's cspace nodes occupy the drawable root storage. + (;; I think this field is wrong... (cspace-array cspace-array :overlay-at root) (flags pov-camera-flag) ;; Controller aborts are ignored briefly after playback begins. @@ -40,7 +41,7 @@ (notify-handle handle) ;; A camera animation name or a spool-anim. (anim-name basic) - ;; Timed commands accompanying an in-memory animation. + ;; Timed commands accompanying an animation. (command-list pair) ;; Processes suppressed while othercam owns the view. (mask-to-clear process-mask) diff --git a/goal_src/jak1/engine/collide/collide-cache-h.gc b/goal_src/jak1/engine/collide/collide-cache-h.gc index 33fb8746b1..cdba3ec7be 100644 --- a/goal_src/jak1/engine/collide/collide-cache-h.gc +++ b/goal_src/jak1/engine/collide/collide-cache-h.gc @@ -5,9 +5,7 @@ ;; Broad-phase tests use *collide-work*, which is prepared for the active cache fill. (define-extern collide-cache-using-line-sphere-test (function vector symbol)) - (define-extern collide-cache-using-y-probe-test (function vector symbol)) - (define-extern collide-cache-using-box-test (function vector symbol)) ;; DECOMP BEGINS @@ -28,12 +26,14 @@ (solid-only symbol))) (deftype collide-puss-sphere (structure) - "One query sphere and its integer-coordinate bounding box in the sphere-probe scratchpad work." + "One query sphere and its integer-coordinate bounding box in the sphere-probe scratchpad work. + PUSS = prim-using-spheres ?" ((bsphere sphere :inline) (bbox4w bounding-box4w :inline))) (deftype collide-puss-work (structure) - "Scratchpad work for testing the cached primitives against as many as 64 query spheres." + "Scratchpad work for testing the cached primitives against as many as 64 query spheres. + PUSS = prim-using-spheres ?" ((closest-pt vector :inline) (tri-normal vector :inline) (tri-bbox4w bounding-box4w :inline) @@ -45,7 +45,8 @@ (deftype collide-puyp-work (structure) "Working state for a downward Y probe. best-u tracks the nearest hit along move-dist and tri-out - receives its surface, point, normal, and representative vertices." + receives its surface, point, normal, and representative vertices. + PUYP = prim-using-y-probe" ((best-u float) (ignore-pat pat-surface) (tri-out collide-tri-result) @@ -57,8 +58,7 @@ ;;;;;;;;;;;;;;;;;;;;;;; (deftype collide-cache-tri (structure) - "One world-space triangle in the collision cache. Its final quadword overlays the surface - properties, owning primitive index, and query-specific user values." + "One world-space triangle in the collision cache." ((vertex vector 3 :inline) ;; actual locations (extra-quad uint128 :offset 48) (pat pat-surface :overlay-at extra-quad) ; metadata about the surface of this tri diff --git a/goal_src/jak1/engine/collide/collide-frag-h.gc b/goal_src/jak1/engine/collide/collide-frag-h.gc index f37ef67d7a..d4faa715cb 100644 --- a/goal_src/jak1/engine/collide/collide-frag-h.gc +++ b/goal_src/jak1/engine/collide/collide-frag-h.gc @@ -16,7 +16,6 @@ ;; compact vertices and strips into ordinary collision triangles. These fragments do not ;; participate directly in the foreground collide-shape hierarchy. -;; Defined with the drawable methods and used by collide-frag's optional debug drawing. (define-extern sphere-cull (function vector symbol)) ;; One expanded background-collision vertex. @@ -30,12 +29,14 @@ (strip-data-len uint16) ;; Byte length of the strip stream, including its terminators. (poly-count uint16) (base-trans vector :inline) ;; Fixed-point translation applied while expanding vertices. - ;; These bytes occupy base-trans.w, which is not part of the XYZ translation. (vertex-count uint8 :overlay-at (-> base-trans w)) (vertex-data-qwc uint8 :offset 29) (total-qwc uint8 :offset 30) (unused uint8 :offset 31))) +;; drawable containing a collide-fragment. +;; These drawables are inserted into the BVH tree for broad-phase collision filtering. + (deftype collide-fragment (drawable) ((mesh collide-frag-mesh :offset 8))) diff --git a/goal_src/jak1/engine/collide/collide-func-h.gc b/goal_src/jak1/engine/collide/collide-func-h.gc index a0c2e07a72..77eecbadb4 100644 --- a/goal_src/jak1/engine/collide/collide-func-h.gc +++ b/goal_src/jak1/engine/collide/collide-func-h.gc @@ -2,4 +2,4 @@ (in-package goal) (bundles "ENGINE.CGO" "GAME.CGO") -;; Collision function declarations are provided by collide-func.gc. +;; Empty. diff --git a/goal_src/jak1/engine/collide/collide-h.gc b/goal_src/jak1/engine/collide/collide-h.gc index 10322bb7d1..9946590ea1 100644 --- a/goal_src/jak1/engine/collide/collide-h.gc +++ b/goal_src/jak1/engine/collide/collide-h.gc @@ -1,4 +1,6 @@ ;;-*-Lisp-*- (in-package goal) (bundles "ENGINE.CGO" "GAME.CGO") + +;; unused flag. (define *collide-test-flag* #f) diff --git a/goal_src/jak1/engine/collide/collide-mesh-h.gc b/goal_src/jak1/engine/collide/collide-mesh-h.gc index 3c3700725b..619dab21a3 100644 --- a/goal_src/jak1/engine/collide/collide-mesh-h.gc +++ b/goal_src/jak1/engine/collide/collide-mesh-h.gc @@ -6,8 +6,8 @@ ;; DECOMP BEGINS ;; Foreground collision meshes belong to moving, jointed objects such as platforms. Their compact -;; local-space vertices and triangles are transformed on demand for collision tests. Static level -;; geometry uses collide-frag-mesh instead. +;; local-space vertices and triangles are transformed to world-space on demand for collision tests. +;; Static level geometry uses collide-frag-mesh instead. ;;;;;;;;;;;;;;;;;;;; ;; result @@ -15,7 +15,7 @@ ;; The triangle and contact selected by a collision test. vertex holds the three world-space ;; corners, intersect is the closest/contact point, normal faces away from the triangle, and pat -;; identifies the surface. Background collision tests use the same result format. +;; identifies the surface parameters. Background collision tests use the same result format. (deftype collide-tri-result (structure) ((vertex vector 3 :inline) (intersect vector :inline) @@ -38,8 +38,6 @@ (declare-type collide-mesh-cache-tri structure) ;; A compact collision mesh bound to one model joint. vertex-data points to local-space positions -;; padded through the next group of four because the transform passes always load four vectors at a -;; time. The variable-length tris array follows the fixed header and indexes the logical positions. (deftype collide-mesh (basic) ((joint-id int32) (num-tris uint32) @@ -64,9 +62,7 @@ ;; of transforming the mesh for every query. This is separate from the general collide-cache used ;; for background and mixed collision probes. ;; -;; id identifies the current cache generation. Every allocation owner keeps the id with its cached -;; triangle pointer; clearing or wrapping the cache advances id, invalidating all of those pointers -;; without walking their owners. +;; ID is used to invalidate the cache when the data is changed ;; og:preserve-this (defconstant COLLIDE_MESH_CACHE_SIZE #xa000) @@ -85,8 +81,6 @@ (defmethod next-id! ((this collide-mesh-cache)) "Discard all cached blocks and advance to a nonzero generation id." (declare (asm-func uint)) - ;; Generation zero is reserved. The likely branch changes a wrapped increment to one without - ;; executing its delay instruction for the normal case. (rlet ((this-reg :reg a0) (current-id :reg v1) (next-id :reg v0)) @@ -110,7 +104,7 @@ (= (-> this id) cache-id)) ;; Expanded cache entry: three world-space vertices, a unit normal, an integer-coordinate bounding -;; box for fast rejection, and surface properties packed into the otherwise-unused normal.w lane. +;; box for fast rejection, and surface properties packed into normal.w. (deftype collide-mesh-cache-tri (structure) ((vertex vector 3 :inline) (normal vector :inline) diff --git a/goal_src/jak1/engine/collide/collide-shape-h.gc b/goal_src/jak1/engine/collide/collide-shape-h.gc index d8d0be052d..da0c1d8f15 100644 --- a/goal_src/jak1/engine/collide/collide-shape-h.gc +++ b/goal_src/jak1/engine/collide/collide-shape-h.gc @@ -24,8 +24,7 @@ ;; geometry or water. ;; ;; General movement queries collect background, water, and foreground primitives into collide-cache, -;; then resolve against that common representation. Foreground mesh handling is duplicated because -;; this path imports expanded mesh triangles into the general cache. +;; then resolve against that common representation. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -67,7 +66,6 @@ #f) ;; A collection of collide-sticky-riders -;; dynamic type. There's one collide-sticky-rider per rider. (deftype collide-sticky-rider-group (basic) ((num-riders int32) (allocated-riders int32) @@ -138,14 +136,15 @@ ((options overlaps-others-options) (tlist touching-list))) -;; The engine system is used to link collision checks with processes. -;; This allows you to have lists of processes where the process will remove itself when it dies. +;; The engine system is used to connect the collision system to processes with collision +;; geometry. There are several different lists available. +;; - hit-by-player is for things that only the player hits (powerups) +;; - usually-hit-by-player for things that jak and others hits: crates, creatures, etc +;; - hit-by-others is a bit weird. In practice, it's used for geometry that the camera should +;; avoid, like doors, big platforms, etc. (define *collide-hit-by-player-list* (new 'global 'engine 'collide-hit-by-player-list 768)) - (define *collide-usually-hit-by-player-list* (new 'global 'engine 'collide-usually-hit-by-player-list 256)) - (define *collide-hit-by-others-list* (new 'global 'engine 'collide-hit-by-others-list 96)) - (define *collide-player-list* (new 'global 'engine 'collide-player-list 32)) (defenum collide-list-enum @@ -164,17 +163,17 @@ :type uint64 :bitfield #t (background 0) - (hit-by-player 1) ;; hit by player - (usually-hit-by-player 2) ;; usually hit by player - (hit-by-others 3) ;; hit by others - (target 4) ;; target + (hit-by-player 1) + (usually-hit-by-player 2) + (hit-by-others 3) + (target 4) (water 5) (powerup 6) (crate 7) (enemy 8) ;; also used for powerups (wall-object 9) ;; also object. door, pusher (blockers?) (projectile 10) - (ground-object 11) ;; object, like darkecobarray, platforms + (ground-object 11) ;; object, platforms (target-attack 12) ;; all target attacks (mother-spider 13) (cak-14 14) ;; unused @@ -262,6 +261,17 @@ (indestructible 4) ;; can't attack it. ) +;; Identification of prim type +(defenum collide-prim-id + :type int8 + (invalid -2) ;; error + (sphere -1) + (group 0) + (fg-mesh 1) + (bg-mesh 2) ;; used for meshes faked through water/background + ) + + ;; Every primitive has a prim-core. ;; this is a 32-byte chunk of data that can be pulled out an put in collide caches ;; it stores the transformed world sphere and the collision settings @@ -270,22 +280,23 @@ (collide-as collide-kind) (action collide-action) (offense collide-offense) - (prim-type int8) + (prim-type collide-prim-id) (extra uint8 2) (quad uint128 2 :overlay-at (-> world-sphere quad)))) (declare-type collide-shape basic) - (declare-type collide-cache-prim structure) - (declare-type collide-shape-prim-group basic) - (declare-type collide-cache basic) + ;; the base class for collision shapes. (deftype collide-shape-prim (basic) ((cshape collide-shape) (prim-id uint32) + ;; -2 : local-sphere is relative to cshape + ;; -1 : user is responsible for setting world-sphere + ;; 0+: use bone translation (transform-index int8) (prim-core collide-prim-core :inline) (local-sphere vector :inline) @@ -294,7 +305,7 @@ (collide-as collide-kind :overlay-at (-> prim-core collide-as)) (action collide-action :overlay-at (-> prim-core action)) (offense collide-offense :overlay-at (-> prim-core offense)) - (prim-type int8 :overlay-at (-> prim-core prim-type)) + (prim-type collide-prim-id :overlay-at (-> prim-core prim-type)) (radius meters :overlay-at (-> local-sphere w))) (:methods (new (symbol type collide-shape uint int) _type_) @@ -327,7 +338,7 @@ ;; sphere collision ;; the pat is stored directly here. -;; I believe the "local sphere" is used as the sphere. +;; The "local sphere" is used as the sphere geometry. (deftype collide-shape-prim-sphere (collide-shape-prim) ((pat pat-surface)) (:methods @@ -335,8 +346,9 @@ ;; mesh collision ;; the pats are stored per tri in the mesh. -;; These meshes interact with a cache automatically (a specific collide-shape-prim-mesh cache, not the -;; more general collide-cache) +;; For direct collision queries (not through collide-cache), these +;; get unpacked into a separate mesh-cache that holds only +;; a single mesh. (deftype collide-shape-prim-mesh (collide-shape-prim) ((mesh collide-mesh) (mesh-id int32) @@ -363,11 +375,14 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This is sort of the "parent" of all collide prims for a process-drawable. -;; Each process-drawable (pd) should have one collide-shape, which is often the root. +;; Each process-drawable (pd) can have one collide-shape. ;; It represents: ;; - the location of the thing in the world ;; - settings abouts collision/navigation ;; - riders +;; since collide-shape is a child of trsqv, it can overlay +;; the existing "root" field, so its position simultaneously sets +;; the process location for drawing, collision, and gameplay logic. (declare-type collide-work structure) @@ -385,7 +400,7 @@ (navf6 6) (navf7 7)) -;; we're a child of trsqv, so we store a full transform + derivative. +;; we're a child of trsqv, so we store a full transform + velocity. (deftype collide-shape (trsqv) ((process process-drawable) (max-iteration-count uint8) @@ -536,7 +551,7 @@ (csrf30) (csrf31)) -;; A collide-shape for independently moving objects +;; A collide-shape for independently moving objects. (deftype collide-shape-moving (collide-shape) ((rider-time time-frame) (rider-last-move vector :inline) @@ -589,7 +604,7 @@ (set! (-> this collide-with) (collide-kind)) (set! (-> this transform-index) -2) (set! (-> this prim-core offense) (collide-offense no-offense)) - (set! (-> this prim-core prim-type) -2) + (set! (-> this prim-core prim-type) (collide-prim-id invalid)) this)) (defmethod new collide-shape-prim-sphere ((allocation symbol) (type-to-make type) (cshape collide-shape) (prim-id uint)) @@ -597,7 +612,7 @@ (let ((this (the collide-shape-prim-sphere ((method-of-type collide-shape-prim new) allocation type-to-make cshape prim-id (size-of collide-shape-prim-sphere))))) (set! (-> this pat) (new 'static 'pat-surface :mode (pat-mode obstacle))) - (set! (-> this prim-core prim-type) -1) + (set! (-> this prim-core prim-type) (collide-prim-id sphere)) this)) (defmethod new collide-shape-prim-mesh ((allocation symbol) (type-to-make type) (cshape collide-shape) (mesh-id uint) (prim-id uint)) @@ -607,7 +622,7 @@ (set! (-> this mesh) #f) (set! (-> this mesh-id) (the-as int mesh-id)) (set! (-> this mesh-cache-id) (the-as uint 0)) - (set! (-> this prim-core prim-type) 1) + (set! (-> this prim-core prim-type) (collide-prim-id fg-mesh)) (the-as collide-shape-prim-mesh this))) (defmethod new collide-shape-prim-group ((allocation symbol) (type-to-make type) (cshape collide-shape) (element-count uint) (prim-id int)) @@ -621,7 +636,7 @@ (the int (+ (-> type-to-make size) (* (+ element-count -1) 4))))))) (set! (-> this allocated-prims) (the int element-count)) (set! (-> this num-prims) 0) - (set! (-> this prim-core prim-type) 0) + (set! (-> this prim-core prim-type) (collide-prim-id group)) (while (nonzero? element-count) (+! element-count -1) (set! (-> this prims element-count) #f) @@ -647,6 +662,7 @@ (set! (-> this event-other) #f) (set! (-> this riders) #f) (set! (-> this root-prim) #f) + ;; ignore the appropriate PATs (case (-> proc type symbol) (('camera) (set! (-> this pat-ignore-mask) (new 'static 'pat-surface :nocamera #x1))) (else (set! (-> this pat-ignore-mask) (new 'static 'pat-surface :noentity #x1)))) @@ -680,6 +696,7 @@ "Return the header size plus storage for the allocated rider capacity." (the-as int (+ (-> this type size) (* (+ (-> this allocated-riders) -1) 32)))) +;; Fake collide-shape-prim for collisions generated from the background. (define *collide-shape-prim-backgnd* (new 'static 'collide-shape-prim-mesh @@ -692,7 +709,7 @@ :collide-as (collide-kind background) :action (collide-action solid) :offense (collide-offense indestructible) - :prim-type 2) + :prim-type (collide-prim-id bg-mesh)) :local-sphere (new 'static 'vector :w 204800000.0) :mesh #f)) @@ -709,7 +726,7 @@ :collide-as (collide-kind water) :action (collide-action solid) :offense (collide-offense indestructible) - :prim-type 2) + :prim-type (collide-prim-id bg-mesh)) :local-sphere (new 'static 'vector :w 204800000.0) :mesh #f)) diff --git a/goal_src/jak1/engine/collide/collide-target-h.gc b/goal_src/jak1/engine/collide/collide-target-h.gc index 93f2c9f985..9237edf8eb 100644 --- a/goal_src/jak1/engine/collide/collide-target-h.gc +++ b/goal_src/jak1/engine/collide/collide-target-h.gc @@ -5,10 +5,7 @@ ;; DECOMP BEGINS -;; target-collision-reaction records the result of each collision frame in a 128-entry ring. -;; An entry keeps the contact point, final position, incoming and outgoing velocity, contact -;; normals, collision state, reaction flags, surface properties, and time. Airborne frames get -;; a minimal entry so readers can walk the ring without losing the frame sequence. +;; History of collision from target, used for debugging. (deftype collide-history (structure) ((intersect vector :inline) (trans vector :inline) @@ -23,10 +20,7 @@ (:methods (update! (_type_ collide-shape-moving vector vector vector) _type_))) -;; Jak's collision shape and movement state. The control frame rotates world velocity into Jak's -;; facing frame so thrust, gravity, and surface response can be applied consistently before the -;; velocity is rotated back to world space. The remainder of the type carries input, contact -;; probes, attack state, edge-grab state, shared state-machine scratch, and collision history. +;; Jak's collision shape and movement state. ;; ;; state-var0/1/2 and state-vector0/1 are deliberately shared between target states. The named ;; overlays select the interpretation used by each state. saved-launch-event through @@ -118,7 +112,6 @@ (danger-sphere0 collide-shape-prim-sphere :offset 1632) (danger-sphere1 collide-shape-prim-sphere :offset 1636) (danger-sphere2 collide-shape-prim-sphere :offset 1640) - ;; Move cooldowns, body attachments, and velocity history. (wheel-counter int32 :offset 1656) (last-wheel-end-time time-frame :offset 1664) (last-running-attack-end-time time-frame :offset 1672) @@ -142,7 +135,6 @@ (transv-history vector 16 :inline :offset 1856) (average-xz-vel float :offset 2112) (idx-of-fastest-xz-vel int32 :offset 2116) - ;; Edge-grab and per-state data. (hand-to-edge-dist float :offset 2120) (edge-grab-edge-dir vector :inline :offset 2128) (edge-grab-across-edge-dir vector :inline :offset 2144) @@ -179,7 +171,6 @@ (launch-camera-state int64 :offset 2440) (launch-dest int64 :offset 2448) (launch-tracking-time int64 :offset 2456) - ;; Collision history and the PAL-expanded tail. (history-data-idx int16 :offset 2488) (history-length int16 :offset 2490) (history-data collide-history 128 :inline) @@ -202,9 +193,7 @@ (unknown-int36 int32 :offset 19000))) (defmethod update! ((this collide-history) (shape collide-shape-moving) (intersect vector) (incoming-velocity vector) (outgoing-velocity vector)) - "Record a collision-history sample, including the contact point, final position, - incoming and outgoing velocity, contact normals, collision state, reaction flags, surface - properties, and the current time." + "Record a collision-history sample." (vector-copy! (-> this intersect) intersect) (vector-copy! (-> this transv) incoming-velocity) (vector-copy! (-> this transv-out) outgoing-velocity) diff --git a/goal_src/jak1/engine/collide/pat-h.gc b/goal_src/jak1/engine/collide/pat-h.gc index 09b5e78085..9f8bd1b778 100644 --- a/goal_src/jak1/engine/collide/pat-h.gc +++ b/goal_src/jak1/engine/collide/pat-h.gc @@ -2,6 +2,13 @@ (in-package goal) (bundles "ENGINE.CGO" "GAME.CGO") (require "engine/math/math.gc") + +;; PAT packs the collision behavior of each mesh triangle into one 32-bit word. +;; The low three skip bits can exclude the triangle from entity, camera, or edge +;; queries. Mode classifies its collision response, material selects movement, +;; sound, and particle effects, camera holds camera-query flags, and event selects +;; a contact hazard. + (defenum pat-material :type uint8 (stone) @@ -46,12 +53,6 @@ ;; DECOMP BEGINS -;; PAT packs the collision behavior of each mesh triangle into one 32-bit word. -;; The low three skip bits can exclude the triangle from entity, camera, or edge -;; queries. Mode classifies its collision response, material selects movement, -;; sound, and particle effects, camera holds camera-query flags, and event selects -;; a contact hazard. - (deftype pat-surface (uint32) ((skip uint8 :offset 0 :size 3) ;; combined collision-query skip mask (mode pat-mode :offset 3 :size 3) @@ -62,8 +63,7 @@ (nocamera uint8 :offset 1 :size 1) ;; exclude from camera collision queries (noedge uint8 :offset 2 :size 1) ;; exclude from edge queries (nolineofsight uint8 :offset 12 :size 1) ;; exclude from camera line-of-sight queries - ;; Ignore endless-fall contacts. This overlaps bit 1 of event because ignore - ;; masks use the same packed bit positions as triangle PAT values. + ;; Ignore endless-fall contacts. (noendlessfall uint8 :offset 15 :size 1))) (defun-debug pat-material->string ((pat pat-surface)) diff --git a/goal_src/jak1/engine/collide/surface-h.gc b/goal_src/jak1/engine/collide/surface-h.gc index d5d01d0351..a3fef29755 100644 --- a/goal_src/jak1/engine/collide/surface-h.gc +++ b/goal_src/jak1/engine/collide/surface-h.gc @@ -2,6 +2,7 @@ (in-package goal) (bundles "ENGINE.CGO" "GAME.CGO") (require "kernel/gcommon.gc") + (defenum surface-flags :bitfield #t :type uint32 @@ -22,10 +23,10 @@ (prevent-jump) ;; target is launch jumping (from a blue eco pad) (prevent-attacks-during-launch-jump) - ;; never set by any shipped surface, but tested together with the launch-jump bit: + ;; never set by any surface, but tested together with the launch-jump bit: ;; blocks square/"hands" attacks, including the flop out of jump states (prevent-hand-attack) - ;; never set by a shipped surface; blocks circle/"feet" spin attacks + ;; never set by any surface; blocks circle/"feet" spin attacks (prevent-feet-attack) (allow-edge-grab) ;; if set, and jak is falling, turn on the ledge grab search. (jump) ;; set on all jumps, used to prevent "on-grounds" in places @@ -48,7 +49,7 @@ (turnv float) ;; maximum rate for turning the facing direction (turnvv float) ;; maximum rate for steering the target direction (tiltv float) ;; maximum rate for leaning toward the surface normal - (tiltvv float) + (tiltvv float) ;; unused (transv-max float) ;; hard speed limit (target-speed float) ;; full-stick speed that acceleration seeks (seek0 float) ;; acceleration with input aligned to motion @@ -79,18 +80,18 @@ ;; these calc-terminal functions are unused. (defun calc-terminal-vel ((acceleration float) (constant-drag float) (drag-coefficient float)) - "Compute the fixed-point velocity for the legacy linear drag equation from per-second + "Compute the final velocity for the legacy linear drag equation from per-second acceleration, constant drag, and the linear drag coefficient." (- (* (/ (- (/ acceleration 60) constant-drag) drag-coefficient) (- 1.0 drag-coefficient)) constant-drag)) (defun calc-terminal2-vel ((acceleration float) (constant-drag float) (drag-coefficient float) (reserved float)) - "Compute the fixed-point velocity for the legacy quadratic drag equation. + "Compute the final velocity for the legacy quadratic drag equation. reserved is accepted by the original interface but is not used." (let ((speed (sqrtf (/ (- (/ acceleration 60) constant-drag) drag-coefficient)))) (- speed (+ constant-drag (* drag-coefficient (square speed)))))) (defun calc-terminal4-vel ((acceleration float) (constant-drag float) (drag-coefficient float)) - "Compute the fixed-point velocity for the legacy fourth-power drag equation from + "Compute the final velocity for the legacy fourth-power drag equation from per-second acceleration, constant drag, and the drag coefficient." (let ((speed (sqrtf (sqrtf (/ (- (/ acceleration 60) constant-drag) drag-coefficient))))) (- speed (+ constant-drag (* drag-coefficient (* (square speed) speed speed)))))) @@ -158,6 +159,7 @@ ;; The common surfaces: +;; modifiers during normal walking/running/standing. (define *walk-mods* (new 'static 'surface @@ -186,6 +188,8 @@ :align-speed 1.0 :flags (surface-flags allow-look-around))) +;; modifiers during punch attack, turnv/turnvv are zero, locking in +;; the punch direction (define *walk-no-turn-mods* (new 'static 'surface @@ -211,6 +215,7 @@ :slope-up-traction 1.0 :align-speed 1.0)) +;; modifiers during the "turn around" animation. (define *turn-around-mods* (new 'static 'surface @@ -233,6 +238,7 @@ :slope-up-traction 1.0 :align-speed 1.0)) +;; slower "duck" crawling walk (let ((a0-3 (new 'static 'surface :name 'duck @@ -263,6 +269,7 @@ ;; og:preserve-this (define *duck-mods* a0-3)) +;; unused. (define *duck-attack-mods* (new 'static 'surface @@ -290,6 +297,7 @@ :mode 'attack :flags (surface-flags attacking ducking))) +;; modifiers for jump (define *jump-mods* (new 'static 'surface @@ -319,6 +327,7 @@ :mode 'air :flags (surface-flags allow-edge-grab jump))) +;; modifiers for jump (define *double-jump-mods* (new 'static 'surface diff --git a/goal_src/jak1/engine/common-obs/generic-obs-h.gc b/goal_src/jak1/engine/common-obs/generic-obs-h.gc index 86a17be9a8..8d55ee27ae 100644 --- a/goal_src/jak1/engine/common-obs/generic-obs-h.gc +++ b/goal_src/jak1/engine/common-obs/generic-obs-h.gc @@ -2,29 +2,20 @@ (in-package goal) (bundles "ENGINE.CGO" "GAME.CGO") (require "engine/game/game-h.gc") + (define-extern mistycam-spawn (function none)) - (define-extern beachcam-spawn (function none)) - (declare-type camera-tracker process) - (define-extern process-grab? (function process symbol :behavior camera-tracker)) - (define-extern process-release? (function process symbol :behavior process)) - (define-extern fuel-cell type) - (define-extern birth-pickup-at-point (function vector pickup-type float symbol process-tree fact-info (pointer process) :behavior process)) (declare-type collide-shape trsqv) - (declare-type collide-shape-moving collide-shape) - (declare-type sparticle-launch-group basic) - (declare-type part-tracker process) - (declare-type collide-prim-core structure) (define-extern part-tracker-init @@ -39,11 +30,8 @@ part-tracker)) (declare-type touch-tracker process-drawable) - (define-extern touch-tracker-init (function vector float time-frame none :behavior touch-tracker)) - (define-extern eco-blue-glow (function vector none)) - (declare-type joint-mod basic) ;; DECOMP BEGINS diff --git a/goal_src/jak1/engine/common-obs/process-drawable-h.gc b/goal_src/jak1/engine/common-obs/process-drawable-h.gc index 3b23d2a8c2..65c20eefc7 100644 --- a/goal_src/jak1/engine/common-obs/process-drawable-h.gc +++ b/goal_src/jak1/engine/common-obs/process-drawable-h.gc @@ -4,10 +4,9 @@ (require "engine/gfx/hw/display-h.gc") (require "engine/anim/joint-h.gc") (require "engine/game/game-h.gc") + (define-extern cspace-index-by-name (function process-drawable string int)) - (define-extern cspace-by-name (function process-drawable string cspace)) - (define-extern joint-control-reset! (function joint-control joint-control-channel none :behavior process-drawable)) (defun cspace-by-name-no-fail ((drawable process-drawable) (name string)) @@ -93,8 +92,7 @@ lets callers hold an animation on an explicitly selected frame." (-> channel frame-num)) -;; Persistent actor state carried between births. A try reset clears #x26f, a full game reset -;; clears #x77f, and force-birth survives both. +;; Persistent actor state carried between births. (defenum entity-perm-status :bitfield #t :type uint16 @@ -116,10 +114,11 @@ Joint-animation recipe for creatures ------------------------------------ -The `ja` helpers operate on `self`'s joint controller. A channel has an animation group, an -internal frame, a frame interpolation value, and a frame-number function. Channel zero is the -ordinary whole-creature animation; use another channel only when the creature's skeleton and art -were authored for a layered animation. +The `ja` helpers operate on a process's joint controller. +The controller tracks multiple "channels", which can be blended together to layer or fade +animations. +Each channel knows the animation, the progress, and has a num-func to produce the next frame +index. Choose the animation with `:group!`, and choose how its frame changes with `:num!`: @@ -133,41 +132,40 @@ Choose the animation with `:group!`, and choose how its frame changes with `:num The speed defaults to 1.0. `seek!` also defaults its target to the animation's last internal frame, so `(seek!)` is the usual one-shot. `ja-aframe` converts an artist's timeline frame to the -internal frame used by `seek!`; use it for authored contacts, anticipation poses, and handoffs. +internal frame used by `seek!`. `ja` applies the requested changes and, when `:num!` selects a frame rule, evaluates the channel -immediately. Direct field changes such as `:group!`, `:num-func`, and `:frame-num` can be combined -to prepare a pose without advancing it. `ja-no-eval` also suppresses the evaluation attached to -`:num!`; that is useful immediately before pushing a blend, or when the caller needs to evaluate -the old stack explicitly with `ja-blend-eval`. +immediately. Setting `:group!`, `:num-func`, and/or `:frame-num` without `:num!` won't evaluate. +`ja-no-eval` can be used to suppresses evaluation even when a new num-func is set with `:num!`. +That is useful when something else will evaluate later and you want to avoid evaluating twice. -`ja-play` is the standard blocking one-shot: it installs the group and frame rule without an -initial evaluation, then suspends once per frame and advances until a seek reaches its target. -Forms in its body run before each suspension, which is where a creature should steer, align root -motion, or evaluate the channels underneath a blend. +`ja-play` is a blocking playback macro: it sets up an animation and runs code in the body until +the animation is done. For a clean transition, call `ja-channel-push!` before selecting the new group. It keeps the old -pose below a new root group and fades it out over the supplied time. During a hand-authored -transition, call `ja-blend-eval` while the new animation plays so the retained pose stays current. -Use `ja-group?` to select animation-specific handoffs rather than restarting a generic pose. +anim below a new root anim and fades it out over the supplied time. During a hand-authored +transition, call `ja-blend-eval` while the new animation plays so the old animation is updated. Typical creature loops are: ;; A looping locomotion cycle. + ;; make the current animation fade out over 0.15 seconds (ja-channel-push! 1 (seconds 0.15)) + ;; install the new main animation of run, starting at min frame (ja :group! creature-run-ja :num! min) + ;; run the run animation in a loop. + ;; evaluation will handle dropping the old animation automatically. (loop (suspend) (ja :num! (loop! run-speed))) - ;; A one-shot action with steering while it plays. + ;; A second example: A one-shot attack animation with steering while it plays. + ;; fade out old anim (ja-channel-push! 1 (seconds 0.1)) + ;; play and steer until attack-ja is done. (ja-play :group! creature-attack-ja :num! (seek!) :frame-num 0.0 (turn-toward-target! self)) -Keep `:frame-num 0.0` on a newly selected one-shot unless the action deliberately joins at a -specific authored pose. A polished creature should blend into new groups, use artist frames for -visual beats, and make its locomotion speed explicit so motion and animation remain in step. |# (defmacro ja-group (&key (chan 0)) diff --git a/goal_src/jak1/engine/debug/debug-h.gc b/goal_src/jak1/engine/debug/debug-h.gc index 00da46c203..7c9ff67d07 100644 --- a/goal_src/jak1/engine/debug/debug-h.gc +++ b/goal_src/jak1/engine/debug/debug-h.gc @@ -7,11 +7,8 @@ (define-extern *debug-menu-context* debug-menu-context) (define-extern add-debug-matrix (function symbol bucket-id matrix matrix)) - (define-extern add-debug-text-sphere (function symbol bucket-id vector float string rgba symbol)) - (define-extern add-debug-line (function symbol bucket-id vector vector rgba symbol rgba symbol)) - (defun-extern add-debug-sphere symbol bucket-id vector float rgba symbol) ;; DECOMP BEGINS @@ -26,18 +23,15 @@ (h-first int32) (h-last int32))) -;; Compact vertex snapshot used by the debug vertex statistics display. It keeps -;; transformed coordinates, a packed normal, texture coordinates, and color in -;; the same 32-byte record. +;; Compact vertex snapshot used by the debug vertex statistics display. It contains +;; transformed coordinates, a packed normal, texture coordinates, and color. (deftype debug-vertex (structure) ((trans vector4w :inline) (normal vector3h :inline) (st vector2h :inline) (color uint32))) -;; Debug geometry statistics and storage for up to 600 captured vertex records. -;; The custom inspector in debug.gc prints the active records and their packed -;; attributes. +;; Storage for debug-vertices. Not sure why it's called "stats". (deftype debug-vertex-stats (basic) ((length int32) (pos-count int32) diff --git a/goal_src/jak1/engine/debug/stats-h.gc b/goal_src/jak1/engine/debug/stats-h.gc index b3a83d0105..ee23f61b39 100644 --- a/goal_src/jak1/engine/debug/stats-h.gc +++ b/goal_src/jak1/engine/debug/stats-h.gc @@ -23,10 +23,11 @@ (cycles-instructions 0) (icache-dcache 1)) -;; One renderer bucket is sampled at a time. select chooses either cycles/instructions or +;; One statistic group in one category is sampled at a time. +;; select chooses either cycles/instructions or ;; instruction-cache/data-cache events, ctrl is the corresponding EE Perf register value, and ;; accum0/accum1 collect the raw counter pair until the end-of-frame code assigns the named totals. -;; The explicit wait totals account for stalls that the event counters do not describe directly. +;; The explicit wait totals are incremented by the engine code when waiting for DMA completion. (deftype perf-stat (structure) ((frame-number uint32) (count uint32) @@ -52,7 +53,6 @@ (deftype perf-stat-array (inline-array-class) ((data perf-stat :inline :dynamic))) -;; perf-stat is exactly 52 bytes; inline arrays use that as their dynamic element stride. (set! (-> perf-stat-array heap-base) (the-as uint 52)) (#unless PC_PORT diff --git a/goal_src/jak1/engine/engine/engines.gc b/goal_src/jak1/engine/engine/engines.gc index 37c312f21f..aa0e266a0e 100644 --- a/goal_src/jak1/engine/engine/engines.gc +++ b/goal_src/jak1/engine/engine/engines.gc @@ -8,7 +8,8 @@ (defconstant MATRIX_ENGINE_AMOUNT (* 1024 PROCESS_HEAP_MULT)) -;; Draw connections for the current level background. +;; Holds the bsp of each level that's current loaded, consumed by +;; background renderers. (define *background-draw-engine* (new 'global 'engine 'draw 10)) ;; The matrix engine is a per-frame queue of process handles rather than an engine. diff --git a/goal_src/jak1/engine/entity/entity-h.gc b/goal_src/jak1/engine/entity/entity-h.gc index bb60864daa..14df863f89 100644 --- a/goal_src/jak1/engine/entity/entity-h.gc +++ b/goal_src/jak1/engine/entity/entity-h.gc @@ -4,34 +4,34 @@ (require "engine/entity/res-h.gc") (require "kernel/gcommon.gc") (require "engine/util/types-h.gc") + +;; Level data contains a list of "entity" objects. +;; An entity-actor tells the game engine to spawn a process of a certain type with +;; certain parameters. +;; An entity-camera is a region with predefined camera setings +;; An entity-ambient is a region with some game setting like music/rendering changes. + (defun-extern entity-by-name string entity) - (defun-extern entity-by-type type entity-actor) - (defun-extern entity-by-aid uint entity) (define-extern reset-actors (function symbol none)) - (define-extern *spawn-actors* symbol) - -;; TODO - for cam-start (define-extern reset-cameras (function none)) - (define-extern process-by-ename (function string process)) - (define-extern entity-birth-no-kill (function entity none)) ;; DECOMP BEGINS +;; toggles for generating actor visibility data. +;; a somewhat broken feature for computing the bounding box of where an actor can +;; be based on watching where it goes. (define *generate-actor-vis* #f) - (define *generate-actor-vis-start* #f) - (define *generate-actor-vis-output* #f) -;; Sixteen bytes of persistent per-entity state. The first eight bytes are available to each actor -;; type, followed by lifecycle flags, task ownership, and the actor id. The quad overlay supports -;; copying the complete record to and from save and level storage. +;; Sixteen bytes of persistent per-entity state. +;; The first 8 are user-defined, and the last 8 have shared meanings. (deftype entity-perm (structure) ((user-object object 2) (user-uint64 uint64 :overlay-at (-> user-object 0)) @@ -51,8 +51,8 @@ (:methods (update-perm! (_type_ symbol entity-perm-status) _type_))) -;; Runtime link between a static entity resource and its live process. Level lists use prev-link -;; and next-link; trans and perm remain available while the process is absent. +;; Runtime link between a static entity resource and its live process. +;; prev-link and next-link iterate through the links in a level's entity list. (deftype entity-links (structure) ((prev-link entity-links) (next-link entity-links) @@ -92,8 +92,7 @@ (deftype entity-camera (entity) ((quat quaternion :inline))) -;; Type-specific ambient state. The first twelve bytes are a compact payload interpreted by the -;; function in the final word. +;; ambient parameters, very flexible. (deftype entity-ambient-data (structure) ((user-object object 3) (function (function drawable-ambient vector none)) @@ -112,19 +111,21 @@ (set! (-> entity-ambient-data-array heap-base) (the-as uint 16)) +;; placement of an ambient. (deftype entity-ambient (entity) ((ambient-data entity-ambient-data :overlay-at extra)) (:methods (draw-debug (_type_) none) (birth-ambient! (_type_) none))) -;; An entity that can own a live actor process, navigation mesh, visibility id, task, and -;; orientation. +;; A placed entity. This inherits position and res-lump settings from +;; the parent type and adds in the info needed to spawn an actor. +;; putting nav-mesh in the entity base type is a bit odd. (deftype entity-actor (entity) ((nav-mesh nav-mesh) - (etype type) - (task game-task) - (vis-id uint16) + (etype type) ;; type of process to spawn + (task game-task) ;; associated task + (vis-id uint16) ;; visibility ID (vis-id-signed int16 :overlay-at vis-id) (quat quaternion :inline)) (:methods @@ -134,6 +135,8 @@ (set-or-clear-status! (_type_ entity-perm-status symbol) none))) ;; Actor creation table entry: process type, load dependencies, pool, and per-process heap size. +;; This is only needed to override the defaults, which is usually only done to change process +;; pool settings or heap sizes. (deftype entity-info (basic) ((ptype type) (package basic) @@ -141,10 +144,8 @@ (pool basic) (heap-size int32))) -;; Navigation supplies this function later in the load order. Until then entity login has a harmless -;; default. (define-extern entity-nav-login (function entity-actor none)) - +;; default entity-nav-login for now... a little suspicious that this is needed (if (zero? entity-nav-login) (set! entity-nav-login (the-as (function entity-actor none) nothing))) ;; Dynamic actor population limits. Processes pause outside pause-dist, eligible entities can be diff --git a/goal_src/jak1/engine/entity/res.gc b/goal_src/jak1/engine/entity/res.gc index 0515d55d14..a132a0cb23 100644 --- a/goal_src/jak1/engine/entity/res.gc +++ b/goal_src/jak1/engine/entity/res.gc @@ -115,8 +115,8 @@ This system grew out of the Crash 2 entity resource system. interpolation endpoint. Return a negative packed result when the property or requested sample is missing." (local-vars (tag-idx int)) - ;; These names belong to the fixed entity record and must not enter generic - ;; property lookup. + ;; These values are stored in the entity type directly. They might have been part of + ;; the lump properties in an earlier version. (when (or (= name-sym 'id) (= name-sym 'aid) (= name-sym 'trans) @@ -130,7 +130,7 @@ This system grew out of the Crash 2 entity resource system. ;; these are the outputs of the function. (let ((hi-tag-idx-out -1) (lo-tag-idx-out -1)) - ;; this value is the index of the most recently passed tag with an "invalid" timestamp + ;; track invalid timestamp point so we avoid using it in interpolation (let ((most-recent-invalid-time-idx -1) ;; read 8 chars of the name we want (type-chars (-> (the-as (pointer uint64) (-> (symbol->string name-sym) data)) 0))) @@ -139,7 +139,6 @@ This system grew out of the Crash 2 entity resource system. ;; min/max are inclusive. (let ((max-search (+ (-> this length) -1)) (min-search 0)) - ;; inclusive, so >= is correct (while (>= max-search min-search) ;; check in the middle of the range to bisect it. (let* ((check-idx (+ min-search (/ (- max-search min-search) 2))) @@ -156,6 +155,7 @@ This system grew out of the Crash 2 entity resource system. ;; got to the end of the loop without finding the answer. Set a negative tag (set! tag-idx -1) (label cfg-32) + ;; return error if the binary search failed. (if (< tag-idx 0) (return (the res-tag-pair tag-idx))) ;; if there are multiple tags with the same name and different timesteps, we can't be sure which we ended on. ;; this loop brings us to the first tag with the correct name. @@ -219,22 +219,20 @@ This system grew out of the Crash 2 entity resource system. (defmethod make-property-data ((this res-lump) (time float) (tag-pair res-tag-pair) (buf pointer)) "Return the property data selected by tag-pair at time. - Reference properties, exact samples, pairs with different element counts or types, a - false buf, and unsupported element types return the lower sample's address directly. - Otherwise interpolate every element of matching inline float, integer, or vector arrays - into buf and return buf. The caller must provide enough storage for the complete array." + This handles interpolation of the data." (let* ((tag-lo (-> this tag (-> tag-pair lo))) (tag-hi (-> this tag (-> tag-pair hi))) (elt-count (-> tag-lo elt-count))) (cond + ;; references just return the referenced data directly ((res-ref? tag-lo) (get-tag-data this tag-lo)) - ((or (not buf) - (= (-> tag-pair lo) (-> tag-pair hi)) - (!= elt-count (-> tag-hi elt-count)) - (!= (-> tag-lo elt-type) (-> tag-hi elt-type))) + ((or (not buf) ;; no storage provided + (= (-> tag-pair lo) (-> tag-pair hi)) ;; no interp needed + (!= elt-count (-> tag-hi elt-count)) ;; different length samples: interpolation impossible + (!= (-> tag-lo elt-type) (-> tag-hi elt-type))) ;; differing types (get-tag-data this tag-lo)) (else - ;; A bracketing pair has distinct key frames; exact samples take the path above. + ;; Interpolation is needed here. (let ((interp (/ (- time (-> tag-lo key-frame)) (- (-> tag-hi key-frame) (-> tag-lo key-frame)))) (src-lo (get-tag-data this tag-lo)) (src-hi (get-tag-data this tag-hi))) @@ -243,6 +241,7 @@ This system grew out of the Crash 2 entity resource system. (dotimes (i elt-count) (set! (deref float buf i) (+ (* (deref float src-lo i) (- 1.0 interp)) (* (deref float src-hi i) interp)))) buf) + ;; integer interpolation uses 12-bit fractional fixed point (('integer 'sinteger 'uinteger 'int64 'uint64) (make-res-int-data interp elt-count buf src-lo src-hi uint64)) (('int8) (make-res-int-data interp elt-count buf src-lo src-hi int8)) (('uint8) (make-res-int-data interp elt-count buf src-lo src-hi uint8)) @@ -304,10 +303,9 @@ This system grew out of the Crash 2 entity resource system. lookup or type conversion fails. mode controls lookup: base ignores time and selects the first sample, exact requires a sample at time, and interp selects an exact sample or brackets time for interpolation. - Integer values are sign- or zero-extended according to their element type; float bits - are returned in the same 128-bit container. If tag-addr is nonfalse, write the selected - lower res-tag there. buf-addr must hold the interpolated array when interpolation is - required." + Integer values are sign- or zero-extended according to their element type. + If tag-addr is nonfalse, write the selected lower res-tag there. buf-addr must hold + the interpolated array when interpolation is required." (let ((tag-pair (lookup-tag-idx this name mode time))) (cond ((< (the-as int tag-pair) 0)) @@ -511,6 +509,7 @@ This system grew out of the Crash 2 entity resource system. ;; get the name and ID (let ((mem-use-id (mem-usage-id res)) (mem-use-name "res")) + ;; the caller may set flags giving us a more specific category (cond ((logtest? flags (mem-usage-flags resource-camera)) (set! mem-use-id (mem-usage-id camera)) (set! mem-use-name "camera")) ((logtest? flags (mem-usage-flags resource-entity)) (set! mem-use-id (mem-usage-id entity)) (set! mem-use-name "entity")) @@ -570,9 +569,6 @@ This system grew out of the Crash 2 entity resource system. (define *res-static-buf* (malloc 'global 128)) -;; Four lookup families cover packed data arrays, referenced structures, raw -;; values up to 128 bits, and numeric values converted to float. - (defmacro res-lump-data (lump name type &key (tag-ptr (the-as (pointer res-tag) #f)) &key (time -1000000000.0)) "Return named packed data, interpolating at time when the property has timed samples." `(the-as ,type diff --git a/goal_src/jak1/engine/game/effect-control-h.gc b/goal_src/jak1/engine/game/effect-control-h.gc index 01eb1282b7..15e7230f95 100644 --- a/goal_src/jak1/engine/game/effect-control-h.gc +++ b/goal_src/jak1/engine/game/effect-control-h.gc @@ -3,6 +3,11 @@ (bundles "ENGINE.CGO" "GAME.CGO") (require "engine/entity/res.gc") (require "engine/game/game-h.gc") + +;; effect-control interprets animation data and triggers effects. +;; This allows artists to script behaviors like footprint markers, walking sound effects, etc +;; and have them line up with the animation. + (define-extern effect-param->sound-spec (function sound-spec (pointer float) int sound-spec)) (defenum effect-control-flag @@ -20,7 +25,7 @@ (last-frame-num float) (channel-offset int32) ;; Root animation channel to follow. (res res-lump) ;; Resource data for the current animation group. - (name (pointer res-tag)) ;; First effect-name tag in res. + (name (pointer res-tag)) (param uint32)) (:methods (new (symbol type process-drawable) _type_) diff --git a/goal_src/jak1/engine/game/fact-h.gc b/goal_src/jak1/engine/game/fact-h.gc index 231001f286..c009a3d315 100644 --- a/goal_src/jak1/engine/game/fact-h.gc +++ b/goal_src/jak1/engine/game/fact-h.gc @@ -72,7 +72,6 @@ (fop4 4) ;; unused (no reads or writes) ;; if set in an actor's options, a nav-enemy (babak checks it in ;; go-initial-state!) spawns dormant in nav-enemy-wait-for-cue instead of idle; - ;; nothing in shipped actor data sets it. (start-wait-for-cue 5) (instant-collect 6) ;; set on balloon lurker, puffer (skip-jump-anim 7) ;; skips fuel cell "jump" animation @@ -181,8 +180,7 @@ this)) (defmethod pickup-collectable! ((this fact-info) (kind pickup-type) (amount float) (source-handle handle)) - "Return zero without changing the pickup state; fact-info-target overrides this - hook to apply pickups." + "Subclasses will override this with a handler for picking up a collectable." 0.0) (defmethod new fact-info-enemy ((allocation symbol) (type-to-make type) (owner process-drawable) (kind pickup-type) (amount float)) diff --git a/goal_src/jak1/engine/game/game-h.gc b/goal_src/jak1/engine/game/game-h.gc index 3452572184..151c2320c4 100644 --- a/goal_src/jak1/engine/game/game-h.gc +++ b/goal_src/jak1/engine/game/game-h.gc @@ -2,24 +2,16 @@ (in-package goal) (bundles "ENGINE.CGO" "GAME.CGO") (require "kernel-defs.gc") + (declare-type target process-drawable) - (declare-type voicebox process-drawable) - (defun-extern voicebox-spawn process vector (pointer process)) - (declare-type nav-control basic) - (declare-type path-control basic) - (declare-type vol-control basic) - (declare-type actor-link-info basic) - (declare-type sparticle-launch-control basic) - (declare-type water-control basic) - (declare-type collide-shape basic) (defenum attack-mask @@ -40,7 +32,7 @@ (rotate-to) (prev-state)) -;; Most state flags describe *target* and are queried through that global. +;; Most state flags are specific to target. ;; Pickups also use fade-out-particles, and basebutton temporarily uses ;; use-alt-cam-pos while controlling the camera. (defenum state-flags @@ -70,8 +62,6 @@ ) (defmacro static-attack-info (&key (mask ()) args) - ;; Derive mask bits from the supplied fields, then initialize a static packet. - ;; Inline vectors must be copied instead of assigned as references. (let ((mask-actual mask)) (dolist (it args) (when (not (member (caar it) mask-actual)) @@ -89,6 +79,8 @@ ;; collision, pickups, particles, water, and sound. (deftype process-drawable (process) ;; World pose and, for collidable subclasses, collision geometry. + ;; many process-drawable types will place a more specific type here + ;; which includes collision. ((root trsqv) ;; Joint and bone hierarchy, including the joint-to-bone mappings. (node-list cspace-array) diff --git a/goal_src/jak1/engine/game/projectiles-h.gc b/goal_src/jak1/engine/game/projectiles-h.gc index 0b948dc748..ae3037f85c 100644 --- a/goal_src/jak1/engine/game/projectiles-h.gc +++ b/goal_src/jak1/engine/game/projectiles-h.gc @@ -2,13 +2,13 @@ (in-package goal) (bundles "ENGINE.CGO" "GAME.CGO") (require "engine/game/game-h.gc") + +;; Projectile is a base class for weapon or effect "projectiles" +;; They typically track a target and play effects or trigger events on collision. + (declare-type projectile process-drawable) (define-extern projectile-init-by-other - "Initialize the projectile from source-entity, launch-position, initial-velocity, launch-context - option bits, and an optional last-target-handle. Create subtype collision and effects, seed the - sixteen-sample stall history, snapshot the parent transform, check initial overlaps for non-blue - projectiles, install the moving event hook, and enter the launch state." (function entity-actor vector vector uint handle none :behavior projectile)) ;; DECOMP BEGINS diff --git a/goal_src/jak1/engine/gfx/background/background-h.gc b/goal_src/jak1/engine/gfx/background/background-h.gc index e1c7df6f5a..b0eeb44a24 100644 --- a/goal_src/jak1/engine/gfx/background/background-h.gc +++ b/goal_src/jak1/engine/gfx/background/background-h.gc @@ -5,10 +5,10 @@ ;; DECOMP BEGINS -;; Frame-local queues filled by drawable-tree draw methods and consumed by finish-background. Each -;; terrain category retains the tree together with its owning level so visibility, mood, texture -;; buckets, and scratchpad state can be changed between entries. tie-generic carries the per-tree -;; continuation for the generic TIE pass, and wait-to-vu0 records background VU0 upload stalls. +;; List of things to draw on the current frame. +;; Calling "draw" on a background drawable tree simply adds it to this background-work +;; The normal tie DMA builder create a chain of instances in tie-generic that is +;; later expanded into the generic format in a later pass. (deftype background-work (basic) ((tfrag-tree-count int32) (tfrag-trees drawable-tree-tfrag 8) diff --git a/goal_src/jak1/engine/gfx/background/subdivide-h.gc b/goal_src/jak1/engine/gfx/background/subdivide-h.gc index 899f91204c..e55b9d3312 100644 --- a/goal_src/jak1/engine/gfx/background/subdivide-h.gc +++ b/goal_src/jak1/engine/gfx/background/subdivide-h.gc @@ -4,6 +4,8 @@ (require "engine/level/bsp-h.gc") (require "engine/util/types-h.gc") +;; This file is a wild mess of different rendering types. + ;; DECOMP BEGINS ;; Terrain LOD distance configuration. Profiles 0 through 2 belong to loaded levels; profile 3 is diff --git a/goal_src/jak1/engine/gfx/depth-cue-h.gc b/goal_src/jak1/engine/gfx/depth-cue-h.gc index 8be931d63e..5c22e128b3 100644 --- a/goal_src/jak1/engine/gfx/depth-cue-h.gc +++ b/goal_src/jak1/engine/gfx/depth-cue-h.gc @@ -3,6 +3,11 @@ (bundles "ENGINE.CGO" "GAME.CGO") (require "kernel-defs.gc") +;; Depth-cue is an effect that tries to blur things in the distance, +;; however it does not look very good on modern high resolution displays. +;; Naughty Dog dropped this effect in later games. +;; This is disabled by default on PC. + ;; DECOMP BEGINS ;; Parameters for one framebuffer depth-cue pass. diff --git a/goal_src/jak1/engine/gfx/lights.gc b/goal_src/jak1/engine/gfx/lights.gc index 4354c84d35..f2c78e828a 100644 --- a/goal_src/jak1/engine/gfx/lights.gc +++ b/goal_src/jak1/engine/gfx/lights.gc @@ -5,10 +5,10 @@ (require "engine/gfx/foreground/bones-h.gc") (require "engine/geometry/geometry.gc") (require "engine/math/vector.gc") + (defun light-slerp ((out light) (a light) (b light) (alpha float)) "Blend light a toward b into out, clamping alpha to 0 through 1. - Color and level are interpolated linearly; direction uses spherical interpolation and - preserves a's direction magnitude." + Color and level are interpolated linearly; direction uses spherical interpolation." (let ((clamped-alpha (fmax 0.0 (fmin 1.0 alpha)))) (vector-lerp! (-> out color) (-> a color) (-> b color) clamped-alpha) (vector-deg-slerp (-> out direction) (-> a direction) (-> b direction) clamped-alpha) @@ -19,15 +19,14 @@ (defun light-group-slerp ((out light-group) (a light-group) (b light-group) (alpha float)) "Blend all three directional lights and the ambient light from - group a toward group b into out. light-slerp clamps alpha separately for each light." + group a toward group b into out." (dotimes (i 4) (light-slerp (-> out lights i) (-> a lights i) (-> b lights i) alpha)) out) (defun light-group-process! ((lights vu-lights) (group light-group) (vector-a vector) (vector-b vector)) "Convert group into the transposed VU lighting layout in lights. - The signed y rotation from vector-b to vector-a is calculated first, but its result is not - used." + Unused" (rotate-y<-vector+vector vector-b vector-a) (vu-lights<-light-group! lights group) (none)) diff --git a/goal_src/jak1/engine/gfx/shrub/shrubbery-h.gc b/goal_src/jak1/engine/gfx/shrub/shrubbery-h.gc index b7bf06f611..acda9b06e1 100644 --- a/goal_src/jak1/engine/gfx/shrub/shrubbery-h.gc +++ b/goal_src/jak1/engine/gfx/shrub/shrubbery-h.gc @@ -8,17 +8,23 @@ ;; DECOMP BEGINS +;; Shrubbery is an instanced renderer optimized for little grass, flowers, rocks, etc. +;; Shrubs fade out or fade into simple single-quad billboard (always face camera) +;; Each instance only has a single color multiplier from the precomputed lighting. +;; (it still uses time of day interpolation, so a shrub can still flicker by a torch, +;; but all vertices receive the same final interpolated time-of-day color) +;; Shrubs don't have precomputed visibility, but still do frustum culling. + ;; The coarsest geometry a shrub prototype can have: one camera-facing quad with one texture. There ;; is no vertex data -- the EE builds the four corners from the instance's own flat-normal and ;; flat-hwidth and writes them straight to the GS -- so the shader is the whole object. (deftype billboard (drawable) ((flat adgif-shader :inline))) -;; The three quadwords of camera constants uploaded to VU address zero once per pass. The overlays -;; are not alternative readings of the same value; they are what different parts of the system call -;; the same word. tex-start-ptr and mtx-buf-ptr are initial values for two words the microprogram -;; reuses as its own saved cursors, and exp23 names the 2^23 bias that lets VU addresses travel in -;; float lanes. +;; The three quadwords of camera constants uploaded to VU data address 0. +;; tex-start-ptr and mtx-buf-ptr are initial values for two words the microprogram +;; reuses as its own saved cursors, and exp23 names the 2^23 bias that lets VU do address +;; math in float registers. (deftype shrub-view-data (structure) ((data uint128 3) (texture-giftag gs-gif-tag :inline :overlay-at (-> data 0)) @@ -58,6 +64,10 @@ (flat-hwidth float :overlay-at (-> flat-normal w)) (color uint32 :overlay-at color-indices))) +;; drawable system types for shrubs, allowing BVH traversal for frustum culling. +;; unlike other BVHs, shrub doesn't have fixed depth and 8-child counts. +;; The usual optimized draw-node asm therefore doesn't work. +;; (shrub instead traverses the BVH in DFS order at DMA generation time using a stack) (deftype drawable-inline-array-instance-shrub (drawable-inline-array) ((data instance-shrubbery 1 :inline) (pad uint32))) @@ -66,6 +76,7 @@ ((info prototype-array-shrub-info :offset 8) (colors-added time-of-day-palette :offset 12))) +;; duplicate geometry for the generic renderer - used when shrubs need clipping. (deftype generic-shrub-fragment (drawable) ((textures (inline-array adgif-shader) :overlay-at id) (vtx-cnt uint32 :offset 8) @@ -86,19 +97,16 @@ (deftype prototype-generic-shrub (drawable-group) ()) -;; One instance as VU1 sees it: five quadwords unpacked into an instance ring slot. The ring's count -;; word sits one quadword before the first of these, which is why the microprogram's record stride is -;; six on entry and five thereafter. +;; Shrub matrix and color uploaded to VU1 per instance. (deftype shrubbery-matrix (structure) ((mat matrix :inline) (color qword :inline))) (defun shrubbery-login-post-texture ((this shrubbery)) - "Repack the logged-in adgif shaders into the shrub's VU1-facing DMA data. Each shader pair keeps - two texture-register qwords but shares one four-qword state block; the first state qword updates - only its three register words and preserves the packet word already in the destination." + "Repack the logged-in adgif shaders into the shrub's VU1-facing DMA data. + Each shader pair shares data and is repacked for more efficient uploads." ;; Each source adgif is five qwords. The pair has different texture registers but identical - ;; remaining state, so the VU1 packet stores both first qwords and only the first shader's state. + ;; remaining state, so the VU1 packet doesn't store the identical part twice. (let* ((shader-pair-count (-> this header data 0)) (state-dst (the-as qword (+ (the-as uint (-> this header)) (* (+ (-> this header data 1) 1) 16)))) (texture-dst (the-as qword (+ (the-as int state-dst) (* shader-pair-count 64)))) @@ -127,45 +135,34 @@ ;; Shrub VU1 addresses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; The three quadwords of camera constants land at VU address zero and shrub-view-data describes -;; them, so the program's loads name fields instead of numbers. Integer division of a field offset -;; by sixteen also lets a lane-level field name the quadword that holds it, which is how -;; tex-start-ptr and mtx-buf-ptr identify the two words the program later reuses as saved cursors. +;; models, instances, and output data are all double-buffered. +;; (unlike tie, shrub doesn't triple buffer the outputs) + (defconstant SHRUB-VU-VIEW-DATA 0) (defmacro shrub-view-const (&rest path) `(+ SHRUB-VU-VIEW-DATA (/ (offset-of shrub-view-data ,@path) 16))) ;; The two model banks. *shrub-state* is the VIF BASE register for the next model upload and -;; alternates between them; subtracting it from the sum is how both the EE and the microprogram -;; flip. Each bank is 160 quadwords, which is the largest shrubbery the exporter will emit. +;; alternates between them. Each bank is 160 quadwords (defconstant SHRUB-VU-MODEL-BANK-A 2) (defconstant SHRUB-VU-MODEL-BANK-B 162) (defconstant SHRUB-VU-MODEL-BANK-SUM (+ SHRUB-VU-MODEL-BANK-A SHRUB-VU-MODEL-BANK-B)) -;; The two instance rings. A ring is one count word followed by ten shrubbery-matrix records, so the -;; second ring's address, the stride the draw entry walks, and the sum it flips through all come out -;; of the type. Record k sits at ring + 1 + 5k; the draw entry reads the first record at fixed -;; offsets from the count word and then walks the rest with post-incrementing loads. +;; The two instance rings. A ring is one count word followed by ten shrubbery-matrix records. (defconstant SHRUB-VU-MATRIX-STRIDE (/ (type-size shrubbery-matrix) 16)) - (defconstant SHRUB-VU-RING-SLOTS 10) - (defconstant SHRUB-VU-RING-A 322) - (defconstant SHRUB-VU-RING-B (+ SHRUB-VU-RING-A 1 (* SHRUB-VU-RING-SLOTS SHRUB-VU-MATRIX-STRIDE))) - (defconstant SHRUB-VU-RING-SUM (+ SHRUB-VU-RING-A SHRUB-VU-RING-B)) (defmacro shrub-matrix-qword (&rest path) `(+ 1 (/ (offset-of shrubbery-matrix ,@path) 16))) -;; The two GIF output buffers, which begin where ring B ends. Their contents are a packet described -;; by the model's own object stream rather than by any GOAL type, so these stay plain constants. +;; The two GIF output buffers, which begin where ring B ends. (defconstant SHRUB-VU-GIF-BUFFER-0 (+ SHRUB-VU-RING-B 1 (* SHRUB-VU-RING-SLOTS SHRUB-VU-MATRIX-STRIDE))) - (defconstant SHRUB-VU-GIF-BUFFER-1 (+ SHRUB-VU-GIF-BUFFER-0 400)) ;; Entry points. Entry 0 loads the camera constants and builds the buffer-address vectors. Entries @@ -173,11 +170,8 @@ ;; the following draw will read, and start-bank in shrub-work.gc records which one each ring ;; position needs. Entry 103 draws one ring of instances against the prepared model. (defconstant SHRUB-VU-ENTRY-INIT 0) - (defconstant SHRUB-VU-ENTRY-INIT-MODEL-A 17) - (defconstant SHRUB-VU-ENTRY-INIT-MODEL-B 21) - (defconstant SHRUB-VU-ENTRY-DRAW 103) ;; The VIF BASE register for the next model upload, and so the model bank the next shrubbery lands @@ -186,8 +180,7 @@ ;; The DMA/VIF template for one near-shrub fragment, handed to the generic renderer rather than to ;; shrub's own VU1 program. Six of the seven packets are patched per fragment -- qwc, source address -;; and unpack count -- and the seventh runs the generic entry. Six of these exist so the EE can -;; rotate to a free one while an earlier chain still names the last. +;; and unpack count -- and the seventh runs the generic entry. (deftype shrub-near-packet (structure) ((matrix-tmpl dma-packet :inline) (header-tmpl dma-packet :inline) @@ -202,14 +195,10 @@ ;; ;; * templates the EE copies and patches: the twenty matrix and count packets of the instance ring, ;; the two MSCALF packets, the adgif and billboard GIF packets, and the six near packets. -;; * per-frame values shared with VU0: the camera planes and guard planes, the hvdf offset, the +;; * per-frame values: the camera planes and guard planes, the hvdf offset, the ;; min-dist accumulator, and colors -- the level's 1024-entry time-of-day palette. ;; * the builder's own state: the six-deep node stack, the two 128-byte node chain staging areas, ;; the current bucket's four list heads, the scratchpad cursors and the DMA stall counters. -;; -;; dummy exists to give the 64-byte alignment of the two chain buffers somewhere to land: the builder -;; rounds work+chaina and work+chainb down to a cache line, and without the padding in front the -;; first would round below the start of the type. (deftype instance-shrub-work (structure) ((dummy qword 3 :inline) (chaina qword 8 :inline) @@ -272,11 +261,6 @@ (wait-from-spr uint32) (wait-to-spr uint32))) -;; The scratchpad, overlaid on the work area of the terrain-context so the level header at the bottom -;; of the scratchpad survives. Two input banks of 325 quadwords each hold instance records copied in -;; by the toSPR channel, and two output banks of 128 quadwords each hold packets on their way back to -;; the DMA buffer. All four addresses carry the work-area bias, which is why the flip masks are not -;; simply the bank spacing. (deftype instance-shrub-dma (structure) ((instancea uint128 325) (instanceb uint128 325) diff --git a/goal_src/jak1/engine/gfx/tfrag/tfrag-h.gc b/goal_src/jak1/engine/gfx/tfrag/tfrag-h.gc index 381812a6b7..aadbd5f6fd 100644 --- a/goal_src/jak1/engine/gfx/tfrag/tfrag-h.gc +++ b/goal_src/jak1/engine/gfx/tfrag/tfrag-h.gc @@ -6,71 +6,47 @@ ;; DECOMP BEGINS -;; Per-patch triangle and display-vertex counts, one entry per detail level plus a spare, filled in by -;; the exporter and read only by stats-tfrag-asm for the terrain debug display. dverts counts the -;; vertices a strip actually sends, which is two more than its triangle count per strip - which is how -;; the debug display recovers the average strip length from the pair. +;; Per-patch triangle and vertex counts, one entry per detail level plus a spare +;; dverts counts the vertices a strip actually sends, two more than triangle count. (deftype tfragment-stats (structure) ((num-tris uint16 4) (num-dverts uint16 4))) -;; Debug-only, and absent from the retail levels: debug-lines is a null pointer there. edge-debug-lines -;; draws the lists when they exist. +;; Debug-only, and absent from the retail levels. (deftype tfragment-debug-data (structure) ((stats tfragment-stats :inline) (debug-lines (array vector-array)))) -;; Declared, never built out. tfragment has no GENERIC path at all: nothing in the game reads or -;; writes generic-tfragment or tfragment.generic, there is no environment-mapped or software-transformed -;; terrain, and dummy exists only so the type has a size. Terrain always goes through VU1. +;; Unused. Tfrag never falls back to generic. (deftype generic-tfragment (structure) ((dummy int32))) -;; One independently culled terrain patch, and one of three nested meshes over the same vertices. +;; A tfragment is one independently culled terrain patch, with three levels of detail. ;; -;; The geometry is a single contiguous block of VIF commands in the level file, and the four transfers +;; The geometry is a single contiguous block of data in the level file, and the four transfers ;; below are four windows into it. Nothing is duplicated except the per-level draw-point and strip -;; tables, because those are the only part that a change of detail actually changes. Measured across -;; JUN, BEA, VI1 and SNO, the block is laid out relative to dma-common (in quadwords): +;; tables. The block is laid out: +;; BASE-ONLY +;; base-only mesh tables +;; COMMON +;; control block, shaders, base point records, base vertices +;; LEVEL-0 +;; level-0-only mesh tables +;; level-0 interp table, point records, vertices +;; LEVEL-1 +;; level-1-only mesh tables +;; level-1 vertices, point records. ;; -;; -8 .. 0 base-only draw-point and strip tables dma-base points here -;; 0 .. C control block, adgif shaders, base point records, base vertices ("common") -;; C .. L level-0-only draw-point and strip tables -;; L .. Z level-0 additions: interpolation table, point records, vertices dma-level-1 here -;; Z .. E level-1 additions: vertices, point records, and its own tables +;; Therefore to draw each level: ;; -;; and the four transfers are +;; Base: single upload. Start at dma-base (BASE-ONLY), upload dma-qwc[1] (upload BASE-ONLY, COMMON) +;; Level0: single upload, Start at dma-level0 (overlays dma-common), upload dma-qwc[2] (upload COMMON, LEVEL-0) +;; Level1: two uploads, +;; dma-common, dma-qwc[0], only loads COMMON +;; dma-level-1, dmq-qwc[3], loads LEVEL-1 ;; -;; base dma-base for dma-qwc[1] -> base tables, then everything in "common" -;; common dma-common for dma-qwc[0] -> "common" alone; dma-qwc[0] = C -;; level 0 dma-level-0 for dma-qwc[3] -> "common", level-0 tables, level-0 additions; -;; dma-qwc[3] = Z -;; level 1 dma-level-1 for dma-qwc[2] -> level-0 additions, then level-1 additions; -;; dma-qwc[2] = E - L ;; -;; So a base draw is one transfer, a level-0 draw is one transfer, and a level-1 draw is two: "common" -;; followed by the level-1 window, which deliberately skips the level-0-only tables in between while -;; still picking up the level-0 additions that level 1 also needs. dma-common and dma-level-0 are one -;; field under two names because the level-0 window simply starts where "common" starts; the two names -;; distinguish "send the common prefix" from "send the whole level-0 window". That is also why -;; dma-chain has three entries and dma-qwc has four - three distinct start addresses, four lengths. -;; -;; dma-qwc is in chain-entry order with the odd one appended, not in level order: -;; dma-qwc[0] length of the common prefix (with dma-chain[0]) -;; dma-qwc[1] length of the base window (with dma-chain[1]) -;; dma-qwc[2] length of the level-1 window (with dma-chain[2]) -;; dma-qwc[3] length of the whole level-0 window (with dma-chain[0] again) -;; -;; Because the windows overlap, never treat the three pointers as three independent allocations; that -;; is what mem-usage is subtracting for. A patch with no level-1 detail leaves dma-level-1 aliased onto -;; dma-chain[0] and unused; num-level1-colors zero is the test for that, and likewise -;; num-level0-colors zero means there is no level-0 window either. -;; -;; Every window unpacks the same five-quadword tfrag-control to the front of the VU input bank, and all -;; three levels write their draw-point and strip tables at the same VU addresses, so the control block -;; never has to change with the detail level. -;; -;; Colors are the one part of a patch that is not in the level file's VIF block, because they follow +;; Colors are the one part of a patch that is not in the level file's data block, because they follow ;; the time of day. One time-of-day-palette is shared by the whole tree (drawable-tree-tfrag has it), ;; and each patch carries its own indices into that palette here: ;; @@ -80,12 +56,6 @@ ;; num-level1-colors number of vertices in base + level 0 + level 1 ;; color-offset the VU quadword where the expanded colors start ;; -;; The counts are cumulative over the nested vertex array, which is exactly what the EE needs: having -;; chosen a stream it takes the matching count, expands that many indices into scratchpad RGBA, and -;; writes the count into the color template's VIF NUM byte - num-base-colors for a base draw, -;; num-level0-colors for level 0, num-level1-colors for level 1. So one number selects both how much -;; color to gather and how much to unpack. color-offset is odd because vertex positions unpack on a -;; 2/1 VIF cycle and the colors land in the quadwords the positions skip, one color per position. (deftype tfragment (drawable) ((color-index uint16 :offset 6) (debug-data tfragment-debug-data :offset 8) @@ -112,46 +82,32 @@ (generic generic-tfragment) (generic-u32 uint32 :overlay-at generic))) -;; The patch list. data is dynamic despite the declared length of one; the real count is the inherited -;; length field, and the fragments are one contiguous 64-byte-stride run, which is what lets the EE draw -;; functions walk them with a fixed stride and DMA sixteen headers at a time. Retail levels have one such -;; array per terrain tree, of up to a couple of thousand fragments. +;; Array of tfragments in the drawable BVH system. +;; These use the usual fixed-max-depth, always 8 children layout and can be culled +;; via precomputed visibility and BVH frustum culling very efficiently in draw-node. (deftype drawable-inline-array-tfrag (drawable-inline-array) ((data tfragment 1 :inline) (pad uint32))) -;; The translucent variant declares a second dynamic slot at offset 112. It is not a separate list: the -;; declaration exists because the type is one tfragment longer than its parent, and the drawing code -;; treats it exactly like the ordinary array. +;; Variant for "transparent" tfrags, this is likely a mistake and unused. +;; It has a second tfragment defined, but nothing seems to read it. (deftype drawable-inline-array-trans-tfrag (drawable-inline-array-tfrag) ((data2 tfragment 1 :inline) (pad2 uint32))) -;; One terrain tree. arrays is every depth of the visibility hierarchy: each array before the last is a -;; level of draw-node, and the last is the drawable-inline-array-tfrag holding the patches. Culling walks -;; the depths, propagating visibility down, and the leaf array is then handed to the draw functions. -;; -;; The time-of-day palette is per tree, not per patch: every fragment's color-indices index into this one -;; palette, and finish-background interpolates it once per frame per tree. That is why the trees are split -;; by surface type in the first place - one palette and one set of GS state per tree. +;; Full drawable tree (BVH hierarchy) for tfrag. +;; Each array is at increasing depth in the BVH. The final array contains +;; tfragment and the others contain draw-nodes (bounding sphere nodes) +;; There's a single color palette shared for the entire tree. (deftype drawable-tree-tfrag (drawable-tree) ((time-of-day-pal time-of-day-palette :offset 12) (arrays drawable-inline-array 1 :overlay-at (-> data 0)))) -;; The five subtypes below differ only in which bucket and which GS TEST setting they draw with; the -;; geometry, the LOD machinery and the microprograms are identical. tfrag-methods.gc has the alpha tests: -;; opaque terrain uses alpha >= #x26, translucent >= #x7e with framebuffer-only alpha failure, dirt uses -;; framebuffer-only failure with no alpha comparison, and ice always passes alpha with the same failure -;; mode. The lowres variants are declared for a distant-terrain pass; no consumer distinguishes them from -;; their parents, and whether any shipped level actually builds one was not established here. +;; The five subtypes below differ only in which bucket and which GS TEST setting they draw with (deftype drawable-tree-trans-tfrag (drawable-tree-tfrag) ()) - (deftype drawable-tree-dirt-tfrag (drawable-tree-tfrag) ()) - (deftype drawable-tree-ice-tfrag (drawable-tree-tfrag) ()) - (deftype drawable-tree-lowres-tfrag (drawable-tree-tfrag) ()) - (deftype drawable-tree-lowres-trans-tfrag (drawable-tree-trans-tfrag) ()) ;; The LOD collapse coefficients, one entry per subdivision level. Despite looking like four @@ -193,8 +149,8 @@ (k0s uint128 2 :overlay-at (-> data 40)) (k1s uint128 2 :overlay-at (-> data 48)))) -;; The five quadwords at the front of every VU1 terrain input bank. Every pointer is a quadword -;; address relative to the bank base, so it can be added straight to the VIF TOP register. +;; Tfrag data layout. `ptr`s are quadword addresses. +;; TODO: this is very hard to understand - rewrite once we get to tfrag.gc ;; ;; A vertex is two quadwords: packed integer position, then the time-of-day color the EE unpacks into ;; the quadword the position skipped. Positions live at ptr-vtxdata in base, level-0, level-1 order, @@ -244,10 +200,6 @@ (ptr-strip-data uint32) (ptr-texture-data uint32))) -;; Counters for the tfrag-print-stats debug page, filled in by hand from the shipped level data rather -;; than by the renderer - nothing in the drawing path writes them, and the single instance is the global -;; t-stat in tfrag.gc. The page turns them into an estimated DMA cost per frame, which is what the from, -;; to and cnt fields are for. (deftype tfrag-stats (structure) ((from int32) (to int32) @@ -266,8 +218,7 @@ (drawpoints int32) (vif int32))) -;; Two quadwords of DMA/VIF tag. Declared here and referenced by nothing: the EE draw functions build -;; their packets straight out of the tfrag-work templates instead. +;; Seems unused. (deftype tfrag-packet (structure) ((tag uint128 2))) @@ -305,7 +256,7 @@ ;; Scratchpad terrain workspace. banka and bankb each hold one batch of sixteen fragment headers, so ;; the toSPR DMA can be filling one while packets are built from the other; outa and outb each hold -;; 128 quadwords of built packet, so the fromSPR DMA can be feeding the VIF buffer from one while the +;; 128 quadwords of built packet, so the fromSPR DMA can be writing back to main memory from one while the ;; other is written. colors is where the EE gathers this frame's time-of-day RGBA before handing it to ;; the VU as part of each fragment's packet. (deftype tfrag-dma (structure) diff --git a/goal_src/jak1/engine/gfx/tie/tie-h.gc b/goal_src/jak1/engine/gfx/tie/tie-h.gc index 4c8ad1d0e2..0ed9e198e6 100644 --- a/goal_src/jak1/engine/gfx/tie/tie-h.gc +++ b/goal_src/jak1/engine/gfx/tie/tie-h.gc @@ -5,26 +5,19 @@ (require "engine/draw/drawable-tree-h.gc") (require "engine/draw/drawable-inline-array-h.gc") -;; TIE's data types. Three separate things live in here and it helps to keep them apart: +;; TIE types for: ;; -;; * the prototype side -- prototype-tie and tie-fragment -- geometry authored once and uploaded to -;; VU1 once per frame; -;; * the instance side -- instance-tie and its drawable arrays -- the BVH of placements; -;; * the two scratchpad work areas the EE packet builders run out of. +;; * the prototypes -- prototype-tie and tie-fragment -- geometry uploaded to VU1 once per frame; +;; * the instances -- instance-tie and its drawable arrays -- the BVH of prototype placements; +;; * the two scratchpad work areas for DMA generation on the EE ;; -;; A fragment holds only counts and references. The actual shaders, points, strip descriptions, and -;; colors sit in separate blocks of level data that nothing in GOAL ever dereferences: they are DMA -;; sources and VU1 input, and the only code that understands their layout is the microprogram in -;; tie.gc and the packet builders in tie-methods.gc. A field with no GOAL reference is not therefore -;; unused. +;; A prototype-tie references geometry fragments which is a chunk of mesh. Mesh size is limited +;; by the VU1 data memory size. ;; -;; Ownership of the color data is split and it is easy to get backwards. The palette -- the colors -- -;; belongs to the prototype, in prototype-bucket-tie.tie-colors, and is uploaded once per prototype per -;; frame for every fragment and every instance to share. What an instance owns is instance-tie's -;; color-indices: a stream of one-byte indices into that shared palette, one per vertex. So instances of -;; the same prototype are identical in geometry and in available colors, and differ only in which entry -;; each of their vertices picks -- which is what lets the same authored crate sit in sunlight and in -;; shadow for one byte per vertex. +;; Ownership of the color data is split and it is easy to get backwards. The color palette (actual RGBs) +;; belong to the prototype. Each instance has its own indices, allowing it to select instance-specific +;; colors. (note that there's a single giant palette shared by all prototypes, prototypes just have +;; a view into this) ;; DECOMP BEGINS @@ -33,24 +26,18 @@ ;; is either DMA'd straight to VU1 or read by the palette expander; the counts are what the packet ;; builder patches into its templates. (deftype tie-fragment (drawable) - ((gif-ref (inline-array adgif-shader) :overlay-at id) ;; adgif shaders, five quadwords each - (point-ref uint32 :offset 8) ;; packed points, uploaded as V4-16 to VU address 50. Nothing in the - ;; source declares a type for this stream; the closest are - ;; generic-tie-base-point and generic-tie-interp-point, which are the - ;; Generic converter's view of its own copy of the geometry. + ((gif-ref (inline-array adgif-shader) :overlay-at id) ;; adgif shaders + (point-ref uint32 :offset 8) ;; packed points, uploaded as V4-16 to VU address 50. (color-index uint16 :offset 12) ;; this fragment's first entry in the prototype color table - (base-colors uint8 :offset 14) ;; palette entries used by base points; each interpolated point takes three - (tex-count uint16) ;; five times the shader count; login divides it back down - (gif-count uint16) ;; quadwords of shader data to upload - (vertex-count uint16) ;; quadwords in the point stream - (color-count uint16) ;; palette entries this fragment selects from the prototype table + (base-colors uint8 :offset 14) ;; unused? unknown meaning. + (tex-count uint16) ;; size of adgifs in qw + (gif-count uint16) ;; size of giftag templates in qw + (vertex-count uint16) ;; size of points in qw + (color-count uint16) ;; size of colors used in qw (num-tris uint16) ;; triangles, for the renderer statistics display - (num-dverts uint16) ;; output vertex slots in this fragment's GIF packets -- base points and - ;; interpolated points together, and a vertex shared by two strips counts once - ;; per strip. collect-stats multiplies it by the instance count to get the - ;; drawn-vertex total, so "d" is the destination slot each one occupies. - (dp-ref uint32) ;; strip descriptions: GIF tag templates and their destination offsets - (dp-qwc uint32) ;; quadwords of strip description + (num-dverts uint16) ;; output vertex slots in this fragment's GIF packets + (dp-ref uint32) ;; unknown metadata for near renderer + (dp-qwc uint32) ;; quadwords of dp (generic-ref uint32) ;; generic-tie-header and its compact stream, when this fragment has one (generic-count uint32) ;; quadwords of Generic data (debug-lines (array vector-array)))) ;; authoring-time wireframe, absent from shipped levels @@ -58,10 +45,7 @@ ;; One placement of a prototype. Instances are the leaves of the TIE tree's BVH, so rejecting a draw ;; node discards a whole subtree of them at once. ;; -;; The transform is a matrix4h: sixteen int16, 32 bytes. Its three rotation rows are 1.12 fixed point -;; and its translation row steps in units of 64 world units, which is how a complete placement fits in -;; 64 bytes including the bounding sphere. See the unpack at the top of -;; draw-inline-array-instance-tie. +;; The transform is a matrix4h with fixed-point integer values. (deftype instance-tie (instance) ((color-indices uint32 :overlay-at error) ;; per-instance palette indices, or zero to use the prototype's (bucket-ptr prototype-bucket-tie :offset 12) ;; the prototype this places @@ -107,15 +91,10 @@ :bitfield #t (has-generic 1)) -;; Everything the instance packet builder needs that is not in the instance itself: camera constants, -;; the DMA/VIF templates it patches per instance, cursors into the visibility string, and the stall -;; counters. tie-work.gc initializes the fixed part; the draw code fills in the camera and cursor -;; fields each frame and copies the whole thing into draw-local storage, since the builder writes to -;; it and the shared original must survive. (deftype instance-tie-work (structure) ((wind-const vector :inline) ;; wind spring: damping, force scale, timestep, low clamp (hmge-d vector :inline) ;; homogeneous depth range used by the near test - (hvdf-offset vector :inline) ;; screen-space offset from the camera + (hvdf-offset vector :inline) ;; see math-camera.gc (wind-force vector :inline) (constant vector :inline) ;; 4096.0 and 128.0: the wind phase clamp (far-morph vector :inline) ;; (1, 0, 0, 256): the fully collapsed morph quadword @@ -150,10 +129,6 @@ ;; The instance builder's scratchpad: two input banks of 32 instances, two 4 KiB output banks, and a ;; copy of the work area after them. -;; -;; The whole record sits one quadword into the scratchpad, leaving the first quadword for control -;; words. That is why every displacement in the packet builders is a field offset plus sixteen -- see -;; spr-offset in tie-methods.gc. (deftype instance-tie-dma (structure) ((banka instance-tie 32 :inline) ;; exactly one visibility word's worth of instances (bankb instance-tie 32 :inline) @@ -190,9 +165,7 @@ (near-wait-from-spr uint32) (near-wait-to-spr uint32))) -;; The prototype builder's scratchpad: two 1 KiB palette banks, two 4 KiB output banks, and the -;; per-prototype state its fragment loop works from. Like instance-tie-dma, this record starts one -;; quadword into the scratchpad. +;; The prototype builder's scratchpad (deftype prototype-tie-dma (structure) ((colora rgba 256) ;; a 1 KiB source chunk is 32 time-of-day entries; each becomes one word (colorb rgba 256) diff --git a/goal_src/jak1/engine/level/bsp-h.gc b/goal_src/jak1/engine/level/bsp-h.gc index d45cd3acda..f5c37b4e80 100644 --- a/goal_src/jak1/engine/level/bsp-h.gc +++ b/goal_src/jak1/engine/level/bsp-h.gc @@ -3,75 +3,146 @@ (bundles "ENGINE.CGO" "GAME.CGO") (require "engine/draw/drawable-h.gc") -;; Every level ends with a large "bt" file containing its bsp-header. Loading it last lets the -;; static level data consume the rest of the level heap. The header owns or references the BSP, -;; drawable trees, actors, cameras, collision properties, textures, and visibility data; it is much -;; broader than its historical name suggests. The shipped files use the -vis suffix because they -;; include precomputed visibility data. +;; Every level DGO file ends with a large "bt" file containing its bsp-header. +;; Loading it last lets it load directly onto the level-heap, skipping the usual double-buffered +;; load and link loader for smaller files. +;; The bsp-header has references to the actual BSP, drawable trees, actors, cameras, collision properties, +;; visibility, and more. The engine stashes references to texture pages and other data here too. +;; The final game files use the -vis suffix because they include precomputed visibility data. ;; ;; "BSP" generally means this static level data, while "level" means its runtime state. (declare-type entity-camera basic) -;; flags: 1 = load -;; 2 = display -;; Each terminal BSP side stores six of these two-bit pairs, one per neighboring level. +;; The actual BSP is very strange. +;; The bsp data structure is strongly inspired by a quake-style BSP. +;; In this approach, each splitting plane is a face from the level geometry, +;; and visibility is precomputed by casting rays through "portals". +;; The design here is based on this, and ND developers stated this is how it works +;; in a GDC talk. + +;; The actual data doesn't match this description. All bsp-nodes describe regularly sized +;; rectangular prisms. (Jak 2 and on use a more comapct data structure: quantized AABBs) +;; It's also a suspicious design. Can the portals really work for big outdoor levels? + +;; My guess is that they started with portals, then pivoted to something else. +;; This "something else" uses rectangular volumes, which is awfully similar to +;; what they did in Jak 2 and on, and _might_ have been the Insomniac approach, +;; although this is pure speculation, ND might have done their own visibility precomputation. ;; DECOMP BEGINS -;; Each plane splits space into front and back children. Front is -;; dot(position, plane.xyz) - plane.w >= 0. A positive child is another bsp-node pointer; a -;; nonpositive value identifies a terminal side; visibility trees use negative values to encode -;; their leaf indices. Each side also carries the packed load/display pairs used when the camera -;; reaches that terminal side. +;; splitting planes in a BSP (deftype bsp-node (structure) - ((front int32) - (back int32) + ;; front/back indices are either: + ;; - positive value indicating a child bsp-node + ;; - negative value for a leaf node + ((front int32) ;; if dot(p, plane.xyz) - >= plane.w + (back int32) ;; otherwise + + ;; these flags appear to be used for diagnostics only. + ;; for each 6 neighboring levels, there is a load and display bit + ;; when the display bit is 0, the visibility generator would + ;; assume that the neighbor level isn't drawn, and therefore skips + ;; computation and maps the cell to all 0's. + ;; these are very similar, but not quite the same as the load boundaries. + ;; this means that you can have a level in "display", but all geometry is + ;; hidden because the camera is in a volume with display = 0. + ;; (it's possible that display/load was once triggered from these!) (front-flags uint32) (back-flags uint32) (plane vector :inline))) -;; This drawable is stored first in the level bt file; drawing it draws the static level. (deftype bsp-header (drawable) + ;; file version, filename, date, etc ((info file-info :overlay-at id) + ;; visibility bitstring with a bit set for every visid + ;; used in this level (all-visible-list (pointer uint16)) + ;; number of bits in visibility list for this level (visible-list-length int32) + ;; All the level models/collision (drawable-trees drawable-tree-array) - (pat pointer) + ;; PAT describes the attributes of a collision triangle. + ;; To avoid storing a full 32-bit PAT per triangle, + ;; triangles typicall store an 8-bit index into + ;; this array. + (pat (pointer pat-surface)) (pat-length int32) + ;; The level texture pages contain combined textures for all assets in the level. + ;; art-groups for creatures/actors/enemies/objects within a level don't reference + ;; this combined texture. This remapping table maps per-art-group texture-ids to + ;; the combined per-level texture pages. This allows the engine to consume the same + ;; exact art-group file for an enemy no matter which level is actually providing + ;; the textures. Background geometry doesn't need this since it's built into + ;; the bsp file and contains reference to the combined texture-pages already. (texture-remap-table (pointer uint64)) (texture-remap-table-len int32) + + ;; a single texture-id for each texture-page. + ;; the textures aren't contained in the bsp-header. + ;; this allows a level to find its textures, which are hopefully loaded + ;; prior to the level. (texture-ids (pointer texture-id)) (texture-page-count int32) + + ;; unused. (unk-zero-0 basic) (name symbol) (nickname symbol) + + ;; level visibility data for this level plus 6 neighbors, plus 1 null-terminator. (vis-info level-vis-info 8) + + ;; all the entity-actors. Each entity-actor defines how to spawn a process. (actors drawable-inline-array-actor) + + ;; all the hand-scripted cameras in the level (cameras (array entity-camera)) + + ;; actual BSP structure (nodes (inline-array bsp-node)) + + ;; edited at runtime: link to runtime level structure for this level (level level) + + ;; edited at runtime: current bsp leaf index for camera position (current-leaf-idx uint16) (unk-data-2 uint16 9) + + ;; boundary of the level as an array of boxes. (boxes box8s-array) - ;; Packed neighboring-level flags from the terminal BSP side containing the camera. - (current-bsp-back-flags uint32) + ;; edited at runtime: the leaf bsp flags + (current-bsp-flags uint32) + + ;; effects in the level (sounds, music changes, etc) (ambients drawable-inline-array-ambient) - (unk-data-4 float) - (unk-data-5 float) + + ;; per-level settings for terrain mesh level-of-detail. + (subdivide-close-distance meters) + (subdivide-far-distance meters) + + ;; all the "shaders" (texture + GS rendering settings) for background drawing. (adgifs adgif-shader-array) + + ;; order that actors should be birthed. (actor-birth-order (pointer uint32)) + + ;; seems to be diagnostic only, an index per each box in boxes. (split-box-indices (pointer uint16)) + + ;; unused? (unk-data-8 uint32 55)) (:methods (relocate (_type_ kheap (pointer uint8)) none :replace) (birth (_type_) none) (deactivate-entities (_type_) none))) -;; Minimal wrapper around a master BSP. Runtime levels normally use bsp-header directly. +;; Minimal wrapper around a master BSP. Unused. (deftype game-level (basic) ((master-bsp basic))) +;; View frustum, stored as vertices, using absurd "hither" and "yonder" for near and far. (deftype view-frustum (structure) ((hither-top-left vector :inline) (hither-top-right vector :inline) @@ -112,6 +183,9 @@ (if (> (-> node back) 0) (map-bsp-tree visit header (the-as bsp-node (-> node back))) (visit node)))) (none)) +;; collision statistic. The collision statistics are mostly broken and +;; likely were from earlier collision code, or were only enabled with a +;; compile-time flag. (deftype cl-stat (structure) ((fragments uint32) (tris uint32) diff --git a/goal_src/jak1/engine/level/bsp.gc b/goal_src/jak1/engine/level/bsp.gc index d38f0eed50..47c6bf80a7 100644 --- a/goal_src/jak1/engine/level/bsp.gc +++ b/goal_src/jak1/engine/level/bsp.gc @@ -328,8 +328,8 @@ (b! #t cfg-1 :delay (set! next-node (the-as bsp-node (-> node back)))) (label cfg-4) (set! (-> header current-leaf-idx) (the-as uint next-node)) - ;; Despite its name, this holds the flags for whichever terminal side was selected. - (set! (-> header current-bsp-back-flags) side-flags))) + (set! (-> header current-bsp-flags) side-flags) + )) 0 (none)))) diff --git a/goal_src/jak1/engine/level/level.gc b/goal_src/jak1/engine/level/level.gc index d9f38ff0b5..cac726cbbc 100644 --- a/goal_src/jak1/engine/level/level.gc +++ b/goal_src/jak1/engine/level/level.gc @@ -585,8 +585,8 @@ ;; done! (set! (-> loaded-level nickname) (-> loaded-level bsp nickname)) (if (nonzero? (-> loaded-level bsp nodes)) (set! *time-of-day-effects* #t) (set! *time-of-day-effects* #f)) - (let ((close-distance (-> loaded-level bsp unk-data-4)) - (far-distance (-> loaded-level bsp unk-data-5))) + (let ((close-distance (-> loaded-level bsp subdivide-close-distance)) + (far-distance (-> loaded-level bsp subdivide-far-distance))) (when (and (= close-distance 0.0) (= far-distance 0.0)) (set! close-distance 122880.0) (set! far-distance 286720.0)) @@ -1289,7 +1289,7 @@ (dotimes (level-index (-> this length)) (let ((active-level (-> this level level-index))) (when (= (-> active-level status) 'active) - (let ((border-flags (-> active-level bsp current-bsp-back-flags))) + (let ((border-flags (-> active-level bsp current-bsp-flags))) (dotimes (neighbor-index 6) (when (and (logtest? border-flags 3) (-> active-level vis-info (+ neighbor-index 1))) (let ((neighbor-info (lookup-level-info (-> active-level vis-info (+ neighbor-index 1) from-level)))) diff --git a/goal_src/jak1/engine/physics/dynamics-h.gc b/goal_src/jak1/engine/physics/dynamics-h.gc index f097c97c26..ddea45e5d1 100644 --- a/goal_src/jak1/engine/physics/dynamics-h.gc +++ b/goal_src/jak1/engine/physics/dynamics-h.gc @@ -8,7 +8,7 @@ ;; A dynamics profile defines the local up direction, gravity acceleration and ;; terminal fall speed used by a moving object. gravity points upward so callers ;; negate it when applying acceleration; gravity-normal is the corresponding unit -;; vector. The profile also carries named walking and running distances. +;; vector. (deftype dynamics (basic) ((name basic) (gravity-max meters) diff --git a/goal_src/jak1/engine/target/target-h.gc b/goal_src/jak1/engine/target/target-h.gc index 679c02d4ee..6b668c2c60 100644 --- a/goal_src/jak1/engine/target/target-h.gc +++ b/goal_src/jak1/engine/target/target-h.gc @@ -2,18 +2,17 @@ (in-package goal) (bundles "ENGINE.CGO" "GAME.CGO") (require "engine/game/game-h.gc") + (declare-type snowball-info basic) - (declare-type tube-info basic) - (declare-type racer-info basic) - (declare-type flut-info basic) - (declare-type sidekick process-drawable) -;; Jak and Daxter's process types and the core target entry points. Most movement and collision -;; state lives in control-info, which occupies the process-drawable root slot. +;; target is the player character. +;; The name is probably from camera code, which refers to the thing being tracked as "target". +;; In math-camera, there's also an unused function `move-target-from-pad`, which likely was +;; used to move the camera target when testing very early camera code. ;; DECOMP BEGINS @@ -34,7 +33,7 @@ (attack-info-rec attack-info :inline) ;; Most recently received attack description. (anim-seed uint64) ;; Shared with Daxter to synchronize ambient animation. (alt-cam-pos vector :inline) ;; Camera focus override selected by state-flags. - (snowball snowball-info) ;; Snowball-riding state. + (snowball snowball-info) ;; Snowball-riding state. (snowball is unimplemented) (tube tube-info) ;; Tube-riding state. (flut flut-info) ;; Flut Flut riding state. (current-level level) ;; Current level used for in-level time accounting. @@ -189,7 +188,7 @@ ((parent-override (pointer target) :overlay-at parent) (control control-info :overlay-at root) (anim-seed uint64 :offset 192) ;; Mirrors Jak's ambient-animation seed. - (shadow-in-movie? symbol)) ;; Permit Daxter's special shadow during movies. + (shadow-in-movie? symbol)) ;; Permit Daxter's shadow during movies. (:states sidekick-clone)) diff --git a/goal_src/jak1/engine/util/sync-info-h.gc b/goal_src/jak1/engine/util/sync-info-h.gc index a8704b4eb4..e2a21fa75b 100644 --- a/goal_src/jak1/engine/util/sync-info-h.gc +++ b/goal_src/jak1/engine/util/sync-info-h.gc @@ -3,10 +3,9 @@ (bundles "ENGINE.CGO" "GAME.CGO") (require "kernel-defs.gc") -;; The sync-info types derive repeatable phases from the global game clock so -;; independently updated objects remain synchronized. Platforms can therefore -;; share a period and retain consistent relative positions without communicating -;; every frame. +;; The sync-info types keep gameplay objects like platforms in sync. +;; Platforms may spawn and despawn during gameplay, and determine their +;; momvement phase from the global clock. ;; ;; This file also contains small randomized and spring-like motion controls that ;; do not use the synchronization clock. @@ -14,8 +13,8 @@ ;; DECOMP BEGINS ;; The base clock produces a sawtooth phase from 0 to 1 over each period. Its -;; mirrored form produces a triangular phase from 0 to 1 and back to 0 over the -;; same period. Citadel's rotating "pies" are synchronized with this clock. +;; mirrored versions produces a triangular phase from 0 to 1 and back to 0 over the +;; same period. (deftype sync-info (structure) (;; Phase offset stored in game-time ticks rather than normalized phase. (offset float) @@ -107,8 +106,7 @@ (at-min? (_type_) symbol) (at-max? (_type_) symbol))) -;; Vector counterpart to delayed-rand-float. X and Z share one symmetric range, -;; Y has its own, and W remains zero. +;; Vector counterpart to delayed-rand-float. (deftype delayed-rand-vector (structure) ((min-time int32) (max-time int32)