jak-project/goal_src/engine/collide/collide-cache.gc

247 lines
7.9 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
;; name: collide-cache.gc
;; name in dgo: collide-cache
;; dgos: GAME, ENGINE
;; TODO this doesnt work properly due to qmfc2 bugs
(defun collide-cache-using-box-test ((arg0 vector))
(local-vars (v1-1 float))
(rlet ((acc :class vf)
(vf0 :class vf)
(vf1 :class vf)
(vf2 :class vf)
(vf3 :class vf)
)
(init-vf0-vector)
(nop!)
(.max.w.vf vf3 vf0 vf0)
(let ((v1-0 *collide-work*))
(nop!)
(.lvf vf1 (&-> arg0 quad))
(nop!)
(.lvf vf2 (&-> v1-0 collide-sphere-neg-r quad))
)
(.sub.vf vf1 vf1 vf2)
(nop!)
(.mul.vf vf1 vf1 vf1)
(nop!)
(.mul.x.vf acc vf3 vf1)
(nop!)
(.add.mul.y.vf acc vf3 vf1 acc)
(nop!)
(.add.mul.z.vf acc vf3 vf1 acc)
(nop!)
(.sub.mul.w.vf vf1 vf3 vf1 acc)
(nop!)
(.mov v1-1 vf1)
(<= (the-as int v1-1) 0)
)
)
;;;;;;;;;;;;;;;;;;;;;
;; 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.
(defun collide-cache-using-line-sphere-test ((arg0 vector))
"Check if the input sphere 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 ((a1-0 *collide-work*))
(.lvf vf5 (&-> arg0 quad))
(.lvf vf4 (&-> a1-0 inv-mat vector 3 quad))
(.lvf vf1 (&-> a1-0 inv-mat vector 0 quad))
(.mul.w.vf acc vf4 vf0)
(.lvf vf2 (&-> a1-0 inv-mat vector 1 quad))
(.add.mul.x.vf acc vf1 vf5 acc)
(.lvf vf3 (&-> a1-0 inv-mat vector 2 quad))
(.add.mul.y.vf acc vf2 vf5 acc)
(let ((v1-0 (-> a1-0 collide-box4w min quad)))
(.add.mul.z.vf vf10 vf3 vf5 acc)
(let ((a1-1 (-> a1-0 collide-box4w max quad)))
(.sub.w.vf vf6 vf10 vf5 :mask #b111)
(.add.w.vf vf7 vf10 vf5 :mask #b111)
(.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 ((arg0 collide-fragment) (arg1 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 (-> arg1 max-scale)))
(let ((a3-0 (the-as uint128 (-> arg1 origin vector4h 3 long))))
(let ((t2-0 (the-as uint128 (-> arg1 origin vector4h 0 long))))
(.pextlh a3-1 a3-0 zero)
(let ((t0-0 (the-as uint128 (-> arg1 origin vector4h 1 long))))
(.pw.sra t1-0 a3-1 10)
(let ((a3-2 (the-as uint128 (-> arg1 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 (&-> arg1 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 vf4 vf4 vf5 :mask #b111)
(.lvf vf5 (&-> arg0 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 vf15 vf6 vf5 :mask #b1)
(.add.x.vf vf12 vf11 vf15 :mask #b111)
(.sub.x.vf vf11 vf11 vf15 :mask #b111)
(.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 collide-fragment ((obj collide-fragment) (arg0 int) (arg1 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 arg0)
(when (collide-cache-using-line-sphere-test (-> obj bsphere))
(let ((v1-5 (-> arg1 items (-> arg1 num-items))))
(set! (-> v1-5 mesh) (-> obj mesh))
(set! (-> v1-5 inst) #f) ;; non-instanced.
)
(+! (-> arg1 num-items) 1)
)
(&+! obj 32)
)
0
(none)
)
(defmethod collide-ray instance-tie ((obj instance-tie) (arg0 int) (arg1 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 arg0)
;; 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 (-> arg1 items (-> arg1 num-items))))
(set! (-> v1-10 mesh) (-> (the-as collide-fragment s1-0) mesh))
(set! (-> v1-10 inst) obj)
)
(+! (-> arg1 num-items) 1)
)
(set! s1-0 (-> (the-as (inline-array collide-fragment) s1-0) 1))
)
)
)
)
)
(&+! obj 64)
)
0
(none)
)