From f142f460459b26b38cd8df7f56621888feeddce7 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sat, 5 Feb 2022 16:30:50 -0500 Subject: [PATCH] add more comments/docstrings on first 58 files, try new windows-specific framelimiting (#1134) * cleanup * type * link against a library --- common/CMakeLists.txt | 8 +- common/util/FrameLimiter.cpp | 77 ++++++ common/util/FrameLimiter.h | 28 +- game/graphics/opengl_renderer/debug_gui.cpp | 1 + game/graphics/opengl_renderer/debug_gui.h | 1 + game/graphics/pipelines/opengl.cpp | 7 +- goal_src/engine/camera/math-camera-h.gc | 13 +- goal_src/engine/camera/math-camera.gc | 92 +++++-- goal_src/engine/debug/memory-usage-h.gc | 7 +- goal_src/engine/dma/dma-h.gc | 2 +- goal_src/engine/engine/connect.gc | 17 +- goal_src/engine/geometry/bounding-box-h.gc | 1 + goal_src/engine/geometry/bounding-box.gc | 17 +- goal_src/engine/geometry/geometry-h.gc | 3 + goal_src/engine/geometry/geometry.gc | 62 ++++- goal_src/engine/gfx/decomp-h.gc | 2 + goal_src/engine/gfx/font-h.gc | 2 + goal_src/engine/gfx/hw/display.gc | 24 +- goal_src/engine/gfx/hw/video-h.gc | 2 - goal_src/engine/gfx/hw/vu1-user-h.gc | 8 +- goal_src/engine/gfx/texture-h.gc | 8 +- goal_src/engine/level/level-h.gc | 96 ++++--- goal_src/engine/load/loader-h.gc | 11 +- goal_src/engine/math/euler-h.gc | 1 + goal_src/engine/math/math.gc | 6 +- goal_src/engine/math/matrix-h.gc | 9 +- goal_src/engine/math/matrix.gc | 271 ++++---------------- goal_src/engine/math/quaternion-h.gc | 3 + goal_src/engine/math/quaternion.gc | 190 +++++--------- goal_src/engine/math/transform-h.gc | 3 + goal_src/engine/math/transform.gc | 2 + goal_src/engine/math/transformq-h.gc | 36 ++- goal_src/engine/math/vector-h.gc | 17 +- goal_src/engine/ps2/vif-h.gc | 3 + goal_src/engine/sound/gsound-h.gc | 4 + goal_src/engine/ui/text-h.gc | 4 + 36 files changed, 545 insertions(+), 493 deletions(-) create mode 100644 common/util/FrameLimiter.cpp diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 00958be7c7..69f56aaf7b 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -38,12 +38,16 @@ add_library(common util/os.cpp util/print_float.cpp util/FontUtils.cpp - util/image_loading.cpp "goos/Printer.cpp" "goos/Printer.h" "goos/PrettyPrinter2.cpp" "goos/PrettyPrinter2.h") + util/FrameLimiter.cpp + util/image_loading.cpp + goos/Printer.cpp + goos/PrettyPrinter2.cpp + ) target_link_libraries(common fmt lzokay replxx libzstd_static) if(WIN32) - target_link_libraries(common wsock32 ws2_32) + target_link_libraries(common wsock32 ws2_32 windowsapp) else() target_link_libraries(common stdc++fs) endif() diff --git a/common/util/FrameLimiter.cpp b/common/util/FrameLimiter.cpp new file mode 100644 index 0000000000..136ca6aae1 --- /dev/null +++ b/common/util/FrameLimiter.cpp @@ -0,0 +1,77 @@ +#include "FrameLimiter.h" +#include + +double FrameLimiter::round_to_nearest_60fps(double current) { + double one_frame = 1.f / 60.f; + int frames_missed = (current / one_frame); // rounds down + if (frames_missed > 4) { + frames_missed = 4; + } + return (frames_missed + 1) * one_frame; +} + +#ifdef __linux__ + +FrameLimiter::FrameLimiter() {} + +FrameLimiter::~FrameLimiter() {} + +void FrameLimiter::run(double target_fps, + bool experimental_accurate_lag, + bool do_sleeps, + double engine_time) { + double target_seconds; + if (experimental_accurate_lag) { + target_seconds = round_to_nearest_60fps(engine_time); + } else { + target_seconds = 1.f / target_fps; + } + double remaining_time = target_seconds - m_timer.getSeconds(); + + if (do_sleeps && remaining_time > 0.001) { + std::this_thread::sleep_for(std::chrono::microseconds(int((remaining_time - 0.001) * 1e6))); + } + + while (remaining_time > 0) { + remaining_time = target_seconds - m_timer.getSeconds(); + } + + m_timer.start(); +} + +#else + +#include + +FrameLimiter::FrameLimiter() { + timeBeginPeriod(1); +} + +FrameLimiter::~FrameLimiter() { + timeEndPeriod(0); +} + +void FrameLimiter::run(double target_fps, + bool experimental_accurate_lag, + bool do_sleeps, + double engine_time) { + double target_seconds; + if (experimental_accurate_lag) { + target_seconds = round_to_nearest_60fps(engine_time); + } else { + target_seconds = 1.f / target_fps; + } + double remaining_time = target_seconds - m_timer.getSeconds(); + + if (do_sleeps && remaining_time > 0.001) { + Sleep((remaining_time * 1000) - 1); + } + + while (remaining_time > 0) { + remaining_time = target_seconds - m_timer.getSeconds(); + } + + m_timer.start(); +} + +#endif \ No newline at end of file diff --git a/common/util/FrameLimiter.h b/common/util/FrameLimiter.h index 3384149e32..9936115622 100644 --- a/common/util/FrameLimiter.h +++ b/common/util/FrameLimiter.h @@ -4,33 +4,13 @@ class FrameLimiter { public: - void run(double target_fps, bool experimental_accurate_lag, double engine_time) { - double target_seconds; - if (experimental_accurate_lag) { - target_seconds = round_to_nearest_60fps(engine_time); - } else { - target_seconds = 1.f / target_fps; - } - double remaining_time = target_seconds - m_timer.getSeconds(); - while (remaining_time > 0) { - if (remaining_time > 0.003) { - std::this_thread::sleep_for(std::chrono::microseconds(int(remaining_time * 1e6 * 0.5))); - } - remaining_time = target_seconds - m_timer.getSeconds(); - } + FrameLimiter(); + ~FrameLimiter(); - m_timer.start(); - } + void run(double target_fps, bool experimental_accurate_lag, bool do_sleeps, double engine_time); private: - double round_to_nearest_60fps(double current) { - double one_frame = 1.f / 60.f; - int frames_missed = (current / one_frame); // rounds down - if (frames_missed > 4) { - frames_missed = 4; - } - return (frames_missed + 1) * one_frame; - } + double round_to_nearest_60fps(double current); Timer m_timer; }; \ No newline at end of file diff --git a/game/graphics/opengl_renderer/debug_gui.cpp b/game/graphics/opengl_renderer/debug_gui.cpp index 5bf047ddcc..ef95cec630 100644 --- a/game/graphics/opengl_renderer/debug_gui.cpp +++ b/game/graphics/opengl_renderer/debug_gui.cpp @@ -122,6 +122,7 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) { } ImGui::Separator(); ImGui::Checkbox("Accurate Lag Mode", &experimental_accurate_lag); + ImGui::Checkbox("Sleep in Frame Limiter", &sleep_in_frame_limiter); ImGui::EndMenu(); } } diff --git a/game/graphics/opengl_renderer/debug_gui.h b/game/graphics/opengl_renderer/debug_gui.h index 666dd4c5d7..fd0e9b9359 100644 --- a/game/graphics/opengl_renderer/debug_gui.h +++ b/game/graphics/opengl_renderer/debug_gui.h @@ -80,6 +80,7 @@ class OpenGlDebugGui { bool framelimiter = false; float target_fps = 60.f; bool experimental_accurate_lag = false; + bool sleep_in_frame_limiter = true; private: FrameTimeRecorder m_frame_timer; diff --git a/game/graphics/pipelines/opengl.cpp b/game/graphics/pipelines/opengl.cpp index 45b6f4e88c..85db247f06 100644 --- a/game/graphics/pipelines/opengl.cpp +++ b/game/graphics/pipelines/opengl.cpp @@ -140,6 +140,7 @@ static std::shared_ptr gl_make_main_display(int width, int height, const char* title, GfxSettings& settings) { + glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE); GLFWwindow* window = glfwCreateWindow(width, height, title, NULL, NULL); if (!window) { @@ -430,9 +431,9 @@ static void gl_render_display(GfxDisplay* display) { g_gfx_data->debug_gui.finish_frame(); glfwSwapBuffers(window); if (g_gfx_data->debug_gui.framelimiter) { - g_gfx_data->frame_limiter.run(g_gfx_data->debug_gui.target_fps, - g_gfx_data->debug_gui.experimental_accurate_lag, - g_gfx_data->last_engine_time); + g_gfx_data->frame_limiter.run( + g_gfx_data->debug_gui.target_fps, g_gfx_data->debug_gui.experimental_accurate_lag, + g_gfx_data->debug_gui.sleep_in_frame_limiter, g_gfx_data->last_engine_time); } g_gfx_data->debug_gui.start_frame(); diff --git a/goal_src/engine/camera/math-camera-h.gc b/goal_src/engine/camera/math-camera-h.gc index 8a8bf42722..1aa3b6719f 100644 --- a/goal_src/engine/camera/math-camera-h.gc +++ b/goal_src/engine/camera/math-camera-h.gc @@ -7,8 +7,13 @@ ;; The math-camera is a global that contains camera projection and culling matrices. +;; Note that it doesn't take into account the position/rotation of the game camera, but +;; just computes the projection matrix/culling stuff and the camera stuff will have to +;; rotate and translate it as needed. + ;; It also contains some GIF stuff, but these seem to be wrong/unused. -;; Some of the code here may be extremely old and unused. +;; Some of the code here may be extremely old and unused, but this does compute the camera projection +;; matrix used almost everywhere. (deftype vis-gif-tag (structure) ((fog0 uint32 :offset-assert 0) @@ -50,6 +55,8 @@ ((d meters :offset-assert 4) ;; camera near plane (f meters :offset-assert 8) ;; camera far plane (fov degrees :offset-assert 12) ;; field of view angle + + ;; view frustum (x-ratio float :offset-assert 16) (y-ratio float :offset-assert 20) (x-pix float :offset-assert 24) @@ -76,6 +83,10 @@ (inv-camera-rot matrix :inline :offset-assert 432) (inv-camera-rot-smooth matrix :inline :offset-assert 496) (inv-camera-rot-smooth-from quaternion :inline :offset-assert 560) + ;; this camera-temp is the main matrix used for renderers. + ;; the camera code will set this. + ;; it's designed so the renderers can do a single matrix-vector multiply + ;; and then get fog, clipping, and final vertex position from the result. (camera-temp matrix :inline :offset-assert 576) (prev-camera-temp matrix :inline :offset-assert 640) (hmge-scale vector :inline :offset-assert 704) diff --git a/goal_src/engine/camera/math-camera.gc b/goal_src/engine/camera/math-camera.gc index 0f700cd1d5..6a210bf6c8 100644 --- a/goal_src/engine/camera/math-camera.gc +++ b/goal_src/engine/camera/math-camera.gc @@ -122,30 +122,45 @@ ;; reset camera rotation (matrix-identity! (-> math-cam camera-rot)) - (let ((fog-constant-1 100.0) - (fog-constant-2 16760631.0) + ;;;;;;;;;;;;;; Perspective matrix setup + + ;; these min/max depths are the values we'd want to write to the 24-bit integer depth buffer + (let ((min-depth 100.0) + (max-depth 16760631.0) ;; almost 2^24. ) - (let ((f0-21 16777115.0))) - (let ((fog-at-near-plane + (let ((f0-21 16777115.0))) ;; unused. this is actually float closest to 2^24 + + ;; next, compute the fog slope d(8bit_integer_fog_value)/d(game_world_distance). + ;; the final fog values we want are an 8-bit integer. + ;; note that this is the fog at the near plane too. + (let ((fog-slope (/ (* (-> math-cam d) (- (-> math-cam fog-min) (-> math-cam fog-max))) (- (-> *math-camera-fog-correction* fog-end) (-> *math-camera-fog-correction* fog-start) ) ) ) - (fog-factor-2 (* -0.5 (- fog-constant-2 fog-constant-1))) + ;; this is half the range of the depth buffer. + (depth-buffer-half-range (* -0.5 (- max-depth min-depth))) ) - (let ((corrected-fog (/ fog-factor-2 (* (-> math-cam d) (- (-> math-cam f) (-> math-cam d))))) + ;; this is the slope to convert game world depths to depth buffer depths + (let ((half-depth-buffer-slope (/ depth-buffer-half-range (* (-> math-cam d) (- (-> math-cam f) (-> math-cam d))))) (cam-fov-mult (-> math-cam fov-correction-factor)) ) + + ;; finally, build the actual matrix. + ;; x/y are just the usual scaling (set! (-> math-cam perspective vector 0 x) (* cam-fov-mult (- (/ (-> math-cam x-pix) (* (-> math-cam x-ratio) (-> math-cam d)))))) (set! (-> math-cam perspective vector 1 y) (* cam-fov-mult (- (/ (-> math-cam y-pix) (* (-> math-cam y-ratio) (-> math-cam d)))))) - (set! (-> math-cam perspective vector 2 z) (* cam-fov-mult (+ (-> math-cam f) (-> math-cam d)) corrected-fog)) - (set! (-> math-cam perspective vector 2 w) (* (/ cam-fov-mult (-> math-cam d)) fog-at-near-plane)) - (set! (-> math-cam perspective vector 3 z) (* -2.0 corrected-fog (-> math-cam f) (-> math-cam d) cam-fov-mult)) + ;; depth scaling + (set! (-> math-cam perspective vector 2 z) (* cam-fov-mult (+ (-> math-cam f) (-> math-cam d)) half-depth-buffer-slope)) + ;; depth to fog + (set! (-> math-cam perspective vector 2 w) (* (/ cam-fov-mult (-> math-cam d)) fog-slope)) + + (set! (-> math-cam perspective vector 3 z) (* -2.0 half-depth-buffer-slope (-> math-cam f) (-> math-cam d) cam-fov-mult)) ) - ;; hvdf/hmge, no idea what these are + ;; hvdf = horizontal, vertical, depth, fog offsets to be applied after transform. (let ((hvdf-x 2048.0) (hvdf-y 2048.0) (hvdf-w @@ -160,15 +175,15 @@ ) ) ) - (let ((hvdf-z (* 0.5 (+ fog-constant-2 fog-constant-1)))) + (let ((hvdf-z (* 0.5 (+ max-depth min-depth)))) (set! (-> math-cam hmge-scale x) (/ 1.0 (-> math-cam x-clip))) (set! (-> math-cam hmge-scale y) (/ 1.0 (-> math-cam y-clip))) - (set! (-> math-cam hmge-scale z) (/ 1.0 fog-factor-2)) - (set! (-> math-cam hmge-scale w) (/ 1.0 fog-at-near-plane)) + (set! (-> math-cam hmge-scale z) (/ 1.0 depth-buffer-half-range)) + (set! (-> math-cam hmge-scale w) (/ 1.0 fog-slope)) (set! (-> math-cam inv-hmge-scale x) (-> math-cam x-clip)) (set! (-> math-cam inv-hmge-scale y) (-> math-cam y-clip)) - (set! (-> math-cam inv-hmge-scale z) fog-factor-2) - (set! (-> math-cam inv-hmge-scale w) fog-at-near-plane) + (set! (-> math-cam inv-hmge-scale z) depth-buffer-half-range) + (set! (-> math-cam inv-hmge-scale w) fog-slope) (set! (-> math-cam hvdf-off x) hvdf-x) (set! (-> math-cam hvdf-off y) hvdf-y) (set! (-> math-cam hvdf-off z) hvdf-z) @@ -188,7 +203,7 @@ ) ) - (set! (-> math-cam isometric vector 3 w) fog-at-near-plane) + (set! (-> math-cam isometric vector 3 w) fog-slope) ;; perspective matrix (let ((persp-xx (-> math-cam perspective vector 0 x)) @@ -215,7 +230,7 @@ (set! (-> math-cam sprite-2d-hvdf x) 2048.0) (set! (-> math-cam sprite-2d-hvdf y) 2048.0) (set! (-> math-cam sprite-2d-hvdf z) (-> math-cam hvdf-off z)) - (set! (-> math-cam pfog0) fog-at-near-plane) + (set! (-> math-cam pfog0) fog-slope) (set! (-> math-cam pfog1) hvdf-w) ) ) @@ -266,6 +281,7 @@ (defmethod new math-camera ((allocation symbol) (type-to-make type)) + "Set up a new math-camera in NTSC mode." (let ((gp-0 (object-new allocation type-to-make (the-as int (-> type-to-make size))))) (set! (-> gp-0 d) 1024.0) (set! (-> gp-0 f) 40960000.0) @@ -382,7 +398,9 @@ ) (defun transform-point-vector! ((arg0 vector) (arg1 vector)) - "Apply camera transformation to a point." + "Apply camera transformation to a point. Return true if it is visible or not. + This returns the point in GS coords, but as float instead of int, so it's + not really useful. See transform-point-qword! for more details" (rlet ((acc :class vf) (Q :class vf) (vf0 :class vf) @@ -428,7 +446,8 @@ ) (defun transform-point-qword! ((arg0 vector4w) (arg1 vector)) - "Apply camera transformation to point, returning fixed point 28.4 position" + "Apply camera transformation to point, returning fixed point 28.4 position + that can be given to the GS directly." (rlet ((acc :class vf) (Q :class vf) (vf0 :class vf) @@ -445,37 +464,60 @@ (init-vf0-vector) (let ((v1-0 0)) ) + + ;; this camera matrix has both the projection and camera translation/rotation (.lvf vf24 (&-> *math-camera* camera-temp vector 0 quad)) (.lvf vf25 (&-> *math-camera* camera-temp vector 1 quad)) (.lvf vf26 (&-> *math-camera* camera-temp vector 2 quad)) (.lvf vf27 (&-> *math-camera* camera-temp vector 3 quad)) + + ;; scaling (.lvf vf29 (&-> *math-camera* hmge-scale quad)) + + ;; offset (.lvf vf30 (&-> *math-camera* hvdf-off quad)) + + ;; input point (.lvf vf28 (&-> arg1 quad)) + + ;; matrix multiply, result in vf28 (.mul.x.vf acc vf24 vf28) (.add.mul.y.vf acc vf25 vf28 acc) (.add.mul.z.vf acc vf26 vf28 acc) - (.add.mul.w.vf vf28 vf27 vf0 acc) ;; matrix mult. - (.add.w.vf vf23 vf0 vf0) ;; clear w. + (.add.mul.w.vf vf28 vf27 vf0 acc) + + + (.add.w.vf vf23 vf0 vf0) ;; set w = 1.0 + + ;; apply hmge scaling. the result of this multiply sets clipping flags appropriately (.mul.vf vf31 vf28 vf29) ;; scale. ;;(TODO.VCLIP vf31 vf31) - (let ((clip (vu-clip vf31 0))) + (let ((clip (vu-clip vf31 0))) ;; clip! + + ;; perspective divide (.div.vf Q vf0 vf31 :fsf #b11 :ftf #b11) (.wait.vf) ;;(.cfc2.i v1-7 Clipping) + ;; perspective (.mul.vf vf28 vf28 Q :mask #b111) + ;; compute scale factor (w was 1.0) (.mul.vf vf23 vf23 Q) + ;; apply hvdf offsets (.add.vf vf28 vf28 vf30) + ;; saturate fog (.max.x.vf vf28 vf28 vf0 :mask #b1000) - ;;(TODO.VFTOI4 vf28 vf28) + ;; convert to GS fixed point (vftoi4.xyzw vf28 vf28) + ;; store result! (.svf (&-> arg0 quad) vf28) + ;; return result of clipping. (zero? (logand clip 63)) ) ) ) (defun transform-point-vector-scale! ((arg0 vector) (arg1 vector)) + "Similar to transform-point-qword! but returns the scale factor instead." (local-vars (v0-0 float)) (rlet ((acc :class vf) (Q :class vf) @@ -523,7 +565,9 @@ ) (defun init-for-transform ((arg0 matrix)) - "Sets up VU0 registers with camera info. Most rendering stuff doesn't use this." + "Sets up VU0 registers with camera info. + This is probably a very old function and it's only used by jungle mirrors. + It stashes some data in vector float registers that must be there before calling transform-float-point." (rlet ((vf1 :class vf) (vf17 :class vf) (vf18 :class vf) diff --git a/goal_src/engine/debug/memory-usage-h.gc b/goal_src/engine/debug/memory-usage-h.gc index 35b7c2fc17..10f0967aa9 100644 --- a/goal_src/engine/debug/memory-usage-h.gc +++ b/goal_src/engine/debug/memory-usage-h.gc @@ -5,11 +5,14 @@ ;; name in dgo: memory-usage-h ;; dgos: GAME, ENGINE -;; The memory-usage system is used to track how memory is arranged. +;; The memory-usage system is used to track how much memory is used by tracking statistics for categories. +;; It can be used in different ways for different objects. +;; - DMA memory usage per renderer +;; - static level data memory usage +;; - actor heap memory usage ;; All basics have a mem-usage method that will add its memory usage to ;; a memory-usage-block. It also takes some flags that are currently unknown. - ;; Information for a single category. (deftype memory-usage-info (structure) ((name string :offset-assert 0) diff --git a/goal_src/engine/dma/dma-h.gc b/goal_src/engine/dma/dma-h.gc index e5be55366b..48072bd0a5 100644 --- a/goal_src/engine/dma/dma-h.gc +++ b/goal_src/engine/dma/dma-h.gc @@ -295,7 +295,7 @@ (debug-draw1 68) ) -;; A DMA bucket is a way of organizing data within a dma buffer. +;; A DMA bucket is a way of sorting data within a dma buffer. ;; The buckets themselves live inside in the dma buffer. ;; the addr field of their tag should point to the next bucket. ;; This is not a PS2 hardware thing diff --git a/goal_src/engine/engine/connect.gc b/goal_src/engine/engine/connect.gc index 3522eb7022..5145e137fb 100644 --- a/goal_src/engine/engine/connect.gc +++ b/goal_src/engine/engine/connect.gc @@ -6,10 +6,17 @@ ;; dgos: GAME, ENGINE ;; This extremely confusing "connection system" allows the connection between -;; "engines" and "processes". Basically, a process may add connections to an engine. -;; A "connection" is really just a function that gets called when the engine runs. -;; Another way to use the system is as a queue of messages from processes to the engine, -;; without using a function. +;; "engines" and "processes". Basically, a process can "register" itself with any number of "engines". +;; The "engines" can then iterate through all the connected processes. If a process is destroyed, it will +;; be removed from all engines. It is okay to connect a process to multiple engines, or even to the same engine +;; multiple times. + +;; Some example uses: +;; - a "foreground-engine" has connections to all foreground objects that need to be drawn on each frame. +;; - when a process wants to change a game setting, it opens a connection to the settings engine to request a change. +;; when the process is killed, the setting change is reverted. + +;; A "connection" is really just a function that gets called when the engine runs, or a set of parameters that the engine can iterate through. ;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -556,8 +563,6 @@ 0 ) - - (defmethod remove-by-param2 engine ((obj engine) (p2-value int)) "Remove all connections with param2 matching p2-value" (let* ((current (-> obj alive-list next0)) diff --git a/goal_src/engine/geometry/bounding-box-h.gc b/goal_src/engine/geometry/bounding-box-h.gc index e923c91672..631216aa0b 100644 --- a/goal_src/engine/geometry/bounding-box-h.gc +++ b/goal_src/engine/geometry/bounding-box-h.gc @@ -40,6 +40,7 @@ ) ;; bounding both that has both a box and box4w. +;; these are used in the collision system where it is useful to have both float/int versions. (deftype bounding-box-both (structure) ((box bounding-box :inline :offset-assert 0) (box4w bounding-box4w :inline :offset-assert 32) diff --git a/goal_src/engine/geometry/bounding-box.gc b/goal_src/engine/geometry/bounding-box.gc index 8281fbdbe1..fd2ca6cbe7 100644 --- a/goal_src/engine/geometry/bounding-box.gc +++ b/goal_src/engine/geometry/bounding-box.gc @@ -29,9 +29,7 @@ ) ) -;; definition for method 11 of type bounding-box -(defmethod set-from-point-offset! bounding-box - ((obj bounding-box) (arg0 vector3s) (arg1 vector3s)) +(defmethod set-from-point-offset! bounding-box ((obj bounding-box) (arg0 vector3s) (arg1 vector3s)) "Set box to smallest containing the points arg0, (arg0 + arg1)" (rlet ((vf0 :class vf) (vf1 :class vf) @@ -54,7 +52,6 @@ ) ) -;; definition for method 10 of type bounding-box (defmethod add-point! bounding-box ((obj bounding-box) (arg0 vector3s)) "Expand the box if needed to contain the given point" (rlet ((vf1 :class vf) @@ -72,7 +69,6 @@ ) ) -;; definition for method 15 of type bounding-box (defmethod add-box! bounding-box ((obj bounding-box) (arg0 bounding-box)) "Expand the box if needed to contain the given box" (rlet ((vf1 :class vf) @@ -92,9 +88,7 @@ ) ) -;; definition for method 12 of type bounding-box -(defmethod set-from-point-offset-pad! bounding-box - ((obj bounding-box) (arg0 vector3s) (arg1 vector3s) (arg2 float)) +(defmethod set-from-point-offset-pad! bounding-box ((obj bounding-box) (arg0 vector3s) (arg1 vector3s) (arg2 float)) "Set the box size to contain pt, pt + offset, with some padding" (rlet ((vf0 :class vf) (vf1 :class vf) @@ -121,7 +115,6 @@ ) ) -;; definition for method 13 of type bounding-box (defmethod set-from-sphere! bounding-box ((obj bounding-box) (arg0 sphere)) "Set the box size to contain the given sphere" (rlet ((vf0 :class vf) @@ -141,6 +134,12 @@ ) ) +;;;;;;;;;;;;;;;;;;;;;;;;; +;; multi-sphere methods +;;;;;;;;;;;;;;;;;;;;;;;;; + +;; these are used in the collision system to build bounding boxes around collision geometries, so they are quite optimized. + (defmethod add-spheres! bounding-box ((obj bounding-box) (spheres (inline-array sphere)) (count int)) "Add count spheres." ;; the PS2 implementation is very optimized diff --git a/goal_src/engine/geometry/geometry-h.gc b/goal_src/engine/geometry/geometry-h.gc index 0b990e70a5..64bae48097 100644 --- a/goal_src/engine/geometry/geometry-h.gc +++ b/goal_src/engine/geometry/geometry-h.gc @@ -7,6 +7,8 @@ (defconstant MAX_CURVE_CONTROL_POINTS 256) +;; A 3 dimensional polynomial spline with arbitrarily placed knot points +;; It's used for camera paths and similar and can be generated by offline tools. (deftype curve (structure) ((cverts pointer :offset-assert 0) (num-cverts int32 :offset-assert 4) @@ -19,6 +21,7 @@ :flag-assert #x900000014 ) +;; unused plane type that would likely trigger some action on crossing. (deftype border-plane (basic) ((name symbol :offset-assert 4) (action basic :offset-assert 8) diff --git a/goal_src/engine/geometry/geometry.gc b/goal_src/engine/geometry/geometry.gc index f08c232ba8..72350e40d8 100644 --- a/goal_src/engine/geometry/geometry.gc +++ b/goal_src/engine/geometry/geometry.gc @@ -6,7 +6,6 @@ ;; dgos: GAME, ENGINE ;; Geometry functions are common vector/plane utilities + the "curve" stuff -;; The curves are likely bezier splines, but not 100% sure yet. (defun vector-flatten! ((dst vector) (src vector) (plane-normal vector)) "Get the projection of src onto a plane with the given normal @@ -143,6 +142,9 @@ ) (defun vector-segment-distance-point! ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + "Compute the distance from a point to the closest point on the line segment. + arg0 is the point. arg1/arg2 are the endpoints of the line segment. + arg3 is an optional output closest point." (local-vars (v0-0 float) (v1-0 float) (v1-1 float)) (rlet ((acc :class vf) (Q :class vf) @@ -212,6 +214,8 @@ ) (defun vector-line-distance ((arg0 vector) (arg1 vector) (arg2 vector)) + "Weird function: given a point arg1, and an infinite line connecting arg2 and arg1, compute the distance + from arg0 to that line." (let* ((a1-3 (vector-normalize! (vector-! (new-stack-vector0) arg2 arg1) 1.0)) (gp-1 (vector-! (new-stack-vector0) arg0 arg1)) (f0-1 (vector-dot a1-3 gp-1)) @@ -222,6 +226,7 @@ ) (defun vector-line-distance-point! ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + "Same as above function, but returns the point on arg2/arg1 in arg3 (ignored if #f)" (let* ((a1-3 (vector-normalize! (vector-! (new-stack-vector0) arg2 arg1) 1.0)) (s4-1 (vector-! (new-stack-vector0) arg0 arg1)) (f0-1 (vector-dot a1-3 s4-1)) @@ -235,6 +240,7 @@ ) (defun vector-orient-by-quat! ((arg0 vector) (arg1 vector) (arg2 quaternion)) + "Rotate a vector by a quaternion." (rlet ((acc :class vf) (vf0 :class vf) (vf1 :class vf) @@ -285,6 +291,7 @@ ;; consistent and provide orthogonal forward/down, they do the same thing. (defun forward-down->inv-matrix ((arg0 matrix) (arg1 vector) (arg2 vector)) + "Create a matrix representing an inverse transform where arg1 is forward (+z) and arg2 is down (-y). Will have the pitch of forward" (vector-normalize-copy! (-> arg0 vector 2) arg1 1.0) (vector-cross! (the-as vector (-> arg0 vector)) (-> arg0 vector 2) arg2) (vector-normalize! (the-as vector (-> arg0 vector)) 1.0) @@ -299,6 +306,7 @@ ) (defun forward-down-nopitch->inv-matrix ((arg0 matrix) (arg1 vector) (arg2 vector)) + "Create a matrix representing an inverse transform where arg1 is forward (+z) and arg2 is down (-y). Will not use the pitch of forward" (vector-normalize-copy! (-> arg0 vector 1) arg2 1.0) (vector-negate! (-> arg0 vector 1) (-> arg0 vector 1)) (vector-cross! (the-as vector (-> arg0 vector)) (-> arg0 vector 1) arg1) @@ -318,14 +326,17 @@ ) (defun forward-up-nopitch->inv-matrix ((arg0 matrix) (arg1 vector) (arg2 vector)) + "Create a matrix representing an inverse transform where arg1 is forward (+z) and arg2 is up (+y). Will not use the pitch of forward" (forward-down-nopitch->inv-matrix arg0 arg1 (vector-negate! (new-stack-vector0) arg2)) ) (defun forward-up-nopitch->quaternion ((arg0 quaternion) (arg1 vector) (arg2 vector)) + "Create a quaternion representing a transform where arg1 is forward (+z) and arg2 is up (+y). Will not use the pitch of forward" (matrix->quaternion arg0 (forward-up-nopitch->inv-matrix (new-stack-matrix0) arg1 arg2)) ) (defun forward-up->quaternion ((arg0 quaternion) (arg1 vector) (arg2 vector)) + "Create a quaternion representing a transform where arg1 is forward (+z) and arg2 is up (+y). Will use the pitch of forward" (matrix->quaternion arg0 (forward-down->inv-matrix (new-stack-matrix0) @@ -336,6 +347,7 @@ ) (defun quaternion-from-two-vectors! ((arg0 quaternion) (arg1 vector) (arg2 vector)) + "Create a quaternion representing the rotation between two vectors" (let* ((s5-0 (vector-cross! (new-stack-vector0) arg1 arg2)) (f0-0 (vector-length s5-0)) (f1-1 (vector-dot arg1 arg2)) @@ -351,6 +363,7 @@ ) (defun quaternion-from-two-vectors-max-angle! ((arg0 quaternion) (arg1 vector) (arg2 vector) (arg3 float)) + "Create a quaternion representing the rotation between two vectors, allowing at most a rotation of arg3 degrees" (let* ((s5-0 (vector-cross! (new-stack-vector0) arg1 arg2)) (f30-0 (vector-length s5-0)) (f26-0 (vector-dot arg1 arg2)) @@ -377,6 +390,7 @@ ) (defun matrix-from-two-vectors! ((arg0 matrix) (arg1 vector) (arg2 vector)) + "Create a rotation matrix representing the rotation between two vectors" (let* ((a1-3 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) (f0-1 (vector-dot arg1 arg2)) (f1-0 1.0) @@ -388,6 +402,7 @@ ) (defun matrix-from-two-vectors-max-angle! ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 float)) + "Create a rotation matrix representing the rotation between two vectors, allowing at most a rotation of arg3 degrees" (let ((s4-1 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) (f30-0 (vector-dot arg1 arg2)) @@ -412,7 +427,13 @@ ) ) + +;; +;; note: these two interpolation functions may be equivalent to slerp. + (defun matrix-from-two-vectors-max-angle-partial! ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 float) (arg4 float)) + "Create a rotation matrix representing the rotation between two vectors, allowing at most a rotation of arg3 degrees, + doing arg4 fraction of the rotation." (let* ((s4-1 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) (f28-0 (vector-dot arg1 arg2)) (f30-0 (cos arg3)) @@ -438,6 +459,7 @@ ) (defun matrix-from-two-vectors-partial-linear! ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 float)) + "Create a rotation matrix representing doing arg3 fraction of the rotation between two vectors" (let ((gp-1 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) (f0-1 (vector-dot arg1 arg2)) ) @@ -460,6 +482,7 @@ ) (defun matrix-remove-z-rot ((arg0 matrix) (arg1 matrix)) + "Remove the z rotation component of a rotation." (let ((s4-0 (new-stack-vector0))) 0.0 0.0 @@ -485,6 +508,7 @@ ) (defun matrix-rot-diff! ((arg0 vector) (arg1 matrix) (arg2 matrix)) + "Get the difference of rotation between two matrices, expressed as a quaternion." (let ((s3-0 (new-stack-quaternion0)) (s2-0 (new-stack-quaternion0)) (s5-0 (new-stack-quaternion0)) @@ -511,6 +535,7 @@ (defun quaternion-seek ((arg0 quaternion) (arg1 quaternion) (arg2 quaternion) (arg3 float) (arg4 float)) + "Strange quaternion rotate toward function. Arg3 is ignored. Arg4 is the max seek amount." (let ((s5-0 (new-stack-matrix0)) (s4-0 (new-stack-matrix0)) ) @@ -529,6 +554,7 @@ ) (defun vector-deg-seek ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 float)) + "Make one vector closer to another, doing at most a rotation by arg3 degrees." (let ((s4-0 (new-stack-matrix0))) (matrix-from-two-vectors-max-angle! s4-0 arg1 arg2 arg3) (vector-matrix*! arg0 arg1 s4-0) @@ -536,6 +562,7 @@ ) (defun vector-deg-slerp ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 float)) + "Slerp for vectors. (imagine that they are the z axis of two frames)" (cond ((>= 0.0 arg3) (set! (-> arg0 quad) (-> arg1 quad)) @@ -560,6 +587,7 @@ ) (defun vector-vector-deg-slerp! ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 float) (arg4 vector)) + "unused. no clue what this does." (local-vars (sv-112 (function float float float float))) (cond ((>= 0.0 arg3) @@ -592,6 +620,7 @@ ) (defun normal-of-plane ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + "Given three points on a plane, compute the plane's normal" (rlet ((acc :class vf) (Q :class vf) (vf0 :class vf) @@ -624,6 +653,7 @@ ) (defun vector-3pt-cross! ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + "Cross product of 2 - 1 and 3 - 1. (will give a normal to the plane, but not of magnitude 1)" (rlet ((acc :class vf) (vf0 :class vf) (vf1 :class vf) @@ -646,7 +676,7 @@ ) (defun closest-pt-in-triangle ((arg0 vector) (arg1 vector) (arg2 matrix) (arg3 vector)) - "arg2 is probably the triangle" + "arg2 is the vertices of the triangle, arg3 is the normal, arg1 is the input point, arg0 is the output." ;; (declare (print-asm)) (local-vars (v1-0 uint) @@ -832,6 +862,7 @@ ) (defun point-in-triangle-cross ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector) (arg4 vector)) + "Check if point is in the triangle using cross product check (so you have to get the order of points right)" (local-vars (v1-0 int) (a0-1 int) (a1-1 int)) (rlet ((acc :class vf) (vf1 :class vf) @@ -881,6 +912,7 @@ ) (defun point-in-plane-<-point+normal! ((arg0 vector) (arg1 vector) (arg2 vector)) + "This function looks wrong and is unused." (let ((f0-3 (+ @@ -1039,6 +1071,15 @@ (none) ) + +;;;;;;;;;;;;;;;;;;; +;; curve +;;;;;;;;;;;;;;;;;;; + +;; the curves take a floating point input and produce a floating point output. +;; the curve is a piecewise polynomial. The first step of evaluation is to figure out which +;; knots the input point lies in between. The second step is to evaluate the appropriate polynomial. + (defun find-knot-span ((arg0 int) (arg1 int) (arg2 float) (arg3 (inline-array vector))) "Binary serach over knots to find which contains the value float in (arg0 arg1). Unused." (local-vars (v0-0 int)) @@ -1092,6 +1133,7 @@ ) (defun calculate-basis-functions-vector! ((arg0 (pointer float)) (arg1 int) (arg2 float) (arg3 (pointer float))) + "Calculate polynomial basis for a given control point." (local-vars (v1-0 int) (v1-1 object)) ;;(.sll v1-0 arg1 2) (set! v1-0 (* 4 arg1)) ;; originally used 32-bit asm @@ -1151,6 +1193,14 @@ ) (defun curve-evaluate! ((arg0 vector) (arg1 float) (arg2 pointer) (arg3 int) (arg4 (inline-array vector)) (arg5 int)) + "Evaluate a curve. + arg0 is the output + arg1 is the input. + arg2 is control vertices + arg3 is the number of control vertices + arg4 is the knot points + arg5 is the number of knots + " (local-vars (v1-7 int) (v1-8 int) (v1-10 float) (s3-0 int)) (rlet ((acc :class vf) (vf0 :class vf) @@ -1164,6 +1214,7 @@ (init-vf0-vector) (let ((s4-0 (new 'static 'array float 4 0.0 0.0 0.0 0.0))) 0 + ;; lookup knot (let* ((f0-0 (-> arg4 0 x)) (f1-0 (-> (&-> arg4 0 data (+ arg5 -1)) 0)) (a2-1 (fmax (fmin (* arg1 f1-0) f1-0) f0-0)) @@ -1211,6 +1262,7 @@ (nop!) (nop!) (label cfg-11) + ;; calculate coefficients for this knot's polynomial, store in s4-0 (calculate-basis-functions-vector! s4-0 s3-0 @@ -1222,6 +1274,7 @@ (set! v1-7 (- s3-0 3)) (.lvf vf6 s4-0) ) + ;; evaluate polynomial! ;;(.sll v1-8 v1-7 4) (set! v1-8 (* v1-7 16)) (.add.x.vf vf1 vf0 vf0 :mask #b1000) @@ -1258,6 +1311,7 @@ ) (defun curve-get-pos! ((arg0 vector) (arg1 float) (arg2 curve)) + "Get the position on the curve at the given input." (curve-evaluate! arg0 arg1 @@ -1269,6 +1323,7 @@ ) (defun curve-length ((arg0 curve)) + "Compute the approximate curve length as the sum of distances between knots." (let ((s5-0 (new-stack-vector0)) (s4-0 (new-stack-vector0)) (s3-0 (* 3 (-> arg0 num-cverts))) @@ -1299,6 +1354,7 @@ ) (defun curve-copy! ((arg0 curve) (arg1 curve)) + "Shallow copy a curve." (set! (-> arg0 cverts) (-> arg1 cverts)) (set! (-> arg0 num-cverts) (-> arg1 num-cverts)) (set! (-> arg0 knots) (-> arg1 knots)) @@ -1308,6 +1364,7 @@ ) (defun curve-closest-point ((arg0 curve) (arg1 vector) (arg2 float) (arg3 float) (arg4 int) (arg5 float)) + "Get the input value for the point on the curve. Approximate! And is O(n_knots)" (local-vars (sv-48 float)) (set! sv-48 arg3) (let ((s3-0 arg4) @@ -1369,6 +1426,7 @@ ) (defun vector-plane-distance ((arg0 vector) (arg1 plane) (arg2 vector)) + "Unused." (vector-dot (vector-! (new 'stack-no-clear 'vector) arg0 (the-as vector (&-> arg1 x))) arg2 diff --git a/goal_src/engine/gfx/decomp-h.gc b/goal_src/engine/gfx/decomp-h.gc index 6e7905f27f..f2d023ba18 100644 --- a/goal_src/engine/gfx/decomp-h.gc +++ b/goal_src/engine/gfx/decomp-h.gc @@ -5,6 +5,8 @@ ;; name in dgo: decomp-h ;; dgos: GAME, ENGINE +;; temporary storage for visibility data decompression. +;; this is stored on the scratchpad. (deftype decomp-work (structure) ((buffer0 uint8 2048 :offset-assert 0) (buffer1 uint8 2048 :offset-assert 2048) diff --git a/goal_src/engine/gfx/font-h.gc b/goal_src/engine/gfx/font-h.gc index 3a7cd5b00e..dd126384a8 100644 --- a/goal_src/engine/gfx/font-h.gc +++ b/goal_src/engine/gfx/font-h.gc @@ -96,6 +96,7 @@ ) ) +;; font settings that can be passed to draw-string (deftype font-context (basic) ((origin vector :inline :offset-assert 16) (strip-gif vector :inline :offset-assert 32) @@ -258,6 +259,7 @@ ) ) +;; Data used by the font-renderer. (deftype font-work (structure) ((font-tmpl dma-gif-packet :inline :offset-assert 0) (char-tmpl dma-gif-packet :inline :offset-assert 32) diff --git a/goal_src/engine/gfx/hw/display.gc b/goal_src/engine/gfx/hw/display.gc index 128e9b544c..1339b98621 100644 --- a/goal_src/engine/gfx/hw/display.gc +++ b/goal_src/engine/gfx/hw/display.gc @@ -13,12 +13,15 @@ ;; for some reason, the display also tracks some timing stuff. (defun get-current-time () - "Possibly the wall-clock time" + "Get the in game time. This advances when the game is unpaused. + This increase at the same rate for PAL/NTSC and if the game is lagging." (-> *display* base-frame-counter) ) (defun get-integral-current-time () - "The integral of game frame time (this slows down as we lag)" + "Get the game time as a number of frames. This advances at different rates for PAL/NTSC. + This counts the number of actual vsyncs done by the PS2, including ones that are missed due to lag. + " (-> *display* integral-frame-counter) ) @@ -250,7 +253,7 @@ ) (defun set-display2 ((disp display) (psm int) (w int) (h int) (ztest int) (zpsm int)) - "Set the display and draw envs only. This assumes you have already done a set-display." + "Set the display and draw envs only. This assumes you have already done a set-display and you just need to update the video mode." (set-display-env (-> disp display-env0) psm w h (-> *video-parms* display-dx) (-> *video-parms* display-dy) 320) (set-display-env (-> disp display-env1) psm w h (-> *video-parms* display-dx) (-> *video-parms* display-dy) 384) (set-draw-env (-> disp draw0) psm w h ztest zpsm 384) @@ -262,10 +265,14 @@ (defun allocate-dma-buffers ((arg0 display)) "Allocate the main DMA buffers!" (when (zero? (-> arg0 frames 0 frame calc-buf)) - ;; not sure what these "calc-buf"s are. Maybe VU0 DMA or other small stuff that is used in the same frame? + ;; allocate a small calc-buf for each frame. + ;; these smaller buffers are used by the engine to patch buckets and get sent directly to VU1. (set! (-> arg0 frames 0 frame calc-buf) (new 'global 'dma-buffer 10000)) (set! (-> arg0 frames 1 frame calc-buf) (new 'global 'dma-buffer 10000)) - ;; the main DMA buffers for each frame's drawing. + + ;; the main DMA buffers for each frame's drawing. The buckets in the calc buf will reference data in here. + ;; the individual renderers use these buffers. + ;; the reason for separate calc/global buf is unknown. (set! (-> arg0 frames 0 frame global-buf) (new 'global 'dma-buffer #x1ac000)) (set! (-> arg0 frames 1 frame global-buf) (new 'global 'dma-buffer #x1ac000)) @@ -279,12 +286,13 @@ arg0 ) - +;; set up the main font contexts. +;; used for debug prints (define *font-context* (new 'global 'font-context *font-default-matrix* 0 24 0.0 (font-color default) (font-flags shadow kerning))) + +;; not used, but looks like it would work for the "PAUSE" text. (define *pause-context* (new 'global 'font-context *font-default-matrix* 256 170 0.0 (font-color orange-red) (font-flags shadow kerning))) - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; PROFILE BAR ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/goal_src/engine/gfx/hw/video-h.gc b/goal_src/engine/gfx/hw/video-h.gc index b4cf12bf52..523ea98d09 100644 --- a/goal_src/engine/gfx/hw/video-h.gc +++ b/goal_src/engine/gfx/hw/video-h.gc @@ -12,8 +12,6 @@ ;; The game is interlaced, meaning each framebuffer is half height. -;; There are two - (deftype video-parms (structure) ((set-video-mode basic :offset-assert 0) (reset-video-mode basic :offset-assert 4) diff --git a/goal_src/engine/gfx/hw/vu1-user-h.gc b/goal_src/engine/gfx/hw/vu1-user-h.gc index 94b7463bf5..de2cb3736e 100644 --- a/goal_src/engine/gfx/hw/vu1-user-h.gc +++ b/goal_src/engine/gfx/hw/vu1-user-h.gc @@ -60,10 +60,10 @@ ;; a dma "sink" is somewhere where a renderer can put stuff. (deftype dma-foreground-sink (basic) - ((bucket bucket-id :offset-assert 4) - (foreground-texture-page int8 :offset-assert 8) ;; ? - (foreground-texture-level int8 :offset-assert 9) ;; ? - (foreground-output-bucket int8 :offset-assert 10) ;; ? + ((bucket bucket-id :offset-assert 4) ;; the DMA bucket + (foreground-texture-page int8 :offset-assert 8) ;; the tpage we need (in the level) + (foreground-texture-level int8 :offset-assert 9) ;; the level we belong to + (foreground-output-bucket int8 :offset-assert 10) ;; ? ) :method-count-assert 9 :size-assert #xb diff --git a/goal_src/engine/gfx/texture-h.gc b/goal_src/engine/gfx/texture-h.gc index fd19ac5c64..6d3b387606 100644 --- a/goal_src/engine/gfx/texture-h.gc +++ b/goal_src/engine/gfx/texture-h.gc @@ -12,7 +12,6 @@ ;; There are a lot more details, see texture.gc for more info - ;;;;;;;;;;;;;;;;;;;;;; ;; Texture Control ;;;;;;;;;;;;;;;;;;;;;; @@ -156,7 +155,7 @@ ) (defun texture-mip->segment ((arg0 int) (arg1 int)) - "Unknown, not used." + "Convert a mip level to the segment that it is stored in." (if (>= 2 arg1) (+ (- -1 arg0) arg1) (max 0 (- 2 arg0))) ) @@ -172,6 +171,8 @@ (size uint32 :offset-assert 24) ;; VRAM words (segment texture-page-segment 3 :inline :offset-assert 28) (pad uint32 16 :offset-assert 64) + + ;; array of texture descriptions. (data texture :dynamic :offset-assert 128) ) :method-count-assert 15 @@ -197,7 +198,8 @@ ;; There is a linked-list of these per texture that uses the shader-ptr type below ;; A shader-ptr is a reference to an adgif shader. -;; The trick here is that it can fit into unused space in the GS packet. +;; The trick here is that it can fit into unused space in the GS packet, allowing each +;; adgif shader to be part of a linked list of adgif shaders for their texture-page. ;; the A+D format only uses bits 0-72, this fits in 72-96. The use of 96-128 is unknown ;; the shader value must be multiplied by 16 first. (deftype shader-ptr (uint32) diff --git a/goal_src/engine/level/level-h.gc b/goal_src/engine/level/level-h.gc index 843796488f..6abbf035bf 100644 --- a/goal_src/engine/level/level-h.gc +++ b/goal_src/engine/level/level-h.gc @@ -5,37 +5,64 @@ ;; name in dgo: level-h ;; dgos: GAME, ENGINE -;; The level system is responsible for loading and managning the two levels. +;; The level system is responsible for loading and managning the two levels, +;; including the visible data. + ;; The "level" type contains runtime information about a level (possibly one that is loading) ;; and the "level-group" type contains two levels. (defconstant LEVEL_COUNT 2) ;; there are two levels in memory! +(declare-type bsp-header basic) +(declare-type drawable basic) +(declare-type engine basic) +(declare-type entity-links-array basic) +(declare-type entity-ambient-data-array basic) +(declare-type mood-context basic) +(declare-type entity-links structure) + +;;;;;;;;;;;;;;; +;; VIS +;;;;;;;;;;;;;;; + +;; each game "level" has some precomputed visibility. +;; There's a binary space partition (bsp) +;; Each leaf node corresponds to a bit string with (up to) 16384 bits +;; These bits tell you if a certain "drawable" is visible or not. +;; The drawable's index is the index of its visibilty bit. +;; Note that not all drawables have a visibility bit - drawable groups sometimes don't and shrub's don't. + +;; One challenge of the visibility system is that you can't actually load the visibility for two levels +;; at the same time. Each level has a large .VIS file that must be loaded. +;; The actual level files contain a small amount of VIS file for areas on their borders. +;; While the .VIS is loading (or you are on the border of two levels), the engine will look in these +;; small visibility infos. + +;; The large .VIS files are stored on the IOP. As a result, there's a small delay to actually +;; fetch a visibility string. + (defenum vis-info-flag :bitfield #t :type uint32 - (twenty-nine 29) ;; is .VIS file vis? - (waiting-for-iop-to-ee 30) - (thirty-one 31) ;; single vis? + (from-vis-file 29) ;; is .VIS file vis? + (waiting-for-iop-to-ee 30) ;; not here yet + (using-this-as-only-vis 31) ;; using this as the only visibility data ) ;; Information related to visibility data for a level. -;; This is just metadata that describes the actual VIS file. +;; This is just metadata that describes the actual visibiltiy data. ;; The typical use is to do (-> info vis-string idx) to get the offset (in the .VIS file) of the ;; compressed visibility string for a given bsp leaf. ;; Each level may have multiple level-vis-infos. -;; Each .VIS file can have visibility data for multiple levels. -;; Each level that is present in a .VIS has a level-vis-info to go with is. ;; One level-vis-info (the first) is always for the -;; actual level, and there is typically one for each neighboring level. +;; actual level (stored in .VIS file), and there is typically one for each neighboring level. ;; The final level-vis-info (7) should always be empty (set to 0 in the bsp-header) ;; When travelling between two levels, the game will only have one .VIS file loaded, ;; and it does two lookups in this .VIS file - one for the current level, and one for the nearby ;; levels. This means that visibility for "beach" near the border of "village1" is stored in ;; both BEA.VIS and VI1.VIS. -(declare-type bsp-header basic) (deftype level-vis-info (basic) ((level symbol :offset-assert 4) (from-level symbol :offset-assert 8) @@ -63,34 +90,35 @@ ) ;; Per level information related to how to load the level. -;; These are stored in level-info.gc +;; These are stored in level-info.gc which is always loaded, so this should have all the information required +;; to do a level load. (deftype level-load-info (basic) ((name-list symbol 3 :offset-assert 4) - (index int32 :offset-assert 16) ;; the level number (starting with 1?) + (index int32 :offset-assert 16) ;; the level number (starting with 1?) (name symbol :offset 4) ;; symbol with full name, like "misty" (visname symbol :offset 8) ;; symbol with vis file name, like "misty-vis" (nickname symbol :offset 12) ;; 3 letter name for DGO, like "mis" - (packages pair :offset-assert 20) ;; list of symbols, usually empty or the level name - (sound-banks pair :offset-assert 24) ;; require sound bank files (list of symbols) + (packages pair :offset-assert 20) ;; list of symbols, usually empty or the level name + (sound-banks pair :offset-assert 24) ;; require sound bank files (list of symbols) (music-bank symbol :offset-assert 28) ;; name of level music - (ambient-sounds pair :offset-assert 32) ;; always empty list. + (ambient-sounds pair :offset-assert 32) ;; always empty list. (mood symbol :offset-assert 36) ;; mood object name (mood-func symbol :offset-assert 40) ;; mood update function name (ocean symbol :offset-assert 44) ;; ocean map object (sky symbol :offset-assert 48) ;; boolean to enable sky - (sun-fade float :offset-assert 52) ;; sun/sky setting - (continues pair :offset-assert 56) ;; list of checkpoints - (tasks pair :offset-assert 60) ;; list of boxed integers for tasks - (priority int32 :offset-assert 64) ;; either 100 or 200 - (load-commands pair :offset-assert 68) ;; ?? - (alt-load-commands pair :offset-assert 72) ;; ?? - (bsp-mask uint64 :offset-assert 80) ;; ?? - (bsphere sphere :offset-assert 88) ;; boundings sphere of level? - (buzzer int32 :offset-assert 92) ;; which task is the scout fly? + (sun-fade float :offset-assert 52) ;; sun/sky setting + (continues pair :offset-assert 56) ;; list of checkpoints + (tasks pair :offset-assert 60) ;; list of boxed integers for tasks + (priority int32 :offset-assert 64) ;; either 100 or 200 + (load-commands pair :offset-assert 68) ;; ?? + (alt-load-commands pair :offset-assert 72) ;; ?? + (bsp-mask uint64 :offset-assert 80) ;; ?? + (bsphere sphere :offset-assert 88) ;; boundings sphere of level? + (buzzer int32 :offset-assert 92) ;; which task is the scout fly? (bottom-height meters :offset-assert 96) - (run-packages pair :offset-assert 100) ;; possibly unused? - (prev-level basic :offset-assert 104) - (next-level basic :offset-assert 108) + (run-packages pair :offset-assert 100) ;; possibly unused? + (prev-level basic :offset-assert 104) + (next-level basic :offset-assert 108) (wait-for-load symbol :offset-assert 112) ) :method-count-assert 9 @@ -100,7 +128,6 @@ ;; The levels are initialized (called "login") over multiple frames. ;; The state of this process is stored in a login-state. -(declare-type drawable basic) (deftype login-state (basic) ((state int32 :offset-assert 4) (pos uint32 :offset-assert 8) @@ -112,20 +139,17 @@ :flag-assert #x900000050 ) -(declare-type engine basic) -(declare-type entity-links-array basic) -(declare-type entity-ambient-data-array basic) -(declare-type mood-context basic) +;; The actual "level". This manages loading and running a game level. (deftype level (basic) ((name symbol :offset-assert 4) (load-name symbol :offset-assert 8) (nickname symbol :offset-assert 12) (index int32 :offset-assert 16) (status symbol :offset-assert 20) - (other level :offset-assert 24) - (heap kheap :inline :offset-assert 32) - (bsp bsp-header :offset-assert 48) - (art-group load-dir-art-group :offset-assert 52) + (other level :offset-assert 24) ;; the other level object + (heap kheap :inline :offset-assert 32) ;; level's ~10 MB heap + (bsp bsp-header :offset-assert 48) ;; the main level object in the DGO + (art-group load-dir-art-group :offset-assert 52) ;; the art (foreground models/anims) for the level (info level-load-info :offset-assert 56) (texture-page texture-page 9 :offset-assert 60) (loaded-texture-page texture-page 16 :offset-assert 96) @@ -190,13 +214,11 @@ ) ) -(declare-type entity-links structure) ;; Main *level* object. ;; There are actually three levels. level0 and level1 correspond to the actual buffered levels ;; The level-default seems to be a fake level that can possibly be used by renderers that ;; don't belong to any level, for example to render Jak. -(declare-type entity-links structure) (deftype level-group (basic) ((length int32 :offset-assert 4) (log-in-level-bsp bsp-header :offset-assert 8) ;; level currently logging in diff --git a/goal_src/engine/load/loader-h.gc b/goal_src/engine/load/loader-h.gc index 074ea0ba43..8f1ee82643 100644 --- a/goal_src/engine/load/loader-h.gc +++ b/goal_src/engine/load/loader-h.gc @@ -5,8 +5,7 @@ ;; name in dgo: loader-h ;; dgos: GAME, ENGINE -;; This is not well-understood yet, but it is definitely related to streaming animation loading, -;; and possibly art-group stuff. +;; The loader is responsible for managing streaming loads. ;; note: lower values are more important. ;; negative values will preload. @@ -80,6 +79,7 @@ ) ;; An external-art-buffer owns some memory for loading files. +;; the "external" means it's not part of the level's (or common, always loaded) static data ;; status: ;; - 'active: file is loaded and art group is linked to level's art group. ;; - 'reserved: buffer is reserved for other purpose @@ -145,8 +145,7 @@ ) -;; A spool-anim tracks the buffers for spooled animations. -;; ?? what are the bufs here. +;; A spool-anim tracks the buffers holding chunks of a spooled animation. (deftype spool-anim (basic) ((name string :offset 16) ;; why? (buf1 external-art-buffer :offset 16) ;; custom @@ -163,7 +162,9 @@ :flag-assert #x90000002c ) -;; This is the main controller for the loader. +;; This is the main controller for the streaming loader. +;; It has two buffers for holding chunks of a spooling animation +;; The buffer can also be reused to hold other things. (deftype external-art-control (basic) ((buffer external-art-buffer 2 :offset-assert 4) ;; actual data buffers (rec spool-anim 3 :inline :offset-assert 16) ;; things we would consider loading diff --git a/goal_src/engine/math/euler-h.gc b/goal_src/engine/math/euler-h.gc index e6eff50f6d..eb3fa934d0 100644 --- a/goal_src/engine/math/euler-h.gc +++ b/goal_src/engine/math/euler-h.gc @@ -14,6 +14,7 @@ ;; just uses the same xyzw and data array as vector. ;; the w stores a float that should be an integer that seems to have ;; bitfields for... something? Like maybe the order? +;; Euler angles are mostly unused (deftype euler-angles (vector) () :method-count-assert 9 diff --git a/goal_src/engine/math/math.gc b/goal_src/engine/math/math.gc index 06aac7d0ce..5c23886234 100644 --- a/goal_src/engine/math/math.gc +++ b/goal_src/engine/math/math.gc @@ -5,10 +5,7 @@ ;; name in dgo: math ;; dgos: GAME, ENGINE -;; contains various math helpers - - - +;; various math helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; float utility @@ -285,6 +282,7 @@ (set! (-> *random-generator* seed) #x666EDD1E) (defmacro sext32-64 (x) + "Sign extend a 32-bit value to 64-bits" `(sar (shl ,x 32) 32) ) diff --git a/goal_src/engine/math/matrix-h.gc b/goal_src/engine/math/matrix-h.gc index a6a532e492..8f5e261015 100644 --- a/goal_src/engine/math/matrix-h.gc +++ b/goal_src/engine/math/matrix-h.gc @@ -6,6 +6,8 @@ ;; dgos: GAME, ENGINE ;; A 4x4 matrix, stored in row-major order +;; some, but not all, functions assume that a matrix is an affine transform. +;; others assume that the rotation has no scale or shear (and that its inverse is its transpose) (deftype matrix (structure) ((vector vector 4 :inline :offset-assert 0) (quad uint128 4 :offset 0) @@ -22,6 +24,7 @@ ;; A 3x3 matrix, stored in row-major order. ;; NOTE: the rows each have an extra 4-bytes of padding ;; so this is really a 3x4 matrix. +;; this type is rarely used (deftype matrix3 (structure) ((data float 12 :offset-assert 0) (vector vector 3 :inline :offset 0) @@ -32,7 +35,11 @@ :flag-assert #x900000030 ) -;; guess on signs here +;; a matrix stored using 16-bit integers. +;; note that these usually have different scaling for the 4th row which +;; contains the translation in an affine transform. +;; so you generally should not unpack these to floats without knowing where they came from +;; and how they were originally packed (for example, in tie/shrub) (deftype matrix4h (structure) ((data int16 16 :offset-assert 0) (vector4h vector4h 4 :inline :offset 0) diff --git a/goal_src/engine/math/matrix.gc b/goal_src/engine/math/matrix.gc index 0391be2c1b..058a419467 100644 --- a/goal_src/engine/math/matrix.gc +++ b/goal_src/engine/math/matrix.gc @@ -25,6 +25,9 @@ ;; which is probably the transpose of what you're used to. +;; note that they also used row-major storage, so the 3rd qword of a matrix is the translation +;; part of the affine transform. + ;; In general, be careful with using these functions as they often have strange ;; requirements for the form of the input matrix or if the input/output matrix are ;; allowed to be the same memory. @@ -315,12 +318,8 @@ (vf5 :class vf) ) ;; this implementation is better than vector-matrix*! - ;; (nop!) - ;; (nop!) (.lvf vf5 (&-> vec quad)) - ;; (nop!) (.lvf vf1 (&-> mat vector 0 quad)) - ;; (nop!) (.lvf vf2 (&-> mat vector 1 quad)) ;; the mul's assume the right-most column of the input matrix are 0,0,0,X (.mul.x.vf acc vf1 vf5) @@ -329,8 +328,6 @@ ;; this load doesn't need to be here! (.lvf vf4 (&-> mat vector 3 quad)) (.add.mul.z.vf vf5 vf3 vf5 acc) - ;; (nop!) - ;; (nop!) (.svf (&-> dst quad) vf5) dst ) @@ -374,12 +371,8 @@ (a3-2 uint128) (t0-1 uint128) ) - ;; (nop!) - ;; (nop!) (let ((t0-0 (-> src vector 0 quad))) - ;; (nop!) (let ((t1-0 (-> src vector 1 quad))) - ;; (nop!) (let ((a2-0 (-> src vector 2 quad))) (.pextlw v1-0 t1-0 t0-0) (let ((a3-0 (-> src vector 3 quad))) @@ -402,7 +395,6 @@ (set! (-> dst vector 1 quad) v1-1) (.pcpyud v1-2 a1-1 a2-1) (set! (-> dst vector 2 quad) a3-2) - ;; (nop!) (set! (-> dst vector 3 quad) v1-2) dst ) @@ -508,119 +500,66 @@ (.xor.vf vf19 vf19 vf19) (init-vf0-vector) - ;; (nop!) - ;; (nop!) (.lvf vf23 (&-> src vector 0 quad)) - ;; (nop!) (.lvf vf24 (&-> src vector 1 quad)) - ;; (nop!) (.lvf vf25 (&-> src vector 2 quad)) - ;; (nop!) (.lvf vf1 (&-> src vector 3 quad)) (.mul.x.vf vf7 vf24 vf23) - ;; (nop!) (.mul.y.vf vf8 vf24 vf23) - ;; (nop!) (.mul.z.vf vf9 vf24 vf23) - ;; (nop!) (.mul.x.vf vf10 vf25 vf23) - ;; (nop!) (.mul.y.vf vf11 vf25 vf23) - ;; (nop!) (.mul.z.vf vf12 vf25 vf23) - ;; (nop!) (.mul.x.vf vf13 vf25 vf24) - ;; (nop!) (.mul.y.vf vf14 vf25 vf24) - ;; (nop!) (.mul.z.vf vf15 vf25 vf24) - ;; (nop!) (.mul.z.vf vf26 vf7 vf25 :mask #b10) - ;; (nop!) (.mul.z.vf vf27 vf11 vf24 :mask #b1) - ;; (nop!) (.mul.y.vf vf28 vf9 vf25 :mask #b1) - ;; (nop!) (.mul.z.vf vf29 vf14 vf23 :mask #b1) - ;; (nop!) (.mul.z.vf vf30 vf8 vf25 :mask #b1) - ;; (nop!) (.mul.y.vf vf31 vf7 vf25 :mask #b100) - ;; (nop!) (.add.y.vf vf16 vf27 vf26 :mask #b1) - ;; (nop!) (.sub.vf vf1 vf0 vf1) - ;; (nop!) (.add.x.vf vf17 vf29 vf30 :mask #b1) - ;; (nop!) (.sub.z.vf vf18 vf28 vf31 :mask #b1) - ;; (nop!) (.sub.y.vf vf23 vf14 vf15 :mask #b100) - ;; (nop!) (.sub.z.vf vf26 vf15 vf13 :mask #b1) - ;; (nop!) (.sub.x.vf vf29 vf13 vf14 :mask #b10) - ;; (nop!) (.sub.vf vf19 vf16 vf17 :mask #b1) - ;; (nop!) (.sub.z.vf vf24 vf12 vf11 :mask #b10) - ;; (nop!) (.sub.x.vf vf27 vf10 vf12 :mask #b100) - ;; (nop!) (.sub.y.vf vf30 vf11 vf10 :mask #b1) - ;; (nop!) (.add.vf vf20 vf19 vf18 :mask #b1) - ;; (nop!) (.sub.y.vf vf25 vf8 vf9 :mask #b100) - ;; (nop!) (.sub.z.vf vf28 vf9 vf7 :mask #b1) - ;; (nop!) (.sub.x.vf vf31 vf7 vf8 :mask #b10) - ;; (nop!) (.div.vf Q vf0 vf20 :fsf #b11 :ftf #b0) - ;; (nop!) ;;(.sub.w.vf vf3 vf3 vf3 :mask #b1000) (.xor.vf vf3 vf3 vf3) - ;; (nop!) ;;(.sub.w.vf vf4 vf4 vf4 :mask #b1000) (.xor.vf vf4 vf4 vf4) - ;; (nop!) ;;(.sub.w.vf vf5 vf5 vf5 :mask #b1000) (.xor.vf vf5 vf5 vf5) - ;; (nop!) (.mov.vf vf6 vf0 :mask #b1000) - ;; (nop!) (.wait.vf) - ;; (nop!) (.add.vf vf2 vf0 Q :mask #b1) - ;; (nop!) (.add.x.vf vf2 vf0 vf2 :mask #b111) - ;; (nop!) (.mul.z.vf vf3 vf2 vf23 :mask #b1) - ;; (nop!) (.mul.x.vf vf4 vf2 vf26 :mask #b1) - ;; (nop!) (.mul.y.vf vf5 vf2 vf29 :mask #b1) - ;; (nop!) (.mul.y.vf vf3 vf2 vf24 :mask #b10) - ;; (nop!) (.mul.z.vf vf4 vf2 vf27 :mask #b10) - ;; (nop!) (.mul.x.vf vf5 vf2 vf30 :mask #b10) - ;; (nop!) (.mul.z.vf vf3 vf2 vf25 :mask #b100) - ;; (nop!) (.mul.x.vf vf4 vf2 vf28 :mask #b100) - ;; (nop!) (.mul.y.vf vf5 vf2 vf31 :mask #b100) - ;; (nop!) (.mul.x.vf acc vf3 vf1) (.svf (&-> dst vector 0 quad) vf3) (.add.mul.y.vf acc vf4 vf1 acc) (.svf (&-> dst vector 1 quad) vf4) (.add.mul.z.vf vf6 vf5 vf1 acc :mask #b111) (.svf (&-> dst vector 2 quad) vf5) - ;; (nop!) (.svf (&-> dst vector 3 quad) vf6) dst ) @@ -1180,81 +1119,33 @@ "Compute the inverse of a 3x3 matrix. Not very efficient. Requires src != dst." (let ((f0-0 (matrix-3x3-determinant src))) - (set! - (-> dst data 0) - (/ - (- - (* (-> src data 5) (-> src data 10)) - (* (-> src data 6) (-> src data 9)) - ) - f0-0 - ) - ) - (set! - (-> dst data 4) - (/ - (- - (* (-> src data 6) (-> src data 8)) - (* (-> src data 4) (-> src data 10)) - ) - f0-0 - ) - ) - (set! - (-> dst data 8) - (/ - (- (* (-> src data 4) (-> src data 9)) (* (-> src data 5) (-> src data 8))) - f0-0 - ) - ) - (set! - (-> dst data 1) - (/ - (- - (* (-> src data 9) (-> src data 2)) - (* (-> src data 10) (-> src data 1)) - ) - f0-0 - ) - ) - (set! - (-> dst data 5) - (/ - (- - (* (-> src data 10) (-> src data 0)) - (* (-> src data 8) (-> src data 2)) - ) - f0-0 - ) - ) - (set! - (-> dst data 9) - (/ - (- (* (-> src data 8) (-> src data 1)) (* (-> src data 9) (-> src data 0))) - f0-0 - ) - ) - (set! - (-> dst data 2) - (/ - (- (* (-> src data 1) (-> src data 6)) (* (-> src data 2) (-> src data 5))) - f0-0 - ) - ) - (set! - (-> dst data 6) - (/ - (- (* (-> src data 2) (-> src data 4)) (* (-> src data 0) (-> src data 6))) - f0-0 - ) - ) - (set! - (-> dst data 10) - (/ - (- (* (-> src data 0) (-> src data 5)) (* (-> src data 1) (-> src data 4))) - f0-0 - ) - ) + (set! (-> dst vector 0 x) + (/ (- (* (-> src vector 1 y) (-> src vector 2 z)) (* (-> src vector 1 z) (-> src vector 2 y))) f0-0) + ) + (set! (-> dst vector 1 x) + (/ (- (* (-> src vector 1 z) (-> src vector 2 x)) (* (-> src vector 1 x) (-> src vector 2 z))) f0-0) + ) + (set! (-> dst vector 2 x) + (/ (- (* (-> src vector 1 x) (-> src vector 2 y)) (* (-> src vector 1 y) (-> src vector 2 x))) f0-0) + ) + (set! (-> dst vector 0 y) + (/ (- (* (-> src vector 2 y) (-> src vector 0 z)) (* (-> src vector 2 z) (-> src vector 0 y))) f0-0) + ) + (set! (-> dst vector 1 y) + (/ (- (* (-> src vector 2 z) (-> src vector 0 x)) (* (-> src vector 2 x) (-> src vector 0 z))) f0-0) + ) + (set! (-> dst vector 2 y) + (/ (- (* (-> src vector 2 x) (-> src vector 0 y)) (* (-> src vector 2 y) (-> src vector 0 x))) f0-0) + ) + (set! (-> dst vector 0 z) + (/ (- (* (-> src vector 0 y) (-> src vector 1 z)) (* (-> src vector 0 z) (-> src vector 1 y))) f0-0) + ) + (set! (-> dst vector 1 z) + (/ (- (* (-> src vector 0 z) (-> src vector 1 x)) (* (-> src vector 0 x) (-> src vector 1 z))) f0-0) + ) + (set! (-> dst vector 2 z) + (/ (- (* (-> src vector 0 x) (-> src vector 1 y)) (* (-> src vector 0 y) (-> src vector 1 x))) f0-0) + ) ) dst ) @@ -1263,81 +1154,33 @@ "Invert and transpose. Requires dst != src." (let ((f0-0 (matrix-3x3-determinant src))) - (set! - (-> dst data 0) - (/ - (- - (* (-> src data 5) (-> src data 10)) - (* (-> src data 6) (-> src data 9)) - ) - f0-0 - ) - ) - (set! - (-> dst data 1) - (/ - (- - (* (-> src data 6) (-> src data 8)) - (* (-> src data 4) (-> src data 10)) - ) - f0-0 - ) - ) - (set! - (-> dst data 2) - (/ - (- (* (-> src data 4) (-> src data 9)) (* (-> src data 5) (-> src data 8))) - f0-0 - ) - ) - (set! - (-> dst data 4) - (/ - (- - (* (-> src data 9) (-> src data 2)) - (* (-> src data 10) (-> src data 1)) - ) - f0-0 - ) - ) - (set! - (-> dst data 5) - (/ - (- - (* (-> src data 10) (-> src data 0)) - (* (-> src data 8) (-> src data 2)) - ) - f0-0 - ) - ) - (set! - (-> dst data 6) - (/ - (- (* (-> src data 8) (-> src data 1)) (* (-> src data 9) (-> src data 0))) - f0-0 - ) - ) - (set! - (-> dst data 8) - (/ - (- (* (-> src data 1) (-> src data 6)) (* (-> src data 2) (-> src data 5))) - f0-0 - ) - ) - (set! - (-> dst data 9) - (/ - (- (* (-> src data 2) (-> src data 4)) (* (-> src data 0) (-> src data 6))) - f0-0 - ) - ) - (set! - (-> dst data 10) - (/ - (- (* (-> src data 0) (-> src data 5)) (* (-> src data 1) (-> src data 4))) - f0-0 - ) - ) + (set! (-> dst vector 0 x) + (/ (- (* (-> src vector 1 y) (-> src vector 2 z)) (* (-> src vector 1 z) (-> src vector 2 y))) f0-0) + ) + (set! (-> dst vector 0 y) + (/ (- (* (-> src vector 1 z) (-> src vector 2 x)) (* (-> src vector 1 x) (-> src vector 2 z))) f0-0) + ) + (set! (-> dst vector 0 z) + (/ (- (* (-> src vector 1 x) (-> src vector 2 y)) (* (-> src vector 1 y) (-> src vector 2 x))) f0-0) + ) + (set! (-> dst vector 1 x) + (/ (- (* (-> src vector 2 y) (-> src vector 0 z)) (* (-> src vector 2 z) (-> src vector 0 y))) f0-0) + ) + (set! (-> dst vector 1 y) + (/ (- (* (-> src vector 2 z) (-> src vector 0 x)) (* (-> src vector 2 x) (-> src vector 0 z))) f0-0) + ) + (set! (-> dst vector 1 z) + (/ (- (* (-> src vector 2 x) (-> src vector 0 y)) (* (-> src vector 2 y) (-> src vector 0 x))) f0-0) + ) + (set! (-> dst vector 2 x) + (/ (- (* (-> src vector 0 y) (-> src vector 1 z)) (* (-> src vector 0 z) (-> src vector 1 y))) f0-0) + ) + (set! (-> dst vector 2 y) + (/ (- (* (-> src vector 0 z) (-> src vector 1 x)) (* (-> src vector 0 x) (-> src vector 1 z))) f0-0) + ) + (set! (-> dst vector 2 z) + (/ (- (* (-> src vector 0 x) (-> src vector 1 y)) (* (-> src vector 0 y) (-> src vector 1 x))) f0-0) + ) ) dst ) diff --git a/goal_src/engine/math/quaternion-h.gc b/goal_src/engine/math/quaternion-h.gc index f74cdd729b..1bacda3157 100644 --- a/goal_src/engine/math/quaternion-h.gc +++ b/goal_src/engine/math/quaternion-h.gc @@ -5,6 +5,9 @@ ;; name in dgo: quaternion-h ;; dgos: GAME, ENGINE +;; general quaternion type used to represent an orientation in a way that's compact (4 floats), +;; avoids singularities of euler angles, and reasonably efficient to transform. +;; the w component is stored last. (deftype quaternion (structure) ((x float :offset-assert 0) (y float :offset-assert 4) diff --git a/goal_src/engine/math/quaternion.gc b/goal_src/engine/math/quaternion.gc index e6313a65e4..f4eecf81b5 100644 --- a/goal_src/engine/math/quaternion.gc +++ b/goal_src/engine/math/quaternion.gc @@ -447,156 +447,80 @@ ) (defun matrix->quaternion ((arg0 quaternion) (arg1 matrix)) - (let ((f0-2 (+ (+ (-> arg1 data 0) (-> arg1 data 5)) (-> arg1 data 10)))) - (if (< 0.0 f0-2) - (let ((f0-4 (sqrtf (+ 1.0 f0-2)))) - (set! (-> arg0 w) (* 0.5 f0-4)) - (let ((f0-5 (/ 0.5 f0-4))) - (set! (-> arg0 x) (* f0-5 (- (-> arg1 data 6) (-> arg1 data 9)))) - (set! (-> arg0 y) (* f0-5 (- (-> arg1 data 8) (-> arg1 data 2)))) - (let ((f0-6 (* f0-5 (- (-> arg1 data 1) (-> arg1 data 4))))) - (set! (-> arg0 z) f0-6) - (let ((v1-0 f0-6)) - ) - ) - ) - ) + "Convert a rotation matrix to a quaternion." + (let ((f0-2 (+ (-> arg1 vector 0 x) (-> arg1 vector 1 y) (-> arg1 vector 2 z)))) + (cond + ((< 0.0 f0-2) + (let ((f0-4 (sqrtf (+ 1.0 f0-2)))) + (set! (-> arg0 w) (* 0.5 f0-4)) + (let ((f0-5 (/ 0.5 f0-4))) + (set! (-> arg0 x) (* f0-5 (- (-> arg1 vector 1 z) (-> arg1 vector 2 y)))) + (set! (-> arg0 y) (* f0-5 (- (-> arg1 vector 2 x) (-> arg1 vector 0 z)))) + (set! (-> arg0 z) (* f0-5 (- (-> arg1 vector 0 y) (-> arg1 vector 1 x)))) + ) + ) + ) + (else (let ((a2-0 0) (a3-0 1) (v1-1 2) ) - (when (< (-> arg1 data 0) (-> arg1 data 5)) + (when (< (-> arg1 vector 0 x) (-> arg1 vector 1 y)) (set! a2-0 1) (set! a3-0 2) (set! v1-1 0) - (let ((t0-1 v1-1)) - ) ) - (when - (< - (-> - (the-as - (pointer float) - (+ (+ (shl a2-0 2) (shl a2-0 4)) (the-as int arg1)) - ) - ) - (-> arg1 data 10) - ) + (when (< (-> (the-as (pointer float) (+ (+ (* a2-0 4) (* a2-0 16)) (the-as int arg1)))) (-> arg1 vector 2 z)) (set! a2-0 2) (set! a3-0 0) (set! v1-1 1) - (let ((t0-6 v1-1)) - ) ) - (let - ((f0-12 - (sqrtf - (+ - (- - 1.0 - (+ - (-> - (the-as - (pointer float) - (+ (+ (shl a3-0 2) (shl a3-0 4)) (the-as int arg1)) - ) - ) - (-> - (the-as - (pointer float) - (+ (+ (shl v1-1 2) (shl v1-1 4)) (the-as int arg1)) - ) - ) + (let ((f0-12 + (sqrtf + (+ (- 1.0 + (+ (-> (the-as (pointer float) (+ (+ (* a3-0 4) (* a3-0 16)) (the-as int arg1)))) + (-> (the-as (pointer float) (+ (+ (* v1-1 4) (* v1-1 16)) (the-as int arg1)))) + ) + ) + (-> (the-as (pointer float) (+ (+ (* a2-0 4) (* a2-0 16)) (the-as int arg1)))) + ) ) - ) - (-> - (the-as - (pointer float) - (+ (+ (shl a2-0 2) (shl a2-0 4)) (the-as int arg1)) - ) - ) ) - ) - ) - ) + ) (set! (-> arg0 data a2-0) (* 0.5 f0-12)) - (when (!= f0-12 0.0) - (set! f0-12 (/ 0.5 f0-12)) - (let ((t0-19 f0-12)) + (if (!= f0-12 0.0) + (set! f0-12 (/ 0.5 f0-12)) ) - ) - (set! - (-> arg0 w) - (* - (- - (-> - (the-as - (pointer float) - (+ (+ (shl v1-1 2) (shl a3-0 4)) (the-as int arg1)) - ) - ) - (-> - (the-as - (pointer float) - (+ (+ (shl a3-0 2) (shl v1-1 4)) (the-as int arg1)) - ) - ) - ) - f0-12 - ) - ) - (set! - (-> arg0 data a3-0) - (* - (+ - (-> - (the-as - (pointer float) - (+ (+ (shl a3-0 2) (shl a2-0 4)) (the-as int arg1)) - ) - ) - (-> - (the-as - (pointer float) - (+ (+ (shl a2-0 2) (shl a3-0 4)) (the-as int arg1)) - ) - ) - ) - f0-12 - ) - ) - (let - ((f0-13 - (* - (+ - (-> - (the-as - (pointer float) - (+ (+ (shl v1-1 2) (shl a2-0 4)) (the-as int arg1)) - ) + (set! (-> arg0 w) + (* (- (-> (the-as (pointer float) (+ (+ (* v1-1 4) (* a3-0 16)) (the-as int arg1)))) + (-> (the-as (pointer float) (+ (+ (* a3-0 4) (* v1-1 16)) (the-as int arg1)))) + ) + f0-12 ) - (-> - (the-as - (pointer float) - (+ (+ (shl a2-0 2) (shl v1-1 4)) (the-as int arg1)) - ) + ) + (set! (-> arg0 data a3-0) + (* (+ (-> (the-as (pointer float) (+ (+ (* a3-0 4) (* a2-0 16)) (the-as int arg1)))) + (-> (the-as (pointer float) (+ (+ (* a2-0 4) (* a3-0 16)) (the-as int arg1)))) + ) + f0-12 ) - ) - f0-12 - ) - ) - ) - (set! (-> arg0 data v1-1) f0-13) - (let ((v1-4 f0-13)) - ) - ) + ) + (set! (-> arg0 data v1-1) + (* (+ (-> (the-as (pointer float) (+ (+ (* v1-1 4) (* a2-0 16)) (the-as int arg1)))) + (-> (the-as (pointer float) (+ (+ (* a2-0 4) (* v1-1 16)) (the-as int arg1)))) + ) + f0-12 + ) + ) ) ) ) + ) ) arg0 ) + (defun matrix-with-scale->quaternion ((arg0 quaternion) (arg1 matrix)) "Convert a matrix with a rotation and scale into a quaternion (just the rotation)" (rlet ((vf1 :class vf) @@ -686,6 +610,7 @@ ) (defun quaternion-exp! ((arg0 quaternion) (arg1 quaternion)) + "Quaternion exponentiation. Unused" (let ((f30-0 (vector-length (the-as vector arg1)))) (cond ((= f30-0 0.0) @@ -827,6 +752,7 @@ ) (defun quaternion-zxy! ((arg0 quaternion) (arg1 vector)) + "Make a quaternion from a sequence of z, x, y axis rotations." (rlet ((acc :class vf) (vf0 :class vf) (vf1 :class vf) @@ -893,7 +819,7 @@ ) (defun quaternion-y-angle ((arg0 quaternion)) - "Not 100% sure, but get the y rotation angle?" + "Get the y rotation angle. Not very efficient" (let ((v1-1 (vector-z-quaternion! (new 'stack-no-clear 'vector) arg0))) (atan (-> v1-1 data 0) (-> v1-1 data 2)) ) @@ -988,6 +914,7 @@ ) (defun quaternion-delta-y ((arg0 quaternion) (arg1 quaternion)) + "Difference in yaw between two quaternions" (acos (vector-dot (vector-z-quaternion! (new 'stack-no-clear 'vector) arg0) (vector-z-quaternion! (new 'stack-no-clear 'vector) arg1) ) @@ -995,6 +922,7 @@ ) (defun quaternion-rotate-y-to-vector! ((arg0 quaternion) (arg1 quaternion) (arg2 quaternion) (arg3 float)) + "Rotate along y so z-axis points to match another. Use arg3 as the max rotation amount." (let ((s5-0 (new 'stack-no-clear 'quaternion))) (let ((t9-0 vector-xz-normalize!) (a0-1 (new 'stack-no-clear 'vector)) @@ -1018,6 +946,7 @@ (defun vector-rotate-y! ((arg0 vector) (arg1 vector) (arg2 float)) + "Rotate vector along y axis. Not very efficient." (let ((a1-2 (quaternion-vector-angle! (new 'stack-no-clear 'quaternion) (new 'static 'vector :y 1.0 :w 1.0) @@ -1031,15 +960,22 @@ ) ) + +;; note that these kind of assume a rotation ordering where you can yaw as much as you want, +;; but if you pitch 180 degrees everything is bad. + (defun vector-y-angle ((arg0 vector)) + "Get the yaw angle of a vector." (atan (-> arg0 data 0) (-> arg0 data 2)) ) (defun vector-x-angle ((arg0 vector)) + "Get the pitch angle of a vector." (atan (-> arg0 data 1) (vector-xz-length arg0)) ) (defun quaterion<-rotate-y-vector ((arg0 quaternion) (arg1 vector)) + "Create a quaternion representing only the yaw of the given vector" (quaternion-vector-angle! arg0 (new 'static 'vector :y 1.0 :w 1.0) @@ -1048,6 +984,7 @@ ) (defun quaternion-xz-angle ((arg0 quaternion)) + "yet another function to compute the yaw of a quaternion. This is a particularly inefficient version." (let ((gp-0 (new 'stack-no-clear 'matrix)) (s5-0 (new 'stack-no-clear 'vector)) ) @@ -1059,6 +996,7 @@ ) (defun-debug quaternion-validate ((arg0 quaternion)) + "Verify that a quaternion is valid, print an error if not." (with-pp (let ((f0-0 (quaternion-norm arg0))) (when (or (< 1.01 f0-0) (< f0-0 0.99)) diff --git a/goal_src/engine/math/transform-h.gc b/goal_src/engine/math/transform-h.gc index 5205f6600b..13fd0b4e0b 100644 --- a/goal_src/engine/math/transform-h.gc +++ b/goal_src/engine/math/transform-h.gc @@ -6,6 +6,8 @@ ;; dgos: GAME, ENGINE ;; Transformation. w components of vectors should be 1.0 +;; This can represent any rotation, translation, and scaling. +;; Note that the scaling is applied before rotation (meaning it scales along the axes of the pre-transformed frame). (deftype transform (structure) ((trans vector :inline :offset-assert 0) ;; translation (rot vector :inline :offset-assert 16) ;; rotation (rotation vector) @@ -18,6 +20,7 @@ ;; Like transform, but it's a basic. +;; some in-game objects have trs as their parent type to represent their location in the game world. (deftype trs (basic) ((trans vector :inline :offset-assert 16) (rot vector :inline :offset-assert 32) diff --git a/goal_src/engine/math/transform.gc b/goal_src/engine/math/transform.gc index edca1890b1..cfedc47f64 100644 --- a/goal_src/engine/math/transform.gc +++ b/goal_src/engine/math/transform.gc @@ -5,6 +5,8 @@ ;; name in dgo: transform ;; dgos: GAME, ENGINE +;; note: transformq and trsq is mostly used instead of transform. + (defmethod print transform ((obj transform)) (format #t "# obj trans))) ) (defmethod relative-y-angle-to-point trsqv ((obj trsqv) (arg0 vector)) - "Get the y angle between here and arg0, starting at whatever angle we're currently at." + "Get the y angle between the current orientation and arg0." (deg-diff (y-angle obj) (vector-y-angle (vector-! (new 'stack-no-clear 'vector) arg0 (-> obj trans))) diff --git a/goal_src/engine/math/vector-h.gc b/goal_src/engine/math/vector-h.gc index d9afb1e3ec..d8aef8d0d1 100644 --- a/goal_src/engine/math/vector-h.gc +++ b/goal_src/engine/math/vector-h.gc @@ -293,7 +293,7 @@ ;; vector types (floating point) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Vector of 4 floats. Shortened to "vector" because it is commonly used. +;; Vector of 4 floats. Shortened to "vector" because it is the most commonly used. (deftype vector (structure) ((x float :offset 0) (y float :offset 4) @@ -331,6 +331,8 @@ (define *x-vector* (new 'static 'vector :x 1. :y 0. :z 0. :w 1.)) (define *y-vector* (new 'static 'vector :x 0. :y 1. :z 0. :w 1.)) (define *z-vector* (new 'static 'vector :x 0. :y 0. :z 1. :w 1.)) + +;; note: y is up. (define *up-vector* (new 'static 'vector :x 0. :y 1. :z 0. :w 1.)) @@ -366,6 +368,10 @@ :flag-assert #x900000010 ) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; other geometric things +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; ax + by + cz = d form (deftype plane (vector) ((a float :offset 0) @@ -405,6 +411,8 @@ `(new 'static 'sphere :x (meters ,x) :y (meters ,y) :z (meters ,z) :w (meters ,r)) ) +;; this type represents a bounding-box, stored as minimum/maximum points +;; note that the types in bounding-box are mostly used, this is used very rarely. (deftype box8s (structure) ((data float 8 :offset-assert 0) (quad uint128 2 :offset 0) @@ -424,10 +432,9 @@ :size-assert #x10 :flag-assert #x900000010 ) - (set! (-> box8s-array heap-base) 32) -;; This is really a capsule - a cylinder with spheres at both end +;; This is really a capsule - a cylinder with spheres at both ends (deftype cylinder (structure) ((origin vector :inline :offset-assert 0) (axis vector :inline :offset-assert 16) @@ -459,6 +466,7 @@ ) ) +;; these vertical plane types are basically unused (deftype vertical-planes (structure) ((data uint128 4 :offset-assert 0) ;; probably wrong ) @@ -476,6 +484,8 @@ :flag-assert #x900000010 ) +;; common 16-byte "quadword" structure. +;; allows access to unsigned arrays of integers of all sizes and floats (deftype qword (structure) ((data uint32 4 :offset-assert 0) (byte uint8 16 :offset 0) @@ -491,6 +501,7 @@ :flag-assert #x900000010 ) +;; 12-byte vector with only 3 components. It's not used very much. (deftype vector3s (structure) ((data float 3 :offset-assert 0) (x float :offset 0) diff --git a/goal_src/engine/ps2/vif-h.gc b/goal_src/engine/ps2/vif-h.gc index 8c4310c61d..bcb4885316 100644 --- a/goal_src/engine/ps2/vif-h.gc +++ b/goal_src/engine/ps2/vif-h.gc @@ -8,6 +8,9 @@ ;; Types related to VIF: the PS2's Vector Interface. ;; Each of VU0 and VU1 has a VIF which is used to sent/receive data. ;; The VIFs are controller by registers and fed data using DMA +;; the vif registers defined here are used extremely rarely, usually they are sent DMA +;; (during gameplay, everything is synchronized by DMA, so code generally does not know when +;; it is safe to mess with VIF registers.) ;;VIF0_STAT or VIF1_STAT bitfields (deftype vif-stat (uint32) diff --git a/goal_src/engine/sound/gsound-h.gc b/goal_src/engine/sound/gsound-h.gc index f24fd499d6..188b096a46 100644 --- a/goal_src/engine/sound/gsound-h.gc +++ b/goal_src/engine/sound/gsound-h.gc @@ -438,8 +438,10 @@ :flag-assert #x90000004c ) +;; each sound command gets a unique ID. (define *current-sound-id* (the sound-id #x10000)) +;; a in-game background sound. (deftype ambient-sound (basic) ((spec sound-spec :offset-assert 4) (playing-id sound-id :offset-assert 8) @@ -471,6 +473,8 @@ ) ) +;; currently loaded sound effect banks. +;; there is an always-loaded common bank and two level-specific banks. (define *sound-bank-1* #f) (define *sound-bank-2* #f) diff --git a/goal_src/engine/ui/text-h.gc b/goal_src/engine/ui/text-h.gc index e57b17cb0d..fe765c03f8 100644 --- a/goal_src/engine/ui/text-h.gc +++ b/goal_src/engine/ui/text-h.gc @@ -8,6 +8,8 @@ ;; This file contains types related to game text. ;; Each game string is assigned an ID number. ;; This ID is used to lookup the string for the currently selected language. +;; These ID's are shared with short spoken audio clips (daxter hints) +;; most (all?) of the daxter clips don't have text strings. ;; GAME-TEXT-ID ENUM BEGINS (defenum game-text-id @@ -482,6 +484,8 @@ ) ) +;; all text is stored in the COMMON text files (one file per language). +;; in theory, you could have multiple text files that are only loaded when needed, but they didn't do this. (define *text-group-names* (new 'static 'boxed-array :type string :length 1 "common")) ;; The heap for storing text