diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 0089dc9d5d..b308ebf13a 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -5129,11 +5129,6 @@ ;; - Types -(defenum vis-info-flag - :bitfield #t - :type uint32 - (waiting-for-load 30) - ) (declare-type bsp-header basic) (deftype level-vis-info (basic) ((level symbol :offset-assert 4) @@ -6313,7 +6308,7 @@ (collide-ray (_type_ int collide-list) none 13) (collect-stats (_type_) none 14) (debug-draw (_type_ drawable display-frame) none 15) - (dummy-16 (_type_ object object) object 16) + (unpack-vis (_type_ (pointer int8) (pointer int8)) (pointer int8) 16) (collect-ambients (_type_ sphere int ambient-list) none 17) ) ) diff --git a/decompiler/config/jak1_ntsc_black_label/hacks.jsonc b/decompiler/config/jak1_ntsc_black_label/hacks.jsonc index 5fd310ea6b..13ad4a2370 100644 --- a/decompiler/config/jak1_ntsc_black_label/hacks.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/hacks.jsonc @@ -267,9 +267,6 @@ // target2 BUG "look-for-points-of-interest", // Failed to split nested sc - looks like dead code to me - // drawable-tree - "(method 16 drawable-tree)", - // collide-cache "(method 10 collide-puss-work)", // CFG "(method 9 collide-puss-work)", // decompiler crash @@ -482,7 +479,8 @@ "birth-pickup-at-point": [0], "draw-bones": [0, 1, 2, 8, 81], - "draw-bones-hud": [7, 8] + "draw-bones-hud": [7, 8], + "(method 16 drawable-tree)": [7, 9, 10] }, // Sometimes the game might use format strings that are fetched dynamically, diff --git a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc index 7bf60d1199..2c1507c61b 100644 --- a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc @@ -7282,5 +7282,21 @@ "(method 13 drawable-inline-array-instance-tie)": [ [[1, 6], "v1", "instance-tie"] ], + + "(method 10 drawable-tree-array)": [ + [4, "v1", "terrain-context"] + ], + + "(method 16 drawable-tree)":[ + [[1,4], "v1", "drawable-inline-array-node"], + //[4, "a1", "int"], + [11, "v1", "(pointer int8)"], + [[29,34], "t0", "drawable-inline-array-node"], + [31, "t2", "drawable-inline-array-node"], + //[[34,36], "a1", "int"], + [36, "t1", "(pointer int8)"], + [[9, 42], "a2", "(pointer int8)"] + ], + "placeholder-do-not-add-below": [] } diff --git a/game/fake_iso.txt b/game/fake_iso.txt index dfd3081541..36806df31d 100644 --- a/game/fake_iso.txt +++ b/game/fake_iso.txt @@ -2,14 +2,19 @@ ; Each entry should consist of an ISO name, followed by a file name ; note that tweakval, vagdir, screen1 have dummy data for now. +;; CGO Files KERNEL.CGO out/iso/KERNEL.CGO GAME.CGO out/iso/GAME.CGO TEST.CGO resources/TEST.CGO ART.CGO out/iso/ART.CGO + +;; Special Weird Files TWEAKVAL.MUS resources/TWEAKVAL.MUS VAGDIR.AYB resources/VAGDIR.AYB SCREEN1.USA resources/SCREEN1.USA SAVEGAME.ICO resources/SAVEGAME.ICO + +;; Text files 0COMMON.TXT out/iso/0COMMON.TXT 1COMMON.TXT out/iso/1COMMON.TXT 2COMMON.TXT out/iso/2COMMON.TXT @@ -17,6 +22,8 @@ SAVEGAME.ICO resources/SAVEGAME.ICO 4COMMON.TXT out/iso/4COMMON.TXT 5COMMON.TXT out/iso/5COMMON.TXT 0TEST.TXT out/iso/0TEST.TXT + +;; Level DGO VI1.DGO out/iso/VI1.DGO VI2.DGO out/iso/VI2.DGO VI3.DGO out/iso/VI3.DGO @@ -28,6 +35,21 @@ MAI.DGO out/iso/MAI.DGO BEA.DGO out/iso/BEA.DGO CIT.DGO out/iso/CIT.DGO SUN.DGO out/iso/SUN.DGO + +;; Level VIS +VI1.VIS out/iso/VI1.VIS +VI2.VIS out/iso/VI2.VIS +VI3.VIS out/iso/VI3.VIS +TRA.VIS out/iso/TRA.VIS +FIN.VIS out/iso/FIN.VIS +FIC.VIS out/iso/FIC.VIS +JUN.VIS out/iso/JUN.VIS +MAI.VIS out/iso/MAI.VIS +BEA.VIS out/iso/BEA.VIS +CIT.VIS out/iso/CIT.VIS +SUN.VIS out/iso/SUN.VIS + +;; Streaming Animations FUCVICTO.STR out/iso/FUCVICTO.STR FUCV2.STR out/iso/FUCV2.STR FUCV3.STR out/iso/FUCV3.STR diff --git a/game/overlord/iso.cpp b/game/overlord/iso.cpp index e4c9081873..3dd70f26a5 100644 --- a/game/overlord/iso.cpp +++ b/game/overlord/iso.cpp @@ -731,7 +731,7 @@ u32 CopyDataToIOP(IsoMessage* _cmd, IsoBufferHeader* buffer_header) { memcpy(cmd->dst_ptr, buffer_header->get_data(), bytes_to_send); - cmd->dest_addr += bytes_to_send; + cmd->dst_ptr += bytes_to_send; cmd->bytes_done += bytes_to_send; buffer_header->data = nullptr; buffer_header->data_size = 0; diff --git a/game/overlord/ramdisk.cpp b/game/overlord/ramdisk.cpp index 9ab08e53d4..f78182577c 100644 --- a/game/overlord/ramdisk.cpp +++ b/game/overlord/ramdisk.cpp @@ -139,6 +139,7 @@ void* RPC_Ramdisk(unsigned int fno, void* data, int size) { gNumFiles++; // Load file into IOP at the appropriate spot + printf("[OVERLORD RAMDISK] loading file %s with size %d\n", cmd->name, file_length); LoadISOFileToIOP(file_record, gMem + gMemUsed, file_length); gMemUsed += gFiles[gNumFiles].size; } else { @@ -169,7 +170,7 @@ void* RPC_Ramdisk(unsigned int fno, void* data, int size) { } // copy to return buffer. This way RAMDISK data is valid until another GET_DATA. - memcpy(gReturnBuffer, gMem + offset + gFiles[file_idx].additional_offset, size); + memcpy(gReturnBuffer, gMem + offset + gFiles[file_idx].additional_offset, cmd->size); return gReturnBuffer; } else if (fno == RAMDISK_BYPASS_LOAD_FILE) { printf("[OVERLORD RAMDISK] got \"%s\"\n", cmd->name); diff --git a/game/system/iop_thread.cpp b/game/system/iop_thread.cpp index a8f9efaed3..2ed60fcdac 100644 --- a/game/system/iop_thread.cpp +++ b/game/system/iop_thread.cpp @@ -6,26 +6,8 @@ #include #endif #include "SystemThread.h" -//#include "shared_config.h" -//#include "ps2/SCE_IOP.h" -//#include "overlord/ramdisk.h" -//#include "ps2/SCE_SIF.h" -//#include "IOP.h" -// -//#include "overlord/dma.h" -//#include "overlord/fake_iso.h" -//#include "overlord/iso.h" -//#include "overlord/iso_api.h" -//#include "overlord/iso_cd.h" -//#include "overlord/iso_queue.h" -//#include "overlord/isocommon.h" -//#include "overlord/overlord.h" -//#include "overlord/ramdisk.h" -//#include "overlord/sbank.h" -//#include "overlord/soundcommon.h" -//#include "overlord/srpc.h" -//#include "overlord/ssound.h" -//#include "overlord/stream.h" + +#include IOP::IOP() {} @@ -68,6 +50,7 @@ void IOP::reset_allocator() { void* IOP::iop_alloc(int size) { void* mem = malloc(size); + memset(mem, 0xaa, size); allocations.push_back(mem); return mem; } diff --git a/goal_src/engine/camera/cam-update.gc b/goal_src/engine/camera/cam-update.gc index 6cb8eec59a..984d53fa84 100644 --- a/goal_src/engine/camera/cam-update.gc +++ b/goal_src/engine/camera/cam-update.gc @@ -5,15 +5,11 @@ ;; name in dgo: cam-update ;; dgos: GAME, ENGINE -;; definition for function plane-from-points -(defun - plane-from-points - ((arg0 (inline-array plane)) - (arg1 vector) - (arg2 vector) - (arg3 vector) - (arg4 int) - ) +;; Once the camera's position and orientation has been calculated, +;; the camera and visibility outputs are updated in this file. + +(defun plane-from-points ((arg0 (inline-array plane)) (arg1 vector) (arg2 vector) (arg3 vector) (arg4 int)) + "Get a plane that contains the 3 given points." (let ((s4-0 (new 'stack-no-clear 'vector))) (vector-cross! s4-0 arg1 arg2) (vector-normalize! s4-0 1.0) @@ -28,8 +24,8 @@ ) ) -;; definition for function set-point (defun set-point ((arg0 vector) (arg1 float) (arg2 float) (arg3 float)) + "Set a vector to an xyz point (sets w = 1.0)" (set! (-> arg0 x) arg1) (set! (-> arg0 y) arg2) (set! (-> arg0 z) arg3) @@ -39,11 +35,8 @@ ) ) -;; definition for function update-view-planes -;; Used lq/sq -(defun - update-view-planes - ((arg0 math-camera) (arg1 (inline-array plane)) (arg2 float)) +(defun update-view-planes ((arg0 math-camera) (arg1 (inline-array plane)) (arg2 float)) + "Compute the frustum planes from the given camera." (local-vars (sv-240 vector)) (when (not *artist-fix-frustum*) (let ((s5-0 (new 'stack 'view-frustum))) @@ -129,116 +122,144 @@ ) ) -;; definition for symbol *update-leaf-when-outside-bsp*, type symbol +;; if we should still attempt vis updates when outside of the bsp's boxes. (define *update-leaf-when-outside-bsp* #t) -;; definition for function update-visible (defun update-visible ((arg0 math-camera)) + "Update occlusion visibility data for the camera position. + Each level has a bsp. Each leaf of the bsp stores a list of visible objects. + This is used to implement occlusion culling. + The vis-bits of the level will be updated if needed." (local-vars (a0-16 symbol) (s3-0 level-vis-info) (s4-0 level-vis-info)) (when (not *artist-fix-visible*) - (dotimes (s5-0 (-> *level* length)) - (let ((v1-4 (-> *level* level s5-0))) - (when (= (-> v1-4 status) 'active) - (if - (and - (nonzero? (-> v1-4 bsp nodes)) - (or *update-leaf-when-outside-bsp* (-> v1-4 inside-boxes?)) - ) - (bsp-camera-asm (-> v1-4 bsp) (-> arg0 trans)) - ) - ) - ) - ) - (dotimes (gp-1 (-> *level* length)) - (let ((s5-1 (-> *level* level gp-1))) - (when (= (-> s5-1 status) 'active) - (let ((a2-0 (/ (+ (-> s5-1 bsp visible-list-length) 15) 16))) - (set! (-> s5-1 all-visible?) (if (-> s5-1 all-visible?) - (-> s5-1 all-visible?) - #t - ) - ) - (cond - ((or (not (-> s5-1 force-all-visible?)) (-> s5-1 inside-boxes?)) - (cond - ((or *artist-all-visible* (zero? (-> s5-1 bsp nodes))) - (quad-copy! (-> s5-1 vis-bits) (-> s5-1 bsp all-visible-list) a2-0) - ) - ((begin - (set! s4-0 (-> s5-1 vis-info (-> s5-1 vis-self-index))) - (set! s3-0 (-> s5-1 vis-info (-> s5-1 vis-adj-index))) - (let ((v1-32 #f)) - (set! a0-16 #f) - (when s4-0 - (set! v1-32 (nonzero? (logand (shl #x8000 16) (-> s4-0 flags)))) - (if (< (-> s4-0 length) (-> s4-0 from-bsp current-leaf-idx)) - (set! v1-32 #f) - ) + ;; first, determine which leaf of the bsp we are in (per level). + (dotimes (s5-0 (-> *level* length)) + (let ((v1-4 (-> *level* level s5-0))) + (when (= (-> v1-4 status) 'active) + (if (and (nonzero? (-> v1-4 bsp nodes)) + (or *update-leaf-when-outside-bsp* (-> v1-4 inside-boxes?)) + ) + ;; will store in the bsp's current-leaf-idx. + (bsp-camera-asm (-> v1-4 bsp) (-> arg0 trans)) ) - (when s3-0 - (set! a0-16 (nonzero? (logand (shl #x8000 16) (-> s3-0 flags)))) - (if (< (-> s3-0 length) (-> s3-0 from-bsp current-leaf-idx)) - (set! a0-16 #f) - ) - ) - v1-32 - ) - ) - (if (!= (-> s5-1 all-visible?) 'loading) - (set! (-> s5-1 all-visible?) #f) - ) - (when - (update-vis! s5-1 s4-0 (-> s4-0 ramdisk) (-> s4-0 string-block)) - (countdown (v1-40 8) - (let ((a0-22 (-> s5-1 vis-info v1-40))) - (when a0-22 - (if (!= a0-22 s4-0) - (set! (-> a0-22 current-vis-string) (the-as uint -1)) - ) - ) - ) - ) - (set! (-> s5-1 all-visible?) #f) - ) - ) - (a0-16 - (if (!= (-> s5-1 all-visible?) 'loading) - (set! (-> s5-1 all-visible?) #f) - ) - (when - (update-vis! s5-1 s3-0 (-> s3-0 ramdisk) (-> s3-0 string-block)) - (countdown (v1-50 8) - (let ((a0-27 (-> s5-1 vis-info v1-50))) - (when a0-27 - (if (!= a0-27 s3-0) - (set! (-> a0-27 current-vis-string) (the-as uint -1)) - ) - ) - ) - ) - (set! (-> s5-1 all-visible?) #f) - ) - ) - ((and (= (-> s5-1 all-visible?) 'loading) (-> *level* play?)) - ) - (else - (quad-copy! (-> s5-1 vis-bits) (-> s5-1 bsp all-visible-list) a2-0) - ) ) - ) - (else - (quad-copy! (-> s5-1 vis-bits) (-> s5-1 bsp all-visible-list) a2-0) - ) ) - ) - (if (and *stats-bsp* (= *master-mode* 'game)) - (format *stdcon* "~0kleaf-index = ~d~%" (-> s5-1 bsp current-leaf-idx)) - ) ) - ) + + ;; do vis updates. + (dotimes (gp-1 (-> *level* length)) + (let ((s5-1 (-> *level* level gp-1))) + (when (= (-> s5-1 status) 'active) + (let ((a2-0 (/ (+ (-> s5-1 bsp visible-list-length) 15) 16))) + + ;; start by setting all-visible to something truthy (either original, or #t) + ;; below, we'll try to figure out a way to get vis data and set this back to #f. + (set! (-> s5-1 all-visible?) (if (-> s5-1 all-visible?) + (-> s5-1 all-visible?) + #t + ) + ) + (cond + ((or (not (-> s5-1 force-all-visible?)) (-> s5-1 inside-boxes?)) + ;; we are inside the level's bsp, we should attempt vis stuff. + (cond + ((or *artist-all-visible* (zero? (-> s5-1 bsp nodes))) + ;; we have no bsp, or manual override all visible. Copy the all vis list + ;; to our vis string. + (quad-copy! (-> s5-1 vis-bits) (-> s5-1 bsp all-visible-list) a2-0) + ) + ((begin + ;; our vis info + (set! s4-0 (-> s5-1 vis-info (-> s5-1 vis-self-index))) + ;; adj vis info (idx will be 7 if there's no adj right now, and will give us #f) + (set! s3-0 (-> s5-1 vis-info (-> s5-1 vis-adj-index))) + + (let ((v1-32 #f)) ;; should use self vis + (set! a0-16 #f) ;; should use adj vis + + ;; see if we want self vis + (when s4-0 + (set! v1-32 (nonzero? (logand (shl #x8000 16) (-> s4-0 flags)))) + + ;; not sure when this would happen, but make sure that our leaf + ;; index is in bounds (maybe if you use the wrong version of levels) + (if (< (-> s4-0 length) (-> s4-0 from-bsp current-leaf-idx)) + (set! v1-32 #f) + ) + ) + + ;; see if we want adj vis. + (when s3-0 + (set! a0-16 (nonzero? (logand (shl #x8000 16) (-> s3-0 flags)))) + (if (< (-> s3-0 length) (-> s3-0 from-bsp current-leaf-idx)) + (set! a0-16 #f) + ) + ) + v1-32 ;; this is the cond condition, and is if we want the self vis. + ) + ) + ;; want self. clear all visible if we aren't loading. + (if (!= (-> s5-1 all-visible?) 'loading) + (set! (-> s5-1 all-visible?) #f) + ) + (when (update-vis! s5-1 s4-0 (-> s4-0 ramdisk) (-> s4-0 string-block)) + ;; success! Remove all other vis strings. + ;; if update vis failed (due to still loading, etc), keep previous. + (countdown (v1-40 8) + (let ((a0-22 (-> s5-1 vis-info v1-40))) + (when a0-22 + (if (!= a0-22 s4-0) + (set! (-> a0-22 current-vis-string) (the-as uint -1)) + ) + ) + ) + ) + ;; successful vis update, remove all-visible. + (set! (-> s5-1 all-visible?) #f) + ) + ) + ;; same case as above, but if we want to use the other vis. + (a0-16 + (if (!= (-> s5-1 all-visible?) 'loading) + (set! (-> s5-1 all-visible?) #f) + ) + (when + (update-vis! s5-1 s3-0 (-> s3-0 ramdisk) (-> s3-0 string-block)) + (countdown (v1-50 8) + (let ((a0-27 (-> s5-1 vis-info v1-50))) + (when a0-27 + (if (!= a0-27 s3-0) + (set! (-> a0-27 current-vis-string) (the-as uint -1)) + ) + ) + ) + ) + (set! (-> s5-1 all-visible?) #f) + ) + ) + ((and (= (-> s5-1 all-visible?) 'loading) (-> *level* play?)) + ;; if we're in between vis, then leave the old string. + ) + (else + ;; couldn't find any vis, just make everything visible + (quad-copy! (-> s5-1 vis-bits) (-> s5-1 bsp all-visible-list) a2-0) + ) + ) + ) + (else + ;; outside boxes, and force all visible is set. + (quad-copy! (-> s5-1 vis-bits) (-> s5-1 bsp all-visible-list) a2-0) + ) + ) + ) + (if (and *stats-bsp* (= *master-mode* 'game)) + (format *stdcon* "~0kleaf-index = ~d~%" (-> s5-1 bsp current-leaf-idx)) + ) + ) + ) + ) + #f ) - #f - ) ) ;; definition for symbol *save-camera-inv-rot*, type matrix diff --git a/goal_src/engine/collide/collide-frag.gc b/goal_src/engine/collide/collide-frag.gc index 015ada1d7d..b5659a4c39 100644 --- a/goal_src/engine/collide/collide-frag.gc +++ b/goal_src/engine/collide/collide-frag.gc @@ -21,10 +21,7 @@ ) ;; definition for method 16 of type drawable-tree-collide-fragment -(defmethod - dummy-16 - drawable-tree-collide-fragment - ((obj drawable-tree-collide-fragment) (arg0 object) (arg1 object)) +(defmethod unpack-vis drawable-tree-collide-fragment ((obj drawable-tree-collide-fragment) (arg0 (pointer int8)) (arg1 (pointer int8))) arg1 ) diff --git a/goal_src/engine/draw/drawable-ambient-h.gc b/goal_src/engine/draw/drawable-ambient-h.gc index e808a3e418..0225f13e07 100644 --- a/goal_src/engine/draw/drawable-ambient-h.gc +++ b/goal_src/engine/draw/drawable-ambient-h.gc @@ -38,7 +38,7 @@ (none) ) -(defmethod dummy-16 drawable-tree-ambient ((obj drawable-tree-ambient) (arg0 object) (arg1 object)) +(defmethod unpack-vis drawable-tree-ambient ((obj drawable-tree-ambient) (arg0 (pointer int8)) (arg1 (pointer int8))) arg1 ) diff --git a/goal_src/engine/draw/drawable-group.gc b/goal_src/engine/draw/drawable-group.gc index 63d2a0300d..3f78d95b71 100644 --- a/goal_src/engine/draw/drawable-group.gc +++ b/goal_src/engine/draw/drawable-group.gc @@ -107,9 +107,9 @@ (none) ) -(defmethod dummy-16 drawable-group ((obj drawable-group) (arg0 object) (arg1 object)) - (dotimes (s4-0 (-> obj length)) - (set! arg1 (dummy-16 (-> obj data s4-0) arg0 arg1)) +(defmethod unpack-vis drawable-group ((obj drawable-group) (arg0 (pointer int8)) (arg1 (pointer int8))) + (dotimes (s4-0 (-> obj length) arg1) + (set! arg1 (unpack-vis (-> obj data s4-0) arg0 arg1)) ) arg1 ) \ No newline at end of file diff --git a/goal_src/engine/draw/drawable-h.gc b/goal_src/engine/draw/drawable-h.gc index 5ecb488619..85bd3a0db1 100644 --- a/goal_src/engine/draw/drawable-h.gc +++ b/goal_src/engine/draw/drawable-h.gc @@ -31,7 +31,7 @@ (collide-ray (_type_ int collide-list) none 13) (collect-stats (_type_) none 14) (debug-draw (_type_ drawable display-frame) none 15) - (dummy-16 (_type_ object object) object 16) + (unpack-vis (_type_ (pointer int8) (pointer int8)) (pointer int8) 16) (collect-ambients (_type_ sphere int ambient-list) none 17) ) ) diff --git a/goal_src/engine/draw/drawable-tree.gc b/goal_src/engine/draw/drawable-tree.gc index 8faf5670af..639632ed9c 100644 --- a/goal_src/engine/draw/drawable-tree.gc +++ b/goal_src/engine/draw/drawable-tree.gc @@ -5,11 +5,116 @@ ;; name in dgo: drawable-tree ;; dgos: GAME, ENGINE -;; todo -(defmethod debug-draw drawable-tree-array ((obj drawable-tree-array) (arg0 drawable) (arg1 display-frame)) - (dotimes (s3-0 (-> obj length)) - (debug-draw (-> obj trees s3-0) (-> (the-as drawable-tree-array arg0) trees s3-0) arg1) - ) +;; The "drawable tree" represents a BVH for a specific render. +;; Typically, levels will have ~10 drawable trees. There will be a tree for +;; tfrag, a tree for actors, a tree for tie, + +;; This file contains common functions for all drawable trees. + +(defmethod draw drawable-tree-array ((obj drawable-tree-array) (arg0 drawable-tree-array) (arg1 display-frame)) + "Draw a drawable tree array. If the current level is set to special or special-vis, the draw is skipped." + (let ((v1-1 (-> (scratchpad-object terrain-context) bsp lev-index))) + (case (-> *level* level v1-1 display?) + (('special 'special-vis #f) + ) + (else + (dotimes (s3-0 (-> obj length)) + (draw (-> obj trees s3-0) (-> arg0 trees s3-0) arg1) + ) + ) + ) + ) 0 (none) - ) \ No newline at end of file + ) + +(defmethod collect-stats drawable-tree-array ((obj drawable-tree-array)) + (dotimes (s5-0 (-> obj length)) + (collect-stats (-> obj trees s5-0)) + ) + (none) + ) + +(defmethod debug-draw drawable-tree-array ((obj drawable-tree-array) (arg0 drawable) (arg1 display-frame)) + (dotimes (s3-0 (-> obj length)) + (debug-draw (-> obj trees s3-0) (-> (the-as drawable-tree-array arg0) trees s3-0) arg1) + ) + (none) + ) + +(defmethod unpack-vis drawable-tree ((obj drawable-tree) (arg0 (pointer int8)) (arg1 (pointer int8))) + "Copy our visibility data from arg1 to arg0, unpacking it." + (local-vars (t5-1 int)) + + ;; grab the first array + (let* ((v1-0 (the-as drawable-inline-array-node (-> obj data 0))) + ;; first elt in top array + (a3-1 (/ (-> v1-0 data 0 id) 8)) + ;; number in first array (8 or fewer) + (t0-0 (-> v1-0 length)) + ;; offset in destination + (v1-1 (&+ arg0 a3-1)) + ;; number of bytes + (a3-3 (/ (+ t0-0 7) 8)) + ) + ;; copy the data! + ;;(mem-print (the (pointer uint32) arg1) 10) + (dotimes (t0-1 a3-3) + (let ((t1-0 (-> arg1 0))) + ;;(format 0 "top-copy: #x~X~%" t1-0) + (set! arg1 (&-> arg1 1)) + (set! (-> v1-1 0) t1-0) + ) + (set! v1-1 (&-> v1-1 1)) + ) + ) + ;; now, the remaining arrays, excluding the final which isn't a draw node array. + (let ((v1-5 (+ (-> obj length) -1))) + (when (nonzero? v1-5) + (dotimes (a3-5 v1-5) + ;; pointer to this array + (let* ((t0-4 (-> obj data a3-5)) + ;; pointer to next depth array + (t2-0 (-> obj data (+ a3-5 1))) + ;; id of first in prev + (t1-5 (/ (-> (the-as drawable-inline-array-node t0-4) data 0 id) 8)) + ;; id of first in next + (t2-2 (/ (-> (the-as drawable-inline-array-node t2-0) data 0 id) 8)) + ;; number of nodes in this one + (t0-5 (-> (the-as drawable-inline-array-node t0-4) length)) + ;; output for prev level + (t1-6 (&+ arg0 t1-5)) + ;; output for next level + (t2-3 (&+ arg0 t2-2)) + ) + (while #t + ;; load the vis byte for the one in this array + (let ((t3-0 (-> t1-6 0))) + ;; inc vis ptr. + (set! t1-6 (&-> t1-6 1)) + ;; vis mask bit. (init at highest) + (let ((t4-0 128)) + (label cfg-7) + ;; check if we're visible + (b! (zero? (logand t3-0 t4-0)) cfg-9 :delay (set! t5-1 (-> arg1 0))) + ;; we are visible. write 8 in the output + (set! arg1 (&-> arg1 1)) + (set! (-> t2-3 0) t5-1) + (label cfg-9) + (+! t0-5 -1) + ;; check if we've done all nodes + (b! (zero? t0-5) cfg-12 :delay (.sra t4-0 t4-0 1)) + ;; check if we're done with this byte and inc output. + (b! (nonzero? t4-0) cfg-7 :delay (set! t2-3 (&-> t2-3 1))) + ) + ) + ) + ) + (label cfg-12) + (nop!) + 0 + ) + ) + ) + arg1 + ) diff --git a/goal_src/engine/draw/drawable.gc b/goal_src/engine/draw/drawable.gc index 8f37a497a8..9481a594b2 100644 --- a/goal_src/engine/draw/drawable.gc +++ b/goal_src/engine/draw/drawable.gc @@ -37,6 +37,10 @@ ) ) +(defmethod unpack-vis drawable ((obj drawable) (arg0 (pointer int8)) (arg1 (pointer int8))) + arg1 + ) + (defun-debug find-instance-by-name ((arg0 string)) (dotimes (s5-0 (-> *level* length)) (let ((v1-3 (-> *level* level s5-0))) diff --git a/goal_src/engine/game/main.gc b/goal_src/engine/game/main.gc index 69e7abdeb8..f22c8dd948 100644 --- a/goal_src/engine/game/main.gc +++ b/goal_src/engine/game/main.gc @@ -659,6 +659,7 @@ ) ;; added + #| (let ( (remain (&- (-> global top) (-> global current))) (total (&- (-> global top) (-> global base))) @@ -668,11 +669,13 @@ (* 100.0 (/ (the float remain) (the float total))) ) ) + + ;; added (format *stdcon* "~3LDMA global: ~d debug: ~d~0L~%" (dma-buffer-free (-> disp frames (-> disp on-screen) frame global-buf)) (dma-buffer-free (-> disp frames (-> disp on-screen) frame debug-buf)) ) - #| + ;; added, prints some level status. (dotimes (i 2) (let ((level-heap (-> *level* level i heap))) diff --git a/goal_src/engine/gfx/shrub/shrubbery.gc b/goal_src/engine/gfx/shrub/shrubbery.gc index 22fb72f06d..f30a8372a0 100644 --- a/goal_src/engine/gfx/shrub/shrubbery.gc +++ b/goal_src/engine/gfx/shrub/shrubbery.gc @@ -5,3 +5,6 @@ ;; name in dgo: shrubbery ;; dgos: GAME, ENGINE +(defmethod unpack-vis drawable-tree-instance-shrub ((obj drawable-tree-instance-shrub) (arg0 (pointer int8)) (arg1 (pointer int8))) + arg1 + ) \ No newline at end of file diff --git a/goal_src/engine/gfx/time-of-day.gc b/goal_src/engine/gfx/time-of-day.gc index 32ae8046e5..027e4444d1 100644 --- a/goal_src/engine/gfx/time-of-day.gc +++ b/goal_src/engine/gfx/time-of-day.gc @@ -158,7 +158,6 @@ ) ;; 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)))) diff --git a/goal_src/engine/gfx/vis/bsp-h.gc b/goal_src/engine/gfx/vis/bsp-h.gc index bf89ac849e..6455c77871 100644 --- a/goal_src/engine/gfx/vis/bsp-h.gc +++ b/goal_src/engine/gfx/vis/bsp-h.gc @@ -5,12 +5,16 @@ ;; name in dgo: bsp-h ;; dgos: GAME, ENGINE -;; Each level has . There is a bsp-header, and a list of bsp-nodes. +;; Each level has a bsp file. There is a bsp-header, and a list of bsp-nodes. ;; The bsp-nodes make up a tree. Each node has a plane and two child nodes. ;; The bsp-header also contains (or references) all of the static level information. ;; The file containing the bsp-header is called the "bt" and is loaded in a special ;; way because that allows it to use all of the remaining level heap memory. ;; This file is very large (>8 MB), and always the last file in a level DGO. +;; The bsp file also contains all the drawable trees and lots of other level data, +;; so the "bsp-header" name isn't very accurate. + +;; Typically, the "bsp" refers to the static level data, and the "level" to the runtime level info. ;; In the game, all of these bsp-header files have -vis after their name ;; I believe this means that this is a version of a level that has an associated vis file @@ -19,6 +23,9 @@ (declare-type entity-camera basic) +;; flags: 1 = load +;; 2 = display + ;; a node in the bsp tree (deftype bsp-node (structure) ((front int32 :offset-assert 0) ;; if > 0, is a pointer to another bsp-node @@ -48,7 +55,7 @@ (unk-zero-0 basic :offset-assert 68) (name symbol :offset-assert 72) (nickname symbol :offset-assert 76) - (vis-info level-vis-info 8 :offset-assert 80) + (vis-info level-vis-info 8 :offset-assert 80) ;; note: 0 when not present. (actors drawable-inline-array-actor :offset-assert 112) (cameras (array entity-camera) :offset-assert 116) (nodes (inline-array bsp-node) :offset-assert 120) diff --git a/goal_src/engine/gfx/vis/bsp.gc b/goal_src/engine/gfx/vis/bsp.gc index f9bc8ba54e..3568cee6f2 100644 --- a/goal_src/engine/gfx/vis/bsp.gc +++ b/goal_src/engine/gfx/vis/bsp.gc @@ -216,6 +216,7 @@ (add-irq-to-tex-buckets! lev) ;; upload the visible list to the scratchpad. + ;; the final result of all visibility calculations is stored in vis-bits. ;; this goes at the end of the scratchpad. (let ((vis-list-qwc (/ (+ (-> obj visible-list-length) 15) 16))) (dma-send-to-spr-no-flush diff --git a/goal_src/engine/level/level-h.gc b/goal_src/engine/level/level-h.gc index 5d9f81aca3..843796488f 100644 --- a/goal_src/engine/level/level-h.gc +++ b/goal_src/engine/level/level-h.gc @@ -6,19 +6,35 @@ ;; dgos: GAME, ENGINE ;; The level system is responsible for loading and managning the two levels. +;; The "level" type contains runtime information about a level (possibly one that is loading) +;; and the "level-group" type contains two levels. (defconstant LEVEL_COUNT 2) ;; there are two levels in memory! (defenum vis-info-flag :bitfield #t :type uint32 - (waiting-for-load 30) + (twenty-nine 29) ;; is .VIS file vis? + (waiting-for-iop-to-ee 30) + (thirty-one 31) ;; single vis? ) ;; Information related to visibility data for a level. -;; Unclear why there are 8 of these per level. -;; Perhaps there are up to 8 "chunks" of the visibility loaded at a single time? -;; The full visibility data lives on the IOP. +;; This is just metadata that describes the actual VIS file. +;; The typical use is to do (-> info vis-string idx) to get the offset (in the .VIS file) of the +;; compressed visibility string for a given bsp leaf. + +;; Each level may have multiple level-vis-infos. +;; Each .VIS file can have visibility data for multiple levels. +;; Each level that is present in a .VIS has a level-vis-info to go with is. +;; One level-vis-info (the first) is always for the +;; actual level, and there is typically one for each neighboring level. +;; The final level-vis-info (7) should always be empty (set to 0 in the bsp-header) + +;; When travelling between two levels, the game will only have one .VIS file loaded, +;; and it does two lookups in this .VIS file - one for the current level, and one for the nearby +;; levels. This means that visibility for "beach" near the border of "village1" is stored in +;; both BEA.VIS and VI1.VIS. (declare-type bsp-header basic) (deftype level-vis-info (basic) ((level symbol :offset-assert 4) @@ -30,7 +46,7 @@ (dictionary-length uint32 :offset-assert 28) (dictionary uint32 :offset-assert 32) (string-block uint32 :offset-assert 36) - (ramdisk uint32 :offset-assert 40) + (ramdisk uint32 :offset-assert 40) ;; ramdisk file ID. (vis-bits pointer :offset-assert 44) (current-vis-string uint32 :offset-assert 48) (vis-string uint32 :dynamic :offset-assert 52) @@ -135,7 +151,7 @@ (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-info level-vis-info 8 :offset-assert 408) ;; note: #f when doesn't exist. (vis-self-index int32 :offset-assert 440) (vis-adj-index int32 :offset-assert 444) (vis-buffer uint8 2048 :offset-assert 448) diff --git a/goal_src/engine/level/level.gc b/goal_src/engine/level/level.gc index 60a06a3faf..c98a31ae1c 100644 --- a/goal_src/engine/level/level.gc +++ b/goal_src/engine/level/level.gc @@ -175,27 +175,40 @@ (defmethod vis-clear level ((obj level)) "Clear the visibility info for when the level is loading." + + ;; clear vis-infos, so we can't try to look up a vis string. (countdown (v1-0 8) (nop!) ;; the usual. (set! (-> obj vis-info v1-0) #f) ) + ;; set the vis string to all 0s. (dotimes (v1-3 128) (set! (deref int128 (-> obj vis-bits) v1-3) (the-as int128 0)) ) + ;; this flag indicates we don't have vis data because loading is in progress (set! (-> obj all-visible?) 'loading) 0 ) (defmethod vis-load level ((obj level)) + "Start the initial load of a VIS file to the IOP VIS buffer. After this is done, we can use + ramdisk-load to load chunks." + + ;; check to see if we have a buffer for loaded vis data. (when (zero? (-> obj vis-info (-> obj vis-self-index) ramdisk)) + ;; nope, we have no vis data buffer, we need to set it up. + + ;; first, we should see if the other level has loaded vis. if so, kill it. (let ((vis (-> obj other vis-info (-> obj other vis-self-index)))) (when (and vis (nonzero? (-> vis ramdisk))) - (set! (-> vis flags) (logand #xffffffffbfffffff (-> vis flags))) ;; clear #x40000000 + (set! (-> vis flags) (logand #xffffffffbfffffff (-> vis flags))) ;; clear waiting-for-load (set! (-> vis ramdisk) 0) 0 ) ) + + ;; set up a ramdisk rpc (fill command, actually load the file from DVD to IOP buffer) (let ((visname (make-file-name (file-kind vis) (the-as string (-> obj nickname)) 0 #f)) (cmd (the-as ramdisk-rpc-fill (add-element *ramdisk-rpc*))) (s5-0 (+ *current-ramdisk-id* 1)) @@ -203,10 +216,14 @@ (set! *current-ramdisk-id* s5-0) (set! (-> cmd filename) (string->sound-name visname)) (set! (-> cmd ee-id) s5-0) - (call *ramdisk-rpc* (the-as uint 1) (the-as pointer 0) (the-as uint 0)) + (load-dbg "doing ramdisk vis load: ~A~%" visname) + (call *ramdisk-rpc* RAMDISK_RPC_FILL_FNO (the-as pointer 0) (the-as uint 0)) + ;; remember which ramdisk id we are assigned (set! (-> obj vis-info (-> obj vis-self-index) ramdisk) s5-0) ) ) + + ;; return the ramdisk ID. (-> obj vis-info (-> obj vis-self-index) ramdisk) ) @@ -227,30 +244,42 @@ ) (defmethod init-vis level ((obj level)) - "Link vis data to level." + "Set up the vis info in a level from the vis info in the BSP." + (when (not (or (= (-> obj status) 'inactive) (not (-> obj bsp)))) + ;; no vis loaded at first, mark as loading/invalid. (set! (-> obj all-visible?) 'loading) + ;; vis info 0 is always self. (let ((s5-0 (-> obj bsp vis-info 0))) + ;; check that our vis info is valid. (cond ((and s5-0 (nonzero? s5-0) (valid? s5-0 level-vis-info #f #f 0)) + ;; add to the level (set! (-> obj vis-info 0) s5-0) + ;; don't have a string loaded yet (set! (-> s5-0 current-vis-string) (the-as uint -1)) + ;; link to bsp (set! (-> s5-0 from-bsp) (-> obj bsp)) + ;; the current vis string (uncompressed). The level allocates/manages this. (set! (-> s5-0 vis-bits) (-> obj vis-bits)) - (set! - (-> s5-0 flags) - (logand (the-as uint #xffffffff3fffffff) (-> s5-0 flags)) - ) + ;; clear waiting-for-load, thirty-one + (set! (-> s5-0 flags) (logand (the-as uint #xffffffff3fffffff) (-> s5-0 flags))) + ;; set twenty-nine (set! (-> s5-0 flags) (logior #x20000000 (-> s5-0 flags))) (set! (-> s5-0 ramdisk) (the-as uint 0)) (set! (-> s5-0 string-block) (the-as uint #f)) + ;; remember that we use the vis system. This will enable warnings in the kernel + ;; if we run out of actor memory. Without vis, I guess this happens a lot. (set! *vis-boot* #t) ) (else + ;; we don't have vis (but it's okay) (set! (-> obj vis-info 0) #f) ) ) ) + + ;; check for up to 6 neighbor level vis info. The last one is always left as null. (dotimes (s5-1 6) (let* ((s3-0 (+ s5-1 1)) (s4-0 (-> obj bsp vis-info s3-0)) @@ -261,10 +290,8 @@ (set! (-> s4-0 current-vis-string) (the-as uint -1)) (set! (-> s4-0 from-bsp) #f) (set! (-> s4-0 vis-bits) (-> obj vis-bits)) - (set! - (-> s4-0 flags) - (logand (the-as uint #xffffffff1fffffff) (-> s4-0 flags)) - ) + ;; clear 29, 30, 31 + (set! (-> s4-0 flags) (logand (the-as uint #xffffffff1fffffff) (-> s4-0 flags))) (set! *vis-boot* #t) ) (else @@ -1017,7 +1044,7 @@ ;; method 10 level (defmethod is-object-visible? level ((obj level) (arg0 int)) - "Is arg0 visible?" + "Is arg0 visible? Note that this will return #f if the visibility data is not loaded." ;; check the vis bits! (let* (;; lwu v1, 388(a0) (vis-data (-> obj vis-bits)) @@ -1033,10 +1060,11 @@ ;; dsllv v1, v1, a0 (check-sign-word (the int (shl vis-byte shift-amount))) ;; signed ) - ;; slt v1, v1, r0 + ;; slt v1, v1, r0 v1 = (csw < 0) ;; daddiu v0, s7, 8 - ;; movz v0, s7, v1 - (>= check-sign-word 0) + ;; movz v0, s7, v1 if (csw >= 0) result = false + ;;(format 0 "vis check ~D ~X ~X ~A~%" arg0 vis-byte check-sign-word (>= check-sign-word 0)) + (< check-sign-word 0) ) ) @@ -1062,7 +1090,7 @@ (< (-> arg0 y) (-> v1-5 0 max y)) (< (-> arg0 z) (-> v1-5 0 max z)) ) - #t + (return #t) ) (set! v1-5 (the (inline-array box8s) (-> v1-5 1))) ) @@ -1759,23 +1787,33 @@ ) ) ) + + ;; load vis info. + ;; The load-state's vis-nick is the level we want vis data for. + ;; Note that we won't load vis until we are inside the level's boxes. + + ;; this will be the level that is currently being used. (let ((s5-3 #f)) (dotimes (v1-121 (-> *level* length)) (let ((a0-55 (-> *level* level v1-121))) - (when (= (-> a0-55 status) 'active) - (if (nonzero? (-> a0-55 vis-info (-> a0-55 vis-self-index) ramdisk)) + (when (= (-> a0-55 status) 'active) ;; level is active + (if (nonzero? (-> a0-55 vis-info (-> a0-55 vis-self-index) ramdisk)) ;; and vis is set up. (set! s5-3 (-> a0-55 nickname)) ) ) ) ) + + ;; if we have the wrong vis (when (and (!= s5-3 (-> obj vis-nick)) (-> *level* vis?)) + ;; and we want a vis (when (-> obj vis-nick) + ;; find matching level and load vis (dotimes (s4-3 (-> *level* length)) (let ((v1-133 (-> *level* level s4-3))) (when (= (-> v1-133 status) 'active) (if (and (= (-> v1-133 nickname) (-> obj vis-nick)) - (-> v1-133 inside-boxes?) + (-> v1-133 inside-boxes?) ;; note: only start if we are inside boxes. ) (load-vis-info (-> obj vis-nick) s5-3) ) @@ -1814,6 +1852,7 @@ (when (= (-> s4-0 status) 'active) (set! (-> s4-0 inside-boxes?) (point-in-boxes? s4-0 (-> *math-camera* trans))) (set! (-> s4-0 inside-sphere?) (>= (-> s4-0 bsp bsphere w) (-> s4-0 level-distance))) + ;; being inside sets your meta-inside to #t. If you are outside, remember your old inside. (if (-> s4-0 inside-boxes?) (set! (-> s4-0 meta-inside?) #t) ) @@ -1828,6 +1867,7 @@ (dotimes (s5-2 (-> obj length)) (let ((s4-1 (-> obj level s5-2))) (when (= (-> s4-1 status) 'active) + ;; if you're outside here, and inside somewhere else, kick out of meta inside. (if (and (-> s4-1 inside-boxes?) (not (-> s4-1 other inside-boxes?))) (set! (-> s4-1 other meta-inside?) #f) ) @@ -1858,17 +1898,21 @@ ) ) - ;; handle visibility stuff + ;; determine vis info idx for each level (dotimes (v1-67 (-> obj length)) (let ((a0-26 (-> obj level v1-67))) (when (= (-> a0-26 status) 'active) + ;; self is always 0 (set! (-> a0-26 vis-self-index) 0) + ;; neighbor level defaults to 7 (null placeholder)... (set! (-> a0-26 vis-adj-index) 7) + ;; but if there's a second level that's active, search for a vis info for that level... (when (= (-> a0-26 other status) 'active) (dotimes (a1-10 8) (if (and (-> a0-26 vis-info a1-10) (= (-> a0-26 vis-info a1-10 from-level) (-> a0-26 other load-name)) ) + ;; and store it in the adj index. (set! (-> a0-26 vis-adj-index) a1-10) ) ) @@ -1905,12 +1949,16 @@ ) ) - ;; not sure what this does yet... + ;; if we have vis for level A, but we aren't "in" it, display an error and + ;; force us out of the other level. Ideally the boxes and the load boundary system + ;; will be consistent and there is no way to set a vis to a level that we aren't in. + ;; (you can be "in" multiple levels at the same time, when crossing levels, it is expected + ;; that you are in both.) (dotimes (s5-4 (-> obj length)) (let ((s4-4 (-> obj level s5-4))) (when (= (-> s4-4 status) 'active) - (when (and (= (-> s4-4 nickname) (-> *load-state* vis-nick)) - (not (-> s4-4 inside-boxes?)) + (when (and (= (-> s4-4 nickname) (-> *load-state* vis-nick)) ;; vis for A + (not (-> s4-4 inside-boxes?)) ;; but not in A ) (if (and (= *cheat-mode* 'debug) (-> s4-4 other inside-boxes?)) (format @@ -1925,7 +1973,9 @@ ) ) - ;; do the bsp vis stuff. + ;; if we are outside of the boxes, we consider ourselves "outside of bsp" + ;; if we are outside of both levels boxes, then we don't really know what to do + ;; for vis, and we can display the classic "outside of bsp" error. (cond ((not (or (-> obj level0 inside-boxes?) (-> obj level1 inside-boxes?))) (when (or (-> obj level0 vis-info 0) (-> obj level1 vis-info 0)) @@ -1935,16 +1985,18 @@ ) ) (else + ;; we are in at least one bsp. + ;; now we need to link vis info to bsps. (dotimes (v1-125 (-> obj length)) (let ((a0-44 (-> obj level v1-125))) (when (= (-> a0-44 status) 'active) + ;; loop over vis infos (dotimes (a1-17 8) (let ((a2-18 (-> a0-44 vis-info a1-17))) (when a2-18 - (set! - (-> a2-18 flags) - (logand (the-as uint #xffffffff7fffffff) (-> a2-18 flags)) - ) + ;; clear bit 31 + (set! (-> a2-18 flags) (logand (the-as uint #xffffffff7fffffff) (-> a2-18 flags))) + ;; link info to bsp (cond ((= a1-17 (-> a0-44 vis-self-index)) (set! (-> a2-18 from-bsp) (-> a0-44 bsp)) @@ -1959,34 +2011,30 @@ ) ) ) + + ;; now, handle setting bit 31 (maybe single vis mode?) (cond + ;; special display self mode. ((= (-> a0-44 display?) 'display-self) (let ((a0-46 (-> a0-44 vis-info (-> a0-44 vis-self-index)))) (if a0-46 - (set! - (-> a0-46 flags) - (the-as uint (logior (shl #x8000 16) (-> a0-46 flags))) - ) + (set! (-> a0-46 flags) (the-as uint (logior (shl #x8000 16) (-> a0-46 flags)))) ) ) ) + ;; in this level, but not the other, only use vis for this. ((and (-> a0-44 inside-boxes?) (not (-> a0-44 other inside-boxes?))) (let ((a0-48 (-> a0-44 vis-info (-> a0-44 vis-self-index)))) (if a0-48 - (set! - (-> a0-48 flags) - (the-as uint (logior (shl #x8000 16) (-> a0-48 flags))) - ) + (set! (-> a0-48 flags) (the-as uint (logior (shl #x8000 16) (-> a0-48 flags)))) ) ) ) + ;; only in other level, only use vis for other. ((-> a0-44 other inside-boxes?) (let ((a0-50 (-> a0-44 vis-info (-> a0-44 vis-adj-index)))) (if a0-50 - (set! - (-> a0-50 flags) - (the-as uint (logior (shl #x8000 16) (-> a0-50 flags))) - ) + (set! (-> a0-50 flags) (the-as uint (logior (shl #x8000 16) (-> a0-50 flags)))) ) ) ) @@ -2113,8 +2161,6 @@ ) - - (defmacro test-play () `(begin ;; before calling play, the C Kernel would set this. diff --git a/goal_src/engine/load/decomp.gc b/goal_src/engine/load/decomp.gc index 72e359bbae..602a3c20fd 100644 --- a/goal_src/engine/load/decomp.gc +++ b/goal_src/engine/load/decomp.gc @@ -5,6 +5,8 @@ ;; name in dgo: decomp ;; dgos: GAME, ENGINE +;; This file contains update-vis! which updates the vis-bits string from the loaded VIS file. + ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; decompression functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -110,56 +112,64 @@ ) (defmethod update-vis! level ((obj level) (vis-info level-vis-info) (arg1 uint) (arg2 uint)) + "Update the vis-bits for the level with the given vis info. + arg1 unused. if the vis-file flag isn't set, will use arg2 as vis data." (local-vars (t0-3 uint128) (vis-buffer object)) (let* ((cam-leaf-idx (-> vis-info from-bsp current-leaf-idx)) ;; current bsp leaf of camera (curr-vis-str (-> vis-info current-vis-string)) ;; currently loaded vis-string. - (desired-vis-str (-> vis-info vis-string cam-leaf-idx)) ;; vis-string ptr for what we want. + (desired-vis-str (-> vis-info vis-string cam-leaf-idx)) ;; vis-string offset for bsp leaf. ) ;; oops 0 (+ 16 #x70000000) (+ 2064 #x70000000) - ;; wait on ramdisk load, or do nothing because we already have the right stuff. + ;; this is the same string we asked for last time. (when (= curr-vis-str desired-vis-str) - ;; we match. but are we loading? (cond - ((logtest? (vis-info-flag waiting-for-load) (-> vis-info flags)) - (if (check-busy *ramdisk-rpc*) - ;; loading, and ramdisk not done, return #f, we don't have vis. - (return #f) - ) - ;; we are done loading. Jump to code that sets it up. - (logclear! (-> vis-info flags) (vis-info-flag waiting-for-load)) + ((logtest? (vis-info-flag waiting-for-iop-to-ee) (-> vis-info flags)) + ;; we started IOP -> EE, but it might not be done yet. + (when (check-busy *ramdisk-rpc*) + ;; not done, wait. + (return #f) + ) + ;; we're done! Deal with the vis data. + (logclear! (-> vis-info flags) (vis-info-flag waiting-for-iop-to-ee)) (set! vis-buffer (-> obj vis-buffer)) (b! #t cfg-27 :delay (nop!)) ) (else - ;; matched, and loaded! + ;; matched, and loaded! A previous run would have done setup. (return #t) ) ) ) - ;; wait for any pending load to finish. - (when (logtest? (vis-info-flag waiting-for-load) (-> vis-info flags)) - (if (check-busy *ramdisk-rpc*) + ;; wait for any pending load to finish before trying to change things. + (when (logtest? (vis-info-flag waiting-for-iop-to-ee) (-> vis-info flags)) + (when (check-busy *ramdisk-rpc*) (return #f) ) - (logclear! (-> vis-info flags) (vis-info-flag waiting-for-load)) + (logclear! (-> vis-info flags) (vis-info-flag waiting-for-iop-to-ee)) ) - ;; not sure what this does yet. + ;; ok, we can now change the current string and request from iop. (set! (-> vis-info current-vis-string) desired-vis-str) + ;; this branch picks between .VIS file ramdisk and BSP file visibility data. + ;; the self vis is always in the ramdisk, and the adj file is in the BSP file. (b! (logtest? #x20000000 (-> vis-info flags)) cfg-15) + ;; we're a BSP file file vis. Just use the given pointer and skip the ramdisk stuff. (set! vis-buffer (the-as (pointer uint8) (+ arg2 desired-vis-str))) (b! #t cfg-27 :delay (nop!)) (label cfg-15) - ;; start a ramdisk load. + ;; start a ramdisk load. This should have already been done as part of level loading anyway. + ;; so this will just get the ramdisk file ID. (let ((vis-load-result (vis-load obj))) (b! (nonzero? vis-load-result) cfg-21) + + ;; ramdisk failed, make everything visible. (let* ((dest-bits (-> vis-info vis-bits)) (len (-> obj bsp visible-list-length)) (bsp-bits (the-as (pointer uinteger) (-> obj bsp all-visible-list))) @@ -178,6 +188,8 @@ (b! #t cfg-55 :delay (nop!)) (the-as none 0) (label cfg-21) + ;; if the ramdisk is busy at this point, it means that it's still loading the file + ;; from the DVD. So display a message and keep us in loading. (when (check-busy *ramdisk-rpc*) (set! (-> vis-info current-vis-string) (the-as uint -1)) (set! (-> obj all-visible?) 'loading) @@ -186,60 +198,64 @@ ) (return #f) ) + ;; now the ramdisk has the file in the IOP for sure. we want to ask for the IOP->EE transfer + ;; for the string for our leaf node. Set a flag to remember that we're waiting on IOP->EE: (set! (-> vis-info flags) (logior (-> vis-info flags) #x40000000)) + ;; and kick off a load (ramdisk-load - (the-as int vis-load-result) - desired-vis-str - (the-as uint 2048) - (-> obj vis-buffer) + (the-as int vis-load-result) ;; file ID in ramdisk + desired-vis-str ;; the offset in the VIS file + (the-as uint 2048) ;; always do 2kB. it's a worst case if the string can't be compressed + (-> obj vis-buffer) ;; copy to the level buffer for vis data ) - (set! result #f) + (set! result #f) ;; this takes time, so quit and report that we failed. (b! #t cfg-55 :delay (nop!)) - ;; setup loaded + ;; we'll get here once the compressed vis data is in vis-buffer + ;; this can come from IOP->EE or from the BSP file directly (label cfg-27) + ;; the vis info has data on how to decompress the data in the lower flag bits (let ((lower-flag-bits (the-as int (logand #x1fffffff (-> vis-info flags)))) - (spad-start (the-as object (+ 16 #x70000000))) - (spad-end (+ 2064 #x70000000)) + (spad-start (the-as object (scratchpad-object object :offset 16))) + (spad-end (the-as int (scratchpad-object int :offset 2064))) (list-len (-> obj bsp visible-list-length)) ) (when (zero? (the-as vis-info-flag lower-flag-bits)) + ;; set the spad buffer to 0 (but we write over this next??) (let ((list-qwc (/ (+ list-len 15) 16))) (dotimes (a0-28 list-qwc) - (set! - (-> (the-as (pointer uint128) spad-start) a0-28) - (the-as uint128 0) - ) + (set! (-> (the-as (pointer uint128) spad-start) a0-28) (the-as uint128 0)) ) ) - (mem-copy! - (the-as pointer spad-start) - (the-as pointer vis-buffer) - list-len - ) + ;; but then copy the vis buffer directly. + (mem-copy! (the-as pointer spad-start) (the-as pointer vis-buffer) list-len) ) + (while (nonzero? lower-flag-bits) (case (logand lower-flag-bits 7) - ((1) + ((1) ;; decomp type 1: this unpacks data that exploits the BVH tree structure. + ;; it omits 0's for children of invisible parents. But to unpack, we need + ;; to know all the BVHs in the level. (let ((v1-55 (/ (+ list-len 15) 16))) (dotimes (a0-32 v1-55) (set! (-> (the-as (pointer uint128) spad-start) a0-32) (the-as uint128 0)) ) ) - (dummy-16 + (unpack-vis (-> obj bsp drawable-trees) - (the-as int spad-start) - (the-as object vis-buffer) + (the-as (pointer int8) spad-start) + (the-as (pointer int8) vis-buffer) ) ) - ((2) + ((2) ;; decomp type 2: run length encoding. Haven't seen this yet. + (format 0 "hit RLE case in decomp.gc, probably worth checking.~%") (unpack-comp-rle (the-as (pointer int8) spad-start) (the-as (pointer int8) vis-buffer) ) ) - ((3) + ((3) ;; decomp type 3: huffman encoding. most common. (unpack-comp-huf (the-as (pointer uint8) spad-start) (the-as (pointer uint8) vis-buffer) @@ -250,14 +266,24 @@ ) ) ) + ;; we have 3 rotating 2kB buffers for this unpacking process. + ;; we really only need 2, but I think they did 3 like this so we do RAM -> SPAD, SPAD->SPAD + ;; in practice, I've only seen this hit exactly 2 decompressions, so no need for more complicated + ;; logic to keep us in scratch after the first. (set! vis-buffer (the-as (pointer uint8) (the-as int spad-start))) (set! spad-start spad-end) (set! spad-end (the-as int vis-buffer)) (.sra lower-flag-bits lower-flag-bits 3) ) + + ;; now vis-buffer points to the uncompressed data. + ;; if things went well, we shouldn't have any bits set for drawables that don't exist. + ;; we can check this by anding with the all visible list, and confirming it doesn't + ;; remove any bits. + ;; this just prints errors. (let ((s2-1 (the-as object vis-buffer)) (s1-1 (the-as (pointer uinteger) (-> obj bsp all-visible-list))) - (v1-67 #f) + (v1-67 #f) ;; found error ) (dotimes (s0-1 list-len) (when (!= (logand (-> (the-as (pointer uint8) s2-1) 0) @@ -270,6 +296,7 @@ (-> (the-as (pointer uint8) s2-1) 0) (-> (the-as (pointer uint8) s1-1) 0) ) + (format #t "bad addr: #x~X~%" s2-1) ;; added (set! v1-67 #t) ) (set! s2-1 (&-> (the-as (pointer uint8) s2-1) 1)) @@ -286,6 +313,9 @@ 0 ) ) + + ;; just in case we failed the above check, and with the all visible list anyway. + ;; also copy from vis-buffer (may be spad) to the final vis-bits output (let ((v1-71 (the-as object vis-buffer)) (a0-47 (-> vis-info vis-bits)) (a1-22 (the-as (pointer uinteger) (-> obj bsp all-visible-list))) @@ -304,6 +334,7 @@ ) ) ) + ;; succeeded! (set! result #t) (label cfg-55) result diff --git a/goal_src/engine/load/ramdisk.gc b/goal_src/engine/load/ramdisk.gc index 4d4493550a..076274b428 100644 --- a/goal_src/engine/load/ramdisk.gc +++ b/goal_src/engine/load/ramdisk.gc @@ -9,6 +9,8 @@ ;; unlike most other loads, ramdisk actually uses the response buffer of the RPC ;; to send the data. +(defconstant RAMDISK_RPC_FILL_FNO (the uint 1)) + ;; command to load something into the OVERLORD RAMDISK from the DVD ;; use with fno = 1 (deftype ramdisk-rpc-fill (structure) diff --git a/goal_src/engine/sparticle/sparticle-launcher.gc b/goal_src/engine/sparticle/sparticle-launcher.gc index 2dad858e60..9b32794a36 100644 --- a/goal_src/engine/sparticle/sparticle-launcher.gc +++ b/goal_src/engine/sparticle/sparticle-launcher.gc @@ -945,13 +945,14 @@ (set! (-> obj center quad) (-> arg0 quad)) ;; check if we are visible (remove this check to force particles to be drawn.) - (if (not (or #t ;;(is-visible? obj arg0) + (if (not (or (is-visible? obj arg0) (logtest? (-> obj group flags) (sp-group-flag always-draw screen-space)) ) ) (return (the-as object 0)) ) + (let ((s4-0 *particle-300hz-timer*) (s5-0 (-> obj last-spawn-time)) ) diff --git a/goal_src/game.gp b/goal_src/game.gp index a53b618002..3cd4c5d548 100644 --- a/goal_src/game.gp +++ b/goal_src/game.gp @@ -117,6 +117,17 @@ :tool 'copy :out '(,(string-append "out/iso/" name ".STR"))))) +(defmacro copy-vis-files (&rest files) + `(begin ,@(apply (lambda (x) `(copy-vis-file ,x)) files))) + +(defmacro copy-vis-file (name) + (let* ((folder (get-environment-variable "OPENGOAL_DECOMP_DIR" :default "")) + (path (string-append "iso_data/" folder "/VIS/" name ".VIS"))) + `(defstep :in ,path + :tool 'copy + :out '(,(string-append "out/iso/" name ".VIS"))))) + + (defmacro group (name &rest stuff) @@ -184,8 +195,10 @@ ;; Streaming anim (common) ;;;;;;;;;;;;;;;;;;;;;;;;;;; -(copy-strs "FUCV3" - "FUCV4") +(copy-strs + "FUCVICTO" + "FUCV3" + "FUCV4") ;;;;;;;;;;;;;;;;;;;;; @@ -230,6 +243,7 @@ "out/iso/0COMMON.TXT" "out/iso/KERNEL.CGO" "out/iso/GAME.CGO" + ;; level dgo "out/iso/VI1.DGO" "out/iso/VI2.DGO" "out/iso/VI3.DGO" @@ -241,6 +255,20 @@ "out/iso/BEA.DGO" "out/iso/CIT.DGO" "out/iso/SUN.DGO" + ;; level vis + "out/iso/VI1.VIS" + "out/iso/VI2.VIS" + "out/iso/VI3.VIS" + "out/iso/TRA.VIS" + "out/iso/FIN.VIS" + "out/iso/FIC.VIS" + "out/iso/JUN.VIS" + "out/iso/MAI.VIS" + "out/iso/BEA.VIS" + "out/iso/CIT.VIS" + "out/iso/SUN.VIS" + + "out/iso/FUCVICTO.STR" "out/iso/FUCV3.STR" "out/iso/FUCV4.STR" ) @@ -327,6 +355,9 @@ "vi1.gd" ) +;; the VIS file +(copy-vis-files "VI1") + ;; the code (goal-src-sequence "levels/" @@ -396,6 +427,8 @@ (cgo "JUN.DGO" "jun.gd") +(copy-vis-files "JUN") + (goal-src-sequence "levels/jungle/" :deps ;; no idea what these depend on, make it depend on the whole engine @@ -460,6 +493,8 @@ "bea.gd" ) +(copy-vis-files "BEA") + (goal-src-sequence "levels/beach/" :deps ("out/obj/default-menu.o") @@ -520,6 +555,8 @@ "fic.gd" ) +(copy-vis-files "FIC") + (copy-textures 1119) ;; might be common/zoomer hud?? (goal-src-sequence @@ -553,6 +590,8 @@ (cgo "TRA.DGO" "tra.gd") +(copy-vis-files "TRA") + ;; The code (goal-src-sequence "levels/training/" @@ -584,6 +623,8 @@ (cgo "VI2.DGO" "vi2.gd") +(copy-vis-files "VI2") + (goal-src-sequence "levels/village2/" :deps ("out/obj/default-menu.o") @@ -644,6 +685,8 @@ (cgo "SUN.DGO" "sun.gd") +(copy-vis-files "SUN") + (goal-src-sequence "levels/sunken/" :deps ("out/obj/default-menu.o") @@ -715,6 +758,8 @@ ;; the definition for the DGO file. (cgo "VI3.DGO" "vi3.gd") +(copy-vis-files "VI3") + ;; the code (goal-src-sequence "levels/" @@ -760,6 +805,8 @@ (cgo "MAI.DGO" "mai.gd") +(copy-vis-files "MAI") + (goal-src-sequence "levels/" :deps ;; no idea what these depend on, make it depend on the whole engine @@ -813,6 +860,8 @@ (cgo "CIT.DGO" "cit.gd") +(copy-vis-files "CIT") + (goal-src-sequence "levels/citadel/" :deps ("out/obj/default-menu.o") @@ -872,6 +921,8 @@ (cgo "FIN.DGO" "fin.gd") +(copy-vis-files "FIN") + (goal-src-sequence "levels/finalboss/" :deps ("out/obj/default-menu.o") diff --git a/goalc/compiler/IR.cpp b/goalc/compiler/IR.cpp index 873ebce600..f98af296db 100644 --- a/goalc/compiler/IR.cpp +++ b/goalc/compiler/IR.cpp @@ -1645,13 +1645,13 @@ void IR_Int128Math3Asm::do_codegen(emitter::ObjectGenerator* gen, gen->add_instr(IGen::parallel_compare_e_w(dst, src2, src1), irec); break; case Kind::PCGTB: - gen->add_instr(IGen::parallel_compare_gt_b(dst, src2, src1), irec); + gen->add_instr(IGen::parallel_compare_gt_b(dst, src1, src2), irec); break; case Kind::PCGTH: - gen->add_instr(IGen::parallel_compare_gt_h(dst, src2, src1), irec); + gen->add_instr(IGen::parallel_compare_gt_h(dst, src1, src2), irec); break; case Kind::PCGTW: - gen->add_instr(IGen::parallel_compare_gt_w(dst, src2, src1), irec); + gen->add_instr(IGen::parallel_compare_gt_w(dst, src1, src2), irec); break; case Kind::PSUBW: // psubW on mips is psubD on x86... diff --git a/test/decompiler/reference/engine/collide/collide-frag_REF.gc b/test/decompiler/reference/engine/collide/collide-frag_REF.gc index 8ca1dbddc7..9808b0c643 100644 --- a/test/decompiler/reference/engine/collide/collide-frag_REF.gc +++ b/test/decompiler/reference/engine/collide/collide-frag_REF.gc @@ -19,7 +19,7 @@ ) ;; definition for method 16 of type drawable-tree-collide-fragment -(defmethod dummy-16 drawable-tree-collide-fragment ((obj drawable-tree-collide-fragment) (arg0 object) (arg1 object)) +(defmethod unpack-vis drawable-tree-collide-fragment ((obj drawable-tree-collide-fragment) (arg0 (pointer int8)) (arg1 (pointer int8))) arg1 ) diff --git a/test/decompiler/reference/engine/draw/drawable-ambient-h_REF.gc b/test/decompiler/reference/engine/draw/drawable-ambient-h_REF.gc index 0f3ca527e9..ccc4c65bac 100644 --- a/test/decompiler/reference/engine/draw/drawable-ambient-h_REF.gc +++ b/test/decompiler/reference/engine/draw/drawable-ambient-h_REF.gc @@ -48,7 +48,7 @@ ) ;; definition for method 16 of type drawable-tree-ambient -(defmethod dummy-16 drawable-tree-ambient ((obj drawable-tree-ambient) (arg0 object) (arg1 object)) +(defmethod unpack-vis drawable-tree-ambient ((obj drawable-tree-ambient) (arg0 (pointer int8)) (arg1 (pointer int8))) arg1 ) diff --git a/test/decompiler/reference/engine/draw/drawable-group_REF.gc b/test/decompiler/reference/engine/draw/drawable-group_REF.gc index db0694f3c3..7e64f45028 100644 --- a/test/decompiler/reference/engine/draw/drawable-group_REF.gc +++ b/test/decompiler/reference/engine/draw/drawable-group_REF.gc @@ -108,9 +108,9 @@ ) ;; definition for method 16 of type drawable-group -(defmethod dummy-16 drawable-group ((obj drawable-group) (arg0 object) (arg1 object)) +(defmethod unpack-vis drawable-group ((obj drawable-group) (arg0 (pointer int8)) (arg1 (pointer int8))) (dotimes (s4-0 (-> obj length)) - (set! arg1 (dummy-16 (-> obj data s4-0) arg0 arg1)) + (set! arg1 (unpack-vis (-> obj data s4-0) arg0 arg1)) ) arg1 ) diff --git a/test/decompiler/reference/engine/draw/drawable-h_REF.gc b/test/decompiler/reference/engine/draw/drawable-h_REF.gc index 35330cb23c..1ddfb9effb 100644 --- a/test/decompiler/reference/engine/draw/drawable-h_REF.gc +++ b/test/decompiler/reference/engine/draw/drawable-h_REF.gc @@ -17,7 +17,7 @@ (collide-ray (_type_ int collide-list) none 13) (collect-stats (_type_) none 14) (debug-draw (_type_ drawable display-frame) none 15) - (dummy-16 (_type_ object object) object 16) + (unpack-vis (_type_ (pointer int8) (pointer int8)) (pointer int8) 16) (collect-ambients (_type_ sphere int ambient-list) none 17) ) ) diff --git a/test/decompiler/reference/engine/load/decomp_REF.gc b/test/decompiler/reference/engine/load/decomp_REF.gc index e1c680327c..49865a368b 100644 --- a/test/decompiler/reference/engine/load/decomp_REF.gc +++ b/test/decompiler/reference/engine/load/decomp_REF.gc @@ -192,7 +192,7 @@ (set! (-> (the-as (pointer uint128) spad-start) a0-32) (the-as uint128 0)) ) ) - (dummy-16 (-> obj bsp drawable-trees) (the-as int spad-start) vis-buffer) + (unpack-vis (-> obj bsp drawable-trees) (the-as (pointer int8) spad-start) (the-as (pointer int8) vis-buffer)) ) ((2) (unpack-comp-rle (the-as (pointer int8) spad-start) (the-as (pointer int8) vis-buffer))