mirror of
https://github.com/open-goal/jak-project
synced 2026-08-09 10:54:39 -04:00
4689 lines
200 KiB
Common Lisp
4689 lines
200 KiB
Common Lisp
;;-*-Lisp-*-
|
|
(in-package goal)
|
|
(bundles "ENGINE.CGO" "GAME.CGO")
|
|
(require "engine/gfx/background/subdivide.gc")
|
|
(require "engine/collide/collide-func.gc")
|
|
(require "examples/debug-collide.gc")
|
|
(require "engine/collide/collide-probe.gc")
|
|
(require "engine/geometry/bounding-box.gc")
|
|
(require "engine/collide/collide-mesh-h.gc")
|
|
(require "engine/collide/main-collide.gc")
|
|
(require "engine/common-obs/water-h.gc")
|
|
(require "engine/collide/collide-shape-h.gc")
|
|
(require "engine/debug/debug.gc")
|
|
|
|
;; A collide-cache gathers the small world-space working set used by one collision query. Background
|
|
;; traversal contributes packed collision fragments, foreground connection lists contribute dynamic
|
|
;; primitives, and water may contribute a two-triangle bottom plane. The narrow-phase probes then
|
|
;; examine only the cached primitives and triangles.
|
|
;;
|
|
;; Box, vertical Y-probe, and swept line-sphere queries share the same cache. The swept query builds
|
|
;; an oriented box around the motion and keeps its inverse transform in *collide-work*; the import
|
|
;; pass can therefore perform the same integer AABB reject in that local frame. Multi-sphere queries
|
|
;; first fill from the spheres' combined bounds and then test each accepted primitive against the
|
|
;; individual spheres.
|
|
|
|
;; DECOMP BEGINS
|
|
|
|
(defmethod debug-draw ((obj collide-cache))
|
|
"Draw the cached triangles with their surface colors and the cached foreground spheres."
|
|
(let ((tri (the-as collide-cache-tri (-> obj tris))))
|
|
(countdown (tris-left (-> obj num-tris))
|
|
(let ((tri-color (copy-and-set-field (-> *pat-mode-info* (-> tri pat mode) color) a 64)))
|
|
(add-debug-flat-triangle #t
|
|
(bucket-id debug-no-zbuf)
|
|
(the-as vector (-> tri vertex))
|
|
(-> tri vertex 1)
|
|
(-> tri vertex 2)
|
|
tri-color)
|
|
(#when PC_PORT
|
|
(add-debug-outline-triangle #t
|
|
(bucket-id debug-no-zbuf)
|
|
(-> tri vertex 0)
|
|
(-> tri vertex 1)
|
|
(-> tri vertex 2)
|
|
(static-rgba 0 0 0 64))))
|
|
(&+! tri 64)))
|
|
(let ((prim (the-as collide-cache-prim (-> obj prims))))
|
|
(countdown (prims-left (-> obj num-prims))
|
|
(when (= (-> prim prim-core prim-type) -1)
|
|
(let ((prim-color (copy-and-set-field (-> *pat-mode-info* (-> (the-as collide-shape-prim-sphere (-> prim prim)) pat mode) color) a 64)))
|
|
(add-debug-sphere #t
|
|
(bucket-id debug-no-zbuf)
|
|
(the-as vector (-> prim prim-core))
|
|
(-> prim prim-core world-sphere w)
|
|
prim-color)))
|
|
(&+! prim 48)))
|
|
0
|
|
(none))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Setup
|
|
;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(define *already-printed-exeeded-max-cache-tris* #f)
|
|
|
|
(defmethod initialize ((obj collide-cache))
|
|
"Empty this cache and clear its querying process."
|
|
(set! (-> obj num-tris) 0)
|
|
(set! (-> obj num-prims) 0)
|
|
(set! (-> obj proc) #f)
|
|
(set! *already-printed-exeeded-max-cache-tris* #f)
|
|
(none))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Fill using Bounding Box
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; Background mesh fill has four stages:
|
|
;; 1. Gather fragments with BSP traversal or the line-sphere collide probe.
|
|
;; 2. Stream each fragment's packed vertices through VIF0 into VU0 data memory.
|
|
;; 3. Unpack and transform the vertices from VU0 into scratchpad triangles.
|
|
;; 4. Reject triangles outside the active query and append the survivors to the cache.
|
|
;;
|
|
;; The EE overlaps stages 2 through 4 across two VU0 buffers. The PC path follows the same data flow
|
|
;; through host implementations.
|
|
|
|
(#when PC_PORT
|
|
(defmethod-mips2c "(method 26 collide-cache)" 26 collide-cache)
|
|
(defmethod-mips2c "(method 27 collide-cache)" 27 collide-cache)
|
|
(defmethod-mips2c "(method 28 collide-cache)" 28 collide-cache)
|
|
(defmethod-mips2c "(method 29 collide-cache)" 29 collide-cache)
|
|
(defmethod-mips2c "(method 32 collide-cache)" 32 collide-cache)
|
|
(defmethod-mips2c "(method 12 collide-shape-prim-mesh)" 12 collide-shape-prim-mesh)
|
|
(defmethod-mips2c "(method 14 collide-shape-prim-mesh)" 14 collide-shape-prim-mesh)
|
|
(defmethod-mips2c "(method 13 collide-shape-prim-mesh)" 13 collide-shape-prim-mesh)
|
|
(defmethod-mips2c "(method 30 collide-cache)" 30 collide-cache)
|
|
(defmethod-mips2c "(method 9 collide-cache-prim)" 9 collide-cache-prim)
|
|
(defmethod-mips2c "(method 10 collide-cache-prim)" 10 collide-cache-prim)
|
|
(defmethod-mips2c "(method 9 collide-puss-work)" 9 collide-puss-work)
|
|
(defmethod-mips2c "(method 10 collide-puss-work)" 10 collide-puss-work)
|
|
(def-mips2c __pc-upload-collide-frag (function object object object none)))
|
|
|
|
;; Scratchpad vertex records occupy 32 bytes. The first quadword is the vertex truncated to
|
|
;; integer world coordinates and the second is the same vertex in floating-point coordinates.
|
|
;; The line-sphere transform fills a second integer bank at scratchpad+0x1000 after rotating the
|
|
;; query into its axis-aligned working frame. Triangle strip bytes select three of these records;
|
|
;; a negative control byte reverses winding while continuing the strip.
|
|
(#unless PC_PORT
|
|
(defconstant COLLIDE-SPAD-BASE #x70000000)
|
|
(defconstant COLLIDE-SPAD-LINE-INTEGER-BANK #x1000)
|
|
(defconstant COLLIDE-SPAD-VERTEX-SIZE #x20)
|
|
;; VIF0 alternates UNPACK destinations 0 and 128. While one bank is being unpacked, the previous
|
|
;; bank is transformed into scratchpad and its triangles are imported into the cache.
|
|
(defconstant COLLIDE-VU0-BANK-QW #x80)
|
|
(defconstant COLLIDE-VIF0-CHANNEL #x10008000)
|
|
;; CHCR STR | TTE. The VIF tag transfer bit is needed because the DMA tag carries the UNPACK
|
|
;; command which selects the destination VU0 bank.
|
|
(defconstant COLLIDE-VIF0-START-TTE #x80002000)
|
|
;; VIF UNPACK V3-16 adds this exponent bias to packed xyz. Subtracting the converted mesh base
|
|
;; translation recovers ordinary floating-point coordinates without scalar halfword conversion.
|
|
(defconstant COLLIDE-PACKED-VERTEX-BIAS-X #x4d000000)
|
|
;; The box and Y-probe importers are identical. Their callers prepare different query bounds, but
|
|
;; both consume the same scratchpad vertex/strip representation and write collide-cache-tri records.
|
|
(defmacro import-spad-triangles-in-query-box ()
|
|
`(begin
|
|
(add.i sp sp -112)
|
|
(s.d ra sp)
|
|
(s.d fp sp 8)
|
|
(m fp t9)
|
|
(s.q s1 sp 16)
|
|
(s.q s2 sp 32)
|
|
(s.q s3 sp 48)
|
|
(s.q s4 sp 64)
|
|
(s.q s5 sp 80)
|
|
(s.q gp sp 96)
|
|
;; Reserve the remaining collide-cache-tri slots and form the output cursor. BASIC field
|
|
;; addresses are four bytes below their displayed offsets, hence 60/76 for collide-box4w.
|
|
(nop!)
|
|
(add.i v1 r0 460)
|
|
(l.wu a2 a0)
|
|
(sub t0 v1 a2)
|
|
(add.i a3 r0 64)
|
|
(mult3 a3 a2 a3)
|
|
(b.lt t0 r0 cache-full :delay (m t0 a0))
|
|
(nop!)
|
|
;; Locate the strip stream, PAT index stream, query bounds, and output record.
|
|
(l.bu t2 a1 25)
|
|
(add.i t0 t0 #x132c)
|
|
(l.wu t1 a1)
|
|
(sll t2 t2 4)
|
|
(l.hu t3 a1 8)
|
|
(add a3 t0 a3)
|
|
(l.q t0 a0 60)
|
|
(add t1 t1 t2)
|
|
(l.q t2 a0 76)
|
|
(nop!)
|
|
(l.wu a1 a1 4)
|
|
(add t3 t1 t3)
|
|
(l.wu t4 a0 8)
|
|
(label next-strip)
|
|
(lui t5 #x7000)
|
|
(l.b t7 t1)
|
|
(nop!)
|
|
(l.b t8 t1 1)
|
|
(b.lt t7 r0 finish-strip :delay (l.b t6 t1 2))
|
|
;; Load the first triangle. Integer vertices are the first quadword of each 32-byte record.
|
|
(sll t7 t7 5)
|
|
(sll t8 t8 5)
|
|
(sll t9 t6 5)
|
|
(add t6 t7 t5)
|
|
(add t7 t8 t5)
|
|
(l.q t8 t6)
|
|
(add ra t9 t5)
|
|
(l.q t9 t7)
|
|
(min.w s4 t8 t9)
|
|
(l.q gp ra)
|
|
(max.w s5 t8 t9)
|
|
(mmi-nop!)
|
|
(min.w s4 s4 gp)
|
|
(mmi-nop!)
|
|
(max.w s5 s5 gp)
|
|
(mmi-nop!)
|
|
;; Reject when any xyz minimum is above query max or any maximum is below query min. ppach
|
|
;; collapses the packed comparison lanes; shifting by sixteen discards the unused w result.
|
|
(pcgt.w s4 s4 t2)
|
|
(mmi-nop!)
|
|
(pcgt.w s5 t0 s5)
|
|
(mmi-nop!)
|
|
(or.q s4 s4 s5)
|
|
(l.bu s5 t3)
|
|
(ppach s4 r0 s4)
|
|
(mmi-nop!)
|
|
(sll s4 s4 16)
|
|
(sll s5 s5 2)
|
|
(b.nz s4 advance-triangle :delay (add s5 s5 a1))
|
|
(b.eq a2 v1 cache-full :delay (l.wu s5 s5))
|
|
(and s4 s5 t4)
|
|
(nop!)
|
|
(b.nz s4 advance-triangle :delay (nop!))
|
|
(nop!)
|
|
;; PAT passes the cache ignore mask. Copy floating vertices from record+16 and overlay PAT in
|
|
;; the destination record's final quadword.
|
|
(s.q r0 a3 48)
|
|
(add.i a2 a2 1)
|
|
(s.w s5 a3 48)
|
|
(add.i a3 a3 64)
|
|
(l.q s5 t6 16)
|
|
(nop!)
|
|
(l.q s4 t7 16)
|
|
(nop!)
|
|
(l.q s3 ra 16)
|
|
(nop!)
|
|
(s.q s5 a3 -64)
|
|
(nop!)
|
|
(s.q s4 a3 -48)
|
|
(nop!)
|
|
(s.q s3 a3 -32)
|
|
(label advance-triangle)
|
|
(add.i t3 t3 1)
|
|
(add.i t1 t1 3)
|
|
(add.i s5 r0 16)
|
|
(nop!)
|
|
;; Each following strip byte supplies the new vertex. Its sign chooses which old edge is
|
|
;; retained, preserving the strip's winding without rebuilding an explicit index triple.
|
|
(label strip-loop)
|
|
(nop!)
|
|
(l.b s4 t1)
|
|
(add.i t1 t1 1)
|
|
(nop!)
|
|
(b.z s4 next-strip :delay (nop!))
|
|
(b.ltl s4 r0 negative-strip-index :delay (sub s4 r0 s4))
|
|
(m.q t8 t9)
|
|
(m t6 t7)
|
|
(sub s5 r0 s5)
|
|
(nop!)
|
|
(label negative-strip-index)
|
|
(add.i s4 s4 -1)
|
|
(m t7 ra)
|
|
(m.q t9 gp)
|
|
(sll ra s4 5)
|
|
(add ra ra t5)
|
|
(l.bu s4 t3)
|
|
(min.w s2 t8 t9)
|
|
(l.q gp ra)
|
|
(max.w s3 t8 t9)
|
|
(mmi-nop!)
|
|
(min.w s2 s2 gp)
|
|
(mmi-nop!)
|
|
(max.w s3 s3 gp)
|
|
(mmi-nop!)
|
|
(pcgt.w s2 s2 t2)
|
|
(mmi-nop!)
|
|
(pcgt.w s3 t0 s3)
|
|
(mmi-nop!)
|
|
(or.q s3 s2 s3)
|
|
(mmi-nop!)
|
|
(ppach s3 r0 s3)
|
|
(mmi-nop!)
|
|
(sll s3 s3 16)
|
|
(sll s4 s4 2)
|
|
(b.nz s3 strip-loop :delay (add.i t3 t3 1))
|
|
(add s4 s4 a1)
|
|
(nop! :count 2)
|
|
(l.wu s4 s4)
|
|
(and s3 s4 t4)
|
|
(nop!)
|
|
(b.nz s3 strip-loop :delay (nop!))
|
|
(b.eq a2 v1 cache-full :delay (nop!))
|
|
(nop!)
|
|
(s.q r0 a3 48)
|
|
(add.i a2 a2 1)
|
|
(s.w s4 a3 48)
|
|
(add.i s2 a3 16)
|
|
(l.q s1 t7 16)
|
|
(add.i a3 a3 64)
|
|
(l.q s4 t6 16)
|
|
(nop!)
|
|
(l.q s3 ra 16)
|
|
(nop!)
|
|
(s.q s1 s2)
|
|
(sub s1 s2 s5)
|
|
(add s2 s2 s5)
|
|
(nop!)
|
|
(s.q s4 s1)
|
|
(b strip-loop :delay (s.q s3 s2))
|
|
(label finish-strip)
|
|
(nop!)
|
|
(s.w a2 a0)
|
|
(b importer-return :delay (nop!))
|
|
(label cache-full)
|
|
(nop!)
|
|
(s.w v1 a0)
|
|
(m! v1 *already-printed-exeeded-max-cache-tris*)
|
|
(b.ne s7 v1 skip-cache-warning :delay (m v1 s7))
|
|
(add.i v1 s7 #t)
|
|
(set! *already-printed-exeeded-max-cache-tris* v1)
|
|
(add.i v1 s7 debug)
|
|
(m! a0 *cheat-mode*)
|
|
(b.ne a0 v1 skip-cache-warning :delay (m v1 s7))
|
|
(m! t9 format)
|
|
(m! a0 *stdcon*)
|
|
(add.i a1 fp L305)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0)
|
|
(label skip-cache-warning)
|
|
(b importer-return :delay (nop!))
|
|
(label importer-return)
|
|
(m v0 r0)
|
|
(l.d ra sp)
|
|
(l.d fp sp 8)
|
|
(l.q gp sp 96)
|
|
(l.q s5 sp 80)
|
|
(l.q s4 sp 64)
|
|
(l.q s3 sp 48)
|
|
(l.q s2 sp 32)
|
|
(l.q s1 sp 16)
|
|
(jr ra :delay (add.i sp sp 112))
|
|
(nop! :count 3))))
|
|
|
|
(#unless PC_PORT
|
|
(defmethod load-mesh-from-spad-in-box ((cache collide-cache) (mesh collide-frag-mesh))
|
|
"Append scratchpad triangles which overlap collide-box4w and are not masked by ignore-mask."
|
|
(rlet ((cache-reg :reg a0 :type collide-cache)
|
|
(mesh-reg :reg a1 :type collide-frag-mesh))
|
|
(import-spad-triangles-in-query-box))))
|
|
|
|
(#unless PC_PORT
|
|
(defmethod transform-collide-mesh-in-spad ((cache collide-cache) (mesh collide-frag-mesh))
|
|
"Transform the scratchpad vertex bank into the line-sphere query frame and write the
|
|
integer-coordinate copy at scratchpad+0x1000."
|
|
(rlet ((matrix-x :reg vf1)
|
|
(matrix-y :reg vf2)
|
|
(matrix-z :reg vf3)
|
|
(matrix-t :reg vf4)
|
|
(point-0 :reg vf5)
|
|
(point-1 :reg vf6)
|
|
(point-2 :reg vf7)
|
|
(point-3 :reg vf8)
|
|
(point-4 :reg vf9)
|
|
(point-5 :reg vf10)
|
|
(point-6 :reg vf11)
|
|
(point-7 :reg vf12))
|
|
(nop! :count 2)
|
|
(m! a0 *collide-work*)
|
|
(lui v1 #x7000)
|
|
(l.bu a1 a1 24)
|
|
(nop!)
|
|
;; inv-mat maps world vertices into the axis-aligned frame constructed for the swept sphere.
|
|
(l.vf matrix-x a0 48)
|
|
(nop!)
|
|
(l.vf matrix-y a0 64)
|
|
(nop!)
|
|
(l.vf matrix-z a0 80)
|
|
(nop!)
|
|
(l.vf matrix-t a0 96)
|
|
(nop!)
|
|
;; Eight vertices are kept in flight. Float vertices remain in the low scratchpad bank;
|
|
;; this function writes only their integer query-frame copies to the bank at +0x1000.
|
|
(l.vf point-0 v1 16)
|
|
(nop!)
|
|
(l.vf point-1 v1 48)
|
|
(nop!)
|
|
(l.vf point-2 v1 80)
|
|
(nop!)
|
|
(l.vf point-3 v1 112)
|
|
(mula.w.vf matrix-t vf0)
|
|
(l.vf point-4 v1 144)
|
|
(madda.x.vf matrix-x point-0)
|
|
(l.vf point-5 v1 176)
|
|
(madda.y.vf matrix-y point-0)
|
|
(l.vf point-6 v1 208)
|
|
(madd.z.vf point-0 matrix-z point-0)
|
|
(l.vf point-7 v1 240)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x point-1)
|
|
(nop!)
|
|
(madda.y.vf matrix-y point-1)
|
|
(nop!)
|
|
(madd.z.vf point-1 matrix-z point-1)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x point-2)
|
|
(nop!)
|
|
(madda.y.vf matrix-y point-2)
|
|
(nop!)
|
|
(madd.z.vf point-2 matrix-z point-2)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x point-3)
|
|
(nop!)
|
|
(madda.y.vf matrix-y point-3)
|
|
(nop!)
|
|
(madd.z.vf point-3 matrix-z point-3)
|
|
(nop!)
|
|
(ftoi.vf point-0 point-0)
|
|
(nop!)
|
|
(ftoi.vf point-1 point-1)
|
|
(nop!)
|
|
(ftoi.vf point-2 point-2)
|
|
(nop!)
|
|
(ftoi.vf point-3 point-3)
|
|
(nop!)
|
|
(label transform-eight)
|
|
(mula.w.vf matrix-t vf0)
|
|
(s.vf point-0 v1 #x1000)
|
|
(madda.x.vf matrix-x point-4)
|
|
(s.vf point-1 v1 #x1020)
|
|
(madda.y.vf matrix-y point-4)
|
|
(s.vf point-2 v1 #x1040)
|
|
(madd.z.vf point-4 matrix-z point-4)
|
|
(s.vf point-3 v1 #x1060)
|
|
(mula.w.vf matrix-t vf0)
|
|
(l.vf point-0 v1 272)
|
|
(madda.x.vf matrix-x point-5)
|
|
(l.vf point-1 v1 304)
|
|
(madda.y.vf matrix-y point-5)
|
|
(l.vf point-2 v1 336)
|
|
(madd.z.vf point-5 matrix-z point-5)
|
|
(l.vf point-3 v1 368)
|
|
(add.i v1 v1 256)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x point-6)
|
|
(add.i a0 a1 -4)
|
|
(madda.y.vf matrix-y point-6)
|
|
(b.le a0 r0 transformed-all :delay (madd.z.vf point-6 matrix-z point-6))
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x point-7)
|
|
(nop!)
|
|
(madda.y.vf matrix-y point-7)
|
|
(nop!)
|
|
(madd.z.vf point-7 matrix-z point-7)
|
|
(nop!)
|
|
(ftoi.vf point-4 point-4)
|
|
(nop!)
|
|
(ftoi.vf point-5 point-5)
|
|
(nop!)
|
|
(ftoi.vf point-6 point-6)
|
|
(nop!)
|
|
(ftoi.vf point-7 point-7)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(s.vf point-4 v1 3968)
|
|
(madda.x.vf matrix-x point-0)
|
|
(s.vf point-5 v1 4000)
|
|
(madda.y.vf matrix-y point-0)
|
|
(s.vf point-6 v1 4032)
|
|
(madd.z.vf point-0 matrix-z point-0)
|
|
(s.vf point-7 v1 4064)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x point-1)
|
|
(add.i a1 a0 -4)
|
|
(madda.y.vf matrix-y point-1)
|
|
(b.le a1 r0 transformed-all :delay (madd.z.vf point-1 matrix-z point-1))
|
|
(mula.w.vf matrix-t vf0)
|
|
(l.vf point-4 v1 144)
|
|
(madda.x.vf matrix-x point-2)
|
|
(l.vf point-5 v1 176)
|
|
(madda.y.vf matrix-y point-2)
|
|
(l.vf point-6 v1 208)
|
|
(madd.z.vf point-2 matrix-z point-2)
|
|
(l.vf point-7 v1 240)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x point-3)
|
|
(nop!)
|
|
(madda.y.vf matrix-y point-3)
|
|
(nop!)
|
|
(madd.z.vf point-3 matrix-z point-3)
|
|
(nop!)
|
|
(ftoi.vf point-0 point-0)
|
|
(nop!)
|
|
(ftoi.vf point-1 point-1)
|
|
(nop!)
|
|
(ftoi.vf point-2 point-2)
|
|
(nop!)
|
|
(ftoi.vf point-3 point-3)
|
|
(nop!)
|
|
(b transform-eight :delay (nop!))
|
|
(label transformed-all)
|
|
(m v0 r0)
|
|
(jr ra :delay (add sp sp r0))
|
|
(nop! :count 3))))
|
|
|
|
(#unless PC_PORT
|
|
(defmethod fill-from-background ((cache collide-cache) (find-mesh (function bsp-header int collide-list none)) (import-mesh (function collide-cache collide-frag-mesh none)))
|
|
"Gather background fragments, overlap their VIF0 uploads with VU0 unpacking, and import the
|
|
triangles accepted by the active query."
|
|
(rlet ((cache-reg :reg gp :type collide-cache)
|
|
(find-mesh-reg :reg s4)
|
|
(import-mesh-reg :reg s5))
|
|
(add.i sp sp -96)
|
|
(s.d ra sp)
|
|
(s.d fp sp 8)
|
|
(m fp t9)
|
|
(s.q s2 sp 16)
|
|
(s.q s3 sp 32)
|
|
(s.q s4 sp 48)
|
|
(s.q s5 sp 64)
|
|
(s.q gp sp 80)
|
|
(m cache-reg a0)
|
|
(m find-mesh-reg a1)
|
|
(m import-mesh-reg a2)
|
|
(m! v1 *collide-list*)
|
|
(s.w r0 v1)
|
|
;; The line-sphere query already has a collide-probe traversal. Other queries ask each
|
|
;; active level BSP to append its matching fragments.
|
|
(m! v1 bsp-header)
|
|
(l.wu v1 v1 68)
|
|
(b.ne find-mesh-reg v1 gather-from-bsps :delay (nop!))
|
|
(add.i s4 r0 0)
|
|
(b probe-level-test :delay (nop!))
|
|
(label probe-level-loop)
|
|
(add.i v1 r0 2608)
|
|
(mult3 v1 v1 s4)
|
|
(add.i v1 v1 96)
|
|
(m! a0 *level*)
|
|
(add a0 v1 a0)
|
|
(add.i v1 s7 active)
|
|
(l.wu a1 a0 16)
|
|
(b.ne a1 v1 probe-next-level :delay (m v1 s7))
|
|
;; Performance counter 14 brackets the collide-probe traversal.
|
|
(m! v1 *perf-stats*)
|
|
(add.i v1 v1 740)
|
|
(l.wu a1 v1 28)
|
|
(l.wu a2 v1 4)
|
|
(add.i a2 a2 1)
|
|
(s.w a2 v1 4)
|
|
(b.z a1 probe-counter-ready :delay (nop!))
|
|
(mtc0 Perf r0)
|
|
(sync.l)
|
|
(sync.p)
|
|
(mtpc pcr0 r0)
|
|
(mtpc pcr1 r0)
|
|
(sync.l)
|
|
(sync.p)
|
|
(mtc0 Perf a1)
|
|
(sync.l)
|
|
(sync.p)
|
|
(label probe-counter-ready)
|
|
(m v1 r0)
|
|
(m! t9 collide-probe-make-list)
|
|
(m! a1 *collide-list*)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m! v1 *perf-stats*)
|
|
(add.i v1 v1 740)
|
|
(l.wu a0 v1 28)
|
|
(b.z a0 probe-next-level :delay (nop!))
|
|
(mtc0 Perf r0)
|
|
(sync.l)
|
|
(sync.p)
|
|
(mfpc a0 pcr0)
|
|
(l.wu a1 v1 32)
|
|
(add a0 a1 a0)
|
|
(s.w a0 v1 32)
|
|
(mfpc a0 pcr1)
|
|
(l.wu a1 v1 36)
|
|
(add a0 a1 a0)
|
|
(s.w a0 v1 36)
|
|
(label probe-next-level)
|
|
(m v1 r0)
|
|
(add.i s4 s4 1)
|
|
(label probe-level-test)
|
|
(m! v1 *level*)
|
|
(l.w v1 v1)
|
|
(slt v1 s4 v1)
|
|
(b.nz v1 probe-level-loop :delay (nop!))
|
|
(m v1 s7)
|
|
(m v1 s7)
|
|
(b fragments-ready :delay (nop!))
|
|
(label gather-from-bsps)
|
|
(add.i s3 r0 0)
|
|
(b bsp-level-test :delay (nop!))
|
|
(label bsp-level-loop)
|
|
(add.i v1 r0 2608)
|
|
(mult3 v1 v1 s3)
|
|
(add.i v1 v1 96)
|
|
(m! a0 *level*)
|
|
(add v1 v1 a0)
|
|
(add.i a0 s7 active)
|
|
(l.wu a1 v1 16)
|
|
(b.ne a1 a0 bsp-next-level :delay (m a0 s7))
|
|
(m t9 find-mesh-reg)
|
|
(l.wu a0 v1 44)
|
|
(add.i a1 r0 0)
|
|
(m! a2 *collide-list*)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m a0 v0)
|
|
(label bsp-next-level)
|
|
(add.i s3 s3 1)
|
|
(label bsp-level-test)
|
|
(m! v1 *level*)
|
|
(l.w v1 v1)
|
|
(slt v1 s3 v1)
|
|
(b.nz v1 bsp-level-loop :delay (nop!))
|
|
(m v1 s7)
|
|
(m v1 s7)
|
|
(label fragments-ready)
|
|
(m! v1 *collide-list*)
|
|
(l.w v1 v1)
|
|
(slt v1 r0 v1)
|
|
(b.z v1 background-fill-done :delay (m v1 s7))
|
|
;; Build the fixed VIF packet at scratchpad+0x2000. STROW supplies the unpack exponent bias,
|
|
;; STMOD/STMASK preserve w, and STCYCL expands V3-16 input to one vector per vertex.
|
|
(add.i v1 r0 #x2000)
|
|
(lui a0 #x7000)
|
|
(add v1 v1 a0)
|
|
(lui a0 #x3000)
|
|
(s.d a0 v1)
|
|
(s.w r0 v1 8)
|
|
(lui a0 #x6900)
|
|
(ori a0 a0 #x4000)
|
|
(s.w a0 v1 12)
|
|
(add.i v1 v1 16)
|
|
(lui a0 #x7000)
|
|
(s.d a0 v1)
|
|
(s.d r0 v1 8)
|
|
(add.i s4 r0 0)
|
|
(m! v1 *collide-list*)
|
|
(add.i s3 v1 16)
|
|
(l.wu v1 s3)
|
|
(add.i a0 r0 #x2000)
|
|
(lui a1 #x7000)
|
|
(add s2 a0 a1)
|
|
(l.bu a0 v1 25)
|
|
(l.wu a1 v1)
|
|
(l.bu v1 v1 24)
|
|
(s.h a0 s2)
|
|
(s.w a1 s2 4)
|
|
(s.b v1 s2 14)
|
|
;; Start the first upload, then enter the two-bank pipeline.
|
|
(lui v1 #x1000)
|
|
(ori v1 v1 #x8000)
|
|
(m a0 v1)
|
|
(label wait-first-vif0)
|
|
(l.w a1 a0)
|
|
(nop! :count 3)
|
|
(and.i a1 a1 256)
|
|
(nop!)
|
|
(b.z a1 first-vif0-idle :delay (nop!))
|
|
(nop! :count 10)
|
|
(b wait-first-vif0 :delay (nop!))
|
|
(label first-vif0-idle)
|
|
(m a0 r0)
|
|
(s.w r0 v1 32)
|
|
(l.d a0 fp collide-vif0-start-tte)
|
|
(s.w a0 v1 48)
|
|
(sync.l)
|
|
(add.i a0 r0 325)
|
|
(s.w a0 v1)
|
|
(sync.l)
|
|
(m v1 r0)
|
|
(b fragment-pipeline-test :delay (nop!))
|
|
(label fragment-pipeline-loop)
|
|
;; Queue fragment N+1 into the opposite VU0 bank before consuming fragment N.
|
|
(add.i a2 s4 1)
|
|
(m! v1 *collide-list*)
|
|
(l.w v1 v1)
|
|
(slt v1 a2 v1)
|
|
(b.z v1 drain-vif0 :delay (nop!))
|
|
(m v1 s3)
|
|
(add.i v1 v1 16)
|
|
(l.wu a1 v1)
|
|
(l.bu v1 a1 25)
|
|
(l.wu a0 a1)
|
|
(l.bu a1 a1 24)
|
|
(and.i a2 a2 1)
|
|
(sll a3 a2 7)
|
|
(lui a2 #x1000)
|
|
(ori a2 a2 #x8000)
|
|
(m t0 a2)
|
|
(label wait-next-vif0)
|
|
(l.w t1 t0)
|
|
(nop! :count 3)
|
|
(and.i t1 t1 256)
|
|
(nop!)
|
|
(b.z t1 next-vif0-idle :delay (nop!))
|
|
(nop! :count 10)
|
|
(b wait-next-vif0 :delay (nop!))
|
|
(label next-vif0-idle)
|
|
(m t0 r0)
|
|
(s.h v1 s2)
|
|
(s.w a0 s2 4)
|
|
(s.b a1 s2 14)
|
|
(s.h a3 s2 12)
|
|
(sync.l)
|
|
(s.w r0 a2 32)
|
|
(l.d v1 fp collide-vif0-start-tte)
|
|
(s.w v1 a2 48)
|
|
(sync.l)
|
|
(add.i v1 r0 325)
|
|
(s.w v1 a2)
|
|
(sync.l)
|
|
(m v1 r0)
|
|
(b consume-current-fragment :delay (nop!))
|
|
(label drain-vif0)
|
|
(lui v1 #x1000)
|
|
(ori v1 v1 #x8000)
|
|
(label wait-vif0-drain)
|
|
(l.w a0 v1)
|
|
(nop! :count 3)
|
|
(and.i a0 a0 256)
|
|
(nop!)
|
|
(b.z a0 consume-current-fragment :delay (nop!))
|
|
(nop! :count 10)
|
|
(b wait-vif0-drain :delay (nop!))
|
|
(label consume-current-fragment)
|
|
(m v1 r0)
|
|
(add.i a3 r0 0)
|
|
(and.i v1 s4 1)
|
|
(b.z v1 current-vu0-bank-ready :delay (m v1 s7))
|
|
(add.i a3 r0 128)
|
|
(m v1 a3)
|
|
(label current-vu0-bank-ready)
|
|
(m a0 cache-reg)
|
|
(l.wu v1 a0 -4)
|
|
(l.wu t9 v1 144)
|
|
(l.wu a1 s3)
|
|
(l.wu a2 s3 4)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0)
|
|
(m t9 import-mesh-reg)
|
|
(m a0 cache-reg)
|
|
(l.wu a1 s3)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(add.i s4 s4 1)
|
|
(add.i s3 s3 16)
|
|
(label fragment-pipeline-test)
|
|
(m! v1 *collide-list*)
|
|
(l.w v1 v1)
|
|
(slt v1 s4 v1)
|
|
(b.nz v1 fragment-pipeline-loop :delay (nop!))
|
|
(m v1 s7)
|
|
;; Background triangles are exposed as one synthetic cached mesh primitive.
|
|
(l.w a0 cache-reg)
|
|
(slt v1 r0 a0)
|
|
(b.z v1 background-fill-done :delay (m a1 s7))
|
|
(add.i v1 cache-reg 108)
|
|
(m! a1 *collide-shape-prim-backgnd*)
|
|
(s.h a0 v1 42)
|
|
(s.w a1 v1 36)
|
|
(add.i a0 r0 1)
|
|
(s.w a0 cache-reg 4)
|
|
(s.h r0 v1 40)
|
|
(s.w cache-reg v1 32)
|
|
(l.q a0 a1 12)
|
|
(s.q a0 v1)
|
|
(l.q a1 a1 28)
|
|
(s.q a1 v1 16)
|
|
(label background-fill-done)
|
|
(m v0 r0)
|
|
(l.d ra sp)
|
|
(l.d fp sp 8)
|
|
(l.q gp sp 80)
|
|
(l.q s5 sp 64)
|
|
(l.q s4 sp 48)
|
|
(l.q s3 sp 32)
|
|
(l.q s2 sp 16)
|
|
(jr ra :delay (add.i sp sp 96))
|
|
(nop! :count 2)
|
|
(asm-data (label collide-vif0-start-tte) (word #x80002000 0)))))
|
|
|
|
(#unless PC_PORT
|
|
(defmethod unpack-background-collide-mesh ((cache collide-cache) (mesh collide-frag-mesh) (inst basic) (vu-bank int))
|
|
"Expand VIF-unpacked vertices from VU0 memory into the scratchpad float/integer vertex layout.
|
|
Apply the compressed TIE instance transform when inst is nonfalse."
|
|
(rlet ((packed-bias :reg vf13)
|
|
(mesh-base :reg vf14)
|
|
(matrix-x :reg vf15)
|
|
(matrix-y :reg vf16)
|
|
(matrix-z :reg vf17)
|
|
(matrix-t :reg vf18))
|
|
(add.i sp sp -16)
|
|
(s.d fp sp 8)
|
|
(m fp t9)
|
|
(add.i a0 fp collide-packed-vertex-bias)
|
|
(nop!)
|
|
(b.eq a2 s7 unpack-uninstanced :delay (nop!))
|
|
;; Decode the compressed instance basis. Rows are signed Q12; translation is widened
|
|
;; separately and added to the instance origin before the vertex batches begin.
|
|
(lui v1 #x7000)
|
|
(l.vf mesh-base a1 12)
|
|
(vmove.xyzw vf1 vf0)
|
|
(l.vf packed-bias a0)
|
|
(vmove.xyzw vf2 vf0)
|
|
(l.bu a0 a1 24)
|
|
(m vi1 a3)
|
|
(vmove.xyzw vf3 vf0)
|
|
(itof.vf mesh-base mesh-base)
|
|
(vmove.xyzw vf4 vf0)
|
|
(vmove.xyzw vf5 vf0)
|
|
(nop!)
|
|
(vmove.xyzw vf6 vf0)
|
|
(nop!)
|
|
(vmove.xyzw vf7 vf0)
|
|
(nop!)
|
|
(vmove.xyzw vf8 vf0)
|
|
(nop! :count 2)
|
|
(l.d a1 a2 52)
|
|
(nop!)
|
|
(l.d t1 a2 28)
|
|
(pextlh a1 a1 r0)
|
|
(l.d a3 a2 36)
|
|
(sra.w t0 a1 10)
|
|
(l.d a1 a2 44)
|
|
(pextlh t1 t1 r0)
|
|
(mmi-nop!)
|
|
(sra.w t1 t1 16)
|
|
(mmi-nop!)
|
|
(pextlh a3 a3 r0)
|
|
(m matrix-t t0)
|
|
(sra.w a3 a3 16)
|
|
(m matrix-x t1)
|
|
(pextlh a1 a1 r0)
|
|
(m matrix-y a3)
|
|
(sra.w a1 a1 16)
|
|
(l.vf vf1 a2 12)
|
|
(nop!)
|
|
(m matrix-z a1)
|
|
(itof.vf matrix-t matrix-t)
|
|
(nop!)
|
|
(itof.vf matrix-x matrix-x :fixed 12)
|
|
(nop!)
|
|
(itof.vf matrix-y matrix-y :fixed 12)
|
|
(nop!)
|
|
(itof.vf matrix-z matrix-z :fixed 12)
|
|
(nop!)
|
|
(add.vf.xyz matrix-t matrix-t vf1)
|
|
(nop!)
|
|
(sub.vf packed-bias packed-bias mesh-base)
|
|
;; Prime eight vertices from the selected VU0 bank.
|
|
(lqi.vf.xyz vf1 vi1)
|
|
(add.i a0 a0 -4)
|
|
(lqi.vf.xyz vf2 vi1)
|
|
(nop!)
|
|
(lqi.vf.xyz vf3 vi1)
|
|
(nop!)
|
|
(lqi.vf.xyz vf4 vi1)
|
|
(sub.vf.xyz vf1 vf1 packed-bias)
|
|
(lqi.vf.xyz vf5 vi1)
|
|
(sub.vf.xyz vf2 vf2 packed-bias)
|
|
(lqi.vf.xyz vf6 vi1)
|
|
(sub.vf.xyz vf3 vf3 packed-bias)
|
|
(lqi.vf.xyz vf7 vi1)
|
|
(sub.vf.xyz vf4 vf4 packed-bias)
|
|
(lqi.vf.xyz vf8 vi1)
|
|
;; Transform the first four while the second four wait in vf5..vf8.
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf1)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf1)
|
|
(nop!)
|
|
(madd.z.vf vf1 matrix-z vf1)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf2)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf2)
|
|
(nop!)
|
|
(madd.z.vf vf2 matrix-z vf2)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf3)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf3)
|
|
(nop!)
|
|
(madd.z.vf vf3 matrix-z vf3)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf4)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf4)
|
|
(nop!)
|
|
(madd.z.vf vf4 matrix-z vf4)
|
|
(nop!)
|
|
(ftoi.vf vf9 vf1)
|
|
(s.vf vf1 v1 16)
|
|
(ftoi.vf vf10 vf2)
|
|
(s.vf vf2 v1 48)
|
|
(ftoi.vf vf11 vf3)
|
|
(s.vf vf3 v1 80)
|
|
(ftoi.vf vf12 vf4)
|
|
(s.vf vf4 v1 112)
|
|
(sub.vf.xyz vf5 vf5 packed-bias)
|
|
(s.vf vf9 v1)
|
|
(sub.vf.xyz vf6 vf6 packed-bias)
|
|
(s.vf vf10 v1 32)
|
|
(sub.vf.xyz vf7 vf7 packed-bias)
|
|
(s.vf vf11 v1 64)
|
|
(sub.vf.xyz vf8 vf8 packed-bias)
|
|
(s.vf vf12 v1 96)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(b.le a0 r0 unpack-done :delay (madda.x.vf matrix-x vf5))
|
|
(madda.y.vf matrix-y vf5)
|
|
(nop!)
|
|
(madd.z.vf vf5 matrix-z vf5)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf6)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf6)
|
|
(nop!)
|
|
(madd.z.vf vf6 matrix-z vf6)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf7)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf7)
|
|
(nop!)
|
|
(madd.z.vf vf7 matrix-z vf7)
|
|
(add.i v1 v1 256)
|
|
(mula.w.vf matrix-t vf0)
|
|
(lqi.vf.xyz vf1 vi1)
|
|
(madda.x.vf matrix-x vf8)
|
|
(lqi.vf.xyz vf2 vi1)
|
|
(madda.y.vf matrix-y vf8)
|
|
(lqi.vf.xyz vf3 vi1)
|
|
(madd.z.vf vf8 matrix-z vf8)
|
|
(lqi.vf.xyz vf4 vi1)
|
|
(ftoi.vf vf9 vf5)
|
|
(s.vf vf5 v1 -112)
|
|
(ftoi.vf vf10 vf6)
|
|
(s.vf vf6 v1 -80)
|
|
(ftoi.vf vf11 vf7)
|
|
(s.vf vf7 v1 -48)
|
|
(ftoi.vf vf12 vf8)
|
|
(s.vf vf8 v1 -16)
|
|
(add.i a0 a0 -4)
|
|
(s.vf vf9 v1 -128)
|
|
(nop!)
|
|
(s.vf vf10 v1 -96)
|
|
(nop!)
|
|
(s.vf vf11 v1 -64)
|
|
(b.le a0 r0 unpack-done :delay (s.vf vf12 v1 -32))
|
|
;; Steady state: consume four, transform them, and overlap the next four VU0 loads.
|
|
(label unpack-instance-loop)
|
|
(sub.vf.xyz vf1 vf1 packed-bias)
|
|
(lqi.vf.xyz vf5 vi1)
|
|
(sub.vf.xyz vf2 vf2 packed-bias)
|
|
(lqi.vf.xyz vf6 vi1)
|
|
(sub.vf.xyz vf3 vf3 packed-bias)
|
|
(lqi.vf.xyz vf7 vi1)
|
|
(sub.vf.xyz vf4 vf4 packed-bias)
|
|
(lqi.vf.xyz vf8 vi1)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf1)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf1)
|
|
(nop!)
|
|
(madd.z.vf vf1 matrix-z vf1)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf2)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf2)
|
|
(nop!)
|
|
(madd.z.vf vf2 matrix-z vf2)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf3)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf3)
|
|
(nop!)
|
|
(madd.z.vf vf3 matrix-z vf3)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf4)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf4)
|
|
(nop!)
|
|
(madd.z.vf vf4 matrix-z vf4)
|
|
(nop!)
|
|
(ftoi.vf vf9 vf1)
|
|
(s.vf vf1 v1 16)
|
|
(ftoi.vf vf10 vf2)
|
|
(s.vf vf2 v1 48)
|
|
(ftoi.vf vf11 vf3)
|
|
(s.vf vf3 v1 80)
|
|
(ftoi.vf vf12 vf4)
|
|
(s.vf vf4 v1 112)
|
|
(sub.vf.xyz vf5 vf5 packed-bias)
|
|
(s.vf vf9 v1)
|
|
(sub.vf.xyz vf6 vf6 packed-bias)
|
|
(s.vf vf10 v1 32)
|
|
(sub.vf.xyz vf7 vf7 packed-bias)
|
|
(s.vf vf11 v1 64)
|
|
(sub.vf.xyz vf8 vf8 packed-bias)
|
|
(s.vf vf12 v1 96)
|
|
(add.i a0 a0 -4)
|
|
(mula.w.vf matrix-t vf0)
|
|
(b.le a0 r0 finish-instance-tail :delay (madda.x.vf matrix-x vf5))
|
|
(madda.y.vf matrix-y vf5)
|
|
(nop!)
|
|
(madd.z.vf vf5 matrix-z vf5)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf6)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf6)
|
|
(nop!)
|
|
(madd.z.vf vf6 matrix-z vf6)
|
|
(nop!)
|
|
(mula.w.vf matrix-t vf0)
|
|
(nop!)
|
|
(madda.x.vf matrix-x vf7)
|
|
(nop!)
|
|
(madda.y.vf matrix-y vf7)
|
|
(nop!)
|
|
(madd.z.vf vf7 matrix-z vf7)
|
|
(add.i v1 v1 256)
|
|
(mula.w.vf matrix-t vf0)
|
|
(lqi.vf.xyz vf1 vi1)
|
|
(madda.x.vf matrix-x vf8)
|
|
(lqi.vf.xyz vf2 vi1)
|
|
(madda.y.vf matrix-y vf8)
|
|
(lqi.vf.xyz vf3 vi1)
|
|
(madd.z.vf vf8 matrix-z vf8)
|
|
(lqi.vf.xyz vf4 vi1)
|
|
(ftoi.vf vf9 vf5)
|
|
(s.vf vf5 v1 -112)
|
|
(ftoi.vf vf10 vf6)
|
|
(s.vf vf6 v1 -80)
|
|
(ftoi.vf vf11 vf7)
|
|
(s.vf vf7 v1 -48)
|
|
(ftoi.vf vf12 vf8)
|
|
(s.vf vf8 v1 -16)
|
|
(nop!)
|
|
(s.vf vf9 v1 -128)
|
|
(add.i a0 a0 -4)
|
|
(s.vf vf10 v1 -96)
|
|
(nop!)
|
|
(s.vf vf11 v1 -64)
|
|
(b.gt a0 r0 unpack-instance-loop :delay (s.vf vf12 v1 -32))
|
|
(label finish-instance-tail)
|
|
(b unpack-done :delay (nop!))
|
|
;; Uninstanced fragments need only exponent-bias removal; eight vertices are converted and
|
|
;; stored per loop iteration.
|
|
(label unpack-uninstanced)
|
|
(lui v1 #x7000)
|
|
(l.vf mesh-base a1 12)
|
|
(vmove.xyzw vf1 vf0)
|
|
(l.vf packed-bias a0)
|
|
(vmove.xyzw vf2 vf0)
|
|
(l.bu a0 a1 24)
|
|
(m vi1 a3)
|
|
(vmove.xyzw vf3 vf0)
|
|
(itof.vf mesh-base mesh-base)
|
|
(vmove.xyzw vf4 vf0)
|
|
(nop!)
|
|
(vmove.xyzw vf5 vf0)
|
|
(nop!)
|
|
(vmove.xyzw vf6 vf0)
|
|
(nop!)
|
|
(vmove.xyzw vf7 vf0)
|
|
(sub.vf packed-bias packed-bias mesh-base)
|
|
(vmove.xyzw vf8 vf0)
|
|
(label unpack-uninstanced-loop)
|
|
(nop!)
|
|
(lqi.vf.xyz vf1 vi1)
|
|
(nop!)
|
|
(lqi.vf.xyz vf2 vi1)
|
|
(nop!)
|
|
(lqi.vf.xyz vf3 vi1)
|
|
(add.i v1 v1 256)
|
|
(lqi.vf.xyz vf4 vi1)
|
|
(sub.vf.xyz vf1 vf1 packed-bias)
|
|
(lqi.vf.xyz vf5 vi1)
|
|
(sub.vf.xyz vf2 vf2 packed-bias)
|
|
(lqi.vf.xyz vf6 vi1)
|
|
(sub.vf.xyz vf3 vf3 packed-bias)
|
|
(lqi.vf.xyz vf7 vi1)
|
|
(sub.vf.xyz vf4 vf4 packed-bias)
|
|
(lqi.vf.xyz vf8 vi1)
|
|
(ftoi.vf vf9 vf1)
|
|
(s.vf vf1 v1 -240)
|
|
(ftoi.vf vf10 vf2)
|
|
(s.vf vf2 v1 -208)
|
|
(ftoi.vf vf11 vf3)
|
|
(s.vf vf3 v1 -176)
|
|
(ftoi.vf vf12 vf4)
|
|
(s.vf vf4 v1 -144)
|
|
(sub.vf.xyz vf5 vf5 packed-bias)
|
|
(s.vf vf9 v1 -256)
|
|
(sub.vf.xyz vf6 vf6 packed-bias)
|
|
(s.vf vf10 v1 -224)
|
|
(sub.vf.xyz vf7 vf7 packed-bias)
|
|
(s.vf vf11 v1 -192)
|
|
(sub.vf.xyz vf8 vf8 packed-bias)
|
|
(s.vf vf12 v1 -160)
|
|
(ftoi.vf vf9 vf5)
|
|
(s.vf vf5 v1 -112)
|
|
(ftoi.vf vf10 vf6)
|
|
(s.vf vf6 v1 -80)
|
|
(ftoi.vf vf11 vf7)
|
|
(s.vf vf7 v1 -48)
|
|
(ftoi.vf vf12 vf8)
|
|
(s.vf vf8 v1 -16)
|
|
(nop!)
|
|
(s.vf vf9 v1 -128)
|
|
(add.i a0 a0 -8)
|
|
(s.vf vf10 v1 -96)
|
|
(nop!)
|
|
(s.vf vf11 v1 -64)
|
|
(b.gt a0 r0 unpack-uninstanced-loop :delay (s.vf vf12 v1 -32))
|
|
(label unpack-done)
|
|
(m v0 r0)
|
|
(l.d fp sp 8)
|
|
(jr ra :delay (add.i sp sp 16))
|
|
(nop! :count 2)
|
|
(asm-data (label collide-packed-vertex-bias) (word #x4d000000 #x4d000000 #x4d000000 0)))))
|
|
|
|
(#unless PC_PORT
|
|
(defmethod load-mesh-from-spad-in-line-sphere ((cache collide-cache) (mesh collide-frag-mesh))
|
|
"Rotate scratchpad vertices into the line-sphere frame, then append triangles whose rotated
|
|
integer bounds overlap collide-work.collide-box4w."
|
|
(rlet ((cache-reg :reg gp :type collide-cache)
|
|
(mesh-reg :reg s5 :type collide-frag-mesh))
|
|
(add.i sp sp -112)
|
|
(s.d ra sp)
|
|
(s.d fp sp 8)
|
|
(m fp t9)
|
|
(s.q s1 sp 16)
|
|
(s.q s2 sp 32)
|
|
(s.q s3 sp 48)
|
|
(s.q s4 sp 64)
|
|
(s.q s5 sp 80)
|
|
(s.q gp sp 96)
|
|
(m cache-reg a0)
|
|
(m mesh-reg a1)
|
|
;; Method slot 29 builds the integer bank at scratchpad+0x1000.
|
|
(m a0 cache-reg)
|
|
(l.wu v1 a0 -4)
|
|
(l.wu t9 v1 132)
|
|
(m a1 mesh-reg)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0)
|
|
(nop!)
|
|
(m! t0 *collide-work*)
|
|
(add.i v1 r0 460)
|
|
(l.wu a0 cache-reg)
|
|
(sub a2 v1 a0)
|
|
(sll a1 a0 6)
|
|
(b.lt a2 r0 line-cache-full :delay (m a2 cache-reg))
|
|
(nop!)
|
|
(l.bu t1 mesh-reg 25)
|
|
(add.i a2 a2 #x132c)
|
|
(l.wu a3 mesh-reg)
|
|
(sll t1 t1 4)
|
|
(l.hu t2 mesh-reg 8)
|
|
(add a1 a2 a1)
|
|
(l.q a2 t0 16)
|
|
(add a3 a3 t1)
|
|
(l.q t0 t0 32)
|
|
(nop!)
|
|
(l.wu t1 mesh-reg 4)
|
|
(add t2 a3 t2)
|
|
(l.wu t3 cache-reg 8)
|
|
(label line-next-strip)
|
|
(lui t4 #x7000)
|
|
(l.b t6 a3)
|
|
(nop!)
|
|
(l.b t7 a3 1)
|
|
(b.lt t6 r0 line-finish-strip :delay (l.b t5 a3 2))
|
|
(sll t6 t6 5)
|
|
(sll t7 t7 5)
|
|
(sll t8 t5 5)
|
|
(add t5 t6 t4)
|
|
(add t6 t7 t4)
|
|
(l.q t7 t5 #x1000)
|
|
(add t9 t8 t4)
|
|
(l.q t8 t6 #x1000)
|
|
(min.w s4 t7 t8)
|
|
(l.q ra t9 #x1000)
|
|
(max.w s5 t7 t8)
|
|
(mmi-nop!)
|
|
(min.w s4 s4 ra)
|
|
(mmi-nop!)
|
|
(max.w s5 s5 ra)
|
|
(mmi-nop!)
|
|
(pcgt.w s4 s4 t0)
|
|
(mmi-nop!)
|
|
(pcgt.w s5 a2 s5)
|
|
(mmi-nop!)
|
|
(or.q s4 s4 s5)
|
|
(l.bu s5 t2)
|
|
(ppach s4 r0 s4)
|
|
(mmi-nop!)
|
|
(sll s4 s4 16)
|
|
(sll s5 s5 2)
|
|
(b.nz s4 line-advance-triangle :delay (add s5 s5 t1))
|
|
(b.eq a0 v1 line-cache-full :delay (l.wu s5 s5))
|
|
(and s4 s5 t3)
|
|
(nop!)
|
|
(b.nz s4 line-advance-triangle :delay (nop!))
|
|
(nop!)
|
|
;; Bounds use the rotated integer bank, but accepted triangles retain their original
|
|
;; world-space floating vertices from record+16.
|
|
(s.q r0 a1 48)
|
|
(add.i a0 a0 1)
|
|
(s.w s5 a1 48)
|
|
(add.i a1 a1 64)
|
|
(l.q s5 t5 16)
|
|
(nop!)
|
|
(l.q s4 t6 16)
|
|
(nop!)
|
|
(l.q s3 t9 16)
|
|
(nop!)
|
|
(s.q s5 a1 -64)
|
|
(nop!)
|
|
(s.q s4 a1 -48)
|
|
(nop!)
|
|
(s.q s3 a1 -32)
|
|
(label line-advance-triangle)
|
|
(add.i t2 t2 1)
|
|
(add.i a3 a3 3)
|
|
(add.i s5 r0 16)
|
|
(nop!)
|
|
(label line-strip-loop)
|
|
(nop!)
|
|
(l.b s4 a3)
|
|
(add.i a3 a3 1)
|
|
(nop!)
|
|
(b.z s4 line-next-strip :delay (nop!))
|
|
(b.ltl s4 r0 line-negative-index :delay (sub s4 r0 s4))
|
|
(m.q t7 t8)
|
|
(m t5 t6)
|
|
(sub s5 r0 s5)
|
|
(nop!)
|
|
(label line-negative-index)
|
|
(add.i s4 s4 -1)
|
|
(m t6 t9)
|
|
(m.q t8 ra)
|
|
(sll t9 s4 5)
|
|
(add t9 t9 t4)
|
|
(l.bu s4 t2)
|
|
(min.w s2 t7 t8)
|
|
(l.q ra t9 #x1000)
|
|
(max.w s3 t7 t8)
|
|
(mmi-nop!)
|
|
(min.w s2 s2 ra)
|
|
(mmi-nop!)
|
|
(max.w s3 s3 ra)
|
|
(mmi-nop!)
|
|
(pcgt.w s2 s2 t0)
|
|
(mmi-nop!)
|
|
(pcgt.w s3 a2 s3)
|
|
(mmi-nop!)
|
|
(or.q s3 s2 s3)
|
|
(mmi-nop!)
|
|
(ppach s3 r0 s3)
|
|
(mmi-nop!)
|
|
(sll s3 s3 16)
|
|
(sll s4 s4 2)
|
|
(b.nz s3 line-strip-loop :delay (add.i t2 t2 1))
|
|
(add s4 s4 t1)
|
|
(nop! :count 2)
|
|
(l.wu s4 s4)
|
|
(and s3 s4 t3)
|
|
(nop!)
|
|
(b.nz s3 line-strip-loop :delay (nop!))
|
|
(b.eq a0 v1 line-cache-full :delay (nop!))
|
|
(nop!)
|
|
(s.q r0 a1 48)
|
|
(add.i a0 a0 1)
|
|
(s.w s4 a1 48)
|
|
(add.i s2 a1 16)
|
|
(l.q s1 t6 16)
|
|
(add.i a1 a1 64)
|
|
(l.q s4 t5 16)
|
|
(nop!)
|
|
(l.q s3 t9 16)
|
|
(nop!)
|
|
(s.q s1 s2)
|
|
(sub s1 s2 s5)
|
|
(add s2 s2 s5)
|
|
(nop!)
|
|
(s.q s4 s1)
|
|
(b line-strip-loop :delay (s.q s3 s2))
|
|
(label line-finish-strip)
|
|
(nop!)
|
|
(s.w a0 cache-reg)
|
|
(b line-import-return :delay (nop!))
|
|
(label line-cache-full)
|
|
(nop!)
|
|
(s.w v1 cache-reg)
|
|
(m! v1 *already-printed-exeeded-max-cache-tris*)
|
|
(b.ne s7 v1 line-skip-warning :delay (m v1 s7))
|
|
(add.i v1 s7 #t)
|
|
(set! *already-printed-exeeded-max-cache-tris* v1)
|
|
(add.i v1 s7 debug)
|
|
(m! a0 *cheat-mode*)
|
|
(b.ne a0 v1 line-skip-warning :delay (m v1 s7))
|
|
(m! t9 format)
|
|
(m! a0 *stdcon*)
|
|
(add.i a1 fp L305)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0)
|
|
(nop!)
|
|
(label line-skip-warning)
|
|
(b line-import-return :delay (nop!))
|
|
(label line-import-return)
|
|
(m v0 r0)
|
|
(l.d ra sp)
|
|
(l.d fp sp 8)
|
|
(l.q gp sp 96)
|
|
(l.q s5 sp 80)
|
|
(l.q s4 sp 64)
|
|
(l.q s3 sp 48)
|
|
(l.q s2 sp 32)
|
|
(l.q s1 sp 16)
|
|
(jr ra :delay (add.i sp sp 112))
|
|
(nop! :count 3))))
|
|
|
|
(#unless PC_PORT
|
|
(defmethod load-mesh-from-spad-in-y-probe ((cache collide-cache) (mesh collide-frag-mesh))
|
|
"Append scratchpad triangles which overlap the active vertical-probe box."
|
|
(rlet ((cache-reg :reg a0 :type collide-cache)
|
|
(mesh-reg :reg a1 :type collide-frag-mesh))
|
|
(import-spad-triangles-in-query-box))))
|
|
|
|
(#unless PC_PORT
|
|
;; collide-cache is BASIC, so an EE pointer is four bytes past the allocation's type word.
|
|
(defconstant COLLIDE-CACHE-BASIC-BIAS 4)
|
|
(defconstant COLLIDE-CACHE-TRIS (- (offset-of collide-cache tris) COLLIDE-CACHE-BASIC-BIAS)) ;; 4908
|
|
(defconstant COLLIDE-CACHE-TRI-STRIDE (type-size collide-cache-tri)) ;; 64
|
|
(defconstant COLLIDE-PUSS-SPHERE-STRIDE (type-size collide-puss-sphere)) ;; 48
|
|
(defconstant COLLIDE-PUSS-FOUR-SPHERE-STRIDE (* 4 COLLIDE-PUSS-SPHERE-STRIDE)) ;; 192
|
|
;; A successful sphere hit is represented by a small triangle in its tangent plane. These
|
|
;; one-meter offsets are rotated into the contact basis and translated to the contact point.
|
|
(asm-data (label collide-cache-sphere-contact-triangle)
|
|
(word #x00000000 #x45800000 #x00000000 #x3f800000)
|
|
(word #x00000000 #xc5800000 #x45800000 #x3f800000)
|
|
(word #x00000000 #xc5800000 #xc5800000 #x3f800000)
|
|
(label collide-cache-default-best-u)
|
|
(word #x40000000) ;; 2.0
|
|
(label collide-cache-miss)
|
|
(word #xccbebc20)) ;; -100000000.0
|
|
(defmethod check-sphere-prim-against-spheres ((this collide-puss-work) (sphere-prim collide-cache-prim) (params collide-using-spheres-params))
|
|
"Return true when sphere-prim overlaps any query sphere."
|
|
(declare (asm-func symbol))
|
|
(rlet ((work :reg a0 :type collide-puss-work)
|
|
(prim :reg a1 :type collide-cache-prim)
|
|
(params-reg :reg a2 :type collide-using-spheres-params)
|
|
(sphere-count :reg v1)
|
|
(prim-sphere :reg vf1))
|
|
;; Reject the primitive against the union of all query-sphere boxes before entering the
|
|
;; four-at-a-time distance loop. The speculative four-sphere loads are safe because the work
|
|
;; area has fixed storage for 64 records.
|
|
(asm-block reject-union-box
|
|
(nop! :count 2)
|
|
(l.wu.field sphere-count params-reg (num-spheres))
|
|
(add.i params-reg work (offset-of collide-puss-work spheres))
|
|
(l.vf prim-sphere prim (offset-of collide-cache-prim world-sphere))
|
|
(b.z sphere-count no-hit :delay (l.q a1 work (offset-of collide-puss-work spheres-bbox4w min)))))
|
|
(rlet ((work :reg a0 :type collide-puss-work)
|
|
(tested-count :reg a0)
|
|
(sphere-cursor :reg a2 :type collide-puss-sphere)
|
|
(sphere-count :reg v1)
|
|
(union-min :reg a1 :class i128)
|
|
(union-max :reg a3 :class i128)
|
|
(prim-min :reg vf2)
|
|
(prim-max :reg vf3)
|
|
(zero :reg vf4)
|
|
(prim-sphere :reg vf1)
|
|
(sphere-0 :reg vf5)
|
|
(sphere-1 :reg vf6)
|
|
(sphere-2 :reg vf7)
|
|
(sphere-3 :reg vf8)
|
|
(delta-0 :reg vf9)
|
|
(delta-1 :reg vf10)
|
|
(delta-2 :reg vf11)
|
|
(delta-3 :reg vf12))
|
|
(asm-block prepare-four-sphere-loop
|
|
(max.w.vf zero vf0 vf0)
|
|
(l.q union-max work (offset-of collide-puss-work spheres-bbox4w max))
|
|
(sub.w.vf.xyz prim-min prim-sphere prim-sphere)
|
|
(m tested-count r0)
|
|
(add.w.vf.xyz prim-max prim-sphere prim-sphere)
|
|
(l.vf sphere-0 sphere-cursor (offset-of collide-puss-sphere bsphere))
|
|
(ftoi.vf prim-min prim-min)
|
|
(l.vf sphere-1 sphere-cursor COLLIDE-PUSS-SPHERE-STRIDE)
|
|
(ftoi.vf prim-max prim-max)
|
|
(l.vf sphere-2 sphere-cursor (* 2 COLLIDE-PUSS-SPHERE-STRIDE))
|
|
(nop!)
|
|
;; Negating the stored radius in w makes delta.w carry the combined-radius term used below.
|
|
(sub.w.vf.w prim-sphere vf0 prim-sphere)
|
|
(m t0 prim-min)
|
|
(l.vf sphere-3 sphere-cursor (* 3 COLLIDE-PUSS-SPHERE-STRIDE))
|
|
(m t1 prim-max)
|
|
(nop!)
|
|
(pcgt.w union-min union-min t1)
|
|
(mmi-nop!)
|
|
(pcgt.w union-max t0 union-max)
|
|
(mmi-nop!)
|
|
(or.q union-min union-min union-max)
|
|
(mmi-nop!)
|
|
(ppach union-min r0 union-min)
|
|
(mmi-nop!)
|
|
(sll union-min union-min 16)
|
|
(nop!)
|
|
(b.nz union-min no-hit :delay (nop!)))
|
|
;; Each VU expression leaves distance-squared minus combined-radius-squared in w. Moving the
|
|
;; vector to an EE register therefore makes a signed <= 0 test sufficient for overlap.
|
|
(asm-block test-four-spheres
|
|
(label next-four)
|
|
(sub.vf delta-0 sphere-0 prim-sphere)
|
|
(add.i sphere-cursor sphere-cursor COLLIDE-PUSS-FOUR-SPHERE-STRIDE)
|
|
(sub.vf delta-1 sphere-1 prim-sphere)
|
|
(l.vf sphere-0 sphere-cursor (offset-of collide-puss-sphere bsphere))
|
|
(sub.vf delta-2 sphere-2 prim-sphere)
|
|
(l.vf sphere-1 sphere-cursor COLLIDE-PUSS-SPHERE-STRIDE)
|
|
(sub.vf delta-3 sphere-3 prim-sphere)
|
|
(l.vf sphere-2 sphere-cursor (* 2 COLLIDE-PUSS-SPHERE-STRIDE))
|
|
(mul.vf delta-0 delta-0 delta-0)
|
|
(l.vf sphere-3 sphere-cursor (* 3 COLLIDE-PUSS-SPHERE-STRIDE))
|
|
(mul.vf delta-1 delta-1 delta-1)
|
|
(nop!)
|
|
(mul.vf delta-2 delta-2 delta-2)
|
|
(nop!)
|
|
(mul.vf delta-3 delta-3 delta-3)
|
|
(nop!)
|
|
(mula.x.vf zero delta-0)
|
|
(nop!)
|
|
(madda.y.vf zero delta-0)
|
|
(nop!)
|
|
(madda.z.vf zero delta-0)
|
|
(nop!)
|
|
(msub.w.vf delta-0 zero delta-0)
|
|
(nop!)
|
|
(mula.x.vf zero delta-1)
|
|
(nop!)
|
|
(madda.y.vf zero delta-1)
|
|
(nop!)
|
|
(madda.z.vf zero delta-1)
|
|
(nop!)
|
|
(msub.w.vf delta-1 zero delta-1)
|
|
(nop!)
|
|
(m a1 delta-0)
|
|
(add.i tested-count tested-count 1)
|
|
(b.le a1 r0 hit :delay (mula.x.vf zero delta-2))
|
|
(b.eq tested-count sphere-count no-hit :delay (madda.y.vf zero delta-2))
|
|
(madda.z.vf zero delta-2)
|
|
(nop!)
|
|
(msub.w.vf delta-2 zero delta-2)
|
|
(nop!)
|
|
(m a1 delta-1)
|
|
(add.i tested-count tested-count 1)
|
|
(b.le a1 r0 hit :delay (mula.x.vf zero delta-3))
|
|
(b.eq tested-count sphere-count no-hit :delay (madda.y.vf zero delta-3))
|
|
(madda.z.vf zero delta-3)
|
|
(nop!)
|
|
(msub.w.vf delta-3 zero delta-3)
|
|
(nop!)
|
|
(m a1 delta-2)
|
|
(add.i tested-count tested-count 1)
|
|
(b.le a1 r0 hit :delay (nop!))
|
|
(b.eq tested-count sphere-count no-hit :delay (nop!))
|
|
(m a1 delta-3)
|
|
(add.i tested-count tested-count 1)
|
|
(b.le a1 r0 hit :delay (nop!))
|
|
(b.ne tested-count sphere-count next-four :delay (nop!))
|
|
(b no-hit :delay (nop!)))
|
|
(asm-block return-result
|
|
(label hit)
|
|
(add.i v1 s7 #t)
|
|
(m v0 v1)
|
|
(b done-sphere-test :delay (nop!))
|
|
(label no-hit)
|
|
(m v0 s7)
|
|
(b done-sphere-test :delay (nop!))
|
|
(m v0 r0)
|
|
(label done-sphere-test)
|
|
(jr ra :delay (add sp sp r0))
|
|
(nop! :count 2))))
|
|
(defmethod check-mesh-prim-against-spheres ((this collide-puss-work) (mesh-prim collide-cache-prim) (params collide-using-spheres-params))
|
|
"Return true when any query sphere overlaps a triangle in mesh-prim. Cache each candidate
|
|
triangle's box and unit normal in this while testing its spheres."
|
|
(declare (asm-func symbol))
|
|
(rlet ((work :reg gp :type collide-puss-work)
|
|
(params-reg :reg s5 :type collide-using-spheres-params)
|
|
(tri-cursor :reg s3 :type collide-cache-tri)
|
|
(tri-count :reg s4)
|
|
(sphere-cursor :reg s2 :type collide-puss-sphere)
|
|
(sphere-count :reg s1)
|
|
(sphere-index :reg s0)
|
|
(vertex-a :reg vf1)
|
|
(vertex-b :reg vf2)
|
|
(vertex-c :reg vf3)
|
|
(edge-ab :reg vf4)
|
|
(edge-ac :reg vf5)
|
|
(tri-min :reg vf6)
|
|
(tri-max :reg vf7)
|
|
(tri-normal :reg vf8)
|
|
(normal-length-squared :reg vf9)
|
|
(closest-point :reg vf10)
|
|
(query-sphere :reg vf11)
|
|
(distance-squared :reg vf9)
|
|
(Q :reg Q))
|
|
(asm-block save-state
|
|
(add.i sp sp -128)
|
|
(s.d ra sp)
|
|
(s.q s0 sp 16)
|
|
(s.q s1 sp 32)
|
|
(s.q s2 sp 48)
|
|
(s.q s3 sp 64)
|
|
(s.q s4 sp 80)
|
|
(s.q s5 sp 96)
|
|
(s.q gp sp 112)
|
|
(m work a0)
|
|
(m params-reg a2)
|
|
(nop!))
|
|
(rlet ((prim :reg a1 :type collide-cache-prim)
|
|
(cache :reg a0 :type collide-cache)
|
|
(first-tri :reg v1)
|
|
(first-tri-offset :reg v1))
|
|
(asm-block find-first-triangle
|
|
(l.wu.field cache prim (ccache))
|
|
(nop!)
|
|
(l.hu.field first-tri prim (first-tri))
|
|
(add.i cache cache COLLIDE-CACHE-TRIS)
|
|
(l.hu.field tri-count prim (num-tris))
|
|
(sll first-tri-offset first-tri 6)
|
|
(nop!)
|
|
(add tri-cursor cache first-tri-offset)
|
|
(nop!)))
|
|
;; The union box rejects most triangles. A surviving triangle gets a normalized face normal,
|
|
;; then its own box is compared with each sphere box before the closest-point calculation.
|
|
(asm-block prepare-triangle
|
|
(label next-triangle)
|
|
(b.z tri-count no-mesh-hit :delay (l.vf vertex-a tri-cursor))
|
|
(add.i tri-count tri-count -1)
|
|
(l.vf vertex-b tri-cursor 16)
|
|
(nop!)
|
|
(l.vf vertex-c tri-cursor 32)
|
|
(sub.vf edge-ab vertex-b vertex-a)
|
|
(l.q a1 work (offset-of collide-puss-work spheres-bbox4w min))
|
|
(sub.vf edge-ac vertex-c vertex-a)
|
|
(l.q v1 work (offset-of collide-puss-work spheres-bbox4w max))
|
|
(min.vf tri-min vertex-a vertex-b)
|
|
(nop!)
|
|
(max.vf tri-max vertex-a vertex-b)
|
|
(nop!)
|
|
(outer.product.a.vf acc edge-ab edge-ac)
|
|
(nop!)
|
|
(move.vf tri-normal vf0)
|
|
(nop!)
|
|
(min.vf tri-min tri-min vertex-c)
|
|
(nop!)
|
|
(max.vf tri-max tri-max vertex-c)
|
|
(nop!)
|
|
(outer.product.b.vf tri-normal edge-ac edge-ab acc)
|
|
(nop!)
|
|
(ftoi.vf tri-min tri-min)
|
|
(nop!)
|
|
(ftoi.vf tri-max tri-max)
|
|
(nop!)
|
|
(mul.vf normal-length-squared tri-normal tri-normal)
|
|
(nop!)
|
|
(m a0 tri-min)
|
|
(nop!)
|
|
(m a2 tri-max)
|
|
(nop!)
|
|
(mula.x.vf.w vf0 normal-length-squared)
|
|
(s.vf tri-min work (offset-of collide-puss-work tri-bbox4w min))
|
|
(madda.y.vf.w vf0 normal-length-squared)
|
|
(s.vf tri-max work (offset-of collide-puss-work tri-bbox4w max))
|
|
(madd.z.vf.w normal-length-squared vf0 normal-length-squared)
|
|
(nop!)
|
|
(pcgt.w a1 a1 a2)
|
|
(mmi-nop!)
|
|
(pcgt.w v1 a0 v1)
|
|
(mmi-nop!)
|
|
(or.q v1 a1 v1)
|
|
(mmi-nop!)
|
|
(rsqrt.w.w Q vf0 normal-length-squared)
|
|
(nop!)
|
|
(ppach v1 r0 v1)
|
|
(mmi-nop!)
|
|
(sll v1 v1 16)
|
|
(nop!)
|
|
(b.nzl v1 next-triangle :delay (add.i tri-cursor tri-cursor COLLIDE-CACHE-TRI-STRIDE))
|
|
(waitq)
|
|
(nop!)
|
|
(mulq.vf.xyz tri-normal tri-normal Q)
|
|
(add.i sphere-cursor work (offset-of collide-puss-work spheres))
|
|
(nop!)
|
|
(l.wu.field sphere-count params-reg (num-spheres))
|
|
(m sphere-index r0)
|
|
(s.vf tri-normal work (offset-of collide-puss-work tri-normal)))
|
|
(asm-block test-spheres-against-triangle
|
|
(label next-sphere)
|
|
(b.eql sphere-index sphere-count next-triangle :delay (add.i tri-cursor tri-cursor COLLIDE-CACHE-TRI-STRIDE))
|
|
(add.i sphere-index sphere-index 1)
|
|
(l.q a1 sphere-cursor (offset-of collide-puss-sphere bbox4w min))
|
|
(nop!)
|
|
(l.q a2 work (offset-of collide-puss-work tri-bbox4w max))
|
|
(nop!)
|
|
(l.q v1 sphere-cursor (offset-of collide-puss-sphere bbox4w max))
|
|
(nop!)
|
|
(l.q a0 work (offset-of collide-puss-work tri-bbox4w min))
|
|
(pcgt.w a1 a1 a2)
|
|
(mmi-nop!)
|
|
(pcgt.w v1 a0 v1)
|
|
(mmi-nop!)
|
|
(or.q v1 a1 v1)
|
|
(mmi-nop!)
|
|
(ppach v1 r0 v1)
|
|
(mmi-nop!)
|
|
(sll v1 v1 16)
|
|
(nop!)
|
|
(b.nzl v1 next-sphere :delay (add.i sphere-cursor sphere-cursor COLLIDE-PUSS-SPHERE-STRIDE))
|
|
(m! t9 closest-pt-in-triangle)
|
|
(m a0 work)
|
|
(m a1 sphere-cursor)
|
|
(m a2 tri-cursor)
|
|
(add.i a3 work (offset-of collide-puss-work tri-normal))
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(l.vf closest-point work (offset-of collide-puss-work closest-pt))
|
|
(l.vf query-sphere sphere-cursor (offset-of collide-puss-sphere bsphere))
|
|
(add.i sphere-cursor sphere-cursor COLLIDE-PUSS-SPHERE-STRIDE)
|
|
(sub.vf.xyz distance-squared closest-point query-sphere)
|
|
;; Put radius squared in w while leaving the sphere center's other lanes untouched.
|
|
(mul.w.vf query-sphere query-sphere query-sphere)
|
|
(mul.vf distance-squared distance-squared distance-squared)
|
|
(mula.x.vf.w vf0 distance-squared)
|
|
(madda.y.vf.w vf0 distance-squared)
|
|
(madd.z.vf.w distance-squared vf0 distance-squared)
|
|
(sub.w.vf distance-squared distance-squared query-sphere)
|
|
(m v1 distance-squared)
|
|
;; The signed distance result is in w, so move its upper doubleword down before branching.
|
|
(pcpyud v1 v1 v1)
|
|
(b.gtl v1 r0 next-sphere :delay (nop!))
|
|
(add.i v1 s7 #t)
|
|
(m v0 v1)
|
|
(b finish-mesh-sphere-test :delay (nop!)))
|
|
(asm-block return-mesh-result
|
|
(label no-mesh-hit)
|
|
(m v0 s7)
|
|
(b finish-mesh-sphere-test :delay (nop!))
|
|
(m v0 r0)
|
|
(label finish-mesh-sphere-test)
|
|
(l.d ra sp)
|
|
(l.q gp sp 112)
|
|
(l.q s5 sp 96)
|
|
(l.q s4 sp 80)
|
|
(l.q s3 sp 64)
|
|
(l.q s2 sp 48)
|
|
(l.q s1 sp 32)
|
|
(l.q s0 sp 16)
|
|
(jr ra :delay (add.i sp sp 128))
|
|
(nop! :count 3))))
|
|
(defmethod resolve-moving-sphere-tri ((this collide-cache-prim) (result collide-tri-result) (moving-sphere collide-prim-core) (move vector) (best-u float) (action collide-action))
|
|
"Sweep moving-sphere against this cached primitive's triangles. Keep the nearest compatible
|
|
hit before best-u, update result, and return its fraction or COLLISION_MISS."
|
|
(declare (asm-func float))
|
|
(rlet ((function-base :reg fp)
|
|
(result-reg :reg gp :type collide-tri-result)
|
|
(sphere-reg :reg s5 :type collide-prim-core)
|
|
(move-reg :reg s4 :type vector)
|
|
(work :reg s3 :type lsmi-work)
|
|
(tri-cursor :reg s2 :type collide-cache-tri)
|
|
(remaining :reg s1)
|
|
(zero :reg f0)
|
|
(current-best :reg f1)
|
|
(candidate :reg f2)
|
|
(facing :reg f3)
|
|
(side :reg f4)
|
|
(move-vf :reg vf1)
|
|
(hit-normal :reg vf2)
|
|
(hit-point :reg vf3)
|
|
(sphere-center :reg vf4)
|
|
(move-dot-normal :reg vf5)
|
|
(side-dot-normal :reg vf6)
|
|
(center-to-hit :reg vf7)
|
|
(vertex-a :reg vf8)
|
|
(vertex-b :reg vf9)
|
|
(vertex-c :reg vf10))
|
|
(asm-block save-state-and-find-triangles
|
|
(add.i sp sp -224)
|
|
(s.d ra sp)
|
|
(s.d function-base sp 8)
|
|
(m function-base t9)
|
|
(s.q s1 sp 128)
|
|
(s.q s2 sp 144)
|
|
(s.q s3 sp 160)
|
|
(s.q s4 sp 176)
|
|
(s.q s5 sp 192)
|
|
(s.q gp sp 208)
|
|
(m result-reg a1)
|
|
(m sphere-reg a2)
|
|
(m move-reg a3)
|
|
(add.i work sp 16)
|
|
(nop!)
|
|
(m zero r0)
|
|
(s.w.field t1 work (action))
|
|
(m current-best t0)
|
|
(l.hu a1 a0 (offset-of collide-cache-prim first-tri))
|
|
(nop!)
|
|
(l.wu v1 a0 (offset-of collide-cache-prim ccache))
|
|
(c.le.s zero current-best)
|
|
(sll a1 a1 6)
|
|
(b.fpt best-ready :delay (add.i v1 v1 COLLIDE-CACHE-TRIS))
|
|
(l.s current-best function-base collide-cache-default-best-u)
|
|
(nop!)
|
|
(label best-ready)
|
|
(add tri-cursor v1 a1)
|
|
(s.s current-best work (offset-of lsmi-work best-u))
|
|
(nop!)
|
|
(l.hu remaining a0 (offset-of collide-cache-prim num-tris))
|
|
(nop!)
|
|
(s.s current-best work (offset-of lsmi-work orig-best-u)))
|
|
;; moving-sphere-triangle-intersect writes the contact point and face normal into the result
|
|
;; workspace embedded in lsmi-work. Negative fractions and contacts no earlier than the best
|
|
;; one already found are discarded.
|
|
(asm-block intersect-triangles
|
|
(label next-cached-triangle)
|
|
(b.z remaining finished-triangles :delay (add.i remaining remaining -1))
|
|
(m! t9 moving-sphere-triangle-intersect)
|
|
(m a0 sphere-reg)
|
|
(m a1 move-reg)
|
|
(l.s zero sphere-reg (offset-of collide-prim-core world-sphere 3))
|
|
(m a2 zero)
|
|
(m a3 tri-cursor)
|
|
(add.i t0 work (offset-of lsmi-work tri-out intersect))
|
|
(add.i t1 work (offset-of lsmi-work tri-out normal))
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0)
|
|
(nop!)
|
|
(m zero r0)
|
|
(l.vf move-vf move-reg)
|
|
(m candidate v1)
|
|
(l.s current-best work (offset-of lsmi-work best-u))
|
|
(c.lt.s candidate zero)
|
|
(l.vf hit-normal work (offset-of lsmi-work tri-out normal))
|
|
(b.fptl next-cached-triangle :delay (add.i tri-cursor tri-cursor COLLIDE-CACHE-TRI-STRIDE))
|
|
(c.le.s current-best candidate)
|
|
(l.vf hit-point work (offset-of lsmi-work tri-out intersect))
|
|
(b.fptl next-cached-triangle :delay (add.i tri-cursor tri-cursor COLLIDE-CACHE-TRI-STRIDE)))
|
|
;; Solid contacts must approach the triangle's front side and start on that side. Non-solid
|
|
;; actions accept the intersection without this one-sided test.
|
|
(asm-block check-one-sided-contact
|
|
(mul.vf move-dot-normal move-vf hit-normal)
|
|
(l.vf sphere-center sphere-reg (offset-of collide-prim-core world-sphere))
|
|
(nop!)
|
|
(l.wu v1 work (offset-of lsmi-work action))
|
|
(sub.vf center-to-hit sphere-center hit-point)
|
|
(and.i v1 v1 1)
|
|
(b.z v1 save-triangle :delay (add.y.vf.x move-dot-normal move-dot-normal move-dot-normal))
|
|
(mul.vf side-dot-normal center-to-hit hit-normal)
|
|
(nop!)
|
|
(add.z.vf.x move-dot-normal move-dot-normal move-dot-normal)
|
|
(nop!)
|
|
(add.y.vf.x side-dot-normal side-dot-normal side-dot-normal)
|
|
(nop!)
|
|
(m v1 move-dot-normal)
|
|
(nop!)
|
|
(m facing v1)
|
|
(nop!)
|
|
(c.le.s zero facing)
|
|
(nop!)
|
|
(b.fptl next-cached-triangle :delay (add.i tri-cursor tri-cursor COLLIDE-CACHE-TRI-STRIDE))
|
|
(add.z.vf.x side-dot-normal side-dot-normal side-dot-normal)
|
|
(nop!)
|
|
(m v1 side-dot-normal)
|
|
(nop!)
|
|
(m side v1)
|
|
(nop!)
|
|
(c.lt.s side zero)
|
|
(nop!)
|
|
(b.fptl next-cached-triangle :delay (add.i tri-cursor tri-cursor COLLIDE-CACHE-TRI-STRIDE)))
|
|
(asm-block save-triangle-result
|
|
(label save-triangle)
|
|
(l.vf vertex-a tri-cursor (offset-of collide-cache-tri vertex 0))
|
|
(l.vf vertex-b tri-cursor (offset-of collide-cache-tri vertex 1))
|
|
(l.vf vertex-c tri-cursor (offset-of collide-cache-tri vertex 2))
|
|
(l.wu v1 tri-cursor (offset-of collide-cache-tri pat))
|
|
(s.s candidate work (offset-of lsmi-work best-u))
|
|
(s.vf hit-point result-reg (offset-of collide-tri-result intersect))
|
|
(s.vf hit-normal result-reg (offset-of collide-tri-result normal))
|
|
(s.vf vertex-a result-reg (offset-of collide-tri-result vertex 0))
|
|
(s.vf vertex-b result-reg (offset-of collide-tri-result vertex 1))
|
|
(s.vf vertex-c result-reg (offset-of collide-tri-result vertex 2))
|
|
(s.w v1 result-reg (offset-of collide-tri-result pat))
|
|
(b next-cached-triangle :delay (add.i tri-cursor tri-cursor COLLIDE-CACHE-TRI-STRIDE)))
|
|
(asm-block return-triangle-result
|
|
(label finished-triangles)
|
|
(l.s current-best work (offset-of lsmi-work best-u))
|
|
(l.s candidate work (offset-of lsmi-work orig-best-u))
|
|
(c.eq.s current-best candidate)
|
|
(b.fpfl restore-triangle-state :delay (m v0 current-best))
|
|
(l.w v0 function-base collide-cache-miss)
|
|
(label restore-triangle-state)
|
|
(l.d ra sp)
|
|
(l.d function-base sp 8)
|
|
(l.q gp sp 208)
|
|
(l.q s5 sp 192)
|
|
(l.q s4 sp 176)
|
|
(l.q s3 sp 160)
|
|
(l.q s2 sp 144)
|
|
(l.q s1 sp 128)
|
|
(jr ra :delay (add.i sp sp 224))
|
|
(nop! :count 3))))
|
|
(defmethod resolve-moving-sphere-sphere ((this collide-cache-prim) (result collide-tri-result) (moving-sphere collide-prim-core) (move vector) (best-u float) (action collide-action))
|
|
"Sweep moving-sphere against this cached sphere primitive. Keep a compatible hit before best-u,
|
|
write a tangent triangle and contact data to result, and return its fraction or COLLISION_MISS."
|
|
(declare (asm-func float))
|
|
(rlet ((prim :reg s3 :type collide-cache-prim)
|
|
(result-reg :reg gp :type collide-tri-result)
|
|
(move-reg :reg s5 :type vector)
|
|
(best-u-bits :reg s2)
|
|
(action-reg :reg s4)
|
|
(contact-out :reg s1)
|
|
(function-base :reg fp)
|
|
(fraction :reg f3)
|
|
(miss :reg f4)
|
|
(zero :reg f0)
|
|
(fraction-copy :reg f1)
|
|
(best-u-float :reg f2)
|
|
(contact-point :reg vf4)
|
|
(prim-sphere :reg vf5)
|
|
(contact-normal :reg vf1)
|
|
(move-vf :reg vf15)
|
|
(facing-products :reg vf16)
|
|
(normal-length-squared :reg vf12)
|
|
(absolute-normal :reg vf13)
|
|
(basis-length-squared :reg vf14)
|
|
(tangent :reg vf2)
|
|
(bitangent :reg vf3)
|
|
(triangle-a :reg vf9)
|
|
(triangle-b :reg vf10)
|
|
(triangle-c :reg vf11)
|
|
(Q :reg Q))
|
|
(asm-block save-state-and-intersect
|
|
(add.i sp sp -128)
|
|
(s.d ra sp)
|
|
(s.d function-base sp 8)
|
|
(m function-base t9)
|
|
(s.q s1 sp 32)
|
|
(s.q s2 sp 48)
|
|
(s.q s3 sp 64)
|
|
(s.q s4 sp 80)
|
|
(s.q s5 sp 96)
|
|
(s.q gp sp 112)
|
|
(m prim a0)
|
|
(m result-reg a1)
|
|
(m move-reg a3)
|
|
(m best-u-bits t0)
|
|
(m action-reg t1)
|
|
(add.i contact-out sp 16)
|
|
(m! t9 moving-sphere-sphere-intersect)
|
|
(m a0 a2)
|
|
(m a1 move-reg)
|
|
(m a2 prim)
|
|
(m a3 contact-out)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m fraction v0)
|
|
(l.s miss function-base collide-cache-miss)
|
|
(m zero r0)
|
|
(l.vf contact-point contact-out)
|
|
(mov.s fraction-copy fraction)
|
|
(l.vf prim-sphere prim (offset-of collide-cache-prim world-sphere))
|
|
(c.lt.s fraction-copy zero)
|
|
(move.vf contact-normal vf0)
|
|
(b.fpt restore-sphere-state :delay (m best-u-float best-u-bits))
|
|
(c.lt.s best-u-float zero)
|
|
(sub.vf.xyz contact-normal contact-point prim-sphere))
|
|
(rlet ((source-prim :reg v1 :type collide-shape-prim-sphere))
|
|
(asm-block reject-late-or-back-contact
|
|
(b.fpt no-best-limit :delay (l.wu source-prim prim (offset-of collide-cache-prim prim)))
|
|
(c.le.s best-u-float fraction-copy)
|
|
(and.i a0 action-reg 1)
|
|
(b.fptl restore-sphere-state :delay (mov.s fraction miss))
|
|
(label no-best-limit)
|
|
(b.z a0 build-sphere-result :delay (l.vf move-vf move-reg))
|
|
(mul.vf facing-products move-vf contact-normal)
|
|
(add.x.vf.y facing-products facing-products facing-products)
|
|
(add.z.vf.y facing-products facing-products facing-products)
|
|
(m a0 facing-products)
|
|
(b.gel a0 r0 restore-sphere-state :delay (mov.s fraction miss))
|
|
(label build-sphere-result)
|
|
(add.i a0 function-base collide-cache-sphere-contact-triangle)
|
|
(nop!)
|
|
(mul.vf normal-length-squared contact-normal contact-normal)
|
|
(s.vf contact-point result-reg (offset-of collide-tri-result intersect))
|
|
(mula.x.vf.w vf0 normal-length-squared)
|
|
(l.vf triangle-a a0)
|
|
(madda.y.vf.w vf0 normal-length-squared)
|
|
(l.vf triangle-b a0 16)
|
|
(madd.z.vf.w normal-length-squared vf0 normal-length-squared)
|
|
(l.vf triangle-c a0 32)
|
|
(rsqrt.w.w Q vf0 normal-length-squared)
|
|
(nop!)
|
|
(waitq)
|
|
(l.wu.field v1 source-prim (pat))
|
|
(mulq.vf.xyz contact-normal contact-normal Q)
|
|
(nop!)
|
|
(mul.vf basis-length-squared contact-normal contact-normal)
|
|
(s.vf contact-normal result-reg (offset-of collide-tri-result normal))
|
|
(abs.vf absolute-normal contact-normal)
|
|
(s.w v1 result-reg (offset-of collide-tri-result pat))
|
|
(move.vf tangent vf0)
|
|
(nop!)
|
|
(add.y.vf.x basis-length-squared basis-length-squared basis-length-squared)
|
|
(m v1 absolute-normal)
|
|
(b.eql v1 r0 tangent-from-z :delay (add.z.vf.x tangent vf0 contact-normal))
|
|
(sub.y.vf.x tangent vf0 contact-normal)
|
|
(nop!)
|
|
(rsqrt.w.x Q vf0 basis-length-squared)
|
|
(nop!)
|
|
(add.x.vf.y tangent vf0 contact-normal)
|
|
(nop!)
|
|
(waitq)
|
|
(nop!)
|
|
(mulq.vf.xy tangent tangent Q)
|
|
(nop!)
|
|
(label tangent-from-z)
|
|
(outer.product.a.vf acc contact-normal tangent)
|
|
(nop!)
|
|
(outer.product.b.vf bitangent tangent contact-normal acc)
|
|
(nop!)))
|
|
;; Rotate the template by the contact-normal/tangent/bitangent basis. vf0.w translates every
|
|
;; point by contact-point while the xyz lanes apply the three basis vectors.
|
|
(asm-block build-contact-triangle
|
|
(mula.w.vf contact-point vf0)
|
|
(nop!)
|
|
(madda.x.vf contact-normal triangle-a)
|
|
(nop!)
|
|
(madda.y.vf tangent triangle-a)
|
|
(nop!)
|
|
(madd.z.vf.xyz triangle-a bitangent triangle-a)
|
|
(nop!)
|
|
(mula.w.vf contact-point vf0)
|
|
(nop!)
|
|
(madda.x.vf contact-normal triangle-b)
|
|
(nop!)
|
|
(madda.y.vf tangent triangle-b)
|
|
(nop!)
|
|
(madd.z.vf.xyz triangle-b bitangent triangle-b)
|
|
(nop!)
|
|
(mula.w.vf contact-point vf0)
|
|
(nop!)
|
|
(madda.x.vf contact-normal triangle-c)
|
|
(nop!)
|
|
(madda.y.vf tangent triangle-c)
|
|
(nop!)
|
|
(madd.z.vf.xyz triangle-c bitangent triangle-c)
|
|
(nop! :count 2)
|
|
(s.vf triangle-a result-reg (offset-of collide-tri-result vertex 0))
|
|
(nop!)
|
|
(s.vf triangle-b result-reg (offset-of collide-tri-result vertex 1))
|
|
(nop!)
|
|
(s.vf triangle-c result-reg (offset-of collide-tri-result vertex 2))
|
|
(m v1 r0))
|
|
(asm-block return-sphere-result
|
|
(label restore-sphere-state)
|
|
(m v0 fraction)
|
|
(l.d ra sp)
|
|
(l.d function-base sp 8)
|
|
(l.q gp sp 112)
|
|
(l.q s5 sp 96)
|
|
(l.q s4 sp 80)
|
|
(l.q s3 sp 64)
|
|
(l.q s2 sp 48)
|
|
(l.q s1 sp 32)
|
|
(jr ra :delay (add.i sp sp 128))
|
|
(nop! :count 2))))
|
|
(defmethod puyp-mesh ((this collide-cache) (work collide-puyp-work) (mesh-prim collide-cache-prim))
|
|
"Cast work's downward probe through mesh-prim's triangles and retain the nearest front-face hit
|
|
before work.best-u."
|
|
(declare (asm-func none))
|
|
(rlet ((cache :reg a0 :type collide-cache)
|
|
(work-reg :reg a1 :type collide-puyp-work)
|
|
(prim :reg a2 :type collide-cache-prim)
|
|
(first-tri :reg a3)
|
|
(remaining :reg v1)
|
|
(first-tri-offset :reg a2)
|
|
(best-u-float :reg f4))
|
|
(asm-block find-probe-triangles
|
|
(nop!)
|
|
(add.i cache cache COLLIDE-CACHE-TRIS)
|
|
(l.hu.field first-tri prim (first-tri))
|
|
(nop!)
|
|
(l.hu.field remaining prim (num-tris))
|
|
(sll first-tri-offset first-tri 6)
|
|
(l.s.field best-u-float work-reg (best-u))
|
|
(add cache cache first-tri-offset)
|
|
(nop!)))
|
|
(rlet ((tri-cursor :reg a0 :type collide-cache-tri)
|
|
(work-reg :reg a1 :type collide-puyp-work)
|
|
(remaining :reg v1)
|
|
(best-u-float :reg f4)
|
|
(fraction-numerator :reg f1)
|
|
(fraction-denominator :reg f2)
|
|
(fraction :reg f3)
|
|
(zero :reg f6)
|
|
(approach :reg f5)
|
|
(vertex-a :reg vf1)
|
|
(vertex-b :reg vf2)
|
|
(vertex-c :reg vf3)
|
|
(probe-start :reg vf4)
|
|
(edge-ab :reg vf5)
|
|
(edge-cb :reg vf6)
|
|
(start-to-b :reg vf7)
|
|
(move-length-squared :reg vf8)
|
|
(unit-normal :reg vf9)
|
|
(normal-length-squared :reg vf10)
|
|
(move-dot-normal :reg vf11)
|
|
(fraction-vf :reg vf12)
|
|
(intersection :reg vf13)
|
|
(b-to-intersection :reg vf14)
|
|
(intersection-to-c :reg vf15)
|
|
(intersection-to-a :reg vf16)
|
|
(edge-test-0 :reg vf17)
|
|
(edge-test-1 :reg vf18)
|
|
(edge-test-2 :reg vf19)
|
|
(probe-move :reg vf20)
|
|
(approach-products :reg vf21)
|
|
(Q :reg Q))
|
|
;; The PAT mask is checked before any division. The triangle cursor advances early, so later
|
|
;; stores intentionally address the accepted triangle at -64 and its PAT at -16.
|
|
(asm-block intersect-probe-plane
|
|
(label next-probe-triangle)
|
|
(b.z remaining finish-y-probe :delay (l.vf vertex-a tri-cursor))
|
|
(add.i remaining remaining -1)
|
|
(l.vf vertex-b tri-cursor (offset-of collide-cache-tri vertex 1))
|
|
(sub.vf edge-ab vertex-b vertex-a)
|
|
(l.vf vertex-c tri-cursor (offset-of collide-cache-tri vertex 2))
|
|
(sub.vf edge-cb vertex-b vertex-c)
|
|
(l.vf probe-start work-reg (offset-of collide-puyp-work start-pos))
|
|
(nop!)
|
|
(l.vf probe-move work-reg (offset-of collide-puyp-work move-dist))
|
|
(sub.vf start-to-b vertex-b probe-start)
|
|
(l.wu a2 tri-cursor (offset-of collide-cache-tri pat))
|
|
(mul.vf move-length-squared probe-move probe-move)
|
|
(l.wu.field a3 work-reg (ignore-pat))
|
|
(outer.product.a.vf acc edge-cb edge-ab)
|
|
(add.i tri-cursor tri-cursor COLLIDE-CACHE-TRI-STRIDE)
|
|
(outer.product.b.vf unit-normal edge-ab edge-cb acc)
|
|
(and a2 a2 a3)
|
|
(b.nz a2 next-probe-triangle :delay (add.y.vf.x move-length-squared move-length-squared move-length-squared))
|
|
(mul.vf normal-length-squared unit-normal unit-normal)
|
|
(nop!)
|
|
(mul.vf start-to-b start-to-b unit-normal)
|
|
(nop!)
|
|
(mul.vf move-dot-normal probe-move unit-normal)
|
|
(nop!)
|
|
(add.z.vf.x move-length-squared move-length-squared move-length-squared)
|
|
(nop!)
|
|
(add.y.vf.x normal-length-squared normal-length-squared normal-length-squared)
|
|
(nop!)
|
|
(add.y.vf.x start-to-b start-to-b start-to-b)
|
|
(nop!)
|
|
(add.y.vf.x move-dot-normal move-dot-normal move-dot-normal)
|
|
(nop!)
|
|
(add.z.vf.x normal-length-squared normal-length-squared normal-length-squared)
|
|
(nop!)
|
|
(add.z.vf.x start-to-b start-to-b start-to-b)
|
|
(nop!)
|
|
(add.z.vf.x move-dot-normal move-dot-normal move-dot-normal)
|
|
(nop!)
|
|
(rsqrt.w.x Q vf0 normal-length-squared)
|
|
(nop!)
|
|
(m a2 move-dot-normal)
|
|
(nop!)
|
|
(m a3 start-to-b)
|
|
(m fraction-denominator a2)
|
|
(m fraction-numerator a3)
|
|
(div.s fraction fraction-numerator fraction-denominator)
|
|
(move.w.vf unit-normal vf0)
|
|
(sll a2 a2 1)
|
|
(b.z a2 next-probe-triangle :delay (nop!))
|
|
(waitq)
|
|
(nop!)
|
|
(mulq.vf.xyz unit-normal unit-normal Q)
|
|
(m a2 fraction)
|
|
(b.lt a2 r0 next-probe-triangle :delay (nop!))
|
|
(m fraction-vf a2)
|
|
(nop!)
|
|
(c.le.s best-u-float fraction)
|
|
(nop!)
|
|
(b.fpt next-probe-triangle :delay (mula.x.vf probe-move fraction-vf))
|
|
(madd.w.vf intersection probe-start vf0)
|
|
(nop!))
|
|
;; Intersecting the plane is not enough: require motion into the triangle's front face and
|
|
;; require the point to lie on the nonnegative side of all three oriented edges.
|
|
(asm-block test-triangle-interior
|
|
(sub.vf b-to-intersection vertex-b intersection)
|
|
(nop!)
|
|
(sub.vf intersection-to-c intersection vertex-c)
|
|
(nop!)
|
|
(sub.vf intersection-to-a intersection vertex-a)
|
|
(nop!)
|
|
(outer.product.a.vf acc edge-cb b-to-intersection)
|
|
(nop!)
|
|
(mul.vf approach-products probe-move unit-normal)
|
|
(nop!)
|
|
(outer.product.b.vf edge-test-0 b-to-intersection edge-cb acc)
|
|
(nop!)
|
|
(add.y.vf.x approach-products approach-products approach-products)
|
|
(nop!)
|
|
(outer.product.a.vf acc b-to-intersection edge-ab)
|
|
(nop!)
|
|
(add.z.vf.x approach-products approach-products approach-products)
|
|
(nop!)
|
|
(m zero r0)
|
|
(nop!)
|
|
(outer.product.b.vf edge-test-1 edge-ab b-to-intersection acc)
|
|
(nop!)
|
|
(m a2 approach-products)
|
|
(nop!)
|
|
(m approach a2)
|
|
(nop!)
|
|
(c.le.s zero approach)
|
|
(nop!)
|
|
(b.fpt next-probe-triangle :delay (outer.product.a.vf acc intersection-to-c intersection-to-a))
|
|
(outer.product.b.vf edge-test-2 intersection-to-a intersection-to-c acc)
|
|
(nop!)
|
|
(mul.vf.xyz edge-test-0 edge-test-0 unit-normal)
|
|
(nop!)
|
|
(mul.vf.xyz edge-test-1 edge-test-1 unit-normal)
|
|
(nop!)
|
|
(mul.vf.xyz edge-test-2 edge-test-2 unit-normal)
|
|
(nop!)
|
|
(add.x.vf.y edge-test-0 edge-test-0 edge-test-0)
|
|
(nop!)
|
|
(add.x.vf.y edge-test-1 edge-test-1 edge-test-1)
|
|
(nop!)
|
|
(add.x.vf.y edge-test-2 edge-test-2 edge-test-2)
|
|
(nop!)
|
|
(add.z.vf.y edge-test-0 edge-test-0 edge-test-0)
|
|
(nop!)
|
|
(add.z.vf.y edge-test-1 edge-test-1 edge-test-1)
|
|
(nop!)
|
|
(add.z.vf.y edge-test-2 edge-test-2 edge-test-2)
|
|
(nop!)
|
|
(m a3 edge-test-0)
|
|
(nop!)
|
|
(m t0 edge-test-1)
|
|
(nop!)
|
|
(m a2 edge-test-2)
|
|
(nop!)
|
|
(or a3 a3 t0)
|
|
(nop!)
|
|
(or a3 a3 a2)
|
|
(l.wu.field a2 work-reg (tri-out))
|
|
(b.lt a3
|
|
r0
|
|
next-probe-triangle
|
|
:delay
|
|
(l.wu a3 tri-cursor (- (offset-of collide-cache-tri pat) COLLIDE-CACHE-TRI-STRIDE))))
|
|
(asm-block save-probe-hit
|
|
(nop!)
|
|
(s.s.field fraction work-reg (best-u))
|
|
(mov.s best-u-float fraction)
|
|
(s.vf vertex-a a2 (offset-of collide-tri-result vertex 0))
|
|
(nop!)
|
|
(s.vf vertex-b a2 (offset-of collide-tri-result vertex 1))
|
|
(nop!)
|
|
(s.vf vertex-c a2 (offset-of collide-tri-result vertex 2))
|
|
(nop!)
|
|
(s.vf unit-normal a2 (offset-of collide-tri-result normal))
|
|
(nop!)
|
|
(s.w a3 a2 (offset-of collide-tri-result pat))
|
|
(b next-probe-triangle :delay (s.vf intersection a2 (offset-of collide-tri-result intersect))))
|
|
(asm-block finish-probe (label finish-y-probe) (m v0 r0) (jr ra :delay (add sp sp r0)) (nop! :count 3)))))
|
|
|
|
;; A mesh primitive keeps its triangles in local space. Before filtering, the mesh vertex
|
|
;; buffer is transformed into scratchpad records containing each world-space vertex followed by
|
|
;; its integer form. Box and Y-probe fills use the ordinary joint transform. The line-sphere
|
|
;; fill also applies *collide-work*'s inverse query transform to the integer copy, so the same
|
|
;; packed AABB test runs in the oriented query's local frame while the float copy remains in world
|
|
;; space for the collision cache.
|
|
;;
|
|
;; Each accepted triangle appends one collide-cache-tri: three float vertices, the PAT word, and
|
|
;; the owning cache-primitive index. A mesh cache primitive is appended only when at least one
|
|
;; triangle survives. The EE limits are 100 primitives and 460 triangles. Primitive
|
|
;; overflow is always reported; triangle overflow is reported once through the shared warning
|
|
;; latch.
|
|
|
|
(#unless PC_PORT
|
|
(defmethod add-fg-prim-using-box ((obj collide-shape-prim-mesh) (cache collide-cache))
|
|
"Transform this mesh to world space, append triangles whose integer bounds overlap the active
|
|
box and whose PAT is not ignored, then append one cache primitive for the accepted range."
|
|
(rlet ((mesh-prim :reg s5 :type collide-shape-prim-mesh)
|
|
(ccache :reg gp :type collide-cache)
|
|
(cache-prim :reg s4 :type collide-cache-prim))
|
|
(asm-block enter
|
|
(add.i sp sp -80)
|
|
(s.d ra sp)
|
|
(s.d fp sp 8)
|
|
(m fp t9)
|
|
(s.q s3 sp 16)
|
|
(s.q s4 sp 32)
|
|
(s.q s5 sp 48)
|
|
(s.q gp sp 64)
|
|
(m mesh-prim a0)
|
|
(m ccache a1)
|
|
(nop! :count 2))
|
|
;; Reserve the cache-primitive slot before transforming. A null mesh contributes nothing.
|
|
(rlet ((mesh :reg s3 :type collide-mesh))
|
|
(asm-block prepare-mesh
|
|
(l.wu mesh (-> mesh-prim mesh))
|
|
(lea.field v1 ccache (prims))
|
|
(l.wu a0 (-> ccache num-prims))
|
|
(b.eq mesh s7 return :delay (nop!))
|
|
(add.i a1 r0 100)
|
|
(sll a2 a0 1)
|
|
(b.eq a0 a1 primitive-capacity-error :delay (add a0 a2 a0))
|
|
(sll a0 a0 4)
|
|
(add cache-prim v1 a0)
|
|
;; transform-verts-1-matrix! writes [float vertex, integer vertex] pairs to scratchpad.
|
|
(m a0 mesh)
|
|
(l.wu v1 a0 -4)
|
|
(l.wu t9 v1 (method-offset collide-mesh transform-verts-1-matrix!))
|
|
(rlet ((shape :reg v1 :type collide-shape)) (l.wu shape (-> mesh-prim cshape)) (l.wu v1 (-> shape process)))
|
|
(rlet ((draw-process :reg v1 :type process-drawable)) (l.wu v1 (-> draw-process node-list)))
|
|
(l.b a1 (-> mesh-prim transform-index))
|
|
(sll a1 a1 5)
|
|
(add v1 v1 a1)
|
|
(l.wu v1 v1 (offset-of cspace param2))
|
|
(add a1 r0 v1)
|
|
(lui a2 #x7000)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0)
|
|
(nop! :count 2)
|
|
(rlet ((total-tris :reg v1)
|
|
(first-tri :reg a0)
|
|
(max-tris :reg a1)
|
|
(mesh-tri :reg a2 :type collide-mesh-tri)
|
|
(tris-left :reg a3)
|
|
(cache-tri :reg t1 :type collide-cache-tri)
|
|
(query-min :reg t0 :class i128)
|
|
(query-max :reg t2 :class i128)
|
|
(scratch-base :reg t3)
|
|
(ignore-mask :reg t4)
|
|
(cache-meta :reg vf1 :class vf))
|
|
(asm-block prepare-filter
|
|
;; a0 first carries the primitive index for cache-meta, then the remaining
|
|
;; triangle capacity. It becomes first-tri after the capacity check.
|
|
(l.wu a0 (-> ccache num-prims))
|
|
(add.i max-tris r0 460)
|
|
(l.wu total-tris (-> ccache num-tris))
|
|
(sll32 a0 a0 0)
|
|
(nop!)
|
|
(m cache-meta a0)
|
|
(nop!)
|
|
(sub a0 max-tris total-tris)
|
|
(sll cache-tri total-tris 6)
|
|
(b.lt a0 r0 triangle-capacity-error :delay (lea.field mesh-tri mesh (tris)))
|
|
(m first-tri total-tris)
|
|
(l.wu tris-left (-> mesh num-tris))
|
|
(lea.field t2 ccache (tris))
|
|
(l.q query-min (-> ccache collide-box4w min quad))
|
|
(add cache-tri t2 cache-tri)
|
|
(l.q query-max (-> ccache collide-box4w max quad))
|
|
(lui scratch-base #x7000)
|
|
(l.wu ignore-mask (-> ccache ignore-mask))
|
|
;; cache-meta is [0, primitive-index, 0, 0]. PAT overwrites the first word.
|
|
(vsub.zw cache-meta vf0 vf0)
|
|
(nop!))
|
|
(rlet ((vertex0 :reg t6 :class i128)
|
|
(vertex1 :reg t7 :class i128)
|
|
(vertex2 :reg t5 :class i128)
|
|
(vertex1-int :reg s3 :class i128)
|
|
(bbox-min :reg ra :class i128)
|
|
(bbox-max :reg t9 :class i128)
|
|
(surface :reg t8))
|
|
(asm-block filter-triangles
|
|
(label triangle-loop)
|
|
(b.z tris-left finish-triangles :delay (l.bu t5 (-> mesh-tri vertex-index 0)))
|
|
(add.i tris-left tris-left -1)
|
|
(l.bu t6 (-> mesh-tri vertex-index 1))
|
|
(sll t8 t5 5)
|
|
(l.bu t5 (-> mesh-tri vertex-index 2))
|
|
(sll t7 t6 5)
|
|
(add vertex0 t8 scratch-base)
|
|
(sll t5 t5 5)
|
|
(nop!)
|
|
(add vertex1 t7 scratch-base)
|
|
(l.q bbox-max vertex0 16)
|
|
(add vertex2 t5 scratch-base)
|
|
(l.q vertex1-int vertex1 16)
|
|
(min.w bbox-min bbox-max vertex1-int)
|
|
(l.q t8 vertex2 16)
|
|
(max.w bbox-max bbox-max vertex1-int)
|
|
(mmi-nop!)
|
|
(min.w bbox-min bbox-min t8)
|
|
(mmi-nop!)
|
|
(max.w t8 bbox-max t8)
|
|
(mmi-nop!)
|
|
;; Reject when any integer axis lies wholly outside the query bounds.
|
|
(pcgt.w bbox-max bbox-min query-max)
|
|
(mmi-nop!)
|
|
(pcgt.w bbox-min query-min t8)
|
|
(l.wu surface (-> mesh-tri pat))
|
|
(or.q bbox-max bbox-max bbox-min)
|
|
(l.q vertex0 vertex0)
|
|
(ppach bbox-max r0 bbox-max)
|
|
(l.q vertex1 vertex1)
|
|
(sll bbox-max bbox-max 16)
|
|
(l.q vertex2 vertex2)
|
|
(b.nz bbox-max triangle-loop :delay (add.i mesh-tri mesh-tri (type-size collide-mesh-tri)))
|
|
;; The delay slot initializes the metadata for the candidate slot. When the
|
|
;; cache is full, the branch prevents the triangle count and range from advancing.
|
|
(b.eq total-tris max-tris triangle-capacity-error :delay (s.vf cache-meta (-> cache-tri extra-quad)))
|
|
(and bbox-max surface ignore-mask)
|
|
(s.w surface (-> cache-tri pat))
|
|
(b.nz bbox-max triangle-loop :delay (s.q vertex0 (-> cache-tri vertex 0 quad)))
|
|
(nop!)
|
|
(s.q vertex1 (-> cache-tri vertex 1 quad))
|
|
(add.i total-tris total-tris 1)
|
|
(s.q vertex2 (-> cache-tri vertex 2 quad))
|
|
(b triangle-loop :delay (add.i cache-tri cache-tri (type-size collide-cache-tri)))))
|
|
;; Publish one cache primitive only if this mesh supplied at least one triangle.
|
|
(asm-block publish-range
|
|
(label finish-triangles)
|
|
(sub tris-left total-tris first-tri)
|
|
(l.wu t0 (-> ccache num-prims))
|
|
(b.z tris-left return :delay (l.q a1 (-> mesh-prim prim-core quad 0)))
|
|
(nop!)
|
|
(l.q a2 (-> mesh-prim prim-core quad 1))
|
|
(nop!)
|
|
(s.q r0 (-> cache-prim extra-quad))
|
|
(nop!)
|
|
(s.h tris-left (-> cache-prim num-tris))
|
|
(nop!)
|
|
(s.w ccache (-> cache-prim ccache))
|
|
(nop!)
|
|
(s.w mesh-prim (-> cache-prim prim))
|
|
(nop!)
|
|
(s.h first-tri (-> cache-prim first-tri))
|
|
(add.i a0 t0 1)
|
|
(s.q a1 (-> cache-prim prim-core quad 0))
|
|
(nop!)
|
|
(s.q a2 (-> cache-prim prim-core quad 1))
|
|
(nop!)
|
|
(s.w a0 (-> ccache num-prims))
|
|
(b return :delay (s.w total-tris (-> ccache num-tris)))))))
|
|
(asm-block errors
|
|
(label primitive-capacity-error)
|
|
(m! t9 format)
|
|
(add.i a0 r0 0)
|
|
(add.i a1 fp collide-cache-primitive-capacity-message)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(b return :delay (nop!))
|
|
(label triangle-capacity-error)
|
|
(m! v1 *already-printed-exeeded-max-cache-tris*)
|
|
(b.ne s7 v1 return :delay (m v1 s7))
|
|
(add.i v1 s7 #t)
|
|
(set! *already-printed-exeeded-max-cache-tris* v1)
|
|
(add.i v1 s7 debug)
|
|
(m! a0 *cheat-mode*)
|
|
(b.ne a0 v1 return :delay (m v1 s7))
|
|
(m! t9 format)
|
|
(m! a0 *stdcon*)
|
|
(add.i a1 fp collide-cache-triangle-capacity-message)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0))
|
|
(asm-block leave
|
|
(label return)
|
|
(m v0 r0)
|
|
(l.d ra sp)
|
|
(l.d fp sp 8)
|
|
(l.q gp sp 64)
|
|
(l.q s5 sp 48)
|
|
(l.q s4 sp 32)
|
|
(l.q s3 sp 16)
|
|
(jr ra :delay (add.i sp sp 80))
|
|
(nop! :count 3)))))
|
|
|
|
(#unless PC_PORT
|
|
(defmethod add-fg-prim-using-line-sphere ((obj collide-shape-prim-mesh) (cache collide-cache))
|
|
"Transform this mesh to world space and into the swept-sphere query frame, append triangles
|
|
overlapping the oriented query whose PAT is not ignored, then append their cache primitive."
|
|
(rlet ((mesh-prim :reg s5 :type collide-shape-prim-mesh)
|
|
(ccache :reg gp :type collide-cache)
|
|
(cache-prim :reg s4 :type collide-cache-prim))
|
|
(asm-block enter
|
|
(add.i sp sp -80)
|
|
(s.d ra sp)
|
|
(s.d fp sp 8)
|
|
(m fp t9)
|
|
(s.q s3 sp 16)
|
|
(s.q s4 sp 32)
|
|
(s.q s5 sp 48)
|
|
(s.q gp sp 64)
|
|
(m mesh-prim a0)
|
|
(m ccache a1)
|
|
(nop! :count 2))
|
|
(rlet ((mesh :reg s3 :type collide-mesh))
|
|
(asm-block prepare-mesh
|
|
(l.wu mesh (-> mesh-prim mesh))
|
|
(lea.field v1 ccache (prims))
|
|
(l.wu a0 (-> ccache num-prims))
|
|
(b.eq mesh s7 line-return :delay (nop!))
|
|
(add.i a1 r0 100)
|
|
(sll a2 a0 1)
|
|
(b.eq a0 a1 line-primitive-capacity-error :delay (add a0 a2 a0))
|
|
(sll a0 a0 4)
|
|
(add cache-prim v1 a0)
|
|
;; transform-verts-2-matrix! keeps world-space floats and creates integer coordinates
|
|
;; after the query inverse transform in the paired scratchpad slots.
|
|
(m a0 mesh)
|
|
(l.wu v1 a0 -4)
|
|
(l.wu t9 v1 (method-offset collide-mesh transform-verts-2-matrix!))
|
|
(rlet ((shape :reg v1 :type collide-shape)) (l.wu shape (-> mesh-prim cshape)) (l.wu v1 (-> shape process)))
|
|
(rlet ((draw-process :reg v1 :type process-drawable)) (l.wu v1 (-> draw-process node-list)))
|
|
(l.b a1 (-> mesh-prim transform-index))
|
|
(sll a1 a1 5)
|
|
(add v1 v1 a1)
|
|
(l.wu v1 v1 (offset-of cspace param2))
|
|
(add a1 r0 v1)
|
|
(m! v1 *collide-work*)
|
|
(rlet ((query-work :reg v1 :type collide-work)) (lea.field a2 query-work (inv-mat)))
|
|
(lui a3 #x7000)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0)
|
|
(m! t2 *collide-work*)
|
|
(nop!)
|
|
(rlet ((total-tris :reg v1)
|
|
(first-tri :reg a0)
|
|
(max-tris :reg a1)
|
|
(mesh-tri :reg a2 :type collide-mesh-tri)
|
|
(tris-left :reg a3)
|
|
(cache-tri :reg t1 :type collide-cache-tri)
|
|
(query-min :reg t0 :class i128)
|
|
(query-max :reg t2 :class i128)
|
|
(scratch-base :reg t3)
|
|
(ignore-mask :reg t4)
|
|
(cache-meta :reg vf1 :class vf))
|
|
(asm-block prepare-filter
|
|
;; Pack the primitive index into cache-meta before reusing a0 for capacity and the
|
|
;; first accepted triangle index.
|
|
(l.wu a0 (-> ccache num-prims))
|
|
(add.i max-tris r0 460)
|
|
(l.wu total-tris (-> ccache num-tris))
|
|
(sll32 a0 a0 0)
|
|
(nop!)
|
|
(m cache-meta a0)
|
|
(nop!)
|
|
(sub a0 max-tris total-tris)
|
|
(sll cache-tri total-tris 6)
|
|
(b.lt a0 r0 line-triangle-capacity-error :delay (lea.field mesh-tri mesh (tris)))
|
|
(m first-tri total-tris)
|
|
(l.wu tris-left (-> mesh num-tris))
|
|
(lea.field t3 ccache (tris))
|
|
(l.q query-min t2 (offset-of collide-work collide-box4w min quad))
|
|
(add cache-tri t3 cache-tri)
|
|
(l.q query-max t2 (offset-of collide-work collide-box4w max quad))
|
|
(lui scratch-base #x7000)
|
|
(l.wu ignore-mask (-> ccache ignore-mask))
|
|
(vsub.zw cache-meta vf0 vf0)
|
|
(nop!))
|
|
(rlet ((vertex0 :reg t6 :class i128)
|
|
(vertex1 :reg t7 :class i128)
|
|
(vertex2 :reg t5 :class i128)
|
|
(vertex1-int :reg s3 :class i128)
|
|
(bbox-min :reg ra :class i128)
|
|
(bbox-max :reg t9 :class i128)
|
|
(surface :reg t8))
|
|
(asm-block filter-triangles
|
|
(label line-triangle-loop)
|
|
(b.z tris-left line-finish-triangles :delay (l.bu t5 (-> mesh-tri vertex-index 0)))
|
|
(add.i tris-left tris-left -1)
|
|
(l.bu t6 (-> mesh-tri vertex-index 1))
|
|
(sll t8 t5 5)
|
|
(l.bu t5 (-> mesh-tri vertex-index 2))
|
|
(sll t7 t6 5)
|
|
(add vertex0 t8 scratch-base)
|
|
(sll t5 t5 5)
|
|
(nop!)
|
|
(add vertex1 t7 scratch-base)
|
|
(l.q bbox-max vertex0 16)
|
|
(add vertex2 t5 scratch-base)
|
|
(l.q vertex1-int vertex1 16)
|
|
(nop!)
|
|
(l.q t8 vertex2 16)
|
|
(min.w bbox-min bbox-max vertex1-int)
|
|
(mmi-nop!)
|
|
(max.w bbox-max bbox-max vertex1-int)
|
|
(mmi-nop!)
|
|
(min.w bbox-min bbox-min t8)
|
|
(mmi-nop!)
|
|
(max.w t8 bbox-max t8)
|
|
(mmi-nop!)
|
|
(pcgt.w bbox-max bbox-min query-max)
|
|
(mmi-nop!)
|
|
(pcgt.w bbox-min query-min t8)
|
|
(l.wu surface (-> mesh-tri pat))
|
|
(or.q bbox-max bbox-max bbox-min)
|
|
(l.q vertex0 vertex0)
|
|
(ppach bbox-max r0 bbox-max)
|
|
(l.q vertex1 vertex1)
|
|
(sll bbox-max bbox-max 16)
|
|
(l.q vertex2 vertex2)
|
|
(b.nz bbox-max line-triangle-loop :delay (add.i mesh-tri mesh-tri (type-size collide-mesh-tri)))
|
|
(b.eq total-tris max-tris line-triangle-capacity-error :delay (s.vf cache-meta (-> cache-tri extra-quad)))
|
|
(and bbox-max surface ignore-mask)
|
|
(s.w surface (-> cache-tri pat))
|
|
(b.nz bbox-max line-triangle-loop :delay (s.q vertex0 (-> cache-tri vertex 0 quad)))
|
|
(add.i total-tris total-tris 1)
|
|
(s.q vertex1 (-> cache-tri vertex 1 quad))
|
|
(nop!)
|
|
(s.q vertex2 (-> cache-tri vertex 2 quad))
|
|
(b line-triangle-loop :delay (add.i cache-tri cache-tri (type-size collide-cache-tri)))))
|
|
(asm-block publish-range
|
|
(label line-finish-triangles)
|
|
(sub tris-left total-tris first-tri)
|
|
(l.wu t0 (-> ccache num-prims))
|
|
(b.z tris-left line-return :delay (l.q a1 (-> mesh-prim prim-core quad 0)))
|
|
(nop!)
|
|
(l.q a2 (-> mesh-prim prim-core quad 1))
|
|
(nop!)
|
|
(s.q r0 (-> cache-prim extra-quad))
|
|
(nop!)
|
|
(s.h tris-left (-> cache-prim num-tris))
|
|
(nop!)
|
|
(s.w ccache (-> cache-prim ccache))
|
|
(nop!)
|
|
(s.w mesh-prim (-> cache-prim prim))
|
|
(nop!)
|
|
(s.h first-tri (-> cache-prim first-tri))
|
|
(add.i a0 t0 1)
|
|
(s.q a1 (-> cache-prim prim-core quad 0))
|
|
(nop!)
|
|
(s.q a2 (-> cache-prim prim-core quad 1))
|
|
(nop!)
|
|
(s.w a0 (-> ccache num-prims))
|
|
(b line-return :delay (s.w total-tris (-> ccache num-tris)))))))
|
|
(asm-block errors
|
|
(label line-primitive-capacity-error)
|
|
(m! t9 format)
|
|
(add.i a0 r0 0)
|
|
(add.i a1 fp collide-cache-primitive-capacity-message)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(b line-return :delay (nop!))
|
|
(label line-triangle-capacity-error)
|
|
(m! v1 *already-printed-exeeded-max-cache-tris*)
|
|
(b.ne s7 v1 line-return :delay (m v1 s7))
|
|
(add.i v1 s7 #t)
|
|
(set! *already-printed-exeeded-max-cache-tris* v1)
|
|
(add.i v1 s7 debug)
|
|
(m! a0 *cheat-mode*)
|
|
(b.ne a0 v1 line-return :delay (m v1 s7))
|
|
(m! t9 format)
|
|
(m! a0 *stdcon*)
|
|
(add.i a1 fp collide-cache-triangle-capacity-message)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0))
|
|
(asm-block leave
|
|
(label line-return)
|
|
(m v0 r0)
|
|
(l.d ra sp)
|
|
(l.d fp sp 8)
|
|
(l.q gp sp 64)
|
|
(l.q s5 sp 48)
|
|
(l.q s4 sp 32)
|
|
(l.q s3 sp 16)
|
|
(jr ra :delay (add.i sp sp 80))
|
|
(nop! :count 3)))))
|
|
|
|
(#unless PC_PORT
|
|
(defmethod add-fg-prim-using-y-probe ((obj collide-shape-prim-mesh) (cache collide-cache))
|
|
"Transform this mesh to world space, append triangles whose integer bounds overlap the active
|
|
vertical probe and whose PAT is not ignored, then append their cache primitive."
|
|
(rlet ((mesh-prim :reg s5 :type collide-shape-prim-mesh)
|
|
(ccache :reg gp :type collide-cache)
|
|
(cache-prim :reg s4 :type collide-cache-prim))
|
|
(asm-block enter
|
|
(add.i sp sp -80)
|
|
(s.d ra sp)
|
|
(s.d fp sp 8)
|
|
(m fp t9)
|
|
(s.q s3 sp 16)
|
|
(s.q s4 sp 32)
|
|
(s.q s5 sp 48)
|
|
(s.q gp sp 64)
|
|
(m mesh-prim a0)
|
|
(m ccache a1)
|
|
(nop! :count 2))
|
|
(rlet ((mesh :reg s3 :type collide-mesh))
|
|
(asm-block prepare-mesh
|
|
(l.wu mesh (-> mesh-prim mesh))
|
|
(lea.field v1 ccache (prims))
|
|
(l.wu a0 (-> ccache num-prims))
|
|
(b.eq mesh s7 y-return :delay (nop!))
|
|
(add.i a1 r0 100)
|
|
(sll a2 a0 1)
|
|
(b.eq a0 a1 y-primitive-capacity-error :delay (add a0 a2 a0))
|
|
(sll a0 a0 4)
|
|
(add cache-prim v1 a0)
|
|
(m a0 mesh)
|
|
(l.wu v1 a0 -4)
|
|
(l.wu t9 v1 (method-offset collide-mesh transform-verts-1-matrix!))
|
|
(rlet ((shape :reg v1 :type collide-shape)) (l.wu shape (-> mesh-prim cshape)) (l.wu v1 (-> shape process)))
|
|
(rlet ((draw-process :reg v1 :type process-drawable)) (l.wu v1 (-> draw-process node-list)))
|
|
(l.b a1 (-> mesh-prim transform-index))
|
|
(sll a1 a1 5)
|
|
(add v1 v1 a1)
|
|
(l.wu v1 v1 (offset-of cspace param2))
|
|
(add a1 r0 v1)
|
|
(lui a2 #x7000)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0)
|
|
(nop! :count 2)
|
|
(rlet ((total-tris :reg v1)
|
|
(first-tri :reg a0)
|
|
(max-tris :reg a1)
|
|
(mesh-tri :reg a2 :type collide-mesh-tri)
|
|
(tris-left :reg a3)
|
|
(cache-tri :reg t1 :type collide-cache-tri)
|
|
(query-min :reg t0 :class i128)
|
|
(query-max :reg t2 :class i128)
|
|
(scratch-base :reg t3)
|
|
(ignore-mask :reg t4)
|
|
(cache-meta :reg vf1 :class vf))
|
|
(asm-block prepare-filter
|
|
;; Pack the primitive index into cache-meta before reusing a0 for capacity and the
|
|
;; first accepted triangle index.
|
|
(l.wu a0 (-> ccache num-prims))
|
|
(add.i max-tris r0 460)
|
|
(l.wu total-tris (-> ccache num-tris))
|
|
(sll32 a0 a0 0)
|
|
(nop!)
|
|
(m cache-meta a0)
|
|
(nop!)
|
|
(sub a0 max-tris total-tris)
|
|
(sll cache-tri total-tris 6)
|
|
(b.lt a0 r0 y-triangle-capacity-error :delay (lea.field mesh-tri mesh (tris)))
|
|
(m first-tri total-tris)
|
|
(l.wu tris-left (-> mesh num-tris))
|
|
(lea.field t2 ccache (tris))
|
|
(l.q query-min (-> ccache collide-box4w min quad))
|
|
(add cache-tri t2 cache-tri)
|
|
(l.q query-max (-> ccache collide-box4w max quad))
|
|
(lui scratch-base #x7000)
|
|
(l.wu ignore-mask (-> ccache ignore-mask))
|
|
(vsub.zw cache-meta vf0 vf0)
|
|
(nop!))
|
|
(rlet ((vertex0 :reg t6 :class i128)
|
|
(vertex1 :reg t7 :class i128)
|
|
(vertex2 :reg t5 :class i128)
|
|
(vertex1-int :reg s3 :class i128)
|
|
(bbox-min :reg ra :class i128)
|
|
(bbox-max :reg t9 :class i128)
|
|
(surface :reg t8))
|
|
(asm-block filter-triangles
|
|
(label y-triangle-loop)
|
|
(b.z tris-left y-finish-triangles :delay (l.bu t5 (-> mesh-tri vertex-index 0)))
|
|
(add.i tris-left tris-left -1)
|
|
(l.bu t6 (-> mesh-tri vertex-index 1))
|
|
(sll t8 t5 5)
|
|
(l.bu t5 (-> mesh-tri vertex-index 2))
|
|
(sll t7 t6 5)
|
|
(add vertex0 t8 scratch-base)
|
|
(sll t5 t5 5)
|
|
(nop!)
|
|
(add vertex1 t7 scratch-base)
|
|
(l.q bbox-max vertex0 16)
|
|
(add vertex2 t5 scratch-base)
|
|
(l.q vertex1-int vertex1 16)
|
|
(min.w bbox-min bbox-max vertex1-int)
|
|
(l.q t8 vertex2 16)
|
|
(max.w bbox-max bbox-max vertex1-int)
|
|
(mmi-nop!)
|
|
(min.w bbox-min bbox-min t8)
|
|
(mmi-nop!)
|
|
(max.w t8 bbox-max t8)
|
|
(mmi-nop!)
|
|
(pcgt.w bbox-max bbox-min query-max)
|
|
(mmi-nop!)
|
|
(pcgt.w bbox-min query-min t8)
|
|
(l.wu surface (-> mesh-tri pat))
|
|
(or.q bbox-max bbox-max bbox-min)
|
|
(l.q vertex0 vertex0)
|
|
(ppach bbox-max r0 bbox-max)
|
|
(l.q vertex1 vertex1)
|
|
(sll bbox-max bbox-max 16)
|
|
(l.q vertex2 vertex2)
|
|
(b.nz bbox-max y-triangle-loop :delay (add.i mesh-tri mesh-tri (type-size collide-mesh-tri)))
|
|
(b.eq total-tris max-tris y-triangle-capacity-error :delay (s.vf cache-meta (-> cache-tri extra-quad)))
|
|
(and bbox-max surface ignore-mask)
|
|
(s.w surface (-> cache-tri pat))
|
|
(b.nz bbox-max y-triangle-loop :delay (s.q vertex0 (-> cache-tri vertex 0 quad)))
|
|
(add.i total-tris total-tris 1)
|
|
(s.q vertex1 (-> cache-tri vertex 1 quad))
|
|
(nop!)
|
|
(s.q vertex2 (-> cache-tri vertex 2 quad))
|
|
(b y-triangle-loop :delay (add.i cache-tri cache-tri (type-size collide-cache-tri)))))
|
|
(asm-block publish-range
|
|
(label y-finish-triangles)
|
|
(sub tris-left total-tris first-tri)
|
|
(l.wu t0 (-> ccache num-prims))
|
|
(b.z tris-left y-return :delay (l.q a1 (-> mesh-prim prim-core quad 0)))
|
|
(nop!)
|
|
(l.q a2 (-> mesh-prim prim-core quad 1))
|
|
(nop!)
|
|
(s.q r0 (-> cache-prim extra-quad))
|
|
(nop!)
|
|
(s.h tris-left (-> cache-prim num-tris))
|
|
(nop!)
|
|
(s.w ccache (-> cache-prim ccache))
|
|
(nop!)
|
|
(s.w mesh-prim (-> cache-prim prim))
|
|
(nop!)
|
|
(s.h first-tri (-> cache-prim first-tri))
|
|
(add.i a0 t0 1)
|
|
(s.q a1 (-> cache-prim prim-core quad 0))
|
|
(nop!)
|
|
(s.q a2 (-> cache-prim prim-core quad 1))
|
|
(nop!)
|
|
(s.w a0 (-> ccache num-prims))
|
|
(b y-return :delay (s.w total-tris (-> ccache num-tris)))))))
|
|
(asm-block errors
|
|
(label y-primitive-capacity-error)
|
|
(m! t9 format)
|
|
(add.i a0 r0 0)
|
|
(add.i a1 fp collide-cache-primitive-capacity-message)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(b y-return :delay (nop!))
|
|
(label y-triangle-capacity-error)
|
|
(m! v1 *already-printed-exeeded-max-cache-tris*)
|
|
(b.ne s7 v1 y-return :delay (m v1 s7))
|
|
(add.i v1 s7 #t)
|
|
(set! *already-printed-exeeded-max-cache-tris* v1)
|
|
(add.i v1 s7 debug)
|
|
(m! a0 *cheat-mode*)
|
|
(b.ne a0 v1 y-return :delay (m v1 s7))
|
|
(m! t9 format)
|
|
(m! a0 *stdcon*)
|
|
(add.i a1 fp collide-cache-triangle-capacity-message)
|
|
(jalr ra t9 :delay (sll v0 ra 0))
|
|
(m v1 v0))
|
|
(asm-block leave
|
|
(label y-return)
|
|
(m v0 r0)
|
|
(l.d ra sp)
|
|
(l.d fp sp 8)
|
|
(l.q gp sp 64)
|
|
(l.q s5 sp 48)
|
|
(l.q s4 sp 32)
|
|
(l.q s3 sp 16)
|
|
(jr ra :delay (add.i sp sp 80))
|
|
(nop! :count 3)))))
|
|
|
|
(#unless PC_PORT
|
|
;; Function-relative strings referenced by the EE blocks above.
|
|
(asm-data (label collide-cache-triangle-capacity-message)
|
|
(word #x27 #x65637845 #x64656465 #x6c6f6320 #x6564696c #x63616320 #x6d206568 #x23207861 #x20666f20 #x73697274 #x257e21)
|
|
(label collide-cache-primitive-capacity-message)
|
|
(word #x34
|
|
#x4f525245
|
|
#x45203a52
|
|
#x65656378
|
|
#x20646564
|
|
#x2078616d
|
|
#x626d756e
|
|
#x6f207265
|
|
#x6f632066
|
|
#x64696c6c
|
|
#x61632d65
|
|
#x20656863
|
|
#x6d697270
|
|
#x257e2173
|
|
0)))
|
|
|
|
(#when PC_PORT
|
|
(defmethod fill-from-background ((obj collide-cache) (bsp-find-mesh-func (function bsp-header int collide-list none)) (import-mesh-func (function collide-cache collide-frag-mesh none)))
|
|
"Collect background fragments with bsp-find-mesh-func, unpack their packed vertices, and pass
|
|
each scratchpad mesh to import-mesh-func. The cache must be empty on entry; all accepted
|
|
triangles are represented by the background primitive in slot zero."
|
|
(local-vars (a0-4 int) (a0-6 int))
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Step 1: Build Collide List
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; this is a list of fragments that we will look at.
|
|
(set! (-> *collide-list* num-items) 0)
|
|
(cond
|
|
((= bsp-find-mesh-func (method-of-type bsp-header collide-ray))
|
|
;; The swept-sphere probe builds its fragment list with the optimized collision traversal.
|
|
(dotimes (probe-level-index (-> *level* length))
|
|
(let ((probe-level (-> *level* level probe-level-index)))
|
|
(when (= (-> probe-level status) 'active)
|
|
(reset! (-> *perf-stats* data 14))
|
|
(collide-probe-make-list probe-level *collide-list*)
|
|
(read! (-> *perf-stats* data 14))))))
|
|
(else
|
|
;; Box and Y-probe fills use the supplied BSP method.
|
|
(dotimes (bsp-level-index (-> *level* length))
|
|
(let ((bsp-level (-> *level* level bsp-level-index)))
|
|
(if (= (-> bsp-level status) 'active) (bsp-find-mesh-func (-> bsp-level bsp) 0 *collide-list*))))))
|
|
(when (> (-> *collide-list* num-items) 0)
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Step 2: Upload to VU0 Data
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; VIF0 and VU0 are emulated synchronously on PC, so process one complete fragment at a time.
|
|
(dotimes (i (-> *collide-list* num-items))
|
|
(let ((frag (-> *collide-list* items i)))
|
|
;; Upload packed vertices to VU0 memory.
|
|
(__pc-upload-collide-frag (-> frag mesh packed-data) (-> frag mesh vertex-data-qwc) (-> frag mesh vertex-count))
|
|
;; Unpack VU0 vertices into scratchpad.
|
|
(unpack-background-collide-mesh obj (-> frag mesh) (-> frag inst) 0)
|
|
;; Import accepted scratchpad triangles into the cache.
|
|
(import-mesh-func obj (-> frag mesh))))
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Represent the imported triangles as one primitive
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Background fill starts on an empty cache, so slot zero can own every imported triangle.
|
|
(let ((tri-count (-> obj num-tris)))
|
|
(when (> tri-count 0)
|
|
(let ((prims (-> obj prims))
|
|
(background-prim *collide-shape-prim-backgnd*))
|
|
(set! (-> prims 0 num-tris) (the-as uint tri-count))
|
|
(set! (-> prims 0 prim) background-prim)
|
|
(set! (-> obj num-prims) 1)
|
|
(set! (-> prims 0 first-tri) (the-as uint 0))
|
|
(set! (-> prims 0 ccache) obj)
|
|
(set! (-> prims 0 prim-core world-sphere quad) (-> background-prim prim-core world-sphere quad))
|
|
(set! (-> prims 0 prim-core quad 1) (-> background-prim prim-core quad 1))))))
|
|
0
|
|
(none)))
|
|
|
|
(defmethod fill-from-water ((obj collide-cache) (water water-control))
|
|
"When active water collision is enabled and capacity remains, append two waterbottom triangles
|
|
covering the active query box in XZ, plus one cached water primitive which owns them. Racers use
|
|
0.2 meters below the surface, swim-ground uses the surface minus swim-height, and other water
|
|
uses base-height minus bottom-height; jump-out water is ignored."
|
|
(rlet ((vf0 :class vf)
|
|
(vf1 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf))
|
|
(init-vf0-vector)
|
|
(when (= (-> obj num-prims) 100)
|
|
(if (= *cheat-mode* 'debug) (format 0 "ERROR: Exceeded max number of collide-cache prims!~%"))
|
|
(return #f))
|
|
(when (< *collide-cache-max-tris* (+ (-> obj num-tris) 2))
|
|
(when (not *already-printed-exeeded-max-cache-tris*)
|
|
(set! *already-printed-exeeded-max-cache-tris* #t)
|
|
(if (= *cheat-mode* 'debug) (format *stdcon* "Exceeded collide cache max # of tris!~%")))
|
|
(return #f))
|
|
(if (not (and (logtest? (-> water flags) (water-flag active))
|
|
(logtest? (-> water flags) (water-flag swim-ground wt07))
|
|
(not (logtest? (water-flag jump-out) (-> water flags)))))
|
|
(return #f))
|
|
(let ((bottom-y (cond
|
|
((logtest? (-> *target* control root-prim prim-core action) (collide-action racer)) (+ -819.2 (-> water height)))
|
|
((logtest? (-> water flags) (water-flag swim-ground)) (- (-> water height) (-> water swim-height)))
|
|
(else (- (-> water base-height) (-> water bottom-height))))))
|
|
(.lvf vf1 (&-> obj collide-box min quad))
|
|
(.lvf vf3 (&-> obj collide-box max quad))
|
|
(let ((prim-index (-> obj num-prims-u))
|
|
(triangles (the-as (inline-array collide-cache-tri) (-> obj tris (-> obj num-tris)))))
|
|
(.mov vf5 bottom-y)
|
|
(.add.x.vf.y vf1 vf0 vf5)
|
|
(set! (-> triangles 0 extra-quad) (the-as uint128 0))
|
|
(set! (-> triangles 0 prim-index) prim-index)
|
|
(.add.x.vf.y vf3 vf0 vf5)
|
|
(set! (-> triangles 1 extra-quad) (the-as uint128 0))
|
|
(set! (-> triangles 1 prim-index) prim-index)
|
|
(.mov.vf vf2 vf1)
|
|
(.mov.vf vf4 vf1)
|
|
(.add.z.vf.z vf2 vf0 vf3)
|
|
(.add.x.vf.x vf4 vf0 vf3)
|
|
(.svf (&-> triangles 0 vertex 0 quad) vf1)
|
|
(.svf (&-> triangles 0 vertex 1 quad) vf2)
|
|
(.svf (&-> triangles 0 vertex 2 quad) vf3)
|
|
(set! (-> triangles 0 pat) (new 'static 'pat-surface :material (pat-material waterbottom)))
|
|
(.svf (&-> triangles 1 vertex 0 quad) vf1)
|
|
(.svf (&-> triangles 1 vertex 1 quad) vf3)
|
|
(.svf (&-> triangles 1 vertex 2 quad) vf4)
|
|
(set! (-> triangles 1 pat) (new 'static 'pat-surface :material (pat-material waterbottom)))))
|
|
(let ((water-prim *collide-shape-prim-water*)
|
|
(cache-prim (-> obj prims (-> obj num-prims))))
|
|
(set! (-> cache-prim first-tri) (the-as uint (-> obj num-tris)))
|
|
(set! (-> cache-prim num-tris) (the-as uint 2))
|
|
(set! (-> cache-prim prim) water-prim)
|
|
(set! (-> cache-prim ccache) obj)
|
|
(set! (-> cache-prim prim-core world-sphere quad) (-> water-prim prim-core world-sphere quad))
|
|
(set! (-> cache-prim prim-core quad 1) (-> water-prim prim-core quad 1)))
|
|
(+! (-> obj num-prims) 1)
|
|
(+! (-> obj num-tris) 2)
|
|
(none)))
|
|
|
|
(defmethod fill-using-bounding-box ((obj collide-cache) (box bounding-box) (collide-with collide-kind) (proc process-drawable) (ignore-pat pat-surface))
|
|
"Refill the cache with anything of the given kinds touching box, skipping proc's own prims and
|
|
surfaces matching ignore-pat. Background, water and foreground are filled separately, each working
|
|
from the box state left in *collide-work*."
|
|
(rlet ((Q :class vf)
|
|
(vf0 :class vf)
|
|
(box-min :class vf)
|
|
(box-max :class vf)
|
|
(box-min-int :class vf)
|
|
(box-max-int :class vf)
|
|
(center :class vf)
|
|
(half :class vf)
|
|
(radius-sq :class vf))
|
|
(init-vf0-vector)
|
|
;; Derive a bounding sphere from the box for the quick reject: center is the corner average,
|
|
;; radius the half-diagonal. The radius is stored negated in w, so the per-candidate test gets the
|
|
;; center difference and the sum of the radii out of a single subtract. See
|
|
;; collide-cache-using-box-test.
|
|
;;
|
|
;; An integer copy of the box goes in collide-box4w. The fragment tests use that one, since pcgtw
|
|
;; compares all four lanes at once.
|
|
(let ((one-half (new 'static 'vector :x 0.5)))
|
|
(nop!)
|
|
(.lvf box-min (&-> box min quad))
|
|
(nop!)
|
|
(.lvf box-max (&-> box max quad))
|
|
(nop!)
|
|
(set! (-> obj proc) proc)
|
|
(.mov.vf.w box-min vf0)
|
|
(let ((work *collide-work*))
|
|
(.mov.vf.w box-max vf0)
|
|
(set! (-> obj ignore-mask) ignore-pat)
|
|
(.ftoi.vf box-min-int box-min)
|
|
(.lvf half (&-> one-half quad))
|
|
(.ftoi.vf box-max-int box-max)
|
|
(set! (-> obj num-tris) 0)
|
|
(.add.vf.xyz center box-max box-min)
|
|
(.svf (&-> obj collide-box min quad) box-min)
|
|
(.mul.x.vf.xyz center center half)
|
|
(.svf (&-> obj collide-box max quad) box-max)
|
|
(.sub.vf.xyz radius-sq center box-min)
|
|
(.sub.vf.w center center center)
|
|
(.mul.vf.xyz radius-sq radius-sq radius-sq)
|
|
(.svf (&-> obj collide-box4w min quad) box-min-int)
|
|
(.add.y.vf.x radius-sq radius-sq radius-sq)
|
|
(.svf (&-> obj collide-box4w max quad) box-max-int)
|
|
(.add.z.vf.x radius-sq radius-sq radius-sq)
|
|
(.svf (&-> work collide-box4w min quad) box-min-int)
|
|
(.sqrt.vf Q radius-sq :ftf #b0)
|
|
(.svf (&-> work collide-box4w max quad) box-max-int)
|
|
(set! *already-printed-exeeded-max-cache-tris* #f)
|
|
(nop!)
|
|
(.wait.vf)
|
|
(set! (-> obj num-prims) 0)
|
|
(.sub.vf.w center center Q)
|
|
(set! (-> obj collide-with) collide-with)
|
|
(nop!)
|
|
(.svf (&-> work collide-sphere-neg-r quad) center)))
|
|
0
|
|
(if (logtest? collide-with (collide-kind background))
|
|
(fill-from-background obj
|
|
(method-of-type bsp-header collide-with-box)
|
|
(method-of-type collide-cache load-mesh-from-spad-in-box)))
|
|
(if (logtest? collide-with (collide-kind water)) (fill-from-water obj (-> proc water)))
|
|
(if (logtest? collide-with (collide-kind cak-1 cak-2 cak-3 target)) (fill-from-foreground-using-box obj))
|
|
0
|
|
(none)))
|
|
|
|
(defun collide-cache-using-box-test ((bsphere vector))
|
|
"Sphere/sphere reject against the cache's bounding sphere. bsphere's radius is in w, so this
|
|
is d^2 <= (r1+r2)^2 with no branches."
|
|
(local-vars (result-bits int))
|
|
(rlet ((acc :class vf)
|
|
(vf0 :class vf)
|
|
(delta :class vf)
|
|
(cache-sphere :class vf)
|
|
(ones :class vf))
|
|
(init-vf0-vector)
|
|
(nop!)
|
|
(.max.w.vf ones vf0 vf0)
|
|
(let ((work *collide-work*))
|
|
(nop!)
|
|
(.lvf delta (&-> bsphere quad))
|
|
(nop!)
|
|
(.lvf cache-sphere (&-> work collide-sphere-neg-r quad)))
|
|
;; The work sphere holds -r in w, so this yields dxyz and r1+r2 together.
|
|
(.sub.vf delta delta cache-sphere)
|
|
(nop!)
|
|
(.mul.vf delta delta delta)
|
|
(nop!)
|
|
;; dx^2 + dy^2 + dz^2 - (r1+r2)^2, one lane at a time against an all-ones vector.
|
|
(.mul.x.vf acc ones delta)
|
|
(nop!)
|
|
(.add.mul.y.vf acc ones delta acc)
|
|
(nop!)
|
|
(.add.mul.z.vf acc ones delta acc)
|
|
(nop!)
|
|
(.sub.mul.w.vf delta ones delta acc)
|
|
(nop!)
|
|
;; Sign test in the integer unit: a negative float has its sign bit set, so it reads as a negative
|
|
;; int. Avoids the FPU compare and the branch on the coprocessor flag.
|
|
(.mov result-bits delta)
|
|
(<= (the-as int result-bits) 0)))
|
|
|
|
(defmethod collide-with-box ((obj collide-fragment) (count int) (clist collide-list))
|
|
"Append each fragment in this contiguous range whose bounding sphere and stored bounds intersect
|
|
the active box query."
|
|
(let ((cwork *collide-work*))
|
|
(dotimes (i count)
|
|
(when (and (collide-cache-using-box-test (-> obj bsphere)) (drawable-sphere-box-intersect? obj (-> cwork collide-box4w)))
|
|
(let ((item (-> clist items (-> clist num-items)))) (set! (-> item mesh) (-> obj mesh)) (set! (-> item inst) #f))
|
|
; (add-debug-sphere #t (bucket-id debug) (-> obj bsphere) (-> obj bsphere w) (new 'static 'rgba :g #x80 :a #x80))
|
|
; (format 0 "~f~%" (-> obj bsphere w))
|
|
(+! (-> clist num-items) 1))
|
|
(&+! obj 32)))
|
|
0
|
|
(none))
|
|
|
|
(defmethod collide-with-box ((obj instance-tie) (count int) (clist collide-list))
|
|
"Append every collision fragment of each enabled TIE instance in this contiguous range whose
|
|
transformed bounds intersect the active box query."
|
|
(dotimes (instance-index count)
|
|
(when (and (zero? (logand (-> obj flags) 1))
|
|
(collide-cache-using-box-test (-> obj bsphere))
|
|
(drawable-sphere-box-intersect? obj (-> *collide-work* collide-box4w)))
|
|
(let ((frag-list (-> obj bucket-ptr collide-frag)))
|
|
(when (nonzero? frag-list)
|
|
(let ((frag (the-as object (-> frag-list data))))
|
|
(dotimes (fragment-index (-> frag-list length))
|
|
(when (instance-sphere-box-intersect? (the-as collide-fragment frag) obj (-> *collide-work* collide-box4w))
|
|
(let ((item (-> clist items (-> clist num-items))))
|
|
(set! (-> item mesh) (-> (the-as collide-fragment frag) mesh))
|
|
(set! (-> item inst) obj))
|
|
(+! (-> clist num-items) 1))
|
|
(set! frag (-> (the-as (inline-array collide-fragment) frag) 1)))))))
|
|
(&+! obj 64))
|
|
0
|
|
(none))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Y PROBE
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defmethod fill-using-y-probe ((obj collide-cache) (probe-origin vector) (probe-length float) (kinds collide-kind) (proc process-drawable) (ignore-pat pat-surface))
|
|
"Refill the cache for a vertical probe centered at start and extending probe-length in both Y
|
|
directions for broad-phase collection. Skip proc's own foreground primitives and surfaces
|
|
matching ignore-pat."
|
|
(rlet ((vf1 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf))
|
|
(set! *already-printed-exeeded-max-cache-tris* #f)
|
|
(.mov vf5 probe-length)
|
|
(.lvf vf2 (&-> probe-origin quad))
|
|
(nop!)
|
|
(let ((cwork *collide-work*))
|
|
(.mov.vf vf1 vf2)
|
|
(set! (-> obj ignore-mask) (the-as pat-surface ignore-pat))
|
|
(.add.x.vf.y vf2 vf2 vf5)
|
|
(set! (-> obj num-tris) 0)
|
|
(.sub.x.vf.y vf1 vf1 vf5)
|
|
(set! (-> obj num-prims) 0)
|
|
(nop!)
|
|
(set! (-> obj collide-with) kinds)
|
|
(nop!)
|
|
(set! (-> obj proc) proc)
|
|
(.ftoi.vf vf4 vf2)
|
|
(.svf (&-> obj collide-box max quad) vf2)
|
|
(.ftoi.vf vf3 vf1)
|
|
(.svf (&-> obj collide-box min quad) vf1)
|
|
(nop!)
|
|
(.svf (&-> obj collide-box4w max quad) vf4)
|
|
(nop!)
|
|
(.svf (&-> obj collide-box4w min quad) vf3)
|
|
(nop!)
|
|
(.svf (&-> cwork collide-box4w max quad) vf4)
|
|
(nop!)
|
|
(.svf (&-> cwork collide-box4w min quad) vf3))
|
|
(if (logtest? kinds (collide-kind background))
|
|
(fill-from-background obj
|
|
(method-of-type bsp-header collide-y-probe)
|
|
(method-of-type collide-cache load-mesh-from-spad-in-y-probe)))
|
|
(if (logtest? kinds (collide-kind water)) (fill-from-water obj (-> proc water)))
|
|
(if (logtest? kinds (collide-kind cak-1 cak-2 cak-3 target)) (fill-from-foreground-using-y-probe obj))
|
|
0
|
|
(none)))
|
|
|
|
(defun collide-cache-using-y-probe-test ((bsphere vector))
|
|
"Return whether bsphere overlaps the active vertical-probe box."
|
|
(local-vars
|
|
(zero uint128)
|
|
(v1-1 uint128)
|
|
(v1-2 uint128)
|
|
(v1-3 uint128)
|
|
(a0-1 uint128)
|
|
(a1-2 uint128)
|
|
(a2-0 uint128)
|
|
(f31-0 none))
|
|
(rlet ((vf1 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf))
|
|
(set! zero (the-as uint128 0))
|
|
(nop!)
|
|
(let ((a1-0 *collide-work*))
|
|
(nop!)
|
|
(.lvf vf1 (&-> bsphere quad))
|
|
(nop!)
|
|
(let ((v1-0 (-> a1-0 collide-box4w min quad)))
|
|
(.sub.w.vf.xyz vf2 vf1 vf1)
|
|
(let ((a1-1 (-> a1-0 collide-box4w max quad)))
|
|
(.add.w.vf.xyz vf3 vf1 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-0 vf4)
|
|
(nop!)
|
|
(.mov a0-1 vf5)
|
|
(nop!)
|
|
(.pcgtw a1-2 a2-0 a1-1))
|
|
(.pcgtw v1-1 v1-0 a0-1)))
|
|
(.por v1-2 a1-2 v1-1)
|
|
(.ppach v1-3 zero v1-2)
|
|
(let ((v1-4 (shl (the-as int v1-3) 16))) (nop!) (zero? v1-4))))
|
|
|
|
(defmethod collide-y-probe ((obj collide-fragment) (count int) (clist collide-list))
|
|
"Append each fragment in this contiguous range whose bounding sphere intersects the active
|
|
vertical probe."
|
|
*collide-work*
|
|
(dotimes (i count)
|
|
(when (collide-cache-using-y-probe-test (-> obj bsphere))
|
|
(let ((item (-> clist items (-> clist num-items)))) (set! (-> item mesh) (-> obj mesh)) (set! (-> item inst) #f))
|
|
(+! (-> clist num-items) 1))
|
|
(&+! obj 32))
|
|
0
|
|
(none))
|
|
|
|
(defmethod collide-y-probe ((obj instance-tie) (count int) (clist collide-list))
|
|
"Append every collision fragment of each enabled TIE instance in this contiguous range whose
|
|
transformed bounds intersect the active vertical probe."
|
|
(dotimes (instance-index count)
|
|
(when (and (zero? (logand (-> obj flags) 1)) (collide-cache-using-y-probe-test (-> obj bsphere)))
|
|
(let ((frag-list (-> obj bucket-ptr collide-frag)))
|
|
(when (nonzero? frag-list)
|
|
(let ((frag (the-as object (-> frag-list data))))
|
|
(dotimes (fragment-index (-> frag-list length))
|
|
(when (instance-sphere-box-intersect? (the-as collide-fragment frag) obj (-> *collide-work* collide-box4w))
|
|
(let ((item (-> clist items (-> clist num-items))))
|
|
(set! (-> item mesh) (-> (the-as collide-fragment frag) mesh))
|
|
(set! (-> item inst) obj))
|
|
(+! (-> clist num-items) 1))
|
|
(set! frag (-> (the-as (inline-array collide-fragment) frag) 1)))))))
|
|
(&+! obj 64))
|
|
0
|
|
(none))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;
|
|
;; Line Sphere Test
|
|
;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; In this mode, we collide a line of spheres.
|
|
;; The first pass sets up a non-axis-aligned bounding box in *collide-work*
|
|
;; The box is stored as an axis-aligned box, and an inv-rot to transform from world to aligned-box coordinates.
|
|
|
|
(#when PC_PORT
|
|
(defmacro pabsw-hack (out in)
|
|
`(let ((temp (new 'stack-no-clear 'array 'int32 4)))
|
|
(set! (-> (the (pointer uint128) temp)) ,in)
|
|
(set! (-> temp 0) (abs (-> temp 0)))
|
|
(set! (-> temp 1) (abs (-> temp 1)))
|
|
(set! (-> temp 2) (abs (-> temp 2)))
|
|
(set! (-> temp 3) (abs (-> temp 3)))
|
|
(set! ,out (-> (the (pointer uint128) temp))))))
|
|
|
|
(#unless PC_PORT
|
|
(defmacro pabsw-hack (out in)
|
|
`(abs.w ,out ,in)))
|
|
|
|
(defmethod fill-using-line-sphere ((obj collide-cache) (start-pt vector) (move-vec vector) (radius float) (kinds collide-kind) (proc process-drawable) (ignore-pat pat-surface))
|
|
"Refill the cache for a sphere of radius moving from start by move. Fall back to an ordinary
|
|
bounding box when every movement component is at most one meter; otherwise construct an oriented
|
|
sweep box and its inverse transform for broad-phase rejection. Skip proc's own foreground
|
|
primitives and surfaces matching ignore-pat."
|
|
(local-vars
|
|
(zero uint128)
|
|
(long-axis-mask uint128)
|
|
(packed-long-axis-mask uint128)
|
|
(direction-x-bits int)
|
|
(move-words uint128)
|
|
(abs-move-words uint128))
|
|
(rlet ((acc :class vf)
|
|
(Q :class vf)
|
|
(vf0 :class vf)
|
|
(vf1 :class vf)
|
|
(vf10 :class vf)
|
|
(vf11 :class vf)
|
|
(vf12 :class vf)
|
|
(vf13 :class vf)
|
|
(vf14 :class vf)
|
|
(vf15 :class vf)
|
|
(vf16 :class vf)
|
|
(vf17 :class vf)
|
|
(vf18 :class vf)
|
|
(vf19 :class vf)
|
|
(vf2 :class vf)
|
|
(vf20 :class vf)
|
|
(vf21 :class vf)
|
|
(vf22 :class vf)
|
|
(vf23 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf)
|
|
(vf6 :class vf)
|
|
(vf7 :class vf)
|
|
(vf8 :class vf)
|
|
(vf9 :class vf))
|
|
(set! zero (the uint128 0))
|
|
(init-vf0-vector)
|
|
(let ((axis-threshold (new 'static 'vector4w :x #x1000 :y #x1000 :z #x1000)))
|
|
(nop!)
|
|
(.mov vf9 radius)
|
|
(.lvf vf3 (&-> move-vec quad))
|
|
(nop!)
|
|
(let ((threshold-words (-> axis-threshold quad)))
|
|
(.ftoi.vf vf21 vf3)
|
|
(.lvf vf1 (&-> start-pt quad))
|
|
(.mul.vf vf8 vf3 vf3)
|
|
(let ((cwork *collide-work*))
|
|
(.add.vf vf2 vf1 vf3)
|
|
(set! (-> obj ignore-mask) ignore-pat)
|
|
(.mov move-words vf21)
|
|
(nop!)
|
|
(pabsw-hack abs-move-words move-words)
|
|
(.pcgtw long-axis-mask abs-move-words threshold-words)
|
|
(.ppach packed-long-axis-mask zero long-axis-mask)
|
|
(let ((has-long-axis? (shl (the-as int packed-long-axis-mask) 16))) (b! (nonzero? has-long-axis?) cfg-3))
|
|
(let ((query-box (new 'stack-no-clear 'bounding-box)))
|
|
(set-from-point-offset-pad! query-box (the-as vector3s start-pt) (the-as vector3s move-vec) radius)
|
|
(fill-using-bounding-box obj query-box kinds proc ignore-pat))
|
|
(b! #t cfg-13 :delay (nop!))
|
|
(set! cwork (the-as collide-work 0))
|
|
(label cfg-3)
|
|
(.add.y.vf.x vf8 vf8 vf8)
|
|
(set! (-> obj num-tris) 0)
|
|
(.min.vf vf4 vf1 vf2)
|
|
(set! (-> obj num-prims) 0)
|
|
(.max.vf vf5 vf1 vf2)
|
|
(set! (-> obj collide-with) kinds)
|
|
(.sub.x.vf.xyz vf10 vf0 vf9)
|
|
(set! (-> obj proc) proc)
|
|
(.add.z.vf.x vf8 vf8 vf8)
|
|
(.sub.x.vf.xyz vf4 vf4 vf9)
|
|
(.add.x.vf.xyz vf5 vf5 vf9)
|
|
(.ftoi.vf vf15 vf10)
|
|
(.isqrt.vf Q vf0 vf8 :fsf #b11 :ftf #b0)
|
|
(.add.x.vf.xyz vf11 vf0 vf9)
|
|
(.svf (&-> cwork collide-box4w min quad) vf15)
|
|
(.ftoi.vf vf6 vf4)
|
|
(.svf (&-> obj collide-box min quad) vf4)
|
|
(.ftoi.vf vf7 vf5)
|
|
(.svf (&-> obj collide-box max quad) vf5)
|
|
(.mov.vf vf13 vf0)
|
|
(.svf (&-> obj collide-box4w min quad) vf6)
|
|
(.svf (&-> obj collide-box4w max quad) vf7)
|
|
(.add.vf.x vf8 vf0 Q)
|
|
(.mul.x.vf vf12 vf3 vf8)
|
|
(.div.vf Q vf0 vf8 :fsf #b11 :ftf #b0)
|
|
(.mul.vf vf22 vf12 vf12)
|
|
(.abs.vf vf23 vf12)
|
|
(.add.y.vf.x vf22 vf22 vf22)
|
|
(.mov direction-x-bits vf23)
|
|
(.wait.vf)
|
|
(.add.vf.x vf8 vf0 Q)
|
|
(b! (zero? direction-x-bits) cfg-6 :likely-delay (.add.z.vf.x vf13 vf0 vf12))
|
|
(.sub.y.vf.x vf13 vf0 vf12)
|
|
(.isqrt.vf Q vf0 vf22 :fsf #b11 :ftf #b0)
|
|
(.add.x.vf.y vf13 vf0 vf12)
|
|
(.wait.vf)
|
|
(.mul.vf.xy vf13 vf13 Q)
|
|
(label cfg-6)
|
|
(.outer.product.a.vf acc vf12 vf13)
|
|
(.add.x.vf.x vf11 vf11 vf8)
|
|
(.outer.product.b.vf vf14 vf13 vf12 acc)
|
|
(.ftoi.vf vf16 vf11)
|
|
(.mov.vf vf17 vf12)
|
|
(.mov.vf vf18 vf13)
|
|
(.mov.vf vf19 vf14)
|
|
(.mov.vf.yzw vf17 vf0)
|
|
(.svf (&-> cwork collide-box4w max quad) vf16)
|
|
(.mov.vf.xzw vf18 vf0)
|
|
(.mov.vf.xyw vf19 vf0)
|
|
(.add.x.vf.y vf17 vf17 vf13)
|
|
(.add.y.vf.x vf18 vf18 vf12)
|
|
(.add.z.vf.x vf19 vf19 vf12)
|
|
(.add.x.vf.z vf17 vf17 vf14)
|
|
(.add.y.vf.z vf18 vf18 vf14)
|
|
(.add.z.vf.y vf19 vf19 vf13)
|
|
(.mul.x.vf acc vf17 vf1)
|
|
(.add.mul.y.vf acc vf18 vf1 acc)
|
|
(.svf (&-> cwork inv-mat vector 0 quad) vf17)
|
|
(.add.mul.z.vf vf20 vf19 vf1 acc)
|
|
(.svf (&-> cwork inv-mat vector 1 quad) vf18)
|
|
(.sub.vf vf20 vf0 vf20)
|
|
(.svf (&-> cwork inv-mat vector 2 quad) vf19)
|
|
(.svf (&-> cwork inv-mat vector 3 quad) vf20))))
|
|
0
|
|
(if (logtest? kinds (collide-kind background))
|
|
(fill-from-background obj
|
|
(method-of-type bsp-header collide-ray)
|
|
(method-of-type collide-cache load-mesh-from-spad-in-line-sphere)))
|
|
(if (logtest? kinds (collide-kind water)) (fill-from-water obj (-> proc water)))
|
|
(if (logtest? kinds (collide-kind cak-1 cak-2 cak-3 target)) (fill-from-foreground-using-line-sphere obj))
|
|
0
|
|
(label cfg-13)
|
|
(none)))
|
|
|
|
(defun collide-cache-using-line-sphere-test ((bsphere vector))
|
|
"Check if bsphere is in the rotated bounding box volume of the current
|
|
line-sphere query."
|
|
(local-vars (v1-1 uint128) (v1-2 uint128) (v1-3 uint128) (a0-1 uint128) (a1-2 uint128) (a2-0 uint128) (zero uint128))
|
|
(rlet ((acc :class vf)
|
|
(vf0 :class vf)
|
|
(vf1 :class vf)
|
|
(vf10 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf)
|
|
(vf6 :class vf)
|
|
(vf7 :class vf)
|
|
(vf8 :class vf)
|
|
(vf9 :class vf))
|
|
(init-vf0-vector)
|
|
(set! zero (the uint128 0))
|
|
(let ((cwork *collide-work*))
|
|
(.lvf vf5 (&-> bsphere quad))
|
|
(.lvf vf4 (&-> cwork inv-mat vector 3 quad))
|
|
(.lvf vf1 (&-> cwork inv-mat vector 0 quad))
|
|
(.mul.w.vf acc vf4 vf0)
|
|
(.lvf vf2 (&-> cwork inv-mat vector 1 quad))
|
|
(.add.mul.x.vf acc vf1 vf5 acc)
|
|
(.lvf vf3 (&-> cwork inv-mat vector 2 quad))
|
|
(.add.mul.y.vf acc vf2 vf5 acc)
|
|
(let ((v1-0 (-> cwork collide-box4w min quad)))
|
|
(.add.mul.z.vf vf10 vf3 vf5 acc)
|
|
(let ((a1-1 (-> cwork collide-box4w max quad)))
|
|
(.sub.w.vf.xyz vf6 vf10 vf5)
|
|
(.add.w.vf.xyz vf7 vf10 vf5)
|
|
(.ftoi.vf vf8 vf6)
|
|
(.ftoi.vf vf9 vf7)
|
|
(.mov a2-0 vf8)
|
|
(.mov a0-1 vf9)
|
|
(.pcgtw a1-2 a2-0 a1-1))
|
|
(.pcgtw v1-1 v1-0 a0-1)))
|
|
(.por v1-2 a1-2 v1-1)
|
|
(.ppach v1-3 zero v1-2)
|
|
(let ((v1-4 (shl (the-as int v1-3) 16))) (nop!) (zero? v1-4))))
|
|
|
|
(defun make-collide-list-using-line-sphere-inst-test ((frag collide-fragment) (inst instance-tie))
|
|
"Check if a collide-fragment at a given instance is in the rotated bounding box volume
|
|
of the current line-sphere query."
|
|
(local-vars
|
|
(v1-1 uint128)
|
|
(v1-2 uint128)
|
|
(v1-3 uint128)
|
|
(v1-4 uint128)
|
|
(a1-2 uint128)
|
|
(a2-1 uint128)
|
|
(a3-1 uint128)
|
|
(a3-3 uint128)
|
|
(a3-4 uint128)
|
|
(t0-1 uint128)
|
|
(t0-2 uint128)
|
|
(t1-0 uint128)
|
|
(t2-1 uint128)
|
|
(t2-2 uint128)
|
|
(zero uint128))
|
|
(rlet ((acc :class vf)
|
|
(vf0 :class vf)
|
|
(vf1 :class vf)
|
|
(vf10 :class vf)
|
|
(vf11 :class vf)
|
|
(vf12 :class vf)
|
|
(vf13 :class vf)
|
|
(vf14 :class vf)
|
|
(vf15 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf)
|
|
(vf6 :class vf)
|
|
(vf7 :class vf)
|
|
(vf8 :class vf)
|
|
(vf9 :class vf))
|
|
(init-vf0-vector)
|
|
(set! zero (the uint128 0))
|
|
(let ((v1-0 *collide-work*))
|
|
(let ((a2-0 (-> inst max-scale)))
|
|
(let ((a3-0 (the-as uint128 (-> inst origin vector4h 3 long))))
|
|
(let ((t2-0 (the-as uint128 (-> inst origin vector4h 0 long))))
|
|
(.pextlh a3-1 a3-0 zero)
|
|
(let ((t0-0 (the-as uint128 (-> inst origin vector4h 1 long))))
|
|
(.pw.sra t1-0 a3-1 10)
|
|
(let ((a3-2 (the-as uint128 (-> inst origin vector4h 2 long))))
|
|
(.pextlh t2-1 t2-0 zero)
|
|
(.pw.sra t2-2 t2-1 16)
|
|
(.pextlh t0-1 t0-0 zero)
|
|
(.mov vf4 t1-0)
|
|
(.pw.sra t0-2 t0-1 16)
|
|
(.mov vf1 t2-2)
|
|
(.pextlh a3-3 a3-2 zero)))))
|
|
(.mov vf2 t0-2)
|
|
(.pw.sra a3-4 a3-3 16)
|
|
(.lvf vf5 (&-> inst bsphere quad))
|
|
(.mov vf3 a3-4)
|
|
(.mov vf6 a2-0))
|
|
(.itof.vf vf4 vf4)
|
|
(vitof12.xyzw vf1 vf1)
|
|
(vitof12.xyzw vf2 vf2)
|
|
(vitof12.xyzw vf3 vf3)
|
|
(.add.vf.xyz vf4 vf4 vf5)
|
|
(.lvf vf5 (&-> frag bsphere quad))
|
|
(vitof12.xyzw vf6 vf6)
|
|
(.mul.x.vf acc vf1 vf5)
|
|
(.add.mul.y.vf acc vf2 vf5 acc)
|
|
(.add.mul.z.vf acc vf3 vf5 acc)
|
|
(.add.mul.w.vf vf11 vf4 vf0 acc)
|
|
(.lvf vf7 (&-> v1-0 inv-mat vector 0 quad))
|
|
(.lvf vf8 (&-> v1-0 inv-mat vector 1 quad))
|
|
(.lvf vf9 (&-> v1-0 inv-mat vector 2 quad))
|
|
(.lvf vf10 (&-> v1-0 inv-mat vector 3 quad))
|
|
(.mul.x.vf acc vf7 vf11)
|
|
(let ((a0-1 (-> v1-0 collide-box4w min quad)))
|
|
(.add.mul.y.vf acc vf8 vf11 acc)
|
|
(let ((a1-1 (-> v1-0 collide-box4w max quad)))
|
|
(.add.mul.z.vf acc vf9 vf11 acc)
|
|
(.add.mul.w.vf vf11 vf10 vf0 acc)
|
|
(.mul.w.vf.x vf15 vf6 vf5)
|
|
(.add.x.vf.xyz vf12 vf11 vf15)
|
|
(.sub.x.vf.xyz vf11 vf11 vf15)
|
|
(.ftoi.vf vf14 vf12)
|
|
(.ftoi.vf vf13 vf11)
|
|
(.mov v1-1 vf14)
|
|
(.mov a2-1 vf13)
|
|
(.pcgtw a1-2 a2-1 a1-1))
|
|
(.pcgtw v1-2 a0-1 v1-1)))
|
|
(.por v1-3 a1-2 v1-2)
|
|
(.ppach v1-4 zero v1-3)
|
|
(let ((v1-5 (shl (the-as int v1-4) 16))) (nop!) (zero? v1-5))))
|
|
|
|
(defmethod collide-ray ((obj collide-fragment) (count int) (result collide-list))
|
|
"Inline-array function to do line-sphere with non-instanced fragments.
|
|
If the bsphere of the mesh is in the non-aligned bounding box, the mesh will be added
|
|
to the given collide-list.
|
|
Note: collide-probe is the faster implementation of this."
|
|
*collide-work*
|
|
;; just iterate over all and check their bsphere.
|
|
(dotimes (s3-0 count)
|
|
(when (collide-cache-using-line-sphere-test (-> obj bsphere))
|
|
(let ((v1-5 (-> result items (-> result num-items))))
|
|
(set! (-> v1-5 mesh) (-> obj mesh))
|
|
(set! (-> v1-5 inst) #f) ;; non-instanced.
|
|
)
|
|
(+! (-> result num-items) 1))
|
|
(&+! obj 32))
|
|
0
|
|
(none))
|
|
|
|
(defmethod collide-ray ((obj instance-tie) (count int) (result collide-list))
|
|
"Inline-array function to do line-sphere with TIE instances.
|
|
If the bsphere of the mesh is in the non-aligned bounding box, the mesh will be added
|
|
to the given collide-list.
|
|
Note: collide-probe is the faster implementation of this."
|
|
;; loop over instance-ties
|
|
(dotimes (s3-0 count)
|
|
;; first check the instance-tie's bsphere
|
|
(when (and (zero? (logand (-> obj flags) 1)) (collide-cache-using-line-sphere-test (-> obj bsphere)))
|
|
;; now, find the collide-frag
|
|
(let ((s2-0 (-> obj bucket-ptr collide-frag)))
|
|
(when (nonzero? s2-0)
|
|
(let ((s1-0 (the-as object (-> s2-0 data))))
|
|
;; and check each mesh in the collide-frag
|
|
(dotimes (s0-0 (-> s2-0 length))
|
|
(when (make-collide-list-using-line-sphere-inst-test (the-as collide-fragment s1-0) obj)
|
|
(let ((v1-10 (-> result items (-> result num-items))))
|
|
(set! (-> v1-10 mesh) (-> (the-as collide-fragment s1-0) mesh))
|
|
(set! (-> v1-10 inst) obj))
|
|
(+! (-> result num-items) 1))
|
|
(set! s1-0 (-> (the-as (inline-array collide-fragment) s1-0) 1)))))))
|
|
(&+! obj 64))
|
|
0
|
|
(none))
|
|
|
|
;;;;;;;;;;;;;;;;;;;
|
|
;; foreground box
|
|
;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; for an unknown reason, the goal compiler went insane on this function
|
|
|
|
(defmethod fill-from-foreground-using-box ((obj collide-cache))
|
|
"Walk the requested foreground connection lists and add compatible primitives whose world bounds
|
|
overlap the active box query, excluding the querying process."
|
|
(local-vars
|
|
(zero uint128)
|
|
(v1-2 uint128)
|
|
(v1-15 uint128)
|
|
(v1-18 uint128)
|
|
(v1-31 uint128)
|
|
(v1-44 uint128)
|
|
(a1-1 uint128)
|
|
(a1-6 uint128)
|
|
(a1-11 uint128)
|
|
(a1-16 uint128)
|
|
(a2-0 uint128)
|
|
(a2-1 uint128)
|
|
(a2-2 uint128)
|
|
(a2-3 uint128)
|
|
(a2-5 uint128)
|
|
(a2-6 uint128)
|
|
(a2-7 uint128)
|
|
(a2-8 uint128)
|
|
(a2-10 uint128)
|
|
(a2-11 uint128)
|
|
(a2-12 uint128)
|
|
(a2-13 uint128)
|
|
(a2-15 uint128)
|
|
(a2-16 uint128)
|
|
(a2-17 uint128)
|
|
(a2-18 uint128)
|
|
(a3-0 uint128)
|
|
(a3-1 uint128)
|
|
(a3-2 uint128)
|
|
(a3-3 uint128)
|
|
(a3-4 uint128)
|
|
(a3-5 uint128)
|
|
(a3-6 uint128)
|
|
(a3-7 uint128)
|
|
(f31-0 none))
|
|
(rlet ((vf1 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf))
|
|
(set! zero (the-as uint128 0))
|
|
(let ((s5-0 (the-as uint128 (-> obj collide-with)))
|
|
(s4-0 (-> obj collide-box4w min quad))
|
|
(s3-0 (-> obj collide-box4w max quad)))
|
|
(let ((v1-1 (the-as uint128 (make-u128 0 16)))) (.pand v1-2 v1-1 s5-0))
|
|
(when (nonzero? (the-as int v1-2))
|
|
(iterate-engine-connections (v1-5 *collide-player-list*)
|
|
(let* ((v1-6 (the-as collide-shape (-> (the-as connection v1-5) param1)))
|
|
(a0-3 (-> v1-6 root-prim)))
|
|
(let ((a1-0 (the-as uint128 (-> a0-3 prim-core collide-as)))) (.pand a1-1 s5-0 a1-0))
|
|
(b! (zero? (the-as int a1-1)) cfg-7)
|
|
(nop!)
|
|
(.lvf vf1 (&-> a0-3 prim-core world-sphere quad))
|
|
(.sub.w.vf vf2 vf1 vf1)
|
|
(nop!)
|
|
(.add.w.vf vf3 vf1 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-0 vf4)
|
|
(let ((v1-7 (-> v1-6 process)))
|
|
(.mov a3-0 vf5)
|
|
(let ((a1-3 (-> obj proc)))
|
|
(.pcgtw a2-1 a2-0 s3-0)
|
|
(.pcgtw a3-1 s4-0 a3-0)
|
|
(.por a2-2 a2-1 a3-1)
|
|
(.ppach a2-3 zero a2-2)
|
|
(let ((a2-4 (shl (the-as int a2-3) 16))) (nop!) (b! (nonzero? a2-4) cfg-6 :delay (nop!)))
|
|
(b! (= a1-3 v1-7) cfg-6 :delay (nop!))))
|
|
(add-fg-prim-using-box a0-3 obj))
|
|
(label cfg-6)
|
|
0
|
|
(label cfg-7)))
|
|
(let ((v1-14 (the-as uint128 (make-u128 0 14)))) (.pand v1-15 v1-14 s5-0))
|
|
(when (nonzero? (the-as int v1-15))
|
|
(let ((v1-17 (the-as uint128 (make-u128 0 2)))) (.pand v1-18 v1-17 s5-0))
|
|
(when (nonzero? (the-as int v1-18))
|
|
(iterate-engine-connections (v1-21 *collide-hit-by-player-list*)
|
|
(let* ((v1-22 (the-as collide-shape (-> (the-as connection v1-21) param1)))
|
|
(a0-10 (-> v1-22 root-prim)))
|
|
(let ((a1-5 (the-as uint128 (-> a0-10 prim-core collide-as)))) (.pand a1-6 s5-0 a1-5))
|
|
(b! (zero? (the-as int a1-6)) cfg-18)
|
|
(nop!)
|
|
(.lvf vf1 (&-> a0-10 prim-core world-sphere quad))
|
|
(.sub.w.vf vf2 vf1 vf1)
|
|
(nop!)
|
|
(.add.w.vf vf3 vf1 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-5 vf4)
|
|
(let ((v1-23 (-> v1-22 process)))
|
|
(.mov a3-2 vf5)
|
|
(let ((a1-8 (-> obj proc)))
|
|
(.pcgtw a2-6 a2-5 s3-0)
|
|
(.pcgtw a3-3 s4-0 a3-2)
|
|
(.por a2-7 a2-6 a3-3)
|
|
(.ppach a2-8 zero a2-7)
|
|
(let ((a2-9 (shl (the-as int a2-8) 16))) (nop!) (b! (nonzero? a2-9) cfg-17 :delay (nop!)))
|
|
(b! (= a1-8 v1-23) cfg-17 :delay (nop!))))
|
|
(add-fg-prim-using-box a0-10 obj))
|
|
(label cfg-17)
|
|
0
|
|
(label cfg-18)))
|
|
(let ((v1-30 (the-as uint128 (make-u128 0 4)))) (.pand v1-31 v1-30 s5-0))
|
|
(when (nonzero? (the-as int v1-31))
|
|
(iterate-engine-connections (v1-34 *collide-usually-hit-by-player-list*)
|
|
(let* ((v1-35 (the-as collide-shape (-> (the-as connection v1-34) param1)))
|
|
(a0-17 (-> v1-35 root-prim)))
|
|
(let ((a1-10 (the-as uint128 (-> a0-17 prim-core collide-as)))) (.pand a1-11 s5-0 a1-10))
|
|
(b! (zero? (the-as int a1-11)) cfg-28)
|
|
(nop!)
|
|
(nop!)
|
|
(.lvf vf1 (&-> a0-17 prim-core world-sphere quad))
|
|
(.sub.w.vf vf2 vf1 vf1)
|
|
(nop!)
|
|
(.add.w.vf vf3 vf1 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-10 vf4)
|
|
(let ((v1-36 (-> v1-35 process)))
|
|
(.mov a3-4 vf5)
|
|
(let ((a1-13 (-> obj proc)))
|
|
(.pcgtw a2-11 a2-10 s3-0)
|
|
(.pcgtw a3-5 s4-0 a3-4)
|
|
(.por a2-12 a2-11 a3-5)
|
|
(.ppach a2-13 zero a2-12)
|
|
(let ((a2-14 (shl (the-as int a2-13) 16))) (nop!) (b! (nonzero? a2-14) cfg-27 :delay (nop!)))
|
|
(b! (= a1-13 v1-36) cfg-27 :delay (nop!))))
|
|
(add-fg-prim-using-box a0-17 obj))
|
|
(label cfg-27)
|
|
0
|
|
(label cfg-28)))
|
|
(let ((v1-43 (the-as uint128 (make-u128 0 8)))) (.pand v1-44 v1-43 s5-0))
|
|
(when (nonzero? (the-as int v1-44))
|
|
(iterate-engine-connections (v1-46 *collide-hit-by-others-list*)
|
|
(let* ((v1-47 (the-as collide-shape (-> (the-as connection v1-46) param1)))
|
|
(a0-24 (-> v1-47 root-prim)))
|
|
(let ((a1-15 (the-as uint128 (-> a0-24 prim-core collide-as)))) (.pand a1-16 s5-0 a1-15))
|
|
(b! (zero? (the-as int a1-16)) cfg-38)
|
|
(nop!)
|
|
(nop!)
|
|
(.lvf vf1 (&-> a0-24 prim-core world-sphere quad))
|
|
(.sub.w.vf vf2 vf1 vf1)
|
|
(nop!)
|
|
(.add.w.vf vf3 vf1 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-15 vf4)
|
|
(let ((v1-48 (-> v1-47 process)))
|
|
(.mov a3-6 vf5)
|
|
(let ((a1-18 (-> obj proc)))
|
|
(.pcgtw a2-16 a2-15 s3-0)
|
|
(.pcgtw a3-7 s4-0 a3-6)
|
|
(.por a2-17 a2-16 a3-7)
|
|
(.ppach a2-18 zero a2-17)
|
|
(let ((a2-19 (shl (the-as int a2-18) 16))) (nop!) (b! (nonzero? a2-19) cfg-37 :delay (nop!)))
|
|
(b! (= a1-18 v1-48) cfg-37 :delay (nop!))))
|
|
(add-fg-prim-using-box a0-24 obj))
|
|
(label cfg-37)
|
|
0
|
|
(label cfg-38)))))
|
|
(none)))
|
|
|
|
(defmethod add-fg-prim-using-box ((obj collide-shape-prim) (cache collide-cache))
|
|
"Add this primitive to the active box query. Sphere leaves are copied into the cache, mesh leaves
|
|
import their overlapping triangles, groups recurse through compatible children, and the base
|
|
implementation reports an invalid primitive type."
|
|
(format 0 "ERROR: Illegal collide-shape-prim type passed to collide-shape-prim::add-fg-prim-using-box!~%")
|
|
(none))
|
|
|
|
(defmethod add-fg-prim-using-box ((obj collide-shape-prim-sphere) (cache collide-cache))
|
|
"Add this primitive to the active box query. Sphere leaves are copied into the cache, mesh leaves
|
|
import their overlapping triangles, groups recurse through compatible children, and the base
|
|
implementation reports an invalid primitive type."
|
|
(local-vars (t1-1 uint))
|
|
(nop!)
|
|
(let* ((t0-0 (-> cache prims))
|
|
(a3-0 (-> cache num-prims-u))
|
|
(t1-0 100)
|
|
(v1-0 (-> obj prim-core world-sphere quad))
|
|
(t2-0 (* a3-0 2))
|
|
(a2-0 (-> obj prim-core quad 1)))
|
|
(b! (= a3-0 t1-0) cfg-2 :delay (set! t1-1 (+ t2-0 a3-0)))
|
|
(let ((t0-1 (the-as object (&-> t0-0 0 prim-core quad t1-1))))
|
|
(let ((a3-1 (+ a3-0 1)))
|
|
(set! (-> (the-as (pointer uint128) t0-1) 2) (the-as uint128 0))
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) prim) obj)
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) prim-core world-sphere quad) v1-0)
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) prim-core quad 1) a2-0)
|
|
(nop!)
|
|
(set! (-> cache num-prims) (the-as int a3-1)))
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) ccache) cache)))
|
|
(b! #t cfg-3 :delay (nop!))
|
|
(label cfg-2)
|
|
(format 0 "ERROR: Exceeded max number of collide-cache prims!~%")
|
|
(label cfg-3)
|
|
(none))
|
|
|
|
(defmethod add-fg-prim-using-box ((obj collide-shape-prim-group) (cache collide-cache))
|
|
"Add this primitive to the active box query. Sphere leaves are copied into the cache, mesh leaves
|
|
import their overlapping triangles, groups recurse through compatible children, and the base
|
|
implementation reports an invalid primitive type."
|
|
(local-vars
|
|
(zero uint128)
|
|
(v1-2 uint128)
|
|
(v1-3 uint128)
|
|
(v1-4 uint128)
|
|
(v1-5 uint128)
|
|
(a0-1 collide-shape-prim)
|
|
(a1-1 uint128)
|
|
(a1-2 uint128))
|
|
(set! zero (the-as uint128 0))
|
|
(rlet ((vf1 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf))
|
|
(nop!)
|
|
(let ((s5-0 (-> obj prims))
|
|
(s4-0 (-> obj num-prims-u)))
|
|
(nop!)
|
|
(let ((s3-0 (-> cache collide-box4w min quad)))
|
|
(nop!)
|
|
(let ((s2-0 (-> cache collide-box4w max quad)))
|
|
(nop!)
|
|
(let ((s1-0 (-> s5-0 0)))
|
|
(nop!)
|
|
(let ((s0-0 (-> cache collide-with)))
|
|
(label cfg-1)
|
|
(b! (zero? s4-0) cfg-5 :delay (set! a0-1 s1-0))
|
|
(label cfg-2)
|
|
(+! s4-0 -1)
|
|
(.lvf vf1 (&-> a0-1 prim-core world-sphere quad))
|
|
(nop!)
|
|
(let ((v1-0 (-> a0-1 prim-core collide-as)))
|
|
(.sub.w.vf vf2 vf1 vf1)
|
|
(set! s5-0 (&-> s5-0 1))
|
|
(.add.w.vf vf3 vf1 vf1)
|
|
(set! s1-0 (-> s5-0 0))
|
|
(let ((v1-1 (logand s0-0 v1-0))) (nop!) (b! (zero? v1-1) cfg-1 :delay (nop!)))))
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a1-1 vf4)
|
|
(nop!)
|
|
(.mov v1-2 vf5)
|
|
(nop!)
|
|
(.pcgtw a1-2 a1-1 s2-0)
|
|
(.pcgtw v1-3 s3-0 v1-2)
|
|
(.por v1-4 a1-2 v1-3)
|
|
(.ppach v1-5 zero v1-4)
|
|
(let ((v1-6 (shl (the-as int v1-5) 16))) (nop!) (b! (nonzero? v1-6) cfg-1 :delay (nop!)))
|
|
(add-fg-prim-using-box a0-1 cache)
|
|
(b! (nonzero? s4-0) cfg-2 :delay (set! a0-1 s1-0))))))
|
|
(label cfg-5)
|
|
0
|
|
(none)))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Foreground Y PROBE
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defmethod fill-from-foreground-using-y-probe ((obj collide-cache))
|
|
"Walk the requested foreground connection lists and add compatible primitives whose world bounds
|
|
overlap the active vertical probe, excluding the querying process."
|
|
(local-vars
|
|
(zero uint128)
|
|
(v1-2 uint128)
|
|
(v1-15 uint128)
|
|
(v1-18 uint128)
|
|
(v1-31 uint128)
|
|
(v1-44 uint128)
|
|
(a1-1 uint128)
|
|
(a1-6 uint128)
|
|
(a1-11 uint128)
|
|
(a1-16 uint128)
|
|
(a2-0 uint128)
|
|
(a2-1 uint128)
|
|
(a2-2 uint128)
|
|
(a2-3 uint128)
|
|
(a2-5 uint128)
|
|
(a2-6 uint128)
|
|
(a2-7 uint128)
|
|
(a2-8 uint128)
|
|
(a2-10 uint128)
|
|
(a2-11 uint128)
|
|
(a2-12 uint128)
|
|
(a2-13 uint128)
|
|
(a2-15 uint128)
|
|
(a2-16 uint128)
|
|
(a2-17 uint128)
|
|
(a2-18 uint128)
|
|
(a3-0 uint128)
|
|
(a3-1 uint128)
|
|
(a3-2 uint128)
|
|
(a3-3 uint128)
|
|
(a3-4 uint128)
|
|
(a3-5 uint128)
|
|
(a3-6 uint128)
|
|
(a3-7 uint128))
|
|
(set! zero (the uint128 0))
|
|
(rlet ((vf1 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf))
|
|
(let ((s5-0 (the-as uint128 (-> obj collide-with)))
|
|
(s4-0 (-> obj collide-box4w min quad))
|
|
(s3-0 (-> obj collide-box4w max quad)))
|
|
(let ((v1-1 (the-as uint128 (make-u128 0 16)))) (.pand v1-2 v1-1 s5-0))
|
|
(when (nonzero? (the-as int v1-2))
|
|
(iterate-engine-connections (v1-5 *collide-player-list*)
|
|
(let* ((v1-6 (the-as collide-shape (-> (the-as connection v1-5) param1)))
|
|
(a0-3 (-> v1-6 root-prim)))
|
|
(let ((a1-0 (the-as uint128 (-> a0-3 prim-core collide-as)))) (.pand a1-1 s5-0 a1-0))
|
|
(b! (zero? (the-as int a1-1)) cfg-7)
|
|
(.lvf vf1 (&-> a0-3 prim-core world-sphere quad))
|
|
(.sub.w.vf vf2 vf1 vf1)
|
|
(.add.w.vf vf3 vf1 vf1)
|
|
(.ftoi.vf vf4 vf2)
|
|
(.ftoi.vf vf5 vf3)
|
|
(.mov a2-0 vf4)
|
|
(let ((v1-7 (-> v1-6 process)))
|
|
(.mov a3-0 vf5)
|
|
(let ((a1-3 (-> obj proc)))
|
|
(.pcgtw a2-1 a2-0 s3-0)
|
|
(.pcgtw a3-1 s4-0 a3-0)
|
|
(.por a2-2 a2-1 a3-1)
|
|
(.ppach a2-3 zero a2-2)
|
|
(let ((a2-4 (shl (the-as int a2-3) 16))) (nop!) (b! (nonzero? a2-4) cfg-6 :delay (nop!)))
|
|
(b! (= a1-3 v1-7) cfg-6 :delay (nop!))))
|
|
(add-fg-prim-using-y-probe a0-3 obj))
|
|
(label cfg-6)
|
|
0
|
|
(label cfg-7)))
|
|
(let ((v1-14 (the-as uint128 (make-u128 0 14)))) (.pand v1-15 v1-14 s5-0))
|
|
(when (nonzero? (the-as int v1-15))
|
|
(let ((v1-17 (the-as uint128 (make-u128 0 2)))) (.pand v1-18 v1-17 s5-0))
|
|
(when (nonzero? (the-as int v1-18))
|
|
(iterate-engine-connections (v1-21 *collide-hit-by-player-list*)
|
|
(let* ((v1-22 (the-as collide-shape (-> (the-as connection v1-21) param1)))
|
|
(a0-10 (-> v1-22 root-prim)))
|
|
(let ((a1-5 (the-as uint128 (-> a0-10 prim-core collide-as)))) (.pand a1-6 s5-0 a1-5))
|
|
(b! (zero? (the-as int a1-6)) cfg-18)
|
|
(nop!)
|
|
(.lvf vf1 (&-> a0-10 prim-core world-sphere quad))
|
|
(.sub.w.vf vf2 vf1 vf1)
|
|
(nop!)
|
|
(.add.w.vf vf3 vf1 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-5 vf4)
|
|
(let ((v1-23 (-> v1-22 process)))
|
|
(.mov a3-2 vf5)
|
|
(let ((a1-8 (-> obj proc)))
|
|
(.pcgtw a2-6 a2-5 s3-0)
|
|
(.pcgtw a3-3 s4-0 a3-2)
|
|
(.por a2-7 a2-6 a3-3)
|
|
(.ppach a2-8 zero a2-7)
|
|
(let ((a2-9 (shl (the-as int a2-8) 16))) (nop!) (b! (nonzero? a2-9) cfg-17 :delay (nop!)))
|
|
(b! (= a1-8 v1-23) cfg-17 :delay (nop!))))
|
|
(add-fg-prim-using-y-probe a0-10 obj))
|
|
(label cfg-17)
|
|
0
|
|
(label cfg-18)))
|
|
(let ((v1-30 (the-as uint128 (make-u128 0 4)))) (.pand v1-31 v1-30 s5-0))
|
|
(when (nonzero? (the-as int v1-31))
|
|
(iterate-engine-connections (v1-34 *collide-usually-hit-by-player-list*)
|
|
(let* ((v1-35 (the-as collide-shape (-> (the-as connection v1-34) param1)))
|
|
(a0-17 (-> v1-35 root-prim)))
|
|
(let ((a1-10 (the-as uint128 (-> a0-17 prim-core collide-as)))) (.pand a1-11 s5-0 a1-10))
|
|
(b! (zero? (the-as int a1-11)) cfg-28)
|
|
(nop!)
|
|
(nop!)
|
|
(.lvf vf1 (&-> a0-17 prim-core world-sphere quad))
|
|
(.sub.w.vf vf2 vf1 vf1)
|
|
(nop!)
|
|
(.add.w.vf vf3 vf1 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-10 vf4)
|
|
(let ((v1-36 (-> v1-35 process)))
|
|
(.mov a3-4 vf5)
|
|
(let ((a1-13 (-> obj proc)))
|
|
(.pcgtw a2-11 a2-10 s3-0)
|
|
(.pcgtw a3-5 s4-0 a3-4)
|
|
(.por a2-12 a2-11 a3-5)
|
|
(.ppach a2-13 zero a2-12)
|
|
(let ((a2-14 (shl (the-as int a2-13) 16))) (nop!) (b! (nonzero? a2-14) cfg-27 :delay (nop!)))
|
|
(b! (= a1-13 v1-36) cfg-27 :delay (nop!))))
|
|
(add-fg-prim-using-y-probe a0-17 obj))
|
|
(label cfg-27)
|
|
0
|
|
(label cfg-28)))
|
|
(let ((v1-43 (the-as uint128 (make-u128 0 8)))) (.pand v1-44 v1-43 s5-0))
|
|
(when (nonzero? (the-as int v1-44))
|
|
(iterate-engine-connections (v1-46 *collide-hit-by-others-list*)
|
|
(let* ((v1-47 (the-as collide-shape (-> (the-as connection v1-46) param1)))
|
|
(a0-24 (-> v1-47 root-prim)))
|
|
(let ((a1-15 (the-as uint128 (-> a0-24 prim-core collide-as)))) (.pand a1-16 s5-0 a1-15))
|
|
(b! (zero? (the-as int a1-16)) cfg-38)
|
|
(nop!)
|
|
(nop!)
|
|
(.lvf vf1 (&-> a0-24 prim-core world-sphere quad))
|
|
(.sub.w.vf vf2 vf1 vf1)
|
|
(nop!)
|
|
(.add.w.vf vf3 vf1 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-15 vf4)
|
|
(let ((v1-48 (-> v1-47 process)))
|
|
(.mov a3-6 vf5)
|
|
(let ((a1-18 (-> obj proc)))
|
|
(.pcgtw a2-16 a2-15 s3-0)
|
|
(.pcgtw a3-7 s4-0 a3-6)
|
|
(.por a2-17 a2-16 a3-7)
|
|
(.ppach a2-18 zero a2-17)
|
|
(let ((a2-19 (shl (the-as int a2-18) 16))) (nop!) (b! (nonzero? a2-19) cfg-37 :delay (nop!)))
|
|
(b! (= a1-18 v1-48) cfg-37 :delay (nop!))))
|
|
(add-fg-prim-using-y-probe a0-24 obj))
|
|
(label cfg-37)
|
|
0
|
|
(label cfg-38)))))
|
|
(none)))
|
|
|
|
(defmethod add-fg-prim-using-y-probe ((obj collide-shape-prim) (cache collide-cache))
|
|
"Add this primitive to the active vertical-probe query. Sphere leaves are copied into the cache,
|
|
mesh leaves import their overlapping triangles, groups recurse through compatible children, and
|
|
the base implementation reports an invalid primitive type."
|
|
(format 0 "ERROR: Illegal collide-shape-prim type passed to collide-shape-prim::add-fg-prim-using-y-probe!~%")
|
|
(none))
|
|
|
|
(defmethod add-fg-prim-using-y-probe ((obj collide-shape-prim-sphere) (cache collide-cache))
|
|
"Add this primitive to the active vertical-probe query. Sphere leaves are copied into the cache,
|
|
mesh leaves import their overlapping triangles, groups recurse through compatible children, and
|
|
the base implementation reports an invalid primitive type."
|
|
(local-vars (t1-1 uint))
|
|
(nop!)
|
|
(let* ((t0-0 (-> cache prims))
|
|
(a3-0 (-> cache num-prims-u))
|
|
(t1-0 100)
|
|
(v1-0 (-> obj prim-core world-sphere quad))
|
|
(t2-0 (* a3-0 2))
|
|
(a2-0 (-> obj prim-core quad 1)))
|
|
(b! (= a3-0 t1-0) cfg-2 :delay (set! t1-1 (+ t2-0 a3-0)))
|
|
(let ((t0-1 (the-as object (&-> t0-0 0 prim-core quad t1-1))))
|
|
(let ((a3-1 (+ a3-0 1)))
|
|
(set! (-> (the-as collide-cache-prim t0-1) extra-quad) (the-as uint128 0))
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) prim) obj)
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) prim-core world-sphere quad) v1-0)
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) prim-core quad 1) a2-0)
|
|
(nop!)
|
|
(set! (-> cache num-prims) (the-as int a3-1)))
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) ccache) cache)))
|
|
(b! #t cfg-3 :delay (nop!))
|
|
(label cfg-2)
|
|
(format 0 "ERROR: Exceeded max number of collide-cache prims!~%")
|
|
(label cfg-3)
|
|
(none))
|
|
|
|
(defmethod add-fg-prim-using-y-probe ((obj collide-shape-prim-group) (cache collide-cache))
|
|
"Add this primitive to the active vertical-probe query. Sphere leaves are copied into the cache,
|
|
mesh leaves import their overlapping triangles, groups recurse through compatible children, and
|
|
the base implementation reports an invalid primitive type."
|
|
(local-vars
|
|
(r0-0 int)
|
|
(r0-1 int)
|
|
(r0-2 uint128)
|
|
(r0-3 int)
|
|
(v1-2 uint128)
|
|
(v1-3 uint128)
|
|
(v1-4 uint128)
|
|
(v1-5 uint128)
|
|
(a0-1 collide-shape-prim)
|
|
(a1-1 uint128)
|
|
(a1-2 uint128)
|
|
(f31-0 none))
|
|
(rlet ((vf1 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf))
|
|
(nop!)
|
|
(let ((s5-0 (-> obj prims))
|
|
(s4-0 (-> obj num-prims-u)))
|
|
(nop!)
|
|
(let ((s3-0 (-> cache collide-box4w min quad)))
|
|
(nop!)
|
|
(let ((s2-0 (-> cache collide-box4w max quad)))
|
|
(nop!)
|
|
(let ((s1-0 (-> s5-0 0)))
|
|
(nop!)
|
|
(let ((s0-0 (-> cache collide-with)))
|
|
(label cfg-1)
|
|
(b! (zero? s4-0) cfg-5 :delay (set! a0-1 s1-0))
|
|
(label cfg-2)
|
|
(+! s4-0 -1)
|
|
(.lvf vf1 (&-> a0-1 prim-core world-sphere quad))
|
|
(nop!)
|
|
(let ((v1-0 (-> a0-1 prim-core collide-as)))
|
|
(.sub.w.vf vf2 vf1 vf1)
|
|
(set! s5-0 (&-> s5-0 1))
|
|
(.add.w.vf vf3 vf1 vf1)
|
|
(set! s1-0 (-> s5-0 0))
|
|
(let ((v1-1 (logand s0-0 v1-0))) (nop!) (b! (zero? v1-1) cfg-1 :delay (nop!)))))
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a1-1 vf4)
|
|
(nop!)
|
|
(.mov v1-2 vf5)
|
|
(nop!)
|
|
(.pcgtw a1-2 a1-1 s2-0)
|
|
(.mov r0-0 f31-0)
|
|
(.pcgtw v1-3 s3-0 v1-2)
|
|
(.mov r0-1 f31-0)
|
|
(.por v1-4 a1-2 v1-3)
|
|
(.mov r0-2 f31-0)
|
|
(.ppach v1-5 r0-2 v1-4)
|
|
(.mov r0-3 f31-0)
|
|
(let ((v1-6 (shl (the-as int v1-5) 16))) (nop!) (b! (nonzero? v1-6) cfg-1 :delay (nop!)))
|
|
(add-fg-prim-using-y-probe a0-1 cache)
|
|
(b! (nonzero? s4-0) cfg-2 :delay (set! a0-1 s1-0))))))
|
|
(label cfg-5)
|
|
0
|
|
(none)))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; foreground Line Sphere
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; Host calls do not preserve the four VU registers holding the swept-query transform.
|
|
(#when PC_PORT
|
|
(deftype pc-fffuls-work (structure)
|
|
((reg-vf28 vector :inline)
|
|
(reg-vf29 vector :inline)
|
|
(reg-vf30 vector :inline)
|
|
(reg-vf31 vector :inline)))
|
|
(define *pc-fffuls-work* (new 'global 'pc-fffuls-work))
|
|
(defmacro save-fffuls-work ()
|
|
`(begin
|
|
(.svf (&-> *pc-fffuls-work* reg-vf31 quad) vf31)
|
|
(.svf (&-> *pc-fffuls-work* reg-vf30 quad) vf30)
|
|
(.svf (&-> *pc-fffuls-work* reg-vf29 quad) vf29)
|
|
(.svf (&-> *pc-fffuls-work* reg-vf28 quad) vf28)))
|
|
(defmacro load-fffuls-work ()
|
|
`(begin
|
|
(.lvf vf28 (&-> *pc-fffuls-work* reg-vf28 quad))
|
|
(.lvf vf29 (&-> *pc-fffuls-work* reg-vf29 quad))
|
|
(.lvf vf30 (&-> *pc-fffuls-work* reg-vf30 quad))
|
|
(.lvf vf31 (&-> *pc-fffuls-work* reg-vf31 quad)))))
|
|
|
|
(defmethod fill-from-foreground-using-line-sphere ((obj collide-cache))
|
|
"Walk the requested foreground connection lists and add compatible primitives whose world bounds
|
|
overlap the active oriented swept-sphere box, excluding the querying process."
|
|
(local-vars
|
|
(zero uint128)
|
|
(v1-1 float)
|
|
(v1-4 uint128)
|
|
(v1-17 uint128)
|
|
(v1-20 uint128)
|
|
(v1-33 uint128)
|
|
(v1-46 uint128)
|
|
(a1-1 uint128)
|
|
(a1-6 uint128)
|
|
(a1-11 uint128)
|
|
(a1-16 uint128)
|
|
(a2-0 uint128)
|
|
(a2-1 uint128)
|
|
(a2-2 uint128)
|
|
(a2-3 uint128)
|
|
(a2-5 uint128)
|
|
(a2-6 uint128)
|
|
(a2-7 uint128)
|
|
(a2-8 uint128)
|
|
(a2-10 uint128)
|
|
(a2-11 uint128)
|
|
(a2-12 uint128)
|
|
(a2-13 uint128)
|
|
(a2-15 uint128)
|
|
(a2-16 uint128)
|
|
(a2-17 uint128)
|
|
(a2-18 uint128)
|
|
(a3-0 uint128)
|
|
(a3-1 uint128)
|
|
(a3-2 uint128)
|
|
(a3-3 uint128)
|
|
(a3-4 uint128)
|
|
(a3-5 uint128)
|
|
(a3-6 uint128)
|
|
(a3-7 uint128)
|
|
(f31-0 none))
|
|
(rlet ((acc :class vf)
|
|
(vf0 :class vf)
|
|
(vf1 :class vf)
|
|
(vf2 :class vf)
|
|
(vf28 :class vf)
|
|
(vf29 :class vf)
|
|
(vf3 :class vf)
|
|
(vf30 :class vf)
|
|
(vf31 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf)
|
|
(vf6 :class vf))
|
|
(init-vf0-vector)
|
|
(set! zero (the uint128 0))
|
|
(let* ((v1-0 *collide-work*)
|
|
(s5-0 (-> v1-0 collide-box4w min quad))
|
|
(s4-0 (-> v1-0 collide-box4w max quad))
|
|
(s3-0 (the-as uint128 (-> obj collide-with))))
|
|
(.lvf vf28 (&-> v1-0 inv-mat vector 0 quad))
|
|
(.lvf vf29 (&-> v1-0 inv-mat vector 1 quad))
|
|
(.lvf vf30 (&-> v1-0 inv-mat vector 2 quad))
|
|
(.lvf vf31 (&-> v1-0 inv-mat vector 3 quad))
|
|
(#when PC_PORT
|
|
(save-fffuls-work))
|
|
(.mov v1-1 vf31)
|
|
(let ((v1-3 (the-as uint128 (make-u128 0 16)))) (.pand v1-4 v1-3 s3-0))
|
|
(when (nonzero? (the-as int v1-4))
|
|
(iterate-engine-connections (v1-7 *collide-player-list*)
|
|
(let* ((v1-8 (the-as collide-shape (-> (the-as connection v1-7) param1)))
|
|
(a0-3 (-> v1-8 root-prim)))
|
|
(let ((a1-0 (the-as uint128 (-> a0-3 prim-core collide-as)))) (.pand a1-1 s3-0 a1-0))
|
|
(b! (zero? (the-as int a1-1)) cfg-7)
|
|
(.mul.w.vf acc vf31 vf0)
|
|
(.lvf vf1 (&-> a0-3 prim-core world-sphere quad))
|
|
(.add.mul.x.vf acc vf28 vf1 acc)
|
|
(nop!)
|
|
(.add.mul.y.vf acc vf29 vf1 acc)
|
|
(nop!)
|
|
(.add.mul.z.vf vf6 vf30 vf1 acc)
|
|
(nop!)
|
|
(.sub.w.vf.xyz vf2 vf6 vf1)
|
|
(nop!)
|
|
(.add.w.vf.xyz vf3 vf6 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-0 vf4)
|
|
(let ((v1-9 (-> v1-8 process)))
|
|
(.mov a3-0 vf5)
|
|
(let ((a1-3 (-> obj proc)))
|
|
(.pcgtw a2-1 a2-0 s4-0)
|
|
(.pcgtw a3-1 s5-0 a3-0)
|
|
(.por a2-2 a2-1 a3-1)
|
|
(.ppach a2-3 zero a2-2)
|
|
(let ((a2-4 (shl (the-as int a2-3) 16))) (nop!) (b! (nonzero? a2-4) cfg-6 :delay (nop!)))
|
|
(b! (= a1-3 v1-9) cfg-6 :delay (nop!))))
|
|
(add-fg-prim-using-line-sphere a0-3 obj))
|
|
(label cfg-6)
|
|
0
|
|
(label cfg-7)))
|
|
(let ((v1-16 (the-as uint128 (make-u128 0 14)))) (.pand v1-17 v1-16 s3-0))
|
|
(when (nonzero? (the-as int v1-17))
|
|
(let ((v1-19 (the-as uint128 (make-u128 0 2)))) (.pand v1-20 v1-19 s3-0))
|
|
(when (nonzero? (the-as int v1-20))
|
|
(iterate-engine-connections (v1-23 *collide-hit-by-player-list*)
|
|
(let* ((v1-24 (the-as collide-shape (-> (the-as connection v1-23) param1)))
|
|
(a0-10 (-> v1-24 root-prim)))
|
|
(let ((a1-5 (the-as uint128 (-> a0-10 prim-core collide-as)))) (.pand a1-6 s3-0 a1-5))
|
|
(b! (zero? (the-as int a1-6)) cfg-18)
|
|
(.mul.w.vf acc vf31 vf0)
|
|
(.lvf vf1 (&-> a0-10 prim-core world-sphere quad))
|
|
(.add.mul.x.vf acc vf28 vf1 acc)
|
|
(nop!)
|
|
(.add.mul.y.vf acc vf29 vf1 acc)
|
|
(nop!)
|
|
(.add.mul.z.vf vf6 vf30 vf1 acc)
|
|
(nop!)
|
|
(.sub.w.vf.xyz vf2 vf6 vf1)
|
|
(nop!)
|
|
(.add.w.vf.xyz vf3 vf6 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-5 vf4)
|
|
(let ((v1-25 (-> v1-24 process)))
|
|
(.mov a3-2 vf5)
|
|
(let ((a1-8 (-> obj proc)))
|
|
(.pcgtw a2-6 a2-5 s4-0)
|
|
(.pcgtw a3-3 s5-0 a3-2)
|
|
(.por a2-7 a2-6 a3-3)
|
|
(.ppach a2-8 zero a2-7)
|
|
(let ((a2-9 (shl (the-as int a2-8) 16))) (nop!) (b! (nonzero? a2-9) cfg-17 :delay (nop!)))
|
|
(b! (= a1-8 v1-25) cfg-17 :delay (nop!))))
|
|
(add-fg-prim-using-line-sphere a0-10 obj))
|
|
(label cfg-17)
|
|
0
|
|
(label cfg-18)))
|
|
(let ((v1-32 (the-as uint128 (make-u128 0 4)))) (.pand v1-33 v1-32 s3-0))
|
|
(when (nonzero? (the-as int v1-33))
|
|
(iterate-engine-connections (v1-36 *collide-usually-hit-by-player-list*)
|
|
(let* ((v1-37 (the-as collide-shape (-> (the-as connection v1-36) param1)))
|
|
(a0-17 (-> v1-37 root-prim)))
|
|
(let ((a1-10 (the-as uint128 (-> a0-17 prim-core collide-as)))) (.pand a1-11 s3-0 a1-10))
|
|
(b! (zero? (the-as int a1-11)) cfg-28)
|
|
(nop!)
|
|
(.mul.w.vf acc vf31 vf0)
|
|
(.lvf vf1 (&-> a0-17 prim-core world-sphere quad))
|
|
(.add.mul.x.vf acc vf28 vf1 acc)
|
|
(nop!)
|
|
(.add.mul.y.vf acc vf29 vf1 acc)
|
|
(nop!)
|
|
(.add.mul.z.vf vf6 vf30 vf1 acc)
|
|
(nop!)
|
|
(.sub.w.vf.xyz vf2 vf6 vf1)
|
|
(nop!)
|
|
(.add.w.vf.xyz vf3 vf6 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-10 vf4)
|
|
(let ((v1-38 (the-as basic (-> v1-37 process))))
|
|
(.mov a3-4 vf5)
|
|
(let ((a1-13 (-> obj proc)))
|
|
(.pcgtw a2-11 a2-10 s4-0)
|
|
(.pcgtw a3-5 s5-0 a3-4)
|
|
(.por a2-12 a2-11 a3-5)
|
|
(.ppach a2-13 zero a2-12)
|
|
(let ((a2-14 (shl (the-as int a2-13) 16))) (nop!) (b! (nonzero? a2-14) cfg-27 :delay (nop!)))
|
|
(b! (= a1-13 (the-as process-drawable v1-38)) cfg-27 :delay (nop!))))
|
|
(add-fg-prim-using-line-sphere a0-17 obj))
|
|
(label cfg-27)
|
|
0
|
|
(label cfg-28)))
|
|
(let ((v1-45 (the-as uint128 (make-u128 0 8)))) (.pand v1-46 v1-45 s3-0))
|
|
(when (nonzero? (the-as int v1-46))
|
|
(iterate-engine-connections (v1-48 *collide-hit-by-others-list*)
|
|
(let* ((v1-49 (the-as collide-shape (-> (the-as connection v1-48) param1)))
|
|
(a0-24 (-> v1-49 root-prim)))
|
|
(let ((a1-15 (the-as uint128 (-> a0-24 prim-core collide-as)))) (.pand a1-16 s3-0 a1-15))
|
|
(b! (zero? (the-as int a1-16)) cfg-38)
|
|
(nop!)
|
|
(.mul.w.vf acc vf31 vf0)
|
|
(.lvf vf1 (&-> a0-24 prim-core world-sphere quad))
|
|
(.add.mul.x.vf acc vf28 vf1 acc)
|
|
(nop!)
|
|
(.add.mul.y.vf acc vf29 vf1 acc)
|
|
(nop!)
|
|
(.add.mul.z.vf vf6 vf30 vf1 acc)
|
|
(nop!)
|
|
(.sub.w.vf.xyz vf2 vf6 vf1)
|
|
(nop!)
|
|
(.add.w.vf.xyz vf3 vf6 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a2-15 vf4)
|
|
(let ((v1-50 (-> v1-49 process)))
|
|
(.mov a3-6 vf5)
|
|
(let ((a1-18 (-> obj proc)))
|
|
(.pcgtw a2-16 a2-15 s4-0)
|
|
(.pcgtw a3-7 s5-0 a3-6)
|
|
(.por a2-17 a2-16 a3-7)
|
|
(.ppach a2-18 zero a2-17)
|
|
(let ((a2-19 (shl (the-as int a2-18) 16))) (nop!) (b! (nonzero? a2-19) cfg-37 :delay (nop!)))
|
|
(b! (= a1-18 v1-50) cfg-37 :delay (nop!))))
|
|
(add-fg-prim-using-line-sphere a0-24 obj))
|
|
(label cfg-37)
|
|
0
|
|
(label cfg-38)))))
|
|
(none)))
|
|
|
|
(defmethod add-fg-prim-using-line-sphere ((obj collide-shape-prim) (cache collide-cache))
|
|
"Add this primitive to the active swept-sphere query. Sphere leaves are copied into the cache,
|
|
mesh leaves import triangles overlapping the oriented sweep box, groups recurse through
|
|
compatible children, and the base implementation reports an invalid primitive type."
|
|
(format 0 "ERROR: Illegal collide-shape-prim type passed to collide-shape-prim::add-fg-prim-using-line-sphere!~%")
|
|
(none))
|
|
|
|
(defmethod add-fg-prim-using-line-sphere ((obj collide-shape-prim-sphere) (cache collide-cache))
|
|
"Add this primitive to the active swept-sphere query. Sphere leaves are copied into the cache,
|
|
mesh leaves import triangles overlapping the oriented sweep box, groups recurse through
|
|
compatible children, and the base implementation reports an invalid primitive type."
|
|
(local-vars (t1-1 uint))
|
|
(nop!)
|
|
(let* ((t0-0 (-> cache prims))
|
|
(a3-0 (-> cache num-prims-u))
|
|
(t1-0 100)
|
|
(v1-0 (-> obj prim-core world-sphere quad))
|
|
(t2-0 (* a3-0 2))
|
|
(a2-0 (-> obj prim-core quad 1)))
|
|
(b! (= a3-0 t1-0) cfg-2 :delay (set! t1-1 (+ t2-0 a3-0)))
|
|
(let ((t0-1 (the-as object (&-> t0-0 0 prim-core quad t1-1))))
|
|
(let ((a3-1 (+ a3-0 1)))
|
|
(set! (-> (the-as collide-cache-prim t0-1) extra-quad) (the-as uint128 0))
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) prim) obj)
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) prim-core world-sphere quad) v1-0)
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) prim-core quad 1) a2-0)
|
|
(nop!)
|
|
(set! (-> cache num-prims) (the-as int a3-1)))
|
|
(nop!)
|
|
(set! (-> (the-as collide-cache-prim t0-1) ccache) cache)))
|
|
(b! #t cfg-3 :delay (nop!))
|
|
(label cfg-2)
|
|
(format 0 "ERROR: Exceeded max number of collide-cache prims!~%")
|
|
(label cfg-3)
|
|
(none))
|
|
|
|
(defmethod add-fg-prim-using-line-sphere ((obj collide-shape-prim-group) (cache collide-cache))
|
|
"Add this primitive to the active swept-sphere query. Sphere leaves are copied into the cache,
|
|
mesh leaves import triangles overlapping the oriented sweep box, groups recurse through
|
|
compatible children, and the base implementation reports an invalid primitive type."
|
|
(local-vars
|
|
(zero uint128)
|
|
(v1-3 uint128)
|
|
(v1-4 uint128)
|
|
(v1-5 uint128)
|
|
(v1-6 uint128)
|
|
(a0-1 collide-shape-prim)
|
|
(a1-1 uint128)
|
|
(a1-2 uint128))
|
|
(rlet ((acc :class vf)
|
|
(vf0 :class vf)
|
|
(vf1 :class vf)
|
|
(vf10 :class vf)
|
|
(vf2 :class vf)
|
|
(vf28 :class vf)
|
|
(vf29 :class vf)
|
|
(vf3 :class vf)
|
|
(vf30 :class vf)
|
|
(vf31 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf))
|
|
(init-vf0-vector)
|
|
(#when PC_PORT
|
|
(load-fffuls-work))
|
|
(set! zero (the-as uint128 0))
|
|
(let ((v1-0 *collide-work*)
|
|
(s5-0 (-> obj prims))
|
|
(s4-0 (-> obj num-prims-u)))
|
|
(nop!)
|
|
(let ((s3-0 (-> v1-0 collide-box4w min quad)))
|
|
(nop!)
|
|
(let ((s2-0 (-> v1-0 collide-box4w max quad)))
|
|
(nop!)
|
|
(let ((s1-0 (-> s5-0 0)))
|
|
(nop!)
|
|
(let ((s0-0 (-> cache collide-with)))
|
|
(label cfg-1)
|
|
(b! (zero? s4-0) cfg-5 :delay (set! a0-1 s1-0))
|
|
(label cfg-2)
|
|
(+! s4-0 -1)
|
|
(.lvf vf1 (&-> a0-1 prim-core world-sphere quad))
|
|
(nop!)
|
|
(let ((v1-1 (-> a0-1 prim-core collide-as)))
|
|
(.mul.w.vf acc vf31 vf0)
|
|
(set! s5-0 (&-> s5-0 1))
|
|
(.add.mul.x.vf acc vf28 vf1 acc)
|
|
(set! s1-0 (-> s5-0 0))
|
|
(let ((v1-2 (logand s0-0 v1-1)))
|
|
(.add.mul.y.vf acc vf29 vf1 acc)
|
|
(b! (zero? v1-2) cfg-1 :delay (.add.mul.z.vf vf10 vf30 vf1 acc)))))
|
|
(.sub.w.vf.xyz vf2 vf10 vf1)
|
|
(nop!)
|
|
(.add.w.vf.xyz vf3 vf10 vf1)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(.mov a1-1 vf4)
|
|
(nop!)
|
|
(.mov v1-3 vf5)
|
|
(nop!)
|
|
(.pcgtw a1-2 a1-1 s2-0)
|
|
(.pcgtw v1-4 s3-0 v1-3)
|
|
(.por v1-5 a1-2 v1-4)
|
|
(.ppach v1-6 zero v1-5)
|
|
(let ((v1-7 (shl (the-as int v1-6) 16))) (nop!) (b! (nonzero? v1-7) cfg-1 :delay (nop!)))
|
|
(add-fg-prim-using-line-sphere a0-1 cache)
|
|
(b! (nonzero? s4-0) cfg-2 :delay (set! a0-1 s1-0))))))
|
|
(label cfg-5)
|
|
0
|
|
(none)))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; PROBE ;; PROBE ;; PROBE ;; PROBE ;; PROBE ;; PROBE ;; PROBE ;; PROBE ;; PROBE ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(deftype lsmi-work (structure)
|
|
"Scratch state for a moving-sphere mesh test. It tracks the current and incoming best hit
|
|
fractions, required action bits, and the candidate triangle result."
|
|
((best-u float)
|
|
(orig-best-u float)
|
|
(action uint32)
|
|
(tri-out collide-tri-result :inline)))
|
|
|
|
(defmethod fill-and-probe-using-y-probe ((obj collide-cache) (probe-origin vector) (probe-length float) (kinds collide-kind) (proc process-drawable) (tri-out collide-tri-result) (ignore-pat pat-surface))
|
|
"Refill the cache around the vertical probe centered at start, then cast downward by
|
|
probe-length. Skip proc's own primitives and surfaces matching ignore-pat; write the nearest
|
|
compatible solid hit to result and return its fraction, or -100000000.0 when nothing is hit."
|
|
(fill-using-y-probe obj probe-origin probe-length kinds proc ignore-pat)
|
|
(probe-using-y-probe obj probe-origin probe-length kinds tri-out ignore-pat))
|
|
|
|
(defmethod probe-using-y-probe ((obj collide-cache) (probe-origin vector) (probe-length float) (kinds collide-kind) (tri-out collide-tri-result) (ignore-pat pat-surface))
|
|
"Cast downward from start by probe-length against compatible solid cached primitives. Ignore
|
|
matching surfaces, write the nearest hit to result, and return its fraction, or -100000000.0
|
|
when nothing is hit."
|
|
(rlet ((vf0 :class vf)
|
|
(vf1 :class vf)
|
|
(vf3 :class vf))
|
|
(init-vf0-vector)
|
|
(let ((work (new 'stack-no-clear 'collide-puyp-work)))
|
|
(.mov vf3 probe-length)
|
|
(.lvf vf1 (&-> probe-origin quad))
|
|
(set! (-> work best-u) 2.0)
|
|
(set! (-> work ignore-pat) ignore-pat)
|
|
(set! (-> work tri-out) tri-out)
|
|
(.sub.x.vf.y vf3 vf0 vf3)
|
|
(.svf (&-> work start-pos quad) vf1)
|
|
(.mov.vf.xzw vf3 vf0)
|
|
(.svf (&-> work move-dist quad) vf3)
|
|
(let ((cprim (the-as object (-> obj prims))))
|
|
(countdown (prims-left (-> obj num-prims))
|
|
(when (and (logtest? kinds (-> (the-as collide-cache-prim cprim) prim-core collide-as))
|
|
(logtest? (-> (the-as collide-cache-prim cprim) prim-core action) (collide-action solid)))
|
|
(cond
|
|
((>= (-> (the-as collide-cache-prim cprim) prim-core prim-type) 0)
|
|
(puyp-mesh obj work (the-as collide-cache-prim cprim)))
|
|
(else
|
|
(if (zero? (logand ignore-pat (-> (the-as collide-shape-prim-sphere (-> (the-as collide-cache-prim cprim) prim)) pat)))
|
|
(puyp-sphere obj work (the-as collide-cache-prim cprim))))))
|
|
(set! cprim (-> (the-as (inline-array collide-cache-prim) cprim) 1))))
|
|
(let ((best-u (-> work best-u))) (if (< 1.0 best-u) (set! best-u -100000000.0)) best-u))))
|
|
|
|
(defmethod puyp-sphere ((obj collide-cache) (work collide-puyp-work) (cprim collide-cache-prim))
|
|
"Intersect the downward probe in work with prim's sphere. When the hit precedes work.best-u,
|
|
update the result point, outward normal, surface, and representative tangent triangle."
|
|
(let ((hit-u (ray-sphere-intersect (-> work start-pos)
|
|
(-> work move-dist)
|
|
(the-as vector (-> cprim prim-core))
|
|
(-> cprim prim-core world-sphere w))))
|
|
(when (and (>= hit-u 0.0) (< hit-u (-> work best-u)))
|
|
(set! (-> work best-u) hit-u)
|
|
(let ((tri-out (-> work tri-out)))
|
|
(set! (-> tri-out pat) (-> (the-as collide-shape-prim-sphere (-> cprim prim)) pat))
|
|
(vector+*! (-> tri-out intersect) (-> work start-pos) (-> work move-dist) hit-u)
|
|
(vector-! (-> tri-out normal) (-> tri-out intersect) (the-as vector (-> cprim prim-core)))
|
|
(vector-normalize! (-> tri-out normal) 1.0)
|
|
(set! (-> tri-out vertex 0 quad) (-> tri-out intersect quad))
|
|
(point-in-plane-<-point+normal! (-> tri-out vertex 1) (-> tri-out intersect) (-> tri-out normal))
|
|
(let* ((tangent (vector-normalize! (vector-! (new 'stack-no-clear 'vector) (-> tri-out vertex 1) (the-as vector (-> tri-out vertex))) 1.0))
|
|
(bitangent (vector-cross! (new 'stack-no-clear 'vector) (-> tri-out normal) tangent)))
|
|
(vector+*! (-> tri-out vertex 2) (-> tri-out intersect) bitangent 4096.0))))))
|
|
|
|
(defmethod fill-and-probe-using-line-sphere ((obj collide-cache) (start-pt vector) (move-vec vector) (radius float) (kinds collide-kind) (proc process) (tri-out collide-tri-result) (ignore-pat pat-surface))
|
|
"Refill the cache for a sphere of radius moving from start by move, then find the nearest
|
|
compatible solid hit. Skip proc's own primitives and surfaces matching ignore-pat; write a hit
|
|
to result and return its movement fraction, or -100000000.0 when nothing is hit."
|
|
(fill-using-line-sphere obj start-pt move-vec radius kinds (the-as process-drawable proc) ignore-pat)
|
|
(probe-using-line-sphere obj start-pt move-vec radius kinds tri-out ignore-pat))
|
|
|
|
(deftype collide-puls-work (structure)
|
|
"Inputs and output for a moving-sphere probe over cached primitives. bsphere holds the starting
|
|
center and radius, move-dist holds the sweep vector, and tri-out receives the nearest hit."
|
|
((ignore-pat pat-surface :offset-assert 0)
|
|
(tri-out collide-tri-result :offset-assert 4)
|
|
(bsphere sphere :inline :offset-assert 16)
|
|
(move-dist vector :inline :offset-assert 32))
|
|
:method-count-assert 9
|
|
:size-assert #x30
|
|
:flag-assert #x900000030)
|
|
|
|
(defmethod probe-using-line-sphere ((obj collide-cache) (start-pt vector) (move-vec vector) (radius float) (kinds collide-kind) (tri-out collide-tri-result) (ignore-pat pat-surface))
|
|
"Sweep a sphere of radius from start by move against compatible solid cached primitives. Ignore
|
|
matching surfaces, write the nearest hit to result, and return its movement fraction, or
|
|
-100000000.0 when nothing is hit."
|
|
(rlet ((vf0 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf))
|
|
(init-vf0-vector)
|
|
(let ((work (new 'stack-no-clear 'collide-puls-work)))
|
|
(.mov vf4 radius)
|
|
(.lvf vf3 (&-> start-pt quad))
|
|
(.lvf vf2 (&-> move-vec quad))
|
|
(set! (-> work ignore-pat) ignore-pat)
|
|
(.mul.x.vf.w vf3 vf0 vf4)
|
|
(set! (-> work tri-out) tri-out)
|
|
(.svf (&-> work move-dist quad) vf2)
|
|
(.svf (&-> work bsphere quad) vf3)
|
|
(let ((cprim (the-as object (-> obj prims)))
|
|
(best-u -100000000.0))
|
|
(countdown (prims-left (-> obj num-prims))
|
|
(when (and (logtest? kinds (-> (the-as collide-cache-prim cprim) prim-core collide-as))
|
|
(logtest? (-> (the-as collide-cache-prim cprim) prim-core action) (collide-action solid)))
|
|
(cond
|
|
((>= (-> (the-as collide-cache-prim cprim) prim-core prim-type) 0)
|
|
(let ((hit-u ((method-of-type collide-cache-prim resolve-moving-sphere-tri)
|
|
(the-as collide-cache-prim cprim)
|
|
(-> work tri-out)
|
|
(the-as collide-prim-core (-> work bsphere))
|
|
(-> work move-dist)
|
|
best-u
|
|
(collide-action solid))))
|
|
(if (>= hit-u 0.0) (set! best-u hit-u))))
|
|
(else
|
|
(when (zero? (logand ignore-pat (-> (the-as collide-shape-prim-sphere (-> (the-as collide-cache-prim cprim) prim)) pat)))
|
|
(let ((hit-u ((method-of-type collide-cache-prim resolve-moving-sphere-sphere)
|
|
(the-as collide-cache-prim cprim)
|
|
(-> work tri-out)
|
|
(the-as collide-prim-core (-> work bsphere))
|
|
(-> work move-dist)
|
|
best-u
|
|
(collide-action solid))))
|
|
(if (>= hit-u 0.0) (set! best-u hit-u)))))))
|
|
(set! cprim (-> (the-as (inline-array collide-cache-prim) cprim) 1)))
|
|
best-u))))
|
|
|
|
(defmethod fill-and-probe-using-spheres ((obj collide-cache) (params collide-using-spheres-params))
|
|
"Refill the cache around params' sphere set, then return whether any compatible cached primitive
|
|
overlaps one of the spheres."
|
|
(fill-using-spheres obj params)
|
|
(probe-using-spheres obj params))
|
|
|
|
(defmethod fill-using-spheres ((obj collide-cache) (params collide-using-spheres-params))
|
|
"Refill the cache from the bounding box enclosing params' sphere set."
|
|
(let ((query-box (new 'stack-no-clear 'bounding-box)))
|
|
(set-from-spheres! query-box (-> params spheres) (the-as int (-> params num-spheres)))
|
|
;; this box looks correct
|
|
(fill-using-bounding-box obj
|
|
query-box
|
|
(-> params collide-with)
|
|
(-> params proc)
|
|
(the-as pat-surface (-> params ignore-pat))))
|
|
(none))
|
|
|
|
(defmethod probe-using-spheres ((obj collide-cache) (params collide-using-spheres-params))
|
|
"Return true on the first cached primitive which overlaps one of params' spheres and satisfies
|
|
its collision-kind and optional solid-only filters. Reject sets larger than 64 spheres."
|
|
(local-vars (v1-12 symbol))
|
|
(rlet ((vf1 :class vf)
|
|
(vf2 :class vf)
|
|
(vf3 :class vf)
|
|
(vf4 :class vf)
|
|
(vf5 :class vf))
|
|
(let ((s5-0 (scratchpad-object collide-puss-work))
|
|
(a3-0 64)
|
|
(a2-0 (-> params num-spheres)))
|
|
(let ((v1-0 (-> s5-0 spheres))
|
|
(a1-1 (-> params spheres)))
|
|
(let ((a3-1 (- a2-0 (the-as uint a3-0)))) (nop!) (b! (> (the-as int a3-1) 0) cfg-20 :delay (nop!)))
|
|
(b! (zero? a2-0) cfg-5 :delay (.lvf vf1 a1-1))
|
|
(let ((a2-1 (+ a2-0 -1))
|
|
(a1-2 (the-as (inline-array sphere) (-> a1-1 1))))
|
|
(.sub.w.vf.xyz vf2 vf1 vf1)
|
|
(.svf (&-> v1-0 0 bsphere quad) vf1)
|
|
(.add.w.vf.xyz vf3 vf1 vf1)
|
|
(let ((v1-1 (-> v1-0 1)))
|
|
(.ftoi.vf vf4 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf3)
|
|
(nop!)
|
|
(nop!)
|
|
(.svf (+ (the int v1-1) -32) vf4)
|
|
(nop!)
|
|
(.svf (+ (the int v1-1) -16) vf5)
|
|
(label cfg-3)
|
|
(b! (zero? a2-1) cfg-5 :delay (.lvf vf1 a1-2))
|
|
(+! a2-1 -1)
|
|
(set! a1-2 (the-as (inline-array sphere) (-> a1-2 1)))
|
|
(.sub.w.vf.xyz vf4 vf1 vf1)
|
|
(.svf (&-> v1-1 bsphere quad) vf1)
|
|
(.add.w.vf.xyz vf5 vf1 vf1)
|
|
(nop!)
|
|
(.min.vf.xyz vf2 vf2 vf4)
|
|
(nop!)
|
|
(.max.vf.xyz vf3 vf3 vf5)
|
|
(nop!)
|
|
(.ftoi.vf vf4 vf4)
|
|
(nop!)
|
|
(.ftoi.vf vf5 vf5)
|
|
(nop!)
|
|
(nop!)
|
|
(.svf (&-> v1-1 bbox4w min quad) vf4)
|
|
(nop!)
|
|
(.svf (&-> v1-1 bbox4w max quad) vf5)
|
|
(b! #t cfg-3 :delay (set! v1-1 (&+ v1-1 48))))))
|
|
(label cfg-5)
|
|
(.ftoi.vf vf2 vf2)
|
|
(nop!)
|
|
(.ftoi.vf vf3 vf3)
|
|
(nop!)
|
|
(nop!)
|
|
(.svf (&-> s5-0 spheres-bbox4w min quad) vf2)
|
|
(nop!)
|
|
(.svf (&-> s5-0 spheres-bbox4w max quad) vf3)
|
|
(let ((s4-0 (the-as collide-cache-prim (-> obj prims)))
|
|
(s3-0 (-> params collide-with))
|
|
(s2-0 (-> obj num-prims)))
|
|
(b! #t cfg-18 :delay (nop!))
|
|
(label cfg-6)
|
|
(+! s2-0 -1)
|
|
(when (logtest? s3-0 (-> s4-0 prim-core collide-as))
|
|
(when (or (not (-> params solid-only)) (logtest? (-> s4-0 prim-core action) (collide-action solid)))
|
|
(if (>= (-> s4-0 prim-core prim-type) 0)
|
|
(set! v1-12 (check-mesh-prim-against-spheres s5-0 s4-0 params))
|
|
(set! v1-12 (check-sphere-prim-against-spheres s5-0 s4-0 params)))
|
|
(when v1-12
|
|
;; uncomment to view the point that blocks you from exiting duck.
|
|
;;(add-debug-point #t (bucket-id debug-no-zbuf) (-> s5-0 closest-pt))
|
|
(return #t))))
|
|
(&+! s4-0 48)
|
|
(label cfg-18)
|
|
(b! (nonzero? s2-0) cfg-6 :delay (nop!)))
|
|
(b! #t cfg-21 :delay (nop!))
|
|
(label cfg-20)
|
|
;; fixed bad format string
|
|
(format 0 "ERROR: Exceeded max # of spheres in collide-cache::probe-using-spheres!~%"))
|
|
(label cfg-21)
|
|
#f))
|
|
|
|
(defun test-closest-pt-in-triangle ((cache collide-cache))
|
|
"Exercise closest-point calculation for every cached triangle against the target position,
|
|
retaining the nearest point in temporary debug storage. Return false."
|
|
(let ((nearest-point (new 'stack-no-clear 'vector)))
|
|
(let ((best-distance-squared -1.0)
|
|
(tri (the-as object (-> cache tris)))
|
|
(target-position (new 'stack-no-clear 'vector))
|
|
(closest-point (new 'stack-no-clear 'vector))
|
|
(normal (new 'stack-no-clear 'vector))
|
|
(triangles-left (-> cache num-tris)))
|
|
(vector-copy! target-position (target-pos 0))
|
|
(while (nonzero? triangles-left)
|
|
(+! triangles-left -1)
|
|
(normal-of-plane normal
|
|
(-> (the-as collide-cache-tri tri) vertex 0)
|
|
(-> (the-as collide-cache-tri tri) vertex 1)
|
|
(-> (the-as collide-cache-tri tri) vertex 2))
|
|
(closest-pt-in-triangle closest-point target-position (the-as matrix (-> (the-as collide-cache-tri tri) vertex)) normal)
|
|
(let ((distance-squared (vector-vector-distance-squared closest-point target-position)))
|
|
(when (or (< best-distance-squared 0.0) (< distance-squared best-distance-squared))
|
|
(set! best-distance-squared distance-squared)
|
|
(vector-copy! nearest-point closest-point)))
|
|
(set! tri (-> (the-as (inline-array collide-cache-tri) tri) 1)))))
|
|
#f)
|