clean up to entity-h

This commit is contained in:
water111
2026-08-10 00:28:14 -07:00
parent 14762d74c3
commit 90d6ee7451
39 changed files with 501 additions and 489 deletions
+2 -1
View File
@@ -63,7 +63,8 @@ FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const {
pool.alloc_single_element_form<GenericElement>(
nullptr, GenericOperator::make_fixed(FixedOperatorKind::ADDRESS_OF),
pool.alloc_single_element_form<StackSpillValueElement>(
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 {
+27
View File
@@ -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<int> stack_slot_address_offset(const AtomicOp* op) {
const auto* set = dynamic_cast<const SetVarOp*>(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<const StackSpillLoadOp*>(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);
}
}
+3 -4
View File
@@ -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<DerefElement*>(new_val->try_as_single_active_element());
existing && !existing->is_addr_of()) {
if (auto* existing = dynamic_cast<DerefElement*>(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<DerefElement>(existing->base(), existing->is_addr_of(),
combined_tokens));
result->push_back(
pool.alloc_element<DerefElement>(existing->base(), false, combined_tokens));
return;
}
}
+15 -14
View File
@@ -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)
+54 -41
View File
@@ -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)
+3 -2
View File
@@ -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)
@@ -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
@@ -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)))
@@ -2,4 +2,4 @@
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
;; Collision function declarations are provided by collide-func.gc.
;; Empty.
@@ -1,4 +1,6 @@
;;-*-Lisp-*-
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
;; unused flag.
(define *collide-test-flag* #f)
+5 -11
View File
@@ -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)
+47 -30
View File
@@ -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))
@@ -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)
+8 -8
View File
@@ -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))
+15 -6
View File
@@ -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
@@ -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
@@ -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))
+3 -9
View File
@@ -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)
+3 -3
View File
@@ -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
+2 -1
View File
@@ -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.
+25 -24
View File
@@ -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
+16 -20
View File
@@ -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
@@ -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_)
+1 -3
View File
@@ -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))
+4 -12
View File
@@ -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)
+4 -4
View File
@@ -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
@@ -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)
@@ -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
+5
View File
@@ -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.
+4 -5
View File
@@ -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))
+28 -44
View File
@@ -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)
+38 -87
View File
@@ -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)
+23 -50
View File
@@ -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)
+96 -22
View File
@@ -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)
+2 -2
View File
@@ -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))))
+3 -3
View File
@@ -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))))
+1 -1
View File
@@ -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)
+7 -8
View File
@@ -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))
+6 -8
View File
@@ -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)