mirror of
https://github.com/Llennpie/Saturn.git
synced 2025-01-22 07:32:02 -05:00
backport studio custom levels (missing textures for now)
This commit is contained in:
parent
d70ad90457
commit
2c7b4775d2
19 changed files with 153 additions and 308 deletions
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
const MacroObject sa_area_3_macro_objs[] = {
|
||||
MACRO_OBJECT_END(),
|
||||
};
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
|
@ -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"
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
#include "custom_level.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#include <map>
|
||||
#include <fstream>
|
||||
|
||||
#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<std::string> split(std::string input, char character) {
|
||||
std::vector<std::string> 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<std::vector<std::string>> tokenize(std::string input) {
|
||||
std::vector<std::vector<std::string>> 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<std::string, filesystem::path>* 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<void*, int>* off, std::vector<float>* vtx, std::vector<int>* 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<std::array<float, 3>> vertices = {};
|
||||
std::vector<std::array<float, 2>> uv = {};
|
||||
std::map<std::string, filesystem::path> 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<float> vtx = {};
|
||||
std::vector<int> tri = {};
|
||||
std::map<void*, int> 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<PackData*>& 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<std::string> 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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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<Expression> Expressions;
|
||||
|
|
Loading…
Reference in a new issue