mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-21 07:37:45 -04:00
89ccb8cbc7
* cleanup `main` * whitespace * start `progress` decomp pt1 * fill in more stuff * Update label_types.jsonc * run cheats * clang * make most of `progress` decompile * `progress` pt 2 * [decompiler] support dynamic format strings * Make `progress-draw` decompile and almost all `progress` * make clang shut up * fix unhandled format string * fix `progress-draw` * Update DecompilerTypeSystem.cpp * fix? * fixes * fix a few functions * make `language-enum` * warn on weird floats * fix minor pad bug * dump stuff in `progress` * make `progress-screen` enum * progress progress * update refs and fix stupid bug * trying to get it to work * it works!? * disable sound functions * fixes * final touches * tests * tests * add process allocations * use the right register for windows * another try for windows, counting is hard * one more try * use process allocations Co-authored-by: water <awaterford111445@gmail.com>
330 lines
8.6 KiB
Common Lisp
330 lines
8.6 KiB
Common Lisp
;;-*-Lisp-*-
|
|
(in-package goal)
|
|
|
|
;; name: math.gc
|
|
;; name in dgo: math
|
|
;; dgos: GAME, ENGINE
|
|
|
|
;; contains various math helpers
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; float macros
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
(defmacro fabs (x)
|
|
"Floating point absolute value"
|
|
;; in GOAL this was implemented by the compiler.
|
|
;; at some point, this could be more optimized.
|
|
;; MIPS has an explicit abs.s instruction, but x86-64 doesn't.
|
|
;; modern clang on O3 does a comiss/branch and this is probably pretty close.
|
|
`(if (< (the float ,x) 0)
|
|
(- (the float ,x))
|
|
(the float ,x))
|
|
)
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; float utility
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defun truncate ((x float))
|
|
"Truncate a floating point number to an integer value.
|
|
Positive values round down and negative values round up."
|
|
(declare (inline))
|
|
(the float (the int x))
|
|
)
|
|
|
|
(defun integral? ((x float))
|
|
"Is a float an exact integer?"
|
|
(= (truncate x) x)
|
|
)
|
|
|
|
(defun fractional-part ((x float))
|
|
"Get the fractional part of a float"
|
|
(- x (truncate x))
|
|
)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; bitfield types
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(deftype rgba (uint32)
|
|
((r uint8 :offset 0)
|
|
(g uint8 :offset 8)
|
|
(b uint8 :offset 16)
|
|
(a uint8 :offset 24)
|
|
)
|
|
:flag-assert #x900000004
|
|
)
|
|
|
|
(defmacro static-rgba (r g b a)
|
|
"make a new static rgba"
|
|
|
|
`(new 'static 'rgba :r ,r :g ,g :b ,b :a ,a)
|
|
)
|
|
|
|
(defmacro static-rgba-uint (col)
|
|
"make a new static rgba"
|
|
`(the-as rgba ,col)
|
|
)
|
|
|
|
;; TODO: fields
|
|
(deftype xyzw (uint128)
|
|
()
|
|
:flag-assert #x900000010
|
|
)
|
|
|
|
;; TODO: fields
|
|
(deftype xyzwh (uint128)
|
|
()
|
|
:flag-assert #x900000010
|
|
)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; utility functions
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defun log2 ((x int))
|
|
"Straight out of Bit Twiddling Hacks graphics.stanford.edu.
|
|
This website is old enough that they possibly used this back
|
|
in 1999."
|
|
(- (sar (the-as int (the float x)) 23) 127)
|
|
)
|
|
|
|
(defun seek ((x float) (target float) (diff float))
|
|
"Move x toward target by at most diff, with floats"
|
|
(let ((err (- target x)))
|
|
(cond
|
|
((>= diff (fabs err))
|
|
;; can get there in one go
|
|
target
|
|
)
|
|
((>= err 0)
|
|
;; increase
|
|
(+ x diff)
|
|
)
|
|
(else
|
|
(- x diff)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
(defun lerp ((minimum float) (maximum float) (amount float))
|
|
"Interpolate between minimum and maximum. The output is not clamped."
|
|
(+ minimum (* amount (- maximum minimum)))
|
|
)
|
|
|
|
(defun lerp-scale ((min-out float) (max-out float)
|
|
(in float) (min-in float) (max-in float))
|
|
"Interpolate from [min-in, max-in] to [min-out, max-out].
|
|
If the output is out of range, it will be clamped.
|
|
This is not a great implementation."
|
|
(let ((scale (fmax 0.0 (fmin 1.0 (/ (- in min-in) (- max-in min-in))))))
|
|
(+ (* (- 1.0 scale) min-out)
|
|
(* scale max-out)
|
|
)
|
|
)
|
|
)
|
|
|
|
(defun lerp-clamp ((minimum float) (maximum float) (amount float))
|
|
"Interpolate between minimum and maximum, but saturate the amount to [0, 1]"
|
|
(cond
|
|
((>= 0.0 amount)
|
|
minimum)
|
|
((>= amount 1.0)
|
|
maximum)
|
|
(else
|
|
;; the implementation in lerp uses fewer operations...
|
|
(+ (* (- 1.0 amount) minimum)
|
|
(* amount maximum)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; utility macros
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defmacro seek! (place target rate)
|
|
"Macro to use seek in-place. place is the base, and where the result is stored."
|
|
`(set! ,place (seek ,place ,target ,rate))
|
|
)
|
|
|
|
(defmacro seekl! (place target rate)
|
|
"Macro to use seekl in-place. place is the base, and where the result is stored."
|
|
`(set! ,place (seekl ,place ,target ,rate))
|
|
)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; integer utility
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defun seekl ((x int) (target int) (diff int))
|
|
"Move x toward a target by at most diff, with integers"
|
|
(let ((err (- target x)))
|
|
(if (< (abs err) diff)
|
|
(return-from #f target)
|
|
)
|
|
|
|
(if (>= err 0)
|
|
(+ x diff)
|
|
(- x diff)
|
|
)
|
|
)
|
|
)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; random vu hardware
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; in the PS2 there is a R register for generating random numbers
|
|
;; it is a "32-bit" register, but the upper bits are fixed so it always
|
|
;; represents a float in (1, 2).
|
|
;; we don't have this register on x86, so we add a special global: *_vu-reg-R_*
|
|
(define *_vu-reg-R_* 0)
|
|
|
|
(defun rand-vu-init ((seed float))
|
|
"Initialize the VU0 random generator"
|
|
;; (.ctc2.i R arg0)
|
|
;; (.cfc2.i v0 R)
|
|
(set! *_vu-reg-R_*
|
|
(logior #x3F800000 (logand (the-as int seed) #x007FFFFF))
|
|
)
|
|
(the-as float *_vu-reg-R_*)
|
|
)
|
|
|
|
;; this is _almost_ sqrt(2) = 1.414
|
|
(rand-vu-init 1.418091058731079)
|
|
|
|
;; rand-vu
|
|
(defun rand-vu ()
|
|
"Get a random number in [0, 1) and advance the random generator."
|
|
;; (.vrget.xyzw vf1) - get current random
|
|
(let ((current-random *_vu-reg-R_*))
|
|
;; here they update the random generate with some junk
|
|
;; for now, we don't do this in OpenGOAL.
|
|
;; (.vsqrty Q vf1)
|
|
;; (.vaddq.x vf2 vf0 Q) ;; you're not allowed to do this!
|
|
;; (.vrxorw vf2)
|
|
|
|
;; and advance
|
|
;; (.vrnext.xyzw vf1)
|
|
(let ((x (logand 1 (shr current-random 4)))
|
|
(y (logand 1 (shr current-random 22)))
|
|
)
|
|
(set! current-random (shl current-random 1))
|
|
(set! current-random (logxor current-random (logxor x y)))
|
|
(set! *_vu-reg-R_* (logior #x3f800000 (logand current-random #x7fffff)))
|
|
)
|
|
)
|
|
|
|
;; (.vsubw.xyzw vf1 vf1 vf0)
|
|
;; (.qmfc2.i v0 vf1)
|
|
(- (the-as float *_vu-reg-R_*) 1.0)
|
|
)
|
|
|
|
;; rand-vu-nostep
|
|
(defun rand-vu-nostep ()
|
|
"Get the number currently in the random generator.
|
|
This will be equal to the last call of (rand-vu)
|
|
This will not update the random generator"
|
|
(- (the-as float *_vu-reg-R_*) 1.0)
|
|
)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; random vu utilities
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defun rand-vu-float-range ((minimum float) (maximum float))
|
|
"Get a random number in the given range.
|
|
TODO: is this inclusive? I think it's [min, max)"
|
|
(+ minimum (* (rand-vu) (- maximum minimum)))
|
|
)
|
|
|
|
(defun rand-vu-percent? ((prob float))
|
|
"Get a boolean that's true with the given probability."
|
|
(>= prob (rand-vu))
|
|
)
|
|
|
|
(defun rand-vu-int-range ((first int) (second int))
|
|
"Get an integer the given range. Inclusive of both?
|
|
It looks like they actually did this right??"
|
|
|
|
(local-vars (float-in-range float))
|
|
|
|
;; increment the larger of the range, so it is inclusive
|
|
;; (we should have (max - min) + 1 buckets)
|
|
(if (< first second)
|
|
(set! second (+ second 1))
|
|
(set! first (+ first 1))
|
|
)
|
|
|
|
;; get a float in the range
|
|
(set! float-in-range
|
|
(rand-vu-float-range (the float first) (the float second))
|
|
)
|
|
|
|
;; negatives round up and positives round down.
|
|
;; but we want all to round consistently, so we subtract one from negatives.
|
|
(when (< float-in-range 0)
|
|
(set! float-in-range (+ -1.0 float-in-range))
|
|
)
|
|
;; and back to integer.
|
|
(the int float-in-range)
|
|
)
|
|
|
|
(defun rand-vu-int-count ((maximum int))
|
|
"Get an integer in [0, maximum)"
|
|
(the int (* (rand-vu) (the float maximum)))
|
|
)
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; terrible random integer generator
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(deftype random-generator (basic)
|
|
((seed uint32 :offset-assert 4)
|
|
)
|
|
:method-count-assert 9
|
|
:size-assert #x8
|
|
:flag-assert #x900000008
|
|
)
|
|
|
|
(define *random-generator* (new 'global 'random-generator))
|
|
;; I wonder who wrote this code.
|
|
(set! (-> *random-generator* seed) #x666EDD1E)
|
|
|
|
(defmacro sext32-64 (x)
|
|
`(sar (shl ,x 32) 32)
|
|
)
|
|
|
|
(defun rand-uint31-gen ((gen random-generator))
|
|
"Generate a supposedly random integer.
|
|
Note, this might not quite be right.
|
|
But the highest bit is always zero, like it says
|
|
and it looks kinda random to me."
|
|
(let* ((sd (-> gen seed))
|
|
;; addiu v1, r0, 16807
|
|
;; mult3 v0, v1, a1
|
|
(prod (imul64 16807 sd))
|
|
;; mfhi v1
|
|
(hi (shr prod 32)) ;; sign extend this?
|
|
(lo (sar (shl prod 32) 32))
|
|
;; daddu v1, v1, v1
|
|
(v1 (+ hi hi))
|
|
;; srl a1, v0, 31
|
|
(a1 (logand #xffffffff (shr lo 31)))
|
|
;; or v1, v1, a1
|
|
;; daddu v0, v0 v1
|
|
(result (+ lo (logior v1 a1)))
|
|
)
|
|
(set! result (shr (logand #xffffffff (shl result 1)) 1))
|
|
(set! (-> gen seed) result)
|
|
(the uint result)
|
|
)
|
|
)
|