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

;; name: subdivide.gc
;; name in dgo: subdivide
;; dgos: GAME

;; DECOMP BEGINS

(define *merc-global-stats* (new 'global 'merc-global-stats))

(defun clear-tr-stat ((arg0 tr-stat))
  "Reset all statistics to 0."
  (set! (-> arg0 groups) (the-as uint 0))
  (set! (-> arg0 fragments) (the-as uint 0))
  (set! (-> arg0 tris) (the-as uint 0))
  (set! (-> arg0 dverts) (the-as uint 0))
  (set! (-> arg0 instances) (the-as uint 0))
  0
  (none)
  )

(define *stat-string-tfrag* (new 'global 'string 128 (the-as string #f)))

(define *stat-string-tfrag-scissor* (new 'global 'string 128 (the-as string #f)))

(define *stat-string-total* (new 'global 'string 128 (the-as string #f)))

;; WARN: Return type mismatch uint vs none.
(defun-debug print-tr-stat ((arg0 tr-stat) (arg1 string) (arg2 string))
  "Print a single tr-stat to the screen."
  (clear arg2)
  (when (nonzero? (+ (-> arg0 groups) (-> arg0 fragments) (-> arg0 tris) (-> arg0 dverts) (-> arg0 instances)))
    (format arg2 "~0k~4d  ~5d   ~6d   ~6d" (-> arg0 groups) (-> arg0 fragments) (-> arg0 tris) (-> arg0 dverts))
    (format
      arg2
      "~0k   ~7f ~5d  ~s"
      (/ (* 2.0 (the float (-> arg0 tris))) (the float (- (-> arg0 dverts) (-> arg0 tris))))
      (-> arg0 instances)
      arg1
      )
    (format *stdcon* "~S~%" arg2)
    (+! (-> *terrain-stats* total groups) (-> arg0 groups))
    (+! (-> *terrain-stats* total fragments) (-> arg0 fragments))
    (+! (-> *terrain-stats* total tris) (-> arg0 tris))
    (+! (-> *terrain-stats* total dverts) (-> arg0 dverts))
    (+! (-> *terrain-stats* total instances) (-> arg0 instances))
    )
  (none)
  )

(defun-debug print-terrain-stats ()
  "Print all tr-stats for renderers to the screen."
  (dotimes (gp-0 (-> *level* length))
    (let ((s5-0 (-> *level* level gp-0)))
      (when (= (-> s5-0 status) 'active)
        (compute-memory-usage! s5-0 #f)
        (format
          *stdcon*
          "~0k~D ~A ~,,2fK + textures~%"
          (-> s5-0 index)
          (-> s5-0 name)
          (* 0.0009765625 (the float (-> s5-0 mem-usage)))
          )
        )
      )
    )
  (format *stdcon* "~0k~%grps  frags     tris   dverts    strip  insts~%")
  (print-tr-stat (-> *terrain-stats* pris) "pris" *temp-string*)
  (print-tr-stat (-> *merc-global-stats* merc) "merc" *temp-string*)
  (print-tr-stat (-> *merc-global-stats* emerc) "emerc" *temp-string*)
  (print-tr-stat (-> *merc-global-stats* mercneric) "mercneric" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-generic) "tie-generic" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-vanish) "tie-vanish" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie) "tie" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-scissor) "tie-scissor" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-envmap) "tie-envmap" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-envmap-scissor) "tie-envmap-scissor" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-trans) "tie-trans" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-scissor-trans) "tie-scissor-trans" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-envmap-trans) "tie-envmap-trans" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-envmap-scissor-trans) "tie-envmap-scissor-trans" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-water) "tie-water" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-scissor-water) "tie-scissor-water" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-envmap-water) "tie-envmap-water" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tie-envmap-scissor-water) "tie-envmap-scissor-water" *temp-string*)
  (print-tr-stat (-> *terrain-stats* shrub-near) "shrub-near" *temp-string*)
  (print-tr-stat (-> *terrain-stats* shrub) "shrub" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tfrag-scissor) "tfrag-scissor" *stat-string-tfrag-scissor*)
  (print-tr-stat (-> *terrain-stats* tfrag) "tfrag" *stat-string-tfrag*)
  (print-tr-stat (-> *terrain-stats* tfrag-trans) "tfrag-trans" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tfrag-scissor-trans) "tfrag-scissor-trans" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tfrag-water) "tfrag-water" *temp-string*)
  (print-tr-stat (-> *terrain-stats* tfrag-scissor-water) "tfrag-scissor-water" *temp-string*)
  (print-tr-stat (-> *terrain-stats* trans-pris) "trans-pris" *temp-string*)
  (print-tr-stat (-> *terrain-stats* billboard) "billboard" *temp-string*)
  (print-tr-stat (-> *terrain-stats* trans-shrub) "trans-shrub" *temp-string*)
  (print-tr-stat (-> *terrain-stats* ocean-mid) "ocean-mid" *temp-string*)
  (print-tr-stat (-> *terrain-stats* ocean-near) "ocean-near" *temp-string*)
  (print-tr-stat (-> *terrain-stats* shadow) "shadow" *temp-string*)
  (print-tr-stat (-> *terrain-stats* hfrag) "hfrag" *temp-string*)
  (format *stdcon* "~0k---------------------------------------------------------------~%")
  (print-tr-stat (-> *terrain-stats* total) "total" *stat-string-total*)
  (clear-tr-stat (-> *terrain-stats* pris))
  (clear-tr-stat (-> *merc-global-stats* merc))
  (clear-tr-stat (-> *merc-global-stats* emerc))
  (clear-tr-stat (-> *merc-global-stats* mercneric))
  (clear-tr-stat (-> *terrain-stats* shrub-near))
  (clear-tr-stat (-> *terrain-stats* tie-generic))
  (clear-tr-stat (-> *terrain-stats* tie-vanish))
  (clear-tr-stat (-> *terrain-stats* tie))
  (clear-tr-stat (-> *terrain-stats* tie-scissor))
  (clear-tr-stat (-> *terrain-stats* tie-envmap))
  (clear-tr-stat (-> *terrain-stats* tie-envmap-scissor))
  (clear-tr-stat (-> *terrain-stats* tie-trans))
  (clear-tr-stat (-> *terrain-stats* tie-scissor-trans))
  (clear-tr-stat (-> *terrain-stats* tie-envmap-trans))
  (clear-tr-stat (-> *terrain-stats* tie-envmap-scissor-trans))
  (clear-tr-stat (-> *terrain-stats* tie-water))
  (clear-tr-stat (-> *terrain-stats* tie-scissor-water))
  (clear-tr-stat (-> *terrain-stats* tie-envmap-water))
  (clear-tr-stat (-> *terrain-stats* tie-envmap-scissor-water))
  (clear-tr-stat (-> *terrain-stats* shrub))
  (clear-tr-stat (-> *terrain-stats* tfrag-scissor))
  (clear-tr-stat (-> *terrain-stats* tfrag))
  (clear-tr-stat (-> *terrain-stats* tfrag-trans))
  (clear-tr-stat (-> *terrain-stats* tfrag-scissor-trans))
  (clear-tr-stat (-> *terrain-stats* tfrag-water))
  (clear-tr-stat (-> *terrain-stats* tfrag-scissor-water))
  (clear-tr-stat (-> *terrain-stats* trans-pris))
  (clear-tr-stat (-> *terrain-stats* billboard))
  (clear-tr-stat (-> *terrain-stats* trans-shrub))
  (clear-tr-stat (-> *terrain-stats* ocean-mid))
  (clear-tr-stat (-> *terrain-stats* ocean-near))
  (clear-tr-stat (-> *terrain-stats* shadow))
  (clear-tr-stat (-> *terrain-stats* hfrag))
  (clear-tr-stat (-> *terrain-stats* total))
  0
  (none)
  )

(defun update-subdivide-settings! ((arg0 subdivide-settings) (arg1 math-camera) (arg2 int))
  "Update the subdivide settings from the far/close settings
   This caches the settings in subdivide-settings itself,
   as well as in tfrag-work, used by EE tfrag code."
  (set! (-> arg0 meters 0) (-> arg0 far arg2))
  (set! (-> arg0 meters 4) (-> arg0 close arg2))
  (let ((f0-3 (* 0.14285715 (- (-> arg0 meters 0) (-> arg0 meters 4)))))
    (set! (-> arg0 meters 3) (+ (-> arg0 meters 4) (* 0.5 f0-3)))
    (set! (-> arg0 meters 2) (+ (-> arg0 meters 3) f0-3))
    (set! (-> arg0 meters 1) (+ (-> arg0 meters 2) (* 2.0 f0-3)))
    )
  (let ((f0-7 (* (-> arg1 fov-correction-factor) (/ (-> arg1 inv-hmge-scale w) (-> arg1 d)))))
    (dotimes (v1-8 5)
      (set! (-> arg0 dist v1-8) (* f0-7 (-> arg0 meters v1-8)))
      )
    )
  (set! (-> *tfrag-work* frag-dists x) (- (-> arg0 meters 0)))
  (set! (-> *tfrag-work* frag-dists y) (- (-> arg0 meters 1)))
  (set! (-> *tfrag-work* frag-dists z) (- (-> arg0 meters 2)))
  (set! (-> *tfrag-work* frag-dists w) (- (-> arg0 meters 4)))
  0
  (none)
  )

(define *subdivide-settings* (new 'global 'subdivide-settings 122880.0 286720.0))

;; WARN: Return type mismatch tfrag-dists vs none.
(defun set-tfrag-dists! ((arg0 tfrag-dists))
  "Update the subdivide settings used in tfrag VU1 code.
   This must be called after update-subdivide-settings!"
  (let ((f2-0 (-> *subdivide-settings* dist 0))
        (f1-0 (-> *subdivide-settings* dist 1))
        (f0-0 (-> *subdivide-settings* dist 2))
        )
    (set! (-> arg0 data 3) (the-as uint f2-0))
    (set! (-> arg0 data 7) (the-as uint f1-0))
    (let ((f4-1 (/ 1.0 (- f2-0 f1-0)))
          (f3-2 (/ 1.0 (- f1-0 f0-0)))
          )
      (set! (-> arg0 data 1) (the-as uint (- f4-1)))
      (set! (-> arg0 data 5) (the-as uint (- f3-2)))
      (set! (-> arg0 data 0) (the-as uint (* 0.5 f4-1)))
      (set! (-> arg0 data 4) (the-as uint (* 0.5 f3-2)))
      (let ((f2-1 (* f2-0 f4-1))
            (f5-7 (* f1-0 f3-2))
            )
        (set! (-> arg0 data 9) (the-as uint f2-1))
        (set! (-> arg0 data 13) (the-as uint f5-7))
        )
      (set! (-> arg0 data 8) (the-as uint (* -0.5 f4-1 f1-0)))
      (set! (-> arg0 data 12) (the-as uint (* -0.5 f3-2 f0-0)))
      )
    )
  (none)
  )

(kmemopen global "terrain-context")

(define *terrain-context* (new 'global 'terrain-context))

(kmemclose)

;; WARN: Return type mismatch perf-stat vs none.
(defmethod print-to-stream ((this perf-stat) (arg0 string) (arg1 basic))
  (format
    *stdcon*
    "~3d  ~8d  ~8d  ~6d ~6d"
    (-> this count)
    (-> this cycles)
    0 ;; (-> this instructions)
    0 ;; (-> this icache) og:preserve-this doesn't work on PC
    0 ;; (-> this dcache)
    )
  (format *stdcon* "  ~2d ~2d ~2d" (-> this to-vu0-waits) (-> this to-spr-waits) (-> this from-spr-waits))
  (format *stdcon* "   ~s~%" arg0)
  (none)
  )

(define GSH_ENABLE #f)

(define GSH_BUCKET (bucket-id bucket3))

(define GSH_WHICH_STAT 1)

(define GSH_MAX_DISPLAY (the-as basic #f))

(define GSH_TIME 64)

(define *perf-stats* (new 'debug 'perf-stat-array 57))

(when *debug-segment*
(define *gomi-stats-hack* (the-as (inline-array perf-stat) (malloc 'debug (* 52 (+ GSH_TIME 1)))))

)
(defun-debug start-perf-stat-collection ()
  "Start the per-frame performance stats.
   This automatically cycles through various stats/categories,
   collecting and aggregating the latest data."
  (let ((v1-2 (+ (-> *perf-stats* data 0 frame-number) 1)))
    (set! (-> *perf-stats* data 0 frame-number) v1-2)
    (let ((gp-0 (mod v1-2 (the-as uint 114))))
      (when GSH_ENABLE
        (let ((v1-5 GSH_BUCKET))
          (let ((a0-2 GSH_WHICH_STAT))
            (set! gp-0 (+ (* (the uint v1-5) 2) a0-2))
            )
          (when GSH_MAX_DISPLAY
            (let ((a0-7 (logand (-> *perf-stats* data 0 frame-number) (+ GSH_TIME -1))))
              (set! (-> *gomi-stats-hack* a0-7 cycles) (-> *perf-stats* data (the-as int v1-5) cycles))
              (set! (-> *gomi-stats-hack* a0-7 instructions) (-> *perf-stats* data (the-as int v1-5) instructions))
              (set! (-> *gomi-stats-hack* a0-7 icache) (-> *perf-stats* data (the-as int v1-5) icache))
              (set! (-> *gomi-stats-hack* a0-7 dcache) (-> *perf-stats* data (the-as int v1-5) dcache))
              (when (zero? a0-7)
                (set! (-> *gomi-stats-hack* GSH_TIME cycles) (the-as uint 0))
                (set! (-> *gomi-stats-hack* GSH_TIME instructions) (the-as uint 0))
                (set! (-> *gomi-stats-hack* GSH_TIME icache) (the-as uint 0))
                (set! (-> *gomi-stats-hack* GSH_TIME dcache) (the-as uint 0))
                (dotimes (v1-22 GSH_TIME)
                  (if (< (-> *gomi-stats-hack* GSH_TIME cycles) (-> *gomi-stats-hack* v1-22 cycles))
                      (set! (-> *gomi-stats-hack* GSH_TIME cycles) (-> *gomi-stats-hack* v1-22 cycles))
                      )
                  (if (< (-> *gomi-stats-hack* GSH_TIME instructions) (-> *gomi-stats-hack* v1-22 instructions))
                      (set! (-> *gomi-stats-hack* GSH_TIME instructions) (-> *gomi-stats-hack* v1-22 instructions))
                      )
                  (if (< (-> *gomi-stats-hack* GSH_TIME icache) (-> *gomi-stats-hack* v1-22 icache))
                      (set! (-> *gomi-stats-hack* GSH_TIME icache) (-> *gomi-stats-hack* v1-22 icache))
                      )
                  (if (< (-> *gomi-stats-hack* GSH_TIME dcache) (-> *gomi-stats-hack* v1-22 dcache))
                      (set! (-> *gomi-stats-hack* GSH_TIME dcache) (-> *gomi-stats-hack* v1-22 dcache))
                      )
                  )
                )
              )
            (format *stdcon* "~%")
            (print-to-stream (-> *gomi-stats-hack* GSH_TIME) "max-value" *stdcon*)
            )
          )
        )
      (dotimes (v1-27 57)
        (set! (-> *perf-stats* data v1-27 count) (the-as uint 0))
        (cond
          ((!= v1-27 (shr gp-0 1))
           (set! (-> *perf-stats* data v1-27 ctrl) (the-as uint 0))
           0
           )
          (else
            (let ((a1-63 (logand gp-0 1))
                  (a0-64 #x80004010)
                  )
              (cond
                ((zero? a1-63)
                 (set! a0-64 (+ #x60020 a0-64))
                 )
                ((= a1-63 1)
                 (set! a0-64 (+ #x300c0 a0-64))
                 )
                )
              (set! (-> *perf-stats* data v1-27 select) a1-63)
              (set! (-> *perf-stats* data v1-27 ctrl) a0-64)
              )
            (set! (-> *perf-stats* data v1-27 accum0) (the-as uint 0))
            (set! (-> *perf-stats* data v1-27 accum1) (the-as uint 0))
            (set! (-> *perf-stats* data v1-27 to-vu0-waits) (the-as uint 0))
            (set! (-> *perf-stats* data v1-27 to-spr-waits) (the-as uint 0))
            (set! (-> *perf-stats* data v1-27 from-spr-waits) (the-as uint 0))
            0
            )
          )
        )
      )
    )
  (let* ((v1-31 (-> *perf-stats* data))
         (a0-76 (-> v1-31 0 ctrl))
         )
    (+! (-> v1-31 0 count) 1)
    (b! (zero? a0-76) cfg-28 :delay (nop!))
    (.mtc0 Perf 0)
    (set! *pc-perf-stat-counter* (get-cpu-clock)) ;; og:preserve-this patched
    (.sync.l)
    (.sync.p)
    ;(.mtpc pcr0 0)
    ;(.mtpc pcr1 0)
    (.sync.l)
    (.sync.p)
    (.mtc0 Perf a0-76)
    )
  (.sync.l)
  (.sync.p)
  (label cfg-28)
  0
  0
  (none)
  )

;; og:preserve-this this part is patched
(if (not *debug-segment*)
    (set! start-perf-stat-collection
          (lambda ()
            (dotimes (v1-0 51)
              (set! (-> *perf-stats* data v1-0 count) (the-as uint 0))
              )
            0
            (none)
            )
          )
    )

(defun-debug end-perf-stat-collection ()
  "End the per-frame performance stats"
  (local-vars (a0-1 int) (a0-3 int))
  (let ((v1-1 (-> *perf-stats* data)))
    (b! (zero? (-> v1-1 0 ctrl)) cfg-2 :delay (nop!))
    (.mtc0 Perf 0)
    (.sync.l)
    (.sync.p)
    ;(.mfpc a0-1 pcr0)
    (+! (-> v1-1 0 accum0) a0-1)
    (+! (-> v1-1 0 accum0) (- (get-cpu-clock) *pc-perf-stat-counter*)) ;; og:preserve-this patched
    ;(.mfpc a0-3 pcr1)
    (+! (-> v1-1 0 accum1) 0) ;; og:preserve-this patched
    )
  (label cfg-2)
  0
  (dotimes (v1-3 57)
    (when (nonzero? (-> *perf-stats* data v1-3 ctrl))
      (let ((a2-0 (-> *perf-stats* data v1-3 select))
            (a1-8 (-> *perf-stats* data v1-3 accum0))
            (a0-15 (-> *perf-stats* data v1-3 accum1))
            )
        (cond
          ((zero? a2-0)
           (set! (-> *perf-stats* data v1-3 cycles) a1-8)
           (set! (-> *perf-stats* data v1-3 instructions) a0-15)
           )
          ((= a2-0 1)
           (set! (-> *perf-stats* data v1-3 icache) a1-8)
           (set! (-> *perf-stats* data v1-3 dcache) a0-15)
           )
          )
        )
      )
    )
  0
  (none)
  )

(defun-debug print-perf-stats ()
  (format *stdcon* "~0k~%count  cycles     instr  icache dcache  vu0/to/from~%")
  (dotimes (gp-0 57)
    (if (and (nonzero? (-> *perf-stats* data gp-0 count)) (< (the-as uint 10000) (-> *perf-stats* data gp-0 cycles)))
        (print-to-stream
          (-> *perf-stats* data gp-0)
          (perf-stat-bucket->string (the-as perf-stat-bucket gp-0))
          *stdcon*
          )
        )
    )
  0
  (none)
  )
