;;-*-Lisp-*-
(in-package goal)

;; name: collide-hash.gc
;; name in dgo: collide-hash
;; dgos: ENGINE, GAME

#|@file
collide-hash is the broad phase collision detector for background collisions.
It esssentially answers the question "what collide fragments are near X"?
and this answer is passed down to lower level collision checks.


unlike jak 1, this uses a "spatial hash". The idea is to divide space into a grid, then map
cells in this grid to a smaller number of buckets using a hash function.

hash collisions are probably not too common, as most space is empty, and can be reject relatively quickly
by doing a bounding sphere check with the collision fragments.

in this file, boxes are commonly represented as a vector, with xyz being the origin, and w being half
the side length.
|#

;; DECOMP BEGINS

(defun add-collide-debug-box ((arg0 vector) (arg1 rgba))
  "Debug draw a box represented as (origin, half-side-length)."
  (rlet ((vf1 :class vf)
         (vf2 :class vf)
         (vf3 :class vf)
         )
    (let ((a3-0 (new 'stack-no-clear 'bounding-box)))
      (.lvf vf1 (&-> arg0 quad))
      (.sub.w.vf vf2 vf1 vf1)
      (.add.w.vf vf3 vf1 vf1)
      (.svf (&-> a3-0 min quad) vf2)
      (.svf (&-> a3-0 max quad) vf3)
      (add-debug-box #t (bucket-id debug2) (-> a3-0 min) (-> a3-0 max) arg1)
      )
    (none)
    )
  )

(defun-debug print-collide-cache-tri-count ()
  "Print the number of triangles in the collide cache."
  (let ((gp-0 0)
        (s4-0 0)
        (s5-0 0)
        (s3-0 0)
        )
    (let ((v1-0 *collide-cache*))
      (dotimes (a0-0 (-> v1-0 num-tris))
        (case (-> v1-0 tris a0-0 pat mode)
          (((pat-mode ground))
           (+! gp-0 1)
           )
          (((pat-mode wall))
           (+! s5-0 1)
           )
          (((pat-mode obstacle))
           (+! s4-0 1)
           )
          (else
            (+! s3-0 1)
            )
          )
        )
      (format *stdcon* "tris ~d (~4,,1f%) " (-> v1-0 num-tris) (* 0.2173913 (the float (-> v1-0 num-tris))))
      )
    (format *stdcon* "(ground ~d, wall ~d, obstacle ~d, other ~d)~%" gp-0 s5-0 s4-0 s3-0)
    )
  (none)
  )

(defun-debug print-exceeded-max-cache-tris ()
  "Complain that the collide cache is full."
  (with-pp
    (when (not *already-printed-exeeded-max-cache-tris*)
      (set! *already-printed-exeeded-max-cache-tris* #t)
      (if pp
          (format *stdcon* "Exceeded collide cache max # of tris (~s)!~%" (-> pp name))
          (format *stdcon* "Exceeded collide cache max # of tris!~%")
          )
      (print-collide-cache-tri-count)
      )
    0
    (none)
    )
  )

;; these methods fill a collide list, given a collide query. This does the actual spatial hash.
(defmethod-mips2c "(method 11 collide-hash)" 11 collide-hash)
(defmethod-mips2c "(method 12 collide-hash)" 12 collide-hash)

;; these methods do the work of writing triangles into the collide cache.
(def-mips2c fill-bg-using-box-new (function collide-cache object collide-query none))
(def-mips2c fill-bg-using-line-sphere-new (function collide-cache object collide-query none))

(defun collide-list-fill-bg-using-box ((arg0 collide-cache) (arg1 collide-list) (arg2 collide-query))
  "Given a list of collision meshes, fill the given collide collide with triangles which are
   inside the box."
  (local-vars
    (v1-12 uint128)
    (v1-14 uint128)
    (v1-15 uint128)
    (a0-10 uint128)
    (a0-11 uint128)
    (a1-3 uint128)
    (a2-3 uint128)
    (a2-4 uint128)
    (sv-16 int)
    (sv-20 collide-list)
    (sv-640 int)
    )
  (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)
         (vf16 :class vf)
         (vf17 :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! sv-16 (-> arg1 num-items))
    (set! sv-20 arg1)

    ;; loop over collision meshes.
    (dotimes (s4-0 sv-16)
      (let ((s3-0 (-> sv-20 items s4-0 mesh)))
        (cond
          ((= (-> s3-0 type) instance-tie) ;; it's an instanced collision mesh.
           (let* ((v1-4 s3-0)
                  (s1-0 (-> v1-4 bucket-ptr))
                  )
             ;; only both checking if collision is enabled on this geometry.
             (when (not (or (logtest? (-> s1-0 flags) (prototype-flags no-collide))
                            (logtest? (-> v1-4 flags) (instance-flags no-collide))
                            )
                        )
               ;; debug draw.
               (if *collide-list-boxes*
                   (add-collide-debug-box (-> s3-0 bsphere) (new 'static 'rgba :r #xff :a #x80))
                   )

               ;; we need to created a modified query to account for the transformation of the instanced mesh.
               (let ((s0-0 (new 'stack-no-clear 'matrix))
                     (s2-0 (new 'stack-no-clear 'collide-query))
                     )
                 ;; start with the input query, copied.
                 (mem-copy! (the-as pointer s2-0) (the-as pointer arg2) 540)

                 ;; unpack the instance matrix.
                 (let ((v1-11 (the-as uint128 (-> s3-0 origin vector4h 3 long))))
                   (let ((a2-2 (the-as uint128 (-> s3-0 origin vector4h 0 long))))
                     (.pextlh v1-12 v1-11 0)
                     (let ((a0-9 (the-as uint128 (-> s3-0 origin vector4h 1 long))))
                       (.pw.sra a1-3 v1-12 10)
                       (let ((v1-13 (the-as uint128 (-> s3-0 origin vector4h 2 long))))
                         (.pextlh a2-3 a2-2 0)
                         (.pw.sra a2-4 a2-3 16)
                         (.pextlh a0-10 a0-9 0)
                         (.mov vf4 a1-3)
                         (.pw.sra a0-11 a0-10 16)
                         (.mov vf1 a2-4)
                         (.pextlh v1-14 v1-13 0)
                         )
                       )
                     )
                   )
                 (.mov vf2 a0-11)
                 (.pw.sra v1-15 v1-14 16)
                 (.lvf vf5 (&-> s3-0 bsphere quad))
                 (.mov vf3 v1-15)
                 (.itof.vf vf4 vf4)
                 (vitof12.xyzw vf1 vf1)
                 (vitof12.xyzw vf2 vf2)
                 (vitof12.xyzw vf3 vf3)
                 (.add.vf.xyz vf4 vf4 vf5)

                 ;; pass the instance mat down.
                 (.svf (&-> s2-0 instance-mat vector 0 quad) vf1)
                 (.svf (&-> s2-0 instance-mat vector 1 quad) vf2)
                 (.svf (&-> s2-0 instance-mat vector 2 quad) vf3)
                 (.svf (&-> s2-0 instance-mat trans quad) vf4)

                 ;; transform the bounding box to instance coordinates.
                 (matrix-4x4-inverse! s0-0 (-> s2-0 instance-mat))
                 (.lvf vf7 (&-> arg2 bbox min quad))
                 (.lvf vf14 (&-> arg2 bbox max quad))
                 (.lvf vf1 (&-> s0-0 vector 0 quad))
                 (.lvf vf2 (&-> s0-0 vector 1 quad))
                 (.lvf vf3 (&-> s0-0 vector 2 quad))
                 (.lvf vf4 (&-> s0-0 trans quad))
                 (.mul.w.vf acc vf4 vf0)
                 (.add.mul.x.vf acc vf1 vf7 acc)
                 (.add.mul.y.vf acc vf2 vf7 acc)
                 (.add.mul.z.vf vf8 vf3 vf14 acc)
                 (.mul.w.vf acc vf4 vf0)
                 (.add.mul.x.vf acc vf1 vf7 acc)
                 (.add.mul.y.vf acc vf2 vf14 acc)
                 (.add.mul.z.vf vf9 vf3 vf7 acc)
                 (.mul.w.vf acc vf4 vf0)
                 (.add.mul.x.vf acc vf1 vf7 acc)
                 (.add.mul.y.vf acc vf2 vf14 acc)
                 (.add.mul.z.vf vf10 vf3 vf14 acc)
                 (.min.vf vf5 vf8 vf9)
                 (.max.vf vf6 vf8 vf9)
                 (.mul.w.vf acc vf4 vf0)
                 (.add.mul.x.vf acc vf1 vf14 acc)
                 (.add.mul.y.vf acc vf2 vf7 acc)
                 (.add.mul.z.vf vf11 vf3 vf7 acc)
                 (.min.vf vf5 vf5 vf10)
                 (.max.vf vf6 vf6 vf10)
                 (.mul.w.vf acc vf4 vf0)
                 (.add.mul.x.vf acc vf1 vf14 acc)
                 (.add.mul.y.vf acc vf2 vf7 acc)
                 (.add.mul.z.vf vf12 vf3 vf14 acc)
                 (.min.vf vf5 vf5 vf11)
                 (.max.vf vf6 vf6 vf11)
                 (.mul.w.vf acc vf4 vf0)
                 (.add.mul.x.vf acc vf1 vf14 acc)
                 (.add.mul.y.vf acc vf2 vf14 acc)
                 (.add.mul.z.vf vf13 vf3 vf7 acc)
                 (.min.vf vf5 vf5 vf12)
                 (.max.vf vf6 vf6 vf12)
                 (.mul.w.vf acc vf4 vf0)
                 (.add.mul.x.vf acc vf1 vf14 acc)
                 (.add.mul.y.vf acc vf2 vf14 acc)
                 (.add.mul.z.vf vf14 vf3 vf14 acc)
                 (.min.vf vf5 vf5 vf13)
                 (.max.vf vf6 vf6 vf13)
                 (.mul.w.vf acc vf4 vf0)
                 (.add.mul.x.vf acc vf1 vf7 acc)
                 (.add.mul.y.vf acc vf2 vf7 acc)
                 (.add.mul.z.vf vf7 vf3 vf7 acc)
                 (.min.vf vf5 vf5 vf14)
                 (.max.vf vf6 vf6 vf14)
                 (.min.vf vf5 vf5 vf7)
                 (.max.vf vf6 vf6 vf7)
                 (.ftoi.vf vf16 vf5)
                 (.ftoi.vf vf17 vf6)

                 ;; update collision query with transformed box
                 (.svf (&-> s2-0 bbox min quad) vf5)
                 (.svf (&-> s2-0 bbox max quad) vf6)
                 (.svf (&-> s2-0 bbox4w min quad) vf16)
                 (.svf (&-> s2-0 bbox4w max quad) vf17)

                 ;; loop over fragments in the mesh.
                 (let ((s1-1 (-> s1-0 collide-hash-fragment-array)))
                   (set! sv-640 (-> s1-1 length))
                   (set! (-> s2-0 instance-ptr) s3-0)
                   (dotimes (s3-1 sv-640)
                     ;; not sure why we set this, maybe something used by the asm function
                     (set! (-> (scratchpad-object collide-hash-scratch) collidable-bits 0) (the-as uint128 0))
                     (set! (-> (scratchpad-object collide-hash-scratch) collidable-bits 1) (the-as uint128 0))
                     ;; reset triangle count
                     (set! (-> (scratchpad-object collide-hash-scratch) tris) (the-as uint 0))
                     ;; unpack triangles, filter, and store in collide cache.
                     (fill-bg-using-box-new arg0 (-> s1-1 fragments s3-1) s2-0)
                     ;; update stats
                     (+! (-> *collide-stats* tris) (-> (scratchpad-object collide-hash-scratch) tris))
                     )
                   )
                 )
               )
             )
           )
          (else
            ;; colliding with non-instanced mesh. Don't need to update query.
            (if *collide-list-boxes*
                (add-collide-debug-box (-> s3-0 bsphere) (new 'static 'rgba :r #xff :g #xff :a #x80))
                )
            (set! (-> (scratchpad-object collide-hash-scratch) collidable-bits 0) (the-as uint128 0))
            (set! (-> (scratchpad-object collide-hash-scratch) collidable-bits 1) (the-as uint128 0))
            (set! (-> arg2 instance-ptr) #f)
            (set! (-> (scratchpad-object collide-hash-scratch) tris) (the-as uint 0))
            (fill-bg-using-box-new arg0 s3-0 arg2)
            (+! (-> *collide-stats* tris) (-> (scratchpad-object collide-hash-scratch) tris))
            )
          )
        )
      )
    0
    (none)
    )
  )

(defmacro .sll (result in sa)
  `(set! ,result (sext32 (the-as int (shl (logand ,in #xffffffff) ,sa))))
  )

(defun collide-list-fill-bg-using-line-sphere ((arg0 collide-cache) (arg1 collide-list) (arg2 collide-query))
  "line-sphere version of collide-list-fill-bg-using-box.
   Logic is basically the same, but transforming the line-sphere query is a bit trickier."
  (local-vars
    (v1-12 uint128)
    (v1-14 uint128)
    (v1-15 uint128)
    (v1-17 number)
    (v1-26 float)
    (a0-10 uint128)
    (a0-11 uint128)
    (a1-3 uint128)
    (a2-3 uint128)
    (a2-4 uint128)
    (sv-16 int)
    (sv-640 int)
    )
  (rlet ((acc :class vf)
         (vf0 :class vf)
         (vf1 :class vf)
         (vf10 :class vf)
         (vf11 :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! sv-16 (-> arg1 num-items))
    (dotimes (s3-0 sv-16)
      (let ((s2-0 (-> arg1 items s3-0 mesh)))
        (cond
          ((= (-> s2-0 type) instance-tie)
           ;; it's an instance, we'll need some fancy logic to transform the query to be in the instance coordinates.
           (let ((v1-4 s2-0))
             (when (not (or (logtest? (-> v1-4 bucket-ptr flags) (prototype-flags no-collide))
                            (logtest? (-> v1-4 flags) (instance-flags no-collide))
                            )
                        )
               (if *collide-list-boxes*
                   (add-collide-debug-box (-> s2-0 bsphere) (new 'static 'rgba :r #xff :a #x80))
                   )
               (let ((s0-0 (new 'stack-no-clear 'matrix))
                     (s1-0 (new 'stack-no-clear 'collide-query))
                     )
                 ;; copy original query
                 (mem-copy! (the-as pointer s1-0) (the-as pointer arg2) 540)
                 ;; unpack instance matrix
                 (let ((v1-11 (the-as uint128 (-> s2-0 origin vector4h 3 long))))
                   (let ((a2-2 (the-as uint128 (-> s2-0 origin vector4h 0 long))))
                     (.pextlh v1-12 v1-11 0)
                     (let ((a0-9 (the-as uint128 (-> s2-0 origin vector4h 1 long))))
                       (.pw.sra a1-3 v1-12 10)
                       (let ((v1-13 (the-as uint128 (-> s2-0 origin vector4h 2 long))))
                         (.pextlh a2-3 a2-2 0)
                         (.pw.sra a2-4 a2-3 16)
                         (.pextlh a0-10 a0-9 0)
                         (.mov vf4 a1-3)
                         (.pw.sra a0-11 a0-10 16)
                         (.mov vf1 a2-4)
                         (.pextlh v1-14 v1-13 0)
                         )
                       )
                     )
                   )
                 (.mov vf2 a0-11)
                 (.pw.sra v1-15 v1-14 16)
                 (.lvf vf5 (&-> s2-0 bsphere quad))
                 (.mov vf3 v1-15)
                 (.itof.vf vf4 vf4)
                 (vitof12.xyzw vf1 vf1)
                 (vitof12.xyzw vf2 vf2)
                 (vitof12.xyzw vf3 vf3)
                 (.add.vf.xyz vf4 vf4 vf5)
                 (.svf (&-> s1-0 instance-mat vector 0 quad) vf1)
                 (.svf (&-> s1-0 instance-mat vector 1 quad) vf2)
                 (.svf (&-> s1-0 instance-mat vector 2 quad) vf3)
                 (.svf (&-> s1-0 instance-mat trans quad) vf4)

                 ;; invert
                 (matrix-4x4-inverse! s0-0 (-> s1-0 instance-mat))
                 (.lvf vf7 (&-> arg2 start-pos quad))
                 (.lvf vf8 (&-> arg2 move-dist quad))
                 (.lvf vf1 (&-> s0-0 vector 0 quad))
                 (.lvf vf2 (&-> s0-0 vector 1 quad))
                 (.lvf vf3 (&-> s0-0 vector 2 quad))
                 (.lvf vf4 (&-> s0-0 trans quad))
                 (.add.vf vf8 vf7 vf8)
                 (let ((v1-16 (-> s2-0 rmin-scale)))
                   (.mul.x.vf acc vf1 vf7)
                   (let ((f2-0 (-> arg2 radius)))
                     (.add.mul.y.vf acc vf2 vf7 acc)
                     (.sll v1-17 v1-16 16)
                     (.add.mul.z.vf acc vf3 vf7 acc)
                     (let ((f1-0 (the-as float v1-17)))
                       (.add.mul.w.vf vf7 vf4 vf0 acc)
                       (.mul.x.vf acc vf1 vf8)
                       (let ((f2-1 (* f2-0 f1-0)))
                         (.add.mul.y.vf acc vf2 vf8 acc)
                         (.add.mul.z.vf acc vf3 vf8 acc)
                         (.add.mul.w.vf vf8 vf4 vf0 acc)
                         (.svf (&-> s1-0 start-pos quad) vf7)
                         (.min.vf vf5 vf7 vf8)
                         (set! (-> s1-0 radius) f2-1)
                         )
                       )
                     )
                   )
                 (.max.vf vf6 vf7 vf8)
                 (.lvf vf9 (&-> s1-0 exit-planes 0 quad))
                 (.sub.vf vf8 vf8 vf7)
                 (.sub.w.vf vf5 vf5 vf9)
                 (.add.w.vf vf6 vf6 vf9)
                 (.svf (&-> s1-0 move-dist quad) vf8)
                 (.ftoi.vf vf10 vf5)
                 (.ftoi.vf vf11 vf6)
                 (.svf (&-> s1-0 bbox min quad) vf5)
                 (.svf (&-> s1-0 bbox max quad) vf6)
                 (.svf (&-> s1-0 bbox4w min quad) vf10)
                 (.svf (&-> s1-0 bbox4w max quad) vf11)
                 (set! (-> s1-0 rlength x) (if (= (-> s1-0 move-dist x) 0.0)
                                               0.0
                                               (/ 1.0 (-> s1-0 move-dist x))
                                               )
                       )
                 (set! (-> s1-0 rlength y) (if (= (-> s1-0 move-dist y) 0.0)
                                               0.0
                                               (/ 1.0 (-> s1-0 move-dist y))
                                               )
                       )
                 (set! (-> s1-0 rlength z) (if (= (-> s1-0 move-dist z) 0.0)
                                               0.0
                                               (/ 1.0 (-> s1-0 move-dist z))
                                               )
                       )
                 (let ((f0-12 1.0))
                   (.lvf vf1 (&-> (-> s1-0 move-dist) quad))
                   (.add.w.vf.x vf2 vf0 vf0)
                   (.mul.vf vf1 vf1 vf1)
                   (.mul.x.vf.x acc vf2 vf1)
                   (.add.mul.y.vf.x acc vf2 vf1 acc)
                   (.add.mul.z.vf.x vf1 vf2 vf1 acc)
                   (.mov v1-26 vf1)
                   (set! (-> s1-0 rlength w) (/ f0-12 v1-26))
                   )
                 (set! (-> s1-0 exit-planes 0 x) (if (< 0.0 (-> s1-0 move-dist x))
                                                     0.0
                                                     100000000000000000000000000000000000000.0
                                                     )
                       )
                 (set! (-> s1-0 exit-planes 0 y) (if (< 0.0 (-> s1-0 move-dist y))
                                                     0.0
                                                     100000000000000000000000000000000000000.0
                                                     )
                       )
                 (set! (-> s1-0 exit-planes 0 z) (if (< 0.0 (-> s1-0 move-dist z))
                                                     0.0
                                                     100000000000000000000000000000000000000.0
                                                     )
                       )
                 (set! (-> s1-0 exit-planes 1 x) (if (< (-> s1-0 move-dist x) 0.0)
                                                     0.0
                                                     100000000000000000000000000000000000000.0
                                                     )
                       )
                 (set! (-> s1-0 exit-planes 1 y) (if (< (-> s1-0 move-dist y) 0.0)
                                                     0.0
                                                     100000000000000000000000000000000000000.0
                                                     )
                       )
                 (set! (-> s1-0 exit-planes 1 z) (if (< (-> s1-0 move-dist z) 0.0)
                                                     0.0
                                                     100000000000000000000000000000000000000.0
                                                     )
                       )
                 (let ((s0-1 (-> s2-0 bucket-ptr collide-hash-fragment-array)))
                   (set! sv-640 (-> s0-1 length))
                   (set! (-> s1-0 instance-ptr) s2-0)
                   (dotimes (s2-1 sv-640)
                     (set! (-> (scratchpad-object collide-hash-scratch) collidable-bits 0) (the-as uint128 0))
                     (set! (-> (scratchpad-object collide-hash-scratch) collidable-bits 1) (the-as uint128 0))
                     (set! (-> (scratchpad-object collide-hash-scratch) tris) (the-as uint 0))
                     (fill-bg-using-line-sphere-new arg0 (-> s0-1 fragments s2-1) s1-0)
                     (+! (-> *collide-stats* tris) (-> (scratchpad-object collide-hash-scratch) tris))
                     )
                   )
                 )
               )
             )
           )
          (else
            (if *collide-list-boxes*
                (add-collide-debug-box (-> s2-0 bsphere) (new 'static 'rgba :r #xff :g #xff :a #x80))
                )
            (set! (-> (scratchpad-object collide-hash-scratch) collidable-bits 0) (the-as uint128 0))
            (set! (-> (scratchpad-object collide-hash-scratch) collidable-bits 1) (the-as uint128 0))
            (set! (-> arg2 instance-ptr) #f)
            (set! (-> (scratchpad-object collide-hash-scratch) tris) (the-as uint 0))
            (fill-bg-using-line-sphere-new arg0 s2-0 arg2)
            (+! (-> *collide-stats* tris) (-> (scratchpad-object collide-hash-scratch) tris))
            )
          )
        )
      )
    0
    (none)
    )
  )

(defmethod mem-usage ((this collide-hash) (arg0 memory-usage-block) (arg1 int))
  "This one is a bit weird because it touches stuff in the scratchpad...
   It's called from the bsp-header's mem-usage function, so it should be fine."
  (set! (-> arg0 length) (max 51 (-> arg0 length)))
  (set! (-> arg0 data 50 name) (symbol->string 'collision))
  (+! (-> arg0 data 50 count) 1)
  (let ((v1-10 (+ (* (-> this num-items) 8) 96 (* (-> this num-buckets) 4))))
    (+! (-> arg0 data 50 used) v1-10)
    (+! (-> arg0 data 50 total) (logand -16 (+ v1-10 15)))
    )
  (dotimes (v1-14 (the-as int (-> this qwc-id-bits)))
    (set! (-> (scratchpad-object collide-hash-scratch) collidable-bits v1-14) (the-as uint128 0))
    )
  (dotimes (s3-0 (the-as int (-> this num-items)))
    (let* ((a0-12 (-> this item-array s3-0 id))
           (v1-19 (shr a0-12 5))
           )
      (when (not (logtest? (-> (scratchpad-object collide-hash-scratch) id-bits v1-19) (ash 1 (logand a0-12 31))))
        (logior! (-> (scratchpad-object collide-hash-scratch) id-bits v1-19) (ash 1 (logand a0-12 31)))
        (if (= (-> this item-array s3-0 collidable type) collide-hash-fragment)
            (mem-usage (-> this item-array s3-0 collidable) arg0 arg1)
            )
        )
      )
    )
  this
  )

(defmethod mem-usage ((this collide-hash-fragment) (arg0 memory-usage-block) (arg1 int))
  (cond
    ((logtest? arg1 1)
     (set! (-> arg0 length) (max 58 (-> arg0 length)))
     (set! (-> arg0 data 55 name) (symbol->string 'prototype-fragment))
     (+! (-> arg0 data 55 count) 1)
     (set! (-> arg0 data 56 name) (symbol->string 'prototype-poly))
     (+! (-> arg0 data 56 count) (the-as int (-> this stats num-polys)))
     (set! (-> arg0 data 57 name) (symbol->string 'prototype-vertex))
     (+! (-> arg0 data 57 count) (the-as int (-> this stats num-verts)))
     (let ((a3-0 (+ (-> this num-indices) 112 (* (-> this num-buckets) 4)))
           (a2-9 (* (-> this stats num-polys) 4))
           (v1-22 (* (the-as uint 6) (the-as uint (-> this stats num-verts))))
           )
       (+! (-> arg0 data 55 used) a3-0)
       (+! (-> arg0 data 55 total) (- (logand -16 (+ v1-22 15 a2-9 a3-0)) (the-as int (+ a2-9 v1-22))))
       (+! (-> arg0 data 56 used) a2-9)
       (+! (-> arg0 data 56 total) a2-9)
       (+! (-> arg0 data 57 used) v1-22)
       (+! (-> arg0 data 57 total) v1-22)
       )
     )
    (else
      (set! (-> arg0 length) (max 54 (-> arg0 length)))
      (set! (-> arg0 data 51 name) (symbol->string 'collision-fragment))
      (+! (-> arg0 data 51 count) 1)
      (set! (-> arg0 data 52 name) (symbol->string 'collision-poly))
      (+! (-> arg0 data 52 count) (the-as int (-> this stats num-polys)))
      (set! (-> arg0 data 53 name) (symbol->string 'collision-vertex))
      (+! (-> arg0 data 53 count) (the-as int (-> this stats num-verts)))
      (let ((a3-8 (+ (-> this num-indices) 112 (* (-> this num-buckets) 4)))
            (a2-22 (* (-> this stats num-polys) 4))
            (v1-45 (* (the-as uint 6) (the-as uint (-> this stats num-verts))))
            )
        (+! (-> arg0 data 51 used) a3-8)
        (+! (-> arg0 data 51 total) (- (logand -16 (+ v1-45 15 a2-22 a3-8)) (the-as int (+ a2-22 v1-45))))
        (+! (-> arg0 data 52 used) a2-22)
        (+! (-> arg0 data 52 total) a2-22)
        (+! (-> arg0 data 53 used) v1-45)
        (+! (-> arg0 data 53 total) v1-45)
        )
      )
    )
  this
  )

(defmethod mem-usage ((this collide-hash-fragment-array) (arg0 memory-usage-block) (arg1 int))
  (set! (-> arg0 length) (max 55 (-> arg0 length)))
  (set! (-> arg0 data 54 name) (symbol->string 'prototype-collision))
  (+! (-> arg0 data 54 count) 1)
  (let ((v1-8 (asize-of this)))
    (+! (-> arg0 data 54 used) v1-8)
    (+! (-> arg0 data 54 total) (logand -16 (+ v1-8 15)))
    )
  (dotimes (s3-0 (-> this length))
    (mem-usage (-> this fragments s3-0) arg0 arg1)
    )
  this
  )
