From 2c7b4775d2742d37c181c68ffd15b078eb523934 Mon Sep 17 00:00:00 2001 From: Dominicentek Date: Wed, 2 Oct 2024 22:31:19 +0200 Subject: [PATCH] backport studio custom levels (missing textures for now) --- levels/sa/area_1/geo.inc.c | 6 +- levels/sa/area_2/geo.inc.c | 6 +- levels/sa/area_3/geo.inc.c | 36 ---- levels/sa/area_3/macro.inc.c | 3 - levels/sa/geo.c | 2 + levels/sa/geo.inc.c | 3 +- levels/sa/leveldata.inc.c | 1 - levels/sa/script.c | 13 -- src/engine/graph_node.h | 7 +- src/engine/level_script.c | 1 + src/game/area.h | 2 +- src/game/custom_level.c | 122 ----------- src/game/custom_level.h | 18 -- src/game/rendering_graph_node.c | 4 + src/saturn/imgui/saturn_imgui_dynos.cpp | 1 + src/saturn/imgui/saturn_imgui_machinima.cpp | 227 ++++++++++---------- src/saturn/imgui/saturn_imgui_machinima.h | 6 + src/saturn/saturn_models.cpp | 2 + src/saturn/saturn_models.h | 1 + 19 files changed, 153 insertions(+), 308 deletions(-) delete mode 100644 levels/sa/area_3/geo.inc.c delete mode 100644 levels/sa/area_3/macro.inc.c delete mode 100644 src/game/custom_level.c delete mode 100644 src/game/custom_level.h diff --git a/levels/sa/area_1/geo.inc.c b/levels/sa/area_1/geo.inc.c index 044049e4..7e4bd58a 100644 --- a/levels/sa/area_1/geo.inc.c +++ b/levels/sa/area_1/geo.inc.c @@ -23,7 +23,11 @@ const GeoLayout sa_area_1[] = { GEO_OPEN_NODE(), GEO_CAMERA(CAMERA_MODE_CLOSE, 0, 0, 0, 0, -100, 0, geo_camera_main), GEO_OPEN_NODE(), - GEO_BRANCH(1, sa_area_1_geo), + GEO_SWITCH_CASE(0, geo_switch_override_model), + GEO_OPEN_NODE(), + GEO_BRANCH(1, sa_area_1_geo), + GEO_DISPLAY_LIST(0, NULL), + GEO_CLOSE_NODE(), GEO_RENDER_OBJ(), GEO_ASM(ENVFX_MODE_NONE, geo_envfx_main), GEO_CLOSE_NODE(), diff --git a/levels/sa/area_2/geo.inc.c b/levels/sa/area_2/geo.inc.c index 9cfefe7f..8ac1ef53 100644 --- a/levels/sa/area_2/geo.inc.c +++ b/levels/sa/area_2/geo.inc.c @@ -22,7 +22,11 @@ const GeoLayout sa_area_2[] = { GEO_OPEN_NODE(), GEO_CAMERA(CAMERA_MODE_CLOSE, 0, 0, 0, 0, -100, 0, geo_camera_main), GEO_OPEN_NODE(), - GEO_BRANCH(1, sa_area_2_geo), + GEO_SWITCH_CASE(0, geo_switch_override_model), + GEO_OPEN_NODE(), + GEO_BRANCH(1, sa_area_2_geo), + GEO_DISPLAY_LIST(0, NULL), + GEO_CLOSE_NODE(), GEO_RENDER_OBJ(), GEO_ASM(ENVFX_MODE_NONE, geo_envfx_main), GEO_CLOSE_NODE(), diff --git a/levels/sa/area_3/geo.inc.c b/levels/sa/area_3/geo.inc.c deleted file mode 100644 index a65e6f59..00000000 --- a/levels/sa/area_3/geo.inc.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "src/game/envfx_snow.h" -#include "src/game/custom_level.h" - -const GeoLayout sa_area_3_geo[] = { - GEO_NODE_START(), - GEO_OPEN_NODE(), - GEO_ASM(LAYER_OPAQUE, geo_custom_level), - GEO_CLOSE_NODE(), - GEO_RETURN(), -}; -const GeoLayout sa_area_3[] = { - GEO_NODE_SCREEN_AREA(10, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, SCREEN_WIDTH/2, SCREEN_HEIGHT/2), - GEO_OPEN_NODE(), - GEO_ZBUFFER(0), - GEO_OPEN_NODE(), - GEO_NODE_ORTHO(100.0000), - GEO_OPEN_NODE(), - GEO_BACKGROUND_DYN(geo_skybox_main), - GEO_CLOSE_NODE(), - GEO_CLOSE_NODE(), - GEO_ZBUFFER(1), - GEO_OPEN_NODE(), - GEO_CAMERA_FRUSTUM_WITH_FUNC(45.0000, 100, 30000, geo_camera_fov), - GEO_OPEN_NODE(), - GEO_CAMERA(CAMERA_MODE_CLOSE, 0, 0, 0, 0, -100, 0, geo_camera_main), - GEO_OPEN_NODE(), - GEO_BRANCH(1, sa_area_3_geo), - GEO_RENDER_OBJ(), - GEO_ASM(ENVFX_MODE_NONE, geo_envfx_main), - GEO_CLOSE_NODE(), - GEO_CLOSE_NODE(), - GEO_CLOSE_NODE(), - GEO_DISPLAY_LIST(LAYER_OPAQUE, sa_dl_material_revert_render_settings), - GEO_CLOSE_NODE(), - GEO_END(), -}; \ No newline at end of file diff --git a/levels/sa/area_3/macro.inc.c b/levels/sa/area_3/macro.inc.c deleted file mode 100644 index 95796a9b..00000000 --- a/levels/sa/area_3/macro.inc.c +++ /dev/null @@ -1,3 +0,0 @@ -const MacroObject sa_area_3_macro_objs[] = { - MACRO_OBJECT_END(), -}; \ No newline at end of file diff --git a/levels/sa/geo.c b/levels/sa/geo.c index e7115c69..3a879e36 100644 --- a/levels/sa/geo.c +++ b/levels/sa/geo.c @@ -9,6 +9,8 @@ #include "game/screen_transition.h" #include "game/paintings.h" +#include "saturn/imgui/saturn_imgui_machinima.h" + #include "make_const_nonconst.h" #include "levels/sa/header.h" diff --git a/levels/sa/geo.inc.c b/levels/sa/geo.inc.c index 04c8e552..33d46e6a 100644 --- a/levels/sa/geo.inc.c +++ b/levels/sa/geo.inc.c @@ -1,3 +1,2 @@ #include "levels/sa/area_2/geo.inc.c" -#include "levels/sa/area_1/geo.inc.c" -#include "levels/sa/area_3/geo.inc.c" \ No newline at end of file +#include "levels/sa/area_1/geo.inc.c" \ No newline at end of file diff --git a/levels/sa/leveldata.inc.c b/levels/sa/leveldata.inc.c index 5cdfe3c1..091c7c4c 100644 --- a/levels/sa/leveldata.inc.c +++ b/levels/sa/leveldata.inc.c @@ -4,5 +4,4 @@ #include "levels/sa/area_1/collision.inc.c" #include "levels/sa/area_1/macro.inc.c" #include "levels/sa/area_1/spline.inc.c" -#include "levels/sa/area_3/macro.inc.c" #include "levels/sa/model.inc.c" diff --git a/levels/sa/script.c b/levels/sa/script.c index 5074ae7e..02f24399 100644 --- a/levels/sa/script.c +++ b/levels/sa/script.c @@ -6,7 +6,6 @@ #include "dialog_ids.h" #include "segment_symbols.h" #include "level_commands.h" -#include "src/game/custom_level.h" #include "game/level_update.h" @@ -69,18 +68,6 @@ const LevelScript level_sa_entry[] = { /* Fast64 end persistent block [area commands] */ END_AREA(), - AREA(3, sa_area_3), - WARP_NODE(0x0A, LEVEL_BOB, 0x01, 0x0A, WARP_NO_CHECKPOINT), - WARP_NODE(0xF0, LEVEL_BOB, 0x01, 0x0A, WARP_NO_CHECKPOINT), - WARP_NODE(0xF1, LEVEL_BOB, 0x01, 0x0A, WARP_NO_CHECKPOINT), - OBJECT(MODEL_NONE, 0, 100, 0, 0, 0, 0, 0x000A0000, bhvSpinAirborneWarp), - MARIO_POS(0x03, 0, 100, 0, 0), - TERRAIN(custom_level_collision), - MACRO_OBJECTS(sa_area_3_macro_objs), - STOP_MUSIC(0), - TERRAIN_TYPE(TERRAIN_GRASS), - END_AREA(), - FREE_LEVEL_POOL(), MARIO_POS(0x02, 180, 0, 200, 0), CALL(0, lvl_init_or_update), diff --git a/src/engine/graph_node.h b/src/engine/graph_node.h index b84bc9e8..d4a4d282 100644 --- a/src/engine/graph_node.h +++ b/src/engine/graph_node.h @@ -369,10 +369,15 @@ extern struct GraphNodeCamera *gCurGraphNodeCamera; extern struct GraphNodeHeldObject *gCurGraphNodeHeldObject; extern u16 gAreaUpdateCounter; +#ifdef __cplusplus +extern "C" { +#endif extern struct GraphNode *gCurRootGraphNode; extern struct GraphNode *gCurGraphNodeList[]; - extern s16 gCurGraphNodeIndex; +#ifdef __cplusplus +} +#endif extern Vec3f gVec3fZero; extern Vec3s gVec3sZero; diff --git a/src/engine/level_script.c b/src/engine/level_script.c index 3a9ed4e7..88c440d1 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -612,6 +612,7 @@ static void level_cmd_set_terrain_data(void) { data = segmented_to_virtual(CMD_GET(void *, 4)); size = get_area_terrain_size(data) * sizeof(Collision); gAreas[sCurrAreaIndex].terrainData = alloc_only_pool_alloc(sLevelPool, size); + gAreas[sCurrAreaIndex].terrainDataOrig = gAreas[sCurrAreaIndex].terrainData; memcpy(gAreas[sCurrAreaIndex].terrainData, data, size); } sCurrentCmd = CMD_NEXT; diff --git a/src/game/area.h b/src/game/area.h index d746caa7..6000aac5 100644 --- a/src/game/area.h +++ b/src/game/area.h @@ -66,7 +66,7 @@ struct Area /*0x01*/ s8 flags; // Only has 1 flag: 0x01 = Is this the active area? /*0x02*/ u16 terrainType; // default terrain of the level (set from level script cmd 0x31) /*0x04*/ struct GraphNodeRoot *unk04; // geometry layout data - /*0x08*/ s16 *terrainData; // collision data (set from level script cmd 0x2E) + /*0x08*/ s16 *terrainData, *terrainDataOrig; // collision data (set from level script cmd 0x2E) /*0x0C*/ s8 *surfaceRooms; // (set from level script cmd 0x2F) /*0x10*/ s16 *macroObjects; // Macro Objects Ptr (set from level script cmd 0x39) /*0x14*/ struct ObjectWarpNode *warpNodes; diff --git a/src/game/custom_level.c b/src/game/custom_level.c deleted file mode 100644 index 62d6009b..00000000 --- a/src/game/custom_level.c +++ /dev/null @@ -1,122 +0,0 @@ -#include "custom_level.h" - -#include - -#include "include/types.h" -#include "include/surface_terrains.h" - -Collision custom_level_collision[1024 * 64] = { - COL_INIT(), - COL_VERTEX_INIT(0), - COL_TRI_INIT(0, 0), - COL_TRI_STOP(), - COL_END(), -}; -Gfx* custom_level_dl; -Gfx* geo_iter; -Vtx* vertices; -int* faces; -char** textures; -int vertex_iter = 0; -int face_iter = 0; -int used_vert = 0; -int tex_iter = 0; - -Lights1 lights = gdSPDefLights1(0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0x28, 0x28, 0x28); - -void custom_level_new() { - if (vertices != NULL) { - free(vertices); - free(faces); - free(custom_level_dl); - for (int i = 0; i < tex_iter; i++) { - free(textures[i]); - } - free(textures); - geo_iter = NULL; - } - vertices = malloc(sizeof(Vtx) * 8192); - faces = malloc(sizeof(int) * 3 * 8192); - custom_level_dl = malloc(sizeof(Gfx) * 16384); - textures = (char**)malloc(sizeof(char*) * 128); - for (int i = 0; i < 128; i++) { - textures[i] = (char*)malloc(sizeof(char) * 256); - } - vertex_iter = 0; - face_iter = 0; - used_vert = 0; - tex_iter = 0; - geo_iter = custom_level_dl; - gDPPipeSync(geo_iter++); - gDPSetCombineLERP(geo_iter++, TEXEL0, 0, SHADE, 0, 0, 0, 0, ENVIRONMENT, TEXEL0, 0, SHADE, 0, 0, 0, 0, ENVIRONMENT); - gSPTexture(geo_iter++, 65535, 65535, 0, 0, 1); - gSPSetLights1(geo_iter++, lights); - custom_level_texture(""); -} - -void custom_level_vertex(float x, float y, float z, float u, float v) { - if (vertex_iter == 8192) return; - vertices[vertex_iter].v.ob[0] = x; - vertices[vertex_iter].v.ob[1] = y; - vertices[vertex_iter].v.ob[2] = z; - vertices[vertex_iter].v.flag = 0; - vertices[vertex_iter].v.tc[0] = u; - vertices[vertex_iter].v.tc[1] = v; - vertices[vertex_iter].v.cn[0] = 255; - vertices[vertex_iter].v.cn[1] = 255; - vertices[vertex_iter].v.cn[2] = 255; - vertices[vertex_iter].v.cn[3] = 255; - vertex_iter++; -} - -void custom_level_face() { - int begin = used_vert; - int num_vert = vertex_iter - used_vert; - gSPVertex(geo_iter++, vertices + begin, num_vert, 0); - for (int i = 2; i < num_vert; i++) { - if (face_iter == 8192) break; - faces[face_iter * 3 + 0] = begin; - faces[face_iter * 3 + 1] = i - 1 + begin; - faces[face_iter * 3 + 2] = i + begin; - face_iter++; - gSP1Triangle(geo_iter++, 0, i - 1, i, 0); - } - used_vert = vertex_iter; -} - -void custom_level_texture(char* texpath) { - memcpy(textures[tex_iter], texpath, strlen(texpath) + 1); - gDPSetTextureImage(geo_iter++, G_IM_FMT_RGBA, G_IM_SIZ_16b_LOAD_BLOCK, 1, textures[tex_iter]); - gDPSetTile(geo_iter++, G_IM_FMT_RGBA, G_IM_SIZ_16b_LOAD_BLOCK, 0, 0, 7, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0); - gDPLoadBlock(geo_iter++, 7, 0, 0, 1023, 256); - gDPSetTile(geo_iter++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 0, 0, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0); - gDPSetTileSize(geo_iter++, 0, 0, 0, 124, 124); - tex_iter++; -} - -void custom_level_finish() { - int iter = 0; - custom_level_collision[iter++] = TERRAIN_LOAD_VERTICES; - custom_level_collision[iter++] = vertex_iter; - int lowest = 0x7FFF; - for (int i = 0; i < vertex_iter; i++) { - for (int j = 0; j < 3; j++) { - if (lowest > vertices[i].v.ob[j]) lowest = vertices[i].v.ob[j]; - custom_level_collision[iter++] = vertices[i].v.ob[j]; - } - } - custom_level_collision[iter++] = 0; - custom_level_collision[iter++] = face_iter; - for (int i = 0; i < face_iter; i++) { - for (int j = 0; j < 3; j++) { - custom_level_collision[iter++] = faces[i * 3 + j]; - } - } - custom_level_collision[iter++] = TERRAIN_LOAD_CONTINUE; - custom_level_collision[iter++] = TERRAIN_LOAD_END; - gSPEndDisplayList(geo_iter++); -} - -Gfx *geo_custom_level(s32 sp, struct GraphNode* graphNode, UNUSED void* context) { - return custom_level_dl; -} \ No newline at end of file diff --git a/src/game/custom_level.h b/src/game/custom_level.h deleted file mode 100644 index 8b6578a1..00000000 --- a/src/game/custom_level.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CUSTOM_LEVEL_H -#define CUSTOM_LEVEL_H - -#include "include/types.h" -#include "include/macros.h" - -extern Collision custom_level_collision[]; -extern Gfx* custom_level_dl; - -void custom_level_new(); -void custom_level_vertex(float x, float y, float z, float u, float v); -void custom_level_face(); -void custom_level_texture(char* texture); -void custom_level_finish(); - -Gfx* geo_custom_level(s32 sp, struct GraphNode* graphNode, UNUSED void* context); - -#endif \ No newline at end of file diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 84bc8d70..d647528e 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -14,6 +14,7 @@ #include "saturn/saturn.h" #include "saturn/saturn_animations.h" #include "pc/configfile.h" +#include "saturn/imgui/saturn_imgui_machinima.h" /** * This file contains the code that processes the scene graph for rendering. @@ -1251,6 +1252,9 @@ static void geo_process_object_parent(struct GraphNodeObjectParent *node) { if (node->node.children != NULL) { geo_process_node_and_siblings(node->node.children); } + if (override_level && override_level_geolayout) { + geo_process_node_and_siblings(override_level_geolayout); + } } /** diff --git a/src/saturn/imgui/saturn_imgui_dynos.cpp b/src/saturn/imgui/saturn_imgui_dynos.cpp index 63bf6270..9ff018e8 100644 --- a/src/saturn/imgui/saturn_imgui_dynos.cpp +++ b/src/saturn/imgui/saturn_imgui_dynos.cpp @@ -154,6 +154,7 @@ void OpenModelSelector() { ImGui::BeginChild("###menu_model_selector", ImVec2(-FLT_MIN, 125), true); for (int i = 0; i < model_list.size(); i++) { Model model = model_list[i]; + if (model.Type != "mario") continue; if (model.Active) { bool is_selected = DynOS_Opt_GetValue(String("dynos_pack_%d", i)); diff --git a/src/saturn/imgui/saturn_imgui_machinima.cpp b/src/saturn/imgui/saturn_imgui_machinima.cpp index 5b10aaf3..d054b5db 100755 --- a/src/saturn/imgui/saturn_imgui_machinima.cpp +++ b/src/saturn/imgui/saturn_imgui_machinima.cpp @@ -7,11 +7,13 @@ #include #include +#include "engine/graph_node.h" #include "saturn/libs/imgui/imgui.h" #include "saturn/libs/imgui/imgui_internal.h" #include "saturn/libs/imgui/imgui_impl_sdl.h" #include "saturn/libs/imgui/imgui_impl_opengl3.h" #include "saturn/saturn.h" +#include "saturn/saturn_models.h" #include "saturn/saturn_textures.h" #include "saturn/saturn_animation_ids.h" #include "saturn/saturn_animations.h" @@ -42,7 +44,7 @@ extern "C" { #include "src/game/interaction.h" #include "include/behavior_data.h" #include "game/object_helpers.h" -#include "game/custom_level.h" +#include "engine/surface_load.h" } using namespace std; @@ -191,92 +193,92 @@ int get_saturn_level_id(int level) { } } -std::vector split(std::string input, char character) { - std::vector tokens = {}; - std::string token = ""; - for (int i = 0; i < input.length(); i++) { - if (input[i] == '\r') continue; - if (input[i] == character) { - tokens.push_back(token); - token = ""; - } - else token += input[i]; +bool override_level = false; +bool custom_level_loaded = false; +struct GraphNode* override_level_geolayout; +Collision* override_level_collision; + +Gfx* geo_switch_override_model(s32 callContext, struct GraphNode *node, UNUSED Mat4 *mtx) { + struct GraphNodeSwitchCase* switchCase = (struct GraphNodeSwitchCase*)node; + if (callContext == GEO_CONTEXT_RENDER) { + switchCase->selectedCase = override_level && override_level_geolayout; } - tokens.push_back(token); - return tokens; -} -std::vector> tokenize(std::string input) { - std::vector> tokens = {}; - auto lines = split(input, '\n'); - for (auto line : lines) { - tokens.push_back(split(line, ' ')); - } - return tokens; + return NULL; } -int textureIndex = 0; -std::filesystem::path customlvl_texdir = std::filesystem::path(sys_user_path()) / "res" / "gfx" / "customlevel"; -bool custom_level_flip_normals = false; - -void parse_materials(char* data, std::map* materials) { - auto tokens = tokenize(std::string(data)); - std::string matname = ""; - for (auto line : tokens) { - if (line[0] == "newmtl") matname = line[1]; - if (line[0] == "map_Kd" && matname != "") { - std::string path = std::to_string(textureIndex++) + ".png"; - std::filesystem::path raw = std::filesystem::path(line[1]); - std::filesystem::path src = raw.is_absolute() ? raw : std::filesystem::path(custom_level_path).parent_path() / raw; - std::filesystem::path dst = customlvl_texdir / path; - std::filesystem::remove(dst); - std::filesystem::copy_file(src, dst); - materials->insert({ matname, "customlevel/" + path }); +#define C0(pos, width) ((dl->words.w0 >> (pos)) & ((1U << width) - 1)) +#define C1(pos, width) ((dl->words.w1 >> (pos)) & ((1U << width) - 1)) +void append_collision_data(Gfx* dl, int* cur, int* nvt, std::map* off, std::vector* vtx, std::vector* tri) { + bool running = true; + while (running) { + int opcode = dl->words.w0 >> 24; + switch (opcode) { + case G_DL: { + append_collision_data((Gfx*)dl->words.w1, cur, nvt, off, vtx, tri); + } break; + case G_VTX: { + Vtx* verts = (Vtx*)dl->words.w1; + if (off->find(verts) == off->end()) { + off->insert({ verts, *nvt }); + int num = C0(12, 8); + *nvt += num; + for (int i = 0; i < num; i++) { + vtx->push_back(verts[i].v.ob[0]); + vtx->push_back(verts[i].v.ob[1]); + vtx->push_back(verts[i].v.ob[2]); + } + } + *cur = (*off)[verts]; + } break; + case G_TRI1: { + tri->push_back(C0(16, 8) / 2 + *cur); + tri->push_back(C0( 8, 8) / 2 + *cur); + tri->push_back(C0( 0, 8) / 2 + *cur); + } break; + case G_TRI2: { + tri->push_back(C0(16, 8) / 2 + *cur); + tri->push_back(C0( 8, 8) / 2 + *cur); + tri->push_back(C0( 0, 8) / 2 + *cur); + tri->push_back(C1(16, 8) / 2 + *cur); + tri->push_back(C1( 8, 8) / 2 + *cur); + tri->push_back(C1( 0, 8) / 2 + *cur); + } break; + case G_ENDDL: { + running = false; + } break; } + dl++; } } -void parse_custom_level(char* data) { - auto tokens = tokenize(std::string(data)); - textureIndex = 0; - if (std::filesystem::exists(customlvl_texdir)) std::filesystem::remove_all(customlvl_texdir); - std::filesystem::create_directories(customlvl_texdir); - custom_level_new(); - std::vector> vertices = {}; - std::vector> uv = {}; - std::map materials = {}; - for (auto line : tokens) { - if (line.size() == 0) continue; - if (line[0] == "mtllib") { - filesystem::path path = filesystem::absolute(std::filesystem::path(custom_level_dirname) / line[1]); - if (!filesystem::exists(path)) continue; - auto size = filesystem::file_size(path); - char* mtldata = (char*)malloc(size); - std::ifstream file = std::ifstream(path, std::ios::binary); - file.read(mtldata, size); - parse_materials(mtldata, &materials); - free(mtldata); +Collision* create_collision_mesh(struct GraphNode* node) { + if (node == NULL) return NULL; + if (node->type == GRAPH_NODE_TYPE_DISPLAY_LIST) { + struct GraphNodeDisplayList* dlnode = (struct GraphNodeDisplayList*)node; + Gfx* dl = (Gfx*)dlnode->displayList; + std::vector vtx = {}; + std::vector tri = {}; + std::map off = {}; + int nvt = 0; + int cur = 0; + append_collision_data(dl, &cur, &nvt, &off, &vtx, &tri); + Collision* coll = (Collision*)malloc(sizeof(s16) * (6 + vtx.size() + tri.size())); + int ptr = 0; + coll[ptr++] = TERRAIN_LOAD_VERTICES; + coll[ptr++] = vtx.size() / 3; + for (int i = 0; i < vtx.size(); i++) { + coll[ptr++] = vtx[i]; } - if (line[0] == "v") vertices.push_back({ std::stof(line[1]), std::stof(line[2]), std::stof(line[3]) }); - if (line[0] == "vt") uv.push_back({ std::stof(line[1]), std::stof(line[2]) }); - if (line[0] == "usemtl") { - if (materials.find(line[1]) == materials.end()) continue; - custom_level_texture((char*)materials[line[1]].c_str()); - } - if (line[0] == "f") { - for (int i = 1; i < line.size(); i++) { - int idx = i; - if (custom_level_flip_normals && idx == 1) idx = 3; - else if (custom_level_flip_normals && idx == 3) idx = 1; - auto indexes = split(line[idx], '/'); - int v = std::stoi(indexes[0]) - 1; - int vt = std::stoi(indexes[1]) - 1; - custom_level_vertex(vertices[v][0] * custom_level_scale, vertices[v][1] * custom_level_scale, vertices[v][2] * custom_level_scale, uv[vt][0] * 1024, uv[vt][1] * 1024); - } - custom_level_face(); + coll[ptr++] = SURFACE_DEFAULT; + coll[ptr++] = tri.size() / 3; + for (int i = 0; i < tri.size(); i++) { + coll[ptr++] = tri[i]; } + coll[ptr++] = TERRAIN_LOAD_CONTINUE; + coll[ptr++] = TERRAIN_LOAD_END; + return coll; } - gfx_precache_textures(); - custom_level_finish(); + return create_collision_mesh(node->children); } struct AnimEntry { @@ -353,6 +355,45 @@ void imgui_machinima_quick_options() { k_frame_keys.clear(); } + if (gCurrLevelNum == LEVEL_SA) { + if (ImGui::Checkbox("Load Level Model", &override_level)) { + gCurrentArea->terrainData = + override_level && override_level_collision ? + override_level_collision : + gAreas[gCurrAreaIndex].terrainDataOrig; + load_area_terrain(gCurrAreaIndex, gCurrentArea->terrainData, gCurrentArea->surfaceRooms, NULL); + } + if (override_level) { + Array& sDynosPacks = DynOS_Gfx_GetPacks(); + ImGui::BeginChild("##level_model_select", ImVec2(0, 120), true); + for (Model& model : model_list) { + if (model.Type != "level") continue; + GfxData* gfx = DynOS_Gfx_LoadFromBinary(sDynosPacks[model.DynOSId]->mPath, "mario_geo"); + GraphNode* geo = (GraphNode*)DynOS_Geo_GetGraphNode((*(gfx->mGeoLayouts.end() - 1))->mData, true); + bool selected = geo == override_level_geolayout; + if (ImGui::Selectable(model.Name.c_str(), selected)) { + if (override_level_collision) { + free(override_level_collision); + override_level_collision = NULL; + } + override_level_geolayout = geo; + override_level_collision = create_collision_mesh(geo); + gCurrentArea->terrainData = override_level_collision; + load_area_terrain(gCurrAreaIndex, gCurrentArea->terrainData, gCurrentArea->surfaceRooms, NULL); + } + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::TextDisabled("%s - by", model.Version.c_str()); + ImGui::SameLine(); + ImGui::Text("%s", model.Author.c_str()); + ImGui::Text("%s", model.Description.c_str()); + ImGui::EndTooltip(); + } + } + ImGui::EndChild(); + } + } + auto locations = saturn_get_locations(); bool do_save = false; std::vector forRemoval = {}; @@ -465,38 +506,6 @@ void imgui_machinima_quick_options() { ImGui::EndMenu(); } } - - UNSTABLE - if (ImGui::BeginMenu("(!) Custom Level")) { - bool in_custom_level = gCurrLevelNum == LEVEL_SA && gCurrAreaIndex == 3; - ImGui::PushItemWidth(80); - ImGui::InputFloat("Scale###cl_scale", &custom_level_scale); - ImGui::PopItemWidth(); - if (!is_custom_level_loaded || in_custom_level) ImGui::BeginDisabled(); - if (ImGui::Button("Load Level")) { - auto size = filesystem::file_size(custom_level_path); - char* data = (char*)malloc(size); - std::ifstream file = std::ifstream((char*)custom_level_path.c_str(), std::ios::binary); - file.read(data, size); - parse_custom_level(data); - free(data); - warp_to_level(0, 3); - } - if (!is_custom_level_loaded || in_custom_level) ImGui::EndDisabled(); - ImGui::SameLine(); - if (ImGui::Button("Load .obj")) { - auto selection = choose_file_dialog("Select a model", { "Wavefront Model (.obj)", "*.obj", "All Files", "*" }, false); - if (selection.size() != 0) { - filesystem::path path = selection[0]; - is_custom_level_loaded = true; - custom_level_path = path.string(); - custom_level_dirname = path.parent_path().string(); - custom_level_filename = path.filename().string(); - } - } - ImGui::Text(is_custom_level_loaded ? custom_level_filename.c_str() : "No model loaded!"); - ImGui::EndMenu(); - } } static char animSearchTerm[128]; diff --git a/src/saturn/imgui/saturn_imgui_machinima.h b/src/saturn/imgui/saturn_imgui_machinima.h index fbab2b1f..b39df9e9 100755 --- a/src/saturn/imgui/saturn_imgui_machinima.h +++ b/src/saturn/imgui/saturn_imgui_machinima.h @@ -8,16 +8,22 @@ extern float gravity; extern bool enable_time_freeze; extern int current_sanim_id; +extern bool override_level; +extern struct GraphNode* override_level_geolayout; +extern Collision* override_level_collision; + extern void anim_play_button(); extern void saturn_create_object(int, const BehaviorScript*, float, float, float, s16, s16, s16, int); #ifdef __cplusplus extern "C" { #endif + void warp_to_level(int, int, int); int get_saturn_level_id(int); void smachinima_imgui_init(void); void smachinima_imgui_controls(SDL_Event * event); + Gfx* geo_switch_override_model(s32 callContext, struct GraphNode *node, UNUSED Mat4 *mtx); void imgui_machinima_animation_player(void); void imgui_machinima_quick_options(void); diff --git a/src/saturn/saturn_models.cpp b/src/saturn/saturn_models.cpp index 82b896db..f54a31fe 100644 --- a/src/saturn/saturn_models.cpp +++ b/src/saturn/saturn_models.cpp @@ -98,6 +98,8 @@ Model LoadModelData(std::string folderPath) { model.Name = root["name"].asString(); model.Author = root["author"].asString(); model.Version = root["version"].asString(); + if (root.isMember("type")) model.Type = root["type"].asString(); + std::transform(model.Type.begin(), model.Type.end(), model.Type.begin(), [](unsigned char c){ return std::tolower(c); }); // Description (optional) if (root.isMember("description")) { diff --git a/src/saturn/saturn_models.h b/src/saturn/saturn_models.h index 8780d3aa..6a970c2a 100644 --- a/src/saturn/saturn_models.h +++ b/src/saturn/saturn_models.h @@ -24,6 +24,7 @@ class Model { std::string Author; std::string Version = "1.0.0"; // String, so version format can be anything std::string Description; + std::string Type = "mario"; // Expressions std::vector Expressions;