From b2052016e2b5a21eed4c8c68343ce9f558e7f82d Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sun, 10 Oct 2021 20:07:03 -0400 Subject: [PATCH] [decomp] sky/time of day (#883) * time of day * goal code seems to work * stars at wrong spot * stars and sun work * debugging clouds * fix texture correction * sky works * cleanup, add profiler * clean up * final clean up * offline tests * missing include --- common/math/Vector.h | 7 + common/util/BitUtils.h | 10 + common/util/colors.h | 25 + decompiler/IR2/FormExpressionAnalysis.cpp | 13 + decompiler/analysis/mips2c.cpp | 20 +- decompiler/config/all-types.gc | 111 +- .../anonymous_function_types.jsonc | 4 +- .../config/jak1_ntsc_black_label/hacks.jsonc | 10 +- .../jak1_ntsc_black_label/label_types.jsonc | 15 + .../stack_structures.jsonc | 15 +- .../jak1_ntsc_black_label/type_casts.jsonc | 93 +- decompiler/util/data_decompile.cpp | 6 + game/CMakeLists.txt | 4 + game/graphics/dma/gs.cpp | 4 + game/graphics/dma/gs.h | 19 +- game/graphics/opengl_renderer/AdgifHandler.h | 45 + .../opengl_renderer/BucketRenderer.cpp | 4 +- .../graphics/opengl_renderer/BucketRenderer.h | 9 +- .../opengl_renderer/DirectRenderer.cpp | 233 ++- .../graphics/opengl_renderer/DirectRenderer.h | 70 +- .../opengl_renderer/OpenGLRenderer.cpp | 78 +- .../graphics/opengl_renderer/OpenGLRenderer.h | 23 +- game/graphics/opengl_renderer/Profiler.cpp | 145 ++ game/graphics/opengl_renderer/Profiler.h | 83 + game/graphics/opengl_renderer/Shader.cpp | 2 + game/graphics/opengl_renderer/Shader.h | 2 + game/graphics/opengl_renderer/SkyRenderer.cpp | 370 +++++ game/graphics/opengl_renderer/SkyRenderer.h | 57 + .../opengl_renderer/SpriteRenderer.cpp | 454 +++++- .../graphics/opengl_renderer/SpriteRenderer.h | 25 +- .../opengl_renderer/TextureUploadHandler.cpp | 4 +- .../opengl_renderer/TextureUploadHandler.h | 2 +- game/graphics/opengl_renderer/debug_gui.cpp | 6 +- game/graphics/opengl_renderer/debug_gui.h | 13 + .../shaders/direct_basic_textured.frag | 3 +- .../shaders/direct_basic_textured.vert | 4 +- .../shaders/direct_basic_textured_tcc0.frag | 6 +- .../shaders/direct_basic_textured_tcc0.vert | 6 +- .../graphics/opengl_renderer/shaders/sky.frag | 13 + .../graphics/opengl_renderer/shaders/sky.vert | 14 + .../opengl_renderer/shaders/sky_blend.frag | 11 + .../opengl_renderer/shaders/sky_blend.vert | 10 + game/graphics/pipelines/opengl.cpp | 51 +- game/graphics/texture/TexturePool.cpp | 35 +- game/graphics/texture/TexturePool.h | 5 +- game/kernel/kdgo.cpp | 3 +- game/kernel/kscheme.cpp | 3 + game/mips2c/functions/sky_tng.cpp | 1112 ++++++++++++++ game/mips2c/functions/texture.cpp | 163 ++ game/mips2c/mips2c_private.h | 46 + game/mips2c/mips2c_table.cpp | 44 +- goal_src/engine/debug/default-menu.gc | 2 +- goal_src/engine/dma/dma-buffer.gc | 4 + goal_src/engine/dma/dma-h.gc | 2 + goal_src/engine/draw/drawable.gc | 14 +- goal_src/engine/gfx/hw/gs.gc | 2 +- goal_src/engine/gfx/sky/sky-h.gc | 16 +- goal_src/engine/gfx/sky/sky-tng.gc | 1329 +++++++++++++++++ goal_src/engine/gfx/sky/sky.gc | 135 ++ goal_src/engine/gfx/sprite/sprite.gc | 27 +- goal_src/engine/gfx/texture.gc | 1 + goal_src/engine/gfx/time-of-day-h.gc | 6 +- goal_src/engine/gfx/time-of-day.gc | 669 ++++++++- goal_src/engine/level/level-h.gc | 2 +- goal_src/engine/level/level.gc | 5 +- goal_src/engine/math/vector-h.gc | 12 +- .../engine/sparticle/sparticle-launcher.gc | 3 +- goal_src/engine/sparticle/sparticle.gc | 1 - goal_src/engine/target/target-util.gc | 6 + goal_src/examples/debug-draw-example.gc | 10 +- goal_src/kernel/gkernel-h.gc | 9 + goal_src/levels/maincave/cavecrystal-light.gc | 2 +- goal_src/levels/sunken/sunken-water.gc | 2 +- goalc/compiler/Env.cpp | 3 + goalc/compiler/compilation/Type.cpp | 2 +- goalc/debugger/Debugger.cpp | 12 + goalc/debugger/Debugger.h | 1 + .../reference/engine/ambient/mood_REF.gc | 6 +- .../reference/engine/dma/dma-buffer_REF.gc | 2 + .../reference/engine/gfx/hw/gs_REF.gc | 4 +- .../reference/engine/gfx/sky/sky-h_REF.gc | 30 +- .../reference/engine/gfx/texture_REF.gc | 138 +- .../engine/gfx/tfrag/subdivide_REF.gc | 2 +- .../reference/engine/gfx/time-of-day-h_REF.gc | 44 +- .../reference/engine/level/level-h_REF.gc | 82 +- .../levels/maincave/cavecrystal-light_REF.gc | 6 +- .../levels/sunken/sunken-water_REF.gc | 2 +- test/offline/offline_test_main.cpp | 2 + 88 files changed, 5577 insertions(+), 528 deletions(-) create mode 100644 common/util/colors.h create mode 100644 game/graphics/opengl_renderer/AdgifHandler.h create mode 100644 game/graphics/opengl_renderer/Profiler.cpp create mode 100644 game/graphics/opengl_renderer/Profiler.h create mode 100644 game/graphics/opengl_renderer/SkyRenderer.cpp create mode 100644 game/graphics/opengl_renderer/SkyRenderer.h create mode 100644 game/graphics/opengl_renderer/shaders/sky.frag create mode 100644 game/graphics/opengl_renderer/shaders/sky.vert create mode 100644 game/graphics/opengl_renderer/shaders/sky_blend.frag create mode 100644 game/graphics/opengl_renderer/shaders/sky_blend.vert create mode 100644 game/mips2c/functions/sky_tng.cpp create mode 100644 game/mips2c/functions/texture.cpp diff --git a/common/math/Vector.h b/common/math/Vector.h index c5c11497f..f8ebca13b 100644 --- a/common/math/Vector.h +++ b/common/math/Vector.h @@ -136,6 +136,13 @@ class Vector { return *this; } + Vector& operator/=(const T& val) { + for (int i = 0; i < Size; i++) { + m_data[i] /= val; + } + return *this; + } + Vector cross(const Vector& other) const { static_assert(Size == 3, "Size for cross"); Vector result = {y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(), diff --git a/common/util/BitUtils.h b/common/util/BitUtils.h index a85062588..4d493143a 100644 --- a/common/util/BitUtils.h +++ b/common/util/BitUtils.h @@ -83,4 +83,14 @@ T align4(T in) { template T align64(T in) { return (in + 63) & (~T(63)); +} + +inline u32 count_leading_zeros_u32(u32 in) { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_clz(in); +#else + unsigned long result; + _BitScanReverse(&result, in); + return result; +#endif } \ No newline at end of file diff --git a/common/util/colors.h b/common/util/colors.h new file mode 100644 index 000000000..96249ec15 --- /dev/null +++ b/common/util/colors.h @@ -0,0 +1,25 @@ +#pragma once + +#include "common/common_types.h" + +namespace colors { +// some reasonable colors that are different from each other +constexpr int COLOR_COUNT = 131; +u32 common_colors[COLOR_COUNT] = { + 0xF0F8FE, 0xFAEBD7, 0x00FFFF, 0x70DB93, 0xF0FFFF, 0xF5F5DC, 0x000000, 0x0000FF, 0x9F5F9F, + 0xB5A642, 0xD9D919, 0x8C7853, 0xA52A2A, 0x5F9EA0, 0xD2691E, 0xB87333, 0xFF7F50, 0xDC143C, + 0x00FFFF, 0x00008B, 0x5C4033, 0x008B8B, 0xB8860B, 0xA9A9A9, 0x006400, 0xBDB76B, 0x8B008B, + 0x4F4F2F, 0xFF8C00, 0x9932CD, 0x871F78, 0xE9967A, 0x6B238E, 0x2F4F4F, 0x97694F, 0x7093DB, + 0x9400D3, 0x855E42, 0x545454, 0x856363, 0xD19275, 0xB22222, 0x238E23, 0xCD7F32, 0xDBDB70, + 0xC0C0C0, 0x00FF00, 0x527F76, 0x93DB70, 0xFF69B4, 0x215E21, 0xCD5C5C, 0x4B0082, 0xFFFFF0, + 0x9F9F5F, 0xE6E6FA, 0xC0D9D9, 0xF08080, 0xE0FFFF, 0xA8A8A8, 0x90EE90, 0xFFB6C1, 0x8F8FBD, + 0xE9C2A6, 0x00FF00, 0x32CD32, 0xFF00FF, 0xE47833, 0x8E236B, 0x32CD99, 0x3232CD, 0x6B8E23, + 0xEAEAAE, 0x9370DB, 0x426F42, 0x7F00FF, 0x7FFF00, 0x70DBDB, 0xDB7093, 0xA68064, 0x2F2F4F, + 0xF5FFFA, 0xFFE4E1, 0x23238E, 0x4D4DFF, 0xFF6EC7, 0x00009C, 0xEBC79E, 0xCFB53B, 0x808000, + 0xFF7F00, 0xFF2400, 0xDB70DB, 0xEEE8AA, 0x8FBC8F, 0xAFEEEE, 0xBC8F8F, 0xEAADEA, 0xB0E0E6, + 0x800080, 0xD9D9F3, 0xFF0000, 0x5959AB, 0x4169E1, 0x8B4513, 0x6F4242, 0xF4A460, 0x8C1717, + 0x238E68, 0x8E6B23, 0xE6E8FA, 0x3299CC, 0x007FFF, 0xFFFAFA, 0xFF1CAE, 0x00FF7F, 0x236B8E, + 0x38B0DE, 0xDB9370, 0x008080, 0xD8BFD8, 0xFF6347, 0xADEAEA, 0x5C4033, 0x5C4033, 0x422F4F, + 0xCC3299, 0xD8D8BF, 0xFFFFFF, 0xFFFF00, 0x99CC32, +}; +} // namespace colors diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index df66bf770..2ba97c650 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -2307,6 +2307,19 @@ void StoreInSymbolElement::push_to_stack(const Env& env, FormPool& pool, FormSta auto val = pool.alloc_single_element_form(nullptr, m_value, m_my_idx); val->update_children_from_stack(env, pool, stack, true); + if (m_cast_for_set) { + // we'd need to cast for set. Let's see if we can simplify it instead: + auto simplified = try_cast_simplify(val, *m_cast_for_set, pool, env, false); + if (simplified) { + if (m_cast_for_define && *m_cast_for_define == *m_cast_for_set) { + // if we'd need exactly the same cast for a define, we can drop it too + m_cast_for_define = {}; + } + m_cast_for_set = {}; + val = simplified; + } + } + auto elt = pool.alloc_element(sym, val, m_cast_for_set, m_cast_for_define); elt->mark_popped(); stack.push_form_element(elt, true); diff --git a/decompiler/analysis/mips2c.cpp b/decompiler/analysis/mips2c.cpp index 97a6936e0..6e4cc2ed7 100644 --- a/decompiler/analysis/mips2c.cpp +++ b/decompiler/analysis/mips2c.cpp @@ -632,6 +632,12 @@ Mips2C_Line handle_generic_op2(const Instruction& i0, instr_str}; } +Mips2C_Line handle_plain_op(const Instruction& /*i0*/, + const std::string& instr_str, + const std::string& op_name) { + return {fmt::format("c->{}();", op_name), instr_str}; +} + Mips2C_Line handle_or(const Instruction& i0, const std::string& instr_str) { if (is_gpr_3(i0, InstructionKind::OR, {}, rs7(), rr0())) { // set reg_dest to #f : or reg_dest, s7, r0 @@ -648,7 +654,7 @@ Mips2C_Line handle_or(const Instruction& i0, const std::string& instr_str) { instr_str}; } else { // actually do a logical OR of two registers: or a0, a1, a2 - return handle_unknown(instr_str); + return handle_generic_op3(i0, instr_str, "_or"); } } @@ -704,6 +710,8 @@ Mips2C_Line handle_non_likely_branch_bc(const Instruction& i0, const std::string return {fmt::format("bc = ((s64){}) <= 0;", reg64_or_zero(i0.get_src(0))), instr_str}; case InstructionKind::BC1F: return {fmt::format("bc = !cop1_bc;"), instr_str}; + case InstructionKind::BC1T: + return {fmt::format("bc = cop1_bc;"), instr_str}; default: return handle_unknown(instr_str); } @@ -849,9 +857,13 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output, case InstructionKind::MULT3: case InstructionKind::PMINW: case InstructionKind::PMAXW: + case InstructionKind::SUBU: + case InstructionKind::DSRAV: return handle_generic_op3(i0, instr_str, {}); case InstructionKind::MULS: return handle_generic_op3(i0, instr_str, "muls"); + case InstructionKind::DIVS: + return handle_generic_op3(i0, instr_str, "divs"); case InstructionKind::ADDS: return handle_generic_op3(i0, instr_str, "adds"); case InstructionKind::SUBS: @@ -893,6 +905,8 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output, return handle_generic_op2(i0, instr_str, "mfc1"); case InstructionKind::MTC1: return handle_generic_op2(i0, instr_str, "mtc1"); + case InstructionKind::NEGS: + return handle_generic_op2(i0, instr_str, "negs"); case InstructionKind::CVTWS: return handle_generic_op2(i0, instr_str, "cvtws"); case InstructionKind::CVTSW: @@ -901,11 +915,15 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output, return handle_generic_op2(i0, instr_str, "pexew"); case InstructionKind::SQRTS: return handle_generic_op2(i0, instr_str, "sqrts"); + case InstructionKind::PLZCW: + return handle_generic_op2(i0, instr_str, "plzcw"); case InstructionKind::LUI: return handle_lui(i0, instr_str); case InstructionKind::CLTS: output.needs_cop1_bc = true; return handle_clts(i0, instr_str); + case InstructionKind::VWAITQ: + return handle_plain_op(i0, instr_str, "vwaitq"); default: unknown_count++; return handle_unknown(instr_str); diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 50480a6df..4da1fc42a 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -518,8 +518,10 @@ (generic-foreground 30) ;; ? (alpha-tex0 31) + (sky-tex0 32) (alpha-tex1 38) + (sky-tex1 39) (bucket-45 45) (bucket-46 46) @@ -3545,6 +3547,8 @@ (deftype dma-gif-packet (structure) ((dma-vif dma-packet :inline :offset-assert 0) (gif uint64 2 :offset-assert 16) ;; guess + (gif0 uint64 :offset 16) + (gif1 uint64 :offset 24) (quad uint128 2 :offset 0) ) :method-count-assert 9 @@ -4338,7 +4342,7 @@ ;; - Symbols -(define-extern *fog-color* int) +(define-extern *fog-color* rgba) (define-extern *default-regs-buffer* dma-buffer) @@ -5050,7 +5054,7 @@ (display? symbol :offset-assert 376) (meta-inside? symbol :offset-assert 380) (mood mood-context :offset-assert 384) - (mood-func function :offset-assert 388) + (mood-func (function mood-context float int none) :offset-assert 388) (vis-bits pointer :offset-assert 392) (all-visible? symbol :offset-assert 396) (force-all-visible? symbol :offset-assert 400) @@ -7334,9 +7338,9 @@ ) (deftype sky-tng-data (basic) - ((giftag-base qword :inline :offset-assert 16) - (giftag-roof qword :inline :offset-assert 32) - (giftag-ocean qword :inline :offset-assert 48) + ((giftag-base gs-gif-tag :inline :offset-assert 16);; changed + (giftag-roof gs-gif-tag :inline :offset-assert 32) + (giftag-ocean gs-gif-tag :inline :offset-assert 48) (fog vector :inline :offset-assert 64) (sky uint32 8 :offset-assert 80) (time float :offset-assert 112) @@ -7354,8 +7358,8 @@ ((adgif-tmpl dma-gif-packet :inline :offset-assert 0) (draw-tmpl dma-gif-packet :inline :offset-assert 32) (blend-tmpl dma-gif-packet :inline :offset-assert 64) - (sky-data uint128 5 :offset-assert 96) - (cloud-data uint128 5 :offset-assert 176) + (sky-data qword 5 :inline :offset-assert 96) + (cloud-data qword 5 :inline :offset-assert 176) ) :method-count-assert 9 :size-assert #x100 @@ -7502,7 +7506,7 @@ :flag-assert #xb00000110 (:methods (reset! (_type_) symbol 9) - (TODO-RENAME-10 (_type_ int float float vector) object 10) ; returns float or error string + (set-fade! (_type_ int float float vector) object 10) ; returns float or error string ) ) @@ -7549,7 +7553,7 @@ ((active-count uint32 :offset-assert 4) (interp float :offset-assert 8) (current-interp float :offset-assert 12) - (moods uint64 2 :offset-assert 16) + (moods mood-context 2 :offset-assert 16) (current-fog mood-fog :inline :offset-assert 32) (current-sun mood-sun :inline :offset-assert 80) (current-prt-color vector :inline :offset-assert 112) @@ -7559,7 +7563,7 @@ (title-light-group light-group :inline :offset-assert 1888) (time float :offset-assert 2080) (target-interp float :offset-assert 2084) - (erase-color uint32 :offset-assert 2088) + (erase-color rgba :offset-assert 2088) (num-stars float :offset-assert 2092) (light-masks-0 uint8 2 :offset-assert 2096) (light-masks-1 uint8 2 :offset-assert 2098) @@ -17536,24 +17540,25 @@ ;; - Functions -(define-extern make-sky-textures function) -(define-extern init-time-of-day (function none)) +(define-extern make-sky-textures (function time-of-day-context int none)) +(define-extern init-time-of-day (function none :behavior time-of-day-proc)) (define-extern update-sky-tng-data (function float none)) -(define-extern time-of-day-update (function none)) -(define-extern start-time-of-day (function int)) -(define-extern time-of-day-setup (function symbol none)) +(define-extern time-of-day-update (function none :behavior time-of-day-proc)) +(define-extern start-time-of-day (function none)) +(define-extern time-of-day-setup (function symbol symbol)) (define-extern set-time-of-day (function float none)) (define-extern init-time-of-day-context (function time-of-day-context float)) (define-extern update-time-of-day (function time-of-day-context none)) ;; - Symbols -(define-extern time-of-day-tick state) +(define-extern time-of-day-tick (state time-of-day-proc)) (define-extern time-of-day-effect (function none)) ;; only 'nothing' is stored here, looks like dead code ;; - Unknowns ;;(define-extern sky-base-polygons object) ;; unknown type +(define-extern sky-base-polygons (inline-array sky-vertex)) ;; ---------------------- @@ -17580,37 +17585,37 @@ ;; - Types -; (deftype sky-frame-data (structure) -; ((data UNKNOWN 18 :offset-assert 0) -; (world-homo-matrix matrix :inline :offset-assert 0) -; (hmge-scale vector :inline :offset-assert 64) -; (hvdf-offset vector :inline :offset-assert 80) -; (consts vector :inline :offset-assert 96) -; (pfog0 float :offset-assert 96) -; (radius float :offset-assert 100) -; (nokick float :offset-assert 108) -; (strip-giftag qword :inline :offset-assert 112) -; (col-adgif qword :inline :offset-assert 128) -; (save UNKNOWN 5 :offset-assert 144) -; (sun-fan-giftag qword :inline :offset-assert 224) -; (sun-strip-giftag qword :inline :offset-assert 240) -; (sun-alpha qword :inline :offset-assert 256) -; (sun-alpha-giftag qword :inline :offset-assert 272) -; ) -; :method-count-assert 9 -; :size-assert #x120 -; :flag-assert #x900000120 -; ) +(deftype sky-frame-data (structure) + ((data uint128 18 :offset-assert 0) + (world-homo-matrix matrix :inline :offset 0) + (hmge-scale vector :inline :offset 64) + (hvdf-offset vector :inline :offset 80) + (consts vector :inline :offset 96) + (pfog0 float :offset 96) + (radius float :offset 100) + (nokick float :offset 108) + (strip-giftag qword :inline :offset 112) + (col-adgif qword :inline :offset 128) + (save uint128 5 :offset 144) + (sun-fan-giftag qword :inline :offset 224) + (sun-strip-giftag qword :inline :offset 240) + (sun-alpha qword :inline :offset 256) + (sun-alpha-giftag qword :inline :offset 272) + ) + :method-count-assert 9 + :size-assert #x120 + :flag-assert #x900000120 + ) ;; - Functions (define-extern sky-add-frame-data function) (define-extern sky-make-sun-data (function sky-parms int float none)) (define-extern sky-make-moon-data (function sky-parms float none)) -(define-extern sky-make-light function) +(define-extern sky-make-light (function sky-parms light int rgba none)) (define-extern sky-init-upload-data function) (define-extern sky-upload function) -(define-extern sky-draw function) +(define-extern sky-draw (function sky-parms none)) ;; - Unknowns @@ -17625,29 +17630,29 @@ ;; - Functions -(define-extern copy-sky-texture function) -(define-extern copy-cloud-texture function) -(define-extern init-sky-regs function) -(define-extern render-sky-tri function) -(define-extern close-sky-buffer function) -(define-extern set-tex-offset function) -(define-extern render-sky-quad function) -(define-extern sky-tng-setup-cloud-layer function) +(define-extern copy-sky-texture (function dma-buffer adgif-shader float none)) +(define-extern copy-cloud-texture (function dma-buffer adgif-shader float none)) +(define-extern init-sky-regs (function none)) +(define-extern render-sky-tri (function (inline-array sky-vertex) dma-buffer none)) +(define-extern close-sky-buffer (function dma-buffer none)) +(define-extern set-tex-offset (function int int none)) +(define-extern render-sky-quad (function int dma-buffer none)) +(define-extern sky-tng-setup-cloud-layer (function float float vector (inline-array sky-vertex) none)) (define-extern draw-large-polygon function) -(define-extern init-sky-tng-data function) +(define-extern init-sky-tng-data (function sky-tng-data none)) (define-extern clip-polygon-against-positive-hyperplane function) (define-extern clip-polygon-against-negative-hyperplane function) (define-extern sky-duplicate-polys function) -(define-extern sky-tng-setup-clouds function) +(define-extern sky-tng-setup-clouds (function none)) (define-extern render-sky-tng (function time-of-day-context none)) ;; - Unknowns -;;(define-extern *sky-work* object) ;; unknown type +(define-extern *sky-work* sky-work) ;; unknown type (define-extern *sky-tng-data* sky-tng-data) ;; unknown type -;;(define-extern sky-roof-polygons object) ;; unknown type -;;(define-extern sky-cloud-polygons object) ;; unknown type -;;(define-extern sky-cloud-polygon-indices object) ;; unknown type +(define-extern sky-roof-polygons (inline-array sky-vertex)) ;; unknown type +(define-extern sky-cloud-polygons (inline-array sky-vertex)) ;; unknown type +(define-extern sky-cloud-polygon-indices (pointer uint8)) ;; unknown type ;; ---------------------- diff --git a/decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc b/decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc index 22c6b0b27..c578a3c18 100644 --- a/decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc @@ -671,8 +671,8 @@ ], "time-of-day": [ - [10, "(function none)"], - [12, "(function sparticle-system sparticle-cpuinfo int none)"] + [10, "(function none :behavior time-of-day-proc)"], + [12, "(function sparticle-system sparticle-cpuinfo none)"] ], "basebutton": [ diff --git a/decompiler/config/jak1_ntsc_black_label/hacks.jsonc b/decompiler/config/jak1_ntsc_black_label/hacks.jsonc index 123fb0749..531211283 100644 --- a/decompiler/config/jak1_ntsc_black_label/hacks.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/hacks.jsonc @@ -547,7 +547,15 @@ "particle-adgif", "sp-launch-particles-var", "sp-process-block-2d", - "sp-process-block-3d" + "sp-process-block-3d", + "draw-large-polygon", + "clip-polygon-against-positive-hyperplane", + "clip-polygon-against-negative-hyperplane", + "render-sky-quad", + "render-sky-tri", + "init-sky-regs", + "set-tex-offset", + "adgif-shader<-texture-with-update!" ] } diff --git a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc index 6ddf2e252..aa3d72d15 100644 --- a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc @@ -799,6 +799,21 @@ ["L733", "uint64", true] ], + "sky": [ + ["L13", "vu-function"] + ], + + "sky-tng": [ + ["L82", "sky-work"], + // 576 bytes, 32 bytes each + ["L81", "(inline-array sky-vertex)", 12], + ["L80", "(inline-array sky-vertex)", 12], + ["L79", "(inline-array sky-vertex)", 72], + ["L78", "(pointer uint8)", 48], + ["L77", "vector"], + ["L76", "vector"] + ], + "effect-control": [ ["L300", "float", true], ["L301", "float", true], diff --git a/decompiler/config/jak1_ntsc_black_label/stack_structures.jsonc b/decompiler/config/jak1_ntsc_black_label/stack_structures.jsonc index fa36e34c8..9052b2024 100644 --- a/decompiler/config/jak1_ntsc_black_label/stack_structures.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/stack_structures.jsonc @@ -1201,7 +1201,8 @@ ], "update-time-of-day": [ - [16, "(array float)"] // TODO - broken! + [16, "(array float)"], // TODO - broken! + [48, "vector"] ], "check-drop-level-rain": [ @@ -2783,5 +2784,17 @@ [32, "vector"] ], + "init-sky-regs": [ + [16, "vector"] + ], + + "set-tex-offset": [ + [16, "vector"] + ], + + "sky-tng-setup-cloud-layer": [ + [16,["inline-array", "sky-vertex", 12]] + ], + "placeholder-do-not-add-below!": [] } diff --git a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc index e78d810f4..0cf753c0c 100644 --- a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc @@ -2634,23 +2634,6 @@ [[15, 250], "s5", "symbol"] ], - "time-of-day-update": [ - [[0, 999], "s6", "time-of-day-proc"] - ], - - "(anon-function 10 time-of-day)": [ - [[0, 999], "s6", "time-of-day-proc"] - ], - - "init-time-of-day": [ - [[0, 999], "s6", "time-of-day-proc"], - [[51, 54], "t9", "(function object object object)"] - ], - - "start-time-of-day": [ - [[20, 23], "t9", "(function process function object)"] - ], - "cam-master-effect": [ [[0, 999], "s6", "camera-master"] ], @@ -3934,6 +3917,82 @@ [2, "v1", "(pointer process-drawable)"] ], + "update-time-of-day": [ + [46, "v0", "(array float)"] + ], + + "sky-make-light": [ + [[10, 23], "a0", "sky-sun-data"] + ], + + "make-sky-textures": [ + [[90, 94], "a0", "dma-packet"], + [[100, 103], "a0", "gs-gif-tag"], + [108, "a0", "(pointer gs-alpha)"], + [110, "a0", "(pointer gs-reg64)"], + [[121, 124], "v1", "dma-packet"] + ], + + "copy-cloud-texture": [ + [[2, 48], "s5", "(pointer uint128)"], + [[28, 32], "s4", "adgif-shader"] + ], + + "copy-sky-texture": [ + [[2, 48], "s5", "(pointer uint128)"], + [[28, 32], "s4", "adgif-shader"] + ], + + "render-sky-tng": [ + [[244, 262], "s2", "(inline-array sky-vertex)"], + [[34, 38], "a0", "dma-packet"], + [[44, 47], "a0", "gs-gif-tag"], + [52, "a0", "(pointer gs-zbuf)"], + [54, "a0", "(pointer gs-reg64)"], + [56, "a0", "(pointer gs-test)"], + [58, "a0", "(pointer gs-reg64)"], + [60, "a0", "(pointer gs-alpha)"], + [62, "a0", "(pointer gs-reg64)"], + [[74, 78], "a0", "dma-packet"], + [[84, 87], "a0", "gs-gif-tag"], + + [107, "s2", "(pointer gs-tex0)"], + [109, "s2", "(pointer gs-reg64)"], + [111, "s2", "(pointer gs-tex1)"], + [113, "s2", "(pointer gs-reg64)"], + [115, "s2", "(pointer gs-clamp)"], + [117, "s2", "(pointer gs-reg64)"], + [118, "s2", "(pointer uint64)"], + [120, "s2", "(pointer gs-reg64)"], + [[159, 166], "s3", "dma-packet"], + [[171, 175], "a0", "dma-packet"], + [[181, 184], "a0", "gs-gif-tag"], + + [189, "s2", "(pointer gs-alpha)"], + [191, "s2", "(pointer gs-reg64)"], + [209, "s2", "(pointer gs-tex0)"], + [211, "s2", "(pointer gs-reg64)"], + [213, "s2", "(pointer gs-tex1)"], + [215, "s2", "(pointer gs-reg64)"], + [216, "s2", "(pointer gs-clamp)"], + [218, "s2", "(pointer gs-reg64)"], + [219, "s2", "(pointer int64)"], + [221, "s2", "(pointer gs-reg64)"], + [[303, 310], "s3", "dma-packet"], + [[312, 316], "v1", "dma-packet"] + ], + + "render-sky-tri": [ + [5, "a0", "int"], + [[6, 50], "a0", "(inline-array sky-vertex)"], + [[25, 48], "a3", "(inline-array sky-vertex)"] + ], + + "render-sky-quad": [ + [[9, 32], "a0", "(inline-array sky-vertex)"], + [[33, 62], "a3", "(inline-array sky-vertex)"] + ], + "(method 10 effect-control)": [ [88, "v1", "collide-shape-moving"], [143, "s3", "(pointer sparticle-launch-group)"], diff --git a/decompiler/util/data_decompile.cpp b/decompiler/util/data_decompile.cpp index 049ffb7a4..57e2eadce 100644 --- a/decompiler/util/data_decompile.cpp +++ b/decompiler/util/data_decompile.cpp @@ -273,6 +273,7 @@ goos::Object decompile_value_array(const TypeSpec& elt_type, } elt_bytes.push_back(word.get_byte(j % 4)); } + assert(elt_type != TypeSpec("uint128")); array_def.push_back(decompile_value(elt_type, elt_bytes, ts)); } @@ -865,6 +866,10 @@ goos::Object bitfield_defs_print(const TypeSpec& type, } else if (def.is_signed) { result.push_back( pretty_print::to_symbol(fmt::format(":{} {}", def.field_name, (s64)def.value))); + } else if (def.nested_field) { + result.push_back(pretty_print::to_symbol(fmt::format( + ":{} {}", def.field_name, + bitfield_defs_print(def.nested_field->field_type, def.nested_field->fields).print()))); } else { result.push_back( pretty_print::to_symbol(fmt::format(":{} #x{:x}", def.field_name, def.value))); @@ -1087,6 +1092,7 @@ goos::Object decompile_boxed_array(const DecompilerLabel& label, } elt_bytes.push_back(word.get_byte(j % 4)); } + assert(content_type != TypeSpec("uint128")); result.push_back(decompile_value(content_type, elt_bytes, ts)); } return pretty_print::build_list(result); diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index c3e21dcb2..0bdfcc356 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -61,9 +61,11 @@ set(RUNTIME_SOURCE kernel/ksound.cpp mips2c/mips2c_table.cpp mips2c/functions/draw_string.cpp + mips2c/functions/sky_tng.cpp mips2c/functions/sparticle.cpp mips2c/functions/sparticle_launcher.cpp mips2c/functions/test_func.cpp + mips2c/functions/texture.cpp overlord/dma.cpp overlord/fake_iso.cpp overlord/iso.cpp @@ -88,7 +90,9 @@ set(RUNTIME_SOURCE graphics/opengl_renderer/debug_gui.cpp graphics/opengl_renderer/DirectRenderer.cpp graphics/opengl_renderer/OpenGLRenderer.cpp + graphics/opengl_renderer/Profiler.cpp graphics/opengl_renderer/Shader.cpp + graphics/opengl_renderer/SkyRenderer.cpp graphics/opengl_renderer/SpriteRenderer.cpp graphics/opengl_renderer/TextureUploadHandler.cpp graphics/texture/TextureConverter.cpp diff --git a/game/graphics/dma/gs.cpp b/game/graphics/dma/gs.cpp index 48af4a4f2..97f81cd66 100644 --- a/game/graphics/dma/gs.cpp +++ b/game/graphics/dma/gs.cpp @@ -81,6 +81,10 @@ std::string GifTag::print() const { return result; } +std::string register_address_name(u32 reg) { + return register_address_name(GsRegisterAddress(reg)); +} + std::string register_address_name(GsRegisterAddress reg) { switch (reg) { case GsRegisterAddress::PRIM: diff --git a/game/graphics/dma/gs.h b/game/graphics/dma/gs.h index 7c50d0449..62604e051 100644 --- a/game/graphics/dma/gs.h +++ b/game/graphics/dma/gs.h @@ -59,10 +59,6 @@ struct GifTag { u64 data[2]; }; -struct AdGif { - GifTag giftag[5]; -}; - std::string reg_descriptor_name(GifTag::RegisterDescriptor reg); enum class GsRegisterAddress : u8 { @@ -125,6 +121,7 @@ enum class GsRegisterAddress : u8 { enum class TextureFormat { PSMZ32, PSMZ24, PSMZ16, PSMZ16S }; std::string register_address_name(GsRegisterAddress reg); +std::string register_address_name(u32 reg); struct GsZbuf { GsZbuf(u64 val) : data(val) {} @@ -332,4 +329,18 @@ struct GsTexa { std::string print() const; u64 data = 0; +}; + +// not including the giftag +struct AdGifData { + u64 tex0_data; + u64 tex0_addr; + u64 tex1_data; + u64 tex1_addr; + u64 mip_data; + u64 mip_addr; + u64 clamp_data; + u64 clamp_addr; + u64 alpha_data; + u64 alpha_addr; }; \ No newline at end of file diff --git a/game/graphics/opengl_renderer/AdgifHandler.h b/game/graphics/opengl_renderer/AdgifHandler.h new file mode 100644 index 000000000..5ccf51131 --- /dev/null +++ b/game/graphics/opengl_renderer/AdgifHandler.h @@ -0,0 +1,45 @@ +#pragma once + +#include "game/graphics/dma/gs.h" + +class AdgifHelper { + public: + // takes the 5QW of adgif data + explicit AdgifHelper(const u8* data) { + memcpy(&m_data, data, 16 * 5); + m_tex0 = GsTex0(m_data.tex0_data); + m_tex1 = GsTex1(m_data.tex1_data); + m_alpha = GsAlpha(m_data.alpha_data); + } + + bool is_normal_adgif() const { + return (u8)m_data.tex0_addr == (u32)GsRegisterAddress::TEX0_1 && + (u8)m_data.tex1_addr == (u32)GsRegisterAddress::TEX1_1 && + (u8)m_data.mip_addr == (u32)GsRegisterAddress::MIPTBP1_1 && + (u8)m_data.clamp_addr == (u32)GsRegisterAddress::CLAMP_1 && + (u8)m_data.alpha_addr == (u32)GsRegisterAddress::ALPHA_1; + } + + std::string print() const { + std::string result; + result += + fmt::format("[0] {}\n {}\n", register_address_name(m_data.tex0_addr), m_tex0.print()); + result += + fmt::format("[1] {}\n {}\n", register_address_name(m_data.tex1_addr), m_tex1.print()); + result += fmt::format("[2] {}\n", register_address_name(m_data.mip_addr)); + result += fmt::format("[3] {}\n", register_address_name(m_data.clamp_addr)); + result += + fmt::format("[4] {}\n {}\n", register_address_name(m_data.alpha_addr), m_alpha.print()); + return result; + } + + const GsAlpha& alpha() const { return m_alpha; } + + const GsTex0& tex0() const { return m_tex0; } + + private: + AdGifData m_data; + GsTex0 m_tex0; + GsTex1 m_tex1; + GsAlpha m_alpha; +}; \ No newline at end of file diff --git a/game/graphics/opengl_renderer/BucketRenderer.cpp b/game/graphics/opengl_renderer/BucketRenderer.cpp index d5013589a..709578523 100644 --- a/game/graphics/opengl_renderer/BucketRenderer.cpp +++ b/game/graphics/opengl_renderer/BucketRenderer.cpp @@ -9,7 +9,9 @@ std::string BucketRenderer::name_and_id() const { EmptyBucketRenderer::EmptyBucketRenderer(const std::string& name, BucketId my_id) : BucketRenderer(name, my_id) {} -void EmptyBucketRenderer::render(DmaFollower& dma, SharedRenderState* render_state) { +void EmptyBucketRenderer::render(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& /*prof*/) { // an empty bucket should have 4 things: // a NEXT in the bucket buffer // a CALL that calls the default register buffer chain diff --git a/game/graphics/opengl_renderer/BucketRenderer.h b/game/graphics/opengl_renderer/BucketRenderer.h index a1ec0b1e2..82a941f2a 100644 --- a/game/graphics/opengl_renderer/BucketRenderer.h +++ b/game/graphics/opengl_renderer/BucketRenderer.h @@ -5,6 +5,7 @@ #include "game/graphics/dma/dma_chain_read.h" #include "game/graphics/opengl_renderer/Shader.h" #include "game/graphics/texture/TexturePool.h" +#include "game/graphics/opengl_renderer/Profiler.h" /*! * Matches the bucket-id enum in GOAL @@ -12,9 +13,11 @@ enum class BucketId { BUCKET0 = 0, BUCKET1 = 1, + SKY_DRAW = 3, TFRAG_TEX_LEVEL0 = 5, SHRUB_TEX_LEVEL0 = 19, ALPHA_TEX_LEVEL0 = 31, + SKY_LEVEL0 = 32, PRIS_TEX_LEVEL0 = 48, WATER_TEX_LEVEL0 = 57, // ... @@ -49,7 +52,9 @@ struct SharedRenderState { class BucketRenderer { public: BucketRenderer(const std::string& name, BucketId my_id) : m_name(name), m_my_id(my_id) {} - virtual void render(DmaFollower& dma, SharedRenderState* render_state) = 0; + virtual void render(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof) = 0; std::string name_and_id() const; virtual ~BucketRenderer() = default; bool& enabled() { return m_enabled; } @@ -69,7 +74,7 @@ class BucketRenderer { class EmptyBucketRenderer : public BucketRenderer { public: EmptyBucketRenderer(const std::string& name, BucketId my_id); - void render(DmaFollower& dma, SharedRenderState* render_state) override; + void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; bool empty() const override { return true; } void draw_debug_window() override {} }; \ No newline at end of file diff --git a/game/graphics/opengl_renderer/DirectRenderer.cpp b/game/graphics/opengl_renderer/DirectRenderer.cpp index 71c27ccc7..14298beae 100644 --- a/game/graphics/opengl_renderer/DirectRenderer.cpp +++ b/game/graphics/opengl_renderer/DirectRenderer.cpp @@ -21,7 +21,7 @@ DirectRenderer::DirectRenderer(const std::string& name, BucketId my_id, int batc glBufferData(GL_ARRAY_BUFFER, m_ogl.color_buffer_bytes, nullptr, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, m_ogl.st_buffer); - m_ogl.st_buffer_bytes = batch_size * 3 * 2 * sizeof(float); + m_ogl.st_buffer_bytes = batch_size * 3 * 3 * sizeof(float); glBufferData(GL_ARRAY_BUFFER, m_ogl.st_buffer_bytes, nullptr, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } @@ -36,7 +36,9 @@ DirectRenderer::~DirectRenderer() { /*! * Render from a DMA bucket. */ -void DirectRenderer::render(DmaFollower& dma, SharedRenderState* render_state) { +void DirectRenderer::render(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { // if we're rendering from a bucket, we should start off we a totally reset state: reset_state(); setup_common_state(render_state); @@ -45,7 +47,7 @@ void DirectRenderer::render(DmaFollower& dma, SharedRenderState* render_state) { while (dma.current_tag_offset() != render_state->next_bucket) { auto data = dma.read_and_advance(); if (data.size_bytes && m_enabled) { - render_vif(data.vif0(), data.vif1(), data.data, data.size_bytes, render_state); + render_vif(data.vif0(), data.vif1(), data.data, data.size_bytes, render_state, prof); } if (dma.current_tag_offset() == render_state->default_regs_buffer) { @@ -57,7 +59,7 @@ void DirectRenderer::render(DmaFollower& dma, SharedRenderState* render_state) { } if (m_enabled) { - flush_pending(render_state); + flush_pending(render_state, prof); } } @@ -91,7 +93,7 @@ float u32_to_sc(u32 in) { return (flt - 0.5) * 16.0; } -void DirectRenderer::flush_pending(SharedRenderState* render_state) { +void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfilerNode& prof) { if (m_prim_buffer.vert_count == 0) { return; } @@ -117,12 +119,6 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) { m_texture_state.needs_gl_update = false; } - if (m_debug_state.wireframe) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } else { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - if (m_debug_state.disable_texture) { // a bit of a hack, this forces the non-textured shader always. render_state->shaders[ShaderId::DIRECT_BASIC].activate(); @@ -131,6 +127,8 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) { if (m_debug_state.red) { render_state->shaders[ShaderId::DEBUG_RED].activate(); glDisable(GL_BLEND); + m_prim_gl_state_needs_gl_update = true; + m_blend_state_needs_gl_update = true; } // hacks @@ -151,8 +149,8 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) { m_prim_buffer.rgba_u8.data()); if (m_prim_gl_state.texture_enable) { glBindBuffer(GL_ARRAY_BUFFER, m_ogl.st_buffer); - glBufferSubData(GL_ARRAY_BUFFER, 0, m_prim_buffer.sts.size() * sizeof(math::Vector), - m_prim_buffer.sts.data()); + glBufferSubData(GL_ARRAY_BUFFER, 0, m_prim_buffer.stqs.size() * sizeof(math::Vector), + m_prim_buffer.stqs.data()); } // setup attributes: @@ -179,7 +177,7 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) { glBindBuffer(GL_ARRAY_BUFFER, m_ogl.st_buffer); glEnableVertexAttribArray(2); glVertexAttribPointer(2, // location 0 in the shader - 2, // 3 floats per vert + 3, // 3 floats per vert GL_FLOAT, // floats GL_FALSE, // normalized, ignored, 0, // tightly packed @@ -190,8 +188,14 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) { int draw_count = 0; if (m_mode == Mode::SPRITE_CPU) { - assert(m_texture_state.tcc); - assert(m_prim_gl_state.texture_enable); + if (!m_prim_gl_state.texture_enable) { + render_state->shaders[ShaderId::DIRECT_BASIC].activate(); + } else { + assert(m_texture_state.tcc); + assert(m_prim_gl_state.texture_enable); + render_state->shaders[ShaderId::SPRITE_CPU].activate(); + } + if (m_sprite_mode.do_first_draw) { glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count); draw_count++; @@ -201,6 +205,8 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) { glDepthMask(GL_FALSE); glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count); glDepthMask(GL_TRUE); + m_prim_gl_state_needs_gl_update = true; + m_blend_state_needs_gl_update = true; draw_count++; } } else { @@ -208,8 +214,20 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) { draw_count++; } + if (m_debug_state.wireframe) { + render_state->shaders[ShaderId::DEBUG_RED].activate(); + glDisable(GL_BLEND); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + draw_count++; + } + glBindVertexArray(0); - m_triangles += draw_count * (m_prim_buffer.vert_count / 3); + int n_tris = draw_count * (m_prim_buffer.vert_count / 3); + prof.add_tri(n_tris); + prof.add_draw_call(draw_count); + m_triangles += n_tris; m_draw_calls += draw_count; m_prim_buffer.vert_count = 0; } @@ -221,6 +239,8 @@ void DirectRenderer::update_gl_prim(SharedRenderState* render_state) { if (m_texture_state.tcc) { if (m_mode == Mode::SPRITE_CPU) { render_state->shaders[ShaderId::SPRITE_CPU].activate(); + } else if (m_mode == Mode::SKY) { + assert(false); } else { render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].activate(); } @@ -229,7 +249,11 @@ void DirectRenderer::update_gl_prim(SharedRenderState* render_state) { } update_gl_texture(render_state); } else { - render_state->shaders[ShaderId::DIRECT_BASIC].activate(); + if (m_mode == Mode::SKY) { + render_state->shaders[ShaderId::SKY].activate(); + } else { + render_state->shaders[ShaderId::DIRECT_BASIC].activate(); + } } if (state.fogging_enable) { assert(false); @@ -255,8 +279,16 @@ void DirectRenderer::update_gl_texture(SharedRenderState* render_state) { } else { tex = render_state->texture_pool->lookup(m_texture_state.texture_base_ptr); } + + if (!tex) { + // TODO Add back + fmt::print("Failed to find texture at {}, using random\n", m_texture_state.texture_base_ptr); + tex = render_state->texture_pool->get_random_texture(); + if (tex) { + // fmt::print("Successful texture lookup! {} {}\n", tex->page_name, tex->name); + } + } assert(tex); - // fmt::print("Successful texture lookup! {} {}\n", tex->page_name, tex->name); // first: do we need to load the texture? if (!tex->on_gpu) { @@ -266,8 +298,14 @@ void DirectRenderer::update_gl_texture(SharedRenderState* render_state) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex->gpu_texture); // Note: CLAMP and CLAMP_TO_EDGE are different... - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (m_clamp_state.clamp) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glUniform1i( @@ -327,7 +365,7 @@ void DirectRenderer::update_gl_test() { } if (state.alpha_test_enable) { - assert(false); + assert(state.alpha_test == GsTest::AlphaTest::ALWAYS); } if (state.depth_writes) { @@ -371,7 +409,8 @@ void DirectRenderer::render_vif(u32 vif0, u32 vif1, const u8* data, u32 size, - SharedRenderState* render_state) { + SharedRenderState* render_state, + ScopedProfilerNode& prof) { // here we process VIF data. Basically we just go forward, looking for DIRECTs. // We skip stuff like flush and nops. @@ -395,7 +434,7 @@ void DirectRenderer::render_vif(u32 vif0, assert(get_direct_qwc_or_nop(VifCode(vif)) == 0); } else { // aligned! do a gif transfer! - render_gif(data + offset_into_data, gif_qwc * 16, render_state); + render_gif(data + offset_into_data, gif_qwc * 16, render_state, prof); offset_into_data += gif_qwc * 16; } } else { @@ -411,7 +450,10 @@ void DirectRenderer::render_vif(u32 vif0, /*! * Render GIF data. */ -void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* render_state) { +void DirectRenderer::render_gif(const u8* data, + u32 size, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { assert(size >= 16); bool eop = false; @@ -433,13 +475,13 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren auto format = tag.flg(); if (format == GifTag::Format::PACKED) { if (tag.pre()) { - handle_prim(tag.prim(), render_state); + handle_prim(tag.prim(), render_state, prof); } for (u32 loop = 0; loop < tag.nloop(); loop++) { for (u32 reg = 0; reg < nreg; reg++) { switch (reg_desc[reg]) { case GifTag::RegisterDescriptor::AD: - handle_ad(data + offset, render_state); + handle_ad(data + offset, render_state, prof); break; case GifTag::RegisterDescriptor::ST: handle_st_packed(data + offset); @@ -448,13 +490,13 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren handle_rgbaq_packed(data + offset); break; case GifTag::RegisterDescriptor::XYZF2: - handle_xyzf2_packed(data + offset, render_state); + handle_xyzf2_packed(data + offset, render_state, prof); break; case GifTag::RegisterDescriptor::PRIM: - handle_prim_packed(data + offset, render_state); + handle_prim_packed(data + offset, render_state, prof); break; case GifTag::RegisterDescriptor::TEX0_1: - handle_tex0_1_packed(data + offset, render_state); + handle_tex0_1_packed(data + offset, render_state, prof); break; default: fmt::print("Register {} is not supported in packed mode yet\n", @@ -473,13 +515,13 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren // reg_descriptor_name(reg_desc[reg])); switch (reg_desc[reg]) { case GifTag::RegisterDescriptor::PRIM: - handle_prim(register_data, render_state); + handle_prim(register_data, render_state, prof); break; case GifTag::RegisterDescriptor::RGBAQ: handle_rgbaq(register_data); break; case GifTag::RegisterDescriptor::XYZF2: - handle_xyzf2(register_data, render_state); + handle_xyzf2(register_data, render_state, prof); break; default: fmt::print("Register {} is not supported in reglist mode yet\n", @@ -501,7 +543,9 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren // fmt::print("{}\n", GifTag(data).print()); } -void DirectRenderer::handle_ad(const u8* data, SharedRenderState* render_state) { +void DirectRenderer::handle_ad(const u8* data, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { u64 value; GsRegisterAddress addr; memcpy(&value, data, sizeof(u64)); @@ -509,22 +553,22 @@ void DirectRenderer::handle_ad(const u8* data, SharedRenderState* render_state) switch (addr) { case GsRegisterAddress::ZBUF_1: - handle_zbuf1(value, render_state); + handle_zbuf1(value, render_state, prof); break; case GsRegisterAddress::TEST_1: - handle_test1(value, render_state); + handle_test1(value, render_state, prof); break; case GsRegisterAddress::ALPHA_1: - handle_alpha1(value, render_state); + handle_alpha1(value, render_state, prof); break; case GsRegisterAddress::PABE: handle_pabe(value); break; case GsRegisterAddress::CLAMP_1: - handle_clamp1(value); + handle_clamp1(value, render_state, prof); break; case GsRegisterAddress::PRIM: - handle_prim(value, render_state); + handle_prim(value, render_state, prof); break; case GsRegisterAddress::TEX1_1: @@ -543,11 +587,13 @@ void DirectRenderer::handle_ad(const u8* data, SharedRenderState* render_state) // TODO break; case GsRegisterAddress::TEX0_1: - handle_tex0_1(value, render_state); + handle_tex0_1(value, render_state, prof); break; case GsRegisterAddress::MIPTBP1_1: // TODO this has the address of different mip levels. break; + case GsRegisterAddress::TEXFLUSH: + break; default: fmt::print("Address {} is not supported\n", register_address_name(addr)); assert(false); @@ -565,22 +611,25 @@ void DirectRenderer::handle_tex1_1(u64 val) { if (!(reg.mmin() == 1 || reg.mmin() == 4)) { // with mipmap off, both of these are linear // lg::error("unsupported mmin"); } - - // } -void DirectRenderer::handle_tex0_1_packed(const u8* data, SharedRenderState* render_state) { +void DirectRenderer::handle_tex0_1_packed(const u8* data, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { u64 val; memcpy(&val, data, sizeof(u64)); - handle_tex0_1(val, render_state); + handle_tex0_1(val, render_state, prof); } -void DirectRenderer::handle_tex0_1(u64 val, SharedRenderState* render_state) { +void DirectRenderer::handle_tex0_1(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { GsTex0 reg(val); // update tbp if (m_texture_state.current_register != reg) { - flush_pending(render_state); + // fmt::print("flush due to tex0\n"); + flush_pending(render_state, prof); m_texture_state.texture_base_ptr = reg.tbp0(); m_texture_state.using_mt4hh = reg.psm() == GsTex0::PSM::PSMT4HH; m_prim_gl_state_needs_gl_update = true; @@ -628,7 +677,9 @@ void DirectRenderer::handle_rgbaq_packed(const u8* data) { m_prim_building.rgba_reg[3] = data[12]; } -void DirectRenderer::handle_xyzf2_packed(const u8* data, SharedRenderState* render_state) { +void DirectRenderer::handle_xyzf2_packed(const u8* data, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { u32 x, y; memcpy(&x, data, 4); memcpy(&y, data + 4, 4); @@ -641,42 +692,52 @@ void DirectRenderer::handle_xyzf2_packed(const u8* data, SharedRenderState* rend bool adc = upper & (1ull << 47); assert(!adc); // assert(!f); - handle_xyzf2_common(x, y, z, f, render_state); + handle_xyzf2_common(x, y, z, f, render_state, prof); } -void DirectRenderer::handle_zbuf1(u64 val, SharedRenderState* render_state) { +void DirectRenderer::handle_zbuf1(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { // note: we can basically ignore this. There's a single z buffer that's always configured the same // way - 24-bit, at offset 448. GsZbuf x(val); assert(x.psm() == TextureFormat::PSMZ24); assert(x.zbp() == 448); - bool write = !x.zmsk(); + bool write = x.zmsk(); // assert(write); if (write != m_test_state.depth_writes) { - flush_pending(render_state); + // fmt::print("flush due to depth write\n"); + flush_pending(render_state, prof); m_test_state_needs_gl_update = true; - m_test_state.depth_writes = !write; + m_test_state.depth_writes = write; } } -void DirectRenderer::handle_test1(u64 val, SharedRenderState* render_state) { +void DirectRenderer::handle_test1(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { GsTest reg(val); - assert(!reg.alpha_test_enable()); + if (reg.alpha_test_enable()) { + assert(reg.alpha_test() == GsTest::AlphaTest::ALWAYS); + } assert(!reg.date()); - assert(!(val & 1)); if (m_test_state.current_register != reg) { - flush_pending(render_state); + // fmt::print("flush due to test\n"); + flush_pending(render_state, prof); m_test_state.from_register(reg); m_test_state_needs_gl_update = true; } } -void DirectRenderer::handle_alpha1(u64 val, SharedRenderState* render_state) { +void DirectRenderer::handle_alpha1(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { GsAlpha reg(val); if (m_blend_state.current_register != reg) { - flush_pending(render_state); + // fmt::print("flush due to alpha1\n"); + flush_pending(render_state, prof); m_blend_state.from_register(reg); m_blend_state_needs_gl_update = true; } @@ -686,17 +747,33 @@ void DirectRenderer::handle_pabe(u64 val) { assert(val == 0); // not really sure how to handle this yet. } -void DirectRenderer::handle_clamp1(u64 val) { - assert(val == 0b101); // clamp s and t. +void DirectRenderer::handle_clamp1(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { + assert(val == 0b101 || val == 0); + if (m_clamp_state.current_register != val) { + flush_pending(render_state, prof); + m_clamp_state.current_register = val; + if (val == 0b101) { + m_clamp_state.clamp = true; + } else { + m_clamp_state.clamp = false; + } + m_texture_state.needs_gl_update = true; + } } -void DirectRenderer::handle_prim_packed(const u8* data, SharedRenderState* render_state) { +void DirectRenderer::handle_prim_packed(const u8* data, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { u64 val; memcpy(&val, data, sizeof(u64)); - handle_prim(val, render_state); + handle_prim(val, render_state, prof); } -void DirectRenderer::handle_prim(u64 val, SharedRenderState* render_state) { +void DirectRenderer::handle_prim(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { if (m_prim_building.tri_strip_startup) { m_prim_building.tri_strip_startup = 0; m_prim_building.building_idx = 0; @@ -709,7 +786,8 @@ void DirectRenderer::handle_prim(u64 val, SharedRenderState* render_state) { GsPrim prim(val); if (m_prim_gl_state.current_register != prim || m_blend_state.alpha_blend_enable != prim.abe()) { - flush_pending(render_state); + // fmt::print("flush due to prim\n"); + flush_pending(render_state, prof); m_prim_gl_state.from_register(prim); m_blend_state.alpha_blend_enable = prim.abe(); m_prim_gl_state_needs_gl_update = true; @@ -728,15 +806,17 @@ void DirectRenderer::handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f, - SharedRenderState* render_state) { + SharedRenderState* render_state, + ScopedProfilerNode& prof) { assert(z < (1 << 24)); (void)f; // TODO: do something with this. if (m_prim_buffer.is_full()) { - flush_pending(render_state); + // fmt::print("flush due to fill {} {}\n", m_prim_buffer.vert_count, m_prim_buffer.max_verts); + flush_pending(render_state, prof); } - // assert(f == 0); - m_prim_building.building_st.at(m_prim_building.building_idx) = m_prim_building.st_reg; + m_prim_building.building_stq.at(m_prim_building.building_idx) = math::Vector( + m_prim_building.st_reg.x(), m_prim_building.st_reg.y(), m_prim_building.Q); m_prim_building.building_rgba.at(m_prim_building.building_idx) = m_prim_building.rgba_reg; m_prim_building.building_vert.at(m_prim_building.building_idx) = {x << 16, y << 16, z << 8}; m_prim_building.building_idx++; @@ -780,7 +860,7 @@ void DirectRenderer::handle_xyzf2_common(u32 x, if (m_prim_building.tri_strip_startup >= 3) { for (int i = 0; i < 3; i++) { m_prim_buffer.push(m_prim_building.building_rgba[i], m_prim_building.building_vert[i], - m_prim_building.building_st[i]); + m_prim_building.building_stq[i]); } } @@ -791,7 +871,7 @@ void DirectRenderer::handle_xyzf2_common(u32 x, m_prim_building.building_idx = 0; for (int i = 0; i < 3; i++) { m_prim_buffer.push(m_prim_building.building_rgba[i], m_prim_building.building_vert[i], - m_prim_building.building_st[i]); + m_prim_building.building_stq[i]); } } break; @@ -807,10 +887,11 @@ void DirectRenderer::handle_xyzf2_common(u32 x, } for (int i = 0; i < 3; i++) { m_prim_buffer.push(m_prim_building.building_rgba[i], m_prim_building.building_vert[i], - m_prim_building.building_st[i]); + m_prim_building.building_stq[i]); } } } break; + case GsPrim::Kind::LINE: { if (m_prim_building.building_idx == 2) { math::Vector pt0 = m_prim_building.building_vert[0].cast(); @@ -845,13 +926,15 @@ void DirectRenderer::handle_xyzf2_common(u32 x, } } -void DirectRenderer::handle_xyzf2(u64 val, SharedRenderState* render_state) { +void DirectRenderer::handle_xyzf2(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { u32 x = val & 0xffff; u32 y = (val >> 16) & 0xffff; u32 z = (val >> 32) & 0xffffff; u32 f = (val >> 56) & 0xff; - handle_xyzf2_common(x, y, z, f, render_state); + handle_xyzf2_common(x, y, z, f, render_state, prof); } void DirectRenderer::reset_state() { @@ -915,15 +998,15 @@ void DirectRenderer::PrimGlState::from_register(GsPrim reg) { DirectRenderer::PrimitiveBuffer::PrimitiveBuffer(int max_triangles) { rgba_u8.resize(max_triangles * 3); verts.resize(max_triangles * 3); - sts.resize(max_triangles * 3); + stqs.resize(max_triangles * 3); max_verts = max_triangles * 3; } void DirectRenderer::PrimitiveBuffer::push(const math::Vector& rgba, const math::Vector& vert, - const math::Vector& st) { + const math::Vector& st) { rgba_u8[vert_count] = rgba; verts[vert_count] = vert; - sts[vert_count] = st; + stqs[vert_count] = st; vert_count++; } diff --git a/game/graphics/opengl_renderer/DirectRenderer.h b/game/graphics/opengl_renderer/DirectRenderer.h index 9f8c46b52..a35638004 100644 --- a/game/graphics/opengl_renderer/DirectRenderer.h +++ b/game/graphics/opengl_renderer/DirectRenderer.h @@ -20,24 +20,33 @@ class DirectRenderer : public BucketRenderer { public: // specializations of direct renderer to handle certain outputs. enum class Mode { - NORMAL, // use for general debug drawing, font. - SPRITE_CPU // use for sprites (does the appropriate alpha test) + NORMAL, // use for general debug drawing, font. + SPRITE_CPU, // use for sprites (does the appropriate alpha test tricks) + SKY // disables texture perspective correction }; DirectRenderer(const std::string& name, BucketId my_id, int batch_size, Mode mode); ~DirectRenderer(); - void render(DmaFollower& dma, SharedRenderState* render_state) override; + void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; /*! * Render directly from _VIF_ data. * You can optionally provide two vif tags that come in front of data. * These can be set to 0 if you don't have these. */ - void render_vif(u32 vif0, u32 vif1, const u8* data, u32 size, SharedRenderState* render_state); + void render_vif(u32 vif0, + u32 vif1, + const u8* data, + u32 size, + SharedRenderState* render_state, + ScopedProfilerNode& prof); /*! * Render directly from _GIF_ data. */ - void render_gif(const u8* data, u32 size, SharedRenderState* render_state); + void render_gif(const u8* data, + u32 size, + SharedRenderState* render_state, + ScopedProfilerNode& prof); void reset_state(); @@ -49,30 +58,41 @@ class DirectRenderer : public BucketRenderer { /*! * If you don't use the render interface, call this at the very end. */ - void flush_pending(SharedRenderState* render_state); + void flush_pending(SharedRenderState* render_state, ScopedProfilerNode& prof); void draw_debug_window() override; private: - void handle_ad(const u8* data, SharedRenderState* render_state); - void handle_zbuf1(u64 val, SharedRenderState* render_state); - void handle_test1(u64 val, SharedRenderState* render_state); - void handle_alpha1(u64 val, SharedRenderState* render_state); + void handle_ad(const u8* data, SharedRenderState* render_state, ScopedProfilerNode& prof); + void handle_zbuf1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); + void handle_test1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); + void handle_alpha1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); void handle_pabe(u64 val); - void handle_clamp1(u64 val); - void handle_prim(u64 val, SharedRenderState* render_state); - void handle_prim_packed(const u8* data, SharedRenderState* render_state); + void handle_clamp1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); + void handle_prim(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); + void handle_prim_packed(const u8* data, + SharedRenderState* render_state, + ScopedProfilerNode& prof); void handle_rgbaq(u64 val); - void handle_xyzf2(u64 val, SharedRenderState* render_state); + void handle_xyzf2(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); void handle_st_packed(const u8* data); void handle_rgbaq_packed(const u8* data); - void handle_xyzf2_packed(const u8* data, SharedRenderState* render_state); - void handle_tex0_1_packed(const u8* data, SharedRenderState* render_state); - void handle_tex0_1(u64 val, SharedRenderState* render_state); + void handle_xyzf2_packed(const u8* data, + SharedRenderState* render_state, + ScopedProfilerNode& prof); + void handle_tex0_1_packed(const u8* data, + SharedRenderState* render_state, + ScopedProfilerNode& prof); + void handle_tex0_1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); void handle_tex1_1(u64 val); void handle_texa(u64 val); - void handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f, SharedRenderState* render_state); + void handle_xyzf2_common(u32 x, + u32 y, + u32 z, + u8 f, + SharedRenderState* render_state, + ScopedProfilerNode& prof); void update_gl_prim(SharedRenderState* render_state); void update_gl_blend(); @@ -110,6 +130,12 @@ class DirectRenderer : public BucketRenderer { } m_blend_state; + struct ClampState { + void from_register(u64 value); + u64 current_register = 0b101; + bool clamp = true; + } m_clamp_state; + // state set through the prim register that requires changing GL stuff. struct PrimGlState { void from_register(GsPrim reg); @@ -141,11 +167,11 @@ class DirectRenderer : public BucketRenderer { std::array, 3> building_rgba; std::array, 3> building_vert; - std::array, 3> building_st; + std::array, 3> building_stq; int building_idx = 0; int tri_strip_startup = 0; - float Q = 0; + float Q = 1.0; } m_prim_building; @@ -153,7 +179,7 @@ class DirectRenderer : public BucketRenderer { PrimitiveBuffer(int max_triangles); std::vector> rgba_u8; std::vector> verts; - std::vector> sts; + std::vector> stqs; int vert_count = 0; int max_verts = 0; @@ -161,7 +187,7 @@ class DirectRenderer : public BucketRenderer { bool is_full() { return max_verts < (vert_count + 18); } void push(const math::Vector& rgba, const math::Vector& vert, - const math::Vector& st); + const math::Vector& stq); } m_prim_buffer; struct { diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index b25fe3f9f..f00f376a1 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -6,6 +6,8 @@ #include "game/graphics/opengl_renderer/SpriteRenderer.h" #include "game/graphics/opengl_renderer/TextureUploadHandler.h" #include "third-party/imgui/imgui.h" +#include "common/util/FileUtil.h" +#include "game/graphics/opengl_renderer/SkyRenderer.h" // for the vif callback #include "game/kernel/kmachine.h" @@ -21,7 +23,8 @@ void GLAPIENTRY opengl_error_callback(GLenum source, const GLchar* message, const void* /*userParam*/) { if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) { - lg::debug("OpenGL notification 0x{:X} S{:X} T{:X}: {}", id, source, type, message); + // On some drivers this prints on every single texture upload, which is too much spam + // lg::debug("OpenGL notification 0x{:X} S{:X} T{:X}: {}", id, source, type, message); } else if (severity == GL_DEBUG_SEVERITY_LOW) { lg::info("OpenGL message 0x{:X} S{:X} T{:X}: {}", id, source, type, message); } else if (severity == GL_DEBUG_SEVERITY_MEDIUM) { @@ -56,7 +59,9 @@ OpenGLRenderer::OpenGLRenderer(std::shared_ptr texture_pool) */ void OpenGLRenderer::init_bucket_renderers() { init_bucket_renderer("bucket0", BucketId::BUCKET0); + init_bucket_renderer("sky", BucketId::SKY_DRAW); init_bucket_renderer("tfrag-tex-0", BucketId::TFRAG_TEX_LEVEL0); + init_bucket_renderer("sky-tex-0", BucketId::SKY_LEVEL0); init_bucket_renderer("shrub-tex-0", BucketId::SHRUB_TEX_LEVEL0); init_bucket_renderer("alpha-tex-0", BucketId::ALPHA_TEX_LEVEL0); init_bucket_renderer("pris-tex-0", BucketId::PRIS_TEX_LEVEL0); @@ -79,27 +84,46 @@ void OpenGLRenderer::init_bucket_renderers() { /*! * Main render function. This is called from the gfx loop with the chain passed from the game. */ -void OpenGLRenderer::render(DmaFollower dma, - int window_width_px, - int window_height_px, - bool draw_debug_window, - bool dump_playback) { - m_render_state.dump_playback = dump_playback; - m_render_state.ee_main_memory = dump_playback ? nullptr : g_ee_main_mem; +void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) { + m_profiler.clear(); + m_render_state.dump_playback = settings.playing_from_dump; + m_render_state.ee_main_memory = settings.playing_from_dump ? nullptr : g_ee_main_mem; m_render_state.offset_of_s7 = offset_of_s7(); - setup_frame(window_width_px, window_height_px); - m_render_state.texture_pool->remove_garbage_textures(); + + { + auto prof = m_profiler.root()->make_scoped_child("frame-setup"); + setup_frame(settings.window_width_px, settings.window_height_px); + } + { + auto prof = m_profiler.root()->make_scoped_child("texture-gc"); + m_render_state.texture_pool->remove_garbage_textures(); + } + // draw_test_triangle(); // render the buckets! - dispatch_buckets(dma); + { + auto prof = m_profiler.root()->make_scoped_child("buckets"); + dispatch_buckets(dma, prof); + } - if (draw_debug_window) { + if (settings.draw_render_debug_window) { + auto prof = m_profiler.root()->make_scoped_child("render-window"); draw_renderer_selection_window(); // add a profile bar for the imgui stuff if (!m_render_state.dump_playback) { vif_interrupt_callback(); } } + + m_profiler.finish(); + if (settings.draw_profiler_window) { + m_profiler.draw(); + } + + if (settings.save_screenshot) { + finish_screenshot(settings.screenshot_path, settings.window_width_px, + settings.window_height_px); + } } void OpenGLRenderer::serialize(Serializer& ser) { @@ -109,6 +133,9 @@ void OpenGLRenderer::serialize(Serializer& ser) { } } +/*! + * Draw the per-renderer debug window + */ void OpenGLRenderer::draw_renderer_selection_window() { ImGui::Begin("Renderer Debug"); for (size_t i = 0; i < m_bucket_renderers.size(); i++) { @@ -145,7 +172,7 @@ void OpenGLRenderer::setup_frame(int window_width_px, int window_height_px) { /*! * This function finds buckets and dispatches them to the appropriate part. */ -void OpenGLRenderer::dispatch_buckets(DmaFollower dma) { +void OpenGLRenderer::dispatch_buckets(DmaFollower dma, ScopedProfilerNode& prof) { // The first thing the DMA chain should be a call to a common default-registers chain. // this chain resets the state of the GS. After this is buckets @@ -176,7 +203,8 @@ void OpenGLRenderer::dispatch_buckets(DmaFollower dma) { // loop over the buckets! for (int bucket_id = 0; bucket_id < (int)BucketId::MAX_BUCKETS; bucket_id++) { auto& renderer = m_bucket_renderers[bucket_id]; - renderer->render(dma, &m_render_state); + auto bucket_prof = prof.make_scoped_child(renderer->name_and_id()); + renderer->render(dma, &m_render_state, bucket_prof); // should have ended at the start of the next chain assert(dma.current_tag_offset() == m_render_state.next_bucket); m_render_state.next_bucket += 16; @@ -246,3 +274,25 @@ void OpenGLRenderer::draw_test_triangle() { glDeleteBuffers(1, &vertex_buffer); glDeleteVertexArrays(1, &vao); } + +/*! + * Take a screenshot! + */ +void OpenGLRenderer::finish_screenshot(const std::string& output_name, int width, int height) { + std::vector buffer(width * height); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadBuffer(GL_BACK); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); + // flip upside down in place + for (int h = 0; h < height / 2; h++) { + for (int w = 0; w < width; w++) { + std::swap(buffer[h * width + w], buffer[(height - h) * width + w]); + } + } + + // set alpha. For some reason, image viewers do weird stuff with alpha. + for (auto& x : buffer) { + x |= 0xff000000; + } + file_util::write_rgba_png(output_name, buffer.data(), width, height); +} \ No newline at end of file diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.h b/game/graphics/opengl_renderer/OpenGLRenderer.h index 161565dce..7eaca1900 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.h +++ b/game/graphics/opengl_renderer/OpenGLRenderer.h @@ -6,30 +6,41 @@ #include "game/graphics/dma/dma_chain_read.h" #include "game/graphics/opengl_renderer/Shader.h" #include "game/graphics/opengl_renderer/BucketRenderer.h" +#include "game/graphics/opengl_renderer/Profiler.h" + +struct RenderOptions { + int window_height_px = 0; + int window_width_px = 0; + bool draw_render_debug_window = false; + bool draw_profiler_window = false; + bool playing_from_dump = false; + + bool save_screenshot = false; + std::string screenshot_path; +}; class OpenGLRenderer { public: OpenGLRenderer(std::shared_ptr texture_pool); - void render(DmaFollower dma, - int window_width_px, - int window_height_px, - bool draw_debug_window, - bool dump_playback); + void render(DmaFollower dma, const RenderOptions& settings); void serialize(Serializer& ser); private: void setup_frame(int window_width_px, int window_height_px); void draw_test_triangle(); - void dispatch_buckets(DmaFollower dma); + void dispatch_buckets(DmaFollower dma, ScopedProfilerNode& prof); void init_bucket_renderers(); void draw_renderer_selection_window(); + void finish_screenshot(const std::string& output_name, int px, int py); + template void init_bucket_renderer(const std::string& name, BucketId id, Args&&... args) { m_bucket_renderers.at((int)id) = std::make_unique(name, id, std::forward(args)...); } SharedRenderState m_render_state; + Profiler m_profiler; std::array, (int)BucketId::MAX_BUCKETS> m_bucket_renderers; }; diff --git a/game/graphics/opengl_renderer/Profiler.cpp b/game/graphics/opengl_renderer/Profiler.cpp new file mode 100644 index 000000000..0e6bab0b5 --- /dev/null +++ b/game/graphics/opengl_renderer/Profiler.cpp @@ -0,0 +1,145 @@ +#include + +#include "Profiler.h" + +#include "common/log/log.h" +#include "common/util/colors.h" +#include "third-party/imgui/imgui.h" +#include "third-party/fmt/core.h" + +ProfilerNode::ProfilerNode(const std::string& name) : m_name(name) {} + +ProfilerNode* ProfilerNode::make_child(const std::string& name) { + m_children.emplace_back(name); + return &m_children.back(); +} + +void ProfilerNode::finish() { + if (m_finished) { + lg::error("finish() called twice on {}\n", m_name); + } else { + m_stats.duration = m_timer.getSeconds(); + float total_child_time = 0; + for (const auto& child : m_children) { + if (!child.finished()) { + lg::error("finish() not called on {}\n", child.name()); + } + total_child_time += child.m_stats.duration; + m_stats.add_draw_stats(child.m_stats); + } + + if (!m_children.empty()) { + float unknown_time = m_stats.duration - total_child_time; + if (unknown_time > 0.0001 || unknown_time > (m_stats.duration * 0.05)) { + ProfilerNode unk("unknown"); + unk.m_stats.duration = unknown_time; + m_children.push_back(unk); + } + } + } + m_finished = true; +} + +void ProfilerNode::sort(ProfilerSort mode) { + if (mode == ProfilerSort::NONE) { + return; + } + std::sort(m_children.begin(), m_children.end(), + [=](const ProfilerNode& a, const ProfilerNode& b) { + switch (mode) { + case ProfilerSort::DRAW_CALLS: + return a.m_stats.draw_calls > b.m_stats.draw_calls; + case ProfilerSort::TIME: + return a.m_stats.duration > b.m_stats.duration; + case ProfilerSort::TRIANGLES: + return a.m_stats.triangles > b.m_stats.triangles; + default: + assert(false); + } + }); + for (auto& child : m_children) { + child.sort(mode); + } +} + +ScopedProfilerNode ProfilerNode::make_scoped_child(const std::string& name) { + return ScopedProfilerNode(make_child(name)); +} + +Profiler::Profiler() : m_root("root") {} + +void Profiler::clear() { + m_root = ProfilerNode("root"); +} + +void Profiler::finish() { + m_root.finish(); +} + +void Profiler::draw() { + ImGui::Begin("Profiler"); + const char* listbox_entries[] = {"None", "Time", "Draw Calls", "Tris"}; + ImGui::Combo("Sort", &m_mode_selector, listbox_entries, 4); + m_root.sort((ProfilerSort)m_mode_selector); + ImGui::SameLine(); + bool all = ImGui::Button("Expand All"); + ImGui::Dummy(ImVec2(0.0f, 80.0f)); + draw_node(m_root, all, 0, 0.f); + ImGui::End(); +} + +u32 name_to_color(const std::string& name) { + u64 val = std::hash{}(name); + return colors::common_colors[val % colors::COLOR_COUNT] | 0xff000000; +} + +void Profiler::draw_node(ProfilerNode& node, bool expand, int depth, float start_time) { + u32 color = 0xFFFFFFFF; + + constexpr int origin_x = 40; + constexpr int origin_y = 60; + constexpr int row_height = 15; + constexpr int px_per_ms = 200; + + if (node.m_stats.duration > 0.00001) { + color = name_to_color(node.m_name); + } + bool color_orange = false; + ImGui::PushStyleColor(ImGuiCol_Text, color); + auto str = + fmt::format("{:20s} {:.2f}ms {:6d} tri {:4d} draw", node.m_name, node.m_stats.duration * 1000, + node.m_stats.triangles, node.m_stats.draw_calls); + if (node.m_children.empty()) { + ImGui::Text(" %s", str.c_str()); + color_orange = ImGui::IsItemHovered(); + } else { + if (expand) { + ImGui::SetNextTreeNodeOpen(true); + } + if (ImGui::TreeNode(node.m_name.c_str(), "%s", str.c_str())) { + color_orange = ImGui::IsItemHovered(); + float child_start = start_time; + for (auto& child : node.m_children) { + draw_node(child, expand, depth + 1, child_start); + child_start += child.m_stats.duration; + } + ImGui::TreePop(); + } + } + + if (node.m_stats.duration > 0.00001 || color_orange) { + if (color_orange) { + color = 0xff00a5ff; + } + auto dl = ImGui::GetWindowDrawList(); + auto window_pos = ImGui::GetWindowPos(); + float x0 = window_pos.x + origin_x + px_per_ms * 1000 * start_time; + float x1 = x0 + px_per_ms * 1000 * node.m_stats.duration; + float y0 = window_pos.y + origin_y + depth * row_height; + float y1 = y0 + row_height; + + dl->AddRectFilled(ImVec2(x0, y0), ImVec2(x1, y1), color); + } + + ImGui::PopStyleColor(); +} \ No newline at end of file diff --git a/game/graphics/opengl_renderer/Profiler.h b/game/graphics/opengl_renderer/Profiler.h new file mode 100644 index 000000000..98c1b9d6e --- /dev/null +++ b/game/graphics/opengl_renderer/Profiler.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "common/util/Timer.h" + +enum class ProfilerSort { NONE = 0, TIME = 1, DRAW_CALLS = 2, TRIANGLES = 3 }; + +struct ProfilerStats { + float duration = 0; // seconds + u32 draw_calls = 0; + u32 triangles = 0; + + void add_draw_stats(const ProfilerStats& other) { + draw_calls += other.draw_calls; + triangles += other.triangles; + } +}; + +class ScopedProfilerNode; + +class ProfilerNode { + public: + ProfilerNode(const std::string& name); + ProfilerNode* make_child(const std::string& name); + ScopedProfilerNode make_scoped_child(const std::string& name); + void sort(ProfilerSort mode); + void finish(); + + bool finished() const { return m_finished; } + const std::string& name() const { return m_name; } + + void add_draw_call(int count = 1) { m_stats.draw_calls += count; } + void add_tri(int count = 1) { m_stats.triangles += count; } + + private: + friend class Profiler; + std::string m_name; + ProfilerStats m_stats; + std::vector m_children; + Timer m_timer; + bool m_finished = false; +}; + +class ScopedProfilerNode { + public: + ScopedProfilerNode(ProfilerNode* node) : m_node(node) {} + ScopedProfilerNode(const ScopedProfilerNode& other) = delete; + ScopedProfilerNode& operator=(const ScopedProfilerNode& other) = delete; + ProfilerNode* make_child(const std::string& name) { return m_node->make_child(name); } + ScopedProfilerNode make_scoped_child(const std::string& name) { + return m_node->make_scoped_child(name); + } + ~ScopedProfilerNode() { m_node->finish(); } + + void add_draw_call(int count = 1) { m_node->add_draw_call(count); } + void add_tri(int count = 1) { m_node->add_tri(count); } + + private: + ProfilerNode* m_node; +}; + +class Profiler { + public: + Profiler(); + void clear(); + void draw(); + void finish(); + ProfilerNode* root() { return &m_root; } + + private: + void draw_node(ProfilerNode& node, bool expand, int depth, float start_time); + + struct BarEntry { + float duration; + float rgba[4]; + }; + + int m_mode_selector = 0; + ProfilerNode m_root; +}; \ No newline at end of file diff --git a/game/graphics/opengl_renderer/Shader.cpp b/game/graphics/opengl_renderer/Shader.cpp index 444cc17f2..7dd83e2d2 100644 --- a/game/graphics/opengl_renderer/Shader.cpp +++ b/game/graphics/opengl_renderer/Shader.cpp @@ -71,4 +71,6 @@ ShaderLibrary::ShaderLibrary() { at(ShaderId::DEBUG_RED) = {"debug_red"}; at(ShaderId::SPRITE_CPU) = {"sprite_cpu"}; at(ShaderId::SPRITE_CPU_AFAIL) = {"sprite_cpu_afail"}; + at(ShaderId::SKY) = {"sky"}; + at(ShaderId::SKY_BLEND) = {"sky_blend"}; } \ No newline at end of file diff --git a/game/graphics/opengl_renderer/Shader.h b/game/graphics/opengl_renderer/Shader.h index 3bd9ac558..cf3326c2e 100644 --- a/game/graphics/opengl_renderer/Shader.h +++ b/game/graphics/opengl_renderer/Shader.h @@ -29,6 +29,8 @@ enum class ShaderId { DEBUG_RED = 4, SPRITE_CPU = 5, SPRITE_CPU_AFAIL = 6, + SKY, + SKY_BLEND, MAX_SHADERS }; diff --git a/game/graphics/opengl_renderer/SkyRenderer.cpp b/game/graphics/opengl_renderer/SkyRenderer.cpp new file mode 100644 index 000000000..740eef400 --- /dev/null +++ b/game/graphics/opengl_renderer/SkyRenderer.cpp @@ -0,0 +1,370 @@ +#include "SkyRenderer.h" +#include "third-party/imgui/imgui.h" +#include "game/graphics/pipelines/opengl.h" +#include "game/graphics/opengl_renderer/AdgifHandler.h" +#include "common/log/log.h" + +// The sky texture system blends together sky textures from different levels and times of day +// to create the final sky texture. + +// The sequence is: +// set-display-gs-state 8qw +// copy-sky-textures (between 0 and 8, usually 2.) +// copy-cloud-texture +// set alpha state +// reset display gs state +// and this happens twice: one for each level. Note that the first call to either of the copy +// functions will use "draw" mode instead of "blend" +// The results are stored in special sky textures. + +// size of the sky texture is 64x96, but it's actually a 64x64 (clouds) and a 32x32 (sky) + +SkyTextureHandler::SkyTextureHandler(const std::string& name, BucketId my_id) + : BucketRenderer(name, my_id) { + // generate textures for sky blending + glGenFramebuffers(2, m_framebuffers); + glGenTextures(2, m_textures); + + GLint old_framebuffer; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_framebuffer); + + // setup the framebuffers + for (int i = 0; i < 2; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers[i]); + glBindTexture(GL_TEXTURE_2D, m_textures[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_sizes[i], m_sizes[i], 0, GL_RGBA, + GL_UNSIGNED_INT_8_8_8_8_REV, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textures[i], 0); + GLenum draw_buffers[1] = {GL_COLOR_ATTACHMENT0}; + glDrawBuffers(1, draw_buffers); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + lg::error("SkyTextureHandler setup failed."); + } + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glGenBuffers(1, &m_gl_vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, m_gl_vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * 6, nullptr, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, old_framebuffer); + + // we only draw squares + m_vertex_data[0].x = 0; + m_vertex_data[0].y = 0; + + m_vertex_data[1].x = 1; + m_vertex_data[1].y = 0; + + m_vertex_data[2].x = 0; + m_vertex_data[2].y = 1; + + m_vertex_data[3].x = 1; + m_vertex_data[3].y = 0; + + m_vertex_data[4].x = 0; + m_vertex_data[4].y = 1; + + m_vertex_data[5].x = 1; + m_vertex_data[5].y = 1; +} + +SkyTextureHandler::~SkyTextureHandler() { + glDeleteFramebuffers(2, m_framebuffers); + glDeleteBuffers(1, &m_gl_vertex_buffer); + glDeleteTextures(2, m_textures); +} + +void SkyTextureHandler::handle_sky_copies(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { + if (!m_enabled) { + while (dma.current_tag().qwc == 6) { + dma.read_and_advance(); + dma.read_and_advance(); + } + return; + } + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + GLint old_viewport[4]; + glGetIntegerv(GL_VIEWPORT, old_viewport); + + GLint old_framebuffer; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_framebuffer); + + while (dma.current_tag().qwc == 6) { + // assuming that the vif and gif-tag is correct + auto setup_data = dma.read_and_advance(); + if (render_state->dump_playback) { + // continue; + } + + // first is an adgif + AdgifHelper adgif(setup_data.data + 16); + assert(adgif.is_normal_adgif()); + assert(adgif.alpha().data == 0x8000000068); // Cs + Cd + + // next is the actual draw + auto draw_data = dma.read_and_advance(); + assert(draw_data.size_bytes == 6 * 16); + + GifTag draw_or_blend_tag(draw_data.data); + + // the first draw overwrites the previous frame's draw by disabling alpha blend (ABE = 0) + bool is_first_draw = !GsPrim(draw_or_blend_tag.prim()).abe(); + + // here's we're relying on the format of the drawing to get the alpha/offset. + u32 coord; + u32 intensity; + memcpy(&coord, draw_data.data + (5 * 16), 4); + memcpy(&intensity, draw_data.data + 16, 4); + + // we didn't parse the render-to-texture setup earlier, so we need a way to tell sky from + // clouds. we can look at the drawing coordinates to tell - the sky is smaller than the clouds. + int buffer_idx = 0; + if (coord == 0x200) { + // sky + buffer_idx = 0; + } else if (coord == 0x400) { + buffer_idx = 1; + } else { + assert(false); // bad data + } + + // look up the source texture + auto tex = render_state->texture_pool->lookup(adgif.tex0().tbp0()); + assert(tex); + + if (!tex->on_gpu) { + render_state->texture_pool->upload_to_gpu(tex); + } + + // setup for rendering! + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers[buffer_idx]); + glViewport(0, 0, m_sizes[buffer_idx], m_sizes[buffer_idx]); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textures[buffer_idx], 0); + render_state->shaders[ShaderId::SKY_BLEND].activate(); + + // if the first is set, it disables alpha. we can just clear here, so it's easier to find + // in renderdoc. + if (is_first_draw) { + float clear[4] = {0, 0, 0, 0}; + glClearBufferfv(GL_COLOR, 0, clear); + } + + // intensities should be 0-128 (maybe higher is okay, but I don't see how this could be + // generated with the GOAL code.) + assert(intensity <= 128); + + // todo - could do this on the GPU, but probably not worth it for <20 triangles... + float intensity_float = intensity / 128.f; + for (auto& vert : m_vertex_data) { + vert.intensity = intensity_float; + } + + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + + // will add. + glBlendFunc(GL_ONE, GL_ONE); + + // setup draw data + glBindBuffer(GL_ARRAY_BUFFER, m_gl_vertex_buffer); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * 6, m_vertex_data); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, // location 0 in the shader + 3, // 3 floats per vert + GL_FLOAT, // floats + GL_TRUE, // normalized, ignored, + 0, // tightly packed + 0 + + ); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tex->gpu_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glUniform1i(glGetUniformLocation(render_state->shaders[ShaderId::SKY_BLEND].id(), "T0"), 0); + + // Draw a sqaure + glDrawArrays(GL_TRIANGLES, 0, 6); + + // 1 draw, 2 triangles + prof.add_draw_call(1); + prof.add_tri(2); + + if (buffer_idx == 0) { + if (is_first_draw) { + m_stats.sky_draws++; + } else { + m_stats.sky_blends++; + } + } else { + if (is_first_draw) { + m_stats.cloud_draws++; + } else { + m_stats.cloud_blends++; + } + } + } + + // put in pool. + for (int i = 0; i < 2; i++) { + // todo - these are hardcoded and rely on the vram layout. + u32 tbp = i == 0 ? 8064 : 8096; + + // lookup existing, or create a new entry + TextureRecord* tex = render_state->texture_pool->lookup(tbp); + if (!tex) { + auto tsp = std::make_shared(); + render_state->texture_pool->set_texture(tbp, tsp); + tex = tsp.get(); + } + + // update it + tex->gpu_texture = m_textures[i]; + tex->on_gpu = true; + tex->only_on_gpu = true; + tex->do_gc = false; + tex->w = m_sizes[i]; + tex->h = m_sizes[i]; + tex->name = fmt::format("PC-SKY-{}", i); + } + + glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]); + glBindFramebuffer(GL_FRAMEBUFFER, old_framebuffer); + glBindVertexArray(0); + glDeleteVertexArrays(1, &vao); +} + +void SkyTextureHandler::render(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { + m_stats = {}; + // First thing should be a NEXT with two nops. this is a jump from buckets to sprite data + auto data0 = dma.read_and_advance(); + assert(data0.vif1() == 0); + assert(data0.vif0() == 0); + assert(data0.size_bytes == 0); + + if (dma.current_tag().kind == DmaTag::Kind::CALL) { + // sky renderer didn't run, let's just get out of here. + for (int i = 0; i < 4; i++) { + dma.read_and_advance(); + } + assert(dma.current_tag_offset() == render_state->next_bucket); + return; + } + + // first is the set-display-gs-state + auto set_display = dma.read_and_advance(); + assert(set_display.size_bytes == 8 * 16); + + handle_sky_copies(dma, render_state, prof); + + auto reset_alpha = dma.read_and_advance(); + assert(reset_alpha.size_bytes == 16 * 2); + + auto reset_gs = dma.read_and_advance(); + assert(reset_gs.size_bytes == 16 * 8); + + auto empty = dma.read_and_advance(); + assert(empty.size_bytes == 0); + assert(empty.vif0() == 0); + assert(empty.vif1() == 0); + + assert(dma.current_tag().kind == DmaTag::Kind::CALL); + dma.read_and_advance(); + dma.read_and_advance(); // cnt + assert(dma.current_tag().kind == DmaTag::Kind::RET); + dma.read_and_advance(); // ret + dma.read_and_advance(); // ret + assert(dma.current_tag_offset() == render_state->next_bucket); +} + +void SkyTextureHandler::draw_debug_window() { + ImGui::Separator(); + ImGui::Text("Draw/Blend ( sky ): %d/%d", m_stats.sky_draws, m_stats.sky_blends); + ImGui::Text("Draw/Blend (cloud): %d/%d", m_stats.cloud_draws, m_stats.cloud_blends); +} + +SkyRenderer::SkyRenderer(const std::string& name, BucketId my_id) + : BucketRenderer(name, my_id), + m_direct_renderer("sky-direct", my_id, 100, DirectRenderer::Mode::NORMAL) {} + +void SkyRenderer::render(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { + m_direct_renderer.reset_state(); + m_frame_stats = {}; + // First thing should be a NEXT with two nops. this is a jump from buckets to sprite data + auto data0 = dma.read_and_advance(); + assert(data0.vif1() == 0); + assert(data0.vif0() == 0); + assert(data0.size_bytes == 0); + + if (dma.current_tag().kind == DmaTag::Kind::CALL) { + // sky renderer didn't run, let's just get out of here. + for (int i = 0; i < 4; i++) { + dma.read_and_advance(); + } + assert(dma.current_tag_offset() == render_state->next_bucket); + return; + } + + auto setup_packet = dma.read_and_advance(); + assert(setup_packet.size_bytes == 16 * 4); + m_direct_renderer.render_gif(setup_packet.data, setup_packet.size_bytes, render_state, prof); + + auto draw_setup_packet = dma.read_and_advance(); + assert(draw_setup_packet.size_bytes == 16 * 5); + m_direct_renderer.render_gif(draw_setup_packet.data, draw_setup_packet.size_bytes, render_state, + prof); + // tex0: tbw = 1, th = 5, hw = 5, sky-base-block + // mmag/mmin = 1 + // clamp + // drawing. + int dma_idx = 0; + while (dma.current_tag().kind == DmaTag::Kind::CNT) { + m_frame_stats.gif_packets++; + auto data = dma.read_and_advance(); + assert(data.vifcode0().kind == VifCode::Kind::NOP); + assert(data.vifcode1().kind == VifCode::Kind::DIRECT); + assert(data.vifcode1().immediate == data.size_bytes / 16); + if (m_enabled) { + m_direct_renderer.render_gif(data.data, data.size_bytes, render_state, prof); + } + dma_idx++; + } + + m_direct_renderer.flush_pending(render_state, prof); + + auto empty = dma.read_and_advance(); + assert(empty.size_bytes == 0); + assert(empty.vif0() == 0); + assert(empty.vif1() == 0); + + assert(dma.current_tag().kind == DmaTag::Kind::CALL); + dma.read_and_advance(); + dma.read_and_advance(); // cnt + assert(dma.current_tag().kind == DmaTag::Kind::RET); + dma.read_and_advance(); // ret + dma.read_and_advance(); // ret + assert(dma.current_tag_offset() == render_state->next_bucket); +} + +void SkyRenderer::draw_debug_window() { + ImGui::Separator(); + ImGui::Text("GIF packets: %d", m_frame_stats.gif_packets); + + if (ImGui::TreeNode("direct")) { + m_direct_renderer.draw_debug_window(); + ImGui::TreePop(); + } +} diff --git a/game/graphics/opengl_renderer/SkyRenderer.h b/game/graphics/opengl_renderer/SkyRenderer.h new file mode 100644 index 000000000..32338b29f --- /dev/null +++ b/game/graphics/opengl_renderer/SkyRenderer.h @@ -0,0 +1,57 @@ + +#pragma once +#include "game/graphics/opengl_renderer/BucketRenderer.h" +#include "game/graphics/opengl_renderer/DirectRenderer.h" + +/*! + * Handles texture blending for the sky. + * Will insert the result texture into the texture pool. + */ +class SkyTextureHandler : public BucketRenderer { + public: + SkyTextureHandler(const std::string& name, BucketId my_id); + void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; + void draw_debug_window() override; + ~SkyTextureHandler(); + + private: + void handle_sky_copies(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof); + GLuint m_framebuffers[2]; // sky, clouds + GLuint m_textures[2]; // sky, clouds + int m_sizes[2] = {32, 64}; + GLuint m_gl_vertex_buffer; + + struct Vertex { + float x = 0; + float y = 0; + float intensity = 0; + }; + + struct FrameStats { + int sky_draws = 0; + int cloud_draws = 0; + int sky_blends = 0; + int cloud_blends = 0; + } m_stats; + + Vertex m_vertex_data[6]; +}; + +/*! + * Handles sky drawing. + */ +class SkyRenderer : public BucketRenderer { + public: + SkyRenderer(const std::string& name, BucketId my_id); + void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; + void draw_debug_window() override; + + private: + DirectRenderer m_direct_renderer; + + struct FrameStats { + int gif_packets = 0; + } m_frame_stats; +}; \ No newline at end of file diff --git a/game/graphics/opengl_renderer/SpriteRenderer.cpp b/game/graphics/opengl_renderer/SpriteRenderer.cpp index 686078b76..e3556fef7 100644 --- a/game/graphics/opengl_renderer/SpriteRenderer.cpp +++ b/game/graphics/opengl_renderer/SpriteRenderer.cpp @@ -147,15 +147,17 @@ SpriteRenderer::SpriteRenderer(const std::string& name, BucketId my_id) * Run the sprite distorter. Currently nothing uses sprite-distorter so this just skips through * the table upload stuff that runs every frame, even if there are no sprites. */ -void SpriteRenderer::render_distorter(DmaFollower& dma, SharedRenderState* render_state) { +void SpriteRenderer::render_distorter(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { // Next thing should be the sprite-distorter setup m_direct_renderer.reset_state(); while (dma.current_tag().qwc != 7) { auto direct_data = dma.read_and_advance(); m_direct_renderer.render_vif(direct_data.vif0(), direct_data.vif1(), direct_data.data, - direct_data.size_bytes, render_state); + direct_data.size_bytes, render_state, prof); } - m_direct_renderer.flush_pending(render_state); + m_direct_renderer.flush_pending(render_state, prof); auto sprite_distorter_direct_setup = dma.read_and_advance(); assert(sprite_distorter_direct_setup.vifcode0().kind == VifCode::Kind::NOP); assert(sprite_distorter_direct_setup.vifcode1().kind == VifCode::Kind::DIRECT); @@ -233,9 +235,41 @@ void SpriteRenderer::render_3d(DmaFollower& dma) { // TODO } -void SpriteRenderer::render_2d_group0(DmaFollower& dma) { +void SpriteRenderer::render_2d_group0(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { (void)dma; - // TODO + while (looks_like_2d_chunk_start(dma)) { + m_debug_stats.blocks_2d_grp0++; + // 4 packets per chunk + + // first is the header + u32 sprite_count = process_sprite_chunk_header(dma); + m_debug_stats.count_2d_grp0 += sprite_count; + + // second is the vector data + u32 expected_vec_size = sizeof(SpriteVecData2d) * sprite_count; + auto vec_data = dma.read_and_advance(); + assert(expected_vec_size <= sizeof(m_vec_data_2d)); + unpack_to_no_stcycl(&m_vec_data_2d, vec_data, VifCode::Kind::UNPACK_V4_32, expected_vec_size, + SpriteDataMem::Vector, false, true); + + // third is the adgif data + u32 expected_adgif_size = sizeof(AdGifData) * sprite_count; + auto adgif_data = dma.read_and_advance(); + assert(expected_adgif_size <= sizeof(m_adgif)); + unpack_to_no_stcycl(&m_adgif, adgif_data, VifCode::Kind::UNPACK_V4_32, expected_adgif_size, + SpriteDataMem::Adgif, false, true); + + // fourth is the actual run!!!!! + auto run = dma.read_and_advance(); + assert(run.vifcode0().kind == VifCode::Kind::NOP); + assert(run.vifcode1().kind == VifCode::Kind::MSCAL); + assert(run.vifcode1().immediate == SpriteProgMem::Sprites2dGrp0); + if (m_enabled) { + do_2d_group0_block_cpu(sprite_count, render_state, prof); + } + } } void SpriteRenderer::render_fake_shadow(DmaFollower& dma) { @@ -249,7 +283,9 @@ void SpriteRenderer::render_fake_shadow(DmaFollower& dma) { /*! * Handle DMA data for group1 2d's (HUD) */ -void SpriteRenderer::render_2d_group1(DmaFollower& dma, SharedRenderState* render_state) { +void SpriteRenderer::render_2d_group1(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { // one time matrix data upload auto mat_upload = dma.read_and_advance(); bool mat_ok = verify_unpack_with_stcycl(mat_upload, VifCode::Kind::UNPACK_V4_32, 4, 4, 80, @@ -275,7 +311,7 @@ void SpriteRenderer::render_2d_group1(DmaFollower& dma, SharedRenderState* rende SpriteDataMem::Vector, false, true); // third is the adgif data - u32 expected_adgif_size = sizeof(AdGif) * sprite_count; + u32 expected_adgif_size = sizeof(AdGifData) * sprite_count; auto adgif_data = dma.read_and_advance(); assert(expected_adgif_size <= sizeof(m_adgif)); unpack_to_no_stcycl(&m_adgif, adgif_data, VifCode::Kind::UNPACK_V4_32, expected_adgif_size, @@ -287,12 +323,14 @@ void SpriteRenderer::render_2d_group1(DmaFollower& dma, SharedRenderState* rende assert(run.vifcode1().kind == VifCode::Kind::MSCAL); assert(run.vifcode1().immediate == SpriteProgMem::Sprites2dHud); if (m_enabled) { - do_2d_group1_block_cpu(sprite_count, render_state); + do_2d_group1_block_cpu(sprite_count, render_state, prof); } } } -void SpriteRenderer::render(DmaFollower& dma, SharedRenderState* render_state) { +void SpriteRenderer::render(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { m_debug_stats = {}; // First thing should be a NEXT with two nops. this is a jump from buckets to sprite data auto data0 = dma.read_and_advance(); @@ -310,7 +348,10 @@ void SpriteRenderer::render(DmaFollower& dma, SharedRenderState* render_state) { } // First is the distorter - render_distorter(dma, render_state); + { + auto child = prof.make_scoped_child("distorter"); + render_distorter(dma, render_state, child); + } // next, sprite frame setup. handle_sprite_frame_setup(dma); @@ -319,15 +360,21 @@ void SpriteRenderer::render(DmaFollower& dma, SharedRenderState* render_state) { render_3d(dma); // 2d draw - render_2d_group0(dma); + m_sprite_renderer.reset_state(); + { + auto child = prof.make_scoped_child("2d-group0"); + render_2d_group0(dma, render_state, child); + } // shadow draw render_fake_shadow(dma); // 2d draw (HUD) - m_sprite_renderer.reset_state(); - render_2d_group1(dma, render_state); - m_sprite_renderer.flush_pending(render_state); + { + auto child = prof.make_scoped_child("2d-group1"); + render_2d_group1(dma, render_state, child); + m_sprite_renderer.flush_pending(render_state, child); + } // TODO finish this up. // fmt::print("next bucket is 0x{}\n", render_state->next_bucket); @@ -345,6 +392,8 @@ void SpriteRenderer::render(DmaFollower& dma, SharedRenderState* render_state) { void SpriteRenderer::draw_debug_window() { ImGui::Separator(); + ImGui::Text("2D Group 0 (World) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp0, + m_debug_stats.count_2d_grp0); ImGui::Text("2D Group 1 (HUD) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp1, m_debug_stats.count_2d_grp1); ImGui::Checkbox("Extra Debug", &m_extra_debug); @@ -398,9 +447,11 @@ void imgui_vec(const Vector4f& vec, const char* name = nullptr, int indent = 0) * - do this math on the GPU * - special case the primitive buffer stuff */ -void SpriteRenderer::do_2d_group1_block_cpu(u32 count, SharedRenderState* render_state) { +void SpriteRenderer::do_2d_group1_block_cpu(u32 count, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { if (m_extra_debug) { - ImGui::Begin("Sprite Extra Debug"); + ImGui::Begin("Sprite Extra Debug 2d_1"); } // set up double buffering @@ -448,6 +499,9 @@ void SpriteRenderer::do_2d_group1_block_cpu(u32 count, SharedRenderState* render // lqi.xyzw vf01, vi02 | nop Vector4f pos_vf01 = m_vec_data_2d[sprite_idx].xyz_sx; + if (m_extra_debug) { + imgui_vec(pos_vf01, "POS", 2); + } // lqi.xyzw vf05, vi02 | nop Vector4f flags_vf05 = m_vec_data_2d[sprite_idx].flag_rot_sy; // lqi.xyzw vf11, vi02 | nop @@ -733,7 +787,7 @@ void SpriteRenderer::do_2d_group1_block_cpu(u32 count, SharedRenderState* render // SIXTEEN is xy3int packet.xy3 = xy3_vf22_int; - m_sprite_renderer.render_gif((const u8*)&packet, sizeof(packet), render_state); + m_sprite_renderer.render_gif((const u8*)&packet, sizeof(packet), render_state, prof); if (m_extra_debug) { imgui_vec(vf12_rotated, "vf12", 2); imgui_vec(vf13_rotated_trans, "vf13", 2); @@ -766,4 +820,368 @@ void SpriteRenderer::do_2d_group1_block_cpu(u32 count, SharedRenderState* render if (m_extra_debug) { ImGui::End(); } -} \ No newline at end of file +} + +void SpriteRenderer::do_2d_group0_block_cpu(u32 count, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { + if (m_extra_debug) { + ImGui::Begin("Sprite Extra Debug 2d_0"); + } + + Matrix4f camera_matrix = m_3d_matrix_data.camera; // vf25, vf26, vf27, vf28 + for (u32 sprite_idx = 0; sprite_idx < count; sprite_idx++) { + if (m_extra_debug) { + ImGui::Text("Sprite: %d", sprite_idx); + } + SpriteHud2DPacket packet; + memset(&packet, 0, sizeof(packet)); + // ilw.y vi08, 1(vi02) | nop vi08 = matrix + u32 offset_selector = m_vec_data_2d[sprite_idx].matrix(); + assert(offset_selector == 0 || offset_selector == 1); + // moved this out of the loop. + // lq.xyzw vf25, 900(vi00) | nop vf25 = cam_mat + // lq.xyzw vf26, 901(vi00) | nop + // lq.xyzw vf27, 902(vi00) | nop + // lq.xyzw vf28, 903(vi00) | nop + // lq.xyzw vf30, 904(vi00) | nop vf30 = hvdf_offset + // vf30 + Vector4f hvdf_offset = m_3d_matrix_data.hvdf_offset; + + // lqi.xyzw vf01, vi02 | nop + Vector4f pos_vf01 = m_vec_data_2d[sprite_idx].xyz_sx; + if (m_extra_debug) { + imgui_vec(pos_vf01, "POS", 2); + } + // lqi.xyzw vf05, vi02 | nop + Vector4f flags_vf05 = m_vec_data_2d[sprite_idx].flag_rot_sy; + // lqi.xyzw vf11, vi02 | nop + Vector4f color_vf11 = m_vec_data_2d[sprite_idx].rgba; + + // multiplications from the right column + Vector4f transformed_pos_vf02 = matrix_transform(camera_matrix, pos_vf01); + + Vector4f scales_vf01 = pos_vf01; // now used for something else. + // lq.xyzw vf12, 1020(vi00) | mulaw.xyzw ACC, vf28, vf00 + // vf12 is fog consts + Vector4f fog_consts_vf12(m_frame_data.fog_min, m_frame_data.fog_max, m_frame_data.max_scale, + m_frame_data.bonus); + // ilw.y vi08, 1(vi02) | maddax.xyzw ACC, vf25, vf01 + // load offset selector for the next round. + // nop | madday.xyzw ACC, vf26, vf01 + // nop | maddz.xyzw vf02, vf27, vf01 + + // move.w vf05, vf00 | addw.z vf01, vf00, vf05 + // scales_vf01.z = sy + scales_vf01.z() = flags_vf05.w(); // start building the scale vector + flags_vf05.w() = 1.f; // what are we building in flags right now?? + + // nop | nop + // div Q, vf31.x, vf02.w | muly.z vf05, vf05, vf31 + float Q = m_frame_data.pfog0 / transformed_pos_vf02.w(); + flags_vf05.z() *= m_frame_data.deg_to_rad; + // nop | mul.xyzw vf03, vf02, vf29 + Vector4f scaled_pos_vf03 = transformed_pos_vf02.elementwise_multiply(m_frame_data.hmge_scale); + // nop | nop + // nop | nop + // nop | mulz.z vf04, vf05, vf05 (ts) + // fmt::print("rot is {} degrees\n", flags_vf05.z() * 360.0 / (2.0 * M_PI)); + + // the load is for rotation stuff, + // lq.xyzw vf14, 1001(vi00) | clipw.xyz vf03, vf03 (used for fcand) + // iaddi vi06, vi00, 0x1 | adda.xyzw ACC, vf11, vf11 (used for fmand) + + // upcoming fcand with 0x3f, that checks all of them. + bool fcand_result = clip_xyz_plus_minus(scaled_pos_vf03); + bool fmand_result = color_vf11.w() == 0; // (really w+w, but I don't think it matters?) + + // L8: + // xgkick double buffer setup + // ior vi05, vi15, vi00 | mul.zw vf01, vf01, Q + scales_vf01.z() *= Q; // sy + scales_vf01.w() *= Q; // sx + + // lq.xyzw vf06, 998(vi00) | mulz.xyzw vf15, vf05, vf04 (ts) + auto adgif_vf06 = m_frame_data.adgif_giftag; + + // lq.xyzw vf14, 1002(vi00) ts| mula.xyzw ACC, vf05, vf14 (ts) + + // fmand vi01, vi06 | mul.xyz vf02, vf02, Q + transformed_pos_vf02.x() *= Q; + transformed_pos_vf02.y() *= Q; + transformed_pos_vf02.z() *= Q; + + // if (m_extra_debug) { + // imgui_vec(transformed_pos_vf02, "scaled xf"); + // } + + // ibne vi00, vi01, L10 | addz.x vf01, vf00, vf01 + scales_vf01.x() = scales_vf01.z(); // = sy + if (fmand_result) { + if (m_extra_debug) { + ImGui::TextColored(ImVec4(0.8, 0.2, 0.2, 1.0), "fmand (1) reject"); + ImGui::Separator(); + } + continue; // reject! + } + + // lqi.xyzw vf07, vi03 | mulz.xyzw vf16, vf15, vf04 (ts) + // vf07 is first use adgif + + // lq.xyzw vf14, 1003(vi00) | madda.xyzw ACC, vf15, vf14 (ts both) + + // lqi.xyzw vf08, vi03 | add.xyzw vf10, vf02, vf30 + // vf08 is second user adgif + Vector4f offset_pos_vf10 = transformed_pos_vf02 + hvdf_offset; + // if (m_extra_debug) { + // ImGui::Text("sel %d", offset_selector); + // //ImGui::Text("hvdf off z: %f tf/w z: %f", hvdf_offset.z(), transformed_pos_vf02.z()); + // imgui_vec(hvdf_offset, "hvdf"); + // imgui_vec(transformed_pos_vf02, "tf'd"); + // } + + // lqi.xyzw vf09, vi03 | mulw.x vf01, vf01, vf01 + // vf09 is third user adgif + scales_vf01.x() *= scales_vf01.w(); // x = sx * sy + + // sqi.xyzw vf06, vi05 | mulz.xyzw vf15, vf16, vf04 (ts) + // FIRST ADGIF IS adgif_vf06 + packet.adgif_giftag = adgif_vf06; + + // lq.xyzw vf14, 1004(vi00) | madda.xyzw ACC, vf16, vf14 (ts both) + + // sqi.xyzw vf07, vi05 | maxx.w vf10, vf10, vf12 + // SECOND ADGIF is first user + // just do all 5 now. + packet.user_adgif = m_adgif[sprite_idx]; + + offset_pos_vf10.w() = std::max(offset_pos_vf10.w(), m_frame_data.fog_max); + + // sqi.xyzw vf08, vi05 | maxz.zw vf01, vf01, vf31 + // THIRD ADGIF is second user + scales_vf01.z() = std::max(scales_vf01.z(), m_frame_data.min_scale); + scales_vf01.w() = std::max(scales_vf01.w(), m_frame_data.min_scale); + + // sqi.xyzw vf09, vi05 | mulz.xyzw vf16, vf15, vf04 (ts) + // FOURTH ADGIF is third user + + // lq.xyzw vf14, 1005(vi00) | madda.xyzw ACC, vf15, vf14 (ts both) + + // lqi.xyzw vf06, vi03 | mulw.x vf01, vf01, vf31 + // vf06 is fourth user adgif + scales_vf01.x() *= m_frame_data.inv_area; // x = sx * sy * inv_area (area ratio) + + // lqi.xyzw vf07, vi03 | miniy.w vf10, vf10, vf12 + // vf07 is fifth user adgif + offset_pos_vf10.w() = std::min(offset_pos_vf10.w(), m_frame_data.fog_min); + + // lq.xyzw vf08, 999(vi00) | miniz.zw vf01, vf01, vf12 + // vf08 is 2d giftag 1 (NOTE THIS IS DIFFERENT FROM 2d 1)!!!!! + scales_vf01.z() = std::min(scales_vf01.z(), fog_consts_vf12.z()); + scales_vf01.w() = std::min(scales_vf01.w(), fog_consts_vf12.z()); + bool use_first_giftag = offset_selector == 0; + + // ilw.x vi07, -2(vi02) | madd.xyzw vf05, vf16, vf14 + auto flag_vi07 = m_vec_data_2d[sprite_idx].flag(); + Vector4f vf05_sincos(0, 0, std::sin(flags_vf05.z()), std::cos(flags_vf05.z())); + + // lqi.xyzw vf23, vi02 | miniw.x vf01, vf01, vf00 + // pipeline + scales_vf01.x() = std::min(scales_vf01.x(), 1.f); + + // nop | suby.w vf02, vf10, vf12 (unique) + transformed_pos_vf02.w() = offset_pos_vf10.w() - fog_consts_vf12.y(); + + // lqi.xyzw vf24, vi02 | mulx.w vf11, vf11, vf01 + // pipeline + color_vf11.w() *= scales_vf01.x(); // is this right? doesn't this stall?? + + // fcand vi01, 0x3f | mulaw.xyzw ACC, vf28, vf00 + // already computed pipeline + + // lq.xyzw vf17, 1006(vi00) | maddax.xyzw ACC, vf25, vf23 (pipeline) + Vector4f basis_x_vf17 = m_frame_data.basis_x; + + // fmand vi09, vi06 | nop + // ibne vi00, vi09, L6 | nop + if (transformed_pos_vf02.w() != 0) { + if (m_extra_debug) { + ImGui::TextColored(ImVec4(0.8, 0.2, 0.2, 1.0), "fmand (2) trick"); + } + use_first_giftag = false; + } + + // lq.xyzw vf18, 1007(vi00) | madday.xyzw ACC, vf26, vf23 (pipeline) + Vector4f basis_y_vf18 = m_frame_data.basis_y; + + assert(flag_vi07 == 0); + Vector4f* xy_array = m_frame_data.xy_array + flag_vi07; + // lq.xyzw vf19, 980(vi07) | ftoi0.xyzw vf11, vf11 + Vector4f xy0_vf19 = xy_array[0]; + math::Vector color_integer_vf11 = color_vf11.cast(); + + // lq.xyzw vf20, 981(vi07) | maddz.xyzw vf02, vf27, vf23 (pipeline) + Vector4f xy1_vf20 = xy_array[1]; + + // lq.xyzw vf21, 982(vi07) | mulaw.xyzw ACC, vf17, vf05 + Vector4f xy2_vf21 = xy_array[2]; + Vector4f acc = basis_x_vf17 * vf05_sincos.w(); + + // lq.xyzw vf22, 983(vi07) | msubz.xyzw vf12, vf18, vf05 + Vector4f xy3_vf22 = xy_array[3]; + Vector4f vf12_rotated = acc - (basis_y_vf18 * vf05_sincos.z()); + // sq.xyzw vf11, 3(vi05) | mulaz.xyzw ACC, vf17, vf05 + // EIGHTH is color integer + packet.color = color_integer_vf11; + + acc = basis_x_vf17 * vf05_sincos.z(); + + // lqi.xyzw vf11, vi02 | maddw.xyzw vf13, vf18, vf05 + // (pipeline) + Vector4f vf13_rotated_trans = acc + basis_y_vf18 * vf05_sincos.w(); + + // move.w vf24, vf00 | addw.z vf23, vf00, vf24 (pipeline both) + + // div Q, vf31.x, vf02.w | mulw.xyzw vf12, vf12, vf01 + // (pipeline) + vf12_rotated *= scales_vf01.w(); + + // ibne vi00, vi01, L9 | muly.z vf24, vf24, vf31 (pipeline) + if (fcand_result) { + if (m_extra_debug) { + ImGui::TextColored(ImVec4(0.8, 0.2, 0.2, 1.0), "fcand reject"); + ImGui::Separator(); + } + continue; // reject (could move earlier) + } + + // ilw.y vi08, 1(vi02) | mulz.xyzw vf13, vf13, vf01 + // (pipeline) + vf13_rotated_trans *= scales_vf01.z(); + + // LEFT OFF HERE! + + // sqi.xyzw vf06, vi05 | mul.xyzw vf03, vf02, vf29 + // FIFTH is fourth user + + // sqi.xyzw vf07, vi05 | mulaw.xyzw ACC, vf10, vf00 + // SIXTH is fifth user + acc = offset_pos_vf10; + + // sqi.xyzw vf08, vi05 | maddax.xyzw ACC, vf12, vf19 + // SEVENTH is giftag2 + packet.sprite_giftag = + use_first_giftag ? m_frame_data.sprite_2d_giftag : m_frame_data.sprite_2d_giftag2; + acc += vf12_rotated * xy0_vf19.x(); + + // lq.xyzw vf06, 988(vi00) | maddy.xyzw vf19, vf13, vf19 + Vector4f st0_vf06 = m_frame_data.st_array[0]; + xy0_vf19 = acc + vf13_rotated_trans * xy0_vf19.y(); + + // lq.xyzw vf07, 989(vi00) | mulaw.xyzw ACC, vf10, vf00 + Vector4f st1_vf07 = m_frame_data.st_array[1]; + acc = offset_pos_vf10; + + // lq.xyzw vf08, 990(vi00) | maddax.xyzw ACC, vf12, vf20 + Vector4f st2_vf08 = m_frame_data.st_array[2]; + acc += vf12_rotated * xy1_vf20.x(); + + // lq.xyzw vf09, 991(vi00) | maddy.xyzw vf20, vf13, vf20 + Vector4f st3_vf09 = m_frame_data.st_array[3]; + xy1_vf20 = acc + vf13_rotated_trans * xy1_vf20.y(); + + // sq.xyzw vf06, 1(vi05) | mulaw.xyzw ACC, vf10, vf00 + // NINTH is st0 + packet.st0 = st0_vf06; + acc = offset_pos_vf10; + + // sq.xyzw vf07, 3(vi05) | maddax.xyzw ACC, vf12, vf21 + // ELEVEN is st1 + packet.st1 = st1_vf07; + acc += vf12_rotated * xy2_vf21.x(); + + // sq.xyzw vf08, 5(vi05) | maddy.xyzw vf21, vf13, vf21 + // THIRTEEN is st2 + packet.st2 = st2_vf08; + xy2_vf21 = acc + vf13_rotated_trans * xy2_vf21.y(); + + // sq.xyzw vf09, 7(vi05) | mulaw.xyzw ACC, vf10, vf00 + // FIFTEEN is st3 + packet.st3 = st3_vf09; + acc = offset_pos_vf10; + + // nop | maddax.xyzw ACC, vf12, vf22 + acc += vf12_rotated * xy3_vf22.x(); + + // nop | maddy.xyzw vf22, vf13, vf22 + xy3_vf22 = acc + vf13_rotated_trans * xy3_vf22.y(); + + // lq.xyzw vf12, 1020(vi00) | ftoi4.xyzw vf19, vf19 + // (pipeline) + auto xy0_vf19_int = (xy0_vf19 * 16.f).cast(); + + // lq.xyzw vf14, 1001(vi00) | ftoi4.xyzw vf20, vf20 + // (pipeline) + auto xy1_vf20_int = (xy1_vf20 * 16.f).cast(); + + // move.xyzw vf05, vf24 | ftoi4.xyzw vf21, vf21 + // (pipeline) + auto xy2_vf21_int = (xy2_vf21 * 16.f).cast(); + + // move.xyzw vf01, vf23 | ftoi4.xyzw vf22, vf22 + // (pipeline) + auto xy3_vf22_int = (xy3_vf22 * 16.f).cast(); + + if (m_extra_debug) { + u32 zi = xy3_vf22_int.z() >> 4; + ImGui::Text("z (int): 0x%08x %s", zi, zi >= (1 << 24) ? "bad" : ""); + ImGui::Text("z (flt): %f", (double)(((u32)zi) << 8) / UINT32_MAX); + } + + // sq.xyzw vf19, 2(vi05) | mulz.z vf04, vf24, vf24 (pipeline) + // TENTH is xy0int + packet.xy0 = xy0_vf19_int; + // sq.xyzw vf20, 4(vi05) | clipw.xyz vf03, vf03 (pipeline) + // TWELVE is xy1int + packet.xy1 = xy1_vf20_int; + // sq.xyzw vf21, 6(vi05) | nop + // FOURTEEN is xy2int + packet.xy2 = xy2_vf21_int; + // sq.xyzw vf22, 8(vi05) | nop + // SIXTEEN is xy3int + packet.xy3 = xy3_vf22_int; + + m_sprite_renderer.render_gif((const u8*)&packet, sizeof(packet), render_state, prof); + if (m_extra_debug) { + imgui_vec(vf12_rotated, "vf12", 2); + imgui_vec(vf13_rotated_trans, "vf13", 2); + ImGui::Separator(); + } + + // xgkick vi15 | nop + // iaddi vi04, vi04, -0x1 | nop + // iaddiu vi01, vi00, 0x672 | nop + // ibne vi00, vi04, L8 | nop + // isub vi15, vi01, vi15 | adda.xyzw ACC, vf11, vf11 + // nop | nop :e + // nop | nop + // L9: + // iaddi vi04, vi04, -0x1 | nop + // iaddi vi02, vi02, -0x3 | nop + // ibne vi00, vi04, L7 | nop + // nop | nop + // nop | nop :e + // nop | nop + // L10: + // iaddi vi04, vi04, -0x1 | nop + // iaddi vi03, vi03, 0x4 | nop + // ibne vi00, vi04, L7 | nop + // nop | nop + // nop | nop :e + // nop | nop + } + + if (m_extra_debug) { + ImGui::End(); + } +} diff --git a/game/graphics/opengl_renderer/SpriteRenderer.h b/game/graphics/opengl_renderer/SpriteRenderer.h index 2fe6852b6..c67f0f4fa 100644 --- a/game/graphics/opengl_renderer/SpriteRenderer.h +++ b/game/graphics/opengl_renderer/SpriteRenderer.h @@ -27,7 +27,7 @@ struct SpriteFrameData { Vector4f basis_x; Vector4f basis_y; GifTag sprite_3d_giftag; - AdGif screen_shader; + AdGifData screen_shader; GifTag clipped_giftag; Vector4f inv_hmge_scale; Vector4f stq_offset; @@ -117,7 +117,7 @@ enum SpriteDataMem { */ struct SpriteHud2DPacket { GifTag adgif_giftag; // starts the adgif shader. 0 - AdGif user_adgif; // the adgif shader 16 + AdGifData user_adgif; // the adgif shader 16 GifTag sprite_giftag; // 96 math::Vector color; Vector4f st0; @@ -146,18 +146,25 @@ static_assert(sizeof(SpriteFrameData) == 0x290, "SpriteFrameData size"); class SpriteRenderer : public BucketRenderer { public: SpriteRenderer(const std::string& name, BucketId my_id); - void render(DmaFollower& dma, SharedRenderState* render_state) override; + void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; void draw_debug_window() override; static constexpr int SPRITES_PER_CHUNK = 48; private: - void render_distorter(DmaFollower& dma, SharedRenderState* render_state); + void render_distorter(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof); void handle_sprite_frame_setup(DmaFollower& dma); void render_3d(DmaFollower& dma); - void render_2d_group0(DmaFollower& dma); + void render_2d_group0(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof); void render_fake_shadow(DmaFollower& dma); - void render_2d_group1(DmaFollower& dma, SharedRenderState* render_state); - void do_2d_group1_block_cpu(u32 count, SharedRenderState* render_state); + void render_2d_group1(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof); + void do_2d_group1_block_cpu(u32 count, SharedRenderState* render_state, ScopedProfilerNode& prof); + void do_2d_group0_block_cpu(u32 count, SharedRenderState* render_state, ScopedProfilerNode& prof); u8 m_sprite_distorter_setup[7 * 16]; // direct data u8 m_sprite_direct_setup[3 * 16]; @@ -166,9 +173,11 @@ class SpriteRenderer : public BucketRenderer { SpriteHudMatrixData m_hud_matrix_data; SpriteVecData2d m_vec_data_2d[SPRITES_PER_CHUNK]; - AdGif m_adgif[SPRITES_PER_CHUNK]; + AdGifData m_adgif[SPRITES_PER_CHUNK]; struct DebugStats { + int blocks_2d_grp0 = 0; + int count_2d_grp0 = 0; int blocks_2d_grp1 = 0; int count_2d_grp1 = 0; } m_debug_stats; diff --git a/game/graphics/opengl_renderer/TextureUploadHandler.cpp b/game/graphics/opengl_renderer/TextureUploadHandler.cpp index a27bdf574..3ab2c73fc 100644 --- a/game/graphics/opengl_renderer/TextureUploadHandler.cpp +++ b/game/graphics/opengl_renderer/TextureUploadHandler.cpp @@ -7,7 +7,9 @@ TextureUploadHandler::TextureUploadHandler(const std::string& name, BucketId my_id) : BucketRenderer(name, my_id) {} -void TextureUploadHandler::render(DmaFollower& dma, SharedRenderState* render_state) { +void TextureUploadHandler::render(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& /*prof*/) { m_stats = {}; // this is the data we get from the PC Port modification. diff --git a/game/graphics/opengl_renderer/TextureUploadHandler.h b/game/graphics/opengl_renderer/TextureUploadHandler.h index abcfc760d..4087451e9 100644 --- a/game/graphics/opengl_renderer/TextureUploadHandler.h +++ b/game/graphics/opengl_renderer/TextureUploadHandler.h @@ -14,7 +14,7 @@ class TextureUploadHandler : public BucketRenderer { public: TextureUploadHandler(const std::string& name, BucketId my_id); - void render(DmaFollower& dma, SharedRenderState* render_state) override; + void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; void draw_debug_window() override; void serialize(Serializer& ser) override; diff --git a/game/graphics/opengl_renderer/debug_gui.cpp b/game/graphics/opengl_renderer/debug_gui.cpp index 4032a3db8..b29bde737 100644 --- a/game/graphics/opengl_renderer/debug_gui.cpp +++ b/game/graphics/opengl_renderer/debug_gui.cpp @@ -84,10 +84,14 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) { if (ImGui::BeginMenu("Windows")) { ImGui::MenuItem("Frame Time Plot", nullptr, &m_draw_frame_time); ImGui::MenuItem("Render Debug", nullptr, &m_draw_debug); + ImGui::MenuItem("Profiler", nullptr, &m_draw_profiler); ImGui::EndMenu(); } if (ImGui::BeginMenu("Gfx Dump")) { + ImGui::MenuItem("Screenshot Next Frame!", nullptr, &m_want_screenshot); + ImGui::InputText("File", m_screenshot_save_name, 30); + ImGui::Separator(); ImGui::MenuItem("Dump Next Frame!", nullptr, &m_want_save); bool old_replay = m_want_replay; ImGui::MenuItem("Load Saved Dump", nullptr, &m_want_replay); @@ -96,7 +100,7 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) { } ImGui::Separator(); - ImGui::InputText("Filename", m_dump_save_name, 12); + ImGui::InputText("Dump", m_dump_save_name, 12); ImGui::EndMenu(); } } diff --git a/game/graphics/opengl_renderer/debug_gui.h b/game/graphics/opengl_renderer/debug_gui.h index 50901979e..0bf584d66 100644 --- a/game/graphics/opengl_renderer/debug_gui.h +++ b/game/graphics/opengl_renderer/debug_gui.h @@ -39,19 +39,32 @@ class OpenGlDebugGui { void finish_frame(); void draw(const DmaStats& dma_stats); bool should_draw_render_debug() const { return m_draw_debug; } + bool should_draw_profiler() const { return m_draw_profiler; } bool& want_save() { return m_want_save; } bool& want_dump_replay() { return m_want_replay; } bool& want_dump_load() { return m_want_dump_load; } const char* dump_name() const { return m_dump_save_name; } + const char* screenshot_name() const { return m_screenshot_save_name; } bool should_advance_frame() { return m_frame_timer.should_advance_frame(); } + bool get_screenshot_flag() { + if (m_want_screenshot) { + m_want_screenshot = false; + return true; + } + return false; + } + private: FrameTimeRecorder m_frame_timer; bool m_draw_frame_time = false; + bool m_draw_profiler = false; bool m_draw_debug = false; bool m_want_save = false; bool m_want_replay = false; bool m_want_dump_load = false; + bool m_want_screenshot = false; char m_dump_save_name[256] = "dump.bin"; + char m_screenshot_save_name[256] = "screenshot.png"; }; \ No newline at end of file diff --git a/game/graphics/opengl_renderer/shaders/direct_basic_textured.frag b/game/graphics/opengl_renderer/shaders/direct_basic_textured.frag index bc9395f95..bbd642119 100644 --- a/game/graphics/opengl_renderer/shaders/direct_basic_textured.frag +++ b/game/graphics/opengl_renderer/shaders/direct_basic_textured.frag @@ -7,6 +7,7 @@ in vec2 tex_coord; uniform sampler2D tex_T0; void main() { - vec4 T0 = texture(tex_T0, tex_coord); + //vec4 T0 = texture(tex_T0, tex_coord); + vec4 T0 = textureProj(tex_T0, vec3(tex_coord, 1.0)); color = fragment_color * T0 * 2.0; } diff --git a/game/graphics/opengl_renderer/shaders/direct_basic_textured.vert b/game/graphics/opengl_renderer/shaders/direct_basic_textured.vert index 500a6e870..beeff2725 100644 --- a/game/graphics/opengl_renderer/shaders/direct_basic_textured.vert +++ b/game/graphics/opengl_renderer/shaders/direct_basic_textured.vert @@ -2,7 +2,7 @@ layout (location = 0) in vec3 position_in; layout (location = 1) in vec4 rgba_in; -layout (location = 2) in vec2 tex_coord_in; +layout (location = 2) in vec3 tex_coord_in; out vec4 fragment_color; out vec2 tex_coord; @@ -10,5 +10,5 @@ out vec2 tex_coord; void main() { gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z, 1.0); fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w * 2.); - tex_coord = tex_coord_in; + tex_coord = tex_coord_in.xy; } \ No newline at end of file diff --git a/game/graphics/opengl_renderer/shaders/direct_basic_textured_tcc0.frag b/game/graphics/opengl_renderer/shaders/direct_basic_textured_tcc0.frag index 322f8ed78..4b01c977e 100644 --- a/game/graphics/opengl_renderer/shaders/direct_basic_textured_tcc0.frag +++ b/game/graphics/opengl_renderer/shaders/direct_basic_textured_tcc0.frag @@ -3,11 +3,13 @@ out vec4 color; in vec4 fragment_color; -in vec2 tex_coord; +in vec3 tex_coord; uniform sampler2D tex_T0; + void main() { - vec4 T0 = texture(tex_T0, tex_coord); + vec4 T0 = texture(tex_T0, tex_coord.xy / tex_coord.z); + //vec4 T0 = textureProj(tex_T0, vec3(tex_coord.xy, 1.0)); T0.w = 1.0; color = fragment_color * T0 * 2.0; } diff --git a/game/graphics/opengl_renderer/shaders/direct_basic_textured_tcc0.vert b/game/graphics/opengl_renderer/shaders/direct_basic_textured_tcc0.vert index 89764e331..ebec49f2f 100644 --- a/game/graphics/opengl_renderer/shaders/direct_basic_textured_tcc0.vert +++ b/game/graphics/opengl_renderer/shaders/direct_basic_textured_tcc0.vert @@ -2,13 +2,13 @@ layout (location = 0) in vec3 position_in; layout (location = 1) in vec4 rgba_in; -layout (location = 2) in vec2 tex_coord_in; +layout (location = 2) in vec3 tex_coord_in; out vec4 fragment_color; -out vec2 tex_coord; +out vec3 tex_coord; void main() { - gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z, 1.0); + gl_Position = vec4((position_in.x - 0.5) * 16. , -(position_in.y - 0.5) * 32, position_in.z, 1.0); fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.a * 2); tex_coord = tex_coord_in; } \ No newline at end of file diff --git a/game/graphics/opengl_renderer/shaders/sky.frag b/game/graphics/opengl_renderer/shaders/sky.frag new file mode 100644 index 000000000..b2ff0385e --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/sky.frag @@ -0,0 +1,13 @@ +#version 330 core + +out vec4 color; + +in vec4 fragment_color; +in vec3 tex_coord; +uniform sampler2D tex_T0; + +void main() { + vec4 T0 = texture(tex_T0, tex_coord.xy / tex_coord.z); + T0.w = 1.0; + color = fragment_color * T0 * 2.0; +} diff --git a/game/graphics/opengl_renderer/shaders/sky.vert b/game/graphics/opengl_renderer/shaders/sky.vert new file mode 100644 index 000000000..6a188a963 --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/sky.vert @@ -0,0 +1,14 @@ +#version 330 core + +layout (location = 0) in vec3 position_in; +layout (location = 1) in vec4 rgba_in; +layout (location = 2) in vec3 tex_coord_in; + +out vec4 fragment_color; +noperspective out vec3 tex_coord; + +void main() { + gl_Position = vec4((position_in.x - 0.5) * 16. , -(position_in.y - 0.5) * 32, position_in.z, 1.0); + fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.a * 2); + tex_coord = tex_coord_in; +} \ No newline at end of file diff --git a/game/graphics/opengl_renderer/shaders/sky_blend.frag b/game/graphics/opengl_renderer/shaders/sky_blend.frag new file mode 100644 index 000000000..e0b662495 --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/sky_blend.frag @@ -0,0 +1,11 @@ +#version 330 core + +layout(location = 0) out vec4 color; + +in vec3 tex_coord; +uniform sampler2D tex_T0; + +void main() { + vec4 T0 = texture(tex_T0, tex_coord.xy); + color = vec4(((T0 )) * tex_coord.z); +} diff --git a/game/graphics/opengl_renderer/shaders/sky_blend.vert b/game/graphics/opengl_renderer/shaders/sky_blend.vert new file mode 100644 index 000000000..a3f8ab061 --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/sky_blend.vert @@ -0,0 +1,10 @@ +#version 330 core + +layout (location = 0) in vec3 position_in; + +out vec3 tex_coord; + +void main() { + gl_Position = vec4(position_in.x*2 -1, position_in.y*2-1, 0.0, 1.0); + tex_coord = position_in; +} \ No newline at end of file diff --git a/game/graphics/pipelines/opengl.cpp b/game/graphics/pipelines/opengl.cpp index 81fb48c76..ff538c553 100644 --- a/game/graphics/pipelines/opengl.cpp +++ b/game/graphics/pipelines/opengl.cpp @@ -190,6 +190,13 @@ static void gl_kill_display(GfxDisplay* display) { glfwDestroyWindow(display->window_glfw); } +namespace { +std::string make_output_file_name(const std::string& file_name) { + file_util::create_dir_if_needed(file_util::get_file_path({"gfx_dumps"})); + return file_util::get_file_path({"gfx_dumps", file_name}); +} +} // namespace + void make_gfx_dump() { Timer ser_timer; Serializer ser; @@ -203,10 +210,8 @@ void make_gfx_dump() { ser_timer.getMs(), ((double)result.second) / (1 << 20), ((double)compressed.size() / (1 << 20)), compression_timer.getMs()); - file_util::create_dir_if_needed(file_util::get_file_path({"gfx_dumps"})); - file_util::write_binary_file( - file_util::get_file_path({"gfx_dumps", g_gfx_data->debug_gui.dump_name()}), compressed.data(), - compressed.size()); + file_util::write_binary_file(make_output_file_name(g_gfx_data->debug_gui.dump_name()), + compressed.data(), compressed.size()); } void render_game_frame(int width, int height) { @@ -234,9 +239,17 @@ void render_game_frame(int width, int height) { auto& chain = g_gfx_data->dma_copier.get_last_result(); g_gfx_data->frame_idx_of_input_data = g_gfx_data->frame_idx; - g_gfx_data->ogl_renderer.render(DmaFollower(chain.data.data(), chain.start_offset), width, - height, g_gfx_data->debug_gui.should_draw_render_debug(), - false); + RenderOptions options; + options.window_height_px = height; + options.window_width_px = width; + options.draw_render_debug_window = g_gfx_data->debug_gui.should_draw_render_debug(); + options.draw_profiler_window = g_gfx_data->debug_gui.should_draw_profiler(); + options.playing_from_dump = false; + options.save_screenshot = g_gfx_data->debug_gui.get_screenshot_flag(); + if (options.save_screenshot) { + options.screenshot_path = make_output_file_name(g_gfx_data->debug_gui.screenshot_name()); + } + g_gfx_data->ogl_renderer.render(DmaFollower(chain.data.data(), chain.start_offset), options); } // before vsync, mark the chain as rendered. @@ -252,8 +265,8 @@ void render_game_frame(int width, int height) { void render_dump_frame(int width, int height) { Timer deser_timer; if (g_gfx_data->debug_gui.want_dump_load()) { - auto data = file_util::read_binary_file( - file_util::get_file_path({"gfx_dumps", g_gfx_data->debug_gui.dump_name()})); + auto data = + file_util::read_binary_file(make_output_file_name(g_gfx_data->debug_gui.dump_name())); auto decompressed = compression::decompress_zstd(data.data(), data.size()); g_gfx_data->loaded_dump = Serializer(decompressed.data(), decompressed.size()); } @@ -268,8 +281,19 @@ void render_dump_frame(int width, int height) { g_gfx_data->debug_gui.want_dump_load() = false; auto& chain = g_gfx_data->dma_copier.get_last_result(); - g_gfx_data->ogl_renderer.render(DmaFollower(chain.data.data(), chain.start_offset), width, height, - g_gfx_data->debug_gui.should_draw_render_debug(), true); + + RenderOptions options; + options.window_height_px = height; + options.window_width_px = width; + options.draw_render_debug_window = g_gfx_data->debug_gui.should_draw_render_debug(); + options.draw_profiler_window = g_gfx_data->debug_gui.should_draw_profiler(); + options.playing_from_dump = true; + options.save_screenshot = g_gfx_data->debug_gui.get_screenshot_flag(); + if (options.save_screenshot) { + options.screenshot_path = make_output_file_name(g_gfx_data->debug_gui.screenshot_name()); + } + + g_gfx_data->ogl_renderer.render(DmaFollower(chain.data.data(), chain.start_offset), options); } static void gl_render_display(GfxDisplay* display) { @@ -314,8 +338,9 @@ static void gl_render_display(GfxDisplay* display) { // exit if display window was closed if (glfwWindowShouldClose(window)) { - // Display::KillDisplay(window); + std::unique_lock lock(g_gfx_data->sync_mutex); MasterExit = 2; + g_gfx_data->sync_cv.notify_all(); } } @@ -330,7 +355,7 @@ u32 gl_vsync() { std::unique_lock lock(g_gfx_data->sync_mutex); auto init_frame = g_gfx_data->frame_idx_of_input_data; - g_gfx_data->sync_cv.wait(lock, [=] { return g_gfx_data->frame_idx > init_frame; }); + g_gfx_data->sync_cv.wait(lock, [=] { return MasterExit || g_gfx_data->frame_idx > init_frame; }); return g_gfx_data->frame_idx & 1; } diff --git a/game/graphics/texture/TexturePool.cpp b/game/graphics/texture/TexturePool.cpp index db1eac9a1..6accaca91 100644 --- a/game/graphics/texture/TexturePool.cpp +++ b/game/graphics/texture/TexturePool.cpp @@ -36,6 +36,16 @@ std::string GoalTexturePage::print() const { } void TextureRecord::serialize(Serializer& ser) { + if (only_on_gpu) { + assert(on_gpu); + if (ser.is_saving()) { + // we should download the texture and save it. + data.resize(w * h * 4); + glBindTexture(GL_TEXTURE_2D, gpu_texture); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data.data()); + } + } + ser.from_str(&page_name); ser.from_str(&name); ser.from_ptr(&mip_level); @@ -46,6 +56,7 @@ void TextureRecord::serialize(Serializer& ser) { ser.from_ptr(&data_segment); ser.from_ptr(&on_gpu); ser.from_ptr(&do_gc); + ser.from_ptr(&only_on_gpu); ser.from_ptr(&gpu_texture); ser.from_ptr(&dest); ser.from_pod_vector(&data); @@ -53,6 +64,10 @@ void TextureRecord::serialize(Serializer& ser) { ser.from_ptr(&max_a_zero); ser.from_ptr(&min_a_nonzero); ser.from_ptr(&max_a_nonzero); + + if (ser.is_loading()) { + gpu_texture = -1; + } } void TextureData::serialize(Serializer& ser) { @@ -67,6 +82,7 @@ void TextureData::serialize(Serializer& ser) { if (mt4hh_texture) { ser.save(1); // has it. mt4hh_texture->serialize(ser); + } else { ser.save(0); } @@ -75,9 +91,7 @@ void TextureData::serialize(Serializer& ser) { if (has_normal) { normal_texture = std::make_shared(); normal_texture->serialize(ser); - // after deserializing, nothing is on the GPU normal_texture->on_gpu = false; - // there will be a duplicate copy of this texture in the bucket, we want this one to be gc'd normal_texture->do_gc = true; } else { normal_texture.reset(); @@ -284,6 +298,7 @@ void TexturePool::set_texture(u32 location, std::shared_ptr recor if (m_textures.at(location).normal_texture) { if (record->do_gc && m_textures.at(location).normal_texture != record) { m_garbage_textures.push_back(std::move(m_textures[location].normal_texture)); + fmt::print("replace add to garbage list {}\n", m_garbage_textures.back()->name); } } m_textures[location].normal_texture = std::move(record); @@ -356,8 +371,8 @@ void TexturePool::draw_debug_for_tex(const std::string& name, TextureRecord& tex ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.3, 0.8, 0.3, 1.0)); } if (ImGui::TreeNode(name.c_str())) { - ImGui::Text("P: %s sz: %d x %d mip %d GPU? %d psm %d cpsm %d", tex.page_name.c_str(), tex.w, - tex.h, tex.mip_level, tex.on_gpu, tex.psm, tex.cpsm); + ImGui::Text("P: %s sz: %d x %d mip %d GPU? %d psm %d cpsm %d dest %d", tex.page_name.c_str(), + tex.w, tex.h, tex.mip_level, tex.on_gpu, tex.psm, tex.cpsm, tex.dest); if (tex.on_gpu) { ImGui::Image((void*)tex.gpu_texture, ImVec2(tex.w, tex.h)); } else { @@ -401,6 +416,7 @@ void TexturePool::remove_garbage_textures() { for (auto& t : m_garbage_textures) { if (t->on_gpu) { m_most_recent_gc_count_gpu++; + fmt::print("GC {}\n", t->name); t->unload_from_gpu(); } } @@ -409,5 +425,16 @@ void TexturePool::remove_garbage_textures() { void TexturePool::discard(std::shared_ptr tex) { assert(!tex->do_gc); + fmt::print("discard {}\n", tex->name); m_garbage_textures.push_back(tex); +} + +TextureRecord* TexturePool::get_random_texture() { + u32 idx = 8; + for (u32 i = 0; i < m_textures.size(); i++) { + if (m_textures.at((i + idx) % m_textures.size()).normal_texture) { + return m_textures.at((i + idx) % m_textures.size()).normal_texture.get(); + } + } + return nullptr; } \ No newline at end of file diff --git a/game/graphics/texture/TexturePool.h b/game/graphics/texture/TexturePool.h index 65c017d07..650f9614b 100644 --- a/game/graphics/texture/TexturePool.h +++ b/game/graphics/texture/TexturePool.h @@ -16,7 +16,8 @@ struct TextureRecord { u16 w, h; u8 data_segment; bool on_gpu = false; - bool do_gc = true; + bool do_gc = true; // if set, will be unloaded from GPU when another is upload on top + bool only_on_gpu = false; std::vector data; u64 gpu_texture = 0; u32 dest = -1; @@ -124,6 +125,8 @@ class TexturePool { } } + TextureRecord* get_random_texture(); + void upload_to_gpu(TextureRecord* rec); void relocate(u32 destination, u32 source, u32 format); diff --git a/game/kernel/kdgo.cpp b/game/kernel/kdgo.cpp index 639e36c2e..11e13d741 100644 --- a/game/kernel/kdgo.cpp +++ b/game/kernel/kdgo.cpp @@ -364,7 +364,8 @@ void load_and_link_dgo_from_c(const char* name, Ptr heap, u32 linkFla char objName[64]; strcpy(objName, (dgoObj + 4).cast().c()); // name from dgo object header - lg::debug("[link and exec] {} {} {}", objName, lastObjectLoaded, objSize); + lg::debug("[link and exec] {:18s} {} {:6d} heap-use {:8d} {:8d}", objName, lastObjectLoaded, + objSize, kheapused(kglobalheap), kheapused(kdebugheap)); link_and_exec(obj, objName, objSize, heap, linkFlag); // link now! // inform IOP we are done diff --git a/game/kernel/kscheme.cpp b/game/kernel/kscheme.cpp index 90d0c91b2..6ef870a0a 100644 --- a/game/kernel/kscheme.cpp +++ b/game/kernel/kscheme.cpp @@ -23,6 +23,7 @@ #include "common/goal_constants.h" #include "common/log/log.h" #include "common/util/Timer.h" +#include "game/mips2c/mips2c_table.h" //! Controls link mode when EnableMethodSet = 0, MasterDebug = 1, DiskBoot = 0. Will enable a //! warning message if EnableMethodSet = 1 @@ -1712,6 +1713,8 @@ s32 test_function(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { */ s32 InitHeapAndSymbol() { Timer heap_init_timer; + // reset all mips2c functions + Mips2C::gLinkedFunctionTable = {}; // allocate memory for the symbol table auto symbol_table = kmalloc(kglobalheap, 0x20000, KMALLOC_MEMSET, "symbol-table").cast(); diff --git a/game/mips2c/functions/sky_tng.cpp b/game/mips2c/functions/sky_tng.cpp new file mode 100644 index 000000000..219ed3cc9 --- /dev/null +++ b/game/mips2c/functions/sky_tng.cpp @@ -0,0 +1,1112 @@ +//--------------------------MIPS2C--------------------- +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/kscheme.h" + +namespace Mips2C { + +ExecutionContext sky_regs_vfs; +void get_fake_spad_addr(int dst, void* sym_addr, u32 offset, ExecutionContext* c) { + u32 val; + memcpy(&val, sym_addr, 4); + c->gprs[dst].du64[0] = val + offset; +} +} // namespace Mips2C + +// clang-format off +//--------------------------MIPS2C--------------------- +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/kscheme.h" +namespace Mips2C { +namespace init_sky_regs { +struct Cache { + void* math_camera; // *math-camera* + void* sky_tng_data; // *sky-tng-data* +} cache; + +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + bool cop1_bc = false; + c->daddiu(sp, sp, -32); // daddiu sp, sp, -32 + c->sd(fp, 8, sp); // sd fp, 8(sp) + c->mov64(fp, t9); // or fp, t9, r0 + c->load_symbol(v1, cache.math_camera); // lw v1, *math-camera*(s7) + c->daddiu(a0, sp, 16); // daddiu a0, sp, 16 + c->sq(r0, 0, a0); // sq r0, 0(a0) + c->mov64(a1, a0); // or a1, a0, r0 + c->daddiu(a2, v1, 732); // daddiu a2, v1, 732 + c->lq(a2, 0, a2); // lq a2, 0(a2) + c->sq(a2, 0, a1); // sq a2, 0(a1) + c->mtc1(f0, r0); // mtc1 f0, r0 + c->lwc1(f1, 848, v1); // lwc1 f1, 848(v1) + cop1_bc = c->fprs[f0] < c->fprs[f1]; // c.lt.s f0, f1 + bc = !cop1_bc; // bc1f L70 + // nop // sll r0, r0, 0 + if (bc) {goto block_2;} // branch non-likely + + c->fprs[f0] = 2049.0; // lwc1 f0, L98(fp) + c->swc1(f0, 4, a0); // swc1 f0, 4(a0) + c->mfc1(a1, f0); // mfc1 a1, f0 + //beq r0, r0, L71 // beq r0, r0, L71 + // nop // sll r0, r0, 0 + goto block_3; // branch always + + + block_2: + c->fprs[f0] = 2047.0; // lwc1 f0, L100(fp) + c->swc1(f0, 4, a0); // swc1 f0, 4(a0) + c->mfc1(a1, f0); // mfc1 a1, f0 + + block_3: + c->load_symbol(a1, cache.sky_tng_data); // lw a1, *sky-tng-data*(s7) + c->daddiu(a1, a1, 60); // daddiu a1, a1, 60 + c->lwc1(f0, 828, v1); // lwc1 f0, 828(v1) + c->swc1(f0, 0, a1); // swc1 f0, 0(a1) + c->lwc1(f0, 128, v1); // lwc1 f0, 128(v1) + c->swc1(f0, 4, a1); // swc1 f0, 4(a1) + c->lwc1(f0, 124, v1); // lwc1 f0, 124(v1) + c->swc1(f0, 8, a1); // swc1 f0, 8(a1) + c->fprs[f0] = 3071.0; // lwc1 f0, L83(fp) + c->swc1(f0, 12, a1); // swc1 f0, 12(a1) + c->lqc2(vf31, 572, v1); // lqc2 vf31, 572(v1) + c->lqc2(vf30, 588, v1); // lqc2 vf30, 588(v1) + c->lqc2(vf29, 604, v1); // lqc2 vf29, 604(v1) + c->lqc2(vf28, 620, v1); // lqc2 vf28, 620(v1) + c->lqc2(vf14, 700, v1); // lqc2 vf14, 700(v1) + c->lqc2(vf26, 716, v1); // lqc2 vf26, 716(v1) + c->lqc2(vf25, 0, a0); // lqc2 vf25, 0(a0) + c->load_symbol(v1, cache.sky_tng_data); // lw v1, *sky-tng-data*(s7) + c->lqc2(vf13, 60, v1); // lqc2 vf13, 60(v1) + c->vmul(DEST::xyzw, vf31, vf31, vf14); // vmul.xyzw vf31, vf31, vf14 + c->vmul(DEST::xyzw, vf30, vf30, vf14); // vmul.xyzw vf30, vf30, vf14 + c->vmul(DEST::xyzw, vf29, vf29, vf14); // vmul.xyzw vf29, vf29, vf14 + c->vmul(DEST::xyzw, vf28, vf28, vf14); // vmul.xyzw vf28, vf28, vf14 + c->vmove(DEST::z, vf25, vf0); // vmove.z vf25, vf0 + c->vmove(DEST::xyzw, vf24, vf0); // vmove.xyzw vf24, vf0 + c->vmove(DEST::xyzw, vf23, vf0); // vmove.xyzw vf23, vf0 + c->mov128_gpr_vf(v1, vf23); // qmfc2.i v1, vf23 + c->gprs[v0].du64[0] = 0; // or v0, r0, r0 + c->ld(fp, 8, sp); // ld fp, 8(sp) + //jr ra // jr ra + c->daddiu(sp, sp, 32); // daddiu sp, sp, 32 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + end_of_function: + sky_regs_vfs.copy_vfs_from_other(c); + return c->gprs[v0].du64[0]; +} + +void link() { + cache.math_camera = intern_from_c("*math-camera*").c(); + cache.sky_tng_data = intern_from_c("*sky-tng-data*").c(); + gLinkedFunctionTable.reg("init-sky-regs", execute, 256); +} + +} // namespace init_sky_regs +} // namespace Mips2C + +//--------------------------MIPS2C--------------------- +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/kscheme.h" +namespace Mips2C { +namespace set_tex_offset { +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + c->daddiu(sp, sp, -32); // daddiu sp, sp, -32 + c->sd(fp, 8, sp); // sd fp, 8(sp) + c->mov64(fp, t9); // or fp, t9, r0 + c->daddiu(v1, sp, 16); // daddiu v1, sp, 16 + c->sq(r0, 0, v1); // sq r0, 0(v1) + c->fprs[f0] = 0.000015258789; // lwc1 f0, L99(fp) + c->mtc1(f1, a0); // mtc1 f1, a0 + c->cvtsw(f1, f1); // cvt.s.w f1, f1 + c->muls(f0, f0, f1); // mul.s f0, f0, f1 + c->swc1(f0, 0, v1); // swc1 f0, 0(v1) + c->fprs[f0] = 0.000015258789; // lwc1 f0, L99(fp) + c->mtc1(f1, a1); // mtc1 f1, a1 + c->cvtsw(f1, f1); // cvt.s.w f1, f1 + c->muls(f0, f0, f1); // mul.s f0, f0, f1 + c->swc1(f0, 4, v1); // swc1 f0, 4(v1) + c->mtc1(f0, r0); // mtc1 f0, r0 + c->swc1(f0, 8, v1); // swc1 f0, 8(v1) + c->mtc1(f0, r0); // mtc1 f0, r0 + c->swc1(f0, 12, v1); // swc1 f0, 12(v1) + c->lqc2(vf24, 0, v1); // lqc2 vf24, 0(v1) + c->mov128_gpr_vf(v1, vf24); // qmfc2.i v1, vf24 + c->gprs[v0].du64[0] = 0; // or v0, r0, r0 + c->ld(fp, 8, sp); // ld fp, 8(sp) + //jr ra // jr ra + c->daddiu(sp, sp, 32); // daddiu sp, sp, 32 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + end_of_function: + sky_regs_vfs.copy_vfs_from_other(c); + return c->gprs[v0].du64[0]; +} + +void link() { + gLinkedFunctionTable.reg("set-tex-offset", execute, 64); +} + +} // namespace set_tex_offset +} // namespace Mips2C + +//--------------------------MIPS2C--------------------- +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/kscheme.h" +namespace Mips2C { +namespace clip_polygon_against_positive_hyperplane { +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + bool cop1_bc = false; + // nop // sll r0, r0, 0 + c->mov64(t1, t0); // or t1, t0, r0 + c->addiu(t0, r0, 0); // addiu t0, r0, 0 + c->lwc1(f1, 0, t2); // lwc1 f1, 0(t2) + c->daddiu(t2, t2, 48); // daddiu t2, t2, 48 + c->lwc1(f0, 12, a2); // lwc1 f0, 12(a2) + c->mov64(t3, a3); // or t3, a3, r0 + c->lqc2(vf1, 0, a2); // lqc2 vf1, 0(a2) + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + cop1_bc = c->fprs[f0] < c->fprs[f1]; // c.lt.s f0, f1 + c->lqc2(vf2, -32, a2); // lqc2 vf2, -32(a2) + bc = !cop1_bc; // bc1f L60 + c->lqc2(vf3, -16, a2); // lqc2 vf3, -16(a2) + if (bc) {goto block_9;} // branch non-likely + + + block_1: + c->lwc1(f3, 0, t2); // lwc1 f3, 0(t2) + c->daddiu(t2, t2, 48); // daddiu t2, t2, 48 + c->lwc1(f2, 12, a2); // lwc1 f2, 12(a2) + c->daddiu(t1, t1, -1); // daddiu t1, t1, -1 + c->lqc2(vf4, 0, a2); // lqc2 vf4, 0(a2) + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + cop1_bc = c->fprs[f2] < c->fprs[f3]; // c.lt.s f2, f3 + c->lqc2(vf5, -32, a2); // lqc2 vf5, -32(a2) + bc = !cop1_bc; // bc1f L58 + c->lqc2(vf6, -16, a2); // lqc2 vf6, -16(a2) + if (bc) {goto block_6;} // branch non-likely + + bc = c->sgpr64(t1) == 0; // beq t1, r0, L64 + // nop // sll r0, r0, 0 + if (bc) {goto block_17;} // branch non-likely + + + block_3: + c->lwc1(f1, 0, t2); // lwc1 f1, 0(t2) + c->daddiu(t2, t2, 48); // daddiu t2, t2, 48 + c->lwc1(f0, 12, a2); // lwc1 f0, 12(a2) + c->daddiu(t1, t1, -1); // daddiu t1, t1, -1 + c->lqc2(vf1, 0, a2); // lqc2 vf1, 0(a2) + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + cop1_bc = c->fprs[f0] < c->fprs[f1]; // c.lt.s f0, f1 + c->lqc2(vf2, -32, a2); // lqc2 vf2, -32(a2) + bc = !cop1_bc; // bc1f L59 + c->lqc2(vf3, -16, a2); // lqc2 vf3, -16(a2) + if (bc) {goto block_8;} // branch non-likely + + bc = c->sgpr64(t1) != 0; // bne t1, r0, L56 + // nop // sll r0, r0, 0 + if (bc) {goto block_1;} // branch non-likely + + //beq r0, r0, L64 // beq r0, r0, L64 + // nop // sll r0, r0, 0 + goto block_17; // branch always + + + block_6: + c->subs(f7, f0, f1); // sub.s f7, f0, f1 + c->vsub(DEST::xyzw, vf7, vf4, vf1); // vsub.xyzw vf7, vf4, vf1 + c->subs(f8, f2, f3); // sub.s f8, f2, f3 + c->vsub(DEST::xyzw, vf8, vf5, vf2); // vsub.xyzw vf8, vf5, vf2 + c->subs(f5, f7, f8); // sub.s f5, f7, f8 + c->vsub(DEST::xyzw, vf9, vf6, vf3); // vsub.xyzw vf9, vf6, vf3 + c->divs(f6, f7, f5); // div.s f6, f7, f5 + c->daddiu(a3, a3, 48); // daddiu a3, a3, 48 + c->mfc1(v1, f6); // mfc1 v1, f6 + c->mov128_vf_gpr(vf10, v1); // qmtc2.i vf10, v1 + c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 + c->vmula_bc(DEST::xyzw, BC::w, vf1, vf0); // vmulaw.xyzw acc, vf1, vf0 + c->daddiu(t6, s7, 8); // daddiu t6, s7, 8 + c->vmadd_bc(DEST::xyzw, BC::x, vf7, vf7, vf10); // vmaddx.xyzw vf7, vf7, vf10 + // nop // sll r0, r0, 0 + c->vmula_bc(DEST::xyzw, BC::w, vf2, vf0); // vmulaw.xyzw acc, vf2, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf8, vf8, vf10); // vmaddx.xyzw vf8, vf8, vf10 + // nop // sll r0, r0, 0 + c->vmula_bc(DEST::xyzw, BC::w, vf3, vf0); // vmulaw.xyzw acc, vf3, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf9, vf9, vf10); // vmaddx.xyzw vf9, vf9, vf10 + // nop // sll r0, r0, 0 + c->sqc2(vf7, -48, a3); // sqc2 vf7, -48(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf8, -32, a3); // sqc2 vf8, -32(a3) + // nop // sll r0, r0, 0 + bc = c->sgpr64(t1) != 0; // bne t1, r0, L61 + c->sqc2(vf9, -16, a3); // sqc2 vf9, -16(a3) + if (bc) {goto block_11;} // branch non-likely + + //beq r0, r0, L64 // beq r0, r0, L64 + // nop // sll r0, r0, 0 + goto block_17; // branch always + + + block_8: + c->subs(f7, f0, f1); // sub.s f7, f0, f1 + c->vsub(DEST::xyzw, vf7, vf1, vf4); // vsub.xyzw vf7, vf1, vf4 + c->subs(f8, f2, f3); // sub.s f8, f2, f3 + c->vsub(DEST::xyzw, vf8, vf2, vf5); // vsub.xyzw vf8, vf2, vf5 + c->subs(f5, f8, f7); // sub.s f5, f8, f7 + c->vsub(DEST::xyzw, vf9, vf3, vf6); // vsub.xyzw vf9, vf3, vf6 + c->divs(f6, f8, f5); // div.s f6, f8, f5 + c->daddiu(a3, a3, 48); // daddiu a3, a3, 48 + c->mfc1(v1, f6); // mfc1 v1, f6 + c->mov128_vf_gpr(vf10, v1); // qmtc2.i vf10, v1 + c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 + c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); // vmulaw.xyzw acc, vf4, vf0 + c->daddiu(t6, s7, 8); // daddiu t6, s7, 8 + c->vmadd_bc(DEST::xyzw, BC::x, vf7, vf7, vf10); // vmaddx.xyzw vf7, vf7, vf10 + // nop // sll r0, r0, 0 + c->vmula_bc(DEST::xyzw, BC::w, vf5, vf0); // vmulaw.xyzw acc, vf5, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf8, vf8, vf10); // vmaddx.xyzw vf8, vf8, vf10 + // nop // sll r0, r0, 0 + c->vmula_bc(DEST::xyzw, BC::w, vf6, vf0); // vmulaw.xyzw acc, vf6, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf9, vf9, vf10); // vmaddx.xyzw vf9, vf9, vf10 + // nop // sll r0, r0, 0 + c->sqc2(vf7, -48, a3); // sqc2 vf7, -48(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf8, -32, a3); // sqc2 vf8, -32(a3) + // nop // sll r0, r0, 0 + bc = c->sgpr64(t1) == 0; // beq t1, r0, L64 + c->sqc2(vf9, -16, a3); // sqc2 vf9, -16(a3) + if (bc) {goto block_17;} // branch non-likely + + + block_9: + c->lwc1(f3, 0, t2); // lwc1 f3, 0(t2) + c->daddiu(t2, t2, 48); // daddiu t2, t2, 48 + c->lwc1(f2, 12, a2); // lwc1 f2, 12(a2) + c->daddiu(t1, t1, -1); // daddiu t1, t1, -1 + c->lqc2(vf4, 0, a2); // lqc2 vf4, 0(a2) + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + cop1_bc = c->fprs[f2] < c->fprs[f3]; // c.lt.s f2, f3 + c->lqc2(vf5, -32, a2); // lqc2 vf5, -32(a2) + bc = cop1_bc; // bc1t L62 + c->lqc2(vf6, -16, a2); // lqc2 vf6, -16(a2) + if (bc) {goto block_14;} // branch non-likely + + c->sqc2(vf1, 0, a3); // sqc2 vf1, 0(a3) + c->daddiu(a3, a3, 48); // daddiu a3, a3, 48 + c->sqc2(vf2, -32, a3); // sqc2 vf2, -32(a3) + c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 + bc = c->sgpr64(t1) == 0; // beq t1, r0, L64 + c->sqc2(vf3, -16, a3); // sqc2 vf3, -16(a3) + if (bc) {goto block_17;} // branch non-likely + + + block_11: + c->lwc1(f1, 0, t2); // lwc1 f1, 0(t2) + c->daddiu(t2, t2, 48); // daddiu t2, t2, 48 + c->lwc1(f0, 12, a2); // lwc1 f0, 12(a2) + c->daddiu(t1, t1, -1); // daddiu t1, t1, -1 + c->lqc2(vf1, 0, a2); // lqc2 vf1, 0(a2) + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + cop1_bc = c->fprs[f0] < c->fprs[f1]; // c.lt.s f0, f1 + c->lqc2(vf2, -32, a2); // lqc2 vf2, -32(a2) + bc = cop1_bc; // bc1t L63 + c->lqc2(vf3, -16, a2); // lqc2 vf3, -16(a2) + if (bc) {goto block_16;} // branch non-likely + + c->sqc2(vf4, 0, a3); // sqc2 vf4, 0(a3) + c->daddiu(a3, a3, 48); // daddiu a3, a3, 48 + c->sqc2(vf5, -32, a3); // sqc2 vf5, -32(a3) + c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 + bc = c->sgpr64(t1) != 0; // bne t1, r0, L60 + c->sqc2(vf6, -16, a3); // sqc2 vf6, -16(a3) + if (bc) {goto block_9;} // branch non-likely + + //beq r0, r0, L64 // beq r0, r0, L64 + // nop // sll r0, r0, 0 + goto block_17; // branch always + + + block_14: + c->subs(f7, f0, f1); // sub.s f7, f0, f1 + c->vsub(DEST::xyzw, vf7, vf1, vf4); // vsub.xyzw vf7, vf1, vf4 + c->subs(f8, f2, f3); // sub.s f8, f2, f3 + c->vsub(DEST::xyzw, vf8, vf2, vf5); // vsub.xyzw vf8, vf2, vf5 + c->subs(f5, f8, f7); // sub.s f5, f8, f7 + c->vsub(DEST::xyzw, vf9, vf3, vf6); // vsub.xyzw vf9, vf3, vf6 + c->divs(f6, f8, f5); // div.s f6, f8, f5 + c->daddiu(a3, a3, 96); // daddiu a3, a3, 96 + c->mfc1(v1, f6); // mfc1 v1, f6 + c->mov128_vf_gpr(vf10, v1); // qmtc2.i vf10, v1 + c->sqc2(vf1, -96, a3); // sqc2 vf1, -96(a3) + c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); // vmulaw.xyzw acc, vf4, vf0 + c->sqc2(vf2, -80, a3); // sqc2 vf2, -80(a3) + c->vmadd_bc(DEST::xyzw, BC::x, vf7, vf7, vf10); // vmaddx.xyzw vf7, vf7, vf10 + c->sqc2(vf3, -64, a3); // sqc2 vf3, -64(a3) + c->vmula_bc(DEST::xyzw, BC::w, vf5, vf0); // vmulaw.xyzw acc, vf5, vf0 + c->daddiu(t0, t0, 2); // daddiu t0, t0, 2 + c->vmadd_bc(DEST::xyzw, BC::x, vf8, vf8, vf10); // vmaddx.xyzw vf8, vf8, vf10 + c->daddiu(t6, s7, 8); // daddiu t6, s7, 8 + c->vmula_bc(DEST::xyzw, BC::w, vf6, vf0); // vmulaw.xyzw acc, vf6, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf9, vf9, vf10); // vmaddx.xyzw vf9, vf9, vf10 + // nop // sll r0, r0, 0 + c->sqc2(vf7, -48, a3); // sqc2 vf7, -48(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf8, -32, a3); // sqc2 vf8, -32(a3) + // nop // sll r0, r0, 0 + bc = c->sgpr64(t1) != 0; // bne t1, r0, L57 + c->sqc2(vf9, -16, a3); // sqc2 vf9, -16(a3) + if (bc) {goto block_3;} // branch non-likely + + //beq r0, r0, L64 // beq r0, r0, L64 + // nop // sll r0, r0, 0 + goto block_17; // branch always + + + block_16: + c->subs(f7, f0, f1); // sub.s f7, f0, f1 + c->vsub(DEST::xyzw, vf7, vf4, vf1); // vsub.xyzw vf7, vf4, vf1 + c->subs(f8, f2, f3); // sub.s f8, f2, f3 + c->vsub(DEST::xyzw, vf8, vf5, vf2); // vsub.xyzw vf8, vf5, vf2 + c->subs(f5, f7, f8); // sub.s f5, f7, f8 + c->vsub(DEST::xyzw, vf9, vf6, vf3); // vsub.xyzw vf9, vf6, vf3 + c->divs(f6, f7, f5); // div.s f6, f7, f5 + c->daddiu(a3, a3, 96); // daddiu a3, a3, 96 + c->mfc1(v1, f6); // mfc1 v1, f6 + c->mov128_vf_gpr(vf10, v1); // qmtc2.i vf10, v1 + c->sqc2(vf4, -96, a3); // sqc2 vf4, -96(a3) + c->vmula_bc(DEST::xyzw, BC::w, vf1, vf0); // vmulaw.xyzw acc, vf1, vf0 + c->sqc2(vf5, -80, a3); // sqc2 vf5, -80(a3) + c->vmadd_bc(DEST::xyzw, BC::x, vf7, vf7, vf10); // vmaddx.xyzw vf7, vf7, vf10 + c->sqc2(vf6, -64, a3); // sqc2 vf6, -64(a3) + c->vmula_bc(DEST::xyzw, BC::w, vf2, vf0); // vmulaw.xyzw acc, vf2, vf0 + c->daddiu(t0, t0, 2); // daddiu t0, t0, 2 + c->vmadd_bc(DEST::xyzw, BC::x, vf8, vf8, vf10); // vmaddx.xyzw vf8, vf8, vf10 + c->daddiu(t6, s7, 8); // daddiu t6, s7, 8 + c->vmula_bc(DEST::xyzw, BC::w, vf3, vf0); // vmulaw.xyzw acc, vf3, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf9, vf9, vf10); // vmaddx.xyzw vf9, vf9, vf10 + // nop // sll r0, r0, 0 + c->sqc2(vf7, -48, a3); // sqc2 vf7, -48(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf8, -32, a3); // sqc2 vf8, -32(a3) + // nop // sll r0, r0, 0 + bc = c->sgpr64(t1) != 0; // bne t1, r0, L56 + c->sqc2(vf9, -16, a3); // sqc2 vf9, -16(a3) + if (bc) {goto block_1;} // branch non-likely + + + block_17: + c->lqc2(vf1, 0, t3); // lqc2 vf1, 0(t3) + // nop // sll r0, r0, 0 + c->lqc2(vf2, 16, t3); // lqc2 vf2, 16(t3) + // nop // sll r0, r0, 0 + c->lqc2(vf3, 32, t3); // lqc2 vf3, 32(t3) + // nop // sll r0, r0, 0 + c->sqc2(vf1, 0, a3); // sqc2 vf1, 0(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf2, 16, a3); // sqc2 vf2, 16(a3) + // nop // sll r0, r0, 0 + //jr ra // jr ra + c->sqc2(vf3, 32, a3); // sqc2 vf3, 32(a3) + goto end_of_function; // return + + //jr ra // jr ra + c->daddu(sp, sp, r0); // daddu sp, sp, r0 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + gLinkedFunctionTable.reg("clip-polygon-against-positive-hyperplane", execute, 1024); +} + +} // namespace clip_polygon_against_positive_hyperplane +} // namespace Mips2C + +//--------------------------MIPS2C--------------------- +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/kscheme.h" +namespace Mips2C { +namespace clip_polygon_against_negative_hyperplane { +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + bool cop1_bc = false; + // nop // sll r0, r0, 0 + c->mov64(t1, t0); // or t1, t0, r0 + c->addiu(t0, r0, 0); // addiu t0, r0, 0 + c->lwc1(f0, 12, a2); // lwc1 f0, 12(a2) + c->mov64(t3, a3); // or t3, a3, r0 + c->lwc1(f1, 0, t2); // lwc1 f1, 0(t2) + c->daddiu(t2, t2, 48); // daddiu t2, t2, 48 + c->lqc2(vf1, 0, a2); // lqc2 vf1, 0(a2) + c->negs(f0, f0); // neg.s f0, f0 + // nop // sll r0, r0, 0 + c->lqc2(vf2, 16, a2); // lqc2 vf2, 16(a2) + cop1_bc = c->fprs[f1] < c->fprs[f0]; // c.lt.s f1, f0 + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + bc = !cop1_bc; // bc1f L50 + c->lqc2(vf3, -16, a2); // lqc2 vf3, -16(a2) + if (bc) {goto block_9;} // branch non-likely + + + block_1: + c->lwc1(f2, 12, a2); // lwc1 f2, 12(a2) + c->daddiu(t1, t1, -1); // daddiu t1, t1, -1 + c->lwc1(f3, 0, t2); // lwc1 f3, 0(t2) + c->daddiu(t2, t2, 48); // daddiu t2, t2, 48 + c->lqc2(vf4, 0, a2); // lqc2 vf4, 0(a2) + c->negs(f2, f2); // neg.s f2, f2 + // nop // sll r0, r0, 0 + c->lqc2(vf5, 16, a2); // lqc2 vf5, 16(a2) + cop1_bc = c->fprs[f3] < c->fprs[f2]; // c.lt.s f3, f2 + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + bc = !cop1_bc; // bc1f L48 + c->lqc2(vf6, -16, a2); // lqc2 vf6, -16(a2) + if (bc) {goto block_6;} // branch non-likely + + bc = c->sgpr64(t1) == 0; // beq t1, r0, L54 + // nop // sll r0, r0, 0 + if (bc) {goto block_17;} // branch non-likely + + + block_3: + c->lwc1(f0, 12, a2); // lwc1 f0, 12(a2) + c->daddiu(t1, t1, -1); // daddiu t1, t1, -1 + c->lwc1(f1, 0, t2); // lwc1 f1, 0(t2) + c->daddiu(t2, t2, 48); // daddiu t2, t2, 48 + c->lqc2(vf1, 0, a2); // lqc2 vf1, 0(a2) + c->negs(f0, f0); // neg.s f0, f0 + // nop // sll r0, r0, 0 + c->lqc2(vf2, 16, a2); // lqc2 vf2, 16(a2) + cop1_bc = c->fprs[f1] < c->fprs[f0]; // c.lt.s f1, f0 + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + bc = !cop1_bc; // bc1f L49 + c->lqc2(vf3, -16, a2); // lqc2 vf3, -16(a2) + if (bc) {goto block_8;} // branch non-likely + + bc = c->sgpr64(t1) != 0; // bne t1, r0, L46 + // nop // sll r0, r0, 0 + if (bc) {goto block_1;} // branch non-likely + + //beq r0, r0, L54 // beq r0, r0, L54 + // nop // sll r0, r0, 0 + goto block_17; // branch always + + + block_6: + c->subs(f7, f0, f1); // sub.s f7, f0, f1 + c->vsub(DEST::xyzw, vf7, vf4, vf1); // vsub.xyzw vf7, vf4, vf1 + c->subs(f8, f2, f3); // sub.s f8, f2, f3 + c->vsub(DEST::xyzw, vf8, vf5, vf2); // vsub.xyzw vf8, vf5, vf2 + c->subs(f5, f7, f8); // sub.s f5, f7, f8 + c->vsub(DEST::xyzw, vf9, vf6, vf3); // vsub.xyzw vf9, vf6, vf3 + c->divs(f6, f7, f5); // div.s f6, f7, f5 + c->daddiu(a3, a3, 48); // daddiu a3, a3, 48 + c->mfc1(v1, f6); // mfc1 v1, f6 + c->mov128_vf_gpr(vf10, v1); // qmtc2.i vf10, v1 + c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 + c->vmula_bc(DEST::xyzw, BC::w, vf1, vf0); // vmulaw.xyzw acc, vf1, vf0 + c->daddiu(t6, s7, 8); // daddiu t6, s7, 8 + c->vmadd_bc(DEST::xyzw, BC::x, vf7, vf7, vf10); // vmaddx.xyzw vf7, vf7, vf10 + // nop // sll r0, r0, 0 + c->vmula_bc(DEST::xyzw, BC::w, vf2, vf0); // vmulaw.xyzw acc, vf2, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf8, vf8, vf10); // vmaddx.xyzw vf8, vf8, vf10 + // nop // sll r0, r0, 0 + c->vmula_bc(DEST::xyzw, BC::w, vf3, vf0); // vmulaw.xyzw acc, vf3, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf9, vf9, vf10); // vmaddx.xyzw vf9, vf9, vf10 + // nop // sll r0, r0, 0 + c->sqc2(vf7, -48, a3); // sqc2 vf7, -48(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf8, -32, a3); // sqc2 vf8, -32(a3) + // nop // sll r0, r0, 0 + bc = c->sgpr64(t1) != 0; // bne t1, r0, L51 + c->sqc2(vf9, -16, a3); // sqc2 vf9, -16(a3) + if (bc) {goto block_11;} // branch non-likely + + //beq r0, r0, L54 // beq r0, r0, L54 + // nop // sll r0, r0, 0 + goto block_17; // branch always + + + block_8: + c->subs(f7, f0, f1); // sub.s f7, f0, f1 + c->vsub(DEST::xyzw, vf7, vf1, vf4); // vsub.xyzw vf7, vf1, vf4 + c->subs(f8, f2, f3); // sub.s f8, f2, f3 + c->vsub(DEST::xyzw, vf8, vf2, vf5); // vsub.xyzw vf8, vf2, vf5 + c->subs(f5, f8, f7); // sub.s f5, f8, f7 + c->vsub(DEST::xyzw, vf9, vf3, vf6); // vsub.xyzw vf9, vf3, vf6 + c->divs(f6, f8, f5); // div.s f6, f8, f5 + c->daddiu(a3, a3, 48); // daddiu a3, a3, 48 + c->mfc1(v1, f6); // mfc1 v1, f6 + c->mov128_vf_gpr(vf10, v1); // qmtc2.i vf10, v1 + c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 + c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); // vmulaw.xyzw acc, vf4, vf0 + c->daddiu(t6, s7, 8); // daddiu t6, s7, 8 + c->vmadd_bc(DEST::xyzw, BC::x, vf7, vf7, vf10); // vmaddx.xyzw vf7, vf7, vf10 + // nop // sll r0, r0, 0 + c->vmula_bc(DEST::xyzw, BC::w, vf5, vf0); // vmulaw.xyzw acc, vf5, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf8, vf8, vf10); // vmaddx.xyzw vf8, vf8, vf10 + // nop // sll r0, r0, 0 + c->vmula_bc(DEST::xyzw, BC::w, vf6, vf0); // vmulaw.xyzw acc, vf6, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf9, vf9, vf10); // vmaddx.xyzw vf9, vf9, vf10 + // nop // sll r0, r0, 0 + c->sqc2(vf7, -48, a3); // sqc2 vf7, -48(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf8, -32, a3); // sqc2 vf8, -32(a3) + // nop // sll r0, r0, 0 + bc = c->sgpr64(t1) == 0; // beq t1, r0, L54 + c->sqc2(vf9, -16, a3); // sqc2 vf9, -16(a3) + if (bc) {goto block_17;} // branch non-likely + + + block_9: + c->lwc1(f2, 12, a2); // lwc1 f2, 12(a2) + c->daddiu(t1, t1, -1); // daddiu t1, t1, -1 + c->lwc1(f3, 0, t2); // lwc1 f3, 0(t2) + c->daddiu(t2, t2, 48); // daddiu t2, t2, 48 + c->lqc2(vf4, 0, a2); // lqc2 vf4, 0(a2) + c->negs(f2, f2); // neg.s f2, f2 + // nop // sll r0, r0, 0 + c->lqc2(vf5, 16, a2); // lqc2 vf5, 16(a2) + cop1_bc = c->fprs[f3] < c->fprs[f2]; // c.lt.s f3, f2 + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + bc = cop1_bc; // bc1t L52 + c->lqc2(vf6, -16, a2); // lqc2 vf6, -16(a2) + if (bc) {goto block_14;} // branch non-likely + + c->sqc2(vf1, 0, a3); // sqc2 vf1, 0(a3) + c->daddiu(a3, a3, 48); // daddiu a3, a3, 48 + c->sqc2(vf2, -32, a3); // sqc2 vf2, -32(a3) + c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 + bc = c->sgpr64(t1) == 0; // beq t1, r0, L54 + c->sqc2(vf3, -16, a3); // sqc2 vf3, -16(a3) + if (bc) {goto block_17;} // branch non-likely + + + block_11: + c->lwc1(f0, 12, a2); // lwc1 f0, 12(a2) + c->daddiu(t1, t1, -1); // daddiu t1, t1, -1 + c->lwc1(f1, 0, t2); // lwc1 f1, 0(t2) + c->daddiu(t2, t2, 48); // daddiu t2, t2, 48 + c->lqc2(vf1, 0, a2); // lqc2 vf1, 0(a2) + c->negs(f0, f0); // neg.s f0, f0 + // nop // sll r0, r0, 0 + c->lqc2(vf2, 16, a2); // lqc2 vf2, 16(a2) + cop1_bc = c->fprs[f1] < c->fprs[f0]; // c.lt.s f1, f0 + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + bc = cop1_bc; // bc1t L53 + c->lqc2(vf3, -16, a2); // lqc2 vf3, -16(a2) + if (bc) {goto block_16;} // branch non-likely + + c->sqc2(vf4, 0, a3); // sqc2 vf4, 0(a3) + c->daddiu(a3, a3, 48); // daddiu a3, a3, 48 + c->sqc2(vf5, -32, a3); // sqc2 vf5, -32(a3) + c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 + bc = c->sgpr64(t1) != 0; // bne t1, r0, L50 + c->sqc2(vf6, -16, a3); // sqc2 vf6, -16(a3) + if (bc) {goto block_9;} // branch non-likely + + //beq r0, r0, L54 // beq r0, r0, L54 + // nop // sll r0, r0, 0 + goto block_17; // branch always + + + block_14: + c->subs(f7, f0, f1); // sub.s f7, f0, f1 + c->vsub(DEST::xyzw, vf7, vf1, vf4); // vsub.xyzw vf7, vf1, vf4 + c->subs(f8, f2, f3); // sub.s f8, f2, f3 + c->vsub(DEST::xyzw, vf8, vf2, vf5); // vsub.xyzw vf8, vf2, vf5 + c->subs(f5, f8, f7); // sub.s f5, f8, f7 + c->vsub(DEST::xyzw, vf9, vf3, vf6); // vsub.xyzw vf9, vf3, vf6 + c->divs(f6, f8, f5); // div.s f6, f8, f5 + c->daddiu(a3, a3, 96); // daddiu a3, a3, 96 + c->mfc1(v1, f6); // mfc1 v1, f6 + c->mov128_vf_gpr(vf10, v1); // qmtc2.i vf10, v1 + c->sqc2(vf1, -96, a3); // sqc2 vf1, -96(a3) + c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); // vmulaw.xyzw acc, vf4, vf0 + c->sqc2(vf2, -80, a3); // sqc2 vf2, -80(a3) + c->vmadd_bc(DEST::xyzw, BC::x, vf7, vf7, vf10); // vmaddx.xyzw vf7, vf7, vf10 + c->sqc2(vf3, -64, a3); // sqc2 vf3, -64(a3) + c->vmula_bc(DEST::xyzw, BC::w, vf5, vf0); // vmulaw.xyzw acc, vf5, vf0 + c->daddiu(t0, t0, 2); // daddiu t0, t0, 2 + c->vmadd_bc(DEST::xyzw, BC::x, vf8, vf8, vf10); // vmaddx.xyzw vf8, vf8, vf10 + c->daddiu(t6, s7, 8); // daddiu t6, s7, 8 + c->vmula_bc(DEST::xyzw, BC::w, vf6, vf0); // vmulaw.xyzw acc, vf6, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf9, vf9, vf10); // vmaddx.xyzw vf9, vf9, vf10 + // nop // sll r0, r0, 0 + c->sqc2(vf7, -48, a3); // sqc2 vf7, -48(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf8, -32, a3); // sqc2 vf8, -32(a3) + // nop // sll r0, r0, 0 + bc = c->sgpr64(t1) != 0; // bne t1, r0, L47 + c->sqc2(vf9, -16, a3); // sqc2 vf9, -16(a3) + if (bc) {goto block_3;} // branch non-likely + + //beq r0, r0, L54 // beq r0, r0, L54 + // nop // sll r0, r0, 0 + goto block_17; // branch always + + + block_16: + c->subs(f7, f0, f1); // sub.s f7, f0, f1 + c->vsub(DEST::xyzw, vf7, vf4, vf1); // vsub.xyzw vf7, vf4, vf1 + c->subs(f8, f2, f3); // sub.s f8, f2, f3 + c->vsub(DEST::xyzw, vf8, vf5, vf2); // vsub.xyzw vf8, vf5, vf2 + c->subs(f5, f7, f8); // sub.s f5, f7, f8 + c->vsub(DEST::xyzw, vf9, vf6, vf3); // vsub.xyzw vf9, vf6, vf3 + c->divs(f6, f7, f5); // div.s f6, f7, f5 + c->daddiu(a3, a3, 96); // daddiu a3, a3, 96 + c->mfc1(v1, f6); // mfc1 v1, f6 + c->mov128_vf_gpr(vf10, v1); // qmtc2.i vf10, v1 + c->sqc2(vf4, -96, a3); // sqc2 vf4, -96(a3) + c->vmula_bc(DEST::xyzw, BC::w, vf1, vf0); // vmulaw.xyzw acc, vf1, vf0 + c->sqc2(vf5, -80, a3); // sqc2 vf5, -80(a3) + c->vmadd_bc(DEST::xyzw, BC::x, vf7, vf7, vf10); // vmaddx.xyzw vf7, vf7, vf10 + c->sqc2(vf6, -64, a3); // sqc2 vf6, -64(a3) + c->vmula_bc(DEST::xyzw, BC::w, vf2, vf0); // vmulaw.xyzw acc, vf2, vf0 + c->daddiu(t0, t0, 2); // daddiu t0, t0, 2 + c->vmadd_bc(DEST::xyzw, BC::x, vf8, vf8, vf10); // vmaddx.xyzw vf8, vf8, vf10 + c->daddiu(t6, s7, 8); // daddiu t6, s7, 8 + c->vmula_bc(DEST::xyzw, BC::w, vf3, vf0); // vmulaw.xyzw acc, vf3, vf0 + // nop // sll r0, r0, 0 + c->vmadd_bc(DEST::xyzw, BC::x, vf9, vf9, vf10); // vmaddx.xyzw vf9, vf9, vf10 + // nop // sll r0, r0, 0 + c->sqc2(vf7, -48, a3); // sqc2 vf7, -48(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf8, -32, a3); // sqc2 vf8, -32(a3) + // nop // sll r0, r0, 0 + bc = c->sgpr64(t1) != 0; // bne t1, r0, L46 + c->sqc2(vf9, -16, a3); // sqc2 vf9, -16(a3) + if (bc) {goto block_1;} // branch non-likely + + + block_17: + c->lqc2(vf1, 0, t3); // lqc2 vf1, 0(t3) + // nop // sll r0, r0, 0 + c->lqc2(vf2, 16, t3); // lqc2 vf2, 16(t3) + // nop // sll r0, r0, 0 + c->lqc2(vf3, 32, t3); // lqc2 vf3, 32(t3) + // nop // sll r0, r0, 0 + c->sqc2(vf1, 0, a3); // sqc2 vf1, 0(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf2, 16, a3); // sqc2 vf2, 16(a3) + // nop // sll r0, r0, 0 + //jr ra // jr ra + c->sqc2(vf3, 32, a3); // sqc2 vf3, 32(a3) + goto end_of_function; // return + + //jr ra // jr ra + c->daddu(sp, sp, r0); // daddu sp, sp, r0 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + gLinkedFunctionTable.reg("clip-polygon-against-negative-hyperplane", execute, 1024); +} + +} // namespace clip_polygon_against_negative_hyperplane +} // namespace Mips2C + +//--------------------------MIPS2C--------------------- +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/kscheme.h" +namespace Mips2C { +namespace draw_large_polygon { +struct Cache { + void* clip_polygon_against_negative_hyperplane; // clip-polygon-against-negative-hyperplane + void* clip_polygon_against_positive_hyperplane; // clip-polygon-against-positive-hyperplane +} cache; + +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + u32 call_addr = 0; + // nop // sll r0, r0, 0 + c->daddiu(sp, sp, -8); // daddiu sp, sp, -8 + // nop // sll r0, r0, 0 + c->sd(ra, 0, sp); // sd ra, 0(sp) + c->load_symbol(t9, cache.clip_polygon_against_positive_hyperplane);// lw t9, clip-polygon-against-positive-hyperplane(s7) + c->mov64(a2, t4); // or a2, t4, r0 + c->mov64(a3, t5); // or a3, t5, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->daddu(t2, a2, r0); // daddu t2, a2, r0 + //c->jalr(call_addr); // jalr ra, t9 + clip_polygon_against_positive_hyperplane::execute(ctxt); + bc = c->sgpr64(t0) == 0; // beq t0, r0, L67 + // nop // sll r0, r0, 0 + if (bc) {goto block_7;} // branch non-likely + + c->mov64(a2, t5); // or a2, t5, r0 + c->mov64(a3, t4); // or a3, t4, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->daddiu(t2, a2, 4); // daddiu t2, a2, 4 + //c->jalr(call_addr); // jalr ra, t9 + clip_polygon_against_positive_hyperplane::execute(ctxt); + bc = c->sgpr64(t0) == 0; // beq t0, r0, L67 + c->load_symbol(t9, cache.clip_polygon_against_negative_hyperplane);// lw t9, clip-polygon-against-negative-hyperplane(s7) + if (bc) {goto block_7;} // branch non-likely + + c->mov64(a2, t4); // or a2, t4, r0 + c->mov64(a3, t5); // or a3, t5, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->daddu(t2, a2, r0); // daddu t2, a2, r0 + //c->jalr(call_addr); // jalr ra, t9 + clip_polygon_against_negative_hyperplane::execute(ctxt); + bc = c->sgpr64(t0) == 0; // beq t0, r0, L67 + // nop // sll r0, r0, 0 + if (bc) {goto block_7;} // branch non-likely + + c->mov64(a2, t5); // or a2, t5, r0 + c->mov64(a3, t4); // or a3, t4, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->daddiu(t2, a2, 4); // daddiu t2, a2, 4 + //c->jalr(call_addr); // jalr ra, t9 + clip_polygon_against_negative_hyperplane::execute(ctxt); + bc = c->sgpr64(t0) == 0; // beq t0, r0, L67 + c->lw(a3, 4, a1); // lw a3, 4(a1) + if (bc) {goto block_7;} // branch non-likely + + c->mov64(a2, t4); // or a2, t4, r0 + // nop // sll r0, r0, 0 + c->sqc2(vf27, 0, a3); // sqc2 vf27, 0(a3) + c->daddiu(a3, a3, 16); // daddiu a3, a3, 16 + c->sw(t0, -16, a3); // sw t0, -16(a3) + // nop // sll r0, r0, 0 + + //fmt::print("draw loop of {}\n", c->gpr_src(t0).du64[0]); + block_5: + c->lqc2(vf1, 0, a2); // lqc2 vf1, 0(a2) + // nop // sll r0, r0, 0 + c->lqc2(vf2, 16, a2); // lqc2 vf2, 16(a2) + //fmt::print("st orig: {}\n", c->print_vf_float(vf2)); + // nop // sll r0, r0, 0 + c->lqc2(vf3, 32, a2); // lqc2 vf3, 32(a2) + c->vdiv(vf0, BC::w, vf1, BC::w); // vdiv Q, vf0.w, vf1.w + c->vmul(DEST::xyzw, vf1, vf1, vf26); // vmul.xyzw vf1, vf1, vf26 + // nop // sll r0, r0, 0 + + // these look like rgba's + c->vftoi0(DEST::xyzw, vf3, vf3); // vftoi0.xyzw vf3, vf3 + + // nop // sll r0, r0, 0 + c->vadd(DEST::xyzw, vf2, vf2, vf24); // vadd.xyzw vf2, vf2, vf24 + //fmt::print("st offset: {}\n", c->print_vf_float(vf2)); + // nop // sll r0, r0, 0 + c->vwaitq(); // vwaitq + // nop // sll r0, r0, 0 + c->vmulq(DEST::xyz, vf1, vf1); // vmulq.xyz vf1, vf1, Q + + // store rgbaq + c->sqc2(vf3, 16, a3); // sqc2 vf3, 16(a3) + c->vmulq(DEST::xyzw, vf2, vf2); // vmulq.xyzw vf2, vf2, Q + //fmt::print("st multiplied: {}\n", c->print_vf_float(vf2)); + c->daddiu(a2, a2, 48); // daddiu a2, a2, 48 + c->vadd(DEST::xyzw, vf1, vf1, vf25); // vadd.xyzw vf1, vf1, vf25 + c->daddiu(a3, a3, 48); // daddiu a3, a3, 48 + c->vmul_bc(DEST::z, BC::z, vf1, vf1, vf0); // vmulz.z vf1, vf1, vf0 + // nop // sll r0, r0, 0 + c->vmini_bc(DEST::w, BC::z, vf1, vf1, vf13); // vminiz.w vf1, vf1, vf13 + // nop // sll r0, r0, 0 + c->vadd_bc(DEST::z, BC::x, vf1, vf1, vf23); // vaddx.z vf1, vf1, vf23 + // nop // sll r0, r0, 0 + c->vmax_bc(DEST::w, BC::y, vf1, vf1, vf13); // vmaxy.w vf1, vf1, vf13 + // nop // sll r0, r0, 0 + // store st + c->sqc2(vf2, -48, a3); // sqc2 vf2, -48(a3) + c->daddiu(t0, t0, -1); // daddiu t0, t0, -1 + //fmt::print("pos: {}\n", c->print_vf_float(vf1)); + c->vftoi4(DEST::xyzw, vf1, vf1); // vftoi4.xyzw vf1, vf1 + // nop // sll r0, r0, 0 + bc = c->sgpr64(t0) != 0; // bne t0, r0, L66 + // store pos + c->sqc2(vf1, -16, a3); // sqc2 vf1, -16(a3) + if (bc) {goto block_5;} // branch non-likely + + c->sw(a3, 4, a1); // sw a3, 4(a1) + // nop // sll r0, r0, 0 + c->ld(ra, 0, sp); // ld ra, 0(sp) + c->daddiu(v0, s7, 8); // daddiu v0, s7, 8 + //jr ra // jr ra + c->daddiu(sp, sp, 8); // daddiu sp, sp, 8 + goto end_of_function; // return + + + block_7: + c->ld(ra, 0, sp); // ld ra, 0(sp) + c->mov64(v0, s7); // or v0, s7, r0 + //jr ra // jr ra + c->daddiu(sp, sp, 8); // daddiu sp, sp, 8 + goto end_of_function; // return + + //jr ra // jr ra + c->daddu(sp, sp, r0); // daddu sp, sp, r0 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + cache.clip_polygon_against_negative_hyperplane = intern_from_c("clip-polygon-against-negative-hyperplane").c(); + cache.clip_polygon_against_positive_hyperplane = intern_from_c("clip-polygon-against-positive-hyperplane").c(); + gLinkedFunctionTable.reg("draw-large-polygon", execute, 1024); +} + +} // namespace draw_large_polygon +} // namespace Mips2C + +//--------------------------MIPS2C--------------------- +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/kscheme.h" +namespace Mips2C { +namespace render_sky_quad { +struct Cache { + void* math_camera; // *math-camera* + void* draw_large_polygon; // draw-large-polygon + void* fake_scratchpad_data; // *fake-scratchpad-data* +} cache; + +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + c->copy_vfs_from_other(&sky_regs_vfs); + c->mov64(v1, a0); // or v1, a0, r0 + c->load_symbol(v1, cache.math_camera); // lw v1, *math-camera*(s7) + c->lqc2(vf14, 700, v1); // lqc2 vf14, 700(v1) + //c->lui(t4, 28672); // lui t4, 28672 + //c->ori(t4, t4, 12288); // ori t4, t4, 12288 + get_fake_spad_addr(t4, cache.fake_scratchpad_data, 12288, c); + //c->lui(t5, 28672); // lui t5, 28672 + //c->ori(t5, t5, 14336); // ori t5, t5, 14336 + get_fake_spad_addr(t5, cache.fake_scratchpad_data, 14336, c); + c->lui(v1, 12288); // lui v1, 12288 + c->mov64(a3, t4); // or a3, t4, r0 + //c->or_(a0, a0, v1); // or a0, a0, v1 + // nop // sll r0, r0, 0 + c->lqc2(vf1, 0, a0); // lqc2 vf1, 0(a0) + c->addiu(t0, r0, 4); // addiu t0, r0, 4 + c->lqc2(vf2, 16, a0); // lqc2 vf2, 16(a0) + // nop // sll r0, r0, 0 + c->lqc2(vf3, 32, a0); // lqc2 vf3, 32(a0) + c->vmula_bc(DEST::xyzw, BC::x, vf31, vf1); // vmulax.xyzw acc, vf31, vf1 + c->lqc2(vf4, 48, a0); // lqc2 vf4, 48(a0) + c->vmadda_bc(DEST::xyzw, BC::y, vf30, vf1); // vmadday.xyzw acc, vf30, vf1 + c->lqc2(vf5, 64, a0); // lqc2 vf5, 64(a0) + c->vmadda_bc(DEST::xyzw, BC::z, vf29, vf1); // vmaddaz.xyzw acc, vf29, vf1 + c->lqc2(vf6, 80, a0); // lqc2 vf6, 80(a0) + c->vmadd_bc(DEST::xyw, BC::w, vf1, vf28, vf1); // vmaddw.xyw vf1, vf28, vf1 + c->lqc2(vf7, 96, a0); // lqc2 vf7, 96(a0) + c->vmove(DEST::z, vf1, vf0); // vmove.z vf1, vf0 + c->lqc2(vf8, 112, a0); // lqc2 vf8, 112(a0) + c->vmula_bc(DEST::xyzw, BC::x, vf31, vf4); // vmulax.xyzw acc, vf31, vf4 + c->lqc2(vf9, 128, a0); // lqc2 vf9, 128(a0) + c->vmadda_bc(DEST::xyzw, BC::y, vf30, vf4); // vmadday.xyzw acc, vf30, vf4 + c->lqc2(vf10, 144, a0); // lqc2 vf10, 144(a0) + c->vmadda_bc(DEST::xyzw, BC::z, vf29, vf4); // vmaddaz.xyzw acc, vf29, vf4 + c->lqc2(vf11, 160, a0); // lqc2 vf11, 160(a0) + c->vmadd_bc(DEST::xyw, BC::w, vf4, vf28, vf4); // vmaddw.xyw vf4, vf28, vf4 + c->lqc2(vf12, 176, a0); // lqc2 vf12, 176(a0) + c->vmove(DEST::z, vf4, vf0); // vmove.z vf4, vf0 + c->sqc2(vf2, 16, a3); // sqc2 vf2, 16(a3) + c->vmula_bc(DEST::xyzw, BC::x, vf31, vf7); // vmulax.xyzw acc, vf31, vf7 + c->sqc2(vf3, 32, a3); // sqc2 vf3, 32(a3) + c->vmadda_bc(DEST::xyzw, BC::y, vf30, vf7); // vmadday.xyzw acc, vf30, vf7 + c->sqc2(vf5, 64, a3); // sqc2 vf5, 64(a3) + c->vmadda_bc(DEST::xyzw, BC::z, vf29, vf7); // vmaddaz.xyzw acc, vf29, vf7 + c->sqc2(vf6, 80, a3); // sqc2 vf6, 80(a3) + c->vmadd_bc(DEST::xyw, BC::w, vf7, vf28, vf7); // vmaddw.xyw vf7, vf28, vf7 + c->sqc2(vf8, 112, a3); // sqc2 vf8, 112(a3) + c->vmove(DEST::z, vf7, vf0); // vmove.z vf7, vf0 + c->sqc2(vf9, 128, a3); // sqc2 vf9, 128(a3) + c->vmula_bc(DEST::xyzw, BC::x, vf31, vf10); // vmulax.xyzw acc, vf31, vf10 + c->sqc2(vf11, 160, a3); // sqc2 vf11, 160(a3) + c->vmadda_bc(DEST::xyzw, BC::y, vf30, vf10); // vmadday.xyzw acc, vf30, vf10 + c->sqc2(vf12, 176, a3); // sqc2 vf12, 176(a3) + c->vmadda_bc(DEST::xyzw, BC::z, vf29, vf10); // vmaddaz.xyzw acc, vf29, vf10 + c->sqc2(vf2, 208, a3); // sqc2 vf2, 208(a3) + c->vmadd_bc(DEST::xyw, BC::w, vf10, vf28, vf10); // vmaddw.xyw vf10, vf28, vf10 + c->sqc2(vf3, 224, a3); // sqc2 vf3, 224(a3) + c->vmove(DEST::z, vf10, vf0); // vmove.z vf10, vf0 + c->sqc2(vf1, 0, a3); // sqc2 vf1, 0(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf1, 192, a3); // sqc2 vf1, 192(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf4, 48, a3); // sqc2 vf4, 48(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf7, 96, a3); // sqc2 vf7, 96(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf10, 144, a3); // sqc2 vf10, 144(a3) + c->load_symbol(t9, cache.draw_large_polygon); // lw t9, draw-large-polygon(s7) + draw_large_polygon::execute(ctxt); + // Unknown instr: jr t9 + // nop // sll r0, r0, 0 + //jr ra // jr ra + c->daddu(sp, sp, r0); // daddu sp, sp, r0 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + cache.math_camera = intern_from_c("*math-camera*").c(); + cache.draw_large_polygon = intern_from_c("draw-large-polygon").c(); + cache.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c(); + gLinkedFunctionTable.reg("render-sky-quad", execute, 1024); +} + +} // namespace render_sky_quad +} // namespace Mips2C + +//--------------------------MIPS2C--------------------- +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/kscheme.h" +namespace Mips2C { +namespace render_sky_tri { +struct Cache { + void* draw_large_polygon; // draw-large-polygon + void* fake_scratchpad_data; +} cache; + +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + c->copy_vfs_from_other(&sky_regs_vfs); + c->mov64(v1, a0); // or v1, a0, r0 + //c->lui(t4, 28672); // lui t4, 28672 + //c->ori(t4, t4, 12288); // ori t4, t4, 12288 + get_fake_spad_addr(t4, cache.fake_scratchpad_data, 12288, c); + //c->lui(t5, 28672); // lui t5, 28672 + //c->ori(t5, t5, 14336); // ori t5, t5, 14336 + get_fake_spad_addr(t5, cache.fake_scratchpad_data, 14336, c); + c->lui(v1, 12288); // lui v1, 12288 + c->mov64(a3, t4); // or a3, t4, r0 + //c->_or(a0, a0, v1); // or a0, a0, v1 + // nop // sll r0, r0, 0 + c->lqc2(vf1, 0, a0); // lqc2 vf1, 0(a0) + c->addiu(t0, r0, 3); // addiu t0, r0, 3 + c->lqc2(vf2, 16, a0); // lqc2 vf2, 16(a0) + // nop // sll r0, r0, 0 + c->lqc2(vf3, 32, a0); // lqc2 vf3, 32(a0) + c->vmula_bc(DEST::xyzw, BC::x, vf31, vf1); // vmulax.xyzw acc, vf31, vf1 + c->lqc2(vf4, 48, a0); // lqc2 vf4, 48(a0) + c->vmadda_bc(DEST::xyzw, BC::y, vf30, vf1); // vmadday.xyzw acc, vf30, vf1 + c->lqc2(vf5, 64, a0); // lqc2 vf5, 64(a0) + c->vmadda_bc(DEST::xyzw, BC::z, vf29, vf1); // vmaddaz.xyzw acc, vf29, vf1 + c->lqc2(vf6, 80, a0); // lqc2 vf6, 80(a0) + c->vmadd_bc(DEST::xyw, BC::w, vf1, vf28, vf1); // vmaddw.xyw vf1, vf28, vf1 + c->lqc2(vf7, 96, a0); // lqc2 vf7, 96(a0) + c->vmove(DEST::z, vf1, vf0); // vmove.z vf1, vf0 + c->lqc2(vf8, 112, a0); // lqc2 vf8, 112(a0) + c->vmula_bc(DEST::xyzw, BC::x, vf31, vf4); // vmulax.xyzw acc, vf31, vf4 + c->lqc2(vf9, 128, a0); // lqc2 vf9, 128(a0) + c->vmadda_bc(DEST::xyzw, BC::y, vf30, vf4); // vmadday.xyzw acc, vf30, vf4 + c->sqc2(vf2, 16, a3); // sqc2 vf2, 16(a3) + c->vmadda_bc(DEST::xyzw, BC::z, vf29, vf4); // vmaddaz.xyzw acc, vf29, vf4 + c->sqc2(vf3, 32, a3); // sqc2 vf3, 32(a3) + c->vmadd_bc(DEST::xyw, BC::w, vf4, vf28, vf4); // vmaddw.xyw vf4, vf28, vf4 + c->sqc2(vf5, 64, a3); // sqc2 vf5, 64(a3) + c->vmove(DEST::z, vf4, vf0); // vmove.z vf4, vf0 + c->sqc2(vf6, 80, a3); // sqc2 vf6, 80(a3) + c->vmula_bc(DEST::xyzw, BC::x, vf31, vf7); // vmulax.xyzw acc, vf31, vf7 + c->sqc2(vf8, 112, a3); // sqc2 vf8, 112(a3) + c->vmadda_bc(DEST::xyzw, BC::y, vf30, vf7); // vmadday.xyzw acc, vf30, vf7 + c->sqc2(vf9, 128, a3); // sqc2 vf9, 128(a3) + c->vmadda_bc(DEST::xyzw, BC::z, vf29, vf7); // vmaddaz.xyzw acc, vf29, vf7 + c->sqc2(vf2, 160, a3); // sqc2 vf2, 160(a3) + c->vmadd_bc(DEST::xyw, BC::w, vf7, vf28, vf7); // vmaddw.xyw vf7, vf28, vf7 + c->sqc2(vf3, 176, a3); // sqc2 vf3, 176(a3) + c->vmove(DEST::z, vf7, vf0); // vmove.z vf7, vf0 + c->sqc2(vf1, 0, a3); // sqc2 vf1, 0(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf1, 144, a3); // sqc2 vf1, 144(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf4, 48, a3); // sqc2 vf4, 48(a3) + // nop // sll r0, r0, 0 + c->sqc2(vf7, 96, a3); // sqc2 vf7, 96(a3) + c->load_symbol(t9, cache.draw_large_polygon); // lw t9, draw-large-polygon(s7) + draw_large_polygon::execute(ctxt); + // Unknown instr: jr t9 + // nop // sll r0, r0, 0 + //jr ra // jr ra + c->daddu(sp, sp, r0); // daddu sp, sp, r0 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + cache.draw_large_polygon = intern_from_c("draw-large-polygon").c(); + cache.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c(); + gLinkedFunctionTable.reg("render-sky-tri", execute, 1024); +} + +} // namespace render_sky_tri +} // namespace Mips2C + +namespace Mips2C { +namespace set_sky_vf27 { +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + // sky_regs_vfs.vfs[27] + memcpy(&sky_regs_vfs.vfs[27].f[0], g_ee_main_mem + c->gpr_addr(a0), 16); + return 0; +} + +void link() { + gLinkedFunctionTable.reg("set-sky-vf27", execute, 64); +} + +} // namespace set_sky_vf27 +} // namespace Mips2C + +namespace Mips2C { +namespace set_sky_vf23_value { +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + // sky_regs_vfs.vfs[27] + u64 value = c->sgpr64(a0); + memcpy(&sky_regs_vfs.vfs[23].f[0], &value, 8); + return 0; +} + +void link() { + gLinkedFunctionTable.reg("set-sky-vf23-value", execute, 64); +} + +} // namespace set_sky_vf23_value +} // namespace Mips2C diff --git a/game/mips2c/functions/texture.cpp b/game/mips2c/functions/texture.cpp new file mode 100644 index 000000000..914f8ecaf --- /dev/null +++ b/game/mips2c/functions/texture.cpp @@ -0,0 +1,163 @@ +//--------------------------MIPS2C--------------------- +// clang-format off +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/kscheme.h" +namespace Mips2C { +namespace adgif_shader_texture_with_update { +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + c->ld(a2, 16, a0); // ld a2, 16(a0) + c->addiu(v1, r0, 256); // addiu v1, r0, 256 + c->andi(a2, a2, 513); // andi a2, a2, 513 + c->mtc1(f0, v1); // mtc1 f0, v1 + c->cvtsw(f0, f0); // cvt.s.w f0, f0 + c->lbu(v1, 4, a1); // lbu v1, 4(a1) + c->lwc1(f1, 44, a1); // lwc1 f1, 44(a1) + c->daddiu(v1, v1, -1); // daddiu v1, v1, -1 + c->divs(f0, f0, f1); // div.s f0, f0, f1 + c->dsll(v1, v1, 2); // dsll v1, v1, 2 + c->or_(a2, a2, v1); // or a2, a2, v1 + c->lbu(v1, 7, a1); // lbu v1, 7(a1) + c->dsll(v1, v1, 19); // dsll v1, v1, 19 + c->lbu(a3, 5, a1); // lbu a3, 5(a1) + c->or_(a2, a2, v1); // or a2, a2, v1 + c->dsll(a3, a3, 5); // dsll a3, a3, 5 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->ld(t1, 0, a0); // ld t1, 0(a0) + c->dsll(t1, t1, 27); // dsll t1, t1, 27 + c->lbu(v1, 6, a1); // lbu v1, 6(a1) + c->dsra32(t1, t1, 30); // dsra32 t1, t1, 30 + c->dsll(v1, v1, 20); // dsll v1, v1, 20 + c->dsll32(t1, t1, 3); // dsll32 t1, t1, 3 + c->lhu(a3, 10, a1); // lhu a3, 10(a1) + c->or_(t1, t1, v1); // or t1, t1, v1 + c->lbu(v1, 26, a1); // lbu v1, 26(a1) + c->or_(t1, t1, a3); // or t1, t1, a3 + c->dsll(v1, v1, 14); // dsll v1, v1, 14 + c->or_(t1, t1, v1); // or t1, t1, v1 + c->lhu(v1, 0, a1); // lhu v1, 0(a1) + c->plzcw(v1, v1); // plzcw v1, v1 + c->addiu(t0, r0, 30); // addiu t0, r0, 30 + c->subu(v1, t0, v1); // subu v1, t0, v1 + c->lhu(a3, 2, a1); // lhu a3, 2(a1) + c->dsll(v1, v1, 26); // dsll v1, v1, 26 + c->plzcw(a3, a3); // plzcw a3, a3 + c->or_(t1, t1, v1); // or t1, t1, v1 + c->subu(a3, t0, a3); // subu a3, t0, a3 + c->dsll(a3, a3, 30); // dsll a3, a3, 30 + c->addiu(v1, r0, 1); // addiu v1, r0, 1 + c->or_(t1, t1, a3); // or t1, t1, a3 + c->dsll32(v1, v1, 2); // dsll32 v1, v1, 2 + c->or_(t1, t1, v1); // or t1, t1, v1 + c->lhu(v1, 24, a1); // lhu v1, 24(a1) + c->dsll32(v1, v1, 5); // dsll32 v1, v1, 5 + c->lhu(a3, 8, a1); // lhu a3, 8(a1) + c->dsll32(a3, a3, 19); // dsll32 a3, a3, 19 + c->or_(t1, t1, v1); // or t1, t1, v1 + c->or_(t1, t1, a3); // or t1, t1, a3 + c->addiu(v1, r0, 1); // addiu v1, r0, 1 + c->dsll32(v1, v1, 29); // dsll32 v1, v1, 29 + c->cvtws(f0, f0); // cvt.w.s f0, f0 + c->or_(t1, t1, v1); // or t1, t1, v1 + c->mfc1(v1, f0); // mfc1 v1, f0 + c->sd(t1, 0, a0); // sd t1, 0(a0) + c->plzcw(a3, v1); // plzcw a3, v1 + c->subu(a3, t0, a3); // subu a3, t0, a3 + c->lbu(t0, 7, a1); // lbu t0, 7(a1) + c->daddiu(t0, t0, -1); // daddiu t0, t0, -1 + // nop // sll r0, r0, 0 + bc = c->sgpr64(t0) == 0; // beq t0, r0, L22 + // nop // sll r0, r0, 0 + if (bc) {goto block_2;} // branch non-likely + + c->daddiu(t0, a3, -4); // daddiu t0, a3, -4 + c->dsll(a3, a3, 4); // dsll a3, a3, 4 + c->dsrav(t0, v1, t0); // dsrav t0, v1, t0 + c->daddiu(a3, a3, -175); // daddiu a3, a3, -175 + c->andi(t0, t0, 15); // andi t0, t0, 15 + // nop // sll r0, r0, 0 + //beq r0, r0, L23 // beq r0, r0, L23 + c->daddu(a3, a3, t0); // daddu a3, a3, t0 + goto block_3; // branch always + + + block_2: + c->daddiu(t0, a3, -5); // daddiu t0, a3, -5 + c->dsll(a3, a3, 5); // dsll a3, a3, 5 + c->dsrav(t0, v1, t0); // dsrav t0, v1, t0 + c->daddiu(a3, a3, -350); // daddiu a3, a3, -350 + c->andi(t0, t0, 31); // andi t0, t0, 31 + // nop // sll r0, r0, 0 + c->daddu(a3, a3, t0); // daddu a3, a3, t0 + // nop // sll r0, r0, 0 + + block_3: + c->andi(a3, a3, 4095); // andi a3, a3, 4095 + c->lhu(t1, 12, a1); // lhu t1, 12(a1) + c->dsll32(a3, a3, 0); // dsll32 a3, a3, 0 + c->lbu(v1, 27, a1); // lbu v1, 27(a1) + c->or_(a2, a2, a3); // or a2, a2, a3 + c->dsll(v1, v1, 14); // dsll v1, v1, 14 + c->sd(a2, 16, a0); // sd a2, 16(a0) + c->or_(a2, t1, v1); // or a2, t1, v1 + c->lhu(v1, 14, a1); // lhu v1, 14(a1) + // nop // sll r0, r0, 0 + c->lbu(a3, 28, a1); // lbu a3, 28(a1) + c->dsll(v1, v1, 20); // dsll v1, v1, 20 + c->or_(a2, a2, v1); // or a2, a2, v1 + c->dsll32(a3, a3, 2); // dsll32 a3, a3, 2 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->lhu(v1, 16, a1); // lhu v1, 16(a1) + c->lbu(a3, 29, a1); // lbu a3, 29(a1) + c->dsll32(v1, v1, 8); // dsll32 v1, v1, 8 + c->or_(a2, a2, v1); // or a2, a2, v1 + c->dsll32(a3, a3, 22); // dsll32 a3, a3, 22 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->lbu(t0, 4, a1); // lbu t0, 4(a1) + c->daddiu(t0, t0, -5); // daddiu t0, t0, -5 + c->sd(a2, 32, a0); // sd a2, 32(a0) + bc = ((s64)c->sgpr64(t0)) < 0; // bltz t0, L24 + c->lbu(a3, 30, a1); // lbu a3, 30(a1) + if (bc) {goto block_5;} // branch non-likely + + c->lhu(a2, 18, a1); // lhu a2, 18(a1) + c->dsll(a3, a3, 14); // dsll a3, a3, 14 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->lhu(v1, 20, a1); // lhu v1, 20(a1) + c->dsll(v1, v1, 20); // dsll v1, v1, 20 + c->lbu(a3, 31, a1); // lbu a3, 31(a1) + c->or_(a2, a2, v1); // or a2, a2, v1 + c->dsll32(a3, a3, 2); // dsll32 a3, a3, 2 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->lhu(v1, 22, a1); // lhu v1, 22(a1) + c->dsll32(v1, v1, 8); // dsll32 v1, v1, 8 + c->lbu(a3, 32, a1); // lbu a3, 32(a1) + c->or_(a2, a2, v1); // or a2, a2, v1 + c->dsll32(a3, a3, 22); // dsll32 a3, a3, 22 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->addiu(v1, r0, 54); // addiu v1, r0, 54 + c->sd(a2, 64, a0); // sd a2, 64(a0) + // nop // sll r0, r0, 0 + c->sw(v1, 72, a0); // sw v1, 72(a0) + // nop // sll r0, r0, 0 + + block_5: + c->mov64(v0, a0); // or v0, a0, r0 + //jr ra // jr ra + c->daddu(sp, sp, r0); // daddu sp, sp, r0 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + gLinkedFunctionTable.reg("adgif-shader<-texture-with-update!", execute, 128); +} + +} // namespace adgif_shader<_texture_with_update +} // namespace Mips2C + diff --git a/game/mips2c/mips2c_private.h b/game/mips2c/mips2c_private.h index 3331dcc51..0080daef3 100644 --- a/game/mips2c/mips2c_private.h +++ b/game/mips2c/mips2c_private.h @@ -6,6 +6,7 @@ #include "common/common_types.h" #include "game/mips2c/mips2c_table.h" #include "common/util/assert.h" +#include "common/util/BitUtils.h" #include "third-party/fmt/core.h" // This file contains utility functions for code generated by the mips2c pass. @@ -162,6 +163,12 @@ struct ExecutionContext { float Q; + void copy_vfs_from_other(const ExecutionContext* other) { + for (int i = 0; i < 32; i++) { + vfs[i] = other->vfs[i]; + } + } + u128 vf_src(int idx) { if (idx == 0) { u128 result; @@ -495,6 +502,9 @@ struct ExecutionContext { } void dsra(int dst, int src, int sa) { gprs[dst].ds64[0] = gpr_src(src).ds64[0] >> sa; } + void dsrav(int dst, int src, int sa) { + gprs[dst].ds64[0] = gpr_src(src).ds64[0] >> gpr_src(sa).du32[0]; + } void dsra32(int dst, int src, int sa) { gprs[dst].ds64[0] = gpr_src(src).ds64[0] >> (32 + sa); } void sra(int dst, int src, int sa) { gprs[dst].ds64[0] = gpr_src(src).ds32[0] >> sa; } void dsll(int dst, int src0, int sa) { gprs[dst].du64[0] = gpr_src(src0).du64[0] << sa; } @@ -518,7 +528,11 @@ struct ExecutionContext { } void dsubu(int dst, int src0, int src1) { gprs[dst].du64[0] = sgpr64(src0) - sgpr64(src1); } + void subu(int dst, int src0, int src1) { + gprs[dst].ds64[0] = gpr_src(src0).ds32[0] - gpr_src(src1).ds32[0]; + } void xor_(int dst, int src0, int src1) { gprs[dst].du64[0] = sgpr64(src0) ^ sgpr64(src1); } + void or_(int dst, int src0, int src1) { gprs[dst].du64[0] = sgpr64(src0) | sgpr64(src1); } void movz(int dst, int src0, int src1) { if (sgpr64(src1) == 0) { @@ -578,6 +592,21 @@ struct ExecutionContext { gprs[dst].du16[7] = s0.du16[3]; } + u32 lzocw(s32 in) { + if (in < 0) { + in = ~in; + } + if (in == 0) { + return 32; + } + return count_leading_zeros_u32(in); + } + + void plzcw(int dst, int src) { + gprs[dst].du32[0] = lzocw(gpr_src(src).ds32[0]) - 1; + gprs[dst].du32[1] = lzocw(gpr_src(src).ds32[1]) - 1; + } + void por(int dst, int src0, int src1) { auto s0 = gpr_src(src0); auto s1 = gpr_src(src1); @@ -646,6 +675,16 @@ struct ExecutionContext { void muls(int dst, int src0, int src1) { fprs[dst] = fprs[src0] * fprs[src1]; } void adds(int dst, int src0, int src1) { fprs[dst] = fprs[src0] + fprs[src1]; } void subs(int dst, int src0, int src1) { fprs[dst] = fprs[src0] - fprs[src1]; } + void divs(int dst, int src0, int src1) { + assert(fprs[src1] != 0); + fprs[dst] = fprs[src0] / fprs[src1]; + } + void negs(int dst, int src) { + u32 v; + memcpy(&v, &fprs[src], 4); + v ^= 0x80000000; + memcpy(&fprs[dst], &v, 4); + } void cvtws(int dst, int src) { // float to int @@ -659,6 +698,13 @@ struct ExecutionContext { memcpy(&value, &fprs[src], 4); fprs[dst] = value; } + + void vwaitq() {} + + std::string print_vf_float(int vf) { + auto src = vf_src(vf); + return fmt::format("{} {} {} {}", src.f[0], src.f[1], src.f[2], src.f[3]); + } }; } // namespace Mips2C \ No newline at end of file diff --git a/game/mips2c/mips2c_table.cpp b/game/mips2c/mips2c_table.cpp index eba75deb7..9cd405ba7 100644 --- a/game/mips2c/mips2c_table.cpp +++ b/game/mips2c/mips2c_table.cpp @@ -36,20 +36,60 @@ namespace sp_process_block_2d { extern void link(); } +namespace draw_large_polygon { +extern void link(); +} + +namespace init_sky_regs { +extern void link(); +} + +namespace clip_polygon_against_positive_hyperplane { +extern void link(); +} + +namespace render_sky_quad { +extern void link(); +} + +namespace render_sky_tri { +extern void link(); +} + +namespace set_tex_offset { +extern void link(); +} + +namespace set_sky_vf27 { +extern void link(); +} + +namespace set_sky_vf23_value { +extern void link(); +} + +namespace adgif_shader_texture_with_update { +extern void link(); +} + LinkedFunctionTable gLinkedFunctionTable; Rng gRng; std::unordered_map> gMips2CLinkCallbacks = { {"font", {draw_string::link}}, {"sparticle-launcher", {sp_init_fields::link, particle_adgif::link, sp_launch_particles_var::link}}, - {"sparticle", {sp_process_block_3d::link, sp_process_block_2d::link}}}; + {"sparticle", {sp_process_block_3d::link, sp_process_block_2d::link}}, + {"texture", {adgif_shader_texture_with_update::link}}, + {"sky-tng", + {draw_large_polygon::link, init_sky_regs::link, clip_polygon_against_positive_hyperplane::link, + render_sky_quad::link, render_sky_tri::link, set_tex_offset::link, set_sky_vf27::link, + set_sky_vf23_value::link}}}; void LinkedFunctionTable::reg(const std::string& name, u64 (*exec)(void*), u32 stack_size) { const auto& it = m_executes.insert({name, {exec, Ptr()}}); if (!it.second) { lg::error("MIPS2C Function {} is registered multiple times, ignoring later registrations.", name); - return; } // this is short stub that will jump to the appropriate function. diff --git a/goal_src/engine/debug/default-menu.gc b/goal_src/engine/debug/default-menu.gc index ee1230cb8..9c4baedbb 100644 --- a/goal_src/engine/debug/default-menu.gc +++ b/goal_src/engine/debug/default-menu.gc @@ -7,7 +7,7 @@ ;; Forward declarations for stuff we haven't written yet: (define-extern external-cam-reset! (function none)) -(define-extern time-of-day-setup (function symbol none)) +(define-extern time-of-day-setup (function symbol symbol)) (define-extern *compact-actors* symbol) (define-extern find-instance-by-name (function string instance)) (define-extern *edit-instance* string) diff --git a/goal_src/engine/dma/dma-buffer.gc b/goal_src/engine/dma/dma-buffer.gc index 8dfaa0a8b..155f2c821 100644 --- a/goal_src/engine/dma/dma-buffer.gc +++ b/goal_src/engine/dma/dma-buffer.gc @@ -52,6 +52,10 @@ (deftype dma-gif-packet (structure) ((dma-vif dma-packet :inline :offset-assert 0) (gif uint64 2 :offset-assert 16) ;; guess + ;; these two were added to make it easier. + (gif0 uint64 :offset 16) + (gif1 uint64 :offset 24) + (quad uint128 2 :offset 0) ) :method-count-assert 9 diff --git a/goal_src/engine/dma/dma-h.gc b/goal_src/engine/dma/dma-h.gc index 146b83ff2..318fe46ca 100644 --- a/goal_src/engine/dma/dma-h.gc +++ b/goal_src/engine/dma/dma-h.gc @@ -234,8 +234,10 @@ (generic-foreground 30) ;; ? (alpha-tex0 31) + (sky-tex0 32) (alpha-tex1 38) + (sky-tex1 39) (bucket-45 45) (bucket-46 46) diff --git a/goal_src/engine/draw/drawable.gc b/goal_src/engine/draw/drawable.gc index 8a1499229..3a0830425 100644 --- a/goal_src/engine/draw/drawable.gc +++ b/goal_src/engine/draw/drawable.gc @@ -127,9 +127,21 @@ ) ) - ;; texture common ;; sky + ;; todo - disabled sky + (when (logtest? *vu1-enable-user* 8) + (cond + ((and (-> *time-of-day-context* sky) *sky-drawn*) + (render-sky-tng *time-of-day-context*) + ) + (else + ;; todo + ) + ) + ) + ;; tod update + (update-time-of-day *time-of-day-context*) ;; closest ;; ocean ;; merc diff --git a/goal_src/engine/gfx/hw/gs.gc b/goal_src/engine/gfx/hw/gs.gc index 071432c04..e09afc33f 100644 --- a/goal_src/engine/gfx/hw/gs.gc +++ b/goal_src/engine/gfx/hw/gs.gc @@ -789,7 +789,7 @@ ;; some nice blue. probably the same as the fog color for geyser/sandover/etc. ;; "default" fog color when resetting registers -(define *fog-color* #xc88029) +(define *fog-color* (the-as rgba (new 'static 'rgba :r #x29 :g #x80 :b #xc8))) ;; set up a DMA buffer. This will hold a message to set the GS state to normal. ;; these regs are NOT the ones mapped in the EE memory, but other internal GS registers. diff --git a/goal_src/engine/gfx/sky/sky-h.gc b/goal_src/engine/gfx/sky/sky-h.gc index 1d47b8503..fdec7467d 100644 --- a/goal_src/engine/gfx/sky/sky-h.gc +++ b/goal_src/engine/gfx/sky/sky-h.gc @@ -126,9 +126,9 @@ ) (deftype sky-tng-data (basic) - ((giftag-base qword :inline :offset-assert 16) - (giftag-roof qword :inline :offset-assert 32) - (giftag-ocean qword :inline :offset-assert 48) + ((giftag-base gs-gif-tag :inline :offset-assert 16);; changed + (giftag-roof gs-gif-tag :inline :offset-assert 32) + (giftag-ocean gs-gif-tag :inline :offset-assert 48) (fog vector :inline :offset-assert 64) (sky uint32 8 :offset-assert 80) (time float :offset-assert 112) @@ -146,8 +146,8 @@ ((adgif-tmpl dma-gif-packet :inline :offset-assert 0) (draw-tmpl dma-gif-packet :inline :offset-assert 32) (blend-tmpl dma-gif-packet :inline :offset-assert 64) - (sky-data uint128 5 :offset-assert 96) - (cloud-data uint128 5 :offset-assert 176) + (sky-data qword 5 :inline :offset-assert 96) + (cloud-data qword 5 :inline :offset-assert 176) ) :method-count-assert 9 :size-assert #x100 @@ -166,3 +166,9 @@ (define *sky-drawn* #f) (define *cloud-drawn* #f) + + +(declare-type time-of-day-context basic) +(define-extern update-sky-tng-data (function float none)) +(define-extern make-sky-textures (function time-of-day-context int none)) +(define-extern sky-base-polygons (inline-array sky-vertex)) \ No newline at end of file diff --git a/goal_src/engine/gfx/sky/sky-tng.gc b/goal_src/engine/gfx/sky/sky-tng.gc index 33d7dcfad..4de28a024 100644 --- a/goal_src/engine/gfx/sky/sky-tng.gc +++ b/goal_src/engine/gfx/sky/sky-tng.gc @@ -5,3 +5,1332 @@ ;; name in dgo: sky-tng ;; dgos: GAME, ENGINE +(rlet ((st :reg r14 :type uint)) + (format 0 "-------> ~A~%" (+ st #x4c58)) + ) + +(define *sky-work* + (new 'static 'sky-work + ;; usual 5x a+d + :adgif-tmpl (new 'static 'dma-gif-packet + :dma-vif (new 'static 'dma-packet + :dma (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt)) + :vif1 (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1) + ) + :gif0 (new 'static 'gif-tag64 :nloop #x5 :eop #x1 :nreg #x1) + :gif1 (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d)) + ) + ;; sprite with texture + :draw-tmpl (new 'static 'dma-gif-packet + :dma-vif (new 'static 'dma-packet + :dma (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt)) + :vif1 (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1) + ) + #| + :gif0 (new 'static 'gif-tag64 + :nloop #x1 + :eop #x1 + :pre #x1 + :prim (new 'static 'gs-prim :prim (gs-prim-type sprite) :tme #x1 :fst #x1) + :nreg #x5 + ) + :gif1 (new 'static 'gif-tag-regs + :regs0 (gif-reg-id rgbaq) + :regs1 (gif-reg-id uv) + :regs2 (gif-reg-id xyzf2) + :regs3 (gif-reg-id uv) + :regs4 (gif-reg-id xyzf2) + ) + |# + :gif (new 'static 'array uint64 2 #x508b400000008001 #x43431) + ) + ;; sprite with texture and abe (alpha blend enable) + :blend-tmpl (new 'static 'dma-gif-packet + :dma-vif (new 'static 'dma-packet + :dma (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt)) + :vif1 (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1) + ) + #| + :gif0 (new 'static 'gif-tag64 + :nloop #x1 + :eop #x1 + :pre #x1 + :prim (new 'static 'gs-prim :prim (gs-prim-type sprite) :tme #x1 :abe #x1 :fst #x1) + :nreg #x5 + ) + :gif1 (new 'static 'gif-tag-regs + :regs0 (gif-reg-id rgbaq) + :regs1 (gif-reg-id uv) + :regs2 (gif-reg-id xyzf2) + :regs3 (gif-reg-id uv) + :regs4 (gif-reg-id xyzf2) + ) + |# + :gif (new 'static 'array uint64 2 #x50ab400000008001 #x43431) + ) + :sky-data (new 'static 'inline-array qword 5 + (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x0 #x0 #x80)) + (new 'static 'qword) + (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x0 #xffffff #x0)) + (new 'static 'qword :data (new 'static 'array uint32 4 #x200 #x200 #x0 #x0)) + (new 'static 'qword :data (new 'static 'array uint32 4 #x200 #x200 #xffffff #x0)) + ) + :cloud-data (new 'static 'inline-array qword 5 + (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x0 #x0 #x80)) + (new 'static 'qword) + (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x200 #xffffff #x0)) + (new 'static 'qword :data (new 'static 'array uint32 4 #x400 #x400 #x0 #x0)) + (new 'static 'qword :data (new 'static 'array uint32 4 #x400 #x600 #xffffff #x0)) + ) + ) + ) + +(defun init-sky-tng-data ((arg0 sky-tng-data)) + "Set up giftags and constants in a sky-tng data" + (set! (-> arg0 giftag-base tag) + (new 'static 'gif-tag64 + :nloop #x1 + :eop #x1 + :pre #x1 + :prim (new 'static 'gs-prim :prim (gs-prim-type tri-fan)) + :nreg #x3 + ) + ) + (set! (-> arg0 giftag-base regs) + (new 'static 'gif-tag-regs + :regs0 (gif-reg-id st) + :regs1 (gif-reg-id rgbaq) + :regs2 (gif-reg-id xyzf2) + ) + ) + (set! (-> arg0 giftag-roof tag) + (new 'static 'gif-tag64 + :nloop #x1 + :eop #x1 + :pre #x1 + :prim (new 'static 'gs-prim :prim (gs-prim-type tri-fan) :iip #x1 :tme #x1 :abe #x1) + :nreg #x3 + ) + ) + (set! (-> arg0 giftag-roof regs) + (new 'static 'gif-tag-regs + :regs0 (gif-reg-id st) + :regs1 (gif-reg-id rgbaq) + :regs2 (gif-reg-id xyzf2) + ) + ) + (set! (-> arg0 giftag-ocean tag) + (new 'static 'gif-tag64 + :nloop #x1 + :eop #x1 + :pre #x1 + :prim (new 'static 'gs-prim :prim (gs-prim-type tri-fan) :iip #x1 :tme #x1 :fge #x1) + :nreg #x3 + ) + ) + (set! (-> arg0 giftag-ocean regs) + (new 'static 'gif-tag-regs + :regs0 (gif-reg-id st) + :regs1 (gif-reg-id rgbaq) + :regs2 (gif-reg-id xyzf2) + ) + ) + (set! (-> arg0 time) 0.0) + (set! (-> arg0 off-s-0) (the-as uint 0)) + (set! (-> arg0 off-t-0) (the-as uint 0)) + (set! (-> arg0 off-s-1) (the-as uint 0)) + (set! (-> arg0 off-t-1) (the-as uint 0)) + 0 + (none) + ) + + +;; create our sky data +(define *sky-tng-data* (new 'global 'sky-tng-data)) +(init-sky-tng-data *sky-tng-data*) + +(defmethod inspect sky-vertex ((obj sky-vertex)) + (format #t "sky-vertex [~X]:~%" obj) + (format #t "~TPos: [~F ~F ~F ~F]~%" + (-> obj pos x) + (-> obj pos y) + (-> obj pos z) + (-> obj pos w) + ) + (format #t "~TSTQ: [~F ~F ~F ~F]~%" + (-> obj stq x) + (-> obj stq y) + (-> obj stq z) + (-> obj stq w) + ) + (format #t "~TCol: [~F ~F ~F ~F]~%" + (-> obj col x) + (-> obj col y) + (-> obj col z) + (-> obj col w) + ) + obj + ) + +(defun update-sky-tng-data ((arg0 float)) + (sky-make-sun-data *sky-parms* 0 arg0) + (sky-make-sun-data *sky-parms* 1 arg0) + (sky-make-moon-data *sky-parms* arg0) + (let ((v1-0 *sky-tng-data*)) + (+! (-> v1-0 off-s-0) 16) + (+! (-> v1-0 off-t-0) 32) + (+! (-> v1-0 off-s-1) -21) + (+! (-> v1-0 off-t-1) 42) + (set! (-> v1-0 time) arg0) + ) + 0 + (none) + ) + +#| +(defun init-sky-regs () + "Initialize vf VU0 registers for sky." + (rlet ((vf0 :class vf) + (vf13 :class vf) + (vf14 :class vf) + (vf23 :class vf) + (vf24 :class vf) + (vf25 :class vf) + (vf26 :class vf) + (vf28 :class vf) + (vf29 :class vf) + (vf30 :class vf) + (vf31 :class vf) + ) + (init-vf0-vector) + + (with-vf (vf13 vf14 vf23 vf24 vf25 vf26 vf28 vf29 vf30 vf31) + :rw 'write + + (let ((v1-0 *math-camera*) + (a0-0 (new-stack-vector0)) + ) + (set! (-> a0-0 quad) (-> v1-0 hvdf-off quad)) + (if (< 0.0 (-> v1-0 trans y)) + (set! (-> a0-0 y) 2049.0) + (set! (-> a0-0 y) 2047.0) + ) + (set-vector! + (-> *sky-tng-data* fog) + (-> v1-0 pfog0) + (-> v1-0 fog-min) + (-> v1-0 fog-max) + 3071.0 + ) + (.lvf vf31 (&-> v1-0 camera-temp vector 0 quad)) + (.lvf vf30 (&-> v1-0 camera-temp vector 1 quad)) + (.lvf vf29 (&-> v1-0 camera-temp vector 2 quad)) + (.lvf vf28 (&-> v1-0 camera-temp vector 3 quad)) + (.lvf vf14 (&-> v1-0 hmge-scale quad)) + (.lvf vf26 (&-> v1-0 inv-hmge-scale quad)) + (.lvf vf25 (&-> a0-0 quad)) + ) + (.lvf vf13 (&-> *sky-tng-data* fog quad)) + (.mul.vf vf31 vf31 vf14) + (.mul.vf vf30 vf30 vf14) + (.mul.vf vf29 vf29 vf14) + (.mul.vf vf28 vf28 vf14) + (.mov.vf vf25 vf0 :mask #b100) + (.mov.vf vf24 vf0) + (.mov.vf vf23 vf0) + ) + ;;(.mov v1-2 vf23) + 0 + (none) + ) + ) +|# +;; The init-sky-regs stashes some stuff in vf regs. We are going to stash that stuff in C++, not the usual registers +;; because everything that uses this is in MIPS2C anyway. +(def-mips2c init-sky-regs (function none)) +(def-mips2c set-sky-vf27 (function object none)) +(def-mips2c set-sky-vf23-value (function int none)) + + +#| +(defun set-tex-offset ((arg0 int) (arg1 int)) + (with-vf (vf24) :rw 'write + (let ((v1-0 (new-stack-vector0))) + (set! (-> v1-0 x) (* 0.000015258789 (the float arg0))) + (set! (-> v1-0 y) (* 0.000015258789 (the float arg1))) + (set! (-> v1-0 z) 0.0) + (set! (-> v1-0 w) 0.0) + (.lvf vf24 (&-> v1-0 quad)) + ) + ;;(.mov v1-1 vf24) + 0 + (none) + ) + ) +|# +;; same is true for set-tex-offset +(def-mips2c set-tex-offset (function int int none)) + +;; there are a bunch of weird functions that don't use normal calling conventions. +;; these are all handled in C++ and aren't accessible from GOAL. + +;; draw-large-polygon +;; clip-polygon-against-positive-hyperplane +;; clip-polygon-against-negative-hyperplane + +;; we do need to expose 2 functions: +(def-mips2c render-sky-quad (function int dma-buffer none)) +(def-mips2c render-sky-tri (function (inline-array sky-vertex) dma-buffer none)) + + +; there's also a sky-duplicate-polys but it's never used. + +(defun close-sky-buffer ((arg0 dma-buffer)) + (nop!) + (let ((v1-0 #x8000) + (v0-0 (-> arg0 base)) + ) + (set! (-> (the-as (pointer uint128) v0-0)) (the uint128 0)) + (nop!) + (set! (-> (the-as (pointer int32) v0-0)) v1-0) + (let ((v0-1 (&+ v0-0 16))) + ;; to save like 1 instruction they put this in the delay slot of the jr-ra + ;;(.jr ra-0) + (set! (-> arg0 base) v0-1) + ) + ) + (none) + ) + +(define + sky-base-polygons + (new 'static 'inline-array sky-vertex 12 + (new 'static 'sky-vertex + :pos (new 'static 'vector :z -40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :x 40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :y -40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :x 40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :z 40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :y -40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :z 40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :x -40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :y -40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :x -40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :z -40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :y -40960000.0) + :col + (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0) + ) + ) + ) + +(define + sky-roof-polygons + (new 'static 'inline-array sky-vertex 12 + (new 'static 'sky-vertex + :pos (new 'static 'vector :z -40960000.0) + :stq (new 'static 'vector :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :x 40960000.0) + :stq (new 'static 'vector :x 1.0 :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :y 10240000.0) + :stq + (new 'static 'vector :x 0.5 :y 0.5 :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :x 40960000.0) + :stq (new 'static 'vector :x 1.0 :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :z 40960000.0) + :stq + (new 'static 'vector :x 1.0 :y 1.0 :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :y 10240000.0) + :stq + (new 'static 'vector :x 0.5 :y 0.5 :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :z 40960000.0) + :stq + (new 'static 'vector :x 1.0 :y 1.0 :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :x -40960000.0) + :stq (new 'static 'vector :y 1.0 :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :y 10240000.0) + :stq + (new 'static 'vector :x 0.5 :y 0.5 :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :x -40960000.0) + :stq (new 'static 'vector :y 1.0 :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :z -40960000.0) + :stq (new 'static 'vector :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + (new 'static 'sky-vertex + :pos (new 'static 'vector :y 10240000.0) + :stq + (new 'static 'vector :x 0.5 :y 0.5 :z 1.0) + :col + (new 'static 'vector :x 128.0 :y 128.0 :z 128.0 :w 128.0) + ) + ) + ) + +(define + sky-cloud-polygons + (new 'static 'inline-array sky-vertex 72 + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + (new 'static 'sky-vertex) + ) + ) + +(define + sky-cloud-polygon-indices + (new 'static 'array uint8 48 + #x0 #x1 #x9 #x8 + #x1 #x2 #xa #x9 + #x2 #x3 #xb #xa + #x3 #x0 #x8 #xb + #x8 #x9 #x5 #x4 + #x9 #xa #x6 #x5 + #xa #xb #x7 #x6 + #xb #x8 #x4 #x7 + #x4 #x5 #x6 #x7 + #x0 #x0 #x0 #x0 + #x0 #x0 #x0 #x0 + #x0 #x0 #x0 #x0 + ) + ) + +(defun sky-tng-setup-cloud-layer ((arg0 float) (arg1 float) (arg2 vector) (arg3 (inline-array sky-vertex))) + (let ((f28-0 (sqrtf (- 1.0 (* arg0 arg0)))) + (f26-0 (sqrtf (- 1.0 (* arg1 arg1)))) + (s5-0 (new 'stack-no-clear 'inline-array 'sky-vertex 12)) + ) + (dotimes (s1-0 12) + ((method-of-type sky-vertex new) (the-as symbol (-> s5-0 s1-0)) sky-vertex) + ) + (let ((f30-0 0.5)) + (let ((f9-0 -22.0) + (f10-0 22.0) + (f11-0 -22.0) + (f8-0 22.0) + (f6-0 -4.0) + (f7-0 5.0) + (f12-0 -5.0) + (f13-0 4.0) + (f1-4 -2.0) + (f2-2 2.0) + (f4-0 -2.0) + (f0-4 2.0) + ) + 0.0 + 1.0 + -1.0 + 0.0 + (let* ((f3-5 (/ (- f1-4 f9-0) (- f10-0 f9-0))) + (f5-2 (/ (- f2-2 f9-0) (- f10-0 f9-0))) + (f15-1 (/ (- f4-0 f11-0) (- f8-0 f11-0))) + (f14-3 (/ (- f0-4 f11-0) (- f8-0 f11-0))) + (f3-7 (+ f6-0 (* f3-5 (- f7-0 f6-0)))) + (f5-4 (+ f6-0 (* f5-2 (- f7-0 f6-0)))) + ) + (+ f12-0 (* f15-1 (- f13-0 f12-0))) + (+ f12-0 (* f14-3 (- f13-0 f12-0))) + (let ((v1-5 (-> s5-0 0))) + (set! (-> v1-5 pos x) f9-0) + (set! (-> v1-5 pos y) 0.0) + (set! (-> v1-5 pos z) f11-0) + (set! (-> v1-5 pos w) 0.0) + ) + (let ((v1-6 (-> s5-0 1))) + (set! (-> v1-6 pos x) f10-0) + (set! (-> v1-6 pos y) 0.0) + (set! (-> v1-6 pos z) f11-0) + (set! (-> v1-6 pos w) 0.0) + ) + (let ((v1-7 (-> s5-0 2))) + (set! (-> v1-7 pos x) f10-0) + (set! (-> v1-7 pos y) 0.0) + (set! (-> v1-7 pos z) f8-0) + (set! (-> v1-7 pos w) 0.0) + ) + (let ((v1-8 (-> s5-0 3))) + (set! (-> v1-8 pos x) f9-0) + (set! (-> v1-8 pos y) 0.0) + (set! (-> v1-8 pos z) f8-0) + (set! (-> v1-8 pos w) 0.0) + ) + (set-vector! (-> s5-0 0 stq) f6-0 f6-0 1.0 1.0) + (set-vector! (-> s5-0 1 stq) f7-0 f6-0 1.0 1.0) + (set-vector! (-> s5-0 2 stq) f7-0 f7-0 1.0 1.0) + (set-vector! (-> s5-0 3 stq) f6-0 f7-0 1.0 1.0) + (let ((v1-13 (-> s5-0 4))) + (set! (-> v1-13 pos x) f1-4) + (set! (-> v1-13 pos y) 1.0) + (set! (-> v1-13 pos z) f4-0) + (set! (-> v1-13 pos w) 0.0) + ) + (let ((v1-14 (-> s5-0 5))) + (set! (-> v1-14 pos x) f2-2) + (set! (-> v1-14 pos y) 1.0) + (set! (-> v1-14 pos z) f4-0) + (set! (-> v1-14 pos w) 0.0) + ) + (let ((v1-15 (-> s5-0 6))) + (set! (-> v1-15 pos x) f2-2) + (set! (-> v1-15 pos y) 1.0) + (set! (-> v1-15 pos z) f0-4) + (set! (-> v1-15 pos w) 0.0) + ) + (let ((v1-16 (-> s5-0 7))) + (set! (-> v1-16 pos x) f1-4) + (set! (-> v1-16 pos y) 1.0) + (set! (-> v1-16 pos z) f0-4) + (set! (-> v1-16 pos w) 0.0) + ) + (set-vector! (-> s5-0 4 stq) f3-7 f3-7 1.0 1.0) + (set-vector! (-> s5-0 5 stq) f5-4 f3-7 1.0 1.0) + (set-vector! (-> s5-0 6 stq) f5-4 f5-4 1.0 1.0) + (set-vector! (-> s5-0 7 stq) f3-7 f5-4 1.0 1.0) + ) + ) + (dotimes (v1-21 4) + (let ((f0-14 (-> s5-0 v1-21 pos x)) + (f1-6 (-> s5-0 v1-21 pos z)) + ) + (set! (-> s5-0 v1-21 pos x) (+ (* f0-14 f26-0) (* f1-6 arg1))) + (set! (-> s5-0 v1-21 pos z) (- (* f1-6 f26-0) (* f0-14 arg1))) + ) + (set! (-> s5-0 v1-21 col quad) (-> arg2 quad)) + (set! (-> s5-0 v1-21 col w) 0.0) + ) + (dotimes (v1-24 4) + (let ((f0-18 (-> s5-0 (+ v1-24 4) pos x)) + (f1-8 (-> s5-0 (+ v1-24 4) pos z)) + ) + (set! (-> s5-0 (+ v1-24 4) pos x) (+ (* f0-18 f28-0) (* f1-8 arg0))) + (set! (-> s5-0 (+ v1-24 4) pos z) (- (* f1-8 f28-0) (* f0-18 arg0))) + ) + (set! (-> s5-0 (+ v1-24 4) col quad) (-> arg2 quad)) + ) + (dotimes (s3-1 4) + (vector4-lerp! + (the-as vector (-> s5-0 (+ s3-1 8))) + (the-as vector (-> s5-0 s3-1)) + (the-as vector (-> s5-0 (+ s3-1 4))) + f30-0 + ) + (vector4-lerp! + (-> s5-0 (+ s3-1 8) stq) + (-> s5-0 s3-1 stq) + (-> s5-0 (+ s3-1 4) stq) + f30-0 + ) + (set! (-> s5-0 (+ s3-1 8) col quad) (-> arg2 quad)) + ) + ) + (dotimes (v1-51 36) + (let ((a0-47 (-> sky-cloud-polygon-indices v1-51))) + (set! (-> arg3 v1-51 pos quad) (-> s5-0 a0-47 pos quad)) + (set! (-> arg3 v1-51 stq quad) (-> s5-0 a0-47 stq quad)) + (set! (-> arg3 v1-51 col quad) (-> s5-0 a0-47 col quad)) + ) + ) + ) + 0 + (none) + ) + +(defun sky-tng-setup-clouds () + (let ((a2-0 (new 'static 'vector :x 20.0 :y 20.0 :z 20.0 :w 128.0)) + (gp-0 (new 'static 'vector :x 20.0 :y 20.0 :z 30.0 :w 128.0)) + ) + (sky-tng-setup-cloud-layer 0.0 0.0 a2-0 sky-cloud-polygons) + (sky-tng-setup-cloud-layer + 0.05584 + 0.01396 + gp-0 + (the-as (inline-array sky-vertex) (-> sky-cloud-polygons 36)) + ) + ) + 0 + (none) + ) + +(sky-tng-setup-clouds) + +(defun render-sky-tng ((arg0 time-of-day-context)) + (local-vars (v1-84 float)) + (rlet ((vf23 :class vf) + (vf27 :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 + ((gp-0 (-> *display* frames (-> *display* on-screen) frame global-buf base)) + ) + (let* + ((s4-0 (-> *display* frames (-> *display* on-screen) frame global-buf)) + (s5-0 (-> s4-0 base)) + ) + (let* ((v1-14 s4-0) + (a0-11 (the-as object (-> v1-14 base))) + ) + (set! + (-> (the-as dma-packet a0-11) dma) + (new 'static 'dma-tag :qwc #x4 :id (dma-tag-id cnt)) + ) + (set! (-> (the-as dma-packet a0-11) vif0) (new 'static 'vif-tag)) + (set! + (-> (the-as dma-packet a0-11) vif1) + (new 'static 'vif-tag :imm #x4 :cmd (vif-cmd direct) :msk #x1) + ) + (set! (-> v1-14 base) (&+ (the-as pointer a0-11) 16)) + ) + (let* ((v1-15 s4-0) + (a0-13 (the-as object (-> v1-15 base))) + ) + (set! + (-> (the-as gs-gif-tag a0-13) tag) + (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x3) + ) + (set! + (-> (the-as gs-gif-tag a0-13) regs) + (new 'static 'gif-tag-regs + :regs0 (gif-reg-id a+d) + :regs1 (gif-reg-id a+d) + :regs2 (gif-reg-id a+d) + :regs3 (gif-reg-id a+d) + :regs4 (gif-reg-id a+d) + :regs5 (gif-reg-id a+d) + :regs6 (gif-reg-id a+d) + :regs7 (gif-reg-id a+d) + :regs8 (gif-reg-id a+d) + :regs9 (gif-reg-id a+d) + :regs10 (gif-reg-id a+d) + :regs11 (gif-reg-id a+d) + :regs12 (gif-reg-id a+d) + :regs13 (gif-reg-id a+d) + :regs14 (gif-reg-id a+d) + :regs15 (gif-reg-id a+d) + ) + ) + (set! (-> v1-15 base) (&+ (the-as pointer a0-13) 16)) + ) + (let* ((v1-16 s4-0) + (a0-15 (-> v1-16 base)) + ) + (set! + (-> (the-as (pointer gs-zbuf) a0-15) 0) + (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24)) + ) + (set! (-> (the-as (pointer gs-reg64) a0-15) 1) (gs-reg64 zbuf-1)) + (set! + (-> (the-as (pointer gs-test) a0-15) 2) + (new 'static 'gs-test + :ate #x1 + :atst (gs-atest always) + :zte #x1 + :ztst (gs-ztest always) + ) + ) + (set! (-> (the-as (pointer gs-reg64) a0-15) 3) (gs-reg64 test-1)) + (set! + (-> (the-as (pointer gs-alpha) a0-15) 4) + (new 'static 'gs-alpha :b #x1 :d #x1) + ) + (set! (-> (the-as (pointer gs-reg64) a0-15) 5) (gs-reg64 alpha-1)) + (set! (-> v1-16 base) (&+ a0-15 48)) + ) + (init-sky-regs) + ;;(.lvf vf27 (&-> *sky-tng-data* giftag-roof qword)) + (set-sky-vf27 (&-> *sky-tng-data* giftag-roof qword)) + (when *sky-drawn* + (let* ((v1-20 s4-0) + (a0-17 (the-as object (-> v1-20 base))) + ) + (set! + (-> (the-as dma-packet a0-17) dma) + (new 'static 'dma-tag :qwc #x5 :id (dma-tag-id cnt)) + ) + (set! (-> (the-as dma-packet a0-17) vif0) (new 'static 'vif-tag)) + (set! + (-> (the-as dma-packet a0-17) vif1) + (new 'static 'vif-tag :imm #x5 :cmd (vif-cmd direct) :msk #x1) + ) + (set! (-> v1-20 base) (&+ (the-as pointer a0-17) 16)) + ) + (let* ((v1-21 s4-0) + (a0-19 (the-as object (-> v1-21 base))) + ) + (set! + (-> (the-as gs-gif-tag a0-19) tag) + (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x4) + ) + (set! + (-> (the-as gs-gif-tag a0-19) regs) + (new 'static 'gif-tag-regs + :regs0 (gif-reg-id a+d) + :regs1 (gif-reg-id a+d) + :regs2 (gif-reg-id a+d) + :regs3 (gif-reg-id a+d) + :regs4 (gif-reg-id a+d) + :regs5 (gif-reg-id a+d) + :regs6 (gif-reg-id a+d) + :regs7 (gif-reg-id a+d) + :regs8 (gif-reg-id a+d) + :regs9 (gif-reg-id a+d) + :regs10 (gif-reg-id a+d) + :regs11 (gif-reg-id a+d) + :regs12 (gif-reg-id a+d) + :regs13 (gif-reg-id a+d) + :regs14 (gif-reg-id a+d) + :regs15 (gif-reg-id a+d) + ) + ) + (set! (-> v1-21 base) (&+ (the-as pointer a0-19) 16)) + ) + (let* ((s3-0 s4-0) + (s2-0 (-> s3-0 base)) + ) + (set! + (-> (the-as (pointer gs-tex0) s2-0) 0) + (new 'static 'gs-tex0 + :tbw #x1 + :th (log2 32) + :tw (log2 32) + :tbp0 *sky-base-block* + ) + ) + (set! (-> (the-as (pointer gs-reg64) s2-0) 1) (gs-reg64 tex0-1)) + (set! + (-> (the-as (pointer gs-tex1) s2-0) 2) + (new 'static 'gs-tex1 :mmag #x1 :mmin #x1) + ) + (set! (-> (the-as (pointer gs-reg64) s2-0) 3) (gs-reg64 tex1-1)) + (set! + (-> (the-as (pointer gs-clamp) s2-0) 4) + (new 'static 'gs-clamp + :wms (gs-tex-wrap-mode clamp) + :wmt (gs-tex-wrap-mode clamp) + ) + ) + (set! (-> (the-as (pointer gs-reg64) s2-0) 5) (gs-reg64 clamp-1)) + (set! (-> (the-as (pointer uint64) s2-0) 6) (the-as uint 0)) + (set! (-> (the-as (pointer gs-reg64) s2-0) 7) (gs-reg64 texflush)) + (set! (-> s3-0 base) (&+ s2-0 64)) + ) + (let ((s3-1 (the-as object (-> s4-0 base)))) + (&+! (-> s4-0 base) 16) + (render-sky-tri + (the-as (inline-array sky-vertex) (-> sky-roof-polygons 0)) + s4-0 + ) + (render-sky-tri + (the-as (inline-array sky-vertex) (-> sky-roof-polygons 3)) + s4-0 + ) + (render-sky-tri + (the-as (inline-array sky-vertex) (-> sky-roof-polygons 6)) + s4-0 + ) + (render-sky-tri + (the-as (inline-array sky-vertex) (-> sky-roof-polygons 9)) + s4-0 + ) + (close-sky-buffer s4-0) + (let ((v1-46 (/ (+ (- -16 (the-as int s3-1)) (the int (-> s4-0 base))) 16))) + (set! + (-> (the-as dma-packet s3-1) dma) + (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc v1-46) + ) + (set! (-> (the-as dma-packet s3-1) vif0) (new 'static 'vif-tag)) + (set! + (-> (the-as dma-packet s3-1) vif1) + (new 'static 'vif-tag :cmd (vif-cmd direct) :msk #x1 :imm v1-46) + ) + ) + ) + ) + (when *cloud-drawn* + (let* ((v1-52 s4-0) + (a0-32 (the-as object (-> v1-52 base))) + ) + (set! + (-> (the-as dma-packet a0-32) dma) + (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt)) + ) + (set! (-> (the-as dma-packet a0-32) vif0) (new 'static 'vif-tag)) + (set! + (-> (the-as dma-packet a0-32) vif1) + (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1) + ) + (set! (-> v1-52 base) (&+ (the-as pointer a0-32) 16)) + ) + (let* ((v1-53 s4-0) + (a0-34 (the-as object (-> v1-53 base))) + ) + (set! + (-> (the-as gs-gif-tag a0-34) tag) + (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x5) + ) + (set! + (-> (the-as gs-gif-tag a0-34) regs) + (new 'static 'gif-tag-regs + :regs0 (gif-reg-id a+d) + :regs1 (gif-reg-id a+d) + :regs2 (gif-reg-id a+d) + :regs3 (gif-reg-id a+d) + :regs4 (gif-reg-id a+d) + :regs5 (gif-reg-id a+d) + :regs6 (gif-reg-id a+d) + :regs7 (gif-reg-id a+d) + :regs8 (gif-reg-id a+d) + :regs9 (gif-reg-id a+d) + :regs10 (gif-reg-id a+d) + :regs11 (gif-reg-id a+d) + :regs12 (gif-reg-id a+d) + :regs13 (gif-reg-id a+d) + :regs14 (gif-reg-id a+d) + :regs15 (gif-reg-id a+d) + ) + ) + (set! (-> v1-53 base) (&+ (the-as pointer a0-34) 16)) + ) + (let* ((s3-2 s4-0) + (s2-1 (-> s3-2 base)) + ) + (set! + (-> (the-as (pointer gs-alpha) s2-1) 0) + (new 'static 'gs-alpha :b #x2 :d #x1) + ) + (set! (-> (the-as (pointer gs-reg64) s2-1) 1) (gs-reg64 alpha-1)) + (set! + (-> (the-as (pointer gs-tex0) s2-1) 2) + (new 'static 'gs-tex0 + :tbw #x1 + :th (log2 64) + :tw (log2 64) + :tbp0 (+ *sky-base-block* 32) + ) + ) + (set! (-> (the-as (pointer gs-reg64) s2-1) 3) (gs-reg64 tex0-1)) + (set! + (-> (the-as (pointer gs-tex1) s2-1) 4) + (new 'static 'gs-tex1 :mmag #x1 :mmin #x1) + ) + (set! (-> (the-as (pointer gs-reg64) s2-1) 5) (gs-reg64 tex1-1)) + (set! (-> (the-as (pointer gs-clamp) s2-1) 6) (new 'static 'gs-clamp)) + (set! (-> (the-as (pointer gs-reg64) s2-1) 7) (gs-reg64 clamp-1)) + (set! (-> (the-as (pointer int64) s2-1) 8) 0) + (set! (-> (the-as (pointer gs-reg64) s2-1) 9) (gs-reg64 texflush)) + (set! (-> s3-2 base) (&+ s2-1 80)) + ) + (let ((s3-3 (the-as object (-> s4-0 base)))) + (&+! (-> s4-0 base) 16) + (init-sky-regs) + (let ((s2-2 (the-as object (-> sky-cloud-polygons 0)))) + (set-tex-offset + (the-as int (-> *sky-tng-data* off-s-0)) + (the-as int (-> *sky-tng-data* off-t-0)) + ) + ;; first cloud layer + (dotimes (s1-4 9) + (render-sky-quad (the-as int s2-2) s4-0) + (set! s2-2 (-> (the-as (inline-array sky-vertex) s2-2) 4)) + ) + (set-tex-offset + (the-as int (-> *sky-tng-data* off-s-1)) + (the-as int (-> *sky-tng-data* off-t-1)) + ) + ;; second cloud layer + (dotimes (s1-5 9) + (render-sky-quad (the-as int s2-2) s4-0) + (set! s2-2 (-> (the-as (inline-array sky-vertex) s2-2) 4)) + ) + ) + ;;(.lvf vf27 (&-> *sky-tng-data* giftag-base qword)) + ;; these draw stuff below the horizon + (set-sky-vf27 (&-> *sky-tng-data* giftag-base qword)) + (set-sky-vf23-value #x43800000) + ; (let ((v1-83 #x43800000)) + ; (.mov vf23 v1-83) + ; ) + ; (.mov v1-84 vf23) + ; not sure what this is, but it draws on the + (render-sky-tri + (the-as (inline-array sky-vertex) (-> sky-base-polygons 0)) + s4-0 + ) + (render-sky-tri + (the-as (inline-array sky-vertex) (-> sky-base-polygons 3)) + s4-0 + ) + (render-sky-tri + (the-as (inline-array sky-vertex) (-> sky-base-polygons 6)) + s4-0 + ) + (render-sky-tri + (the-as (inline-array sky-vertex) (-> sky-base-polygons 9)) + s4-0 + ) + (close-sky-buffer s4-0) + (let ((v1-92 (/ (+ (- -16 (the-as int s3-3)) (the int (-> s4-0 base))) 16))) + (set! + (-> (the-as dma-packet s3-3) dma) + (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc v1-92) + ) + (set! (-> (the-as dma-packet s3-3) vif0) (new 'static 'vif-tag)) + (set! + (-> (the-as dma-packet s3-3) vif1) + (new 'static 'vif-tag :cmd (vif-cmd direct) :msk #x1 :imm v1-92) + ) + ) + ) + ) + (let ((a3-0 (-> s4-0 base))) + (let ((v1-96 (the-as object (-> s4-0 base)))) + (set! + (-> (the-as dma-packet v1-96) dma) + (new 'static 'dma-tag :id (dma-tag-id next)) + ) + (set! (-> (the-as dma-packet v1-96) vif0) (new 'static 'vif-tag)) + (set! (-> (the-as dma-packet v1-96) vif1) (new 'static 'vif-tag)) + (set! (-> s4-0 base) (&+ (the-as pointer v1-96) 16)) + ) + (dma-bucket-insert-tag + (-> *display* frames (-> *display* on-screen) frame bucket-group) + (bucket-id bucket-3) + s5-0 + (the-as (pointer dma-tag) a3-0) + ) + ) + ) + (let ((v1-101 *dma-mem-usage*)) + (when (nonzero? v1-101) + (set! (-> v1-101 length) (max 86 (-> v1-101 length))) + (set! (-> v1-101 data 85 name) "sky") + (+! (-> v1-101 data 85 count) 1) + (+! + (-> v1-101 data 85 used) + (&- + (-> *display* frames (-> *display* on-screen) frame global-buf base) + (the-as uint gp-0) + ) + ) + (set! (-> v1-101 data 85 total) (-> v1-101 data 85 used)) + ) + ) + ) + (if *debug-segment* + (add-frame + (-> *display* frames (-> *display* on-screen) frame profile-bar 0) + 'draw + (new 'static 'rgba :r #xff :b #xff :a #x80) + ) + ) + 0 + (none) + ) + ) + +;; definition for function copy-sky-texture +;; INFO: Return type mismatch pointer vs none. +;; Used lq/sq +(defun copy-sky-texture ((arg0 dma-buffer) (arg1 adgif-shader) (arg2 float)) + (let ((s5-0 (-> arg0 base))) + (let ((v1-0 (the int (+ 0.5 (* 128.0 arg2)))) + (a0-2 (-> *sky-work* sky-data)) + ) + (set! (-> a0-2 0 vector4w x) v1-0) + (set! (-> a0-2 0 vector4w y) v1-0) + (set! (-> a0-2 0 vector4w z) v1-0) + (set! (-> a0-2 0 vector4w w) 128) + ) + (set! + (-> (the-as (pointer uint128) s5-0) 0) + (-> *sky-work* adgif-tmpl dma-vif quad) + ) + (set! + (-> (the-as (pointer uint128) s5-0) 1) + (-> *sky-work* adgif-tmpl quad 1) + ) + (let ((s4-0 (the-as object (&-> (the-as (pointer uint128) s5-0) 2)))) + (quad-copy! (the-as (pointer uint128) s4-0) (the-as pointer arg1) 5) + (set! + (-> (the-as adgif-shader s4-0) clamp) + (new 'static 'gs-clamp + :wms (gs-tex-wrap-mode clamp) + :wmt (gs-tex-wrap-mode clamp) + ) + ) + (set! + (-> (the-as adgif-shader s4-0) alpha) + (new 'static 'gs-miptbp :tbp1 #x68 :tbw2 #x20) + ) + ) + (cond + (*sky-drawn* + (set! + (-> (the-as (pointer uint128) s5-0) 7) + (-> *sky-work* blend-tmpl dma-vif quad) + ) + (set! + (-> (the-as (pointer uint128) s5-0) 8) + (-> *sky-work* blend-tmpl quad 1) + ) + ) + (else + (set! + (-> (the-as (pointer uint128) s5-0) 7) + (-> *sky-work* draw-tmpl dma-vif quad) + ) + (set! + (-> (the-as (pointer uint128) s5-0) 8) + (-> *sky-work* draw-tmpl quad 1) + ) + (set! *sky-drawn* #t) + ) + ) + (quad-copy! (&+ s5-0 144) (the-as pointer (-> *sky-work* sky-data)) 5) + (set! (-> arg0 base) (&+ s5-0 224)) + ) + (none) + ) + +;; definition for function copy-cloud-texture +;; INFO: Return type mismatch pointer vs none. +;; Used lq/sq +(defun copy-cloud-texture ((arg0 dma-buffer) (arg1 adgif-shader) (arg2 float)) + (let ((s5-0 (-> arg0 base))) + (let ((v1-0 (the int (+ 0.5 (* 128.0 arg2)))) + (a0-2 (-> *sky-work* cloud-data)) + ) + (set! (-> a0-2 0 vector4w x) v1-0) + (set! (-> a0-2 0 vector4w y) v1-0) + (set! (-> a0-2 0 vector4w z) v1-0) + (set! (-> a0-2 0 vector4w w) 128) + ) + (set! + (-> (the-as (pointer uint128) s5-0) 0) + (-> *sky-work* adgif-tmpl dma-vif quad) + ) + (set! + (-> (the-as (pointer uint128) s5-0) 1) + (-> *sky-work* adgif-tmpl quad 1) + ) + (let ((s4-0 (the-as object (&-> (the-as (pointer uint128) s5-0) 2)))) + (quad-copy! (the-as (pointer uint128) s4-0) (the-as pointer arg1) 5) + (set! + (-> (the-as adgif-shader s4-0) clamp) + (new 'static 'gs-clamp + :wms (gs-tex-wrap-mode clamp) + :wmt (gs-tex-wrap-mode clamp) + ) + ) + (set! + (-> (the-as adgif-shader s4-0) alpha) + (new 'static 'gs-miptbp :tbp1 #x68 :tbw2 #x20) + ) + ) + (cond + (*cloud-drawn* + (set! + (-> (the-as (pointer uint128) s5-0) 7) + (-> *sky-work* blend-tmpl dma-vif quad) + ) + (set! + (-> (the-as (pointer uint128) s5-0) 8) + (-> *sky-work* blend-tmpl quad 1) + ) + ) + (else + (set! + (-> (the-as (pointer uint128) s5-0) 7) + (-> *sky-work* draw-tmpl dma-vif quad) + ) + (set! + (-> (the-as (pointer uint128) s5-0) 8) + (-> *sky-work* draw-tmpl quad 1) + ) + (set! *cloud-drawn* #t) + ) + ) + (quad-copy! (&+ s5-0 144) (the-as pointer (-> *sky-work* cloud-data)) 5) + (set! (-> arg0 base) (&+ s5-0 224)) + ) + (none) + ) + +;; definition for function make-sky-textures +;; INFO: Return type mismatch int vs none. +(defun make-sky-textures ((arg0 time-of-day-context) (arg1 int)) + (when + (and + (= (-> *level* level arg1 status) 'active) + (-> *level* level arg1 info sky) + ) + (let ((f30-0 (-> arg0 current-interp))) + (if (zero? arg1) + (set! f30-0 (- 1.0 f30-0)) + ) + (if (= (-> arg0 active-count) 1) + (set! f30-0 1.0) + ) + (when (!= f30-0 0.0) + (let ((gp-0 (if (zero? arg1) + 32 + 39 + ) + ) + (s1-0 (-> *level* level arg1 bsp adgifs)) + ) + (when (nonzero? s1-0) + (let* + ((s2-0 (-> *display* frames (-> *display* on-screen) frame global-buf)) + (s3-0 (-> s2-0 base)) + ) + (set-display-gs-state s2-0 *sky-base-page* 64 96 0 0) + (dotimes (s0-0 8) + (let ((f0-3 (* (-> arg0 moods arg1 sky-times s0-0) f30-0))) + (if (!= f0-3 0.0) + (copy-sky-texture s2-0 (-> s1-0 data s0-0) f0-3) + ) + ) + ) + (copy-cloud-texture s2-0 (-> s1-0 data 8) f30-0) + (let* ((v1-31 s2-0) + (a0-19 (the-as object (-> v1-31 base))) + ) + (set! + (-> (the-as dma-packet a0-19) dma) + (new 'static 'dma-tag :qwc #x2 :id (dma-tag-id cnt)) + ) + (set! (-> (the-as dma-packet a0-19) vif0) (new 'static 'vif-tag)) + (set! + (-> (the-as dma-packet a0-19) vif1) + (new 'static 'vif-tag :imm #x2 :cmd (vif-cmd direct) :msk #x1) + ) + (set! (-> v1-31 base) (&+ (the-as pointer a0-19) 16)) + ) + (let* ((v1-32 s2-0) + (a0-21 (the-as object (-> v1-32 base))) + ) + (set! + (-> (the-as gs-gif-tag a0-21) tag) + (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x1) + ) + (set! + (-> (the-as gs-gif-tag a0-21) regs) + (new 'static 'gif-tag-regs + :regs0 (gif-reg-id a+d) + :regs1 (gif-reg-id a+d) + :regs2 (gif-reg-id a+d) + :regs3 (gif-reg-id a+d) + :regs4 (gif-reg-id a+d) + :regs5 (gif-reg-id a+d) + :regs6 (gif-reg-id a+d) + :regs7 (gif-reg-id a+d) + :regs8 (gif-reg-id a+d) + :regs9 (gif-reg-id a+d) + :regs10 (gif-reg-id a+d) + :regs11 (gif-reg-id a+d) + :regs12 (gif-reg-id a+d) + :regs13 (gif-reg-id a+d) + :regs14 (gif-reg-id a+d) + :regs15 (gif-reg-id a+d) + ) + ) + (set! (-> v1-32 base) (&+ (the-as pointer a0-21) 16)) + ) + (let* ((v1-33 s2-0) + (a0-23 (-> v1-33 base)) + ) + (set! + (-> (the-as (pointer gs-alpha) a0-23) 0) + (new 'static 'gs-alpha :b #x1 :d #x1) + ) + (set! (-> (the-as (pointer gs-reg64) a0-23) 1) (gs-reg64 alpha-1)) + (set! (-> v1-33 base) (&+ a0-23 16)) + ) + (reset-display-gs-state *display* s2-0 *oddeven*) + (let ((a3-1 (-> s2-0 base))) + (let ((v1-34 (the-as object (-> s2-0 base)))) + (set! + (-> (the-as dma-packet v1-34) dma) + (new 'static 'dma-tag :id (dma-tag-id next)) + ) + (set! (-> (the-as dma-packet v1-34) vif0) (new 'static 'vif-tag)) + (set! (-> (the-as dma-packet v1-34) vif1) (new 'static 'vif-tag)) + (set! (-> s2-0 base) (&+ (the-as pointer v1-34) 16)) + ) + (dma-bucket-insert-tag + (-> *display* frames (-> *display* on-screen) frame bucket-group) + (the-as bucket-id gp-0) + s3-0 + (the-as (pointer dma-tag) a3-1) + ) + ) + ) + ) + ) + ) + ) + ) + 0 + (none) + ) + + diff --git a/goal_src/engine/gfx/sky/sky.gc b/goal_src/engine/gfx/sky/sky.gc index 78ff256dc..834de8483 100644 --- a/goal_src/engine/gfx/sky/sky.gc +++ b/goal_src/engine/gfx/sky/sky.gc @@ -5,3 +5,138 @@ ;; name in dgo: sky ;; dgos: GAME, ENGINE +(defun sky-make-sun-data ((arg0 sky-parms) (arg1 int) (arg2 float)) + "Make sun data for the arg1th sun at arg2 time" + (let* ((s4-0 (-> arg0 orbit arg1)) + (s3-0 (-> arg0 upload-data sun arg1)) + (f0-1 (- arg2 (-> s4-0 high-noon))) + (f30-0 (* 2730.6667 f0-1)) + (f28-0 (* (sin f30-0) (-> s4-0 dist))) + (f30-1 (cos f30-0)) + ) + (let* ((f24-0 (* f30-1 (-> s4-0 dist))) + (f26-0 (* f24-0 (cos-rad (-> s4-0 tilt)))) + (f24-1 (* f24-0 (sin-rad (-> s4-0 tilt)))) + (f22-0 (sin-rad (-> s4-0 rise))) + (f0-10 (cos-rad (-> s4-0 rise))) + ) + (set! (-> s3-0 pos z) (- (+ (* f28-0 f0-10) (* f24-1 f22-0)))) + (set! (-> s3-0 pos y) f26-0) + (set! (-> s3-0 pos x) (- (* f24-1 f0-10) (* f28-0 f22-0))) + ) + (let ((f0-14 (if (< f30-1 0.0) + 0.0 + f30-1 + ) + ) + ) + (set! + (-> arg0 upload-data sun arg1 r-aurora) + (+ (* (-> s4-0 min-halo) (- 1.0 f0-14)) (* (-> s4-0 max-halo) f0-14)) + ) + ) + ) + (none) + ) + +(defun sky-make-moon-data ((arg0 sky-parms) (arg1 float)) + "Make moon data for moon at arg1 time" + (let* ((s5-0 (-> arg0 orbit 2)) + (gp-0 (-> arg0 upload-data moon)) + (f0-1 (- arg1 (-> s5-0 high-noon))) + (f28-0 (* 2730.6667 f0-1)) + (f30-0 (* (sin f28-0) (-> s5-0 dist))) + (f26-0 (* (cos f28-0) (-> s5-0 dist))) + (f28-1 (* f26-0 (cos-rad (-> s5-0 tilt)))) + (f26-1 (* f26-0 (sin-rad (-> s5-0 tilt)))) + (f24-0 (sin-rad (-> s5-0 rise))) + (f0-10 (cos-rad (-> s5-0 rise))) + ) + (set! (-> gp-0 pos z) (- (+ (* f30-0 f0-10) (* f26-1 f24-0)))) + (set! (-> gp-0 pos y) f28-1) + (set! (-> gp-0 pos x) (- (* f26-1 f0-10) (* f30-0 f24-0))) + ) + (none) + ) + + + + + + + +;;;;;;;;;;;;;;;;;;;;; +;; Old Sky Renderer +;;;;;;;;;;;;;;;;;;;;; + +(defun sky-make-light ((arg0 sky-parms) (arg1 light) (arg2 int) (arg3 rgba)) + (let* ((v1-2 (-> arg0 orbit arg2)) + (a0-1 (if (= arg2 2) + (-> arg0 upload-data moon) + (-> arg0 upload-data sun arg2) + ) + ) + (f0-0 0.003921569) + (f1-1 (/ 1.0 (-> v1-2 dist))) + (v1-3 arg1) + ) + (set! (-> v1-3 direction x) (* (-> (the-as sky-sun-data a0-1) pos x) f1-1)) + (set! (-> v1-3 direction y) (* (-> (the-as sky-sun-data a0-1) pos y) f1-1)) + (set! (-> v1-3 direction z) (* (-> (the-as sky-sun-data a0-1) pos z) f1-1)) + (set! (-> v1-3 color x) (* (the float (-> arg3 r)) f0-0)) + (set! (-> v1-3 color y) (* (the float (-> arg3 g)) f0-0)) + (set! (-> v1-3 color z) (* (the float (-> arg3 b)) f0-0)) + (set! (-> v1-3 color w) 1.0) + (set! (-> v1-3 levels x) 1.0) + ) + (none) + ) + + +(deftype sky-frame-data (structure) + ((data uint128 18 :offset-assert 0) + (world-homo-matrix matrix :inline :offset 0) + (hmge-scale vector :inline :offset 64) + (hvdf-offset vector :inline :offset 80) + (consts vector :inline :offset 96) + (pfog0 float :offset 96) + (radius float :offset 100) + (nokick float :offset 108) + (strip-giftag qword :inline :offset 112) + (col-adgif qword :inline :offset 128) + (save uint128 5 :offset 144) + (sun-fan-giftag qword :inline :offset 224) + (sun-strip-giftag qword :inline :offset 240) + (sun-alpha qword :inline :offset 256) + (sun-alpha-giftag qword :inline :offset 272) + ) + :method-count-assert 9 + :size-assert #x120 + :flag-assert #x900000120 + ) + +;; skipping old sky stuff (for now) +(define sky-vu1-block (new 'static 'vu-function)) + +;; TODO sky-init-upload-data +;; sky-add-frame-data +;; sky-upload +;; sky-draw + + +;; set the suns +(sky-set-sun-radii *sky-parms* 0 60.0 200.0 300.0) +(sky-set-sun-radii *sky-parms* 1 15.0 20.0 300.0) + + +(sky-set-sun-colors *sky-parms* 1 + (new 'static 'rgba :r #xc2 :g #xfe :b #x78 :a #x80) + (new 'static 'rgba :r #xc2 :g #xfe :b #x78 :a #x80) + (new 'static 'rgba :r #xc2 :g #xfe :b #x78 :a #x20) + (new 'static 'rgba :r #xc2 :g #xfe :b #x78) + ) + + +(sky-set-orbit *sky-parms* 0 12.5 -15.0 0.0 9950.0 300.0 300.0) +(sky-set-orbit *sky-parms* 1 4.0 0.0 60.0 9950.0 120.0 120.0) +(sky-set-orbit *sky-parms* 2 0.0 0.0 -10.0 9950.0 0.0 0.0) \ No newline at end of file diff --git a/goal_src/engine/gfx/sprite/sprite.gc b/goal_src/engine/gfx/sprite/sprite.gc index 7eb1f47fb..7fd2d8ff5 100644 --- a/goal_src/engine/gfx/sprite/sprite.gc +++ b/goal_src/engine/gfx/sprite/sprite.gc @@ -645,17 +645,22 @@ ) ) - ; (dotimes (i num-sprites) - ; (let ((spidx (+ i start-sprite-idx))) - ; (when (or (= spidx (-> sprites num-sprites 0)) (= spidx (+ 1 (-> sprites num-sprites 0)))) - ; (let ((data (the sprite-vec-data-2d (&+ (-> sprites vec-data) (* 48 (+ i start-sprite-idx)))))) - ; (format #t "spidx: ~d~%") - ; (inspect data) - ; (inspect (-> data r-g-b-a)) - ; ) - ; ) - ; ) - ; ) + #| + ;(when (= mscal-addr 3) + (dotimes (i num-sprites) + (let ((spidx (+ i start-sprite-idx))) + ;(when (or (= spidx (-> sprites num-sprites 0)) (= spidx (+ 1 (-> sprites num-sprites 0)))) + (let ((data (the sprite-vec-data-2d (&+ (-> sprites vec-data) (* 48 (+ i start-sprite-idx)))))) + (let ((vec (-> data x-y-z-sx))) + (format 0 "sp: ~d ~f ~f ~f~%" (+ i start-sprite-idx) (-> vec x) (-> vec y) (-> vec z)) + ) + ) + ; ) + ) + ) + ; ) + |# + ;; third packet is adgif data (5 qw/sprite) (let ((qwc-pkt3 (* 5 num-sprites))) diff --git a/goal_src/engine/gfx/texture.gc b/goal_src/engine/gfx/texture.gc index 2afcf9c23..da4272a0e 100644 --- a/goal_src/engine/gfx/texture.gc +++ b/goal_src/engine/gfx/texture.gc @@ -2435,6 +2435,7 @@ ) ;; TODO adgif-shader<-texture-with-update! +(def-mips2c adgif-shader<-texture-with-update! (function adgif-shader texture adgif-shader)) (defun adgif-shader-login ((shader adgif-shader)) "If not logged in already, link us and update from texture." diff --git a/goal_src/engine/gfx/time-of-day-h.gc b/goal_src/engine/gfx/time-of-day-h.gc index 77a5a548f..f6c17424c 100644 --- a/goal_src/engine/gfx/time-of-day-h.gc +++ b/goal_src/engine/gfx/time-of-day-h.gc @@ -24,7 +24,7 @@ :flag-assert #xb00000110 (:methods (reset! (_type_) symbol 9) - (TODO-RENAME-10 (_type_ int float float vector) object 10) ; returns float or error string + (set-fade! (_type_ int float float vector) object 10) ; returns float or error string ) ) @@ -74,7 +74,7 @@ ((active-count uint32 :offset-assert 4) (interp float :offset-assert 8) (current-interp float :offset-assert 12) - (moods uint64 2 :offset-assert 16) + (moods mood-context 2 :offset-assert 16) (current-fog mood-fog :inline :offset-assert 32) (current-sun mood-sun :inline :offset-assert 80) (current-prt-color vector :inline :offset-assert 112) @@ -84,7 +84,7 @@ (title-light-group light-group :inline :offset-assert 1888) (time float :offset-assert 2080) (target-interp float :offset-assert 2084) - (erase-color uint32 :offset-assert 2088) + (erase-color rgba :offset-assert 2088) (num-stars float :offset-assert 2092) (light-masks-0 uint8 2 :offset-assert 2096) (light-masks-1 uint8 2 :offset-assert 2098) diff --git a/goal_src/engine/gfx/time-of-day.gc b/goal_src/engine/gfx/time-of-day.gc index f85b0251c..1aad792c2 100644 --- a/goal_src/engine/gfx/time-of-day.gc +++ b/goal_src/engine/gfx/time-of-day.gc @@ -5,4 +5,671 @@ ;; name in dgo: time-of-day ;; dgos: GAME, ENGINE -(define *time-of-day-proc* (the (pointer time-of-day-proc) #f)) \ No newline at end of file +(defmethod asize-of time-of-day-palette ((obj time-of-day-palette)) + "Compute the size in memory of a time-of-day-palette" + (the-as int (+ (-> obj type size) (* (* (-> obj height) (-> obj width)) 4))) + ) + +;; The time-of-day-effect function is a callback used before doing a time-of-day-update. +;; I think it's unused? +(define-extern time-of-day-effect (function none)) +;; if undefined, set to nothing so we can still call it. +(if (zero? time-of-day-effect) + (set! time-of-day-effect nothing) + ) + +(defbehavior time-of-day-update time-of-day-proc () + "Update the particles and sky tng renderer for time-of-day effects" + (time-of-day-effect) + + ;; spawn or kill stars, if needed. + (cond + ;; should have stars in the sky + ((and (or (>= (-> self hour) 19) (>= 5 (-> self hour))) ;; night time + (and (< 45.0 (-> *time-of-day-context* num-stars)) (-> *time-of-day-context* sky)) ;; sky + stars desired + ) + + ;; see if we need more + (when (and *dproc* (< (-> self star-count) (the int (-> *time-of-day-context* num-stars)))) + (spawn (-> self stars) (math-camera-pos)) + (+! (-> self star-count) 1) + ) + ) + + ;; have stars, but don't want them + ((> (-> self star-count) 0) + ;; kill all stars. + (forall-particles-with-key + (-> self stars) + (lambda ((arg0 sparticle-system) (arg1 sparticle-cpuinfo)) + (if (< (the-as uint #x493e0) (-> arg1 next-time)) + (set! (-> arg1 next-time) (the-as uint 5)) + (sparticle-kill-it arg0 arg1) + ) + (none) + ) + #t + #t + ) + (set! (-> self star-count) 0) + 0 + ) + ) + + ;; spawn or kill sun, if needed + (cond + ((and (>= (-> self time-of-day) 6.25) + (< (-> self time-of-day) 18.75) + (!= (-> *time-of-day-context* sun-fade) 0.0) + ) + (when (and *dproc* (zero? (-> self sun-count))) + (spawn (-> self sun) (math-camera-pos)) + (+! (-> self sun-count) 1) + ) + ) + ((> (-> self sun-count) 0) + (kill-and-free-particles (-> self sun)) + (set! (-> self sun-count) 0) + 0 + ) + ) + + ;; spawn or kill green sun, if needed + (cond + ((and (or (>= (-> self time-of-day) 21.75) (>= 10.25 (-> self time-of-day))) + (!= (-> *time-of-day-context* sun-fade) 0.0) + ) + (when (and *dproc* (zero? (-> self green-sun-count))) + (spawn (-> self green-sun) (math-camera-pos)) + (+! (-> self green-sun-count) 1) + ) + ) + ((> (-> self green-sun-count) 0) + (kill-and-free-particles (-> self green-sun)) + (set! (-> self green-sun-count) 0) + 0 + ) + ) + + ;; update the sky renderer. + (update-sky-tng-data (-> self time-of-day)) + 0 + (none) + ) + + +;; State for just ticking time forward. +(defstate time-of-day-tick (time-of-day-proc) + :code + (behavior () + (while #t + ;; tick! + (+! (-> self frame) (the int (* (-> self time-ratio) (-> *display* time-adjust-ratio)))) + + ;; now update time... + (when (>= (-> self frame) 300) + ;; 300 ticks/second + (while (>= (-> self frame) 300) + (+! (-> self frame) -300) + (+! (-> self second) 1) + ) + ;; 60 sec/minute + (when (>= (-> self second) 60) + (while (>= (-> self second) 60) + (+! (-> self second) -60) + (+! (-> self minute) 1) + ) + ;; 60 min/hour + (when (>= (-> self minute) 60) + (while (>= (-> self minute) 60) + (+! (-> self minute) -60) + (+! (-> self hour) 1) + ) + ;; 24 hour/day + (when (>= (-> self hour) 24) + (while (>= (-> self hour) 24) + (+! (-> self hour) -24) + (+! (-> self day) 1) + ) + ;; 7 day/week + (when (>= (-> self day) 7) + (while (>= (-> self day) 7) + (+! (-> self day) -7) + (+! (-> self week) 1) + ) + ;; 4 week/month + (when (>= (-> self week) 4) + (while (>= (-> self week) 4) + (+! (-> self week) -4) + (+! (-> self month) 1) + ) + ;; 12 month/year + (when (>= (-> self month) 12) + (while (>= (-> self month) 12) + (+! (-> self month) -12) + (+! (-> self year) 1) + ) + ) + ) + ) + ) + ) + ) + ) + + ;; set the time of day float. This is in hours (0-24) + (format *stdcon* "~0kstars: ~d time ~d:~2d~%" (-> self star-count) (-> self hour) (-> self minute)) + (let* ((f0-4 (the float (-> self frame))) + (f0-6 (+ (* 0.0033333334 f0-4) (the float (-> self second)))) + (f0-8 (+ (* 0.016666668 f0-6) (the float (-> self minute)))) + (f0-10 (+ (* 0.016666668 f0-8) (the float (-> self hour)))) + ) + (set! (-> self time-of-day) f0-10) + (set! (-> *time-of-day-context* time) f0-10) + ) + (suspend) + ) + (none) + ) + :post time-of-day-update + ) + +(defbehavior init-time-of-day time-of-day-proc () + "Initialize the time-of-day process" + (stack-size-set! (-> self main-thread) 128) + (set! (-> self year) 0) + (set! (-> self month) 0) + (set! (-> self week) 0) + (set! (-> self day) 0) + (set! (-> self hour) 0) + (set! (-> self minute) 0) + (set! (-> self second) 0) + (set! (-> self frame) 0) + (set! (-> self time-of-day) 0.0) + (if *time-of-day-fast* + (set! (-> self time-ratio) 18000.0) + (set! (-> self time-ratio) 300.0) + ) + (set! (-> self star-count) 0) + (set! (-> self stars) (create-launch-control (-> *part-group-id-table* 34) self)) + (set! (-> self sun) (create-launch-control (-> *part-group-id-table* 35) self)) + (set! (-> self green-sun) (create-launch-control (-> *part-group-id-table* 36) self)) + (go time-of-day-tick) + (none) + ) + +(defun start-time-of-day () + "Start up the time of day process. Kill any existing ones" + (kill-by-name 'time-of-day-proc *active-pool*) + (let ((gp-0 (get-process *default-dead-pool* time-of-day-proc #x4000))) + (set! *time-of-day-proc* + (the-as (pointer time-of-day-proc) + (when gp-0 + (let ((t9-2 (method-of-type time-of-day-proc activate))) + (t9-2 (the-as time-of-day-proc gp-0) *default-pool* 'time-of-day-proc (the-as pointer #x70004000)) + ) + (run-now-in-process gp-0 init-time-of-day) + (-> gp-0 ppointer ) + ) + ) + ) + ) + (none) + ) + +(defun time-of-day-setup ((arg0 symbol)) + "This function is weird. Returns if time of day will tick forward or not. + If you set arg0 it will toggle on/off time of day. + Otherwise, calling the function has no side effects." + (when arg0 + (cond + ((= (-> *time-of-day-proc* 0 time-ratio) 0.0) + (if *time-of-day-fast* + (set! (-> *time-of-day-proc* 0 time-ratio) 18000.0) + (set! (-> *time-of-day-proc* 0 time-ratio) 300.0) + ) + (set! *time-of-day-mode* 8) + ) + (else + (set! (-> *time-of-day-proc* 0 time-ratio) 0.0) + (set! *time-of-day-mode* 4) + (set! (-> *time-of-day-proc* 0 hour) 12) + (set! (-> *time-of-day-proc* 0 minute) 0) + 0 + ) + ) + ) + (if (= (-> *time-of-day-proc* 0 time-ratio) 0.0) + #f + #t + ) + ) + +(defun set-time-of-day ((arg0 float)) + "Manually set the time of day." + (let ((v1-0 *time-of-day-proc*)) + (set! (-> v1-0 0 hour) (the int arg0)) + (let ((a0-1 (* 60.0 (- arg0 (the float (the int arg0)))))) + (set! (-> v1-0 0 minute) (the int a0-1)) + (set! (-> v1-0 0 second) (the int (* 60.0 (- a0-1 (the float (the int a0-1)))))) + ) + ) + 0 + (none) + ) + +;; TODO time-of-day-interp-colors +;; TODO time-of-day-interp-colors-scratch + + +(defun init-time-of-day-context ((arg0 time-of-day-context)) + "Set up the title-light-group." + (set-vector! (-> arg0 title-light-group dir0 color) 0.82 0.82 0.82 1.0) + (set-vector! (-> arg0 title-light-group dir1 color) 2.0 2.0 2.0 1.0) + (set-vector! (-> arg0 title-light-group ambi color) 0.5 0.5 0.5 1.0) + (set! (-> arg0 title-light-group dir0 levels x) 1.0) + (set! (-> arg0 title-light-group dir1 levels x) 1.0) + (let ((f0-14 1.0)) + (set! (-> arg0 title-light-group ambi levels x) f0-14) + f0-14 + ) + ) + +(defun update-time-of-day ((arg0 time-of-day-context)) + "Update the time of day context" + + ;; set defaults + (set! (-> arg0 sky) #f) + (set! (-> arg0 target-interp) 0.0) + ;; TODO re-enable + #| + (when *target* + (set! (-> *target* draw light-index) (the-as uint 0)) + (when (-> *target* sidekick) + (set! (-> *target* sidekick 0 draw light-index) (the-as uint 0)) + 0 + ) + ) + |# + + ;; see if either level gives us a sky. + (dotimes (v1-12 (-> *level* length)) + (let ((a0-4 (-> *level* level v1-12))) + (when (= (-> a0-4 status) 'active) + (if (-> a0-4 info sky) + (set! (-> arg0 sky) #t) + ) + ) + ) + ) + + ;; level distances + (let ((s4-0 (new 'stack-no-clear 'array 'float 2))) ;; was a boxed array, but the GOAL implementation seems buggy. + (set! (-> s4-0 0) 0.0) + (set! (-> s4-0 1) 0.0) + 0.0 + + (let ((s5-0 0) + (f30-0 (-> arg0 current-interp)) + ) + (set! *lightning-frame-done* #f) + (set! *lightning-realtime-done* #f) + + ;; loop over levels and figure out which to use. + (dotimes (s3-0 2) + (let ((s2-0 (-> *level* level s3-0))) + (cond + ((!= (-> s2-0 status) 'inactive) + ;; level is good, use its mood + (set! (-> s4-0 s3-0) (-> s2-0 level-distance)) + (set! (-> arg0 moods s3-0) (-> s2-0 mood)) + ;; run its mood callback + ((-> s2-0 mood-func) (-> s2-0 mood) (-> arg0 time) s3-0) + ;; sky count + (if (and (= (-> s2-0 status) 'active) (-> s2-0 info sky)) + (+! s5-0 1) + ) + ) + (else + ;; level is no good. Use the default mood in its place. + (set! (-> s4-0 s3-0) 4095996000.0) + (set! (-> arg0 moods s3-0) *default-mood*) + (update-mood-default *default-mood* (-> arg0 time) 0) + ) + ) + ) + ) + + ;; now pick desired interpolation weights + (let* ((f0-6 (-> s4-0 0)) + (f1-0 (-> s4-0 1)) + (f28-0 (cond + ((= f1-0 4095996000.0) + ;; second level is no good, just use first + 0.0 + ) + ((= f0-6 4095996000.0) + ;; first level is no good, just use second. + 1.0 + ) + ((= f0-6 f1-0) + ;; not sure why this is special cased... + 0.5 + ) + ;; this is a hack to pick the mood of village2 when we're closer to sunken, as long as + ;; the camera is above 0. + ((and (< 0.0 (-> *math-camera* trans y)) + (= (-> *level* level0 name) 'village2) + (= (-> *level* level1 name) 'sunken) + ) + 0.0 ;; picks 0 = village2 + ) + ((and (< 0.0 (-> *math-camera* trans y)) + (= (-> *level* level0 name) 'sunken) + (= (-> *level* level1 name) 'village2) + ) + 1.0 ;; picks 1 = village 2 + ) + (else + ;; interplate between them. + (/ f0-6 (+ f0-6 f1-0)) + ) + ) + ) + ) + + ;; normally we will slowly ramp the interpolation weights. + ;; but if we've just teleported, immediately snap to the new value. + (if *teleport* + (set! f30-0 f28-0) + ) + + ;; ramp interpolation weights. + (when (not (or (paused?) (= f28-0 f30-0))) + (let ((f0-7 (- f30-0 f28-0))) + (set! f30-0 (cond + ((= (-> *setting-control* current video-mode) 'pal) + (cond + ((< (fabs f0-7) 0.00396) + ;; close enough + f28-0 + ) + ((< f0-7 0.0) + ;; ramp up + (+ 0.00396 f30-0) + ) + (else + ;; ramp down + (+ -0.00396 f30-0) + ) + ) + ) + ((< (fabs f0-7) 0.0033) + ;; close enough + f28-0 + ) + ((< f0-7 0.0) + ;; ramp up + (+ 0.0033 f30-0) + ) + (else + ;; ramp down. + (+ -0.0033 f30-0) + ) + ) + ) + ) + ) + + ;; number of active skys + (set! (-> arg0 active-count) (the-as uint s5-0)) + ;; interpolation value between the two level moods. + (set! (-> arg0 interp) f28-0) + ) + + ;; Do the interpolation + (set! (-> arg0 current-interp) f30-0) + (set! *sky-drawn* #f) + (set! *cloud-drawn* #f) + (let ((s5-1 (-> arg0 current-fog))) + (cond + ((= f30-0 0.0) + ;; special case: only use level 0 + (let ((v1-67 (-> arg0 moods 0 current-fog))) + (set! (-> s5-1 fog-color quad) (-> v1-67 fog-color quad)) + (set! (-> s5-1 fog-dists quad) (-> v1-67 fog-dists quad)) + (set! (-> s5-1 erase-color quad) (-> v1-67 erase-color quad)) + ) + (set! (-> arg0 current-prt-color quad) (-> arg0 moods 0 current-prt-color quad)) + (set! (-> arg0 current-sun sun-color quad) (-> arg0 moods 0 current-sun sun-color quad)) + (set! (-> arg0 current-sun env-color quad) (-> arg0 moods 0 current-sun env-color quad)) + (set! (-> arg0 current-shadow quad) (-> arg0 moods 0 current-shadow quad)) + (set! (-> arg0 current-shadow-color quad) (-> arg0 moods 0 current-shadow-color quad)) + (dotimes (s4-1 8) + (quad-copy! (the-as pointer (-> arg0 light-group s4-1)) (the-as pointer (-> arg0 moods 0 light-group s4-1)) 12) + ) + (set! (-> arg0 num-stars) (-> arg0 moods 0 num-stars)) + (set! (-> arg0 sun-fade) (-> *level* level0 info sun-fade)) + ) + ((= f30-0 1.0) + ;; special case: use only level 1 + (let ((v1-88 (-> arg0 moods 1 current-fog))) + (set! (-> s5-1 fog-color quad) (-> v1-88 fog-color quad)) + (set! (-> s5-1 fog-dists quad) (-> v1-88 fog-dists quad)) + (set! (-> s5-1 erase-color quad) (-> v1-88 erase-color quad)) + ) + (set! (-> arg0 current-prt-color quad) (-> arg0 moods 1 current-prt-color quad)) + (set! (-> arg0 current-sun sun-color quad) (-> arg0 moods 1 current-sun sun-color quad)) + (set! (-> arg0 current-sun env-color quad) (-> arg0 moods 1 current-sun env-color quad)) + (set! (-> arg0 current-shadow quad) (-> arg0 moods 1 current-shadow quad)) + (set! (-> arg0 current-shadow-color quad) (-> arg0 moods 1 current-shadow-color quad)) + (dotimes (s4-2 8) + (quad-copy! (the-as pointer (-> arg0 light-group s4-2)) (the-as pointer (-> arg0 moods 1 light-group s4-2)) 12) + ) + (set! (-> arg0 num-stars) (-> arg0 moods 1 num-stars)) + (set! (-> arg0 sun-fade) (-> *level* level1 info sun-fade)) + ) + (else + ;; interpolate! + ;; note: the array access here seems to be different from everywhere else and I suspect there was some + ;; weird pointer math in the original code. + (let ((s4-3 (-> arg0 moods 0 current-fog)) + (s3-1 (-> arg0 moods 1 current-fog)) + ) + (vector4-lerp! (-> s5-1 fog-color) (-> s4-3 fog-color) (-> s3-1 fog-color) f30-0) + (vector4-lerp! (-> s5-1 fog-dists) (-> s4-3 fog-dists) (-> s3-1 fog-dists) f30-0) + (vector4-lerp! (-> s5-1 erase-color) (-> s4-3 erase-color) (-> s3-1 erase-color) f30-0) + ) + (vector4-lerp! (-> arg0 current-prt-color) (-> arg0 moods 0 current-prt-color) (-> arg0 moods 1 current-prt-color) f30-0) + (vector4-lerp! + (the-as vector (-> arg0 current-sun)) + (the-as vector (-> arg0 moods 0 current-sun)) + (the-as vector (-> arg0 moods 1 current-sun)) + f30-0 + ) + (vector4-lerp! (-> arg0 current-sun env-color) (-> arg0 moods 0 current-sun env-color) (-> arg0 moods 1 current-sun env-color) f30-0) + (vector4-lerp! (-> arg0 current-shadow) (-> arg0 moods 0 current-shadow) (-> arg0 moods 1 current-shadow) f30-0) + (vector4-lerp! (-> arg0 current-shadow-color) (-> arg0 moods 0 current-shadow-color) (-> arg0 moods 1 current-shadow-color) f30-0) + (dotimes (s4-4 8) + (dotimes (s3-2 3) + (let ((s2-1 (+ (+ (* 48 s3-2) 156 (* 192 s4-4)) (the-as int arg0)))) + (let ((s1-0 (+ (+ (* 48 s3-2) 156 (* 192 s4-4)) (the-as int (-> arg0 moods 0))) ) + (s0-0 (+ (+ (* 48 s3-2) 156 (* 192 s4-4)) (the-as int (-> arg0 moods 1))) ) + ) + (vector4-lerp! (the-as vector (+ s2-1 0)) (the-as vector (+ s1-0 0)) (the-as vector (+ s0-0 0)) f30-0) + (vector4-lerp! (the-as vector (+ s2-1 16)) (the-as vector (+ s1-0 16)) (the-as vector (+ s0-0 16)) f30-0) + (vector4-lerp! (the-as vector (+ s2-1 32)) (the-as vector (+ s1-0 32)) (the-as vector (+ s0-0 32)) f30-0) + ) + (vector-normalize! (the-as vector (+ s2-1 0)) 1.0) + ) + ) + (let ((s3-3 (+ (the-as uint (-> arg0 light-group 0 ambi)) (* 192 s4-4))) + (s2-2 (+ (the-as uint (-> arg0 moods 0 light-group 0 ambi)) (* 192 s4-4))) + (s1-1 (+ (the-as uint (-> arg0 moods 1 light-group 0 ambi)) (* 192 s4-4))) + ) + (vector4-lerp! (the-as vector (+ s3-3 0)) (the-as vector (+ s2-2 0)) (the-as vector (+ s1-1 0)) f30-0) + (vector4-lerp! (the-as vector (+ s3-3 16)) (the-as vector (+ s2-2 16)) (the-as vector (+ s1-1 16)) f30-0) + (vector4-lerp! (the-as vector (+ s3-3 32)) (the-as vector (+ s2-2 32)) (the-as vector (+ s1-1 32)) f30-0) + ) + ) + (set! (-> arg0 num-stars) (+ (-> arg0 moods 0 num-stars) (* (- (-> arg0 moods 1 num-stars) (-> arg0 moods 0 num-stars)) f30-0))) + (let ((f0-20 (-> *level* level0 info sun-fade))) + (set! (-> arg0 sun-fade) (+ f0-20 (* f30-0 (- (-> *level* level1 info sun-fade) f0-20)))) + ) + ) + ) + + ;; setup sky stuff + (dotimes (s4-5 2) + (make-sky-textures arg0 s4-5) + ) + (set! (-> sky-base-polygons 0 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 1 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 2 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 3 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 4 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 5 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 6 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 7 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 8 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 9 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 10 col quad) (-> s5-1 erase-color quad)) + (set! (-> sky-base-polygons 11 col quad) (-> s5-1 erase-color quad)) + ) + ) + ) + (set! (-> arg0 current-sun env-color x) (* 0.5019608 (-> arg0 current-sun env-color x))) + (set! (-> arg0 current-sun env-color y) (* 0.5019608 (-> arg0 current-sun env-color y))) + (set! (-> arg0 current-sun env-color z) (* 0.5019608 (-> arg0 current-sun env-color z))) + (set! (-> arg0 current-sun env-color w) (* 0.5019608 (-> arg0 current-sun env-color w))) + + (let ((v1-179 (-> arg0 current-fog))) + (set! *fog-color* + (new 'static 'rgba + :r (the int (-> v1-179 fog-color x)) + :g (the int (-> v1-179 fog-color y)) + :b (the int (-> v1-179 fog-color z)) + ) + ) + ) + (let ((v1-184 (-> arg0 current-fog erase-color))) + (set! (-> arg0 erase-color) + (new 'static 'rgba + :a #x80 + :b (the int (-> v1-184 z)) + :g (the int (-> v1-184 y)) + :r (the int (-> v1-184 x)) + ) + ) + ) + (set! (-> *math-camera* fog-start) (-> arg0 current-fog fog-dists x)) + (set! (-> *math-camera* fog-end) (-> arg0 current-fog fog-dists y)) + (set! (-> *math-camera* fog-max) (-> arg0 current-fog fog-dists z)) + (set! (-> *math-camera* fog-min) (-> arg0 current-fog fog-dists w)) + + ;; interp target lights. + (let* ((v1-195 0 #|(-> *target* draw light-index)|#) ;; TODO + (f30-1 (-> arg0 target-interp)) + (s4-6 (-> arg0 light-group)) + (s5-2 (-> arg0 light-group v1-195)) + ) + + + (when (nonzero? v1-195) + (cond + ((= f30-1 1.0) + ) + ((= f30-1 0.0) + (quad-copy! (the-as pointer (-> arg0 light-group v1-195)) (the-as pointer (-> arg0 light-group)) 12) + ) + (else + (dotimes (s3-4 4) + (vector4-lerp! + (the-as vector (+ (the-as uint (-> s5-2 dir0)) (* 48 s3-4))) + (the-as vector (+ (the-as uint (-> s4-6 0)) (* 48 s3-4))) + (the-as vector (+ (the-as uint (-> s5-2 dir0)) (* 48 s3-4))) + f30-1 + ) + (vector4-lerp! + (the-as vector (+ (the-as uint (-> s5-2 dir0 color)) (* 48 s3-4))) + (the-as vector (+ (the-as uint (-> s4-6 0 dir0 color)) (* 48 s3-4))) + (the-as vector (+ (the-as uint (-> s5-2 dir0 color)) (* 48 s3-4))) + f30-1 + ) + (vector4-lerp! + (the-as vector (+ (the-as uint (-> s5-2 dir0 levels)) (* 48 s3-4))) + (the-as vector (+ (the-as uint (-> s4-6 0 dir0 levels)) (* 48 s3-4))) + (the-as vector (+ (the-as uint (-> s5-2 dir0 levels)) (* 48 s3-4))) + f30-1 + ) + (vector-normalize! + (the-as vector (+ (the-as uint (-> s5-2 dir0)) (* 48 s3-4))) + 1.0 + ) + ) + ) + ) + + ;; some shadow thing. + (let ((a2-30 (new 'stack-no-clear 'vector))) + (set! (-> a2-30 x) (- (-> s5-2 dir0 direction x))) + (set! (-> a2-30 y) (- (-> s5-2 dir0 direction y))) + (set! (-> a2-30 z) (- (-> s5-2 dir0 direction z))) + (when (< (-> s5-2 dir0 direction y) 0.9063) + (let* ((f0-56 0.4226) + (f1-17 (-> a2-30 x)) + (f1-19 (* f1-17 f1-17)) + (f2-7 (-> a2-30 z)) + (f0-57 (/ f0-56 (sqrtf (+ f1-19 (* f2-7 f2-7))))) + ) + (set! (-> a2-30 x) (* (-> a2-30 x) f0-57)) + (set! (-> a2-30 y) -0.9063) + (set! (-> a2-30 z) (* (-> a2-30 z) f0-57)) + ) + ) + (vector4-lerp! (-> arg0 current-shadow) (-> arg0 current-shadow) a2-30 f30-1) + ) + (vector-normalize! (-> arg0 current-shadow) 1.0) + ) + ) + + (reset! *palette-fade-controls*) + 0 + (none) + ) + +(defmethod set-fade! palette-fade-controls ((obj palette-fade-controls) (arg0 int) (arg1 float) (arg2 float) (arg3 vector)) + (cond + ((and (>= arg0 0) (< arg0 8)) + (let ((v1-3 (-> obj control arg0))) + (when (< arg2 (-> v1-3 actor-dist)) + (if arg3 + (set! (-> v1-3 trans quad) (-> arg3 quad)) + ) + (set! (-> v1-3 fade) (fmax 0.0 (fmin 1.993 arg1))) + (let ((f0-3 arg2)) + (set! (-> v1-3 actor-dist) f0-3) + f0-3 + ) + ) + ) + ) + (else + (format 0 "ERROR: Bogus palette-fade-control index!~%") + ) + ) + ) + +(defmethod reset! palette-fade-controls ((obj palette-fade-controls)) + (countdown (v1-0 8) + (let ((a1-2 (-> obj control v1-0))) + (set! (-> a1-2 fade) 0.0) + (set! (-> a1-2 actor-dist) 4096000000.0) + ) + ) + #f + ) + + +;; start the time of day process!! +(start-time-of-day) \ No newline at end of file diff --git a/goal_src/engine/level/level-h.gc b/goal_src/engine/level/level-h.gc index 22b7f919b..602c0946c 100644 --- a/goal_src/engine/level/level-h.gc +++ b/goal_src/engine/level/level-h.gc @@ -130,7 +130,7 @@ (display? symbol :offset-assert 376) (meta-inside? symbol :offset-assert 380) (mood mood-context :offset-assert 384) - (mood-func function :offset-assert 388) + (mood-func (function mood-context float int none) :offset-assert 388) (vis-bits pointer :offset-assert 392) (all-visible? symbol :offset-assert 396) (force-all-visible? symbol :offset-assert 400) diff --git a/goal_src/engine/level/level.gc b/goal_src/engine/level/level.gc index 5d6872065..534d3e01f 100644 --- a/goal_src/engine/level/level.gc +++ b/goal_src/engine/level/level.gc @@ -274,7 +274,7 @@ (set! (-> s5-1 load-name) level-name) ) (set! (-> s5-1 mood) (the mood-context (-> s5-1 info mood value))) - (set! (-> s5-1 mood-func) (the function (-> s5-1 info mood-func value))) + (set! (-> s5-1 mood-func) (the (function mood-context float int none) (-> s5-1 info mood-func value))) (set! (-> s5-1 display?) #f) (set! (-> s5-1 force-all-visible?) #f) (set! (-> s5-1 force-inside?) #f) @@ -493,8 +493,7 @@ (when (nonzero? (-> bsp adgifs)) (let ((adgifs (-> bsp adgifs))) (dotimes (i (-> adgifs length)) - ;; TODO - ;;(adgif-shader-login-no-remap (-> adgifs data i)) TODO texture.gc + (adgif-shader-login-no-remap (-> adgifs data i)) ) ) ) diff --git a/goal_src/engine/math/vector-h.gc b/goal_src/engine/math/vector-h.gc index 1905568fb..9255ec244 100644 --- a/goal_src/engine/math/vector-h.gc +++ b/goal_src/engine/math/vector-h.gc @@ -495,12 +495,12 @@ (defmacro set-vector! (v xv yv zv wv) "Set all fields in a vector" (with-gensyms (vec) - `(let ((vec ,v)) - (set! (-> vec x) ,xv) - (set! (-> vec y) ,yv) - (set! (-> vec z) ,zv) - (set! (-> vec w) ,wv) - vec + `(let ((,vec ,v)) + (set! (-> ,vec x) ,xv) + (set! (-> ,vec y) ,yv) + (set! (-> ,vec z) ,zv) + (set! (-> ,vec w) ,wv) + ,vec ) ) ) diff --git a/goal_src/engine/sparticle/sparticle-launcher.gc b/goal_src/engine/sparticle/sparticle-launcher.gc index 4fca19f92..31c286de3 100644 --- a/goal_src/engine/sparticle/sparticle-launcher.gc +++ b/goal_src/engine/sparticle/sparticle-launcher.gc @@ -251,7 +251,6 @@ (s3-0 (new 'stack-no-clear 'vector)) ) - (format #t "adjust launch~%") ;; use the field-init-spec to create a totally new launchinfo. (sp-init-fields! (-> s5-0 launchrot) @@ -288,6 +287,7 @@ (+! (-> arg0 launchrot z) (-> s3-0 z)) ) + ;; if desired, apply addition y rotation. (when (!= (-> s5-0 rotate-y) 0.0) (let ((s3-1 (new 'stack-no-clear 'matrix))) @@ -689,7 +689,6 @@ (defun sp-relaunch-particle-2d ((arg0 object) (arg1 sparticle-launcher) (arg2 sparticle-cpuinfo) (arg3 sprite-vec-data-3d)) "relaunch a 2d particle" (sp-relaunch-setup-fields arg0 arg1 arg2 arg3) - (format #t "here we are... ~A~%" (logtest? (-> arg2 flags) (sp-cpuinfo-flag aux-list))) (when (logtest? (-> arg2 flags) (sp-cpuinfo-flag aux-list)) (set! (-> arg2 func) add-to-sprite-aux-list) (set! (-> arg3 r-g-b-a w) 0.0) diff --git a/goal_src/engine/sparticle/sparticle.gc b/goal_src/engine/sparticle/sparticle.gc index 3df64fb5c..34b6636a0 100644 --- a/goal_src/engine/sparticle/sparticle.gc +++ b/goal_src/engine/sparticle/sparticle.gc @@ -301,7 +301,6 @@ (when (= a3-0 t0-0) ;; wrap (set! a3-0 0) - (format #t "wrapped!!~%") ) ) ) diff --git a/goal_src/engine/target/target-util.gc b/goal_src/engine/target/target-util.gc index fd1d14284..5b39a5d33 100644 --- a/goal_src/engine/target/target-util.gc +++ b/goal_src/engine/target/target-util.gc @@ -1534,6 +1534,12 @@ ;; definition for function target-joint-pos (defun target-joint-pos () + ;; added hack + (when (and *target* (zero? (-> *target* draw))) + ;; just return 0, we have the fake target + (return (new 'static 'vector)) + ) + (let ((v1-0 *target*)) (if v1-0 (vector<-cspace! diff --git a/goal_src/examples/debug-draw-example.gc b/goal_src/examples/debug-draw-example.gc index e569294de..ec41e0f5e 100644 --- a/goal_src/examples/debug-draw-example.gc +++ b/goal_src/examples/debug-draw-example.gc @@ -34,7 +34,11 @@ (matrix-transpose! (-> *math-camera* camera-rot) (-> *math-camera* inv-camera-rot)) ;; fake some value here - (set! (-> *math-camera* fov-correction-factor) 1.0) + ;;(set! (-> *math-camera* fov-correction-factor) 1000.0) + (set! (-> *math-camera* fov) (degrees 64.0)) + (let ((f0-28 (fmin 11650.845 (-> *math-camera* fov)))) + (set! (-> *math-camera* fov-correction-factor) (* 0.00008583069 f0-28)) + ) ;; do the math (set! (-> *math-camera* trans quad) (-> location quad)) @@ -185,10 +189,10 @@ (set! (-> trans rot x) (+ -54.13336 (-> trans rot x))) ) (if (logtest? (-> *cpad-list* cpads pad-idx button0-abs 0) (pad-buttons left)) - (set! (-> trans rot y) (+ 546.13336 (-> trans rot y))) + (set! (-> trans rot y) (+ 150.13336 (-> trans rot y))) ) (if (logtest? (-> *cpad-list* cpads pad-idx button0-abs 0) (pad-buttons right)) - (set! (-> trans rot y) (+ -546.13336 (-> trans rot y))) + (set! (-> trans rot y) (+ -150.13336 (-> trans rot y))) ) (set! (-> trans scale x) 1.) diff --git a/goal_src/kernel/gkernel-h.gc b/goal_src/kernel/gkernel-h.gc index cc894362c..05b93c6e2 100644 --- a/goal_src/kernel/gkernel-h.gc +++ b/goal_src/kernel/gkernel-h.gc @@ -592,3 +592,12 @@ "Create a pointer to an object on the scratchpad." `(the-as (pointer ,type) (&+ *fake-scratchpad-data* ,offset)) ) + + +(defmacro def-mips2c (name type) + "Define a mips2c object." + `(begin + (define-extern ,name ,type) + (set! ,name (the-as ,type (__pc-get-mips2c ,(symbol->string name)))) + ) + ) \ No newline at end of file diff --git a/goal_src/levels/maincave/cavecrystal-light.gc b/goal_src/levels/maincave/cavecrystal-light.gc index 2e4732dac..1c40c3cf7 100644 --- a/goal_src/levels/maincave/cavecrystal-light.gc +++ b/goal_src/levels/maincave/cavecrystal-light.gc @@ -211,7 +211,7 @@ (set! (-> s3-0 intensity) arg1) ) ) - (TODO-RENAME-10 *palette-fade-controls* (+ arg0 1) arg1 0.0 (-> s3-0 trans)) + (set-fade! *palette-fade-controls* (+ arg0 1) arg1 0.0 (-> s3-0 trans)) ) ) diff --git a/goal_src/levels/sunken/sunken-water.gc b/goal_src/levels/sunken/sunken-water.gc index d80749771..a827ab4b3 100644 --- a/goal_src/levels/sunken/sunken-water.gc +++ b/goal_src/levels/sunken/sunken-water.gc @@ -243,7 +243,7 @@ ) ) ) - (TODO-RENAME-10 + (set-fade! *palette-fade-controls* 3 (-> self deadly-fade) diff --git a/goalc/compiler/Env.cpp b/goalc/compiler/Env.cpp index 5a8fed1ac..65438008b 100644 --- a/goalc/compiler/Env.cpp +++ b/goalc/compiler/Env.cpp @@ -275,6 +275,9 @@ StackVarAddrVal* FunctionEnv::allocate_aligned_stack_variable(const TypeSpec& ts int size_bytes, int align_bytes) { require_aligned_stack(); + if (align_bytes > 16) { + fmt::print("\n\n\nBad stack align: {} bytes for {}\n\n\n\n", align_bytes, ts.print()); + } assert(align_bytes <= 16); int align_slots = (align_bytes + emitter::GPR_SIZE - 1) / emitter::GPR_SIZE; while (m_stack_var_slots_used % align_slots) { diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index 3b1a56795..e5f5f8861 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -1103,7 +1103,7 @@ Val* Compiler::compile_stack_new(const goos::Object& form, assert(stride == info.stride); int size_in_bytes = info.stride * constant_count; - auto addr = fe->allocate_aligned_stack_variable(ts, size_in_bytes, stride); + auto addr = fe->allocate_aligned_stack_variable(ts, size_in_bytes, 16); return addr; } else { auto ti = m_ts.lookup_type(type_of_object); diff --git a/goalc/debugger/Debugger.cpp b/goalc/debugger/Debugger.cpp index 41f5256d1..05ca1aeb8 100644 --- a/goalc/debugger/Debugger.cpp +++ b/goalc/debugger/Debugger.cpp @@ -564,6 +564,9 @@ bool Debugger::get_symbol_value(const std::string& sym_name, u32* output) { * Starts the debugger watch thread which watches the target process to see if it stops. */ void Debugger::start_watcher() { + if (m_watcher_running) { + stop_watcher(); + } assert(!m_watcher_running); m_watcher_running = true; m_watcher_should_stop = false; @@ -609,6 +612,7 @@ void Debugger::watcher() { break; case xdbg::SignalInfo::DISAPPEARED: printf("Target has disappeared. Maybe it quit or was killed.\n"); + handle_disappearance(); break; default: printf("[Debugger] unhandled signal in watcher: %d\n", int(signal_info.kind)); @@ -629,6 +633,14 @@ void Debugger::watcher() { } } +void Debugger::handle_disappearance() { + m_watcher_should_stop = true; + xdbg::close_memory(m_debug_context.tid, &m_memory_handle); + xdbg::detach_and_resume(m_debug_context.tid); + m_context_valid = false; + m_attached = false; +} + Debugger::SignalInfo Debugger::pop_signal() { { std::unique_lock lock(m_watcher_mutex); diff --git a/goalc/debugger/Debugger.h b/goalc/debugger/Debugger.h index df9075971..76c7c7b88 100644 --- a/goalc/debugger/Debugger.h +++ b/goalc/debugger/Debugger.h @@ -165,6 +165,7 @@ class Debugger { void stop_watcher(); void watcher(); void update_continue_info(); + void handle_disappearance(); struct Breakpoint { u32 goal_addr = 0; // address to break at diff --git a/test/decompiler/reference/engine/ambient/mood_REF.gc b/test/decompiler/reference/engine/ambient/mood_REF.gc index 936f6ce2e..10f4f61a1 100644 --- a/test/decompiler/reference/engine/ambient/mood_REF.gc +++ b/test/decompiler/reference/engine/ambient/mood_REF.gc @@ -980,7 +980,7 @@ (define *thunder-id2* (new-sound-id)) ;; definition for symbol *thunder-id*, type sound-id -(define *thunder-id* (the-as sound-id 0)) +(define *thunder-id* (new 'static 'sound-id)) ;; definition for symbol *thunder-count*, type int (define *thunder-count* 0) @@ -4014,7 +4014,3 @@ (update-mood-itimes arg0) (none) ) - - - - diff --git a/test/decompiler/reference/engine/dma/dma-buffer_REF.gc b/test/decompiler/reference/engine/dma/dma-buffer_REF.gc index b41133dd2..2551d89de 100644 --- a/test/decompiler/reference/engine/dma/dma-buffer_REF.gc +++ b/test/decompiler/reference/engine/dma/dma-buffer_REF.gc @@ -48,6 +48,8 @@ (deftype dma-gif-packet (structure) ((dma-vif dma-packet :inline :offset-assert 0) (gif uint64 2 :offset-assert 16) + (gif0 uint64 :offset 16) + (gif1 uint64 :offset 24) (quad uint128 2 :offset 0) ) :method-count-assert 9 diff --git a/test/decompiler/reference/engine/gfx/hw/gs_REF.gc b/test/decompiler/reference/engine/gfx/hw/gs_REF.gc index d765abd33..69f629de4 100644 --- a/test/decompiler/reference/engine/gfx/hw/gs_REF.gc +++ b/test/decompiler/reference/engine/gfx/hw/gs_REF.gc @@ -790,8 +790,8 @@ (the-as gif-tag (format #t "~Tregs15: ~4d~%" (-> obj regs15))) ) -;; definition for symbol *fog-color*, type int -(define *fog-color* #xc88029) +;; definition for symbol *fog-color*, type rgba +(define *fog-color* (new 'static 'rgba :r #x29 :g #x80 :b #xc8)) ;; definition for symbol *default-regs-buffer*, type dma-buffer (define *default-regs-buffer* (new 'global 'dma-buffer 1024)) diff --git a/test/decompiler/reference/engine/gfx/sky/sky-h_REF.gc b/test/decompiler/reference/engine/gfx/sky/sky-h_REF.gc index acb609eb4..f521b26aa 100644 --- a/test/decompiler/reference/engine/gfx/sky/sky-h_REF.gc +++ b/test/decompiler/reference/engine/gfx/sky/sky-h_REF.gc @@ -226,16 +226,16 @@ ;; definition of type sky-tng-data (deftype sky-tng-data (basic) - ((giftag-base qword :inline :offset-assert 16) - (giftag-roof qword :inline :offset-assert 32) - (giftag-ocean qword :inline :offset-assert 48) - (fog vector :inline :offset-assert 64) - (sky uint32 8 :offset-assert 80) - (time float :offset-assert 112) - (off-s-0 uint16 :offset-assert 116) - (off-t-0 uint16 :offset-assert 118) - (off-s-1 uint16 :offset-assert 120) - (off-t-1 uint16 :offset-assert 122) + ((giftag-base gs-gif-tag :inline :offset-assert 16) + (giftag-roof gs-gif-tag :inline :offset-assert 32) + (giftag-ocean gs-gif-tag :inline :offset-assert 48) + (fog vector :inline :offset-assert 64) + (sky uint32 8 :offset-assert 80) + (time float :offset-assert 112) + (off-s-0 uint16 :offset-assert 116) + (off-t-0 uint16 :offset-assert 118) + (off-s-1 uint16 :offset-assert 120) + (off-t-1 uint16 :offset-assert 122) ) :method-count-assert 9 :size-assert #x7c @@ -260,11 +260,11 @@ ;; definition of type sky-work (deftype sky-work (structure) - ((adgif-tmpl dma-gif-packet :inline :offset-assert 0) - (draw-tmpl dma-gif-packet :inline :offset-assert 32) - (blend-tmpl dma-gif-packet :inline :offset-assert 64) - (sky-data uint128 5 :offset-assert 96) - (cloud-data uint128 5 :offset-assert 176) + ((adgif-tmpl dma-gif-packet :inline :offset-assert 0) + (draw-tmpl dma-gif-packet :inline :offset-assert 32) + (blend-tmpl dma-gif-packet :inline :offset-assert 64) + (sky-data qword 5 :inline :offset-assert 96) + (cloud-data qword 5 :inline :offset-assert 176) ) :method-count-assert 9 :size-assert #x100 diff --git a/test/decompiler/reference/engine/gfx/texture_REF.gc b/test/decompiler/reference/engine/gfx/texture_REF.gc index fce01d211..90c3658a0 100644 --- a/test/decompiler/reference/engine/gfx/texture_REF.gc +++ b/test/decompiler/reference/engine/gfx/texture_REF.gc @@ -3154,143 +3154,7 @@ ) ;; definition for function adgif-shader<-texture-with-update! -;; WARN: Unsupported inline assembly instruction kind - [plzcw v1, v1] -;; WARN: Unsupported inline assembly instruction kind - [subu v1, t0, v1] -;; WARN: Unsupported inline assembly instruction kind - [plzcw a3, a3] -;; WARN: Unsupported inline assembly instruction kind - [subu a3, t0, a3] -;; WARN: Unsupported inline assembly instruction kind - [plzcw a3, v1] -;; WARN: Unsupported inline assembly instruction kind - [subu a3, t0, a3] -(defun adgif-shader<-texture-with-update! ((arg0 adgif-shader) (arg1 texture)) - (local-vars - (v1-11 uint128) - (v1-12 int) - (a3-4 uint128) - (a3-5 int) - (a3-9 uint128) - (a3-10 int) - (a3-13 int) - (a3-22 uint) - ) - (let* ((a2-0 (-> arg0 tex1)) - (v1-0 256) - (a2-1 (incomplete-bitfield-access a2-0)) - (f0-1 (the float v1-0)) - (v1-1 (-> arg1 num-mips)) - (f1-0 (-> arg1 uv-dist)) - (v1-2 (+ v1-1 -1)) - (f0-2 (/ f0-1 f1-0)) - (a2-2 (logior a2-1 (* v1-2 4))) - (v1-5 (shl (-> arg1 mip-shift) 19)) - (a3-0 (-> arg1 tex1-control)) - (a2-4 (logior (logior a2-2 v1-5) (* a3-0 32))) - ) - (let* ((t1-1 (incomplete-bitfield-access (-> arg0 tex0))) - (v1-6 (-> arg1 psm)) - (t1-2 (sar t1-1 62)) - (v1-7 (shl (the-as int v1-6) 20)) - (t1-3 (shl t1-2 35)) - (a3-2 (-> arg1 dest 0)) - (t1-4 (logior t1-3 v1-7)) - (v1-8 (-> arg1 width 0)) - (t1-6 (logior (logior t1-4 a3-2) (shl v1-8 14))) - ) - (let ((v1-10 (the-as uint128 (-> arg1 wu)))) - (.plzcw v1-11 (the-as uint v1-10)) - ) - (let ((t0-0 30)) - (.subu v1-12 t0-0 (the-as int v1-11)) - (let ((a3-3 (the-as uint128 (-> arg1 hu))) - (v1-13 (shl v1-12 26)) - ) - (.plzcw a3-4 (the-as uint a3-3)) - (let ((t1-7 (logior t1-6 v1-13))) - (.subu a3-5 t0-0 (the-as int a3-4)) - (let* ((a3-6 (shl a3-5 30)) - (v1-14 1) - (t1-9 (logior (logior t1-7 a3-6) (shl v1-14 34))) - (v1-17 (shl (-> arg1 clutdest) 37)) - (a3-8 (shl (-> arg1 clutpsm) 51)) - (t1-11 (logior (logior t1-9 v1-17) a3-8)) - (v1-19 (shl 1 61)) - (f0-3 (the int f0-2)) - (t1-12 (logior t1-11 v1-19)) - (v1-20 (the-as uint128 f0-3)) - ) - (set! (-> arg0 tex0) (the-as gs-tex0 t1-12)) - (.plzcw a3-9 (the-as int v1-20)) - (.subu a3-10 t0-0 (the-as int a3-9)) - (let ((t0-2 (+ (-> arg1 mip-shift) -1))) - (nop!) - (b! (zero? t0-2) cfg-2 :delay (nop!)) - ) - (let* ((t0-3 (+ a3-10 -4)) - (a3-11 (* a3-10 16)) - (t0-4 (sar (the-as int v1-20) t0-3)) - (a3-12 (+ a3-11 -175)) - (t0-5 (logand t0-4 15)) - ) - (nop!) - (b! #t cfg-3 :delay (set! a3-13 (+ a3-12 t0-5))) - ) - (label cfg-2) - (let* ((t0-6 (+ a3-10 -5)) - (a3-14 (* a3-10 32)) - (t0-7 (sar (the-as int v1-20) t0-6)) - (a3-15 (+ a3-14 -350)) - (t0-8 (logand t0-7 31)) - ) - (nop!) - (set! a3-13 (+ a3-15 t0-8)) - ) - ) - ) - ) - ) - ) - (nop!) - (label cfg-3) - (let* ((a3-16 (logand a3-13 4095)) - (t1-13 (-> arg1 dest 1)) - (a3-17 (shl a3-16 32)) - (v1-21 (-> arg1 width 1)) - (a2-5 (logior a2-4 a3-17)) - (v1-22 (shl v1-21 14)) - ) - (set! (-> arg0 tex1) a2-5) - (let ((a2-6 (logior t1-13 v1-22)) - (v1-23 (-> arg1 dest 2)) - ) - (nop!) - (let* ((a3-18 (-> arg1 width 2)) - (a2-8 (logior (logior a2-6 (shl v1-23 20)) (shl a3-18 34))) - (v1-25 (-> arg1 dest 3)) - (a3-20 (-> arg1 width 3)) - (a2-10 (logior (logior a2-8 (shl v1-25 40)) (shl a3-20 54))) - (t0-10 (+ (-> arg1 num-mips) -5)) - ) - (set! (-> arg0 miptbp1) (the-as gs-miptbp a2-10)) - (b! (< (the-as int t0-10) 0) cfg-5 :delay (set! a3-22 (-> arg1 width 4))) - ) - ) - ) - ) - (let* ((a2-12 (logior (-> arg1 dest 4) (shl a3-22 14))) - (v1-28 (shl (-> arg1 dest 5) 20)) - (a3-24 (-> arg1 width 5)) - (a2-14 (logior (logior a2-12 v1-28) (shl a3-24 34))) - (v1-30 (shl (-> arg1 dest 6) 40)) - (a3-26 (-> arg1 width 6)) - (a2-16 (logior (logior a2-14 v1-30) (shl a3-26 54))) - (v1-31 54) - ) - (set! (-> arg0 alpha) (the-as gs-miptbp a2-16)) - (nop!) - (set! (-> arg0 quad 4 vector4w z) v1-31) - ) - (nop!) - (label cfg-5) - arg0 - ) +;; ERROR: function was not converted to expressions. Cannot decompile. ;; definition for function adgif-shader-login (defun adgif-shader-login ((shader adgif-shader)) diff --git a/test/decompiler/reference/engine/gfx/tfrag/subdivide_REF.gc b/test/decompiler/reference/engine/gfx/tfrag/subdivide_REF.gc index f91efb94f..4121cc313 100644 --- a/test/decompiler/reference/engine/gfx/tfrag/subdivide_REF.gc +++ b/test/decompiler/reference/engine/gfx/tfrag/subdivide_REF.gc @@ -304,7 +304,7 @@ (define GSH_ENABLE #f) ;; definition for symbol GSH_BUCKET, type bucket-id -(define GSH_BUCKET (the-as bucket-id 3)) +(define GSH_BUCKET (bucket-id bucket-3)) ;; definition for symbol GSH_WHICH_STAT, type int (define GSH_WHICH_STAT 1) diff --git a/test/decompiler/reference/engine/gfx/time-of-day-h_REF.gc b/test/decompiler/reference/engine/gfx/time-of-day-h_REF.gc index 9289f8ef2..48df0af2f 100644 --- a/test/decompiler/reference/engine/gfx/time-of-day-h_REF.gc +++ b/test/decompiler/reference/engine/gfx/time-of-day-h_REF.gc @@ -30,7 +30,7 @@ :flag-assert #xb00000110 (:methods (reset! (_type_) symbol 9) - (TODO-RENAME-10 (_type_ int float float vector) object 10) + (set-fade! (_type_ int float float vector) object 10) ) ) @@ -123,27 +123,27 @@ ;; definition of type time-of-day-context (deftype time-of-day-context (basic) - ((active-count uint32 :offset-assert 4) - (interp float :offset-assert 8) - (current-interp float :offset-assert 12) - (moods uint64 2 :offset-assert 16) - (current-fog mood-fog :inline :offset-assert 32) - (current-sun mood-sun :inline :offset-assert 80) - (current-prt-color vector :inline :offset-assert 112) - (current-shadow vector :inline :offset-assert 128) - (current-shadow-color vector :inline :offset-assert 144) - (light-group light-group 9 :inline :offset-assert 160) - (title-light-group light-group :inline :offset-assert 1888) - (time float :offset-assert 2080) - (target-interp float :offset-assert 2084) - (erase-color uint32 :offset-assert 2088) - (num-stars float :offset-assert 2092) - (light-masks-0 uint8 2 :offset-assert 2096) - (light-masks-1 uint8 2 :offset-assert 2098) - (light-interp uint32 2 :offset-assert 2100) - (sky symbol :offset-assert 2108) - (sun-fade float :offset-assert 2112) - (title-updated symbol :offset-assert 2116) + ((active-count uint32 :offset-assert 4) + (interp float :offset-assert 8) + (current-interp float :offset-assert 12) + (moods mood-context 2 :offset-assert 16) + (current-fog mood-fog :inline :offset-assert 32) + (current-sun mood-sun :inline :offset-assert 80) + (current-prt-color vector :inline :offset-assert 112) + (current-shadow vector :inline :offset-assert 128) + (current-shadow-color vector :inline :offset-assert 144) + (light-group light-group 9 :inline :offset-assert 160) + (title-light-group light-group :inline :offset-assert 1888) + (time float :offset-assert 2080) + (target-interp float :offset-assert 2084) + (erase-color rgba :offset-assert 2088) + (num-stars float :offset-assert 2092) + (light-masks-0 uint8 2 :offset-assert 2096) + (light-masks-1 uint8 2 :offset-assert 2098) + (light-interp uint32 2 :offset-assert 2100) + (sky symbol :offset-assert 2108) + (sun-fade float :offset-assert 2112) + (title-updated symbol :offset-assert 2116) ) :method-count-assert 9 :size-assert #x848 diff --git a/test/decompiler/reference/engine/level/level-h_REF.gc b/test/decompiler/reference/engine/level/level-h_REF.gc index 49d5dc21c..bedc2eacf 100644 --- a/test/decompiler/reference/engine/level/level-h_REF.gc +++ b/test/decompiler/reference/engine/level/level-h_REF.gc @@ -139,47 +139,47 @@ ;; definition of type 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) - (info level-load-info :offset-assert 56) - (texture-page texture-page 9 :offset-assert 60) - (loaded-texture-page texture-page 16 :offset-assert 96) - (loaded-texture-page-count int32 :offset-assert 160) - (foreground-sink-group dma-foreground-sink-group 3 :inline :offset-assert 176) - (foreground-draw-engine engine 3 :offset-assert 272) - (entity entity-links-array :offset-assert 284) - (ambient entity-ambient-data-array :offset-assert 288) - (closest-object float 9 :offset-assert 292) - (upload-size int32 9 :offset-assert 328) - (level-distance meters :offset-assert 364) - (inside-sphere? symbol :offset-assert 368) - (inside-boxes? symbol :offset-assert 372) - (display? symbol :offset-assert 376) - (meta-inside? symbol :offset-assert 380) - (mood mood-context :offset-assert 384) - (mood-func function :offset-assert 388) - (vis-bits pointer :offset-assert 392) - (all-visible? symbol :offset-assert 396) - (force-all-visible? symbol :offset-assert 400) - (linking basic :offset-assert 404) - (vis-info level-vis-info 8 :offset-assert 408) - (vis-self-index int32 :offset-assert 440) - (vis-adj-index int32 :offset-assert 444) - (vis-buffer uint8 2048 :offset-assert 448) - (mem-usage-block memory-usage-block :offset-assert 2496) - (mem-usage int32 :offset-assert 2500) - (code-memory-start pointer :offset-assert 2504) - (code-memory-end pointer :offset-assert 2508) - (texture-mask uint32 9 :offset-assert 2512) - (force-inside? symbol :offset-assert 2548) - (pad uint8 56 :offset-assert 2552) + ((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) + (info level-load-info :offset-assert 56) + (texture-page texture-page 9 :offset-assert 60) + (loaded-texture-page texture-page 16 :offset-assert 96) + (loaded-texture-page-count int32 :offset-assert 160) + (foreground-sink-group dma-foreground-sink-group 3 :inline :offset-assert 176) + (foreground-draw-engine engine 3 :offset-assert 272) + (entity entity-links-array :offset-assert 284) + (ambient entity-ambient-data-array :offset-assert 288) + (closest-object float 9 :offset-assert 292) + (upload-size int32 9 :offset-assert 328) + (level-distance meters :offset-assert 364) + (inside-sphere? symbol :offset-assert 368) + (inside-boxes? symbol :offset-assert 372) + (display? symbol :offset-assert 376) + (meta-inside? symbol :offset-assert 380) + (mood mood-context :offset-assert 384) + (mood-func (function mood-context float int none) :offset-assert 388) + (vis-bits pointer :offset-assert 392) + (all-visible? symbol :offset-assert 396) + (force-all-visible? symbol :offset-assert 400) + (linking basic :offset-assert 404) + (vis-info level-vis-info 8 :offset-assert 408) + (vis-self-index int32 :offset-assert 440) + (vis-adj-index int32 :offset-assert 444) + (vis-buffer uint8 2048 :offset-assert 448) + (mem-usage-block memory-usage-block :offset-assert 2496) + (mem-usage int32 :offset-assert 2500) + (code-memory-start pointer :offset-assert 2504) + (code-memory-end pointer :offset-assert 2508) + (texture-mask uint32 9 :offset-assert 2512) + (force-inside? symbol :offset-assert 2548) + (pad uint8 56 :offset-assert 2552) ) :method-count-assert 29 :size-assert #xa30 diff --git a/test/decompiler/reference/levels/maincave/cavecrystal-light_REF.gc b/test/decompiler/reference/levels/maincave/cavecrystal-light_REF.gc index 4f05ed1d8..a2ef359f6 100644 --- a/test/decompiler/reference/levels/maincave/cavecrystal-light_REF.gc +++ b/test/decompiler/reference/levels/maincave/cavecrystal-light_REF.gc @@ -239,7 +239,7 @@ (set! (-> s3-0 intensity) arg1) ) ) - (TODO-RENAME-10 *palette-fade-controls* (+ arg0 1) arg1 0.0 (-> s3-0 trans)) + (set-fade! *palette-fade-controls* (+ arg0 1) arg1 0.0 (-> s3-0 trans)) ) ) @@ -281,7 +281,3 @@ f30-0 ) ) - - - - diff --git a/test/decompiler/reference/levels/sunken/sunken-water_REF.gc b/test/decompiler/reference/levels/sunken/sunken-water_REF.gc index 1aa8a668f..179897741 100644 --- a/test/decompiler/reference/levels/sunken/sunken-water_REF.gc +++ b/test/decompiler/reference/levels/sunken/sunken-water_REF.gc @@ -272,7 +272,7 @@ ) ) ) - (TODO-RENAME-10 + (set-fade! *palette-fade-controls* 3 (-> self deadly-fade) diff --git a/test/offline/offline_test_main.cpp b/test/offline/offline_test_main.cpp index 7454963bf..e4031b73b 100644 --- a/test/offline/offline_test_main.cpp +++ b/test/offline/offline_test_main.cpp @@ -63,6 +63,8 @@ const std::unordered_set g_functions_expected_to_reject = { // display "vblank-handler", // asm "vif1-handler", "vif1-handler-debug", + // texture + "adgif-shader<-texture-with-update!", // mips2c // sparticle "sp-launch-particles-var", "particle-adgif", "sp-init-fields!", "memcpy", "sp-process-block-2d", "sp-process-block-3d",