mirror of
https://github.com/open-goal/jak-project
synced 2026-05-24 07:11:15 -04:00
169 lines
4.3 KiB
Common Lisp
169 lines
4.3 KiB
Common Lisp
;;-*-Lisp-*-
|
|
(in-package goal)
|
|
|
|
;; name: math.gc
|
|
;; name in dgo: math
|
|
;; dgos: GAME, ENGINE
|
|
|
|
;; contains various math helpers
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; float macros
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; 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.
|
|
|
|
(defmacro fabs (x)
|
|
`(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))
|
|
)
|
|
|
|
;; todo, rgba, xyzw, xyzwh
|
|
|
|
(defun log2 ((x int))
|
|
"Straight out of Bit Twiddling Hacks graphics.stanford.edu"
|
|
(- (sarv (the-as integer (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)))
|
|
;; if we can get there all at once
|
|
(if (<= (fabs err) diff)
|
|
(return-from #f target)
|
|
)
|
|
|
|
(if (>= err 0)
|
|
(+ x diff)
|
|
(- 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. Clamp output.
|
|
For some reason, the interpolate here is done in a less efficient way than lerp."
|
|
(if (<= amount 0.0)
|
|
(return-from #f minimum)
|
|
)
|
|
|
|
(if (>= amount 1.0)
|
|
(return-from #f maximum)
|
|
)
|
|
;; lerp computes this part, but more efficiently
|
|
(+ (* (- 1.0 amount) minimum)
|
|
(* amount maximum)
|
|
)
|
|
)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; 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
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; TODO
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; 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)
|
|
`(sarv (shlv ,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 (shrv prod 32)) ;; sign extend this?
|
|
(lo (sarv (shlv prod 32) 32))
|
|
;; daddu v1, v1, v1
|
|
(v1 (+ hi hi))
|
|
;; srl a1, v0, 31
|
|
(a1 (logand #xffffffff (shrv lo 31)))
|
|
;; or v1, v1, a1
|
|
;; daddu v0, v0 v1
|
|
(result (+ lo (logior v1 a1)))
|
|
)
|
|
(set! result (shrv (logand #xffffffff (shlv result 1)) 1))
|
|
(set! (-> gen seed) result)
|
|
result
|
|
)
|
|
) |