Added adjustable track properties to editor

This commit is contained in:
MegaMech
2025-03-10 01:29:44 -06:00
parent 68d9addb6f
commit 9e4b7ae6b4
12 changed files with 337 additions and 8 deletions
+13
View File
@@ -22,6 +22,8 @@ extern "C" {
#include "camera.h"
}
namespace EditorNamespace {
int gfx_create_framebuffer(uint32_t width, uint32_t height, uint32_t native_width, uint32_t native_height,
uint8_t resize);
@@ -107,3 +109,14 @@ void Editor::SelectObjectFromSceneExplorer(GameObject* object) {
eObjectPicker.eGizmo.Enabled = true;
eObjectPicker.eGizmo.SetGizmoNoCursor(object);
}
void Editor::SetLevelDimensions(s16 minX, s16 maxX, s16 minZ, s16 maxZ, s16 minY, s16 maxY) {
eObjectPicker.eGizmo.dimensions.MinX = minX + -1000;
eObjectPicker.eGizmo.dimensions.MaxX = maxX + 1000;
eObjectPicker.eGizmo.dimensions.MinY = minY + -100;
eObjectPicker.eGizmo.dimensions.MaxY = maxY + 500;
eObjectPicker.eGizmo.dimensions.MinZ = minZ + -1000;
eObjectPicker.eGizmo.dimensions.MaxZ = maxZ + 1000;
}
}
+13
View File
@@ -24,6 +24,8 @@ extern "C" {
#include "src/racing/collision.h"
}
namespace EditorNamespace {
Gizmo::Gizmo() {
}
@@ -109,6 +111,16 @@ void Gizmo::Translate() {
break;
}
if (CVarGetInteger("gEditorBoundary", 0) == true) {
_selected->Pos->x = MAX(_selected->Pos->x, dimensions.MinX);
_selected->Pos->x = MIN(_selected->Pos->x, dimensions.MaxX);
_selected->Pos->y = MAX(_selected->Pos->y, dimensions.MinY);
_selected->Pos->y = MIN(_selected->Pos->y, dimensions.MaxY);
_selected->Pos->z = MAX(_selected->Pos->z, dimensions.MinZ);
_selected->Pos->z = MIN(_selected->Pos->z, dimensions.MaxZ);
}
Pos = FVector(
_selected->Pos->x,
@@ -195,3 +207,4 @@ void Gizmo::DrawHandles() {
gSPDisplayList(gDisplayListHead++, handle_Cylinder_mesh);
}
}
}
+12
View File
@@ -4,6 +4,8 @@
#include <libultra/gbi.h>
#include "Collision.h"
namespace EditorNamespace {
class Gizmo {
public:
@@ -27,6 +29,15 @@ public:
void DrawHandles();
f32 SnapToSurface(FVector* pos);
struct TrackDimensions {
s16 MinX = -10000;
s16 MaxX = 10000;
s16 MinY = -3000;
s16 MaxY = 3000;
s16 MinZ = -10000;
s16 MaxZ = 10000;
};
TrackDimensions dimensions;
bool Enabled;
GizmoHandle SelectedHandle;
@@ -542,3 +553,4 @@ Gfx handle_Cylinder_mesh[13] = {
};
};
}
+3
View File
@@ -23,6 +23,8 @@ extern "C" {
#include "camera.h"
}
namespace EditorNamespace {
ObjectPicker::ObjectPicker() {
}
@@ -180,3 +182,4 @@ void ObjectPicker::FindObject(Ray ray, std::vector<GameObject>& objects) {
_selected = nullptr;
}
}
}
+3
View File
@@ -5,6 +5,8 @@
#include "Collision.h"
#include "Gizmo.h"
namespace EditorNamespace {
class ObjectPicker {
public:
ObjectPicker();
@@ -25,3 +27,4 @@ class ObjectPicker {
void Copy(MtxF* src, MtxF* dest);
void Clear(MtxF* mf);
};
}
+5 -1
View File
@@ -102,7 +102,7 @@ ModelLoader gModelLoader;
HarbourMastersIntro gMenuIntro;
Editor gEditor;
EditorNamespace::Editor gEditor;
s32 gTrophyIndex = NULL;
@@ -419,6 +419,10 @@ void CM_DrawEditor() {
gEditor.Draw();
}
void CM_Editor_SetLevelDimensions(s16 minX, s16 maxX, s16 minZ, s16 maxZ, s16 minY, s16 maxY) {
gEditor.SetLevelDimensions(minX, maxX, minZ, maxZ, minY, maxY);
}
void CM_TickParticles() {
if (gWorldInstance.CurrentCourse) {
gWorldInstance.TickParticles();
+1 -1
View File
@@ -16,7 +16,7 @@ extern "C" {
extern s32 gTrophyIndex;
#ifdef __cplusplus
extern Editor gEditor;
extern EditorNamespace::Editor gEditor;
#endif
Properties* CM_GetProps();
+6
View File
@@ -6,6 +6,7 @@
#include "FreecamWindow.h"
#include "Tools.h"
#include "SceneExplorer.h"
#include "TrackProperties.h"
#include "ContentBrowser.h"
#include <spdlog/spdlog.h>
@@ -37,6 +38,7 @@ std::shared_ptr<Ship::GuiWindow> mGameInfoWindow;
std::shared_ptr<Ship::GuiWindow> mMultiplayerWindow;
std::shared_ptr<Ship::GuiWindow> mToolsWindow;
std::shared_ptr<Ship::GuiWindow> mSceneExplorerWindow;
std::shared_ptr<Ship::GuiWindow> mTrackPropertiesWindow;
std::shared_ptr<Ship::GuiWindow> mContentBrowserWindow;
void SetupGuiElements() {
@@ -86,6 +88,9 @@ void SetupGuiElements() {
mSceneExplorerWindow = std::make_shared<EditorNamespace::SceneExplorerWindow>("gEditorEnabled", "Scene Explorer");
gui->AddGuiWindow(mSceneExplorerWindow);
mTrackPropertiesWindow = std::make_shared<EditorNamespace::TrackPropertiesWindow>("gEditorEnabled", "Track Properties");
gui->AddGuiWindow(mTrackPropertiesWindow);
mContentBrowserWindow =
std::make_shared<EditorNamespace::ContentBrowserWindow>("gEditorEnabled", "Content Browser");
gui->AddGuiWindow(mContentBrowserWindow);
@@ -101,6 +106,7 @@ void Destroy() {
mInputEditorWindow = nullptr;
mToolsWindow = nullptr;
mSceneExplorerWindow = nullptr;
mTrackPropertiesWindow = nullptr;
mContentBrowserWindow = nullptr;
}
+27 -6
View File
@@ -13,6 +13,7 @@
extern "C" {
#include "code_800029B0.h"
#include "code_80057C60.h"
}
namespace EditorNamespace {
@@ -26,7 +27,8 @@ namespace EditorNamespace {
}
void ToolsWindow::DrawElement() {
static bool toggleState = CVarGetInteger("gEditorSnapToGround", 0);
static bool toggleGroundSnap = CVarGetInteger("gEditorSnapToGround", 0);
static bool toggleBoundary = CVarGetInteger("gEditorBoundary", 0);
static int selectedTool = 0; // 0: Move, 1: Rotate, 2: Scale
static int selectedPlayTool = 0; // 0: Play, 1: Paused
@@ -42,7 +44,7 @@ namespace EditorNamespace {
ImGui::PopStyleColor();
};
// Draw buttons
ToolButton("Move", 0);
ImGui::SameLine();
@@ -52,16 +54,29 @@ namespace EditorNamespace {
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, toggleState ? ImVec4(0.4f, 0.7f, 0.9f, 1.0f) : defaultColor);
if (ImGui::Button(toggleState ? "SNAP TO GROUND" : "SNAP TO GROUND", ImVec2(125, 25))) {
toggleState = !toggleState;
// Snap to ground
ImGui::PushStyleColor(ImGuiCol_Button, toggleGroundSnap ? ImVec4(0.4f, 0.7f, 0.9f, 1.0f) : defaultColor);
if (ImGui::Button(toggleGroundSnap ? "SNAP TO GROUND" : "SNAP TO GROUND", ImVec2(125, 25))) {
toggleGroundSnap = !toggleGroundSnap;
CVarSetInteger("gEditorSnapToGround", toggleState);
CVarSetInteger("gEditorSnapToGround", toggleGroundSnap);
}
ImGui::PopStyleColor();
ImGui::SameLine();
// Boundary
ImGui::PushStyleColor(ImGuiCol_Button, toggleBoundary ? ImVec4(0.4f, 0.7f, 0.9f, 1.0f) : defaultColor);
if (ImGui::Button(toggleBoundary ? "Map Boundaries" : "Map Boundaries", ImVec2(125, 25))) {
toggleBoundary = !toggleBoundary;
CVarSetInteger("gEditorBoundary", toggleBoundary);
}
ImGui::PopStyleColor();
ImGui::SameLine();
if (ImGui::Button("Player One AI/Human", ImVec2(160, 25))) {
if (gPlayerOne->type & PLAYER_KART_AI) {
gPlayerOne->type &= ~PLAYER_KART_AI;
@@ -88,5 +103,11 @@ namespace EditorNamespace {
PlayButton("Play", 0);
ImGui::SameLine();
PlayButton("Pause", 1);
ImGui::SameLine();
if (ImGui::Button("Toggle HUD", ImVec2(150, 25))) {
gIsHUDVisible = !gIsHUDVisible;
}
}
}
+228
View File
@@ -0,0 +1,228 @@
#include "TrackProperties.h"
#include "port/ui/PortMenu.h"
#include "UIWidgets.h"
#include "libultraship/src/Context.h"
#include <imgui.h>
#include <map>
#include <libultraship/libultraship.h>
#include <spdlog/fmt/fmt.h>
#include "spdlog/formatter.h"
#include <common_structs.h>
#include <defines.h>
#include "port/Game.h"
extern "C" {
#include "code_800029B0.h"
#include "sounds.h"
#include "external.h"
#include "render_courses.h"
}
namespace EditorNamespace {
TrackPropertiesWindow::~TrackPropertiesWindow() {
SPDLOG_TRACE("destruct track properties window");
}
void TrackPropertiesWindow::DrawElement() {
static char idBuffer[128] = "mk:mario_raceway";
static char nameBuffer[128] = "Mario Raceway";
static char debugNameBuffer[128] = "m circuit";
static char lengthBuffer[128] = "567m";
ImGui::InputText("ID", idBuffer, IM_ARRAYSIZE(idBuffer));
ImGui::InputText("Name", nameBuffer, IM_ARRAYSIZE(nameBuffer));
ImGui::InputText("Debug Name", debugNameBuffer, IM_ARRAYSIZE(debugNameBuffer));
ImGui::InputText("Course Length", lengthBuffer, IM_ARRAYSIZE(lengthBuffer));
ImGui::Separator();
static float aiMaxSeparation = 50.0f;
static float aiMinSeparation = 0.3f;
static int aiSteeringSensitivity = 48;
ImGui::InputFloat("AI Max Separation", &gWorldInstance.CurrentCourse->Props.AIMaximumSeparation);
ImGui::InputFloat("AI Min Separation", &gWorldInstance.CurrentCourse->Props.AIMinimumSeparation);
ImGui::InputInt("AI Steering Sensitivity", (int*)&gWorldInstance.CurrentCourse->Props.AISteeringSensitivity);
ImGui::Separator();
ImGui::InputInt("Minimap Finishline X Offset", (int*)&gWorldInstance.CurrentCourse->Props.MinimapFinishlineX);
ImGui::InputInt("Minimap Finishline Y Offset", (int*)&gWorldInstance.CurrentCourse->Props.MinimapFinishlineY);
ImGui::Separator();
static float nearPersp = 9.0f;
static float farPersp = 4500.0f;
ImGui::InputFloat("Near Perspective", &gWorldInstance.CurrentCourse->Props.NearPersp);
ImGui::InputFloat("Far Perspective", &gWorldInstance.CurrentCourse->Props.FarPersp);
ImGui::Separator();
static float d_0D009418[4] = { 4.1666665f, 5.5833334f, 6.1666665f, 6.75f };
for (int i = 0; i < 4; i++) {
ImGui::InputFloat(fmt::format("D_0D009418[{}]", i).c_str(), &d_0D009418[i]);
}
ImGui::Separator();
// Convert and pass to ImGui ColorEdit3
float topRight[3], bottomRight[3], bottomLeft[3], topLeft[3];
float floorTopRight[3], floorBottomRight[3], floorBottomLeft[3], floorTopLeft[3];
// Convert RGB8 (0-255) to float (0.0f to 1.0f)
RGB8ToFloat((u8*)&gWorldInstance.CurrentCourse->Props.Skybox.TopRight, topRight);
RGB8ToFloat((u8*)&gWorldInstance.CurrentCourse->Props.Skybox.BottomRight, bottomRight);
RGB8ToFloat((u8*)&gWorldInstance.CurrentCourse->Props.Skybox.BottomLeft, bottomLeft);
RGB8ToFloat((u8*)&gWorldInstance.CurrentCourse->Props.Skybox.TopLeft, topLeft);
RGB8ToFloat((u8*)&gWorldInstance.CurrentCourse->Props.Skybox.FloorTopRight, floorTopRight);
RGB8ToFloat((u8*)&gWorldInstance.CurrentCourse->Props.Skybox.FloorBottomRight, floorBottomRight);
RGB8ToFloat((u8*)&gWorldInstance.CurrentCourse->Props.Skybox.FloorBottomLeft, floorBottomLeft);
RGB8ToFloat((u8*)&gWorldInstance.CurrentCourse->Props.Skybox.FloorTopLeft, floorTopLeft);
// Use these float arrays with ImGui::ColorEdit3
ImGui::ColorEdit3("Skybox Top Right", topRight);
ImGui::ColorEdit3("Skybox Bottom Right", bottomRight);
ImGui::ColorEdit3("Skybox Bottom Left", bottomLeft);
ImGui::ColorEdit3("Skybox Top Left", topLeft);
ImGui::ColorEdit3("Skybox Floor Top Right", floorTopRight);
ImGui::ColorEdit3("Skybox Floor Bottom Right", floorBottomRight);
ImGui::ColorEdit3("Skybox Floor Bottom Left", floorBottomLeft);
ImGui::ColorEdit3("Skybox Floor Top Left", floorTopLeft);
// Convert the modified float values back to RGB8 (0-255)
FloatToRGB8(topRight, (u8*)&gWorldInstance.CurrentCourse->Props.Skybox.TopRight);
FloatToRGB8(bottomRight, (u8*)&gWorldInstance.CurrentCourse->Props.Skybox.BottomRight);
FloatToRGB8(bottomLeft, (u8*)&gWorldInstance.CurrentCourse->Props.Skybox.BottomLeft);
FloatToRGB8(topLeft, (u8*)&gWorldInstance.CurrentCourse->Props.Skybox.TopLeft);
FloatToRGB8(floorTopRight, (u8*)&gWorldInstance.CurrentCourse->Props.Skybox.FloorTopRight);
FloatToRGB8(floorBottomRight, (u8*)&gWorldInstance.CurrentCourse->Props.Skybox.FloorBottomRight);
FloatToRGB8(floorBottomLeft, (u8*)&gWorldInstance.CurrentCourse->Props.Skybox.FloorBottomLeft);
FloatToRGB8(floorTopLeft, (u8*)&gWorldInstance.CurrentCourse->Props.Skybox.FloorTopLeft);
ImGui::Separator();
TrackPropertiesWindow::DrawMusic();
ImGui::Separator();
TrackPropertiesWindow::DrawLight();
}
void TrackPropertiesWindow::DrawMusic() {
const char* items[] = {
"None", "Title Screen", "Main Menu", "Raceways Wario Stadium", "Moo Moo Farm / Yoshi Valley",
"Choco Mountain", "Koopa Troopa Beach", "Banshee Boardwalk", "Frappe Snowland", "Bowser's Castle",
"Kalimari Desert", "Start Grid GP/VS", "Final Lap Fanfare", "Finish 1st Place", "Finish 2nd-4th Place",
"Finish 5th-8th Place", "16", "Star Jingle", "Rainbow Road", "DK Jungle", "Game Over", "Toad's Turnpike",
"Start Grid Time Attack", "VS Battle Results", "Losing Results", "Battle Arenas", "Award Ceremony Buildup",
"Award Ceremony 1st-3rd", "Staff Roll", "Award Ceremony 4th-8th"
};
const char* currentItem = MusicSeqToString(gWorldInstance.CurrentCourse->Props.Sequence); // Get the current selected value's string
if (ImGui::BeginCombo("Music Sequence", currentItem)) {
for (int i = 0; i < IM_ARRAYSIZE(items); ++i) {
bool isSelected = (currentItem == items[i]);
if (ImGui::Selectable(items[i], isSelected)) {
// Update the sequence when an option is selected
gWorldInstance.CurrentCourse->Props.Sequence = static_cast<MusicSeq>(i);
play_sequence(gWorldInstance.CurrentCourse->Props.Sequence); // Call play_sequence with the updated sequence
// Update currentItem after selection is made
currentItem = items[i];
}
if (isSelected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
}
// Enum to string conversion
const char* TrackPropertiesWindow::MusicSeqToString(MusicSeq seq) {
switch (seq) {
case MUSIC_SEQ_00: return "None";
case MUSIC_SEQ_TITLE_SCREEN: return "Title Screen";
case MUSIC_SEQ_MAIN_MENU: return "Main Menu";
case MUSIC_SEQ_RACEWAYS_WARIO_STADIUM: return "Raceways Wario Stadium";
case MUSIC_SEQ_MOO_MOO_FARM_YOSHI_VALLEY: return "Moo Moo Farm / Yoshi Valley";
case MUSIC_SEQ_CHOCO_MOUNTAIN: return "Choco Mountain";
case MUSIC_SEQ_KOOPA_TROOPA_BEACH: return "Koopa Troopa Beach";
case MUSIC_SEQ_BANSHEE_BOARDWALK: return "Banshee Boardwalk";
case MUSIC_SEQ_FRAPPE_SNOWLAND: return "Frappe Snowland";
case MUSIC_SEQ_BOWSERS_CASTLE: return "Bowser's Castle";
case MUSIC_SEQ_KALIMARI_DESERT: return "Kalimari Desert";
case MUSIC_SEQ_START_GRID_GP_VS: return "Start Grid GP/VS";
case MUSIC_SEQ_FINAL_LAP_FANFARE: return "Final Lap Fanfare";
case MUSIC_SEQ_FINISH_1ST_PLACE: return "Finish 1st Place";
case MUSIC_SEQ_FINISH_2ND_4TH_PLACE: return "Finish 2nd-4th Place";
case MUSIC_SEQ_FINISH_5TH_8TH_PLACE: return "Finish 5th-8th Place";
case MUSIC_SEQ_16: return "16";
case MUSIC_SEQ_STAR_JINGLE: return "Star Jingle";
case MUSIC_SEQ_RAINBOW_ROAD: return "Rainbow Road";
case MUSIC_SEQ_DK_JUNGLE: return "DK Jungle";
case MUSIC_SEQ_GAME_OVER: return "Game Over";
case MUSIC_SEQ_TOADS_TURNPIKE: return "Toad's Turnpike";
case MUSIC_SEQ_START_GIRD_TIME_ATTACK: return "Start Grid Time Attack";
case MUSIC_SEQ_VS_BATTLE_RESULTS: return "VS Battle Results";
case MUSIC_SEQ_LOSING_RESULTS: return "Losing Results";
case MUSIC_SEQ_BATTLE_ARENAS: return "Battle Arenas";
case MUSIC_SEQ_AWARD_CEREMONY_BUILDUP: return "Award Ceremony Buildup";
case MUSIC_SEQ_AWARD_CEREMONY_1ST_3RD: return "Award Ceremony 1st-3rd";
case MUSIC_SEQ_STAFF_ROLL: return "Staff Roll";
case MUSIC_SEQ_AWARD_CEREMONY_4TH_8TH: return "Award Ceremony 4th-8th";
default: return "None";
}
}
void TrackPropertiesWindow::DrawLight() {
// Convert and pass to ImGui ColorEdit3
for (int i = 0; i < 2; ++i) {
float ambient[3], diffuse[3], direction[3];
RGB8ToFloat((u8*)&D_800DC610[i].a.l.col, ambient);
RGB8ToFloat((u8*)&D_800DC610[i].l->l.col, diffuse);
RGB8ToFloat((u8*)&D_800DC610[i].l->l.dir, direction);
// Edit the ambient RGB color
ImGui::Text("Light %d - Ambient Color", i + 1);
ImGui::ColorEdit3(("Ambient Color " + std::to_string(i)).c_str(), (float*)&ambient); // Modify ambient color
// Edit the diffuse RGB color
ImGui::Text("Light %d - Diffuse Color", i + 1);
ImGui::ColorEdit3(("Diffuse Color " + std::to_string(i)).c_str(), (float*)&diffuse); // Modify diffuse color
// Edit the direction RGB color (this could be represented as a direction vector)
ImGui::Text("Light %d - Direction", i + 1);
ImGui::ColorEdit3(("Direction Color " + std::to_string(i)).c_str(), (float*)&direction); // Modify direction vector color
FloatToRGB8(ambient, (u8*)&D_800DC610[i].a.l.col);
FloatToRGB8(ambient, (u8*)&D_800DC610[i].a.l.colc);
FloatToRGB8(diffuse, (u8*)&D_800DC610[i].l->l.col);
FloatToRGB8(diffuse, (u8*)&D_800DC610[i].l->l.colc);
FloatToRGB8(direction, (u8*)&D_800DC610[i].l->l.dir);
}
}
// Convert s16 color values to float (normalized to [0, 1] range)
void TrackPropertiesWindow::RGB8ToFloat(const u8* src, float* dst) {
for (int i = 0; i < 3; ++i) {
dst[i] = src[i] / 255.0f; // Normalize to the range [0.0f, 1.0f]
}
}
void TrackPropertiesWindow::FloatToRGB8(const float* src, u8* dst) {
for (int i = 0; i < 3; ++i) {
dst[i] = static_cast<u8>(src[i] * 255.0f); // Scale to [0, 255] range
}
}
}
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <libultraship/libultraship.h>
extern "C" {
#include "sounds.h"
}
namespace EditorNamespace {
class TrackPropertiesWindow : public Ship::GuiWindow {
public:
using Ship::GuiWindow::GuiWindow;
~TrackPropertiesWindow();
protected:
void InitElement() override {};
void DrawElement() override;
void DrawMusic();
void DrawLight();
void UpdateElement() override {};
void RGB8ToFloat(const u8* src, float* dst);
void FloatToRGB8(const float* src, u8* dst);
const char* MusicSeqToString(MusicSeq seq);
};
}
+1
View File
@@ -1512,4 +1512,5 @@ void load_course(s32 courseId) {
gNextFreeMemoryAddress = gFreeMemoryResetAnchor;
CM_CleanWorld();
LoadCourse();
CM_Editor_SetLevelDimensions(gCourseMinX, gCourseMaxX, gCourseMinZ, gCourseMaxZ, gCourseMinY, gCourseMaxY);
}