diff --git a/.idea/editor.xml b/.idea/editor.xml
index a7ae94c..3361f21 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -15,7 +15,7 @@
-
+
@@ -328,6 +328,7 @@
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 35eb1dd..8287001 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,5 +2,6 @@
+
\ No newline at end of file
diff --git a/Makefile b/Makefile
index b130ec6..79408c7 100644
--- a/Makefile
+++ b/Makefile
@@ -40,8 +40,15 @@ else
DEP_FILES := $(O_FILES:.o=.d)
endif
-TEST_SRCS_C := test/context.c test/level.c test/gl33core/gl33core_renderer.c test/gl20/gl20_renderer.c
-TEST_SRCS_CPP := test/main.cpp test/audio.cpp
+TEST_SRCS_C := test/level.c test/gl33core/gl33core_renderer.c test/gl20/gl20_renderer.c
+TEST_SRCS_CPP := test/main.cpp test/audio.cpp test/context.cpp \
+ test/imgui/imgui.cpp \
+ test/imgui/imgui_demo.cpp \
+ test/imgui/imgui_draw.cpp \
+ test/imgui/imgui_tables.cpp \
+ test/imgui/imgui_widgets.cpp \
+ test/imgui/backends/imgui_impl_sdl2.cpp \
+ test/imgui/backends/imgui_impl_opengl3.cpp
TEST_OBJS := $(foreach file,$(TEST_SRCS_C),$(BUILD_DIR)/$(file:.c=.o)) $(foreach file,$(TEST_SRCS_CPP),$(BUILD_DIR)/$(file:.cpp=.o))
ifdef WINDOWS_BUILD
@@ -51,7 +58,7 @@ else ifdef MACOS_BUILD
LIB_FILE := $(DIST_DIR)/sm64.dylib
endif
-DUMMY := $(shell mkdir -p $(ALL_DIRS) build/test build/test/gl33core build/test/gl20 src/decomp/mario $(DIST_DIR)/include)
+DUMMY := $(shell mkdir -p $(ALL_DIRS) build/test build/test/gl33core build/test/gl20 build/test/imgui build/test/imgui/backends src/decomp/mario $(DIST_DIR)/include)
$(filter-out src/decomp/mario/geo.inc.c,$(IMPORTED)): src/decomp/mario/geo.inc.c
src/decomp/mario/geo.inc.c: ./import-mario-geo.py
@@ -88,21 +95,21 @@ test/level.c: ./import-test-collision.py
test/main.cpp test/gl20/gl20_renderer.c test/gl33core/gl33core_renderer.c: test/level.c
+SDL2_CFLAGS := $(shell sdl2-config --cflags)
+
$(BUILD_DIR)/test/%.o: test/%.c
- @$(CC) $(CFLAGS) -I src/decomp/include -MM -MP -MT $@ -MF $(BUILD_DIR)/test/$*.d $<
- $(CC) -c $(CFLAGS) -I src/decomp/include -o $@ $<
+ $(CC) -c $(CFLAGS) $(SDL2_CFLAGS) -I src/decomp/include -o $@ $<
$(BUILD_DIR)/test/%.o: test/%.cpp
- @$(CXX) $(CFLAGS) -I src/decomp/include -MM -MP -MT $@ -MF $(BUILD_DIR)/test/$*.d $<
- $(CXX) -c $(CFLAGS) -I src/decomp/include -std=c++17 -o $@ $<
+ $(CXX) -c $(CFLAGS) $(SDL2_CFLAGS) -I src/decomp/include -std=c++17 -o $@ $<
$(TEST_FILE): $(LIB_FILE) $(TEST_OBJS)
ifdef WINDOWS_BUILD
- $(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -lglew32 -lopengl32 -lSDL2 -lSDL2main -lm
+ $(CXX) -o $@ $(TEST_OBJS) $(LIB_FILE) -lglew32 -lopengl32 -lSDL2 -lSDL2main -lm
else ifdef MACOS_BUILD
- $(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -framework OpenGL -lGLEW -lSDL2 -lSDL2main -lm -lpthread
+ $(CXX) -o $@ $(TEST_OBJS) $(LIB_FILE) -framework OpenGL -lGLEW -lSDL2 -lSDL2main -lm -lpthread
else
- $(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -lGLEW -lGL -lSDL2 -lSDL2main -lm -lpthread
+ $(CXX) -o $@ $(TEST_OBJS) $(LIB_FILE) -lGLEW -lGL $(shell sdl2-config --libs) -lm -lpthread
endif
lib: $(LIB_FILE) $(LIB_H_FILE)
@@ -119,4 +126,4 @@ endif
clean:
rm -rf $(BUILD_DIR) $(DIST_DIR) $(TEST_FILE)
--include $(DEP_FILES)
+-include $(DEP_FILES)
\ No newline at end of file
diff --git a/import-test-collision.py b/import-test-collision.py
index 84ad628..074e3f5 100755
--- a/import-test-collision.py
+++ b/import-test-collision.py
@@ -1,9 +1,10 @@
#!/usr/bin/env python3
-import os
-import shutil
import urllib.request
+import re
+
+COLLISION_URL = "https://raw.githubusercontent.com/n64decomp/sm64/06ec56df7f951f88da05f468cdcacecba496145a/levels/bob/areas/1/collision.inc.c"
+SCRIPT_URL = "https://raw.githubusercontent.com/n64decomp/sm64/06ec56df7f951f88da05f468cdcacecba496145a/levels/bob/script.c"
-BOB_COLLISION_URL = "https://raw.githubusercontent.com/n64decomp/sm64/06ec56df7f951f88da05f468cdcacecba496145a/levels/bob/areas/1/collision.inc.c"
LEVEL_H = """#pragma once
@@ -14,46 +15,101 @@ extern const size_t surfaces_count;
"""
-def main():
- print("Downloading " + BOB_COLLISION_URL)
- in_lines = urllib.request.urlopen(BOB_COLLISION_URL).read().decode('utf8').splitlines()
+def extract_surface(token):
+ token = token.strip()
+ if "SURFACE_" in token:
+ token = token[token.find("SURFACE_"):]
+ if "," in token:
+ token = token.split(",")[0].strip()
+ return token
+
+def parse_collision(raw):
verts = []
tris = []
- mode = ""
+ current_surface = "SURFACE_DEFAULT"
- for line in in_lines:
- if not line.strip().startswith("COL_"):
- continue;
+ for line in raw:
+ line = line.strip()
- tokens = line.strip().replace("(", ",").replace(")", "").split(",")
+ if "COL_VERTEX(" in line:
+ inside = line[line.find("(") + 1:line.rfind(")")]
+ t = [x.strip() for x in inside.split(",")]
+ verts.append((int(t[0]), int(t[1]), int(t[2])))
- if tokens[0] == "COL_VERTEX":
- verts.append([int(tokens[1]), int(tokens[2]), int(tokens[3])])
- elif tokens[0] == "COL_TRI_INIT":
- mode = tokens[1]
- elif tokens[0] == "COL_TRI":
- tris.append([int(tokens[1]), int(tokens[2]), int(tokens[3]), mode])
+ elif "COL_TRI_INIT(" in line:
+ inside = line[line.find("(") + 1:line.rfind(")")]
+ t = [x.strip() for x in inside.split(",")]
+ current_surface = extract_surface(t[0])
+
+ elif "COL_TRI(" in line:
+ inside = line[line.find("(") + 1:line.rfind(")")]
+ t = [x.strip() for x in inside.split(",")]
+ tris.append((int(t[0]), int(t[1]), int(t[2]), current_surface))
+
+ return verts, tris
+
+
+def parse_script(raw):
+ current_area = None
+ area_terrain = {}
+
+ for line in raw:
+ line = line.strip()
+
+ m_area = re.search(r"AREA\s*\(\s*(\d+)", line)
+ if m_area:
+ current_area = int(m_area.group(1))
+
+ m_terrain = re.search(r"TERRAIN_TYPE\s*\(\s*([A-Z_0-9]+)\s*\)", line)
+ if m_terrain and current_area is not None:
+ area_terrain[current_area] = m_terrain.group(1)
+
+ return area_terrain
+
+
+def main():
+ print("Downloading collision...")
+ collision_raw = urllib.request.urlopen(COLLISION_URL).read().decode("utf8").splitlines()
+
+ print("Downloading script...")
+ script_raw = urllib.request.urlopen(SCRIPT_URL).read().decode("utf8").splitlines()
+
+ verts, tris = parse_collision(collision_raw)
+ area_terrain = parse_script(script_raw)
+
+ current_terrain = area_terrain.get(1, "TERRAIN_GRASS")
out_lines = []
for tri in tris:
- out_lines.append("{%s,0,TERRAIN_SNOW,0,{{%s,%s,%s},{%s,%s,%s},{%s,%s,%s}}}" % (tri[3], \
- verts[tri[0]][0], verts[tri[0]][1], verts[tri[0]][2], \
- verts[tri[1]][0], verts[tri[1]][1], verts[tri[1]][2], \
- verts[tri[2]][0], verts[tri[2]][1], verts[tri[2]][2]))
+ v1 = verts[tri[0]]
+ v2 = verts[tri[1]]
+ v3 = verts[tri[2]]
+ surf = tri[3]
+
+ out_lines.append(
+ "{%s,0,%s,0,{{%d,%d,%d},{%d,%d,%d},{%d,%d,%d}}}" % (
+ surf,
+ current_terrain,
+ v1[0], v1[1], v1[2],
+ v2[0], v2[1], v2[2],
+ v3[0], v3[1], v3[2],
+ )
+ )
out_str = ",\n".join(out_lines)
- out_str = "const struct SM64Surface surfaces[] = {\n" + out_str + "};\n\n"
- out_str += "const size_t surfaces_count = sizeof( surfaces ) / sizeof( surfaces[0] );"
+
+ out_str = "const struct SM64Surface surfaces[] = {\n" + out_str + "\n};\n\n"
+ out_str += "const size_t surfaces_count = sizeof(surfaces) / sizeof(surfaces[0]);\n"
out_str = '#include "../src/decomp/include/surface_terrains.h"\n' + out_str
out_str = '#include "level.h"\n' + out_str
- with open("test/level.c", "w") as file:
- file.write(out_str)
+ with open("test/level.c", "w") as f:
+ f.write(out_str)
- with open("test/level.h", "w") as file:
- file.write(LEVEL_H)
+ with open("test/level.h", "w") as f:
+ f.write(LEVEL_H)
if __name__ == "__main__":
diff --git a/src/libsm64.c b/src/libsm64.c
index 006cfa0..538e5fd 100644
--- a/src/libsm64.c
+++ b/src/libsm64.c
@@ -720,6 +720,26 @@ SM64_LIB_FN void sm64_stop_background_music(uint16_t seqId)
stop_background_music(seqId);
}
+extern SM64_LIB_FN void sm64_play_cap_music(uint16_t playMusic)
+{
+ play_cap_music(playMusic);
+}
+
+SM64_LIB_FN void sm64_stop_cap_music()
+{
+ stop_cap_music();
+}
+
+extern SM64_LIB_FN void sm64_play_shell_music()
+{
+ play_shell_music();
+}
+
+SM64_LIB_FN void sm64_stop_shell_music()
+{
+ stop_shell_music();
+}
+
SM64_LIB_FN void sm64_fadeout_background_music(uint16_t arg0, uint16_t fadeOut)
{
fadeout_background_music(arg0, fadeOut);
diff --git a/src/libsm64.h b/src/libsm64.h
index 9cf4446..1f2c940 100644
--- a/src/libsm64.h
+++ b/src/libsm64.h
@@ -245,6 +245,14 @@ extern SM64_LIB_FN void sm64_play_music(uint8_t player, uint16_t seqArgs, uint16
extern SM64_LIB_FN void sm64_stop_background_music(uint16_t seqId);
+extern SM64_LIB_FN void sm64_play_cap_music(uint16_t playMusic);
+
+extern SM64_LIB_FN void sm64_stop_cap_music();
+
+extern SM64_LIB_FN void sm64_play_shell_music();
+
+extern SM64_LIB_FN void sm64_stop_shell_music();
+
extern SM64_LIB_FN void sm64_fadeout_background_music(uint16_t arg0, uint16_t fadeOut);
extern SM64_LIB_FN uint16_t sm64_get_current_background_music();
diff --git a/test/context.c b/test/context.cpp
similarity index 81%
rename from test/context.c
rename to test/context.cpp
index f0ce831..df09bc3 100644
--- a/test/context.c
+++ b/test/context.cpp
@@ -1,6 +1,7 @@
#include "context.h"
-
#include
+#include "imgui/imgui.h"
+#include "imgui/backends/imgui_impl_sdl2.h"
static SDL_Window *s_sdlWindow;
static SDL_GLContext s_sdlGlContext;
@@ -10,50 +11,47 @@ int WINDOW_HEIGHT;
void context_init(const char *title, int width, int height, int major, int minor)
{
+ int profile;
+ #ifndef __APPLE__
+ GLenum glewInitResult;
+ #endif
+ int i;
+
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) goto err;
- int profile = major < 3 ? SDL_GL_CONTEXT_PROFILE_COMPATIBILITY : SDL_GL_CONTEXT_PROFILE_CORE;
-
+ profile = major < 3 ? SDL_GL_CONTEXT_PROFILE_COMPATIBILITY : SDL_GL_CONTEXT_PROFILE_CORE;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile);
-
WINDOW_WIDTH = width;
WINDOW_HEIGHT = height;
-
s_sdlWindow = SDL_CreateWindow(
title,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
width, height,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
);
-
if (!s_sdlWindow) goto err;
-
s_sdlGlContext = SDL_GL_CreateContext(s_sdlWindow);
SDL_GL_SetSwapInterval(1);
-
if (!s_sdlGlContext) goto err;
-
#ifndef __APPLE__
glewExperimental = GL_TRUE;
- const GLenum glewInitResult = glewInit();
+ glewInitResult = glewInit();
if (glewInitResult != GLEW_OK) goto err;
#endif
-
s_controller = NULL;
-
- for (int i = 0; i < SDL_NumJoysticks(); ++i)
+ for (i = 0; i < SDL_NumJoysticks(); ++i)
{
if (!SDL_IsGameController(i)) continue;
s_controller = SDL_GameControllerOpen(i);
printf("Using game controller: %s", SDL_GameControllerName(s_controller));
if (s_controller) break;
}
-
return;
-err: SDL_GL_DeleteContext(s_sdlGlContext);
+err:
+ SDL_GL_DeleteContext(s_sdlGlContext);
SDL_DestroyWindow(s_sdlWindow);
SDL_Quit();
}
@@ -63,26 +61,32 @@ SDL_GameController *context_get_controller(void)
return s_controller;
}
+SDL_Window *context_get_window(void)
+{
+ return s_sdlWindow;
+}
+
+SDL_GLContext context_get_gl_context(void)
+{
+ return s_sdlGlContext;
+}
+
bool context_flip_frame_poll_events(void)
{
bool still_running = true;
-
SDL_GL_SwapWindow(s_sdlWindow);
-
SDL_Event event;
-
while (SDL_PollEvent(&event))
{
+ ImGui_ImplSDL2_ProcessEvent(&event);
switch (event.type)
{
case SDL_QUIT:
still_running = false;
break;
-
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_ESCAPE)
still_running = false;
-
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
@@ -93,7 +97,6 @@ bool context_flip_frame_poll_events(void)
break;
}
}
-
return still_running;
}
@@ -101,13 +104,10 @@ void context_terminate(void)
{
if (!s_sdlWindow)
return;
-
if (s_controller)
SDL_GameControllerClose(s_controller);
-
SDL_GL_DeleteContext(s_sdlGlContext);
SDL_DestroyWindow(s_sdlWindow);
SDL_Quit();
-
s_sdlWindow = NULL;
-}
+}
\ No newline at end of file
diff --git a/test/context.h b/test/context.h
index 5eb281c..c0e970e 100644
--- a/test/context.h
+++ b/test/context.h
@@ -1,7 +1,5 @@
#pragma once
-
#include
-
#ifdef __APPLE__
# include
# include
@@ -17,10 +15,17 @@
extern int WINDOW_WIDTH;
extern int WINDOW_HEIGHT;
-extern void context_init(const char *title, int width, int height, int major, int minor);
+#ifdef __cplusplus
+extern "C" {
+ #endif
-extern bool context_flip_frame_poll_events(void);
+ extern void context_init(const char *title, int width, int height, int major, int minor);
+ extern bool context_flip_frame_poll_events(void);
+ extern SDL_GameController *context_get_controller(void);
+ extern SDL_Window *context_get_window(void);
+ extern SDL_GLContext context_get_gl_context(void);
+ extern void context_terminate(void);
-extern SDL_GameController *context_get_controller(void);
-
-extern void context_terminate(void);
\ No newline at end of file
+ #ifdef __cplusplus
+}
+#endif
\ No newline at end of file
diff --git a/test/main.cpp b/test/main.cpp
index 5ac0050..09ac1e8 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -21,7 +21,671 @@ extern "C"
#include "gl20/gl20_renderer.h"
}
+#include "imgui/imgui.h"
+#include "imgui/backends/imgui_impl_sdl2.h"
+#include "imgui/backends/imgui_impl_opengl3.h"
+
#include "audio.h"
+#include "sm64.h"
+
+
+// Add this include near the top, after libsm64.h
+// AnimInfo is defined in the decomp headers, not the public API
+#include "../src/decomp/include/types.h" // or wherever AnimInfo is fully defined in your tree
+
+// -------------------------------------------------------
+// Named struct so it can be used as a parameter type
+struct FlagEntry
+{
+ uint32_t bit;
+ const char *name;
+};
+
+static const FlagEntry sMarioFlags[] = {
+ {MARIO_NORMAL_CAP, "MARIO_NORMAL_CAP"},
+ {MARIO_VANISH_CAP, "MARIO_VANISH_CAP"},
+ {MARIO_METAL_CAP, "MARIO_METAL_CAP"},
+ {MARIO_WING_CAP, "MARIO_WING_CAP"},
+ {MARIO_CAP_ON_HEAD, "MARIO_CAP_ON_HEAD"},
+ {MARIO_CAP_IN_HAND, "MARIO_CAP_IN_HAND"},
+ {MARIO_METAL_SHOCK, "MARIO_METAL_SHOCK"},
+ {MARIO_TELEPORTING, "MARIO_TELEPORTING"},
+ {MARIO_UNKNOWN_08, "MARIO_UNKNOWN_08"},
+ {MARIO_UNKNOWN_13, "MARIO_UNKNOWN_13"},
+ {MARIO_ACTION_SOUND_PLAYED, "MARIO_ACTION_SOUND_PLAYED"},
+ {MARIO_MARIO_SOUND_PLAYED, "MARIO_MARIO_SOUND_PLAYED"},
+ {MARIO_UNKNOWN_18, "MARIO_UNKNOWN_18"},
+ {MARIO_PUNCHING, "MARIO_PUNCHING"},
+ {MARIO_KICKING, "MARIO_KICKING"},
+ {MARIO_TRIPPING, "MARIO_TRIPPING"},
+ {MARIO_UNKNOWN_25, "MARIO_UNKNOWN_25"},
+ {MARIO_UNKNOWN_30, "MARIO_UNKNOWN_30"},
+ {MARIO_UNKNOWN_31, "MARIO_UNKNOWN_31"},
+};
+
+static const FlagEntry sParticleFlags[] = {
+ {PARTICLE_DUST, "PARTICLE_DUST"},
+ {PARTICLE_VERTICAL_STAR, "PARTICLE_VERTICAL_STAR"},
+ {PARTICLE_2, "PARTICLE_2"},
+ {PARTICLE_SPARKLES, "PARTICLE_SPARKLES"},
+ {PARTICLE_HORIZONTAL_STAR, "PARTICLE_HORIZONTAL_STAR"},
+ {PARTICLE_BUBBLE, "PARTICLE_BUBBLE"},
+ {PARTICLE_WATER_SPLASH, "PARTICLE_WATER_SPLASH"},
+ {PARTICLE_IDLE_WATER_WAVE, "PARTICLE_IDLE_WATER_WAVE"},
+ {PARTICLE_SHALLOW_WATER_WAVE, "PARTICLE_SHALLOW_WATER_WAVE"},
+ {PARTICLE_PLUNGE_BUBBLE, "PARTICLE_PLUNGE_BUBBLE"},
+ {PARTICLE_WAVE_TRAIL, "PARTICLE_WAVE_TRAIL"},
+ {PARTICLE_FIRE, "PARTICLE_FIRE"},
+ {PARTICLE_SHALLOW_WATER_SPLASH, "PARTICLE_SHALLOW_WATER_SPLASH"},
+ {PARTICLE_LEAF, "PARTICLE_LEAF"},
+ {PARTICLE_SNOW, "PARTICLE_SNOW"},
+ {PARTICLE_DIRT, "PARTICLE_DIRT"},
+ {PARTICLE_MIST_CIRCLE, "PARTICLE_MIST_CIRCLE"},
+ {PARTICLE_BREATH, "PARTICLE_BREATH"},
+ {PARTICLE_TRIANGLE, "PARTICLE_TRIANGLE"},
+ {PARTICLE_19, "PARTICLE_19"},
+};
+
+static const char *GetActionName(uint32_t action)
+{
+ switch (action)
+ {
+ case ACT_UNINITIALIZED:
+ return "ACT_UNINITIALIZED";
+ // stationary
+ case ACT_IDLE:
+ return "ACT_IDLE";
+ case ACT_START_SLEEPING:
+ return "ACT_START_SLEEPING";
+ case ACT_SLEEPING:
+ return "ACT_SLEEPING";
+ case ACT_WAKING_UP:
+ return "ACT_WAKING_UP";
+ case ACT_PANTING:
+ return "ACT_PANTING";
+ case ACT_HOLD_PANTING_UNUSED:
+ return "ACT_HOLD_PANTING_UNUSED";
+ case ACT_HOLD_IDLE:
+ return "ACT_HOLD_IDLE";
+ case ACT_HOLD_HEAVY_IDLE:
+ return "ACT_HOLD_HEAVY_IDLE";
+ case ACT_STANDING_AGAINST_WALL:
+ return "ACT_STANDING_AGAINST_WALL";
+ case ACT_COUGHING:
+ return "ACT_COUGHING";
+ case ACT_SHIVERING:
+ return "ACT_SHIVERING";
+ case ACT_IN_QUICKSAND:
+ return "ACT_IN_QUICKSAND";
+ case ACT_UNKNOWN_0002020E:
+ return "ACT_UNKNOWN_0002020E";
+ case ACT_CROUCHING:
+ return "ACT_CROUCHING";
+ case ACT_START_CROUCHING:
+ return "ACT_START_CROUCHING";
+ case ACT_STOP_CROUCHING:
+ return "ACT_STOP_CROUCHING";
+ case ACT_START_CRAWLING:
+ return "ACT_START_CRAWLING";
+ case ACT_STOP_CRAWLING:
+ return "ACT_STOP_CRAWLING";
+ case ACT_SLIDE_KICK_SLIDE_STOP:
+ return "ACT_SLIDE_KICK_SLIDE_STOP";
+ case ACT_SHOCKWAVE_BOUNCE:
+ return "ACT_SHOCKWAVE_BOUNCE";
+ case ACT_FIRST_PERSON:
+ return "ACT_FIRST_PERSON";
+ case ACT_BACKFLIP_LAND_STOP:
+ return "ACT_BACKFLIP_LAND_STOP";
+ case ACT_JUMP_LAND_STOP:
+ return "ACT_JUMP_LAND_STOP";
+ case ACT_DOUBLE_JUMP_LAND_STOP:
+ return "ACT_DOUBLE_JUMP_LAND_STOP";
+ case ACT_FREEFALL_LAND_STOP:
+ return "ACT_FREEFALL_LAND_STOP";
+ case ACT_SIDE_FLIP_LAND_STOP:
+ return "ACT_SIDE_FLIP_LAND_STOP";
+ case ACT_HOLD_JUMP_LAND_STOP:
+ return "ACT_HOLD_JUMP_LAND_STOP";
+ case ACT_HOLD_FREEFALL_LAND_STOP:
+ return "ACT_HOLD_FREEFALL_LAND_STOP";
+ case ACT_AIR_THROW_LAND:
+ return "ACT_AIR_THROW_LAND";
+ case ACT_TWIRL_LAND:
+ return "ACT_TWIRL_LAND";
+ case ACT_LAVA_BOOST_LAND:
+ return "ACT_LAVA_BOOST_LAND";
+ case ACT_TRIPLE_JUMP_LAND_STOP:
+ return "ACT_TRIPLE_JUMP_LAND_STOP";
+ case ACT_LONG_JUMP_LAND_STOP:
+ return "ACT_LONG_JUMP_LAND_STOP";
+ case ACT_GROUND_POUND_LAND:
+ return "ACT_GROUND_POUND_LAND";
+ case ACT_BRAKING_STOP:
+ return "ACT_BRAKING_STOP";
+ case ACT_BUTT_SLIDE_STOP:
+ return "ACT_BUTT_SLIDE_STOP";
+ case ACT_HOLD_BUTT_SLIDE_STOP:
+ return "ACT_HOLD_BUTT_SLIDE_STOP";
+ // moving
+ case ACT_WALKING:
+ return "ACT_WALKING";
+ case ACT_HOLD_WALKING:
+ return "ACT_HOLD_WALKING";
+ case ACT_TURNING_AROUND:
+ return "ACT_TURNING_AROUND";
+ case ACT_FINISH_TURNING_AROUND:
+ return "ACT_FINISH_TURNING_AROUND";
+ case ACT_BRAKING:
+ return "ACT_BRAKING";
+ case ACT_RIDING_SHELL_GROUND:
+ return "ACT_RIDING_SHELL_GROUND";
+ case ACT_HOLD_HEAVY_WALKING:
+ return "ACT_HOLD_HEAVY_WALKING";
+ case ACT_CRAWLING:
+ return "ACT_CRAWLING";
+ case ACT_BURNING_GROUND:
+ return "ACT_BURNING_GROUND";
+ case ACT_DECELERATING:
+ return "ACT_DECELERATING";
+ case ACT_HOLD_DECELERATING:
+ return "ACT_HOLD_DECELERATING";
+ case ACT_BEGIN_SLIDING:
+ return "ACT_BEGIN_SLIDING";
+ case ACT_HOLD_BEGIN_SLIDING:
+ return "ACT_HOLD_BEGIN_SLIDING";
+ case ACT_BUTT_SLIDE:
+ return "ACT_BUTT_SLIDE";
+ case ACT_STOMACH_SLIDE:
+ return "ACT_STOMACH_SLIDE";
+ case ACT_HOLD_BUTT_SLIDE:
+ return "ACT_HOLD_BUTT_SLIDE";
+ case ACT_HOLD_STOMACH_SLIDE:
+ return "ACT_HOLD_STOMACH_SLIDE";
+ case ACT_DIVE_SLIDE:
+ return "ACT_DIVE_SLIDE";
+ case ACT_MOVE_PUNCHING:
+ return "ACT_MOVE_PUNCHING";
+ case ACT_CROUCH_SLIDE:
+ return "ACT_CROUCH_SLIDE";
+ case ACT_SLIDE_KICK_SLIDE:
+ return "ACT_SLIDE_KICK_SLIDE";
+ case ACT_HARD_BACKWARD_GROUND_KB:
+ return "ACT_HARD_BACKWARD_GROUND_KB";
+ case ACT_HARD_FORWARD_GROUND_KB:
+ return "ACT_HARD_FORWARD_GROUND_KB";
+ case ACT_BACKWARD_GROUND_KB:
+ return "ACT_BACKWARD_GROUND_KB";
+ case ACT_FORWARD_GROUND_KB:
+ return "ACT_FORWARD_GROUND_KB";
+ case ACT_SOFT_BACKWARD_GROUND_KB:
+ return "ACT_SOFT_BACKWARD_GROUND_KB";
+ case ACT_SOFT_FORWARD_GROUND_KB:
+ return "ACT_SOFT_FORWARD_GROUND_KB";
+ case ACT_GROUND_BONK:
+ return "ACT_GROUND_BONK";
+ case ACT_DEATH_EXIT_LAND:
+ return "ACT_DEATH_EXIT_LAND";
+ case ACT_JUMP_LAND:
+ return "ACT_JUMP_LAND";
+ case ACT_FREEFALL_LAND:
+ return "ACT_FREEFALL_LAND";
+ case ACT_DOUBLE_JUMP_LAND:
+ return "ACT_DOUBLE_JUMP_LAND";
+ case ACT_SIDE_FLIP_LAND:
+ return "ACT_SIDE_FLIP_LAND";
+ case ACT_HOLD_JUMP_LAND:
+ return "ACT_HOLD_JUMP_LAND";
+ case ACT_HOLD_FREEFALL_LAND:
+ return "ACT_HOLD_FREEFALL_LAND";
+ case ACT_QUICKSAND_JUMP_LAND:
+ return "ACT_QUICKSAND_JUMP_LAND";
+ case ACT_HOLD_QUICKSAND_JUMP_LAND:
+ return "ACT_HOLD_QUICKSAND_JUMP_LAND";
+ case ACT_TRIPLE_JUMP_LAND:
+ return "ACT_TRIPLE_JUMP_LAND";
+ case ACT_LONG_JUMP_LAND:
+ return "ACT_LONG_JUMP_LAND";
+ case ACT_BACKFLIP_LAND:
+ return "ACT_BACKFLIP_LAND";
+ // airborne
+ case ACT_JUMP:
+ return "ACT_JUMP";
+ case ACT_DOUBLE_JUMP:
+ return "ACT_DOUBLE_JUMP";
+ case ACT_TRIPLE_JUMP:
+ return "ACT_TRIPLE_JUMP";
+ case ACT_BACKFLIP:
+ return "ACT_BACKFLIP";
+ case ACT_STEEP_JUMP:
+ return "ACT_STEEP_JUMP";
+ case ACT_WALL_KICK_AIR:
+ return "ACT_WALL_KICK_AIR";
+ case ACT_SIDE_FLIP:
+ return "ACT_SIDE_FLIP";
+ case ACT_LONG_JUMP:
+ return "ACT_LONG_JUMP";
+ case ACT_WATER_JUMP:
+ return "ACT_WATER_JUMP";
+ case ACT_DIVE:
+ return "ACT_DIVE";
+ case ACT_FREEFALL:
+ return "ACT_FREEFALL";
+ case ACT_TOP_OF_POLE_JUMP:
+ return "ACT_TOP_OF_POLE_JUMP";
+ case ACT_BUTT_SLIDE_AIR:
+ return "ACT_BUTT_SLIDE_AIR";
+ case ACT_FLYING_TRIPLE_JUMP:
+ return "ACT_FLYING_TRIPLE_JUMP";
+ case ACT_SHOT_FROM_CANNON:
+ return "ACT_SHOT_FROM_CANNON";
+ case ACT_FLYING:
+ return "ACT_FLYING";
+ case ACT_RIDING_SHELL_JUMP:
+ return "ACT_RIDING_SHELL_JUMP";
+ case ACT_RIDING_SHELL_FALL:
+ return "ACT_RIDING_SHELL_FALL";
+ case ACT_VERTICAL_WIND:
+ return "ACT_VERTICAL_WIND";
+ case ACT_HOLD_JUMP:
+ return "ACT_HOLD_JUMP";
+ case ACT_HOLD_FREEFALL:
+ return "ACT_HOLD_FREEFALL";
+ case ACT_HOLD_BUTT_SLIDE_AIR:
+ return "ACT_HOLD_BUTT_SLIDE_AIR";
+ case ACT_HOLD_WATER_JUMP:
+ return "ACT_HOLD_WATER_JUMP";
+ case ACT_TWIRLING:
+ return "ACT_TWIRLING";
+ case ACT_FORWARD_ROLLOUT:
+ return "ACT_FORWARD_ROLLOUT";
+ case ACT_AIR_HIT_WALL:
+ return "ACT_AIR_HIT_WALL";
+ case ACT_RIDING_HOOT:
+ return "ACT_RIDING_HOOT";
+ case ACT_GROUND_POUND:
+ return "ACT_GROUND_POUND";
+ case ACT_SLIDE_KICK:
+ return "ACT_SLIDE_KICK";
+ case ACT_AIR_THROW:
+ return "ACT_AIR_THROW";
+ case ACT_JUMP_KICK:
+ return "ACT_JUMP_KICK";
+ case ACT_BACKWARD_ROLLOUT:
+ return "ACT_BACKWARD_ROLLOUT";
+ case ACT_CRAZY_BOX_BOUNCE:
+ return "ACT_CRAZY_BOX_BOUNCE";
+ case ACT_SPECIAL_TRIPLE_JUMP:
+ return "ACT_SPECIAL_TRIPLE_JUMP";
+ case ACT_BACKWARD_AIR_KB:
+ return "ACT_BACKWARD_AIR_KB";
+ case ACT_FORWARD_AIR_KB:
+ return "ACT_FORWARD_AIR_KB";
+ case ACT_HARD_FORWARD_AIR_KB:
+ return "ACT_HARD_FORWARD_AIR_KB";
+ case ACT_HARD_BACKWARD_AIR_KB:
+ return "ACT_HARD_BACKWARD_AIR_KB";
+ case ACT_BURNING_JUMP:
+ return "ACT_BURNING_JUMP";
+ case ACT_BURNING_FALL:
+ return "ACT_BURNING_FALL";
+ case ACT_SOFT_BONK:
+ return "ACT_SOFT_BONK";
+ case ACT_LAVA_BOOST:
+ return "ACT_LAVA_BOOST";
+ case ACT_GETTING_BLOWN:
+ return "ACT_GETTING_BLOWN";
+ case ACT_THROWN_FORWARD:
+ return "ACT_THROWN_FORWARD";
+ case ACT_THROWN_BACKWARD:
+ return "ACT_THROWN_BACKWARD";
+ // submerged
+ case ACT_WATER_IDLE:
+ return "ACT_WATER_IDLE";
+ case ACT_HOLD_WATER_IDLE:
+ return "ACT_HOLD_WATER_IDLE";
+ case ACT_WATER_ACTION_END:
+ return "ACT_WATER_ACTION_END";
+ case ACT_HOLD_WATER_ACTION_END:
+ return "ACT_HOLD_WATER_ACTION_END";
+ case ACT_DROWNING:
+ return "ACT_DROWNING";
+ case ACT_BACKWARD_WATER_KB:
+ return "ACT_BACKWARD_WATER_KB";
+ case ACT_FORWARD_WATER_KB:
+ return "ACT_FORWARD_WATER_KB";
+ case ACT_WATER_DEATH:
+ return "ACT_WATER_DEATH";
+ case ACT_WATER_SHOCKED:
+ return "ACT_WATER_SHOCKED";
+ case ACT_BREASTSTROKE:
+ return "ACT_BREASTSTROKE";
+ case ACT_SWIMMING_END:
+ return "ACT_SWIMMING_END";
+ case ACT_FLUTTER_KICK:
+ return "ACT_FLUTTER_KICK";
+ case ACT_HOLD_BREASTSTROKE:
+ return "ACT_HOLD_BREASTSTROKE";
+ case ACT_HOLD_SWIMMING_END:
+ return "ACT_HOLD_SWIMMING_END";
+ case ACT_HOLD_FLUTTER_KICK:
+ return "ACT_HOLD_FLUTTER_KICK";
+ case ACT_WATER_SHELL_SWIMMING:
+ return "ACT_WATER_SHELL_SWIMMING";
+ case ACT_WATER_THROW:
+ return "ACT_WATER_THROW";
+ case ACT_WATER_PUNCH:
+ return "ACT_WATER_PUNCH";
+ case ACT_WATER_PLUNGE:
+ return "ACT_WATER_PLUNGE";
+ case ACT_CAUGHT_IN_WHIRLPOOL:
+ return "ACT_CAUGHT_IN_WHIRLPOOL";
+ case ACT_METAL_WATER_STANDING:
+ return "ACT_METAL_WATER_STANDING";
+ case ACT_HOLD_METAL_WATER_STANDING:
+ return "ACT_HOLD_METAL_WATER_STANDING";
+ case ACT_METAL_WATER_WALKING:
+ return "ACT_METAL_WATER_WALKING";
+ case ACT_HOLD_METAL_WATER_WALKING:
+ return "ACT_HOLD_METAL_WATER_WALKING";
+ case ACT_METAL_WATER_FALLING:
+ return "ACT_METAL_WATER_FALLING";
+ case ACT_HOLD_METAL_WATER_FALLING:
+ return "ACT_HOLD_METAL_WATER_FALLING";
+ case ACT_METAL_WATER_FALL_LAND:
+ return "ACT_METAL_WATER_FALL_LAND";
+ case ACT_HOLD_METAL_WATER_FALL_LAND:
+ return "ACT_HOLD_METAL_WATER_FALL_LAND";
+ case ACT_METAL_WATER_JUMP:
+ return "ACT_METAL_WATER_JUMP";
+ case ACT_HOLD_METAL_WATER_JUMP:
+ return "ACT_HOLD_METAL_WATER_JUMP";
+ case ACT_METAL_WATER_JUMP_LAND:
+ return "ACT_METAL_WATER_JUMP_LAND";
+ case ACT_HOLD_METAL_WATER_JUMP_LAND:
+ return "ACT_HOLD_METAL_WATER_JUMP_LAND";
+ // cutscene
+ case ACT_DISAPPEARED:
+ return "ACT_DISAPPEARED";
+ case ACT_INTRO_CUTSCENE:
+ return "ACT_INTRO_CUTSCENE";
+ case ACT_STAR_DANCE_EXIT:
+ return "ACT_STAR_DANCE_EXIT";
+ case ACT_STAR_DANCE_WATER:
+ return "ACT_STAR_DANCE_WATER";
+ case ACT_FALL_AFTER_STAR_GRAB:
+ return "ACT_FALL_AFTER_STAR_GRAB";
+ case ACT_READING_AUTOMATIC_DIALOG:
+ return "ACT_READING_AUTOMATIC_DIALOG";
+ case ACT_READING_NPC_DIALOG:
+ return "ACT_READING_NPC_DIALOG";
+ case ACT_STAR_DANCE_NO_EXIT:
+ return "ACT_STAR_DANCE_NO_EXIT";
+ case ACT_READING_SIGN:
+ return "ACT_READING_SIGN";
+ case ACT_JUMBO_STAR_CUTSCENE:
+ return "ACT_JUMBO_STAR_CUTSCENE";
+ case ACT_WAITING_FOR_DIALOG:
+ return "ACT_WAITING_FOR_DIALOG";
+ case ACT_DEBUG_FREE_MOVE:
+ return "ACT_DEBUG_FREE_MOVE";
+ case ACT_STANDING_DEATH:
+ return "ACT_STANDING_DEATH";
+ case ACT_QUICKSAND_DEATH:
+ return "ACT_QUICKSAND_DEATH";
+ case ACT_ELECTROCUTION:
+ return "ACT_ELECTROCUTION";
+ case ACT_SUFFOCATION:
+ return "ACT_SUFFOCATION";
+ case ACT_DEATH_ON_STOMACH:
+ return "ACT_DEATH_ON_STOMACH";
+ case ACT_DEATH_ON_BACK:
+ return "ACT_DEATH_ON_BACK";
+ case ACT_EATEN_BY_BUBBA:
+ return "ACT_EATEN_BY_BUBBA";
+ case ACT_END_PEACH_CUTSCENE:
+ return "ACT_END_PEACH_CUTSCENE";
+ case ACT_CREDITS_CUTSCENE:
+ return "ACT_CREDITS_CUTSCENE";
+ case ACT_END_WAVING_CUTSCENE:
+ return "ACT_END_WAVING_CUTSCENE";
+ case ACT_PULLING_DOOR:
+ return "ACT_PULLING_DOOR";
+ case ACT_PUSHING_DOOR:
+ return "ACT_PUSHING_DOOR";
+ case ACT_WARP_DOOR_SPAWN:
+ return "ACT_WARP_DOOR_SPAWN";
+ case ACT_EMERGE_FROM_PIPE:
+ return "ACT_EMERGE_FROM_PIPE";
+ case ACT_SPAWN_SPIN_AIRBORNE:
+ return "ACT_SPAWN_SPIN_AIRBORNE";
+ case ACT_SPAWN_SPIN_LANDING:
+ return "ACT_SPAWN_SPIN_LANDING";
+ case ACT_EXIT_AIRBORNE:
+ return "ACT_EXIT_AIRBORNE";
+ case ACT_EXIT_LAND_SAVE_DIALOG:
+ return "ACT_EXIT_LAND_SAVE_DIALOG";
+ case ACT_DEATH_EXIT:
+ return "ACT_DEATH_EXIT";
+ case ACT_UNUSED_DEATH_EXIT:
+ return "ACT_UNUSED_DEATH_EXIT";
+ case ACT_FALLING_DEATH_EXIT:
+ return "ACT_FALLING_DEATH_EXIT";
+ case ACT_SPECIAL_EXIT_AIRBORNE:
+ return "ACT_SPECIAL_EXIT_AIRBORNE";
+ case ACT_SPECIAL_DEATH_EXIT:
+ return "ACT_SPECIAL_DEATH_EXIT";
+ case ACT_FALLING_EXIT_AIRBORNE:
+ return "ACT_FALLING_EXIT_AIRBORNE";
+ case ACT_UNLOCKING_KEY_DOOR:
+ return "ACT_UNLOCKING_KEY_DOOR";
+ case ACT_UNLOCKING_STAR_DOOR:
+ return "ACT_UNLOCKING_STAR_DOOR";
+ case ACT_ENTERING_STAR_DOOR:
+ return "ACT_ENTERING_STAR_DOOR";
+ case ACT_SPAWN_NO_SPIN_AIRBORNE:
+ return "ACT_SPAWN_NO_SPIN_AIRBORNE";
+ case ACT_SPAWN_NO_SPIN_LANDING:
+ return "ACT_SPAWN_NO_SPIN_LANDING";
+ case ACT_BBH_ENTER_JUMP:
+ return "ACT_BBH_ENTER_JUMP";
+ case ACT_BBH_ENTER_SPIN:
+ return "ACT_BBH_ENTER_SPIN";
+ case ACT_TELEPORT_FADE_OUT:
+ return "ACT_TELEPORT_FADE_OUT";
+ case ACT_TELEPORT_FADE_IN:
+ return "ACT_TELEPORT_FADE_IN";
+ case ACT_SHOCKED:
+ return "ACT_SHOCKED";
+ case ACT_SQUISHED:
+ return "ACT_SQUISHED";
+ case ACT_HEAD_STUCK_IN_GROUND:
+ return "ACT_HEAD_STUCK_IN_GROUND";
+ case ACT_BUTT_STUCK_IN_GROUND:
+ return "ACT_BUTT_STUCK_IN_GROUND";
+ case ACT_FEET_STUCK_IN_GROUND:
+ return "ACT_FEET_STUCK_IN_GROUND";
+ case ACT_PUTTING_ON_CAP:
+ return "ACT_PUTTING_ON_CAP";
+ // automatic
+ case ACT_HOLDING_POLE:
+ return "ACT_HOLDING_POLE";
+ case ACT_GRAB_POLE_SLOW:
+ return "ACT_GRAB_POLE_SLOW";
+ case ACT_GRAB_POLE_FAST:
+ return "ACT_GRAB_POLE_FAST";
+ case ACT_CLIMBING_POLE:
+ return "ACT_CLIMBING_POLE";
+ case ACT_TOP_OF_POLE_TRANSITION:
+ return "ACT_TOP_OF_POLE_TRANSITION";
+ case ACT_TOP_OF_POLE:
+ return "ACT_TOP_OF_POLE";
+ case ACT_START_HANGING:
+ return "ACT_START_HANGING";
+ case ACT_HANGING:
+ return "ACT_HANGING";
+ case ACT_HANG_MOVING:
+ return "ACT_HANG_MOVING";
+ case ACT_LEDGE_GRAB:
+ return "ACT_LEDGE_GRAB";
+ case ACT_LEDGE_CLIMB_SLOW_1:
+ return "ACT_LEDGE_CLIMB_SLOW_1";
+ case ACT_LEDGE_CLIMB_SLOW_2:
+ return "ACT_LEDGE_CLIMB_SLOW_2";
+ case ACT_LEDGE_CLIMB_DOWN:
+ return "ACT_LEDGE_CLIMB_DOWN";
+ case ACT_LEDGE_CLIMB_FAST:
+ return "ACT_LEDGE_CLIMB_FAST";
+ case ACT_GRABBED:
+ return "ACT_GRABBED";
+ case ACT_IN_CANNON:
+ return "ACT_IN_CANNON";
+ case ACT_TORNADO_TWIRLING:
+ return "ACT_TORNADO_TWIRLING";
+ // object
+ case ACT_PUNCHING:
+ return "ACT_PUNCHING";
+ case ACT_PICKING_UP:
+ return "ACT_PICKING_UP";
+ case ACT_DIVE_PICKING_UP:
+ return "ACT_DIVE_PICKING_UP";
+ case ACT_STOMACH_SLIDE_STOP:
+ return "ACT_STOMACH_SLIDE_STOP";
+ case ACT_PLACING_DOWN:
+ return "ACT_PLACING_DOWN";
+ case ACT_THROWING:
+ return "ACT_THROWING";
+ case ACT_HEAVY_THROW:
+ return "ACT_HEAVY_THROW";
+ case ACT_PICKING_UP_BOWSER:
+ return "ACT_PICKING_UP_BOWSER";
+ case ACT_HOLDING_BOWSER:
+ return "ACT_HOLDING_BOWSER";
+ case ACT_RELEASING_BOWSER:
+ return "ACT_RELEASING_BOWSER";
+ default:
+ return "ACT_UNKNOWN";
+ }
+}
+
+// -------------------------------------------------------
+// All helpers defined BEFORE DrawMarioState
+
+static void DrawBitFlags(
+ const char *label, uint32_t value,
+ const FlagEntry *table, int count)
+{
+ ImGui::Text("%s: 0x%08X", label, value);
+ ImGui::Indent();
+ for (int i = 0; i < count; i++)
+ {
+ bool set = (value & table[i].bit) != 0;
+ ImGui::TextColored(
+ set
+ ? ImVec4(0.2f, 1.0f, 0.4f, 1.0f)
+ : ImVec4(0.4f, 0.4f, 0.4f, 1.0f),
+ "[%c] %s", set ? 'X' : ' ', table[i].name);
+ }
+ ImGui::Unindent();
+}
+
+static void DrawAnimInfo(const AnimInfo *anim)
+{
+ if (!anim)
+ {
+ ImGui::TextDisabled("animInfo: (null)");
+ return;
+ }
+
+ if (ImGui::TreeNode("animInfo"))
+ {
+ ImGui::Text("animID: %d", anim->animID);
+ ImGui::Text("animYTrans: %d", anim->animYTrans);
+ ImGui::Text("curAnim: %p", (void *)anim->curAnim);
+ ImGui::Text("animFrame: %d", anim->animFrame);
+ ImGui::Text("animTimer: %u", anim->animTimer);
+ ImGui::Text("animFrameAccelAssist: %d", anim->animFrameAccelAssist);
+ ImGui::Text("animAccel: %d", anim->animAccel);
+ ImGui::TreePop();
+ }
+}
+
+static void DrawMarioState(const SM64MarioState *m)
+{
+ ImGui::Begin("Mario State");
+
+ if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ ImGui::Text("Position: (%.2f, %.2f, %.2f)", m->position[0], m->position[1], m->position[2]);
+ ImGui::Text("Velocity: (%.2f, %.2f, %.2f)", m->velocity[0], m->velocity[1], m->velocity[2]);
+ ImGui::Text("Face Angle: %.4f rad (%.1f deg)", m->faceAngle, m->faceAngle * (180.0f / 3.14159265f));
+ ImGui::Text("Fwd Velocity: %.2f", m->forwardVelocity);
+ }
+
+ if (ImGui::CollapsingHeader("Status", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ int hpSegs = (m->health & 0xFF00) >> 8;
+ ImGui::Text("Health: 0x%04X (HP segments: %d / 8)", (uint16_t)m->health, hpSegs);
+ ImGui::ProgressBar(hpSegs / 8.0f, ImVec2(-1, 0));
+ ImGui::Text("Invinc Timer: %d", m->invincTimer);
+ }
+
+ if (ImGui::CollapsingHeader("Action", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ ImGui::Text("0x%08X (%s)", m->action, GetActionName(m->action));
+ ImGui::Indent();
+ // group
+ switch (m->action & ACT_GROUP_MASK)
+ {
+ case ACT_GROUP_STATIONARY:
+ ImGui::TextDisabled("group: STATIONARY");
+ break;
+ case ACT_GROUP_MOVING:
+ ImGui::TextColored({0.2f, 1.0f, 0.4f, 1.0f}, "group: MOVING");
+ break;
+ case ACT_GROUP_AIRBORNE:
+ ImGui::TextColored({0.2f, 0.8f, 1.0f, 1.0f}, "group: AIRBORNE");
+ break;
+ case ACT_GROUP_SUBMERGED:
+ ImGui::TextColored({0.2f, 0.4f, 1.0f, 1.0f}, "group: SUBMERGED");
+ break;
+ case ACT_GROUP_CUTSCENE:
+ ImGui::TextColored({1.0f, 0.8f, 0.2f, 1.0f}, "group: CUTSCENE");
+ break;
+ case ACT_GROUP_AUTOMATIC:
+ ImGui::TextColored({0.8f, 0.4f, 1.0f, 1.0f}, "group: AUTOMATIC");
+ break;
+ case ACT_GROUP_OBJECT:
+ ImGui::TextColored({1.0f, 0.5f, 0.2f, 1.0f}, "group: OBJECT");
+ break;
+ }
+ // relevant flags
+ if (m->action & ACT_FLAG_AIR) ImGui::Text("[x] ACT_FLAG_AIR");
+ if (m->action & ACT_FLAG_SWIMMING) ImGui::Text("[x] ACT_FLAG_SWIMMING");
+ if (m->action & ACT_FLAG_ATTACKING) ImGui::Text("[x] ACT_FLAG_ATTACKING");
+ if (m->action & ACT_FLAG_INVULNERABLE) ImGui::Text("[x] ACT_FLAG_INVULNERABLE");
+ if (m->action & ACT_FLAG_INTANGIBLE) ImGui::Text("[x] ACT_FLAG_INTANGIBLE");
+ if (m->action & ACT_FLAG_RIDING_SHELL) ImGui::Text("[x] ACT_FLAG_RIDING_SHELL");
+ if (m->action & ACT_FLAG_ON_POLE) ImGui::Text("[x] ACT_FLAG_ON_POLE");
+ if (m->action & ACT_FLAG_HANGING) ImGui::Text("[x] ACT_FLAG_HANGING");
+ if (m->action & ACT_FLAG_DIVING) ImGui::Text("[x] ACT_FLAG_DIVING");
+ if (m->action & ACT_FLAG_SWIMMING_OR_FLYING)ImGui::Text("[x] ACT_FLAG_SWIMMING_OR_FLYING");
+ if (m->action & ACT_FLAG_IDLE) ImGui::Text("[x] ACT_FLAG_IDLE");
+ if (m->action & ACT_FLAG_THROWING) ImGui::Text("[x] ACT_FLAG_THROWING");
+ ImGui::Unindent();
+ }
+
+ if (ImGui::CollapsingHeader("Flags"))
+ DrawBitFlags("flags", m->flags, sMarioFlags, (int)(sizeof(sMarioFlags) / sizeof(sMarioFlags[0])));
+
+ if (ImGui::CollapsingHeader("Particle Flags"))
+ DrawBitFlags("particleFlags", m->particleFlags, sParticleFlags, (int)(sizeof(sParticleFlags) / sizeof(sParticleFlags[0])));
+
+ if (ImGui::CollapsingHeader("Animation"))
+ DrawAnimInfo(m->animInfo);
+
+ ImGui::End();
+}
static SDL_Haptic *gHaptic = nullptr;
@@ -134,7 +798,7 @@ int main(void)
sm64_register_rumble_callback_function(Rumble);
sm64_static_surfaces_load(surfaces, surfaces_count);
- int32_t marioId = sm64_mario_create(0, 1000, 0);
+ int32_t marioId = sm64_mario_create(-6558, 0, 6464);
printf("MarioID: %i\n", marioId);
free(rom);
@@ -159,6 +823,16 @@ int main(void)
context_init("libsm64", 1280, 720, major, minor);
renderer->init(&renderState, texture);
+ IMGUI_CHECKVERSION();
+ ImGui::CreateContext();
+
+ // Setup Dear ImGui style
+ ImGui::StyleColorsDark();
+
+ // Setup Platform/Renderer backends
+ ImGui_ImplSDL2_InitForOpenGL(context_get_window(), context_get_gl_context());
+ ImGui_ImplOpenGL3_Init("#version 130"); // Use #version 130 for OpenGL 3.0+
+
struct SM64MarioInputs marioInputs;
struct SM64MarioState marioState;
struct SM64MarioGeometryBuffers marioGeometry;
@@ -178,10 +852,21 @@ int main(void)
audio_init();
- sm64_play_music(0, 0x05 | 0x80, 0); // from decomp/include/seq_ids.h: SEQ_LEVEL_WATER | SEQ_VARIATION
+ sm64_play_music(0, 0x03, 0); // from decomp/include/seq_ids.h: SEQ_LEVEL_WATER | SEQ_VARIATION
do
{
+ // --- ImGui frame setup ---
+ ImGui_ImplOpenGL3_NewFrame();
+ ImGui_ImplSDL2_NewFrame();
+ ImGui::NewFrame();
+
+ // --- Define ImGui content ---
+ // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
+ ImGui::SetNextWindowCollapsed(true, ImGuiCond_Appearing);
+ ImGui::ShowDemoWindow();
+
+ // --- Game logic and input ---
float dt = (SDL_GetTicks() - lastTicks) / 1000.f;
lastTicks = SDL_GetTicks();
tick += dt;
@@ -281,12 +966,24 @@ int main(void)
for (int i = 0; i < 3; i++) marioState.position[i] = lerp(lastPos[i], currPos[i], tick / (1.f / 30));
for (int i = 0; i < marioGeometry.numTrianglesUsed * 9; i++) marioGeometry.position[i] = lerp(lastGeoPos[i], currGeoPos[i], tick / (1.f / 30));
+ // --- Game Rendering ---
renderer->draw(&renderState, cameraPos, &marioState, &marioGeometry);
+
+ DrawMarioState(&marioState);
+
+ // --- ImGui Rendering ---
+ ImGui::Render(); // Prepare draw data
+ ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); // Render ImGui draw data
}
while (context_flip_frame_poll_events());
sm64_stop_background_music(sm64_get_current_background_music());
sm64_global_terminate();
+
+ ImGui_ImplOpenGL3_Shutdown();
+ ImGui_ImplSDL2_Shutdown();
+ ImGui::DestroyContext();
+
context_terminate();
if (gHaptic != nullptr)