;;-*-Lisp-*- (in-package goal) ;; name: bones.gc ;; name in dgo: bones ;; dgos: GAME, ENGINE ;; Bones. ;; There are 4 main functions used by the outside world: ;; - bones-init. Call this before doing process-drawable DMA building. ;; - draw-bones. Call this once for each process-drawable during DMA building. ;; - bones-wrapup. Call this after all calls to draw-bones. ;; the above 3 functions are done separate for different levels. ;; - bones-mtx-calc-execute. Call this after all that. ;; It's more than just bones in here - submitting to merc is done from here. ;;;;;;;;;;;;;;;;;; ;; calc list ;;;;;;;;;;;;;;;;;; (defenum bone-calc-flags :type uint16 :bitfield #t (bncfl00 0) (bncfl01 1) ;; use identity matrix in bone matrix calc instead of cam rot (effectively screen-space bones?) (bncfl02 2) (bncfl03 3) (bncfl04 4) (bncfl05 5) (bncfl06 6) (bncfl07 7) (bncfl08 8) (bncfl09 9) (bncfl10 10) (bncfl11 11) (bncfl12 12) (bncfl13 13) (bncfl14 14) (bncfl15 15) ) ;; this type represents a "calculation" that will be performed at later time. (deftype bone-calculation (structure) ((flags bone-calc-flags :offset-assert 0) (num-bones uint16 :offset-assert 2) (matrix-area (inline-array matrix) :offset-assert 4) (joints (inline-array joint) :offset-assert 8) (bones (inline-array bone) :offset-assert 12) (ripple-scale float :offset-assert 16) (ripple-y-scale float :offset-assert 20) (ripple-normal-scale float :offset-assert 24) (ripple-area (inline-array vector) :offset-assert 28) (next bone-calculation :offset-assert 32) (dummy-1 uint32 :offset-assert 36) (dummy-2 uint32 :offset-assert 40) (dummy-3 uint32 :offset-assert 44) ) :method-count-assert 9 :size-assert #x30 :flag-assert #x900000030 ) ;; linked list of bone-calculations. ;; you have to bring your own bone-calculations (deftype bone-calculation-list (structure) ((first bone-calculation :offset-assert 0) (next bone-calculation :offset-assert 4) ) :method-count-assert 9 :size-assert #x8 :flag-assert #x900000008 ) ;; the global calculation list. (define *bone-calculation-list* (new 'global 'bone-calculation-list)) (defun bone-list-init () "Reset the bone list to have nothing." (let ((v1-0 *bone-calculation-list*)) (set! (-> v1-0 first) (the-as bone-calculation 0)) (set! (-> v1-0 next) (the-as bone-calculation 0)) ) (none) ) (bone-list-init) ;;;;;;;;;;;;;;;;;; ;; texscroll ;;;;;;;;;;;;;;;;;; ;; the "texture scroll" moves the texture. This is done by modifying the merc data. ;; list of all texture scroll effects. (deftype texscroll-globals (structure) ((requests int32 :offset-assert 0) (effects merc-effect 32 :offset-assert 4) ) :method-count-assert 9 :size-assert #x84 :flag-assert #x900000084 ) (define *texscroll-globals* (new 'global 'texscroll-globals)) (defun texscroll-make-request ((arg0 merc-effect)) "Request that the given merc-effect have its texture scroll updated. Note: only call this if you actually have a texture scroll effect!" (let* ((v1-1 (-> *texscroll-globals* requests)) (a1-0 (-> arg0 extra-info)) (a1-1 (the-as mei-texture-scroll (+ (the-as uint a1-0) (* (-> a1-0 texture-scroll-offset) 16)))) ) (when (< v1-1 32) (let* ((a3-1 (-> *display* integral-frame-counter)) (a2-3 (-> a1-1 time-factor)) (t0-2 (+ (ash 1 a2-3) -1)) ) (if (zero? (-> a1-1 scroll-dir)) (set! a3-1 (- a3-1)) ) (let ((a2-5 (ash (ash (logand a3-1 t0-2) (- 12 (the-as int (-> a1-1 st-int-scale)))) (- (the-as int a2-3))))) (when (!= a2-5 (-> a1-1 cached-time)) (set! (-> a1-1 time-delta) (the-as uint (- a2-5 (the-as int (-> a1-1 cached-time))))) (set! (-> a1-1 cached-time) (the-as uint a2-5)) (set! (-> *texscroll-globals* effects v1-1) arg0) (+! (-> *texscroll-globals* requests) 1) ) ) ) ) ) (none) ) (defun texscroll-execute () "Do all requested texture scroll updates." (dotimes (v1-0 (-> *texscroll-globals* requests)) (let* ((a2-0 (-> *texscroll-globals* effects v1-0)) (a0-2 (-> a2-0 frag-count)) (a1-1 (-> a2-0 extra-info)) (a1-2 (the-as mei-texture-scroll (+ (the-as uint a1-1) (* (-> a1-1 texture-scroll-offset) 16)))) (t1-0 (-> a2-0 frag-geo)) (a2-1 (-> a2-0 frag-ctrl)) ) (dotimes (a3-2 (the-as int a0-2)) (let ((t0-4 (&+ (the-as pointer t1-0) (logand (* (+ (-> a2-1 unsigned-four-count) 3) 4) #xfff0)))) (let ((t2-2 (+ (-> t1-0 header mat1-cnt) (-> t1-0 header mat2-cnt) (-> t1-0 header mat3-cnt)))) (the-as (pointer int8) (-> a1-2 time-delta)) (let* ((t1-3 (the-as (pointer int8) (&+ t0-4 9))) (t2-4 (&+ t1-3 (* (the-as uint 12) t2-2))) (t3-3 (-> a1-2 time-delta)) ) (nop!) (label cfg-3) (let ((t4-0 (-> t1-3 0))) (nop!) (nop!) (nop!) (let ((t4-1 (+ t4-0 t3-3))) (set! t1-3 (&-> t1-3 12)) (b! (!= t1-3 t2-4) cfg-3 :delay (set! (-> t1-3 -12) t4-1)) ) ) ) ) (set! t1-0 (the-as merc-fragment (&+ (&+ t0-4 (logand (* (+ (-> a2-1 lump-four-count) 3) 4) #xfff0)) (* (-> a2-1 fp-qwc) 16)) ) ) ) (set! a2-1 (the-as merc-fragment-control (+ (the-as uint a2-1) (* (-> a2-1 mat-xfer-count) 2) 4))) ) ) ) (set! (-> *texscroll-globals* requests) 0) 0 (none) ) ;;;;;;;;;;;;;;;;;;;; ;; Merc Submission ;;;;;;;;;;;;;;;;;;;; ;; when submitting to merc, we must provide some information to pick the appropriate rendering settings. ;; this information can't be precomputed and is done in bones. ;; per-effect information (deftype merc-effect-bucket-info (structure) ((color-fade rgba :offset-assert 0) (use-mercneric uint8 :offset-assert 4) (ignore-alpha uint8 :offset-assert 5) (pad0 uint8 :offset-assert 6) (pad1 uint8 :offset-assert 7) ) :pack-me :method-count-assert 9 :size-assert #x8 :flag-assert #x900000008 ) ;; information for everything being submitted. (deftype merc-bucket-info (structure) ((light vu-lights :inline :offset-assert 0) (needs-clip int32 :offset-assert 112) (need-mercprime-if-merc int32 :offset-assert 116) (must-use-mercneric-for-clip int32 :offset-assert 120) (effect merc-effect-bucket-info 16 :inline :offset-assert 124) ) :method-count-assert 9 :size-assert #xfc :flag-assert #x9000000fc ) (define *merc-bucket-info* (new 'global 'merc-bucket-info)) ;; UNUSED. (define *use-generic* #f) ;;;;;;;;;;;;;;;; ;; VU / DMA ;;;;;;;;;;;;;;;; (define bones-vu0-block (new 'static 'vu-function #|:length 63 :qlength 32|#)) ;; these changes only matter if transferring in _interleave_ mode. (defun bones-set-sqwc () ;; transfer 4, skip 1. (#unless PC_PORT (set! (-> (the-as dma-bank-control #x1000e000) sqwc) (new 'static 'dma-sqwc :sqwc #x1 :tqwc #x4)) ) (none) ) (defun bones-reset-sqwc () ;; transfer 1, skip 1 ;; note: not sure what uses this mode?? (#unless PC_PORT (set! (-> (the-as dma-bank-control #x1000e000) sqwc) (new 'static 'dma-sqwc :sqwc #x1 :tqwc #x1)) ) (none) ) ;; ?? used by generic merc (define *merc-global-array* (new 'global 'merc-global-array)) (defun vu-lights<-light-group! ((arg0 vu-lights) (arg1 light-group)) "Convert a light-group to the VU format lights used by merc." (local-vars (v1-0 uint128) (v1-1 uint128) (a2-1 uint128) (t0-1 uint128) (t1-1 uint128)) (rlet ((vf0 :class vf) (vf10 :class vf) (vf11 :class vf) (vf4 :class vf) (vf5 :class vf) (vf6 :class vf) (vf7 :class vf) (vf8 :class vf) (vf9 :class vf) ) (init-vf0-vector) (nop!) (let ((a3-0 (the-as uint128 (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)))) (nop!) (let ((a2-0 (-> arg1 dir0 direction quad))) (nop!) (let ((t1-0 (-> arg1 dir1 direction quad))) (nop!) (.lvf vf4 (&-> arg1 dir0 color quad)) (.pextlw v1-0 t1-0 a2-0) (let ((t0-0 (-> arg1 dir2 direction quad))) (.pextuw a2-1 t1-0 a2-0) (.lvf vf8 (&-> arg1 dir0 levels quad)) (.pextlw t1-1 a3-0 t0-0) (.lvf vf5 (&-> arg1 dir1 color quad)) (.pextuw t0-1 a3-0 t0-0) ) ) ) ) (.lvf vf9 (&-> arg1 dir1 levels quad)) (let ((a3-1 (make-u128 t1-1 v1-0))) (.lvf vf6 (&-> arg1 dir2 color quad)) (.pcpyud v1-1 v1-0 t1-1) (.lvf vf10 (&-> arg1 dir2 levels quad)) (let ((a2-2 (make-u128 (the-as int t0-1) a2-1))) (.lvf vf7 (&-> arg1 ambi color quad)) (.mul.x.vf vf4 vf4 vf8) (.lvf vf11 (&-> arg1 ambi levels quad)) (.mul.x.vf vf5 vf5 vf9) (set! (-> arg0 direction 0 quad) (the-as uint128 a3-1)) (.mul.x.vf vf6 vf6 vf10) (set! (-> arg0 direction 1 quad) v1-1) (.mul.x.vf vf7 vf7 vf11) (set! (-> arg0 direction 2 quad) (the-as uint128 a2-2)) ) ) (.min.x.vf vf4 vf0 vf0 :mask #b1000) (nop!) (.min.x.vf vf5 vf0 vf0 :mask #b1000) (nop!) (.min.x.vf vf6 vf0 vf0 :mask #b1000) (nop!) (.max.w.vf vf7 vf0 vf0 :mask #b1000) (nop!) (nop!) (.svf (&-> arg0 color 0 quad) vf4) (nop!) (.svf (&-> arg0 color 1 quad) vf5) (nop!) (.svf (&-> arg0 color 2 quad) vf6) (nop!) (.svf (&-> arg0 ambient quad) vf7) 0 (none) ) ) ;;;;;;;;;;;;;;;;;;;; ;; BONE ;;;;;;;;;;;;;;;;;;;; (defun bones-init ((arg0 dma-buffer) (arg1 dma-foreground-sink-group)) "Initialize the scratchpad and VU0 for bone work." (scratchpad-object int) (let ((a2-1 (the-as bone-memory (+ 16 (scratchpad-object int)))) (v1-2 (the-as bone-memory (+ 16 (scratchpad-object int)))) ) ;; layout joints, bones, and outputs (set! (-> a2-1 work layout joint 0) (the-as joint (+ 256 (scratchpad-object int)))) (set! (-> a2-1 work layout joint 1) (the-as joint (+ 4864 (scratchpad-object int)))) (set! (-> a2-1 work layout bone 0) (the-as bone (+ 1280 (scratchpad-object int)))) (set! (-> a2-1 work layout bone 1) (the-as bone (+ 5888 (scratchpad-object int)))) (set! (-> a2-1 work layout output 0) (the-as uint (+ 2816 (scratchpad-object int)))) (set! (-> a2-1 work layout output 1) (the-as uint (+ 7424 (scratchpad-object int)))) ;; set up work (set! (-> v1-2 work next-tag dma) (new 'static 'dma-tag :id (dma-tag-id next))) (set! (-> v1-2 work next-tag vif0) (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))) (set! (-> v1-2 work next-tag vif1) (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))) (set! (-> v1-2 work dma-buf) arg0) (set! (-> v1-2 work sink-group) arg1) (set! (-> v1-2 work next-merc) (the-as dma-packet 0)) ) ;; reset globals (let ((v1-3 *merc-globals*)) (set! (-> v1-3 first) (the-as uint 0)) (set! (-> v1-3 next) (the-as uint 0)) ) ;; upload bones program. (#unless PC_PORT (let ((gp-0 *vu0-dma-list*)) (let ((v1-4 gp-0)) (set! (-> v1-4 base) (-> v1-4 data)) (set! (-> v1-4 end) (&-> v1-4 data-buffer (-> v1-4 allocated-length))) ) (dma-buffer-add-vu-function gp-0 bones-vu0-block 0) (let* ((v1-5 gp-0) (a0-6 (-> v1-5 base)) ) (set! (-> (the-as (pointer int64) a0-6)) #x70000000) (set! (-> (the-as (pointer int64) a0-6) 1) 0) (set! (-> v1-5 base) (&+ a0-6 16)) ) (.sync.l) (dma-buffer-send-chain (the-as dma-bank-source #x10008000) gp-0) ) ) ;; we will use "run" in the shadow queue. Reset that (but don't increment yet, just in case we don't draw shadows) (let ((gp-1 *shadow-queue*)) (if (>= (-> gp-1 cur-run) (the-as uint 15)) (format #t "Too many shadow-queues!!~%") ) (let ((v1-13 (-> gp-1 run (-> gp-1 cur-run)))) (set! (-> v1-13 first) (the-as uint 0)) (set! (-> v1-13 next) (the-as uint 0)) ) ) 0 (none) ) (defun draw-bones-mtx-calc ((arg0 bone-calculation) (arg1 int) (arg2 bone-calc-flags)) "Add the current work to the bone calculation list." (let ((t2-0 (the-as bone-memory (+ 16 (scratchpad-object int)))) (v1-1 *bone-calculation-list*) (a3-1 arg0) ) ;; grab active buffers (let ((t0-0 (-> t2-0 work regs joint-ptr)) (t1-0 (-> t2-0 work regs bone-ptr)) (t2-1 (-> t2-0 work regs num-bones)) (t3-0 a3-1) ) (set! (-> t3-0 flags) arg2) (set! (-> t3-0 num-bones) t2-1) (set! (-> t3-0 matrix-area) (the-as (inline-array matrix) arg1)) (set! (-> t3-0 joints) t0-0) (set! (-> t3-0 bones) t1-0) (set! (-> t3-0 next) (the-as bone-calculation 0)) ) ;; splice into list (if (nonzero? (-> v1-1 next)) (set! (-> v1-1 next next) a3-1) ) (if (zero? (-> v1-1 first)) (set! (-> v1-1 first) a3-1) ) (set! (-> v1-1 next) a3-1) ) (the-as object (&+ arg0 48)) ) (def-mips2c bones-mtx-calc (function int pointer pointer int object none)) (defun bones-mtx-calc-execute () "Do all pending bone calculations" (local-vars (v1-14 float)) (rlet ((vf1 :class vf) (vf2 :class vf) (vf25 :class vf) (vf26 :class vf) (vf27 :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) (vf7 :class vf) (vf8 :class vf) ) (if *debug-segment* (add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0) 'draw (new 'static 'rgba :r #x40 :b #x40 :a #x80) ) ) (let ((v1-8 (the-as bone-memory (+ 16 (scratchpad-object int))))) (+ 16 #x70000000) (set! (-> v1-8 work layout joint 0) (the-as joint (+ 256 (scratchpad-object int)))) (set! (-> v1-8 work layout joint 1) (the-as joint (+ 4864 (scratchpad-object int)))) (set! (-> v1-8 work layout bone 0) (the-as bone (+ 1280 (scratchpad-object int)))) (set! (-> v1-8 work layout bone 1) (the-as bone (+ 5888 (scratchpad-object int)))) (set! (-> v1-8 work layout output 0) (the-as uint (+ 2816 (scratchpad-object int)))) (set! (-> v1-8 work layout output 1) (the-as uint (+ 7424 (scratchpad-object int)))) ) (#unless PC_PORT (set! (-> (the-as dma-bank-control #x1000e000) sqwc) (new 'static 'dma-sqwc :sqwc #x1 :tqwc #x4))) (let* ((v1-10 *bone-calculation-list*) (gp-0 *identity-matrix*) (s5-0 (-> *math-camera* camera-rot)) (s4-0 (-> v1-10 first)) ) (while (nonzero? s4-0) (let ((v1-13 (if (logtest? (-> s4-0 flags) (bone-calc-flags bncfl01)) gp-0 s5-0 ) ) ) (.lvf vf28 (&-> v1-13 vector 0 quad)) (.lvf vf29 (&-> v1-13 vector 1 quad)) (.lvf vf30 (&-> v1-13 vector 2 quad)) (.lvf vf31 (&-> v1-13 vector 3 quad)) (.lvf vf25 (&-> v1-13 vector 0 quad)) (.lvf vf26 (&-> v1-13 vector 1 quad)) (.lvf vf27 (&-> v1-13 vector 2 quad)) (.mov v1-14 vf27) (bones-mtx-calc (the-as int (-> s4-0 matrix-area)) (the-as pointer (-> s4-0 joints)) (the-as pointer (-> s4-0 bones)) (the-as int (-> s4-0 num-bones)) v1-13 ;; hack, added ) ) (when (logtest? (-> s4-0 flags) (bone-calc-flags bncfl00)) (let ((v1-18 (-> s4-0 matrix-area)) (a0-22 (-> s4-0 num-bones)) (f1-0 (-> s4-0 ripple-scale)) (f2-0 (-> s4-0 ripple-y-scale)) (f0-0 (-> s4-0 ripple-normal-scale)) (a1-9 (-> s4-0 ripple-area)) ) (let ((a2-2 f2-0)) (.mov vf1 a2-2) ) (let ((a2-3 f1-0)) (.mov vf2 a2-3) ) (let ((a2-4 f0-0)) (.mov vf3 a2-4) ) (label cfg-8) (.lvf vf5 (&-> v1-18 0 vector 1 quad)) (.lvf vf6 (&-> v1-18 0 vector 3 quad)) (.lvf vf7 (&-> v1-18 1 vector 0 quad)) (.lvf vf8 (&-> v1-18 1 vector 2 quad)) (.mul.x.vf vf4 vf5 vf2) (.mul.x.vf vf5 vf5 vf1) (let ((a3-1 (-> v1-18 0 vector 0 quad))) (.mul.x.vf vf7 vf7 vf3) (let ((a2-6 (-> v1-18 0 vector 2 quad))) (.mul.x.vf vf8 vf8 vf3) (set! (-> a1-9 0 quad) a3-1) (let ((a3-2 (-> v1-18 1 vector 1 quad))) (.sub.vf vf6 vf6 vf4) (set! (-> a1-9 2 quad) a2-6) (.svf (&-> a1-9 1 quad) vf5) (set! (-> a1-9 5 quad) a3-2) ) ) ) (+! a0-22 -1) (.svf (&-> a1-9 4 quad) vf7) ;(.addiu v1-18 (the-as object v1-18) 128) (&+ v1-18 128) (.svf (&-> a1-9 3 quad) vf6) ;;(.addiu (the-as (inline-array vector) a1-9) a1-9 128) (&+ a1-9 128) (b! (nonzero? a0-22) cfg-8 :delay (.svf (&-> a1-9 -2 quad) vf8)) ) 0 ) (set! s4-0 (-> s4-0 next)) ) ) (#unless PC_PORT (set! (-> (the-as dma-bank-control #x1000e000) sqwc) (new 'static 'dma-sqwc :sqwc #x1 :tqwc #x1))) (bone-list-init) (if *debug-segment* (add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0) 'draw (new 'static 'rgba :r #x7b :g #x7b :b #x7b :a #x80) ) ) 0 (none) ) ) (defun bones-wrapup () (let ((v1-1 (the-as bone-memory (+ 16 (scratchpad-object int))))) (when (nonzero? (-> v1-1 work next-merc)) ;; only add if we actually drew with merc. (let* ((a0-2 (-> v1-1 work dma-buf)) (a3-0 (-> a0-2 base)) ) (let ((a1-0 (the-as object (-> a0-2 base)))) (set! (-> (the-as dma-packet a1-0) dma) (new 'static 'dma-tag :id (dma-tag-id next))) (set! (-> (the-as dma-packet a1-0) vif0) (new 'static 'vif-tag)) (set! (-> (the-as dma-packet a1-0) vif1) (new 'static 'vif-tag)) (set! (-> a0-2 base) (&+ (the-as pointer a1-0) 16)) ) (dma-bucket-insert-tag (-> *display* frames (-> *display* on-screen) frame bucket-group) (-> v1-1 work sink-group merc-sink bucket) (the-as pointer (-> v1-1 work next-merc)) (the-as (pointer dma-tag) a3-0) ) ) ) ) (none) ) ;;;;;;;;;;;;;;; ;; bone debug ;;;;;;;;;;;;;;; (define *bones-first* #f) (defun-debug dump-qword ((arg0 qword)) (let ((v1-0 arg0)) (format 0 "~8,'0X: ~8,'0X ~8,'0X ~8,'0X ~8,'0X~%" v1-0 (-> v1-0 data 0) (-> v1-0 data 1) (-> v1-0 data 2) (-> v1-0 data 3) ) ) 0 (none) ) (defun-debug dump-mem ((arg0 pointer) (arg1 int)) (dotimes (s4-0 arg1) (format 0 "~8,'0X: ~8,'0X ~8,'0X ~8,'0X ~8,'0X" (&+ arg0 (* (* s4-0 4) 4)) (-> (the-as (pointer uint32) (&+ arg0 (* (* s4-0 4) 4)))) (-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 1) 4)))) (-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 2) 4)))) (-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 3) 4)))) ) (format 0 " ~F ~F ~F ~F ~%" (-> (the-as (pointer uint32) (&+ arg0 (* (* s4-0 4) 4)))) (-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 1) 4)))) (-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 2) 4)))) (-> (the-as (pointer uint32) (&+ arg0 (* (+ (* s4-0 4) 3) 4)))) ) ) 0 (none) ) (defun-debug bones-debug () 0 (none) ) (defun-debug dump-bone-mem () (format 0 "== joints 0 ===========~%") (dump-mem (the-as pointer (+ 256 #x70000000)) 64) (format 0 "== bones 0 ============~%") (dump-mem (the-as pointer (+ 1280 #x70000000)) 96) (format 0 "== output 0 ===========~%") (dump-mem (the-as pointer (+ 2816 #x70000000)) 128) (format 0 "~%~%~%") (format 0 "== joints 1 ===========~%") (dump-mem (the-as pointer (+ 4864 #x70000000)) 64) (format 0 "== bones 1 ============~%") (dump-mem (the-as pointer (+ 5888 #x70000000)) 96) (format 0 "== output 1 ===========~%") (dump-mem (the-as pointer (+ 7424 #x70000000)) 128) (format 0 "== dma-list ===========~%") (dump-mem (the-as pointer (+ 256 #x70000000)) 90) (format 0 "========================~%~%") 0 (none) ) (define *default-shadow-settings* (new 'static 'shadow-settings :shadow-dir (new 'static 'vector :x -0.4226 :y -0.9063 :w 409600.0) :bot-plane (new 'static 'plane :y 1.0 :w 37683.2) :top-plane (new 'static 'plane :y 1.0 :w 4096.0) :fade-dist 409600.0 ) ) ;; draw-bones-shadow ;; draw-bones-generic-merc ;; draw-boes-merc ;; draw-bones-check-longest-edge ;; draw-bones-check-longest-edgei-asm ;; draw-bones ;; draw-bones-hud ;; HACK incomplete: (defun draw-bones-hack ((arg0 draw-control) (arg1 dma-buffer) (arg2 float)) (local-vars (at-0 object) (a0-16 int) (a0-17 int) (a0-62 int) (a2-10 int) (a2-12 int) (sv-96 int) (sv-112 int) (sv-128 int) (sv-144 ripple-control) ) (rlet ((vf1 :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) ) (let* ((s1-0 (+ (-> arg0 mgeo num-joints) 3)) (a0-1 (* s1-0 128)) ) ;;(.lui at-0 28672) (let* ((v1-2 (-> arg1 base)) (a1-1 (the-as object (&+ v1-2 16))) (s3-0 (the-as object (&+ v1-2 64))) ) (let ((a2-1 (logand (the-as int s3-0) 48))) (b! (zero? a2-1) cfg-2 :delay (nop!)) (set! s3-0 (&- (&+ (the-as pointer s3-0) 64) (the-as uint a2-1))) ) (label cfg-2) ; (let* ((a2-3 (-> *perf-stats* data 13)) ; (a3-1 (-> a2-3 ctrl)) ; ) ; (+! (-> a2-3 count) 1) ; (b! (zero? a3-1) cfg-4 :delay (nop!)) ; (.mtc0 Perf r0) ; (.sync.l) ; (.sync.p) ; (.mtpc pcr0 r0) ; (.mtpc pcr1 r0) ; (.sync.l) ; (.sync.p) ; (.mtc0 Perf a3-1) ; ) ; (.sync.l) ; (.sync.p) ; (label cfg-4) 0 (let ((a2-6 (the-as bone-regs (+ 240 (scratchpad-object int))))) (set! (-> a2-6 joint-ptr) (the-as (inline-array joint) (-> arg0 jgeo data 0))) (set! (-> a2-6 bone-ptr) (-> arg0 skeleton bones)) (set! (-> a2-6 num-bones) (the-as uint s1-0)) ) (let ((t0-2 s3-0) (t1-0 0) (t4-0 (the-as bone-memory (+ 16 (scratchpad-object int)))) (a2-8 *bone-calculation-list*) (a3-8 (the-as bone-calculation a1-1)) ) (let ((t2-0 (-> t4-0 work regs joint-ptr)) (t3-0 (-> t4-0 work regs bone-ptr)) (t4-1 (-> t4-0 work regs num-bones)) (t5-0 a3-8) ) (set! (-> t5-0 flags) (the-as bone-calc-flags t1-0)) (set! (-> t5-0 num-bones) t4-1) (set! (-> t5-0 matrix-area) (the-as (inline-array matrix) t0-2)) (set! (-> t5-0 joints) t2-0) (set! (-> t5-0 bones) t3-0) (set! (-> t5-0 next) (the-as bone-calculation 0)) ) (if (nonzero? (-> a2-8 next)) (set! (-> a2-8 next next) a3-8) ) (if (zero? (-> a2-8 first)) (set! (-> a2-8 first) a3-8) ) (set! (-> a2-8 next) a3-8) ;; total guess (&+! (-> arg1 base) (* 2 (+ 256 a0-1))) ) ))) (none)) (def-mips2c draw-bones-merc (function draw-control object object int int pointer)) (def-mips2c draw-bones-check-longest-edge-asm (function draw-control float symbol)) (defun draw-bones ((arg0 draw-control) (dma-buf dma-buffer) (arg2 float)) "Main draw function for all bone-related renderers. Will set up merc, generic and shadow. and also add the bones to the calculation list." (local-vars (a0-16 int) (a0-17 int) (a0-62 int) (a2-10 int) (a2-12 int) (used-merc int) (used-mercneric int) (effect-idx int) (sv-144 ripple-control)) (rlet ((vf1 :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) (acc :class vf)) ;; compute the number of bones. I believe this num-joints doesn't count align/prejoint/main, so each needs a bone (let* ((num-bones (+ (-> arg0 mgeo num-joints) 3)) ;; we'll use 128-bytes/bone. (bone-data-size (* num-bones 128)) ;; temp work (spr-work (scratchpad-object terrain-context)) ) ;;;;;;;;;;;;;;;;;;;;;;;;; ;; BONE CALC SETUP ;;;;;;;;;;;;;;;;;;;;;;;;; ;; next, grab some DMA data. ;; we'll also use this for storing bone calculation entries. (let* ((dma-data-start (-> dma-buf base)) ;; first qw is the tag, stash the bone-calc-entry right after that. (bone-calc-entry (the-as bone-calculation (&+ dma-data-start 16))) ;; after that we'll use the space for storing bone matrices. ;; we won't calculate them now, but instead we'll tell the *bone-calculation-list* to put them here later. (matrix-data (the-as object (&+ dma-data-start 64))) ) ;; align the matrix data to 64 bytes (we know it is at least 16 byte aligned) (let ((a2-1 (logand (the-as int matrix-data) 48))) (b! (zero? a2-1) cfg-2 :delay (nop!)) (set! matrix-data (&- (&+ (the-as pointer matrix-data) 64) (the-as uint a2-1))) ) (label cfg-2) ;; start recording perf stats. ;; this just counts the stats for adding the calculation to the linked list. ;; which is really fast and not worth profiling. ;; I suspect the bone calculation originally was here, ;; but they moved it and forgot to move the performance counters too. (reset! (-> *perf-stats* data (perf-stat-bucket bones))) ;; figure out where everything will be (let ((a2-6 (the-as bone-regs (+ 240 (scratchpad-object int))))) ;; the joints are stored in the static art data (set! (-> a2-6 joint-ptr) (the-as (inline-array joint) (-> arg0 jgeo data 0))) ;; the final bones output used by the rest of the engine is stored in ;; the process-drawable's skeleton (set! (-> a2-6 bone-ptr) (-> arg0 skeleton bones)) (set! (-> a2-6 num-bones) (the-as uint num-bones)) ) ;; Add the bone calculation to the list, to be done later. ;; this will write to both the "matrix data" and the bones array. (let ((t0-2 matrix-data) (t1-0 0) (t4-0 (the-as bone-memory (+ 16 (scratchpad-object int)))) (a2-8 *bone-calculation-list*) (a3-8 bone-calc-entry) ) (let ((t2-0 (-> t4-0 work regs joint-ptr)) (t3-0 (-> t4-0 work regs bone-ptr)) (t4-1 (-> t4-0 work regs num-bones)) (t5-0 a3-8) ) (set! (-> t5-0 flags) (the-as bone-calc-flags t1-0)) (set! (-> t5-0 num-bones) t4-1) (set! (-> t5-0 matrix-area) (the-as (inline-array matrix) t0-2)) (set! (-> t5-0 joints) t2-0) (set! (-> t5-0 bones) t3-0) (set! (-> t5-0 next) (the-as bone-calculation 0)) ) (if (nonzero? (-> a2-8 next)) (set! (-> a2-8 next next) a3-8) ) (if (zero? (-> a2-8 first)) (set! (-> a2-8 first) a3-8) ) (set! (-> a2-8 next) a3-8) ) (&+ bone-calc-entry 48) ;; end stat collection (read! (-> *perf-stats* data (perf-stat-bucket bones))) ;; set up the dma buffer (let ((s2-0 (the-as object (+ (the-as uint matrix-data) bone-data-size)))) (let ((a0-2 (shl (the-as int s2-0) 32))) (set! (-> (the-as (pointer uint128) dma-data-start)) (logior (-> spr-work work foreground bone-mem work next-tag quad) a0-2) ) ;; NOTE: does this work correctly for the upper 64 bits?? ) ;; only data-format 1 is supported. (when (= (-> arg0 data-format) 1) ;; lights should be converted to a single vu-lights already, by the drawing code. ;; it stashes lights on the scratchpad. We'll load these here and transform them. ;; the result goes in the merc-bucke-info. (let ((v1-6 (the-as vu-lights (+ 64 (scratchpad-object int)))) (a0-7 (-> *merc-bucket-info* light)) ) (let ((a1-8 (-> *math-camera* inv-camera-rot))) (.lvf vf4 (&-> a1-8 vector 0 quad)) (.lvf vf5 (&-> a1-8 vector 1 quad)) (.lvf vf6 (&-> a1-8 vector 2 quad)) ) (.lvf vf1 (&-> v1-6 direction 0 quad)) (.lvf vf2 (&-> v1-6 direction 1 quad)) (.lvf vf3 (&-> v1-6 direction 2 quad)) ;;(.vcallms 54) ;; TODO! ;mulax.xyzw ACC, vf01, vf04 (.mul.x.vf acc vf1 vf4) ;madday.xyzw ACC, vf02, vf04 (.add.mul.y.vf acc vf2 vf4 acc) ;maddz.xyzw vf07, vf03, vf04 (.add.mul.z.vf vf7 vf3 vf4 acc) ;mulax.xyzw ACC, vf01, vf05 (.mul.x.vf acc vf1 vf5) ;madday.xyzw ACC, vf02, vf05 (.add.mul.y.vf acc vf2 vf5 acc) ;maddz.xyzw vf08, vf03, vf05 (.add.mul.z.vf vf8 vf3 vf5 acc) ;mulax.xyzw ACC, vf01, vf06 (.mul.x.vf acc vf1 vf6) ;madday.xyzw ACC, vf02, vf06 :e (.add.mul.y.vf acc vf2 vf6 acc) ;maddz.xyzw vf09, vf03, vf06 (.add.mul.z.vf vf9 vf3 vf6 acc) (let ((a1-9 (-> v1-6 color 0 quad))) (let ((a2-14 (-> v1-6 color 1 quad))) (let ((a3-11 (-> v1-6 color 2 quad))) (let ((v1-7 (-> v1-6 ambient quad))) (set! (-> a0-7 color 0 quad) a1-9) (set! (-> a0-7 color 1 quad) a2-14) (set! (-> a0-7 color 2 quad) a3-11) (set! (-> a0-7 ambient quad) v1-7) ) ) ) ) (.svf (&-> a0-7 direction 0 quad) vf7) (.svf (&-> a0-7 direction 1 quad) vf8) (.svf (&-> a0-7 direction 2 quad) vf9) (set! (-> a0-7 direction 1 w) (the-as float 0)) ) ;; the drawable system's culling already knows if we need clipping or not, ;; we just trust it. (set! (-> *merc-bucket-info* needs-clip) (if (logtest? (-> arg0 status) (draw-status needs-clip)) 1 0 ) ) ;; Now, we need to decide on merc settings. Default to nothing. (set! used-merc 0) (set! used-mercneric 0) (set! (-> *merc-bucket-info* need-mercprime-if-merc) 0) (set! (-> *merc-bucket-info* must-use-mercneric-for-clip) 0) (when (logtest? (-> arg0 status) (draw-status needs-clip)) ;; we can either clip with "mercprime" (part of merc), or fall back to generic. ;; the generic approach always works, but is slower, so we try to use mercprime. ;; the user must provide a longest edge length, and we must pass an edge check (fails if close to camera) (cond ((nonzero? (-> arg0 longest-edge)) ;; TODO this makes close up things bad... (if (draw-bones-check-longest-edge-asm arg0 arg2) (set! (-> *merc-bucket-info* need-mercprime-if-merc) 1) ;; clip with mercprime! (set! (-> *merc-bucket-info* must-use-mercneric-for-clip) 1) ;; failed, use generic ) ) (else (set! (-> *merc-bucket-info* must-use-mercneric-for-clip) 1) ;; no longest edge info, use generic. ) ) ) ;; grab the geometry at the appropriate level of detail. (let ((geom (-> arg0 lod-set lod (-> arg0 cur-lod) geo))) ;; loop over effects, and set them up/pick renderers. (set! effect-idx 0) (while (< effect-idx (the-as int (-> geom header effect-count))) ;; try texture scroll (when (logtest? (-> geom effect effect-idx effect-bits) 1) (let* ((v1-35 (-> geom effect effect-idx extra-info)) (v1-36 (the-as mei-texture-scroll (+ (the-as uint v1-35) (* (-> v1-35 texture-scroll-offset) 16)))) ) (if (< arg2 (-> v1-36 max-dist)) ;; just add to texscroll list. (texscroll-make-request (-> geom effect effect-idx)) ) ) ) ;; try ripple (when (logtest? (-> geom effect effect-idx effect-bits) 4) ;; TODO. ; (when (-> arg0 ripple) ; (set! sv-144 (-> arg0 ripple)) ; (let* ((f1-4 (/ (- (-> sv-144 far-fade-dist) arg2) (- (-> sv-144 far-fade-dist) (-> sv-144 close-fade-dist)))) ; (f1-6 (fmax 0.0 (fmin 1.0 f1-4))) ; (f0-4 f1-6) ; (f30-0 (* f1-6 (-> sv-144 global-scale))) ; ) ; (set! (-> sv-144 faded-scale) f30-0) ; (let ((f1-9 (/ f30-0 (* 128.0 (-> geom header xyz-scale))))) ; 0 ; (.sll a0-16 num-bones 7) ; (let ((v1-56 #x20000000)) ; (.addu a0-17 a0-16 s2-0) ; (s.q! s2-0 v1-56) ; ) ; (let ((v1-57 (+ a0-17 16))) ; (s.w! (+ s2-0 4) v1-57) ; ) ; (.addiu matrix-data s2-0 16) ; (let ((v1-59 (-> *bone-calculation-list* next))) ; (logior! (-> v1-59 flags) (bone-calc-flags bncfl00)) ; (set! (-> v1-59 ripple-scale) f30-0) ; (set! (-> v1-59 ripple-y-scale) f1-9) ; (set! (-> v1-59 ripple-normal-scale) (* f0-4 (-> sv-144 individual-normal-scale))) ; (set! (-> v1-59 ripple-area) (the-as (inline-array vector) matrix-data)) ; ) ; ) ; (set! (-> dma-buf base) (the-as pointer (-> (the-as (pointer uint32) s2-0) 1))) ; (set! s2-0 (-> dma-buf base)) ; (if (not (and (= f30-0 0.0) (= (-> sv-144 last-frame-scale) 0.0))) ; (ripple-make-request (the-as ripple-wave (-> sv-144 waveform)) (-> geom effect effect-idx)) ; ) ; (set! (-> sv-144 last-frame-scale) f30-0) ; ) ; ) ) (cond ((nonzero? (-> arg0 death-timer)) ;; if using hte death effect, use mercneric always! (set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 1)) (set! used-mercneric 1) used-mercneric ) ((nonzero? (-> geom effect effect-idx envmap-usage)) ;; if we need envmap, set it up. (let* ((v1-83 (-> geom effect effect-idx extra-info)) ;; pointer to envmap tint data (v1-84 (the-as structure (+ (the-as uint v1-83) (* (-> v1-83 envmap-tint-offset) 16)))) ;; the envmap effect fades away at a certain distance (f1-12 (-> (the-as mei-envmap-tint v1-84) fade0)) (f0-8 (-> (the-as mei-envmap-tint v1-84) fade1)) ) ;; compute and saturate the envmap effect strength (let ((f0-9 (+ (* f1-12 arg2) f0-8))) (if (< 1.0 f0-9) (set! f0-9 1.0) ) (if (< f0-9 0.0) (set! f0-9 0.0) ) (cond ;; do envmap stuff if we are using generic anyway, or our strength is > 0. ((or (nonzero? (-> *merc-bucket-info* must-use-mercneric-for-clip)) (< 0.0 f0-9)) ;; multiply colors by sun tint. (let ((v1-85 (&-> (the-as merc-extra-info v1-84) dummy 4)) (a0-36 (the-as object (-> *merc-bucket-info* effect effect-idx))) ) (let ((a1-16 (-> *time-of-day-context* current-sun env-color)) (f0-10 (* 0.0078125 f0-9)) ) (dotimes (a2-15 3) (set! (-> (the-as (pointer int8) a0-36) a2-15) (the int (* f0-10 (-> a1-16 data a2-15) (the float (-> v1-85 a2-15)))) ) ) ) (set! (-> (the-as (pointer uint8) a0-36) 3) (the-as uint 0)) ) ;; env mapping, so use mercneric. (set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 1)) (set! used-mercneric 1) used-mercneric ) (else ;; no env map, don't use mercneric. (set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 0)) (set! (-> *merc-bucket-info* effect effect-idx ignore-alpha) (the-as uint 1)) (set! used-merc 1) ;; note sure what this is exactly... (when (logtest? (-> geom effect effect-idx effect-bits) 2) (let ((v1-102 (-> *merc-bucket-info* light))) (set! (-> v1-102 direction 1 w) 0.000000000000000000000000000000000000011755039) ) ) ) ) ) ) ) ;; final two cases are for all other effects that don't matter generic/normal ((nonzero? (-> *merc-bucket-info* must-use-mercneric-for-clip)) (set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 1)) (set! used-mercneric 1) used-mercneric ) (else (set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 0)) (set! (-> *merc-bucket-info* effect effect-idx ignore-alpha) (the-as uint 0)) (set! used-merc 1) used-merc ) ) ;; HACK just use merc. (when (logtest? *vu1-enable-user* (vu1-renderer-mask generic)) (unless (logtest? (-> arg0 status) (draw-status needs-clip)) (set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 0)) ) (when (and (logtest? (-> arg0 status) (draw-status needs-clip)) ;; we need to clip ;;(nonzero? (-> arg0 longest-edge)) ;; we known the longest edge ;;(draw-bones-check-longest-edge-asm arg0 arg2) ;; it's ok to use percprime. ) (set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 0)) (set! (-> *merc-bucket-info* need-mercprime-if-merc) 1) ) ) (set! effect-idx (+ effect-idx 1)) ) ;; end effect loop ;; draw generic! ;; note: this doesn't do the fully draw, there's some other stuff in process-drawable.gc to actually execute. ;; TODO!! ; (when (nonzero? used-mercneric) ; (when (logtest? *vu1-enable-user* (vu1-renderer-mask generic)) ; (set! (-> dma-buf base) (draw-bones-generic-merc arg0 matrix-data s2-0 0)) ; (set! s2-0 (-> dma-buf base)) ; ) ; ) ;; draw shadow! ;; TODO ; (when (-> arg0 shadow) ; (when #t ; (set! s2-0 (draw-bones-shadow arg0 matrix-data s2-0)) ; (set! (-> dma-buf base) (the-as pointer s2-0)) ; ) ; ) ;; draw merc! (set! used-merc 1) (when (nonzero? used-merc) (when (logtest? *vu1-enable-user* (vu1-renderer-mask merc)) (when (= (-> arg0 cur-lod) (-> arg0 lod-set max-lod)) (let ((f0-13 (- (-> arg0 lod-set lod (-> arg0 cur-lod) dist) arg2))) (when (< f0-13 81920.0) (when (zero? (logand (-> geom effect 0 effect-bits) 2)) (let* ((a1-25 (the int (* 0.0015625 f0-13))) (v1-147 (min 128 (max 0 a1-25))) (a0-56 (-> *merc-bucket-info* light)) ) (set! (-> a0-56 direction 1 w) 0.000000000000000000000000000000000000011755084) (set! (-> a0-56 direction 2 w) (the-as float v1-147)) ) 0 ) ) ) ) (if (nonzero? (-> *merc-bucket-info* need-mercprime-if-merc)) (set! (-> dma-buf base) (draw-bones-merc arg0 matrix-data s2-0 32 17)) (set! (-> dma-buf base) (draw-bones-merc arg0 matrix-data s2-0 35 20)) ) (set! s2-0 (-> dma-buf base)) ) ) ) ;; end geom processing ;; advance death timer. (when (nonzero? (-> arg0 death-timer)) (when (not (paused?)) (+! (-> arg0 death-timer) -1) (if (>= (the-as uint 1) (-> arg0 death-timer)) (send-event (-> arg0 process) 'death-end arg0) ) ) ) ) (let ((v1-164 (logand (the-as int s2-0) 48))) 0 (b! (zero? v1-164) cfg-83 :delay (set! a0-62 #x20000000)) ;;(s.q! s2-0 a0-62) (set! (-> (the (pointer uint128) s2-0) 0) (the uint128 a0-62)) (let ((a0-63 s2-0)) (set! s2-0 (+ (- (the-as int s2-0) v1-164) 64)) ;;(s.w! (+ a0-63 4) (the-as int s2-0)) (set! (-> (the (pointer int32) (+ (the-as uint a0-63) 4))) (the-as int s2-0)) ) ) (label cfg-83) (set! (-> dma-buf base) (the-as pointer (logand (the-as uint s2-0) (the-as uint #xfffffff)))) ) ) ) 0 (none) ) ) (defun draw-bones-hud ((arg0 draw-control) (arg1 dma-buffer)) (none) ) (define-extern draw-bones-hud (function draw-control dma-buffer none))