diff --git a/goal_src/jak1/engine/gfx/background/subdivide.gc b/goal_src/jak1/engine/gfx/background/subdivide.gc index 0b7fd03337..3249d0b9b2 100644 --- a/goal_src/jak1/engine/gfx/background/subdivide.gc +++ b/goal_src/jak1/engine/gfx/background/subdivide.gc @@ -54,11 +54,7 @@ (defun-debug print-terrain-stats () "Print active-level memory use and every renderer-statistics bucket, update the display strings, and clear the counters for the next reporting interval." - ;; make our own profile thing. - (if *debug-segment* - (add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0) - 'draw - (new 'static 'rgba :r #x40 :b #x40 :a #x80))) + (add-profile-frame! #x40 0 #x40 #x80 'draw) (dotimes (i (-> *level* length)) (let ((lev (-> *level* level i))) (when (= (-> lev status) 'active) @@ -68,7 +64,6 @@ (-> lev index) (-> lev name) (* 0.0009765625 (the float (-> lev mem-usage))))))) - ;; print all stats (format *stdcon* "~0k~%grps frags tris dverts strip insts~%") (print-tr-stat (-> *terrain-stats* pris) "pris" *temp-string*) (print-tr-stat (-> *merc-global-stats* merc) "merc" *temp-string*) @@ -107,11 +102,11 @@ (clear-tr-stat (-> *terrain-stats* ocean-mid)) (clear-tr-stat (-> *terrain-stats* ocean-near)) (clear-tr-stat (-> *terrain-stats* total)) - (if *debug-segment* - (add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0) 'draw (new 'static 'rgba :b #xff :a #x80))) + (add-profile-frame! 0 0 #xff #x80 'draw) 0 (none)) + (defun update-subdivide-settings! ((settings subdivide-settings) (math-cam math-camera) (idx int)) "Select a close/far LOD profile, construct five nonuniform world-distance thresholds, convert them to camera-scaled distances, and update the tfragment thresholds." @@ -125,14 +120,14 @@ (set! (-> settings meters 3) (+ (-> settings meters 4) (/ band-unit 2))) (set! (-> settings meters 2) (+ (-> settings meters 3) band-unit)) (set! (-> settings meters 1) (+ (-> settings meters 2) (* 2.0 band-unit)))) - ;; VU code compares against homogeneous camera-space distance, so scale the world thresholds - ;; once here instead of converting each fragment during subdivision. The EE classifier wants the - ;; unscaled world values instead, because it works from a bounding sphere in world units; it gets - ;; them negated so it can add rather than subtract. meters[3] is computed for the record and has no - ;; consumer on either side. + + ;; On the VU, tfrag compares the FOG value, which is proportional to distance + ;; from the camera. This scale factor inverts it. inv-hmge-scale.w is the fog range and + ;; d converts from homogenous coordinates to actual distance in meters (let ((camera-scale (/ (-> math-cam inv-hmge-scale w) (-> math-cam d)))) (dotimes (i 5) (set! (-> settings dist i) (* camera-scale (-> settings meters i))))) + ;; On the EE, the DMA generation code looks at world space positions and expects negated distances. (set! (-> *tfrag-work* frag-dists x) (- (-> settings meters 0))) (set! (-> *tfrag-work* frag-dists y) (- (-> settings meters 1))) (set! (-> *tfrag-work* frag-dists z) (- (-> settings meters 2))) @@ -143,28 +138,24 @@ (define *subdivide-settings* (new 'global 'subdivide-settings (meters 30) (meters 70))) (defun set-tfrag-dists! ((dists tfrag-dists)) - "Fill the affine collapse coefficients for the two tfragment subdivision levels. For distance d in - [near, far], y is (far - d) / (far - near), x is half of (d - near) / (far - near), and w stores - the far boundary, which is the distance at which that level has finished collapsing." - ;; Each k0*d + k1 pair evaluates the descending y weight and half-scaled ascending x weight - ;; without a divide in the VU program. Entry 0 is level 0 and covers dist[0] down to dist[1]; - ;; entry 1 is level 1 and covers dist[1] down to dist[2]. - ;; - ;; The VU applies these as pos = pos * y + (parent-a + parent-b) * x, so at y = 0, x = 0.5 a - ;; subdivided vertex is sitting exactly on the midpoint of the parent edge it splits and the - ;; coarser mesh can take over without moving anything. Everything in here is per frame and per - ;; level, never per fragment: that is what makes two terrain patches agree on where a vertex they - ;; both own has got to, which is why terrain does not crack along a detail boundary. - ;; - ;; The w lanes are the same numbers again, kept unscaled so the VU can compare a transformed w - ;; against them directly for its discrete "both parents have finished collapsing" test. Remember - ;; these are camera-scaled through inv-hmge-scale.w, which is the fog slope and is negative, so - ;; dist[] is negative and grows more negative with distance. + "Fill the affine collapse coefficients for the two tfragment subdivision levels." + ;; The VU computes weights.xy = k0.xy * pos.w + k1.xy + ;; where + ;; weights.x goes from 0 -> 0.5 + ;; weights.y goes from 1 -> 0 + ;; and + ;; pos = p * weights.y + (parent-a + parent-b) * weights.x + ;; so + ;; pos goes from "p" to the midpoint of the parents as the level of detail drops. (let ((far-0 (-> *subdivide-settings* dist 0)) (boundary-1 (-> *subdivide-settings* dist 1)) (near-2 (-> *subdivide-settings* dist 2))) + ;; also store the boundaries so VU can check if both parents are beyond the threshold and + ;; collapse. (set! (-> dists k0s 0 w) far-0) (set! (-> dists k0s 1 w) boundary-1) + + ;; find k0/k1 coefficients (let ((inverse-span-0 (/ 1.0 (- far-0 boundary-1))) (inverse-span-1 (/ 1.0 (- boundary-1 near-2)))) (set! (-> dists k0s 0 y) (- inverse-span-0)) diff --git a/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc b/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc index 9ce17acff5..0fb3b820dd 100644 --- a/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc +++ b/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc @@ -21,9 +21,7 @@ (giftag gs-gif-tag :inline) (color qword :inline))) -;; VU1 memory for the distorter. The tables are uploaded starting at entry, so every address in the -;; program is that base plus a quadword index into the type -- change the type and the program -;; follows. The count word and the input area are not part of any type and stay plain constants. +;; VU1 memory for the distorter. ;; ;; 352 - 479 entry: 128 quadwords, alternating screen direction and framebuffer ST offset ;; 480 - 488 ientry: the first direction of each turn count from 3 through 11 @@ -102,24 +100,8 @@ (new 'static 'gs-prim :prim (gs-prim-type tri-strip) :tme #x1) :nreg #xf)) ;; set up registers - (set! (-> tables giftag regs) - (new 'static - 'gif-tag-regs - :regs0 (gif-reg-id st) - :regs1 (gif-reg-id rgbaq) - :regs2 (gif-reg-id xyzf2) - :regs3 (gif-reg-id st) - :regs4 (gif-reg-id rgbaq) - :regs5 (gif-reg-id xyzf2) - :regs6 (gif-reg-id st) - :regs7 (gif-reg-id rgbaq) - :regs8 (gif-reg-id xyzf2) - :regs9 (gif-reg-id st) - :regs10 (gif-reg-id rgbaq) - :regs11 (gif-reg-id xyzf2) - :regs12 (gif-reg-id st) - :regs13 (gif-reg-id rgbaq) - :regs14 (gif-reg-id xyzf2))) + (set! (-> tables giftag regs) (gs-reg-list st rgbaq xyzf2 st rgbaq xyzf2 st rgbaq xyzf2 st rgbaq xyzf2 st rgbaq xyzf2)) + ;; set color (set! (-> tables color vector4w x) 128) (set! (-> tables color vector4w y) 128) diff --git a/goal_src/jak1/engine/gfx/sprite/sprite.gc b/goal_src/jak1/engine/gfx/sprite/sprite.gc index 0b5b6b7fdf..e80208ed9c 100644 --- a/goal_src/jak1/engine/gfx/sprite/sprite.gc +++ b/goal_src/jak1/engine/gfx/sprite/sprite.gc @@ -93,8 +93,7 @@ (none)) (defun add-to-sprite-aux-list ((system sparticle-system) (cpuinfo sparticle-cpuinfo) (sprite-data sprite-vec-data-3d)) - "Record a particle's four-byte 2D warp-sprite reference in the auxiliary list when space remains, - then clear the submitted 3D sprite's alpha. This is a sparticle callback." + "Sparticle callback to add a sprite to the aux-list." (let ((aux-list *sprite-aux-list*)) (when (< (-> aux-list entry) (-> aux-list num-entries)) (set! (-> aux-list data (-> aux-list entry)) (-> cpuinfo sprite)) @@ -135,14 +134,11 @@ (fog-max float :overlay-at (-> fog-clamp y)) (max-scale float :overlay-at (-> fog-clamp z)))) -;; Sprite VU1 memory map. Nothing here is a bare number twice: the input buffer is described by the -;; per-chunk packet layout and the constants by sprite-frame-data, whose field order is its upload -;; order, so both ends of the DMA name the same thing. -;; +;; Sprite VU1 memory map. ;; 0 chunk header: the sprite count for this batch ;; 1 - 144 48 sprites x 3 vector quadwords ;; 145 - 384 48 sprites x 5 adgif quadwords -;; 400 - 799 the same layout again -- VIF's own double buffer, selected with BASE and OFFSET +;; 400 - 799 Same as 0-399, double buffered input ;; 800 - 849 GIF output buffer 0 ;; 850 - 899 GIF output buffer 1 ;; 900 - 903 the active transform @@ -170,15 +166,12 @@ (defconstant SPRITE-VU-USER-HVDF (+ SPRITE-VU-HVDF 1)) -;; The frame constants. sprite-frame-data is uploaded as one 41-quadword block and its field order is -;; its upload order, so every constant the microprogram loads can name a field instead of a number. (defconstant SPRITE-VU-FRAME-DATA 980) (defmacro sprite-frame-const (&rest path) `(+ SPRITE-VU-FRAME-DATA (/ (offset-of sprite-frame-data ,@path) 16))) -;; VU1 entry points. Entry 0 loads the constants that outlive a chunk; the other three are one -;; MSCAL per chunk. +;; VU1 entry points. (defconstant SPRITE-VU-ENTRY-INIT 0) (defconstant SPRITE-VU-ENTRY-2D-WORLD 3) @@ -198,14 +191,7 @@ ;; the A+D mode ;; each adgif has 5x registers, so we set up a tag to do 5x a+d's (set! (-> data adgif-giftag tag) (new 'static 'gif-tag64 :nloop #x1 :nreg #x5)) - (set! (-> data adgif-giftag regs) - (new 'static - 'gif-tag-regs - :regs0 (gif-reg-id a+d) - :regs1 (gif-reg-id a+d) - :regs2 (gif-reg-id a+d) - :regs3 (gif-reg-id a+d) - :regs4 (gif-reg-id a+d))) + (set! (-> data adgif-giftag regs) (gs-reg-list a+d a+d a+d a+d a+d)) ;; World-space 2D sprites use one shared color followed by four ST/XYZF2 pairs. (set! (-> data sprite-2d-giftag tag) (new 'static @@ -216,18 +202,8 @@ :prim (new 'static 'gs-prim :prim (gs-prim-type tri-fan) :tme #x1 :fge #x1 :abe #x1) :nreg #x9)) - (set! (-> data sprite-2d-giftag regs) - (new 'static - 'gif-tag-regs - :regs0 (gif-reg-id rgbaq) - :regs1 (gif-reg-id st) - :regs2 (gif-reg-id xyzf2) - :regs3 (gif-reg-id st) - :regs4 (gif-reg-id xyzf2) - :regs5 (gif-reg-id st) - :regs6 (gif-reg-id xyzf2) - :regs7 (gif-reg-id st) - :regs8 (gif-reg-id xyzf2))) + (set! (-> data sprite-2d-giftag regs) (gs-reg-list rgbaq st xyzf2 st xyzf2 st xyzf2 st xyzf2)) + ;; Screen-space 2D sprites use the same vertex layout without fog. (set! (-> data sprite-2d-giftag-2 tag) (new 'static @@ -238,18 +214,8 @@ :prim (new 'static 'gs-prim :prim (gs-prim-type tri-fan) :tme #x1 :abe #x1) :nreg #x9)) - (set! (-> data sprite-2d-giftag-2 regs) - (new 'static - 'gif-tag-regs - :regs0 (gif-reg-id rgbaq) - :regs1 (gif-reg-id st) - :regs2 (gif-reg-id xyzf2) - :regs3 (gif-reg-id st) - :regs4 (gif-reg-id xyzf2) - :regs5 (gif-reg-id st) - :regs6 (gif-reg-id xyzf2) - :regs7 (gif-reg-id st) - :regs8 (gif-reg-id xyzf2))) + (set! (-> data sprite-2d-giftag-2 regs) (gs-reg-list rgbaq st xyzf2 st xyzf2 st xyzf2 st xyzf2)) + ;; 3D sprites carry ST, color, and XYZF2 for each of their four vertices. (set! (-> data sprite-3d-giftag tag) (new 'static @@ -261,21 +227,8 @@ (new 'static 'gs-prim :prim (gs-prim-type tri-fan) :tme #x1 :fge #x1 :abe #x1) :nreg #xc)) ;; note that we have rgbaq's per vertex in 3d - (set! (-> data sprite-3d-giftag regs) - (new 'static - 'gif-tag-regs - :regs0 (gif-reg-id st) - :regs1 (gif-reg-id rgbaq) - :regs2 (gif-reg-id xyzf2) - :regs3 (gif-reg-id st) - :regs4 (gif-reg-id rgbaq) - :regs5 (gif-reg-id xyzf2) - :regs6 (gif-reg-id st) - :regs7 (gif-reg-id rgbaq) - :regs8 (gif-reg-id xyzf2) - :regs9 (gif-reg-id st) - :regs10 (gif-reg-id rgbaq) - :regs11 (gif-reg-id xyzf2))) + (set! (-> data sprite-3d-giftag regs) (gs-reg-list st rgbaq xyzf2 st rgbaq xyzf2 st rgbaq xyzf2 st rgbaq xyzf2)) + ;; A clipped 3D quad becomes a variable-length triangle fan, so each vertex supplies one ;; ST/RGBAQ/XYZF2 triplet. (set! (-> data clipped-giftag tag) @@ -287,8 +240,8 @@ :prim (new 'static 'gs-prim :prim (gs-prim-type tri-fan) :tme #x1 :fge #x1 :abe #x1) :nreg #x3)) - (set! (-> data clipped-giftag regs) - (new 'static 'gif-tag-regs :regs0 (gif-reg-id st) :regs1 (gif-reg-id rgbaq) :regs2 (gif-reg-id xyzf2))) + (set! (-> data clipped-giftag regs) (gs-reg-list st rgbaq xyzf2)) + ;; Triangle giftag for the warped-sprite path. sprite-vu1-block does not load this frame ;; constant, so that path is not active here. (set! (-> data warp-giftag tag) @@ -300,18 +253,8 @@ :prim (new 'static 'gs-prim :prim (gs-prim-type tri) :tme #x1 :abe #x1) :nreg #xc)) - (set! (-> data warp-giftag regs) - (new 'static - 'gif-tag-regs - :regs0 (gif-reg-id st) - :regs1 (gif-reg-id rgbaq) - :regs2 (gif-reg-id xyzf2) - :regs3 (gif-reg-id st) - :regs4 (gif-reg-id rgbaq) - :regs5 (gif-reg-id xyzf2) - :regs6 (gif-reg-id st) - :regs7 (gif-reg-id rgbaq) - :regs8 (gif-reg-id xyzf2))) + (set! (-> data warp-giftag regs) (gs-reg-list st rgbaq xyzf2 st rgbaq xyzf2 st rgbaq xyzf2)) + ;; set up an adgif. (set! (-> data screen-shader prims 1) (gs-reg64 tex0-1)) (set! (-> data screen-shader tex0) (new 'static 'gs-tex0 :tbw #x8 :tw #xa :th #x8 :tbp0 (* tbp-offset 32))) @@ -324,7 +267,7 @@ (new 'static 'gs-clamp :wms (gs-tex-wrap-mode region-clamp) :wmt (gs-tex-wrap-mode region-clamp) :maxu 639 :maxv 239)) (set! (-> data screen-shader prims 9) (gs-reg64 alpha-1)) (set! (-> data screen-shader alpha) (new 'static 'gs-alpha :b #x1 :d #x1)) - ;; sin/cosine table + ;; sin/cosine polynomial coefficients for rotation (set! (-> data sincos-01 z) 0.999998) (set! (-> data sincos-23 z) -0.16666014) (set! (-> data sincos-45 z) 0.008326521) @@ -345,12 +288,11 @@ (set! (-> data basis-y y) (- (-> *math-camera* perspective vector 1 y))) (set! (-> data min-scale) (sqrtf (* (/ 1.0 (-> data basis-x x)) (/ 1.0 (-> data basis-y y))))) (set! (-> data inv-area) (/ 1.0 (* (-> data min-scale) (-> data min-scale)))) - ;; Four blocks of four corners. A 2D sprite's flag field is a quadword index straight into this - ;; array, so it selects its own block: 0 gives a quad centred on the sprite position, 4 gives one - ;; anchored at its left edge, which is what a bar or a run of text wants. Block 8 is the texture - ;; coordinate corners, the same for every sprite, and block 12 is a quad lying in the XZ plane -- - ;; the 3D path's starting shape, before the quaternion rotates it, and the reason a fake shadow - ;; ends up flat on the ground. + ;; cdata stores 4 sets of 4 corners. The mode can be picked by flags / 4. + ;; 0 - centered (-0.5, -0.5) to (0.5, 0.5) + ;; 4 - (0, -0.5) to (1, 0.5) + ;; 8 - (0, 0) to (1, 1), used for texture coords + ;; 12 - XZ plane, for 3D (set-vector! (-> data cdata 0) -0.5 -0.5 0.0 0.0) (set-vector! (-> data cdata 1) 0.5 -0.5 0.0 0.0) (set-vector! (-> data cdata 2) 0.5 0.5 0.0 0.0) @@ -548,27 +490,6 @@ 0 (none)) -#| -(defun sprite-add-frame-data ((dma-buff dma-buffer) (tbp-offset uint)) - "Upload the frame data." - (let ((s5-0 41)) ;; qwc of frame data. - (dma-buffer-add-cnt-vif2 dma-buff s5-0 - (new 'static 'vif-tag :cmd (vif-cmd stcycl) - :imm (new 'static 'vif-stcycl-imm :cl 4 :wl 4)) - (new 'static 'vif-tag :cmd (vif-cmd unpack-v4-32) :num s5-0 - :imm (new 'static 'vif-unpack-imm :addr 980)) - ) - ;; setup frame data directly in the dma buffer. - (sprite-setup-frame-data - (the-as sprite-frame-data (-> dma-buff base)) - (the-as int tbp-offset) - ) - (&+! (-> dma-buff base) (* s5-0 16)) - ) - (none) - ) -|# - (defun sprite-add-frame-data ((dma-buff dma-buffer) (tbp-offset uint)) "Build and upload the 41 quadwords of sprite constants shared by every chunk in this frame." (let ((frame-qwc 41)) @@ -608,21 +529,6 @@ (&+ (-> sprites vec-data) (* 48 start-sprite-idx)) (new 'static 'vif-tag :cmd (vif-cmd nop)) (new 'static 'vif-tag :cmd (vif-cmd unpack-v4-32) :num qwc-pkt2 :imm (new 'static 'vif-unpack-imm :flg 1 :addr SPRITE-VU-VEC-DATA)))) - #| - ;(when (= mscal-addr 3) - (dotimes (i num-sprites) - (let ((spidx (+ i start-sprite-idx))) - ;(when (or (= spidx (-> sprites num-sprites 0)) (= spidx (+ 1 (-> sprites num-sprites 0)))) - (let ((data (the sprite-vec-data-2d (&+ (-> sprites vec-data) (* 48 (+ i start-sprite-idx)))))) - (let ((vec (-> data x-y-z-sx))) - (format 0 "sp: ~d ~f ~f ~f~%" (+ i start-sprite-idx) (-> vec x) (-> vec y) (-> vec z)) - ) - ) - ; ) - ) - ) - ; ) - |# ;; third packet is adgif data (5 qw/sprite) (let ((qwc-pkt3 (* 5 num-sprites))) (dma-buffer-add-ref-vif2 dma-buff