Files
jak-project/goal_src/jak1/engine/draw/drawable.gc
T
2026-07-28 12:00:35 -07:00

1584 lines
81 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
(require "engine/engine/engines.gc")
(require "engine/gfx/tie/tie-methods.gc")
(require "engine/level/load-boundary.gc")
(require "engine/gfx/mood/time-of-day.gc")
(require "engine/gfx/shadow/shadow-cpu.gc")
(require "engine/gfx/generic/generic.gc")
(require "engine/collide/collide-shape.gc")
(require "engine/gfx/generic/generic-merc.gc")
;; DECOMP BEGINS
;; A drawable is the common interface for renderer leaves, flat arrays, and the interior nodes of
;; the draw trees. The base methods do no work so a tree traversal can dispatch without first
;; identifying the concrete child type.
;;
;; Camera side-plane coefficients are transposed across four vectors: each vector supplies one
;; coefficient for all four planes. VU0 therefore classifies a sphere or segment against every side
;; plane in parallel. The guard planes enclose a wider volume and distinguish geometry that can be
;; accepted directly from geometry that needs clipping.
(#when PC_PORT
(defun sphere-cull ((sphere vector))
"Test sphere against the four current view-frustum side planes. Return true unless the sphere
lies wholly outside any plane; the EE entry uses plane coefficients left in vf16-vf19 by its
caller."
;; The PC renderers perform their own visibility rejection.
#t))
;; Each caller loads vf16-vf19 with the transposed side-plane coefficients before entering the
;; traversal. Each result lane is the signed center distance plus the sphere radius.
(#unless PC_PORT
(defun sphere-cull ((sphere vector))
"Return true when the sphere intersects every current view-frustum half-space."
(local-vars (dist-bits uint128) (outside-bits uint128) (packed-outside uint128))
(rlet ((acc :reg acc)
(vu-zero :reg vf0)
(sphere-center-radius :reg vf10)
(plane-x :reg vf16)
(plane-y :reg vf17)
(plane-z :reg vf18)
(plane-offset :reg vf19)
(plane-distances :reg vf9))
(l.vf sphere-center-radius sphere)
(mul.x.vf acc plane-x sphere-center-radius)
(add.mul.y.vf acc plane-y sphere-center-radius acc)
(add.mul.z.vf acc plane-z sphere-center-radius acc)
(sub.mul.w.vf plane-distances plane-offset vu-zero acc)
(add.w.vf plane-distances plane-distances sphere-center-radius)
(m dist-bits plane-distances)
(pcgt.w outside-bits 0 dist-bits)
(ppach packed-outside 0 outside-bits)
(zero? (the-as int packed-outside)))))
(#when PC_PORT
(defun guard-band-cull ((sphere vector))
"Return true when the sphere crosses an expanded guard-plane boundary and therefore needs
clipping."
(local-vars (v1-0 uint128) (v1-1 uint128) (v1-2 uint128))
(rlet ((acc :class vf)
(vf0 :class vf)
(vf10 :class vf)
(vf20 :class vf)
(vf21 :class vf)
(vf22 :class vf)
(vf23 :class vf)
(vf9 :class vf))
(init-vf0-vector)
;; og:preserve-this manually added
(let ((at-0 *math-camera*))
(.lvf vf20 (&-> at-0 guard-plane 0 quad))
(.lvf vf21 (&-> at-0 guard-plane 1 quad))
(.lvf vf22 (&-> at-0 guard-plane 2 quad))
(.lvf vf23 (&-> at-0 guard-plane 3 quad)))
(.lvf vf10 (&-> sphere quad))
(.mul.x.vf acc vf20 vf10)
(.add.mul.y.vf acc vf21 vf10 acc)
(.add.mul.z.vf acc vf22 vf10 acc)
(.sub.mul.w.vf vf9 vf23 vf0 acc)
(.sub.w.vf vf9 vf9 vf10)
(.mov v1-0 vf9)
(.pcgtw v1-1 0 v1-0)
(.ppach v1-2 (the-as uint128 0) v1-1)
(nonzero? (the-as int v1-2)))))
;; dma-add-process-drawable leaves the transposed guard planes in vf20-vf23. Subtracting the radius
;; identifies a sphere which is not wholly inside the expanded volume.
(#unless PC_PORT
(defun guard-band-cull ((sphere vector))
"Return true when the sphere crosses an expanded guard-plane boundary and therefore needs
clipping."
(local-vars (dist-bits uint128) (outside-bits uint128) (packed-outside uint128))
(rlet ((acc :reg acc)
(vu-zero :reg vf0)
(sphere-center-radius :reg vf10)
(plane-x :reg vf20)
(plane-y :reg vf21)
(plane-z :reg vf22)
(plane-offset :reg vf23)
(plane-distances :reg vf9))
(l.vf sphere-center-radius sphere)
(mul.x.vf acc plane-x sphere-center-radius)
(add.mul.y.vf acc plane-y sphere-center-radius acc)
(add.mul.z.vf acc plane-z sphere-center-radius acc)
(sub.mul.w.vf plane-distances plane-offset vu-zero acc)
(sub.w.vf plane-distances plane-distances sphere-center-radius)
(m dist-bits plane-distances)
(pcgt.w outside-bits 0 dist-bits)
(ppach packed-outside 0 outside-bits)
(nonzero? (the-as int packed-outside)))))
(defun sphere-in-view-frustum? ((sphere sphere))
"Return true unless sphere lies wholly outside one of *math-camera*'s four view-frustum side
planes."
(local-vars (distance-bits uint128) (outside-bits uint128) (packed-outside uint128))
(rlet ((acc :class vf)
(vf0 :class vf)
(vf1 :class vf)
(vf2 :class vf)
(vf3 :class vf)
(vf4 :class vf)
(vf5 :class vf)
(vf6 :class vf))
(init-vf0-vector)
(let ((view-camera *math-camera*))
(.lvf vf6 (&-> sphere quad))
(.lvf vf1 (&-> view-camera plane 0 quad))
(.lvf vf2 (&-> view-camera plane 1 quad))
(.lvf vf3 (&-> view-camera plane 2 quad))
(.lvf vf4 (&-> view-camera plane 3 quad)))
(.mul.x.vf acc vf1 vf6)
(.add.mul.y.vf acc vf2 vf6 acc)
(.add.mul.z.vf acc vf3 vf6 acc)
(.sub.mul.w.vf vf5 vf4 vf0 acc)
(.add.w.vf vf5 vf5 vf6)
(.mov distance-bits vf5)
(.pcgtw outside-bits 0 distance-bits)
(.ppach packed-outside (the-as uint128 0) outside-bits)
(zero? (the-as int packed-outside))))
(defun line-in-view-frustum? ((start vector) (end vector))
"Conservatively test the segment from start to end against the four view-frustum side planes.
Return false only when both endpoints lie outside the same plane."
(local-vars
(start-distance-bits uint128)
(start-outside-bits uint128)
(start-outside-mask uint128)
(end-distance-bits uint128)
(end-outside-bits uint128)
(end-outside-mask uint128))
(rlet ((acc :class vf)
(vf0 :class vf)
(vf10 :class vf)
(vf16 :class vf)
(vf17 :class vf)
(vf18 :class vf)
(vf19 :class vf)
(vf9 :class vf))
(init-vf0-vector)
(let ((view-camera *math-camera*))
(.lvf vf9 (&-> start quad))
(.lvf vf10 (&-> end quad))
(.lvf vf16 (&-> view-camera plane 0 quad))
(.lvf vf17 (&-> view-camera plane 1 quad))
(.lvf vf18 (&-> view-camera plane 2 quad))
(.lvf vf19 (&-> view-camera plane 3 quad)))
(.mul.x.vf acc vf16 vf9)
(.add.mul.y.vf acc vf17 vf9 acc)
(.add.mul.z.vf acc vf18 vf9 acc)
(.sub.mul.w.vf vf9 vf19 vf0 acc)
(.mul.x.vf acc vf16 vf10)
(.add.mul.y.vf acc vf17 vf10 acc)
(.add.mul.z.vf acc vf18 vf10 acc)
(.sub.mul.w.vf vf10 vf19 vf0 acc)
(.mov start-distance-bits vf9)
(.pcgtw start-outside-bits 0 start-distance-bits)
(.ppach start-outside-mask (the-as uint128 0) start-outside-bits)
(.mov end-distance-bits vf10)
(.pcgtw end-outside-bits 0 end-distance-bits)
(.ppach end-outside-mask (the-as uint128 0) end-outside-bits)
(not (logtest? (the-as int start-outside-mask) (the-as int end-outside-mask)))))
(#when PC_PORT
(defun vis-cull ((id int))
"Return the visibility bit for draw-node id from the current scratchpad visibility list."
;; Error spheres are debug-only on PC, where the visibility list is not kept in scratchpad.
#t))
(#unless PC_PORT
(defun vis-cull ((id int))
"Return the visibility bit for draw-node id from the current scratchpad visibility list."
;; Draw-node bits are stored most-significant-bit first within each signed byte.
(rlet ((scratch-base)
(byte-address)
(vis-byte)
(bit-index)
(shifted-byte))
(lui scratch-base #x7000)
(sra byte-address id 3)
(add byte-address byte-address scratch-base)
(l.b vis-byte byte-address #x38b0)
(and.i bit-index id 7)
(add.i bit-index bit-index 56)
(sll.v shifted-byte vis-byte bit-index)
(< shifted-byte 0))))
(defun error-sphere ((item drawable-error) (name string))
"When artist error spheres are enabled and item passes visibility and frustum culling, draw its
red bounding sphere and label it with name."
(when *artist-error-spheres*
(when (vis-cull (-> item id))
(when (sphere-cull (-> item bsphere))
(add-debug-sphere #t (bucket-id debug) (-> item bsphere) (-> item bsphere w) (new 'static 'rgba :r #x80 :a #x80))
(add-debug-text-3d #t (bucket-id debug-no-zbuf) name (-> item bsphere) (font-color white) (the-as vector2h #f)))))
0
(none))
(defmethod login ((this drawable))
"Initialize a drawable after its linked data has been loaded."
this)
(defmethod draw ((this drawable) (draw-data drawable) (frame display-frame))
"Submit this drawable's work for the current display frame."
0
(none))
(defmethod collide-with-box ((this drawable) (count int) (result collide-list))
"Traverse count contiguous siblings beginning at this and append collision
geometry intersecting the active collision box to result."
0
(none))
(defmethod collide-y-probe ((this drawable) (count int) (result collide-list))
"Traverse count contiguous siblings beginning at this and append collision
geometry intersecting the active vertical probe to result."
0
(none))
(defmethod collide-ray ((this drawable) (count int) (result collide-list))
"Traverse count contiguous siblings beginning at this and append collision geometry
intersecting the active swept-sphere ray to result."
0
(none))
(defmethod collect-ambients ((this drawable) (query-sphere sphere) (count int) (result ambient-list))
"Traverse count contiguous siblings beginning at this and append ambient
objects overlapping query-sphere to result."
0
(none))
(defmethod collect-stats ((this drawable))
"Accumulate this drawable's renderer statistics."
0
(none))
(defmethod debug-draw ((this drawable) (draw-data drawable) (frame display-frame))
"Submit debug geometry for this drawable."
0
(none))
(defmethod draw ((this drawable-error) (item drawable-error) (frame display-frame))
"Draw item's labeled error sphere for frame."
(error-sphere item (-> item name))
(none))
(defmethod unpack-vis ((this drawable) (destination (pointer int8)) (source (pointer int8)))
"Decode this drawable's visibility bytes into destination and return the advanced source pointer."
source)
(define *edit-instance* (the-as string #f))
(when *debug-segment*
(define *instance-mem-usage* (new 'debug 'memory-usage-block)))
(defun-debug find-instance-by-name ((name string))
"Search every active level's shrub and TIE prototype arrays for name. Return the matching
prototype bucket, or false when no prototype matches."
(dotimes (level-index (-> *level* length))
(let ((active-level (-> *level* level level-index)))
(when (= (-> active-level status) 'active)
(let ((drawable-trees (-> active-level bsp drawable-trees)))
(dotimes (tree-index (-> drawable-trees length))
(let ((tree (-> drawable-trees trees tree-index)))
(case (-> tree type)
((drawable-tree-instance-shrub)
(let ((shrub-prototypes (-> (the-as drawable-tree-instance-shrub tree) info prototype-inline-array-shrub)))
(dotimes (prototype-index (-> shrub-prototypes length))
(if (string= name (-> shrub-prototypes data prototype-index name)) (return (-> shrub-prototypes data prototype-index))))))
((drawable-tree-instance-tie)
(let ((tie-prototypes (-> (the-as drawable-tree-instance-tie tree) prototypes prototype-array-tie)))
(dotimes (prototype-index (-> tie-prototypes length))
(if (string= name (-> tie-prototypes array-data prototype-index name))
(return (-> tie-prototypes array-data prototype-index)))))))))))))
(the-as prototype-bucket #f))
(defun-debug find-instance-by-index ((tree-type type) (prototype-index int) (bsp-filter bsp-header))
"Search active levels, optionally restricted to bsp-filter, for a shrub or TIE tree of tree-type
and return prototype-index from its prototype array. Return false when no tree matches;
prototype-index is not bounds checked."
(dotimes (level-index (-> *level* length))
(let ((active-level (-> *level* level level-index)))
(when (= (-> active-level status) 'active)
(let ((level-bsp (-> active-level bsp)))
(when (or (not bsp-filter) (= level-bsp bsp-filter))
(let ((drawable-trees (-> level-bsp drawable-trees)))
(dotimes (tree-index (-> drawable-trees length))
(let ((tree (-> drawable-trees trees tree-index)))
(case (-> tree type)
((drawable-tree-instance-shrub)
(when (= tree-type (-> tree type))
(let ((shrub-prototypes (-> (the-as drawable-tree-instance-shrub tree) info prototype-inline-array-shrub)))
(return (-> shrub-prototypes data prototype-index)))))
((drawable-tree-instance-tie)
(when (= tree-type (-> tree type))
(let ((tie-prototypes (-> (the-as drawable-tree-instance-tie tree) prototypes prototype-array-tie)))
(return (-> tie-prototypes array-data prototype-index))))))))))))))
(the-as prototype-bucket #f))
(defun-debug prototype-bucket-type ((prototype prototype-bucket))
"Classify prototype from the type of geometry slot 1, returning instance-shrubbery or
instance-tie."
(case (-> prototype geometry 1 type)
((prototype-shrubbery shrubbery) instance-shrubbery)
((prototype-tie prototype-tie tie-fragment) instance-tie)))
(defun-debug prototype-bucket-recalc-fields ((prototype prototype-bucket))
"Recompute prototype's derived LOD distances after editing its near or far plane. TIE places the
mid plane one third of the way from near to far; shrub preserves its mid plane and uses the full
near-to-far span for rdists.x. Update the reciprocal band lengths, set the near stiffening distance
to half the near plane, and return prototype."
(case (prototype-bucket-type prototype)
((instance-shrubbery) (set! (-> prototype rdists x) (/ 1.0 (- (-> prototype dists w) (-> prototype dists x)))))
(else
(set! (-> prototype dists z)
(+ (-> prototype dists x) (* 0.33333334 (- (-> prototype dists w) (-> prototype dists x)))))
(set! (-> prototype rdists x) (/ 1.0 (- (-> prototype dists z) (-> prototype dists x))))))
(set! (-> prototype rdists z) (/ 1.0 (- (-> prototype dists w) (-> prototype dists z))))
(set! (-> prototype dists y) (/ (-> prototype dists x) 2))
(set! (-> prototype rdists y) (/ 1.0 (-> prototype dists y)))
prototype)
(#unless PC_PORT
(defun-debug draw-instance-info ((output string))
"When instance statistics are enabled and *edit-instance* names a prototype, print its memory
use, LOD distances, instance counts, and per-geometry triangle, displayed-vertex, strip-length, and
texture statistics to output. Do nothing when the selection is absent."
(local-vars
(lod int)
(last-lod int)
(tie-triangle-count int)
(tie-displayed-vertex-count int)
(tie-texture-count int)
(visible-instance-count int))
(when (and *display-instance-info* *edit-instance*)
(let ((prototype (find-instance-by-name *edit-instance*)))
(when prototype
(let ((instance-type (prototype-bucket-type prototype)))
(let ((geometry-bytes 0))
0
(cond
((= instance-type instance-shrubbery) (set! geometry-bytes 595))
((= instance-type instance-tie)
(reset! *instance-mem-usage*)
(dotimes (s4-1 4)
(when (nonzero? (-> prototype geometry s4-1))
(let* ((a0-4 (-> prototype geometry s4-1))
(t9-3 (method-of-object a0-4 mem-usage))
(a1-0 *instance-mem-usage*)
(v1-16 s4-1))
(t9-3 a0-4
a1-0
(the-as mem-usage-flags
(logior (cond
((= v1-16 1) 4)
((= v1-16 2) 8)
((= v1-16 3) 16)
(else 0))
2))))))
(set! geometry-bytes (+ (calculate-total *instance-mem-usage*) 580))))
(mem-usage prototype (reset! *instance-mem-usage*) (mem-usage-flags))
(let ((prototype-bytes (calculate-total *instance-mem-usage*)))
(format output
"~%~A ~A b @ #x~X ~,,2fK/~,,2fK~%"
instance-type
(-> prototype name)
prototype
(* 0.0009765625 (the float prototype-bytes))
(* 0.0009765625 (the float geometry-bytes)))))
(format output "near: ~m mid: ~m far: ~m~%" (-> prototype dists x) (-> prototype dists z) (-> prototype dists w))
(let ((total-triangles 0)
(total-displayed-vertices 0))
(cond
((= instance-type instance-shrubbery)
(let ((estimated-cost 0.0))
(format output
"usage: vis: ~D shurb: ~D trans-shrub ~D bill: ~D in level: ~D~%"
(-> prototype count 0)
(-> prototype count 1)
(-> prototype count 2)
(-> prototype count 3)
(-> prototype in-level))
(format output "~%frag# tris dverts strlen tex~%")
(let ((shrub-geometry (-> prototype geometry 1))
(shrub-instance-count (+ (-> prototype count 1) (-> prototype count 2))))
(dotimes (fragment-index (-> (the-as drawable-group shrub-geometry) length))
(let ((shrub-triangle-count (shrub-num-tris (the-as shrubbery (+ (+ (* fragment-index 32) 32) (the-as int shrub-geometry)))))
(shrub-displayed-vertex-count (-> (the-as prototype-shrubbery (+ (the-as uint shrub-geometry) (* fragment-index 32))) data 0 header data 2))
(shrub-texture-count (-> (the-as prototype-shrubbery (+ (the-as uint shrub-geometry) (* fragment-index 32))) data 0 header data 0)))
(format output
"~5D ~4D ~5D ~6f ~D~%"
fragment-index
shrub-triangle-count
shrub-displayed-vertex-count
(/ (* 2.0 (the float shrub-triangle-count)) (the float (- shrub-displayed-vertex-count shrub-triangle-count)))
shrub-texture-count)
(+! total-triangles shrub-triangle-count)
(+! total-displayed-vertices shrub-displayed-vertex-count)
(set! estimated-cost
(+ 29.0
(* 5.5 (the float (- shrub-displayed-vertex-count shrub-triangle-count)))
(* 22.0 (the float shrub-texture-count))
(* 8.0 (the float shrub-displayed-vertex-count))
(* 53.0 (the float (/ (+ shrub-instance-count 9) (the-as uint 10))))
(* (the float shrub-instance-count)
(+ 15.0 (* 5.0 (the float shrub-texture-count)) (* 13.5 (the float shrub-displayed-vertex-count))))
estimated-cost))))
(format output
"total ~4D ~5D ~6f ~D speed: ~f~%"
total-triangles
total-displayed-vertices
(/ (* 2.0 (the float total-triangles)) (the float (- total-displayed-vertices total-triangles)))
(-> prototype utextures)
(/ estimated-cost (* (the float shrub-instance-count) (the float total-triangles)))))))
((= instance-type instance-tie)
(set! visible-instance-count 0)
(let ((displayed-triangle-total 0)
(displayed-vertex-total 0)
(texture-total 0))
(format output "~%level visible frags tris dverts strlen tex ttris~%")
(set! lod 1)
(set! last-lod 3)
(while (>= last-lod lod)
(let ((tie-geometry (-> prototype geometry lod)))
(set! tie-triangle-count 0)
(set! tie-displayed-vertex-count 0)
(set! tie-texture-count 0)
(dotimes (fragment-index (-> (the-as prototype-tie tie-geometry) length))
(+! tie-triangle-count (l.hu (+ (the-as uint tie-geometry) (* fragment-index 64) 68)))
(+! tie-displayed-vertex-count (l.hu (+ (the-as uint tie-geometry) (* fragment-index 64) 70)))
(+! tie-texture-count (l.hu (+ (the-as uint tie-geometry) (* fragment-index 64) 60))))
(+! visible-instance-count (-> prototype count lod))
(format output
"~5D ~7D ~5D ~5D"
lod
(-> prototype count lod)
(-> (the-as prototype-tie tie-geometry) length)
tie-triangle-count))
(format output
" ~5D ~6f ~3D ~5D~%"
tie-displayed-vertex-count
(/ (* 2.0 (the float tie-triangle-count)) (the float (- tie-displayed-vertex-count tie-triangle-count)))
tie-texture-count
(* (the-as uint tie-triangle-count) (-> prototype count lod)))
(+! displayed-triangle-total (* (the-as uint tie-triangle-count) (-> prototype count lod)))
(+! displayed-vertex-total (* (the-as uint tie-displayed-vertex-count) (-> prototype count lod)))
(+! total-triangles tie-triangle-count)
(+! total-displayed-vertices tie-displayed-vertex-count)
(+! texture-total tie-texture-count)
(+! lod 1))
(format output "total ~7D/~3D ~5D" visible-instance-count (-> prototype in-level) total-triangles)
(format output
" ~5D ~6f ~3D ~5D~%"
total-displayed-vertices
(/ (* 2.0 (the float displayed-triangle-total)) (the float (- displayed-vertex-total displayed-triangle-total)))
texture-total
displayed-triangle-total)))))))))
(none)))
;; The default dma-add-func for a process-drawable's draw-control (set in initialize-skeleton). Called
;; once per actor during foreground drawing to: (1) frustum-cull the actor by its bounding sphere,
;; (2) compute its lighting (sample the level's time-of-day light-group, blend between two lights across
;; shadow boundaries, and fold in color-mult/color-emissive), (3) pick the LOD level by camera distance,
;; (4) register which texture pages/levels the actor needs, and finally (5) call draw-bones to emit the
;; merc skeletal-mesh DMA. Returns early (#f) whenever the actor is culled or too far for its max LOD.
;; The lighting/clip/LOD math is all done in VU0 macro-ops on the scratchpad for speed.
(defun dma-add-process-drawable ((actor process-drawable) (control draw-control) (flag symbol) (dma-buf dma-buffer))
"Cull actor by its bounding sphere, select and smoothly blend its time-of-day lighting and shadow
contribution, choose a distance LOD, register the required texture masks, set clipping and draw
status flags, and submit its bones to dma-buf. Queue a matrix refresh when changing to a
higher-detail skeleton. flag is the unused connection payload."
(local-vars (v1-37 float))
(rlet ((acc :class vf)
(Q :class vf)
(vf0 :class vf)
(vf15 :class vf)
(vf16 :class vf)
(vf17 :class vf)
(vf18 :class vf)
(vf19 :class vf)
(vf2 :class vf)
(vf20 :class vf)
(vf21 :class vf)
(vf22 :class vf)
(vf23 :class vf)
(vf24 :class vf)
(vf25 :class vf)
(vf26 :class vf)
(vf27 :class vf)
(vf28 :class vf)
(vf29 :class vf)
(vf3 :class vf)
(vf4 :class vf)
(vf5 :class vf))
(init-vf0-vector)
(logclear! (-> control status) (draw-status was-drawn))
(when (not (logtest? (-> control status) (draw-status hidden no-anim no-skeleton-update)))
;; og:preserve-this scratchpad
(let ((bounds-sphere (-> (scratchpad-object terrain-context) work foreground joint-work temp-mtx vector 2))
(scratch-lights (the-as vu-lights (-> (scratchpad-object terrain-context) work foreground joint-work temp-mtx vector 3)))
(time-of-day *time-of-day-context*))
(.lvf vf16 (&-> control origin quad))
(.lvf vf17 (&-> control bounds quad))
(.mul.x.vf.w vf16 vf16 vf0)
(.add.vf vf16 vf16 vf17)
(.svf (&-> bounds-sphere quad) vf16)
(.lvf vf28 (&-> control color-mult quad))
(.lvf vf29 (&-> control color-emissive quad))
(when (sphere-in-view-frustum? (the-as sphere bounds-sphere))
(case (-> control global-effect)
(((draw-effect title))
(when (not (-> time-of-day title-updated))
(set! (-> time-of-day title-updated) #t)
(let ((s0-0 (-> *math-camera* inv-camera-rot))
(a1-1 (new 'stack-no-clear 'vector))
(s1-0 (new 'stack-no-clear 'vector)))
(set-vector! a1-1 0.612 0.5 -0.612 0.0)
(set-vector! s1-0 -0.696 0.174 0.696 0.0)
(vector-matrix*! (the-as vector (-> time-of-day title-light-group)) a1-1 s0-0)
(vector-matrix*! (-> time-of-day title-light-group dir1 direction) s1-0 s0-0))
(set-vector! (-> *time-of-day-context* current-shadow) 0.612 -0.5 -0.612 1.0))
(vu-lights<-light-group! scratch-lights (-> time-of-day title-light-group)))
(else
(let ((target-light-interp (-> control secondary-interp))
(current-light-interp (-> control current-secondary-interp))
(shadow-mask (-> control shadow-mask))
(light-level-index (-> control level-index))
(selected-light (-> time-of-day light-group (-> *target* draw light-index)))
(blended-light (new 'stack-no-clear 'light-group)))
(cond
((= (-> control light-index) 255))
((= light-level-index 2) (set! selected-light (-> time-of-day light-group (-> control light-index))))
(else (set! selected-light (-> time-of-day moods light-level-index light-group (-> control light-index)))))
(when (not (or (= light-level-index 2) (zero? shadow-mask)))
(let* ((shadow-mask-0 (-> time-of-day light-masks-0 light-level-index))
(shadow-mask-1 (-> time-of-day light-masks-1 light-level-index))
(shadow-interp (-> time-of-day light-interp light-level-index))
(a0-13 (logand shadow-mask-0 shadow-mask))
(v1-18 (logand shadow-mask-1 shadow-mask)))
(cond
((and (zero? a0-13) (zero? v1-18)))
(else
(set! target-light-interp
(cond
((and (nonzero? a0-13) (nonzero? v1-18)) 1.0)
((zero? a0-13)
(quad-copy! (the-as pointer blended-light) (the-as pointer selected-light) 12)
(set! selected-light blended-light)
(set! (-> selected-light dir1 levels x) 0.0)
shadow-interp)
(else
(quad-copy! (the-as pointer blended-light) (the-as pointer selected-light) 12)
(set! selected-light blended-light)
(set! (-> selected-light dir0 levels x) 0.0)
(- 1.0 shadow-interp))))))))
(if *teleport* (set! current-light-interp target-light-interp))
(when (not (or (paused?) (= target-light-interp current-light-interp)))
(let ((f0-15 (- current-light-interp target-light-interp)))
(set! current-light-interp
(cond
((< (fabs f0-15) 0.2) target-light-interp)
((< f0-15 0.0) (+ 0.2 current-light-interp))
(else (+ -0.2 current-light-interp)))))
(set! (-> control current-secondary-interp) current-light-interp))
(cond
((= current-light-interp 0.0) (vu-lights<-light-group! scratch-lights selected-light))
(else
(if (!= selected-light blended-light) (quad-copy! (the-as pointer blended-light) (the-as pointer selected-light) 12))
(let ((f0-20 (- 1.0 current-light-interp)))
(set! (-> blended-light dir0 levels x) (* (-> blended-light dir0 levels x) f0-20))
(set! (-> blended-light dir0 levels y) (* (-> blended-light dir0 levels y) f0-20))
(set! (-> blended-light dir1 levels x) (* (-> blended-light dir1 levels x) f0-20))
(set! (-> blended-light dir1 levels y) (* (-> blended-light dir1 levels y) f0-20))
(set! (-> blended-light dir2 levels x) (* (-> blended-light dir2 levels x) f0-20))
(set! (-> blended-light dir2 levels y) (* (-> blended-light dir2 levels y) f0-20)))
(vu-lights<-light-group! scratch-lights blended-light))))
(.lvf vf2 (&-> scratch-lights color 0 quad))
(.lvf vf3 (&-> scratch-lights color 1 quad))
(.lvf vf4 (&-> scratch-lights color 2 quad))
(.lvf vf5 (&-> scratch-lights ambient quad))
(.mul.vf vf5 vf5 vf28)
(.mul.vf vf2 vf2 vf28)
(.mul.vf vf3 vf3 vf28)
(.mul.vf vf4 vf4 vf28)
(.add.vf vf5 vf5 vf29)
(.svf (&-> scratch-lights color 0 quad) vf2)
(.svf (&-> scratch-lights color 1 quad) vf3)
(.svf (&-> scratch-lights color 2 quad) vf4)
(.svf (&-> scratch-lights ambient quad) vf5)
(.mov v1-37 vf5)))
(if *display-lights* (add-debug-lights #t (bucket-id debug) (-> time-of-day light-group 0 lights) (-> control origin)))
(let ((at-0 *math-camera*))
(.lvf vf16 (&-> at-0 plane 0 quad))
(.lvf vf17 (&-> at-0 plane 1 quad))
(.lvf vf18 (&-> at-0 plane 2 quad))
(.lvf vf19 (&-> at-0 plane 3 quad))
(.lvf vf20 (&-> at-0 guard-plane 0 quad))
(.lvf vf21 (&-> at-0 guard-plane 1 quad))
(.lvf vf22 (&-> at-0 guard-plane 2 quad))
(.lvf vf23 (&-> at-0 guard-plane 3 quad))
(.lvf vf24 (&-> at-0 camera-rot vector 0 quad))
(.lvf vf25 (&-> at-0 camera-rot vector 1 quad))
(.lvf vf26 (&-> at-0 camera-rot vector 2 quad))
(.lvf vf27 (&-> at-0 camera-rot vector 3 quad)))
(let ((camera-space-position (-> (scratchpad-object terrain-context) work foreground joint-work joint-stack data 1 vector 1)))
(.lvf vf15 (&-> bounds-sphere quad))
(.mul.w.vf acc vf27 vf0)
(.add.mul.x.vf acc vf24 vf15 acc)
(.add.mul.y.vf acc vf25 vf15 acc)
(.add.mul.z.vf.xyz vf15 vf26 vf15 acc)
(.mul.vf vf28 vf15 vf15)
(.max.w.vf vf29 vf0 vf0)
(.add.y.vf acc vf28 vf28)
(.add.mul.z.vf.x vf28 vf29 vf28 acc)
(.sqrt.vf Q vf28 :ftf #b0)
(.sub.w.vf.w vf28 vf0 vf15)
(.wait.vf)
(.add.vf.w vf15 vf28 Q)
(.svf (&-> camera-space-position quad) vf15)
(when (< 0.0 (+ (-> camera-space-position z) (-> control bounds w)))
(let ((lod-to-use 0))
(let ((camera-distance (-> camera-space-position w)))
(when (nonzero? (-> control lod-set max-lod))
(cond
((>= (-> control force-lod) 0)
(set! lod-to-use (-> control force-lod))
;; og:preserve-this lod hacks
(if (#if (not PC_PORT)
(< (-> control lod-set lod (-> control lod-set max-lod) dist) camera-distance)
(and (-> *pc-settings* ps2-lod-dist?) (< (-> control lod-set lod (-> control lod-set max-lod) dist) camera-distance)))
(return #f)))
(else
(while (and (< lod-to-use (-> control lod-set max-lod)) (< (-> control lod-set lod lod-to-use dist) camera-distance))
(+! lod-to-use 1)))))
;; og:preserve-this lod hacks!
(with-pc
(if (not (-> *pc-settings* ps2-lod-dist?))
(set! lod-to-use (minmax (-> *pc-settings* lod-force-actor) 0 (-> control lod-set max-lod)))))
;; og:preserve-this lod hacks
(if (#if (not PC_PORT)
(and (< (-> control lod-set lod lod-to-use dist) camera-distance) (< (-> control force-lod) 0))
(and (-> *pc-settings* ps2-lod-dist?)
(< (-> control lod-set lod lod-to-use dist) camera-distance)
(< (-> control force-lod) 0)))
(return #f))
(let ((v1-64 (-> control sink-group level))
(a0-26 (+ (-> control sink-group merc-sink foreground-texture-page) 6)))
(when (#if (not PC_PORT)
(not (logtest? (-> control status) (draw-status do-not-check-distance)))
(and (-> *pc-settings* ps2-lod-dist?) (not (logtest? (-> control status) (draw-status do-not-check-distance)))))
(if (< camera-distance (-> v1-64 closest-object a0-26)) (set! (-> v1-64 closest-object a0-26) camera-distance))
(when (and (!= a0-26 6) (!= (-> control level-index) 2))
(let ((a1-45 (cond
((< 102400.0 camera-distance) (-> control mgeo header masks 0))
((< 81920.0 camera-distance) (-> control mgeo header masks 1))
(else (-> control mgeo header masks 2)))))
(logior! (-> v1-64 texture-mask a0-26) a1-45)))))
(if (or (guard-band-cull bounds-sphere) (< camera-distance (* 1.2 (-> *math-camera* d))))
(logior! (-> control status) (draw-status needs-clip))
(logclear! (-> control status) (draw-status needs-clip)))
(logior! (-> control status) (draw-status was-drawn))
(if (logtest? (-> control status) (draw-status skip-bones)) (return #f))
(draw-bones control dma-buf camera-distance))
(when (and (< lod-to-use (-> control cur-lod)) (logtest? (-> control status) (draw-status has-joint-channels)))
;; og:preserve-this added this check for PC port to prevent memory corruption
(if (< (-> *matrix-engine* length) MATRIX_ENGINE_AMOUNT)
(let ((v1-82 *matrix-engine*)) (set! (-> v1-82 (-> v1-82 length)) (process->handle actor)) (+! (-> v1-82 length) 1))))
(lod-set! control lod-to-use)))))))
0
(none)))
(define *hud-lights* (new 'global 'vu-lights))
(set-vector! (-> *hud-lights* direction 0) 1.0 0.0 0.0 1.0)
(set-vector! (-> *hud-lights* direction 1) 0.0 1.0 0.0 1.0)
(set-vector! (-> *hud-lights* direction 2) 0.0 0.0 1.0 1.0)
(set-vector! (-> *hud-lights* color 0) 0.0 0.0 0.0 1.0)
(set-vector! (-> *hud-lights* color 1) 0.0 0.0 0.0 1.0)
(set-vector! (-> *hud-lights* color 2) 0.5 0.5 0.5 1.0)
(set-vector! (-> *hud-lights* ambient) 0.5 0.5 0.5 1.0)
(defun dma-add-process-drawable-hud ((actor process-drawable) (control draw-control) (flag symbol) (dma-buf dma-buffer))
"Draw actor at LOD 0 with *hud-lights*. Skip hidden or disabled controls, copy the fixed lights to
foreground scratchpad, mark the actor drawn, and submit its HUD bones to dma-buf; flag is unused."
(logclear! (-> control status) (draw-status was-drawn))
(when (not (logtest? (-> control status) (draw-status hidden no-anim no-skeleton-update)))
(let ((scratch-lights (the-as vu-lights (+ 64 (scratchpad-object int))))
(hud-lights *hud-lights*))
(vector-copy! (-> scratch-lights direction 0) (-> hud-lights direction 0))
(vector-copy! (-> scratch-lights direction 1) (-> hud-lights direction 1))
(vector-copy! (-> scratch-lights direction 2) (-> hud-lights direction 2))
(vector-copy! (-> scratch-lights color 0) (-> hud-lights color 0))
(vector-copy! (-> scratch-lights color 1) (-> hud-lights color 1))
(vector-copy! (-> scratch-lights color 2) (-> hud-lights color 2))
(vector-copy! (-> scratch-lights ambient) (-> hud-lights ambient)))
(lod-set! control 0)
(logior! (-> control status) (draw-status was-drawn))
(draw-bones-hud control dma-buf))
0
(none))
;; og:preserve-this added
(defun dma-add-process-drawable-hud-merc ((actor process-drawable) (control draw-control) (flag symbol) (dma-buf dma-buffer))
"PC Merc variant of HUD submission: draw actor at LOD 0 with *hud-lights*, mark it drawn, and
submit HUD Merc bones to dma-buf unless its control is hidden or disabled; flag is unused."
(logclear! (-> control status) (draw-status was-drawn))
(when (not (logtest? (-> control status) (draw-status hidden no-anim no-skeleton-update)))
(let ((vu-lights (scratchpad-object vu-lights :offset 64))
(hud-lights *hud-lights*))
(vector-copy! (-> vu-lights direction 0) (-> hud-lights direction 0))
(vector-copy! (-> vu-lights direction 1) (-> hud-lights direction 1))
(vector-copy! (-> vu-lights direction 2) (-> hud-lights direction 2))
(vector-copy! (-> vu-lights color 0) (-> hud-lights color 0))
(vector-copy! (-> vu-lights color 1) (-> hud-lights color 1))
(vector-copy! (-> vu-lights color 2) (-> hud-lights color 2))
(vector-copy! (-> vu-lights ambient) (-> hud-lights ambient)))
(lod-set! control 0)
(logior! (-> control status) (draw-status was-drawn))
(draw-bones-hud-merc control dma-buf))
(none))
(defun add-process-drawable ((actor process-drawable) (control draw-control) (flag symbol) (dma-buf dma-buffer))
"Invoke control's configured DMA submission function for actor, forwarding flag and dma-buf."
((-> control dma-add-func) actor control flag dma-buf)
(none))
;; The sink address is the 96-byte level-group header, the selected 2608-byte level record, its
;; foreground-sink-group at byte 176, and the selected 32-byte sink.
(defun foreground-engine-execute ((draw-engine engine) (frame display-frame) (level-index int) (sink-index int))
"Execute one foreground draw engine for level-index and sink-index. Initialize bone DMA with the
selected level foreground sink, invoke the actor connections, finish the Merc stream, account Merc
and Generic DMA use, cue Generic Merc, and advance the shadow queue. frame is retained by the
draw-engine interface although this function uses the current display buffers."
(let ((merc-dma-start (-> *display* frames (-> *display* on-screen) frame global-buf base)))
(if *debug-segment*
(add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0)
'draw
(new 'static 'rgba :r #x40 :b #x40 :a #x80)))
(let ((sink-group (+ (+ (* sink-index 32) 272 (* 2608 level-index)) (the-as int *level*)))
(global-buf (-> frame global-buf)))
;; Make the two indexed cache selections containing the packet head visible to DMA.
(#unless PC_PORT
(let ((cache-base (-> global-buf base))) (sync.l) (cache dxwbin cache-base 0) (sync.l) (cache dxwbin cache-base 1))
(sync.l))
0
(bones-init global-buf (the-as dma-foreground-sink-group sink-group))
(execute-connections draw-engine global-buf))
(bones-wrapup)
(if *debug-segment*
(add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0)
'draw
(new 'static 'rgba :r #xbe :g #x55 :b #x82 :a #x80)))
(let ((dma-usage *dma-mem-usage*))
(when (nonzero? dma-usage)
(set! (-> dma-usage length) (max 36 (-> dma-usage length)))
(set! (-> dma-usage data 35 name) "pris-fragment")
(+! (-> dma-usage data 35 count) 1)
(+! (-> dma-usage data 35 used)
(&- (-> *display* frames (-> *display* on-screen) frame global-buf base) (the-as uint merc-dma-start)))
(set! (-> dma-usage data 35 total) (-> dma-usage data 35 used)))))
(when (logtest? *vu1-enable-user* (vu1-renderer-mask generic))
(when (nonzero? (-> *merc-globals* first))
(let ((generic-dma-start (-> *display* frames (-> *display* on-screen) frame global-buf base)))
(let ((generic-sink (-> (the-as (pointer uint32) (+ (the-as uint *level*) (* 2608 level-index) (* sink-index 32))) 69)))
(generic-merc-add-to-cue (the-as generic-dma-foreground-sink generic-sink)))
(let ((dma-usage *dma-mem-usage*))
(when (nonzero? dma-usage)
(set! (-> dma-usage length) (max 87 (-> dma-usage length)))
(set! (-> dma-usage data 86 name) "pris-generic")
(+! (-> dma-usage data 86 count) 1)
(+! (-> dma-usage data 86 used)
(&- (-> *display* frames (-> *display* on-screen) frame global-buf base) (the-as uint generic-dma-start)))
(set! (-> dma-usage data 86 total) (-> dma-usage data 86 used)))))))
(when #t
(let ((shadow-queue *shadow-queue*)) (+! (-> shadow-queue cur-run) 1)))
0
(none))
(defun-debug main-debug-hook ()
"Execute debug-engine connections during gameplay; skip them while the master mode is menu or
progress."
(when (not (or (= *master-mode* 'menu) (= *master-mode* 'progress)))
(execute-connections *debug-engine* #f)
;; (draw-instance-info *stdcon*)
)
(none))
(define *debug-hook* main-debug-hook)
(define *add-sphere* #f)
(define *generic-effect-mode* 0)
(defun real-main-draw-hook ()
"Build one frame's renderer DMA lists, dispatching the active background, foreground, shadow,
particle, sprite, HUD, and debug draw systems."
(when *slow-frame-rate*
(dotimes (delay-index (#if PC_PORT 50000000 #xc3500))
(nop!)
(nop!)
(nop!)
(nop!)
(nop!)
(nop!)))
"Function to be executed to set up for engine dma" ;; accidental docstring from the original game
;; update render enables from the debug menu
(set! *vu1-enable-user* *vu1-enable-user-menu*)
(set! *texture-enable-user* *texture-enable-user-menu*)
;; reset and display dma memory stats.
(when *debug-segment*
(when (or *stats-memory* *stats-memory-short*)
(dotimes (level-index (-> *level* length))
(let ((active-level (-> *level* level level-index)))
(if (= (-> active-level status) 'active) (print-mem-usage (compute-memory-usage active-level #f) active-level *stdcon*)))))
(reset! *dma-mem-usage*))
(#unless PC_PORT
(shrub-make-perspective-matrix (-> *math-camera* shrub-mat)))
;; initialize dma buckets that are generic sinks.
;; other renderers may output to these, so do them first.
(generic-init-buffers)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; texture uploads
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; next we use the texture system to build DMA commands to load texture.
;; internally, add-tex-to-dma! has special logic to avoid loading textures
;; that won't be used. (though it's pretty basic, it doesn't actually track per-texture usage)
;; level tfrag's upload if the level is running.
(with-profiler "texture-upload"
(when (logtest? *texture-enable-user* 1)
(dotimes (level-index (-> *level* length))
(let ((active-level (-> *level* level level-index)))
(if (= (-> active-level status) 'active) (add-tex-to-dma! *texture-pool* active-level 0)))))
;; level pris's upload if the level is running.
(when (logtest? *texture-enable-user* 2)
(dotimes (level-index (-> *level* length))
(let ((active-level (-> *level* level level-index)))
(if (= (-> active-level status) 'active) (add-tex-to-dma! *texture-pool* active-level 1)))))
;; level shrubs upload if the level is loading.
(when (logtest? *texture-enable-user* 4)
(dotimes (level-index (-> *level* length))
(let ((active-level (-> *level* level level-index)))
(if (= (-> active-level status) 'active) (add-tex-to-dma! *texture-pool* active-level 2)))))
;; alpha and common.
(when (logtest? *texture-enable-user* 8)
(let ((uploaded-common #f))
(dotimes (level-index (-> *level* length))
(let ((active-level (-> *level* level level-index)))
(when (= (-> active-level status) 'active)
(add-tex-to-dma! *texture-pool* active-level 3)
(when (not uploaded-common)
(upload-one-common! *texture-pool* (-> *level* level0))
(set! uploaded-common #t)))))
(when (not uploaded-common)
(upload-one-common! *texture-pool* (-> *level* level0))
#t)))
;; water.
(when (logtest? *texture-enable-user* 16)
(dotimes (level-index (-> *level* length))
(let ((active-level (-> *level* level level-index)))
(if (= (-> active-level status) 'active) (add-tex-to-dma! *texture-pool* active-level 4))))))
;;;;;;;;;;;;;
;; sky
;;;;;;;;;;;;;
(with-profiler "sky"
(when (zero? (logand *vu1-enable-user* (vu1-renderer-mask sky)))
;; the sky is disabled. Just draw a solid gradient on the whole screen.
(with-dma-buffer-add-bucket ((dma-buf (-> (current-frame) global-buf)) (bucket-id sky-draw))
(dma-buffer-add-gs-set dma-buf
(zbuf-1 (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24)))
(test-1 (new 'static 'gs-test :ate #x1 :atst (gs-atest always) :zte #x1 :ztst (gs-ztest always)))
(alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1)))
(screen-gradient dma-buf
(-> *display* bg-clear-color 0)
(-> *display* bg-clear-color 1)
(-> *display* bg-clear-color 2)
(-> *display* bg-clear-color 3))))
(when (logtest? *vu1-enable-user* (vu1-renderer-mask sky))
;; check if we want the sky, and if we actually have textures ready.
;; we generate sky textures on the previous frame and they sit in vram (8160) until the next frame.
;; on the first frame after we request sky, we draw the textures, but they aren't ready until the next frame.
(cond
((and (-> *time-of-day-context* sky) *sky-drawn*) (render-sky-tng *time-of-day-context*))
(else
;; todo
(with-dma-buffer-add-bucket ((dma-buf (-> (current-frame) global-buf)) (bucket-id sky-draw))
(dma-buffer-add-gs-set dma-buf
(zbuf-1 (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24)))
(test-1 (new 'static 'gs-test :ate #x1 :atst (gs-atest always) :zte #x1 :ztst (gs-ztest always)))
(alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1)))
(screen-gradient dma-buf
(-> *time-of-day-context* erase-color)
(-> *time-of-day-context* erase-color)
(-> *time-of-day-context* erase-color)
(-> *time-of-day-context* erase-color)))))))
;; update mood lighting, draw sky textures.
(with-profiler "time-of-day"
(update-time-of-day *time-of-day-context*))
;; Foreground drawing fills these with the nearest requested object and its texture pages.
(#unless PC_PORT
(dotimes (level-index (-> *level* length))
(let ((active-level (-> *level* level level-index)))
(when (= (-> active-level status) 'active)
(dotimes (sink-index 9)
(set! (-> active-level closest-object sink-index) 4095996000.0)
(set! (-> active-level texture-mask sink-index) (the-as uint 0)))))))
(add-ee-profile-frame 'draw :r #x40 :b #x40 :a #x80)
;;;;;;; OCEAN
(with-profiler "ocean"
(update-ocean) ;; ocean map update
(draw-ocean) ;; far, mid, near, transition, and texture.
)
(add-ee-profile-frame 'draw :b #xff :a #x80)
;; reset MERC
(with-profiler "merc"
(set! (-> *merc-global-array* count) (the-as uint 0))
(set! *merc-globals* (the-as merc-globals (-> *merc-global-array* globals)))
(set! (-> *shadow-queue* cur-run) (the-as uint 0)))
;; draw the background!
(with-profiler "background"
(init-background)
(execute-connections *background-draw-engine* (current-frame))
;; finish bg (most of the work is here)
(reset! (-> *perf-stats* data 3))
(finish-background)
(read! (-> *perf-stats* data 3))
(update-wait-stats (-> *perf-stats* data 3) (-> *background-work* wait-to-vu0) (the-as uint 0) (the-as uint 0)))
;; perf stats are printed and restarted here, for some reason.
(with-profiler "stats"
(end-perf-stat-collection)
(when (not (paused?))
(when *stats-poly*
(dotimes (level-index (-> *level* length))
(let ((active-level (-> *level* level level-index)))
(if (= (-> active-level status) 'active) (collect-stats (-> active-level bsp)))))
(print-terrain-stats))
(if *display-perf-stats* (print-perf-stats)))
(start-perf-stat-collection))
;; draw the foreground engines.
(with-profiler "foreground-engines"
(foreground-engine-execute (-> *level* level-default foreground-draw-engine 0)
(current-frame)
2
0)
(foreground-engine-execute (-> *level* level-default foreground-draw-engine 1)
(current-frame)
2
1))
;; handle extra processing for foreground
(let ((foreground-buffer (-> *display* frames (-> *display* on-screen) frame global-buf)))
(with-profiler "bones"
(bones-mtx-calc-execute)) ;; skinning matrix calculation
(with-profiler "gmerc"
(generic-merc-execute-all foreground-buffer)) ;; mercneric conversion.
(with-profiler "shadow"
(shadow-execute-all foreground-buffer *shadow-queue*))
(with-profiler "eyes"
(update-eyes)))
;; sprite draw
(when (logtest? (vu1-renderer-mask sprite) *vu1-enable-user*)
(with-profiler "sprite"
(swap-fake-shadow-buffers)
(sprite-draw *display*)))
;; debug drawing
(with-profiler "debug-draw"
(when *debug-segment*
(debug-draw-actors *level* *display-actor-marks*)
(collide-shape-draw-debug-marks))
(render-boundaries))
;; for some reason we clear the touching list here...
(with-profiler "touching"
(send-events-for-touching-shapes *touching-list*)
(free-all-prim-nodes *touching-list*))
(add-ee-profile-frame 'draw :r #x40 :b #x40 :a #x80)
;; spawn actors, compact heaps, etc.
(with-profiler "actors-update"
(actors-update *level*))
(add-ee-profile-frame 'draw :r #x80 :a #x80)
(when (not (paused?))
(if *stats-collide* (print-collide-stats)))
(none))
(defun main-draw-hook ()
"Submit all renderer work for the current frame."
(real-main-draw-hook)
(none))
(define *draw-hook* main-draw-hook)
(defun debug-init-buffer ((debug-bucket bucket-id) (zbuf gs-zbuf) (test gs-test))
"Append a GIF packet that installs zbuf and test for debug draws in bucket."
;; The packet sends three qwords through VIF DIRECT: an A+D GIF tag followed by ZBUF_1 and
;; TEST_1 register writes. Its NEXT tail is inserted into the selected debug bucket so later
;; debug geometry inherits these depth settings.
(with-dma-buffer-add-bucket ((global-buf (-> *display* frames (-> *display* on-screen) frame global-buf)) debug-bucket) :bucket-group (-> *display* frames (-> *display* on-screen) frame bucket-group) (let ((packet-head (the-as object (-> global-buf base))))
(set! (-> (the-as dma-packet packet-head) dma) (new 'static 'dma-tag :qwc #x3 :id (dma-tag-id cnt)))
(set! (-> (the-as dma-packet packet-head) vif0) (new 'static 'vif-tag))
(set! (-> (the-as dma-packet packet-head) vif1) (new 'static 'vif-tag :imm #x3 :cmd (vif-cmd direct) :msk #x1))
(set! (-> global-buf base) (&+ (the-as pointer packet-head) 16))) (let ((gif-head (the-as object (-> global-buf base))))
(set! (-> (the-as gs-gif-tag gif-head) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x2))
(set! (-> (the-as gs-gif-tag gif-head) regs) GIF_REGS_ALL_AD)
(set! (-> global-buf base) (&+ (the-as pointer gif-head) 16))) (let ((register-data (-> global-buf base)))
(set! (-> (the-as (pointer gs-zbuf) register-data) 0) zbuf)
(set! (-> (the-as (pointer gs-reg64) register-data) 1) (gs-reg64 zbuf-1))
(set! (-> (the-as (pointer gs-test) register-data) 2) test)
(set! (-> (the-as (pointer gs-reg64) register-data) 3) (gs-reg64 test-1))
(set! (-> global-buf base) (&+ register-data 32))))
(none))
(define *screen-shot* #f)
(defun display-frame-start ((disp display) (new-frame-idx int) (odd-even int))
"Initialize display frame new-frame-idx for drawing field odd-even. Update timing and frame
counters, reset its DMA buffers and debug state, reserve ordered render buckets, initialize the
debug bucket, update the draw environment, and service the controllers."
;; Mask the VIF1 error selected by ERR.me0; the hardware requires this workaround before a frame.
(#unless PC_PORT
(set! (-> (the-as vif-bank #x10003c00) err me0) 1))
;; figure out how fast we're going compared to the desired.
;; larger = slower than we should.
;; due to vsync, we should never go too fast.
(let ((time-ratio (the float
(+ (/ (timer-count (the-as timer-bank #x10000800)) (the-as uint *ticks-per-frame*))
1 ;; so we round up.
))))
(let ((float-time-ratio (/ (the float (timer-count (the-as timer-bank #x10000800))) (the float *ticks-per-frame*))))
;; on the PS2, if you have > 1/60 seconds between frames, it means you missed a vsync.
;; this doesn't seem to be the case on my machine. It appears that glfwSwapBuffers sometimes returns ~1 ms early,
;; making the next frame ~1 ms too long.
;; to work around with, we internally run the game at 60 fps if it appears to be slightly too slow.
;; if we actually do miss a frame, the time ratio will be around 2.
(#when PC_PORT
(if (< float-time-ratio 1.3) (set! time-ratio 1.0))
#|
(if (> time-ratio 1.)
(format #t "LAG ~f frames~%" (- time-ratio 1.))
)
|#
))
;; inform display system of our speed. This will adjust the scaling used in all physics calculations
(set-time-ratios *display* time-ratio)
;; set our "old" counters. In the event of a game load/save, these will not jump
(set! (-> disp old-base-frame-counter) (-> disp base-frame-counter))
(set! (-> disp old-game-frame-counter) (-> disp game-frame-counter))
(set! (-> disp old-real-frame-counter) (-> disp real-frame-counter))
(set! (-> disp old-integral-frame-counter) (-> disp integral-frame-counter))
(set! (-> disp old-real-integral-frame-counter) (-> disp real-integral-frame-counter))
(set! (-> disp old-part-frame-counter) (-> disp part-frame-counter))
(set! (-> disp old-actual-frame-counter) (-> disp actual-frame-counter))
(set! (-> disp old-real-actual-frame-counter) (-> disp real-actual-frame-counter))
;; base, part, game, and real advance in 300-Hz time-frame ticks. integral counters advance by
;; the number of vertical-sync intervals that elapsed, while actual counters advance once per
;; rendered frame. The real counters continue while paused, and game also stops during movies.
(let ((scaled-ticks (* (the int time-ratio) (the int (-> disp time-factor)))))
;; tell the sparticle system
(set-particle-frame-time (min (seconds 0.04) scaled-ticks))
;; the "not real" frame counters only count when unpaused
(when (not (paused?))
;; these count by scaled time
(+! (-> disp base-frame-counter) scaled-ticks)
(+! (-> disp part-frame-counter) scaled-ticks)
;; this counts actual frames, not seconds. Will count 2 frames if we lag
(+! (-> disp integral-frame-counter) (the int time-ratio))
;; this counts actual frames, not doubling for lag. Will count 1 per frame drawn
(+! (-> disp actual-frame-counter) 1)
;; game counter will count seconds that we're not in a movie
(if (not (movie?)) (+! (-> disp game-frame-counter) scaled-ticks)))
;; real counts like base, but increments when paused
(+! (-> disp real-frame-counter) scaled-ticks))
;; actual frames, lag counts as 2x
(+! (-> disp real-integral-frame-counter) (the int time-ratio)))
;; actual real frames (for real)
(+! (-> disp real-actual-frame-counter) 1)
;; reset the timer.
(timer-reset (the-as timer-bank #x10000800))
;; take a screenshot, if desired
(when *screen-shot*
(if *debug-segment* (store-image odd-even))
(set! *screen-shot* #f))
;; set up the frame object.
(let ((new-frame (-> disp frames new-frame-idx frame)))
;; profile setup
(when *debug-segment*
(dotimes (bar-index 2)
(reset (-> new-frame profile-bar bar-index))))
;; right now, the old frame is being rendered.
;; if we set *sync-dma*, we will wait here until it finishes rendering.
(if *sync-dma* (sync-path 0 0))
;; reset the global dma buffer.
(let ((global-buf (-> new-frame global-buf)))
(set! (-> global-buf base) (-> global-buf data))
(set! (-> global-buf end) (&-> global-buf data-buffer (-> global-buf allocated-length))))
;; reset the debug dma buffer
(when *debug-segment*
(let ((debug-buf (-> new-frame debug-buf)))
(set! (-> debug-buf base) (-> debug-buf data))
(set! (-> debug-buf end) (&-> debug-buf data-buffer (-> debug-buf allocated-length)))))
;; reset the calc buffer. This holds the buckets themselves and what is sent
;; to actually draw the frame.
(let ((calc-buf (-> new-frame calc-buf)))
(set! (-> calc-buf base) (-> calc-buf data))
(set! (-> calc-buf end) (&-> calc-buf data-buffer (-> calc-buf allocated-length))))
;; the default buffer holds a DMA chain to fully reset the GS.
;; reinitialize it, just to be safe
(default-buffer-init *default-regs-buffer*)
;; and add it to the very beginning of the calc buf
(let* ((calc-buf (-> new-frame calc-buf))
(default-regs *default-regs-buffer*)
(reset-call (the-as object (-> calc-buf base))))
(set! (-> (the-as dma-packet reset-call) dma)
(new 'static 'dma-tag :id (dma-tag-id call) :addr (the-as int (-> default-regs data))))
(set! (-> (the-as dma-packet reset-call) vif0) (new 'static 'vif-tag))
(set! (-> (the-as dma-packet reset-call) vif1) (new 'static 'vif-tag))
(set! (-> calc-buf base) (&+ (the-as pointer reset-call) 16)))
;; could be used for debugging or something, but is set to nothing.
(*pre-draw-hook* (-> new-frame calc-buf))
;; reset debugging stuff
(when (not (paused?))
(clear *stdcon1*)
(debug-reset-buffers))
;; Reserve the ordered bucket heads at the front of calc-buf. Renderers may build their packets
;; in any CPU order; inserting each packet into its bucket determines the GS draw order.
(set! (-> new-frame bucket-group) (dma-buffer-add-buckets (-> new-frame calc-buf) BUCKET_COUNT)))
;; initialize the debug bucket
(debug-init-buffer (bucket-id debug-no-zbuf)
(new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24) :zmsk #x1)
(new 'static 'gs-test :zte #x1 :ztst (gs-ztest always)))
;; setup our drawing offset for even/odd offset
(set-draw-env-offset (-> disp frames new-frame-idx draw) 2048 2048 odd-even)
;; read controllers
(service-cpads)
;; now we are ready to run a frame!
(none))
(defun display-frame-finish ((disp display))
"Finish the current frame's DMA lists, link its ordered render buckets, append the final DMA tag,
flush the cache, and return disp. This does not start the transfer."
(let* ((this-frame (-> disp frames (-> disp on-screen) frame))
(this-calc-buf (-> this-frame calc-buf)))
;; post draw stuff
(tie-init-buffers this-calc-buf)
(merc-vu1-init-buffers)
(*post-draw-hook* (-> disp frames (-> disp on-screen) frame calc-buf))
;; Close each bucket with the default GS-state reset and a NEXT tag, so state cannot leak from
;; one rendering stage into the following stage.
;; iterate through all buckets and append a final GS state reset.
(dotimes (bucket-idx BUCKET_COUNT)
;; clear GS state after the bucket
(with-dma-buffer-add-bucket ((this-global-buf (-> this-frame global-buf)) (the-as bucket-id bucket-idx)) :bucket-group (-> *display* frames (-> *display* on-screen) frame bucket-group) (let* ((a0-3 this-global-buf)
(t0-0 *default-regs-buffer*)
(a1-0 (the-as object (-> a0-3 base))))
(set! (-> (the-as dma-packet a1-0) dma) (new 'static 'dma-tag :id (dma-tag-id call) :addr (the-as int (-> t0-0 data))))
(set! (-> (the-as dma-packet a1-0) vif0) (new 'static 'vif-tag :irq #x1))
(set! (-> (the-as dma-packet a1-0) vif1) (new 'static 'vif-tag))
(set! (-> a0-3 base) (&+ (the-as pointer a1-0) 16)))))
;; append a FLUSHE and IRQ to end the calc-buf
(let* ((v1-14 this-calc-buf)
(a0-10 (the-as object (-> v1-14 base))))
(set! (-> (the-as dma-packet a0-10) dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))
(set! (-> (the-as dma-packet a0-10) vif0) (new 'static 'vif-tag :cmd (vif-cmd flushe) :msk #x1))
(set! (-> (the-as dma-packet a0-10) vif1) (new 'static 'vif-tag :irq #x1))
(set! (-> v1-14 base) (&+ (the-as pointer a0-10) 16)))
;; Each reserved head is a zero-length NEXT tag. An empty head jumps directly to the following
;; bucket; a populated head enters its packet chain, whose tail returns to the following head.
;; Patching the heads therefore makes the complete ordered frame one GIF DMA chain.
;; patch the buckets. Now sending the calc buf will send everything!
(dma-buffer-patch-buckets (-> this-frame bucket-group) BUCKET_COUNT)
;; append the final END.
(let* ((v1-15 this-calc-buf)
(a0-13 (the-as object (-> v1-15 base))))
(set! (-> (the-as dma-packet a0-13) dma) (new 'static 'dma-tag :id (dma-tag-id end)))
(set! (-> (the-as (pointer uint64) a0-13) 1) (the-as uint 0))
(set! (-> v1-15 base) (&+ (the-as pointer a0-13) 16)))
;; final cache flush after finishing DMA chains
(flush-cache 0)
;; print debug stats.
(when (not (paused?))
(when *stats-buffer*
(let* ((global-buf (-> this-frame global-buf))
(calc-current (-> this-calc-buf base))
(calc-start (-> this-calc-buf data))
(global-current (-> global-buf base))
(global-start (-> global-buf data))
(global-end (-> global-buf end)))
(format *stdcon* "~0kvu1 buf = ~d~%" (&- calc-current (the-as uint calc-start)))
(format *stdcon* "~0kglobal buf = ~d~%" (&- global-current (the-as uint global-start)))
(format *stdcon* "~0kbase = #x~x~%" global-current)
(format *stdcon* "~0kend = #x~x~%" global-end)))))
disp)
(defun determine-pause-mode ()
"Handle debug frame advance, pause input, controller-loss pause, and progress-screen
deactivation."
;; debug frame advance
(when (and *debug-pause* (= *master-mode* 'pause))
(logclear! (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons start r2))
(logclear! (-> *cpad-list* cpads 0 button0-rel 0) (pad-buttons start r2))
(while (and (= *master-mode* 'pause) (not (cpad-pressed? 0 start r2)))
(sync-path 0 0)
(service-cpads))
(toggle-pause))
(when (or (not *progress-process*) (can-go-back? (-> *progress-process* 0)))
(if (or (cpad-pressed? 0 select r3 start) ;; push pause
(and (logtest? (-> *cpad-list* cpads 0 valid) 128) ;; controller lost
(= *master-mode* 'game)
(>= (-> *display* base-frame-counter) (-> *game-info* blackout-time))
;; this is a hack. this is initialized to (seconds 1000). It prevents controller-loss pause from
;; triggering in the first few seconds of gameplay.
(< (seconds 1003) (-> *display* real-frame-counter)))
(and (cpad-pressed? 0 r2) (paused?)) ;; debug press
*pause-lock*)
(toggle-pause)))
;; if we toggled out of pause, kill it.
(if (!= *master-mode* 'progress) (deactivate-progress))
0)
(define *surrogate-dma-buffer* (the dma-buffer #f))
(#when PC_PORT
(define *disasm-count* 0)
(defmacro disasm-next-dma (&key (count 1))
`(set! *disasm-count* ,count)))
(defun display-sync ((disp display))
"Wait for the previous render and vertical sync, apply pending video-mode changes, start the
current frame's DMA chain, update pause state, and initialize the next display frame."
;; wait for rendering to finish.
(sync-path 0 0)
;; remember when.
;; og:preserve-this setting this to 0 to get rid of lag compensation in PC port, since it's not helpful
(set! (-> disp frames (-> disp on-screen) frame run-time)
(#if PC_PORT 0 (the-as int (timer-count (the-as timer-bank #x10000800)))))
;; now, do a vsync. If we finished rendering in time, this will just wait until the next.
(let ((frame-idx (-> disp on-screen))
(syncv-result (syncv 0)))
;; starting here, we are in a new frame
;; syncv returns odd/even (if you miss multiple syncv's due to the sync-path above taking many
;; frames, this will get us back on the correct field)
(set! *oddeven* syncv-result)
;; if we need to change video modes:
(when (-> *video-parms* set-video-mode)
;; to GS
(set-display2 *display* 0 512 (-> *video-parms* screen-sy) 2 49)
(set! (-> *video-parms* set-video-mode) #f)
;; reset video mode is for changing ntsc/pal
(when (-> *video-parms* reset-video-mode)
(set! (-> *video-parms* reset-video-mode) #f)
;; need to call reset-graph with some magic number
;; also stash this parameter so that if things go really wrong and our DMA transfer
;; times out, we can reset-graph to the appropriate video mode
(if (or (= (-> *setting-control* current video-mode) 'ntsc) (= (-> *setting-control* current video-mode) 'custom))
(set! *video-reset-parm* 2)
(set! *video-reset-parm* 3))
(reset-graph 0 1 *video-reset-parm* 1)))
;; setup the env (Sony functions)
(put-display-env (-> disp frames frame-idx display))
(put-draw-env (the-as (pointer gif-tag) (-> disp frames frame-idx gif)))
;; begin rendering the next frame
(let ((dma-buf-to-send (-> disp frames frame-idx frame calc-buf)))
(when (nonzero? (dma-buffer-length dma-buf-to-send))
(#when PC_PORT
(when (> *disasm-count* 0)
(disasm-dma-list (the-as dma-packet (-> dma-buf-to-send data-buffer)) 'details #t #t -1)
(-! *disasm-count* 1)))
(#if PC_PORT
(__send-gfx-dma-chain (the-as dma-bank-source #x10009000)
(cond
;; some buffer for debugging, not used
(*surrogate-dma-buffer* *surrogate-dma-buffer*)
(else (-> dma-buf-to-send data-buffer))))
(dma-buffer-send-chain (the-as dma-bank-source #x10009000)
(cond
(*surrogate-dma-buffer* *surrogate-dma-buffer*)
(else dma-buf-to-send))))))
(determine-pause-mode)
;; update display frame
(let ((next-frame (+ frame-idx 1)))
(if (< 1 next-frame) (set! next-frame 0))
(set! (-> disp last-screen) (-> disp on-screen))
(set! (-> disp on-screen) next-frame)
;; initialize next frame
(display-frame-start disp next-frame syncv-result)))
(none))
(defun swap-display ((disp display))
"Swap frames! Synchronizes with rendering and vsync, kicks off the next render, and initializes the
to-draw frame"
(display-frame-finish disp)
(display-sync disp) ;; also starts next
)
(defun-debug marks-cam-restore ()
"Restore Mark's saved Village3 camera pose and FOV, install its CPU, VU, and tfragment profiling
baselines, clear the saved statistic strings, and enable old-stat display."
(let ((camera-position (new-stack-vector0))
(camera-rotation (new-stack-matrix0)))
(set! (-> camera-position x) 1672489.2)
(set! (-> camera-position y) 60862.703)
(set! (-> camera-position z) -13051605.0)
(set! (-> camera-position w) 1.0)
(set! (-> camera-rotation vector 0 x) -0.1783)
(set! (-> camera-rotation vector 0 y) 0.0)
(set! (-> camera-rotation vector 0 z) 0.9839)
(set! (-> camera-rotation vector 0 w) 0.0)
(set! (-> camera-rotation vector 1 x) -0.0629)
(set! (-> camera-rotation vector 1 y) 0.9979)
(set! (-> camera-rotation vector 1 z) -0.0114)
(set! (-> camera-rotation vector 1 w) 0.0)
(set! (-> camera-rotation vector 2 x) -0.9819)
(set! (-> camera-rotation vector 2 y) -0.064)
(set! (-> camera-rotation vector 2 z) -0.178)
(set! (-> camera-rotation vector 2 w) 0.0)
(set! (-> camera-rotation vector 3 x) 0.0)
(set! (-> camera-rotation vector 3 y) 0.0)
(set! (-> camera-rotation vector 3 z) 0.0)
(set! (-> camera-rotation vector 3 w) 1.0)
(debug-set-camera-pos-rot! camera-position camera-rotation))
(send-event *camera* 'set-fov 17294.205)
(clear *camera-old-level*)
(format *camera-old-level* "village3")
(set! *camera-old-cpu* 1219)
(set! *camera-old-vu* 9602)
(set! *camera-old-tfrag-bytes* 0)
(clear *camera-old-stat-string-tfrag*)
(clear *camera-old-stat-string-tfrag-near*)
(clear *camera-old-stat-string-total*)
(set! *display-camera-old-stats* #t)
(none))
(defun-debug eddie-cam-restore ()
"Restore Eddie's saved debug camera pose."
(let ((camera-position (new-stack-vector0))
(camera-rotation (new-stack-matrix0)))
(set! (-> camera-position x) -427963.66)
(set! (-> camera-position y) 24967.182)
(set! (-> camera-position z) 339465.53)
(set! (-> camera-position w) 1.0)
(set! (-> camera-rotation vector 0 x) -0.6026)
(set! (-> camera-rotation vector 0 y) 0.0)
(set! (-> camera-rotation vector 0 z) 0.7979)
(set! (-> camera-rotation vector 0 w) 0.0)
(set! (-> camera-rotation vector 1 x) -0.1522)
(set! (-> camera-rotation vector 1 y) 0.9816)
(set! (-> camera-rotation vector 1 z) -0.1149)
(set! (-> camera-rotation vector 1 w) 0.0)
(set! (-> camera-rotation vector 2 x) -0.7833)
(set! (-> camera-rotation vector 2 y) -0.1908)
(set! (-> camera-rotation vector 2 z) -0.5915)
(set! (-> camera-rotation vector 2 w) 0.0)
(set! (-> camera-rotation vector 3 x) 0.0)
(set! (-> camera-rotation vector 3 y) 0.0)
(set! (-> camera-rotation vector 3 z) 0.0)
(set! (-> camera-rotation vector 3 w) 1.0)
(debug-set-camera-pos-rot! camera-position camera-rotation))
(none))
(defun-debug gregs-jungle-cam-restore ()
"Restore Greg's saved Jungle camera pose and FOV, install its CPU, VU, and tfragment profiling
baselines, and clear the saved statistic strings."
(let ((camera-position (new-stack-vector0))
(camera-rotation (new-stack-matrix0)))
(set! (-> camera-position x) 1399233.0)
(set! (-> camera-position y) 39027.11)
(set! (-> camera-position z) -1485580.1)
(set! (-> camera-position w) 1.0)
(set! (-> camera-rotation vector 0 x) 0.9965)
(set! (-> camera-rotation vector 0 y) 0.0)
(set! (-> camera-rotation vector 0 z) 0.0829)
(set! (-> camera-rotation vector 0 w) 0.0)
(set! (-> camera-rotation vector 1 x) -0.0021)
(set! (-> camera-rotation vector 1 y) 0.9996)
(set! (-> camera-rotation vector 1 z) 0.0253)
(set! (-> camera-rotation vector 1 w) 0.0)
(set! (-> camera-rotation vector 2 x) -0.0829)
(set! (-> camera-rotation vector 2 y) -0.0254)
(set! (-> camera-rotation vector 2 z) 0.9962)
(set! (-> camera-rotation vector 2 w) 0.0)
(set! (-> camera-rotation vector 3 x) 0.0)
(set! (-> camera-rotation vector 3 y) 0.0)
(set! (-> camera-rotation vector 3 z) 0.0)
(set! (-> camera-rotation vector 3 w) 1.0)
(debug-set-camera-pos-rot! camera-position camera-rotation))
(send-event *camera* 'set-fov 11650.845)
(clear *camera-old-level*)
(format *camera-old-level* "jungle")
(set! *camera-old-cpu* 5801)
(set! *camera-old-vu* 9605)
(set! *camera-old-tfrag-bytes* #x1ffee0)
(clear *camera-old-stat-string-tfrag*)
(clear *camera-old-stat-string-tfrag-near*)
(clear *camera-old-stat-string-total*)
(none))
(defun-debug gregs-village1-cam-restore ()
"Restore Greg's saved Village1 camera pose and FOV, install its CPU, VU, and tfragment profiling
baselines, and clear the saved statistic strings."
(let ((camera-position (new-stack-vector0))
(camera-rotation (new-stack-matrix0)))
(set! (-> camera-position x) -511224.06)
(set! (-> camera-position y) 157579.95)
(set! (-> camera-position z) 764585.25)
(set! (-> camera-position w) 1.0)
(set! (-> camera-rotation vector 0 x) -0.9009)
(set! (-> camera-rotation vector 0 y) 0.0)
(set! (-> camera-rotation vector 0 z) -0.4338)
(set! (-> camera-rotation vector 0 w) 0.0)
(set! (-> camera-rotation vector 1 x) 0.0984)
(set! (-> camera-rotation vector 1 y) 0.9739)
(set! (-> camera-rotation vector 1 z) -0.2043)
(set! (-> camera-rotation vector 1 w) 0.0)
(set! (-> camera-rotation vector 2 x) 0.4225)
(set! (-> camera-rotation vector 2 y) -0.2268)
(set! (-> camera-rotation vector 2 z) -0.8774)
(set! (-> camera-rotation vector 2 w) 0.0)
(set! (-> camera-rotation vector 3 x) 0.0)
(set! (-> camera-rotation vector 3 y) 0.0)
(set! (-> camera-rotation vector 3 z) 0.0)
(set! (-> camera-rotation vector 3 w) 1.0)
(debug-set-camera-pos-rot! camera-position camera-rotation))
(send-event *camera* 'set-fov 11650.845)
(clear *camera-old-level*)
(format *camera-old-level* "village1")
(set! *camera-old-cpu* 4899)
(set! *camera-old-vu* 9605)
(set! *camera-old-tfrag-bytes* #x24e680)
(clear *camera-old-stat-string-tfrag*)
(clear *camera-old-stat-string-tfrag-near*)
(clear *camera-old-stat-string-total*)
(none))
(defun-debug gregs-texture-cam-restore ()
"Restore Greg's saved Village1 texture-test camera pose and FOV, install its CPU, VU, and
tfragment profiling baselines, and clear the saved statistic strings."
(let ((camera-position (new-stack-vector0))
(camera-rotation (new-stack-matrix0)))
(set! (-> camera-position x) 1103816.0)
(set! (-> camera-position y) 96275.71)
(set! (-> camera-position z) -632064.5)
(set! (-> camera-position w) 1.0)
(set! (-> camera-rotation vector 0 x) 0.4063)
(set! (-> camera-rotation vector 0 y) 0.0)
(set! (-> camera-rotation vector 0 z) -0.9137)
(set! (-> camera-rotation vector 0 w) 1.0)
(set! (-> camera-rotation vector 1 x) 0.2824)
(set! (-> camera-rotation vector 1 y) 0.951)
(set! (-> camera-rotation vector 1 z) 0.1256)
(set! (-> camera-rotation vector 1 w) 1.0)
(set! (-> camera-rotation vector 2 x) 0.8689)
(set! (-> camera-rotation vector 2 y) -0.3091)
(set! (-> camera-rotation vector 2 z) 0.3864)
(set! (-> camera-rotation vector 2 w) 1.0)
(set! (-> camera-rotation vector 3 x) 0.0)
(set! (-> camera-rotation vector 3 y) 0.0)
(set! (-> camera-rotation vector 3 z) 0.0)
(set! (-> camera-rotation vector 3 w) 1.0)
(debug-set-camera-pos-rot! camera-position camera-rotation))
(send-event *camera* 'set-fov 11650.845)
(clear *camera-old-level*)
(format *camera-old-level* "village1")
(set! *camera-old-cpu* 4772)
(set! *camera-old-vu* 9603)
(set! *camera-old-tfrag-bytes* #x22e680)
(clear *camera-old-stat-string-tfrag*)
(clear *camera-old-stat-string-tfrag-near*)
(clear *camera-old-stat-string-total*)
(none))
(defun-debug gregs-texture2-cam-restore ()
"Restore Greg's saved second Village1 texture-test camera pose and FOV, install its CPU, VU, and
tfragment profiling baselines, and clear the saved statistic strings."
(let ((camera-position (new-stack-vector0))
(camera-rotation (new-stack-matrix0)))
(set! (-> camera-position x) 1954572.9)
(set! (-> camera-position y) 135123.98)
(set! (-> camera-position z) -1028725.44)
(set! (-> camera-position w) 1.0)
(set! (-> camera-rotation vector 0 x) 0.2535)
(set! (-> camera-rotation vector 0 y) 0.0)
(set! (-> camera-rotation vector 0 z) 0.9673)
(set! (-> camera-rotation vector 0 w) 1.0)
(set! (-> camera-rotation vector 1 x) -0.1051)
(set! (-> camera-rotation vector 1 y) 0.994)
(set! (-> camera-rotation vector 1 z) 0.0275)
(set! (-> camera-rotation vector 1 w) 1.0)
(set! (-> camera-rotation vector 2 x) -0.9615)
(set! (-> camera-rotation vector 2 y) -0.1087)
(set! (-> camera-rotation vector 2 z) 0.252)
(set! (-> camera-rotation vector 2 w) 1.0)
(set! (-> camera-rotation vector 3 x) 0.0)
(set! (-> camera-rotation vector 3 y) 0.0)
(set! (-> camera-rotation vector 3 z) 0.0)
(set! (-> camera-rotation vector 3 w) 1.0)
(debug-set-camera-pos-rot! camera-position camera-rotation))
(send-event *camera* 'set-fov 11650.845)
(clear *camera-old-level*)
(format *camera-old-level* "village1")
(set! *camera-old-cpu* 4936)
(set! *camera-old-vu* #x4b0c)
(set! *camera-old-tfrag-bytes* #x22e680)
(clear *camera-old-stat-string-tfrag*)
(clear *camera-old-stat-string-tfrag-near*)
(clear *camera-old-stat-string-total*)
(none))
(defun-debug cave-cam-restore ()
"Restore the saved cave debug camera pose."
(let ((camera-position (new-stack-vector0))
(camera-rotation (new-stack-matrix0)))
(set! (-> camera-position x) -1449013.1)
(set! (-> camera-position y) 15114.015)
(set! (-> camera-position z) -1621305.5)
(set! (-> camera-position w) 1.0)
(set! (-> camera-rotation vector 0 x) -0.8223)
(set! (-> camera-rotation vector 0 y) 0.0)
(set! (-> camera-rotation vector 0 z) -0.5689)
(set! (-> camera-rotation vector 0 w) 0.0)
(set! (-> camera-rotation vector 1 x) 0.0076)
(set! (-> camera-rotation vector 1 y) 0.9999)
(set! (-> camera-rotation vector 1 z) -0.0111)
(set! (-> camera-rotation vector 1 w) 0.0)
(set! (-> camera-rotation vector 2 x) 0.5689)
(set! (-> camera-rotation vector 2 y) -0.0135)
(set! (-> camera-rotation vector 2 z) -0.8222)
(set! (-> camera-rotation vector 2 w) 0.0)
(set! (-> camera-rotation vector 3 x) 0.0)
(set! (-> camera-rotation vector 3 y) 0.0)
(set! (-> camera-rotation vector 3 z) 0.0)
(set! (-> camera-rotation vector 3 w) 1.0)
(debug-set-camera-pos-rot! camera-position camera-rotation))
(none))
(defun-debug paals-cam-restore ()
"Restore Paal's saved debug camera pose."
(let ((camera-position (new-stack-vector0))
(camera-rotation (new-stack-matrix0)))
(set! (-> camera-position x) -791260.7)
(set! (-> camera-position y) 50858.62)
(set! (-> camera-position z) -163715.47)
(set! (-> camera-position w) 1.0)
(set! (-> camera-rotation vector 0 x) -0.7816)
(set! (-> camera-rotation vector 0 y) 0.0)
(set! (-> camera-rotation vector 0 z) -0.6236)
(set! (-> camera-rotation vector 0 w) 0.0)
(set! (-> camera-rotation vector 1 x) 0.0672)
(set! (-> camera-rotation vector 1 y) 0.9941)
(set! (-> camera-rotation vector 1 z) -0.0843)
(set! (-> camera-rotation vector 1 w) 0.0)
(set! (-> camera-rotation vector 2 x) 0.62)
(set! (-> camera-rotation vector 2 y) -0.1079)
(set! (-> camera-rotation vector 2 z) -0.7771)
(set! (-> camera-rotation vector 2 w) 0.0)
(set! (-> camera-rotation vector 3 x) 0.0)
(set! (-> camera-rotation vector 3 y) 0.0)
(set! (-> camera-rotation vector 3 z) 0.0)
(set! (-> camera-rotation vector 3 w) 1.0)
(debug-set-camera-pos-rot! camera-position camera-rotation))
(none))