diff --git a/common/type_system/TypeSystem.cpp b/common/type_system/TypeSystem.cpp index 6a0186a834..82c2b2ab94 100644 --- a/common/type_system/TypeSystem.cpp +++ b/common/type_system/TypeSystem.cpp @@ -1294,9 +1294,8 @@ bool TypeSystem::typecheck_and_throw(const TypeSpec& expected, */ bool TypeSystem::typecheck_base_types(const std::string& expected, const std::string& actual) const { - // just to make sure it exists. (note - could there be a case when it just has to be forward - // declared, but not defined?) - lookup_type(expected); + // just to make sure it exists. + lookup_type_allow_partial_def(expected); if (expected == actual || expected == lookup_type_allow_partial_def(actual)->get_name()) { lookup_type_allow_partial_def(actual); // make sure it exists diff --git a/decompiler/Function/CfgVtx.cpp b/decompiler/Function/CfgVtx.cpp index f2eac76c6c..fed54285bd 100644 --- a/decompiler/Function/CfgVtx.cpp +++ b/decompiler/Function/CfgVtx.cpp @@ -577,6 +577,19 @@ bool ControlFlowGraph::is_goto_not_end_and_unreachable(CfgVtx* b0, CfgVtx* b1) { return true; // match! } +bool ControlFlowGraph::is_infinite_continue(CfgVtx* b0) { + if (!b0) { + return false; + } + + // end branch always. + if (!b0->end_branch.has_branch || !b0->end_branch.branch_always || b0->end_branch.branch_likely) { + return false; + } + + return true; +} + bool ControlFlowGraph::is_goto_end_and_unreachable(CfgVtx* b0, CfgVtx* b1) { if (!b0 || !b1) { return false; @@ -848,6 +861,98 @@ bool ControlFlowGraph::find_goto_end() { return replaced; } +int get_prev_count(CfgVtx* start, CfgVtx* to_find) { + int result = 0; + while (start && start != to_find) { + result++; + start = start->prev; + } + + if (start == to_find) { + return result; + } + return -1; +} + +bool ControlFlowGraph::find_infinite_continue() { + bool replaced = false; + + for_each_top_level_vtx([&](CfgVtx* vtx) { + auto* b0 = vtx; + if (is_infinite_continue(b0)) { + int my_block = b0->get_first_block_id(); + int dest_block = b0->succ_branch->get_first_block_id(); + + fmt::print("Considering {} as an infinite continue:\n", b0->to_string()); + + if (dest_block >= my_block) { + fmt::print(" Rejecting because destination block {} comes after me {}\n", dest_block, + my_block); + return true; + } else { + fmt::print(" Order OK {} -> {}\n", my_block, dest_block); + } + + int prev_count = get_prev_count(b0, b0->succ_branch); + if (prev_count == -1) { + fmt::print( + " Rejecting because we can't find the destination in the current ungrouped sequence."); + return true; + } else { + fmt::print(" Sequencing OK: {} prev's\n", prev_count); + } + replaced = true; + + auto* new_goto = alloc(); + m_has_break = true; + new_goto->body = b0; + new_goto->unreachable_block = nullptr; + new_goto->dest_block_id = b0->succ_branch->get_first_block_id(); + m_blocks.at(new_goto->dest_block_id)->needs_label = true; + + // patch up thing -> goto branches + for (auto* new_pred : b0->pred) { + new_pred->replace_succ_and_check(b0, new_goto); + } + new_goto->pred = b0->pred; + + assert(b0->succs().size() == 1 && b0->succs().front() == b0->succ_branch); + + // patch up next and prev. + new_goto->next = b0->next; + if (new_goto->next) { + assert(new_goto->next->prev == b0); + new_goto->next->prev = new_goto; + } + new_goto->prev = b0->prev; + if (new_goto->prev) { + assert(new_goto->prev->next == b0); + new_goto->prev->next = new_goto; + } + + // now we want to make it look like the goto will fall through to next. + if (new_goto->next) { + // now we will fall through + new_goto->succ_ft = b0->next; + assert(!new_goto->succ_ft->has_pred(new_goto)); + new_goto->succ_ft->pred.push_back(new_goto); + assert(!new_goto->succ_branch); + } + + // break goto preds. + b0->succ_branch->replace_preds_with_and_check({b0}, nullptr); + + b0->parent_claim(new_goto); + return false; + } + + // keep looking + return true; + }); + + return replaced; +} + bool ControlFlowGraph::find_goto_not_end() { bool replaced = false; @@ -2132,6 +2237,7 @@ std::shared_ptr build_cfg(const LinkedObjectFile& file, cfg->flag_early_exit(func.basic_blocks); bool changed = true; + bool complained_about_weird_gotos = false; while (changed) { changed = false; // note - we should prioritize finding short-circuiting expressions. @@ -2164,7 +2270,14 @@ std::shared_ptr build_cfg(const LinkedObjectFile& file, if (!changed) { changed = changed || cfg->find_cond_w_empty_else(); - if (changed) { + } + + if (!changed) { + changed = changed || cfg->find_infinite_continue(); + if (changed && !complained_about_weird_gotos) { + complained_about_weird_gotos = true; + func.warnings.general_warning( + "Found some very strange gotos. Check result carefully, this is not well tested."); } } } diff --git a/decompiler/Function/CfgVtx.h b/decompiler/Function/CfgVtx.h index 100fa0fb6a..8e3ac8b3c2 100644 --- a/decompiler/Function/CfgVtx.h +++ b/decompiler/Function/CfgVtx.h @@ -110,7 +110,7 @@ class CfgVtx { /*! * Lazy function for getting all non-null succesors */ - std::vector succs() { + std::vector succs() const { std::vector result; if (succ_branch) { result.push_back(succ_branch); @@ -320,6 +320,7 @@ class ControlFlowGraph { bool find_cond_w_else(const CondWithElseLengthHack& hacks); bool find_cond_w_empty_else(); bool find_cond_n_else(); + bool find_infinite_continue(); // bool find_if_else_top_level(); bool find_seq_top_level(bool allow_self_loops); @@ -372,6 +373,7 @@ class ControlFlowGraph { bool is_until_loop(CfgVtx* b1, CfgVtx* b2); bool is_goto_end_and_unreachable(CfgVtx* b0, CfgVtx* b1); bool is_goto_not_end_and_unreachable(CfgVtx* b0, CfgVtx* b1); + bool is_infinite_continue(CfgVtx* b0); std::vector m_blocks; // all block nodes, in order. std::vector m_node_pool; // all nodes allocated EntryVtx* m_entry; // the entry vertex diff --git a/decompiler/analysis/cfg_builder.cpp b/decompiler/analysis/cfg_builder.cpp index 998e2553cf..7274e6b672 100644 --- a/decompiler/analysis/cfg_builder.cpp +++ b/decompiler/analysis/cfg_builder.cpp @@ -193,6 +193,12 @@ void clean_up_break(FormPool& pool, BreakElement* ir) { } void clean_up_break_final(const Function& f, BreakElement* ir) { + EmptyElement* dead_empty = dynamic_cast(ir->dead_code->try_as_single_element()); + if (dead_empty) { + ir->dead_code = nullptr; + return; + } + SetVarElement* dead = dynamic_cast(ir->dead_code->try_as_single_element()); if (!dead) { dead = dynamic_cast(ir->dead_code->elts().front()); @@ -1464,6 +1470,14 @@ void insert_cfg_into_list(FormPool& pool, } } +Form* cfg_to_ir_allow_null(FormPool& pool, Function& f, const CfgVtx* vtx) { + if (vtx) { + return cfg_to_ir(pool, f, vtx); + } else { + return pool.alloc_single_element_form(nullptr); + } +} + Form* cfg_to_ir_helper(FormPool& pool, Function& f, const CfgVtx* vtx) { if (dynamic_cast(vtx)) { auto* bv = dynamic_cast(vtx); @@ -1627,15 +1641,14 @@ Form* cfg_to_ir_helper(FormPool& pool, Function& f, const CfgVtx* vtx) { } else if (dynamic_cast(vtx)) { auto* cvtx = dynamic_cast(vtx); auto result = pool.alloc_single_element_form( - nullptr, cfg_to_ir(pool, f, cvtx->body), cfg_to_ir(pool, f, cvtx->unreachable_block), - cvtx->dest_block_id); + nullptr, cfg_to_ir(pool, f, cvtx->body), + cfg_to_ir_allow_null(pool, f, cvtx->unreachable_block), cvtx->dest_block_id); clean_up_break(pool, dynamic_cast(result->try_as_single_element())); return result; } else if (dynamic_cast(vtx)) { return pool.alloc_single_element_form(nullptr); } - throw std::runtime_error("not yet implemented IR conversion."); return nullptr; } diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 26909b15a3..b64941c037 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -1526,7 +1526,7 @@ (deftype vertical-planes-array (basic) ((length uint32 :offset-assert 4) - (data vertical-planes :dynamic :offset 16) ;; todo, why is this here? + (data vertical-planes :inline :dynamic :offset-assert 16) ) :method-count-assert 9 :size-assert #x10 @@ -4055,10 +4055,11 @@ ;; - Types +(declare-type art-group basic) (deftype load-dir (basic) ((unknown basic) (string-array (array string)) - (data-array (array basic))) + (data-array (array art-group))) :flag-assert #xb00000010 (:methods (new (symbol type int basic) _type_ 0) @@ -4067,6 +4068,7 @@ ) ) + (deftype load-dir-art-group (load-dir) () :flag-assert #xb00000010 @@ -4434,11 +4436,12 @@ :flag-assert #x900000074 ) +(declare-type drawable basic) (deftype login-state (basic) ((state int32 :offset-assert 4) (pos uint32 :offset-assert 8) (elts uint32 :offset-assert 12) - (elt uint32 16 :offset-assert 16) + (elt drawable 16 :offset-assert 16) ;; might be something more specific. ) :method-count-assert 9 :size-assert #x50 @@ -8666,7 +8669,7 @@ ) (deftype proxy-prototype-array-tie (basic) - ((prototype-array-tie basic :offset-assert 4) + ((prototype-array-tie prototype-array-tie :offset-assert 4) (wind-vectors uint32 :offset-assert 8) ; likely a pointer ) :method-count-assert 9 @@ -11270,8 +11273,8 @@ (boxes box8s-array :offset-assert 148) (unk-data-3 uint32 :offset-assert 152) (ambients drawable-inline-array-ambient :offset-assert 156) - (unk-data-4 uint32 :offset-assert 160) - (unk-data-5 uint32 :offset-assert 164) + (unk-data-4 float :offset-assert 160) + (unk-data-5 float :offset-assert 164) (adgifs adgif-shader-array :offset-assert 168) (unk-data-6 pointer :offset-assert 172) (unk-data-7 pointer :offset-assert 176) @@ -11810,7 +11813,7 @@ ) (deftype drawable-tree-instance-tie (drawable-tree) - ((prototypes basic :offset 8) + ((prototypes proxy-prototype-array-tie :offset 8) ) :method-count-assert 18 :size-assert #x24 @@ -12610,7 +12613,8 @@ ;; - Functions -(define-extern entity-nav-login function) ;; only called in `level` in an asm function...tough, returns nothing +;; may be actor. +(define-extern entity-nav-login (function basic none)) ;; only called in `level` in an asm function...tough, returns nothing ;; - Symbols @@ -14494,7 +14498,7 @@ ;; - Unknowns -;;(define-extern *subdivide-settings* object) ;; unknown type +(define-extern *subdivide-settings* subdivide-settings) ;; unknown type ;;(define-extern *tfrag-work* object) ;; unknown type ;;(define-extern *perf-stats* object) ;; unknown type ;;(define-extern *merc-global-stats* object) ;; unknown type @@ -16899,7 +16903,7 @@ (define-extern update-sound-banks function) (define-extern load-vis-info function) (define-extern on (function symbol process)) -(define-extern level-update-after-load function) +(define-extern level-update-after-load (function level login-state none)) (define-extern add-bsp-drawable function) (define-extern remap-level-name (function level-load-info object)) (define-extern bg (function symbol symbol)) diff --git a/decompiler/config/jak1_ntsc_black_label/hacks.jsonc b/decompiler/config/jak1_ntsc_black_label/hacks.jsonc index 10493f1406..168afe9aad 100644 --- a/decompiler/config/jak1_ntsc_black_label/hacks.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/hacks.jsonc @@ -280,9 +280,6 @@ "render-boundary-quad", "draw-boundary-polygon", - // level BUG - "level-update-after-load", - // text BUG "load-game-text-info", diff --git a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc index d814c87f33..c3e3b0e8c5 100644 --- a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc @@ -591,5 +591,9 @@ "main": [ ["L230", "_lambda_", true] + ], + + "geometry": [ + ["L125", "float", true] ] } diff --git a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc index dfa078555b..8de1d53d2e 100644 --- a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc @@ -705,5 +705,11 @@ "bg": [ [37, "a0", "symbol"] + ], + + "level-update-after-load": [ + [[29, 55], "s2", "drawable-tree-tfrag"], + [[121, 146], "s1", "drawable-inline-array-tfrag"], + [[150, 151], "s1", "drawable-tree-instance-tie"] ] } diff --git a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc index b774e793a5..47852f8f21 100644 --- a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc @@ -590,6 +590,22 @@ "args": ["dst", "src", "plane-normal"] }, + "vector-reflect!": { + "args": ["dst", "src", "plane-normal"] + }, + + "vector-reflect-flat!": { + "args": ["dst", "src", "plane-normal"] + }, + + "vector-reflect-true-flat!": { + "args": ["dst", "src", "plane-normal"] + }, + + "vector-reflect-flat-above!": { + "args": ["dst", "src", "plane-normal"] + }, + "deg-seek": { "args": ["in", "target", "max-diff"], "vars": { @@ -1847,31 +1863,35 @@ }, "entity-actor-lookup": { - "args":["lump", "name", "idx"] + "args": ["lump", "name", "idx"] }, - "(method 0 actor-link-info)" : { - "args":["allocation", "type-to-make", "proc"], - "vars": {"s5-0":"obj", "a0-1":"ent"} + "(method 0 actor-link-info)": { + "args": ["allocation", "type-to-make", "proc"], + "vars": { "s5-0": "obj", "a0-1": "ent" } }, - "(method 25 actor-link-info)" : { - "vars": {"s5-0":"actor", "gp-0":"count"} + "(method 25 actor-link-info)": { + "vars": { "s5-0": "actor", "gp-0": "count" } }, - "(method 9 actor-link-info)" : { + "(method 9 actor-link-info)": { "args": ["obj", "matching-type"], - "vars": {"s3-0":"actor", "s5-0":"mask", "s4-0":"current-bit"} + "vars": { "s3-0": "actor", "s5-0": "mask", "s4-0": "current-bit" } }, - "(method 10 actor-link-info)" : { - "vars" : {"s5-0":"this-actor", "s4-0":"actor", "gp-0":"count"} + "(method 10 actor-link-info)": { + "vars": { "s5-0": "this-actor", "s4-0": "actor", "gp-0": "count" } }, "alt-actor-list-subtask-incomplete-count": { - "vars":{"s4-0":"alt-actor-count", "gp-0":"incomplete-count", "s3-0":"alt-actor-idx"} + "vars": { + "s4-0": "alt-actor-count", + "gp-0": "incomplete-count", + "s3-0": "alt-actor-idx" + } }, - + "check-irx-version": { "vars": { "gp-0": ["cmd", "sound-rpc-get-irx-version"] } }, @@ -1906,12 +1926,19 @@ "vars": { "gp-0": ["cmd", "sound-rpc-set-ear-trans"] } }, "sound-play-by-name": { - "args": [ "name", "id", "vol", "pitch", "bend", "group", "trans" ], - "vars": { "s5-0": ["cmd", "sound-rpc-play"], "s3-1": ["proc", "process-drawable"], "s4-0": "sound-trans" } + "args": ["name", "id", "vol", "pitch", "bend", "group", "trans"], + "vars": { + "s5-0": ["cmd", "sound-rpc-play"], + "s3-1": ["proc", "process-drawable"], + "s4-0": "sound-trans" + } }, "sound-play-by-spec": { - "args": [ "spec", "id", "trans" ], - "vars": { "s5-0": ["cmd", "sound-rpc-play"], "s3-1": ["proc", "process-drawable"] } + "args": ["spec", "id", "trans"], + "vars": { + "s5-0": ["cmd", "sound-rpc-play"], + "s3-1": ["proc", "process-drawable"] + } }, "sound-pause": { "vars": { "v1-0": ["cmd", "sound-rpc-pause-sound"] } @@ -1957,87 +1984,116 @@ }, "(method 0 path-control)": { - "args":["allocation", "type-to-make", "proc", "name", "time"], - "vars": {"gp-0":["obj", "path-control"], "s3-1":"ent", "v1-7":"lookup-entity", "sv-16":"tag", "v1-9":"data"} + "args": ["allocation", "type-to-make", "proc", "name", "time"], + "vars": { + "gp-0": ["obj", "path-control"], + "s3-1": "ent", + "v1-7": "lookup-entity", + "sv-16": "tag", + "v1-9": "data" + } }, "(method 0 curve-control)": { - "args":["allocation", "type-to-make", "proc", "name", "time"], - "vars": {"gp-0":"obj", "s3-1":"ent", "v1-3":"lookup-entity"} + "args": ["allocation", "type-to-make", "proc", "name", "time"], + "vars": { "gp-0": "obj", "s3-1": "ent", "v1-3": "lookup-entity" } }, "nav-mesh-connect": { - "args":["proc", "trans", "nav-cont"], - "vars": {"s2-0":"ent", "v0-0":"lookup-entity", "s3-0":"entity-nav-mesh"} + "args": ["proc", "trans", "nav-cont"], + "vars": { + "s2-0": "ent", + "v0-0": "lookup-entity", + "s3-0": "entity-nav-mesh" + } }, "(method 0 nav-control)": { - "args":["allocation", "type-to-make", "shape", "sphere-count", "nearest-y-threshold-default"], - "vars": {"s5-0":["obj", "nav-control"], "a0-3":"ent"} + "args": [ + "allocation", + "type-to-make", + "shape", + "sphere-count", + "nearest-y-threshold-default" + ], + "vars": { "s5-0": ["obj", "nav-control"], "a0-3": "ent" } }, - + "add-debug-point": { "vars": { - "a0-6":["a0-6", "(pointer uint64)"], - "a0-7":["a0-7", "dma-packet"], - "a3-0":["a3-0", "dma-packet"], - "a3-2":["a3-2", "gs-gif-tag"], - "a3-4":["a3-4", "vector4w-2"], - "a3-6":["a3-6", "vector4w-2"], - "a3-8":["a3-8", "vector4w-2"], - "a1-30":["a1-30", "vector4w-2"] + "a0-6": ["a0-6", "(pointer uint64)"], + "a0-7": ["a0-7", "dma-packet"], + "a3-0": ["a3-0", "dma-packet"], + "a3-2": ["a3-2", "gs-gif-tag"], + "a3-4": ["a3-4", "vector4w-2"], + "a3-6": ["a3-6", "vector4w-2"], + "a3-8": ["a3-8", "vector4w-2"], + "a1-30": ["a1-30", "vector4w-2"] } }, "internal-draw-debug-line": { "vars": { - "s2-0":["s2-0", "rgba"], - "s5-0":["s5-0", "rgba"], - "a3-1":["a3-1", "dma-packet"], - "a3-3":["a3-3", "gs-gif-tag"], - "a1-43":["a1-43", "(inline-array vector4w-2)"], - "a0-31":["a0-31", "(pointer uint64)"], - "a0-32":["a0-32", "dma-packet"] + "s2-0": ["s2-0", "rgba"], + "s5-0": ["s5-0", "rgba"], + "a3-1": ["a3-1", "dma-packet"], + "a3-3": ["a3-3", "gs-gif-tag"], + "a1-43": ["a1-43", "(inline-array vector4w-2)"], + "a0-31": ["a0-31", "(pointer uint64)"], + "a0-32": ["a0-32", "dma-packet"] } }, "add-debug-flat-triangle": { "vars": { - "a3-1":["a3-1", "dma-packet"], - "a3-3":["a3-3", "gs-gif-tag"], - "a3-5":["a3-5", "(inline-array vector4w-3)"], - "a0-9":["a0-9", "(pointer uint64)"], - "a0-10":["a0-10", "dma-packet"] + "a3-1": ["a3-1", "dma-packet"], + "a3-3": ["a3-3", "gs-gif-tag"], + "a3-5": ["a3-5", "(inline-array vector4w-3)"], + "a0-9": ["a0-9", "(pointer uint64)"], + "a0-10": ["a0-10", "dma-packet"] } }, "add-debug-line2d": { "vars": { - "a2-3":["a2-3", "dma-packet"], - "a2-5":["a2-5", "gs-gif-tag"], - "a2-7":["a2-7", "(inline-array vector4w)"], - "a2-9":["a2-9", "(inline-array vector4w)"], - "a0-20":["a0-20", "(pointer uint64)"], - "v1-10":["v1-10", "dma-packet"] + "a2-3": ["a2-3", "dma-packet"], + "a2-5": ["a2-5", "gs-gif-tag"], + "a2-7": ["a2-7", "(inline-array vector4w)"], + "a2-9": ["a2-9", "(inline-array vector4w)"], + "a0-20": ["a0-20", "(pointer uint64)"], + "v1-10": ["v1-10", "dma-packet"] } }, "debug-percent-bar": { "vars": { - "v1-5":["v1-5", "dma-packet"] + "v1-5": ["v1-5", "dma-packet"] } }, "debug-pad-display": { "vars": { - "v1-12":["v1-12", "dma-packet"] + "v1-12": ["v1-12", "dma-packet"] } }, "internal-draw-debug-text-3d": { "vars": { - "v1-11":["v1-11", "dma-packet"] + "v1-11": ["v1-11", "dma-packet"] } }, - "add-debug-light": { "vars": { "s1-0":["s1-0", "rgba"]} }, - + "add-debug-light": { "vars": { "s1-0": ["s1-0", "rgba"] } }, + "generic-init-buffers": { "vars": { "v1-8": ["packet", "dma-packet"] } + }, + + "level-update-after-load": { + "args": ["loaded-level", "level-login-state"], + "vars": { + "s3-0":"level-drawable-trees", + "s5-0":"initial-timer", + "v1-4":"current-timer", + "v1-5":"elapsed-timer", + "s2-0":"current-login-pos", + "s2-1":"current-drawable", + "s1-0":"idx-in-drawable" + } } } diff --git a/docs/markdown/progress-notes/changelog.md b/docs/markdown/progress-notes/changelog.md index 51f4b3fa39..c6b8fab8d5 100644 --- a/docs/markdown/progress-notes/changelog.md +++ b/docs/markdown/progress-notes/changelog.md @@ -167,4 +167,5 @@ - The `deftype` form is more strict and will throw an error if the type definition is in any way incompatible with existing forward declarations of types. - Added a `type-ref` form to insert a reference to a type into a static structure and optionally forward declare the number of methods - The `method-of-type` form will now accept an expression returning a type instead of just a type name. In this case, it will only allow you to access method of `object`. -- Added a `defun-recursive` to make it easier to define recursive functions \ No newline at end of file +- Added a `defun-recursive` to make it easier to define recursive functions +- Forward declared basics can be used in more places \ No newline at end of file diff --git a/goal_src/engine/entity/entity-h.gc b/goal_src/engine/entity/entity-h.gc index 53e347fc32..0b2b42ad08 100644 --- a/goal_src/engine/entity/entity-h.gc +++ b/goal_src/engine/entity/entity-h.gc @@ -191,9 +191,9 @@ ;; NOTE - this is a strange pattern...this symbol isn't defined until a later file 'navigate' ;; But this seems to be setting the symbol to nothing if it's not found, but of course, our compiler freaks out -(define-extern entity-nav-login function) +(define-extern entity-nav-login (function basic none)) (if (zero? entity-nav-login) - (set! entity-nav-login nothing) + (set! entity-nav-login (the-as (function basic none) nothing)) ) ;; definition of type actor-bank diff --git a/goal_src/engine/geometry/geometry.gc b/goal_src/engine/geometry/geometry.gc index 8f47bf449b..415901542d 100644 --- a/goal_src/engine/geometry/geometry.gc +++ b/goal_src/engine/geometry/geometry.gc @@ -5,6 +5,129 @@ ;; name in dgo: geometry ;; dgos: GAME, ENGINE +(defun vector-flatten! ((dst vector) (src vector) (plane-normal vector)) + "Get the projection of src onto a plane with the given normal + The normal should have magnitude 1.0." + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) ;; src + (vf2 :class vf) ;; normal + (vf3 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> src quad)) + (.lvf vf2 (&-> plane-normal quad)) + (.mov.vf vf3 vf0 :mask #b1000) + (.outer.product.vf vf3 vf1 vf2) ;; has the right magnitude, but rotation is off by 90 degrees + (.outer.product.vf vf3 vf2 vf3) ;; rotate by 90 about normal of plane + (.svf (&-> dst quad) vf3) + dst + ) + ) + +(defun vector-reflect! ((dst vector) (src vector) (plane-normal vector)) + "Reflect a vector off of a plane." + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + ) + ;; we want to split the vector into normal / tangent components. + ;; let src = T + N, where T dot plane-normal = 0. + ;; then the reflection is T - N = 2 * T - src. + ;; we can compute T from vector-flatten!'s trick + (init-vf0-vector) + (.lvf vf1 (&-> src quad)) + (.lvf vf2 (&-> plane-normal quad)) + (.mov.vf vf3 vf0 :mask #b1000) + (.outer.product.vf vf3 vf1 vf2) + (.outer.product.vf vf3 vf2 vf3) ;; vf3 is the projection on the plane + (.add.vf acc vf3 vf3 :mask #b111) ;; double that part + (.sub.mul.w.vf vf3 vf1 vf0 acc :mask #b111) ;; and subtract the original + (.svf (&-> dst quad) vf3) + dst + ) + ) + +(defun vector-reflect-flat! ((dst vector) (src vector) (plane-normal vector)) + "This is a weird one. It doesn't care about the value of src dot normal + and it effectively replaces the component of src normal to the plane with + the plane's normal. I think this requires src/normal to both be unit vectors + in order to make sense. + NOTE: src should point from positive halfspace to negative otherwise it + doesn't work." + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> src quad)) + (.lvf vf2 (&-> plane-normal quad)) + (.mov.vf vf3 vf0 :mask #b1000) + (.outer.product.vf vf3 vf1 vf2) + (.outer.product.vf vf3 vf2 vf3) ;; part on the plane (requires normal to be unit) + (.add.vf vf3 vf3 vf2 :mask #b111) ;; add normal to that. + (.svf (&-> dst quad) vf3) + dst + ) + ) + +(defun vector-reflect-true-flat! ((dst vector) (src vector) (plane-normal vector)) + "Not really a reflect. Same as flatten" + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> src quad)) + (.lvf vf2 (&-> plane-normal quad)) + (.mov.vf vf3 vf0 :mask #b1000) + (.outer.product.vf vf3 vf1 vf2) + (.outer.product.vf vf3 vf2 vf3) + (.svf (&-> dst quad) vf3) + dst + ) + ) + +(defun vector-reflect-flat-above! ((dst vector) (src vector) (plane-normal vector)) + "A hacked up version of reflect, probably to make their collision system work. + It is a less aggressive version of reflect that also has a limit to the output + normal component" + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> src quad)) + (.lvf vf2 (&-> plane-normal quad)) + (.mov.vf vf3 vf0 :mask #b1000) + (.outer.product.vf vf3 vf1 vf2) + (.outer.product.vf vf3 vf2 vf3) + (.svf (&-> dst quad) vf3) + + ;; dst is now the normal part of src + (let ((f0-0 (vector-length dst)) ;; length of normal + (f1-1 (vector-dot dst plane-normal))) ;; ?? this is always zero. + (let* ((f1-2 f1-1) + ;; f1-3 = .02 * length of normal. f1-2 is always zero here + (f1-3 (- (* 0.02 f0-0) f1-2)) + ) + ;; scale down and limit the normal component + (vector+float*! dst dst plane-normal (fmin 16384.0 (* 16.0 f1-3))) + ) + ) + ) + ) + +;; TODO vector-segment-distance-point! + ;; TODO - temporary for lights.gc (define-extern vector-deg-slerp (function vector vector vector float vector)) ;; TODO - temporary for transformq.gc @@ -14,4 +137,4 @@ ;; TODO (define-extern vector-3pt-cross! (function vector vector vector vector vector)) -(define-extern curve-evaluate! (function vector float int int vector int int)) \ No newline at end of file +(define-extern curve-evaluate! (function vector float int int vector int int)) diff --git a/goal_src/engine/gfx/tie/prototype-h.gc b/goal_src/engine/gfx/tie/prototype-h.gc index 8c1a89fd8a..aeec235f65 100644 --- a/goal_src/engine/gfx/tie/prototype-h.gc +++ b/goal_src/engine/gfx/tie/prototype-h.gc @@ -105,7 +105,7 @@ ) (deftype proxy-prototype-array-tie (basic) - ((prototype-array-tie basic :offset-assert 4) + ((prototype-array-tie prototype-array-tie :offset-assert 4) (wind-vectors uint32 :offset-assert 8) ) :method-count-assert 9 diff --git a/goal_src/engine/gfx/tie/tie-h.gc b/goal_src/engine/gfx/tie/tie-h.gc index f1d748ec6a..3097177464 100644 --- a/goal_src/engine/gfx/tie/tie-h.gc +++ b/goal_src/engine/gfx/tie/tie-h.gc @@ -48,7 +48,7 @@ ) (deftype drawable-tree-instance-tie (drawable-tree) - ((prototypes basic :offset 8) + ((prototypes proxy-prototype-array-tie :offset 8) ) :method-count-assert 18 :size-assert #x24 diff --git a/goal_src/engine/gfx/vis/bsp-h.gc b/goal_src/engine/gfx/vis/bsp-h.gc index f42af51d8d..293773e3d0 100644 --- a/goal_src/engine/gfx/vis/bsp-h.gc +++ b/goal_src/engine/gfx/vis/bsp-h.gc @@ -42,8 +42,8 @@ (boxes box8s-array :offset-assert 148) (unk-data-3 uint32 :offset-assert 152) (ambients drawable-inline-array-ambient :offset-assert 156) - (unk-data-4 uint32 :offset-assert 160) - (unk-data-5 uint32 :offset-assert 164) + (unk-data-4 float :offset-assert 160) + (unk-data-5 float :offset-assert 164) (adgifs adgif-shader-array :offset-assert 168) (unk-data-6 pointer :offset-assert 172) (unk-data-7 pointer :offset-assert 176) diff --git a/goal_src/engine/level/level-h.gc b/goal_src/engine/level/level-h.gc index cd340e017c..8f2e4e7fb9 100644 --- a/goal_src/engine/level/level-h.gc +++ b/goal_src/engine/level/level-h.gc @@ -72,11 +72,12 @@ :flag-assert #x900000074 ) +(declare-type drawable basic) (deftype login-state (basic) ((state int32 :offset-assert 4) (pos uint32 :offset-assert 8) (elts uint32 :offset-assert 12) - (elt uint32 16 :offset-assert 16) + (elt drawable 16 :offset-assert 16) ;; might be more specific ) :method-count-assert 9 :size-assert #x50 diff --git a/goal_src/engine/load/loader-h.gc b/goal_src/engine/load/loader-h.gc index 25634414de..6c11422445 100644 --- a/goal_src/engine/load/loader-h.gc +++ b/goal_src/engine/load/loader-h.gc @@ -5,13 +5,12 @@ ;; name in dgo: loader-h ;; dgos: GAME, ENGINE -(define-extern art-group type) - ;; This type didn't have an inspect method, so these field names are made up. +(declare-type art-group basic) (deftype load-dir (basic) ((unknown basic) (string-array (array string)) ;; these are the names - (data-array (array basic)) ;; this is the file data. + (data-array (array art-group)) ;; this is the file data. ) :flag-assert #xb00000010 (:methods @@ -44,7 +43,7 @@ (set! (-> obj string-array length) 0) ;; create the data array (set! (-> obj data-array) - (the-as (array basic) + (the-as (array art-group) ((method-of-type array new) allocation array basic length) )) (set! (-> obj data-array length) 0) diff --git a/goal_src/engine/math/math.gc b/goal_src/engine/math/math.gc index 77dada6210..8a62fd311b 100644 --- a/goal_src/engine/math/math.gc +++ b/goal_src/engine/math/math.gc @@ -11,11 +11,13 @@ ;;;; float macros ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; at some point, this could be more optimized. -;; MIPS has an explicit abs.s instruction, but x86-64 doesn't. -;; modern clang on O3 does a comiss/branch and this is probably pretty close. (defmacro fabs (x) + "Floating point absolute value" + ;; in GOAL this was implemented by the compiler. + ;; at some point, this could be more optimized. + ;; MIPS has an explicit abs.s instruction, but x86-64 doesn't. + ;; modern clang on O3 does a comiss/branch and this is probably pretty close. `(if (< (the float ,x) 0) (- (the float ,x)) (the float ,x)) @@ -159,10 +161,12 @@ ;;;; random vu hardware ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; added in OpenGOAL +;; in the PS2 there is a R register for generating random numbers +;; it is a "32-bit" register, but the upper bits are fixed so it always +;; represents a float in (1, 2). +;; we don't have this register on x86, so we add a special global: *_vu-reg-R_* (define *_vu-reg-R_* 0) -;; TODO (defun rand-vu-init ((seed float)) "Initialize the VU0 random generator" ;; (.ctc2.i R arg0) @@ -173,6 +177,7 @@ (the-as float *_vu-reg-R_*) ) +;; this is _almost_ sqrt(2) = 1.414 (rand-vu-init 1.418091058731079) ;; rand-vu diff --git a/goal_src/engine/math/matrix-h.gc b/goal_src/engine/math/matrix-h.gc index 599748123b..a6a532e492 100644 --- a/goal_src/engine/math/matrix-h.gc +++ b/goal_src/engine/math/matrix-h.gc @@ -44,6 +44,7 @@ ) (defun matrix-copy! ((dst matrix) (src matrix)) + "Copy src to dst" (let ((v1-0 (-> src vector 0 quad)) (a2-0 (-> src vector 1 quad)) (a3-0 (-> src vector 2 quad)) diff --git a/goal_src/engine/math/transform-h.gc b/goal_src/engine/math/transform-h.gc index f773cffd5e..5205f6600b 100644 --- a/goal_src/engine/math/transform-h.gc +++ b/goal_src/engine/math/transform-h.gc @@ -5,11 +5,11 @@ ;; name in dgo: transform-h ;; dgos: GAME, ENGINE - +;; Transformation. w components of vectors should be 1.0 (deftype transform (structure) - ((trans vector :inline :offset-assert 0) - (rot vector :inline :offset-assert 16) - (scale vector :inline :offset-assert 32) + ((trans vector :inline :offset-assert 0) ;; translation + (rot vector :inline :offset-assert 16) ;; rotation (rotation vector) + (scale vector :inline :offset-assert 32) ;; scale (xyz components) ) :method-count-assert 9 :size-assert #x30 @@ -17,6 +17,7 @@ ) +;; Like transform, but it's a basic. (deftype trs (basic) ((trans vector :inline :offset-assert 16) (rot vector :inline :offset-assert 32) diff --git a/goal_src/engine/math/vector-h.gc b/goal_src/engine/math/vector-h.gc index 957ae330a3..d5a6f52394 100644 --- a/goal_src/engine/math/vector-h.gc +++ b/goal_src/engine/math/vector-h.gc @@ -9,6 +9,8 @@ ;; bit array ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; the bit-array is a dynamically sized array that is bit addressable + (deftype bit-array (basic) ((length int32 :offset-assert 4) (allocated-length int32 :offset-assert 8) @@ -103,6 +105,8 @@ ;; vector types (integer) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; the GOAL vector types are structures, storing values in memory. + ;; Vector of 4 unsigned bytes. (deftype vector4ub (structure) ((data uint8 4 :offset-assert 0) @@ -363,6 +367,7 @@ :flag-assert #x900000010 ) +;; ax + by + cz = d form (deftype plane (vector) ((a float :offset 0) (b float :offset 4) @@ -374,15 +379,15 @@ :flag-assert #x900000010 ) +;; x, y, z are the origin, replaces w with r, the radius (deftype sphere (vector) - ((r float :offset 12) + ((r float :offset 12 :score 10) ;; prefer over w ) :method-count-assert 9 :size-assert #x10 :flag-assert #x900000010 ) - (deftype isphere (vec4s) () :method-count-assert 9 @@ -452,7 +457,7 @@ (deftype vertical-planes-array (basic) ((length uint32 :offset-assert 4) - (data vertical-planes :dynamic :offset 16) ;; todo, why is this here? + (data vertical-planes :inline :dynamic :offset-assert 16) ;; likely inline based on alignment ) :method-count-assert 9 :size-assert #x10 @@ -485,7 +490,14 @@ :flag-assert #x90000000c ) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Macros and inline functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (defmacro set-vector! (v xv yv zv wv) + "Set all fields in a vector" (with-gensyms (vec) `(let ((vec ,v)) (set! (-> vec x) ,xv) @@ -545,6 +557,7 @@ ) (defmacro print-vf (vf &key (name #f)) + "Print out a vf register as a vector." `(let ((temp (new 'stack 'vector))) (.svf temp ,vf) ,(if name @@ -555,6 +568,7 @@ ) (defmacro print-vf-hex (vf) + "Print out a vf register as 4x 32-bit hexadecimal integers" `(let ((temp (new 'stack 'vector4w))) (.svf temp ,vf) (format #t "~`vector4w`P~%" temp) diff --git a/goal_src/engine/ps2/vu1-macros.gc b/goal_src/engine/ps2/vu1-macros.gc index 41210e2624..c36dcf8db7 100644 --- a/goal_src/engine/ps2/vu1-macros.gc +++ b/goal_src/engine/ps2/vu1-macros.gc @@ -5,7 +5,10 @@ ;; name in dgo: vu1-macros ;; dgos: GAME, ENGINE -;; this file has no code! +;; this file has no code, just macros for vector-unit stuff. + +;; in OpenGOAL we're also using this for VU0 macros to help with VU0 operations that are not +;; directly implemented by the OpenGOAL compiler (defmacro vu-clip (vfr cf) "Returns the result of VCLIP. diff --git a/goal_src/engine/util/types-h.gc b/goal_src/engine/util/types-h.gc index 85a13655d0..f06852e601 100644 --- a/goal_src/engine/util/types-h.gc +++ b/goal_src/engine/util/types-h.gc @@ -18,12 +18,24 @@ :flag-assert #x900000004 ) +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Common Units +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; in-game durations, distances, and rotations are stored in special formats. +;; these macros/constants convert from literals to the correct format. +;; for example, (meters 4.0) will give you a distance representing 4 in-game meters. + +;; meters are stored as (usually) a float, scaled by 4096. +;; this gives you reasonable accuracy as an integer. (defglobalconstant METER_LENGTH 4096.0) (defmacro meters (x) "Convert number to meters. If the input is a constant float or integer, the result will be a compile time constant float. Otherwise, it will not be constant." + + ;; we don't have enough constant propagation for the compiler to figure this out. (cond ((float? x) (* METER_LENGTH x) @@ -37,6 +49,10 @@ ) ) +;; rotations are stored in 65,536ths of a full rotation. +;; like with meters, you get a reasonable accuracy as an integer. +;; additionally, it is a power-of-two, so wrapping rotations can be done +;; quickly by converting to an int, masking, and back to float (defglobalconstant DEGREES_PER_ROT 65536.0) (defmacro degrees (x) @@ -54,6 +70,10 @@ ) ) +;; times are stored in 300ths of a second. +;; this divides evenly into frames at both 50 and 60 fps. +;; typically these are stored as integers as more precision is not useful. +;; an unsigned 32-bit integer can store about 150 days (defglobalconstant TICKS_PER_SECOND 300) ;; 5 t/frame @ 60fps, 6 t/frame @ 50fps (defmacro seconds (x) @@ -75,4 +95,4 @@ (defmacro vel-tick (vel) "turn a velocity value into a per-tick value" `(* (/ 1.0 ,TICKS_PER_SECOND) ,vel) - ) \ No newline at end of file + ) diff --git a/test/decompiler/reference/engine/entity/entity-h_REF.gc b/test/decompiler/reference/engine/entity/entity-h_REF.gc index 7f5cf4f99c..d0b3bbcaf6 100644 --- a/test/decompiler/reference/engine/entity/entity-h_REF.gc +++ b/test/decompiler/reference/engine/entity/entity-h_REF.gc @@ -276,7 +276,7 @@ ;; failed to figure out what this is: (if (zero? entity-nav-login) - (set! entity-nav-login nothing) + (set! entity-nav-login (the-as (function basic none) nothing)) ) ;; definition of type actor-bank diff --git a/test/decompiler/reference/engine/gfx/tie/prototype-h_REF.gc b/test/decompiler/reference/engine/gfx/tie/prototype-h_REF.gc index e3bf406ab1..697322c158 100644 --- a/test/decompiler/reference/engine/gfx/tie/prototype-h_REF.gc +++ b/test/decompiler/reference/engine/gfx/tie/prototype-h_REF.gc @@ -226,8 +226,8 @@ ;; definition of type proxy-prototype-array-tie (deftype proxy-prototype-array-tie (basic) - ((prototype-array-tie basic :offset-assert 4) - (wind-vectors uint32 :offset-assert 8) + ((prototype-array-tie prototype-array-tie :offset-assert 4) + (wind-vectors uint32 :offset-assert 8) ) :method-count-assert 9 :size-assert #xc diff --git a/test/decompiler/reference/engine/gfx/tie/tie-h_REF.gc b/test/decompiler/reference/engine/gfx/tie/tie-h_REF.gc index 1c0db49012..240b8388b9 100644 --- a/test/decompiler/reference/engine/gfx/tie/tie-h_REF.gc +++ b/test/decompiler/reference/engine/gfx/tie/tie-h_REF.gc @@ -86,7 +86,7 @@ ;; definition of type drawable-tree-instance-tie (deftype drawable-tree-instance-tie (drawable-tree) - ((prototypes basic :offset 8) + ((prototypes proxy-prototype-array-tie :offset 8) ) :method-count-assert 18 :size-assert #x24 diff --git a/test/decompiler/reference/engine/gfx/vis/bsp-h_REF.gc b/test/decompiler/reference/engine/gfx/vis/bsp-h_REF.gc index c73ba6be99..1006f34903 100644 --- a/test/decompiler/reference/engine/gfx/vis/bsp-h_REF.gc +++ b/test/decompiler/reference/engine/gfx/vis/bsp-h_REF.gc @@ -49,8 +49,8 @@ (boxes box8s-array :offset-assert 148) (unk-data-3 uint32 :offset-assert 152) (ambients drawable-inline-array-ambient :offset-assert 156) - (unk-data-4 uint32 :offset-assert 160) - (unk-data-5 uint32 :offset-assert 164) + (unk-data-4 float :offset-assert 160) + (unk-data-5 float :offset-assert 164) (adgifs adgif-shader-array :offset-assert 168) (unk-data-6 pointer :offset-assert 172) (unk-data-7 pointer :offset-assert 176) diff --git a/test/decompiler/reference/engine/level/level-h_REF.gc b/test/decompiler/reference/engine/level/level-h_REF.gc index 3dba508bae..aac9831dca 100644 --- a/test/decompiler/reference/engine/level/level-h_REF.gc +++ b/test/decompiler/reference/engine/level/level-h_REF.gc @@ -117,10 +117,10 @@ ;; definition of type login-state (deftype login-state (basic) - ((state int32 :offset-assert 4) - (pos uint32 :offset-assert 8) - (elts uint32 :offset-assert 12) - (elt uint32 16 :offset-assert 16) + ((state int32 :offset-assert 4) + (pos uint32 :offset-assert 8) + (elts uint32 :offset-assert 12) + (elt drawable 16 :offset-assert 16) ) :method-count-assert 9 :size-assert #x50 diff --git a/test/decompiler/reference/engine/load/loader-h_REF.gc b/test/decompiler/reference/engine/load/loader-h_REF.gc index 74b4ddb507..7116367d42 100644 --- a/test/decompiler/reference/engine/load/loader-h_REF.gc +++ b/test/decompiler/reference/engine/load/loader-h_REF.gc @@ -3,9 +3,9 @@ ;; definition of type load-dir (deftype load-dir (basic) - ((unknown basic :offset-assert 4) - (string-array (array string) :offset-assert 8) - (data-array (array basic) :offset-assert 12) + ((unknown basic :offset-assert 4) + (string-array (array string) :offset-assert 8) + (data-array (array art-group) :offset-assert 12) ) :method-count-assert 11 :size-assert #x10 @@ -50,7 +50,7 @@ (set! (-> obj data-array) (the-as - (array basic) + (array art-group) ((method-of-type array new) allocation array basic length) ) ) diff --git a/test/decompiler/reference/engine/math/vector-h_REF.gc b/test/decompiler/reference/engine/math/vector-h_REF.gc index 7e76c35edd..b24ba71542 100644 --- a/test/decompiler/reference/engine/math/vector-h_REF.gc +++ b/test/decompiler/reference/engine/math/vector-h_REF.gc @@ -749,8 +749,8 @@ ;; definition of type vertical-planes-array (deftype vertical-planes-array (basic) - ((length uint32 :offset-assert 4) - (data vertical-planes :dynamic :offset 16) + ((length uint32 :offset-assert 4) + (data vertical-planes :inline :dynamic :offset-assert 16) ) :method-count-assert 9 :size-assert #x10