diff --git a/include/functions.h b/include/functions.h index b85f8490c..c9c845e4a 100644 --- a/include/functions.h +++ b/include/functions.h @@ -89,6 +89,7 @@ void Cutscene_DrawGreatFox(void); // fox_display void Display_ArwingWings(ArwingInfo*); void Display_DrawEngineGlow(EngineGlowColor); +void Display_DrawEngineGlowCustom(Color_RGBA8 primary, Color_RGBA8 secondary); //u8 r, u8 g, u8 b, u8 a); void Display_SetupPlayerSfxPos(Player*); void Display_Update(void); @@ -114,6 +115,8 @@ void CoBuilding10_Draw(Scenery*); void ActorDebris_Draw(Actor*); void Actor_DrawEngineAndContrails(Actor*); void Actor_DrawEngineGlow(Actor*, EngineGlowColor); +void Actor_DrawEngineAndContrailsCustom(Actor*, Color_RGBA8 primary, Color_RGBA8 secondary); +void Actor_DrawEngineGlowCustom(Actor*,Color_RGBA8 primary, Color_RGBA8 secondary); void ActorTeamArwing_Draw(Actor*); void MeMolarRock_Draw(Actor*); void MeMeteor2_Draw(MeMeteor2*); diff --git a/src/engine/fox_360.c b/src/engine/fox_360.c index 034b9bf08..6bcad207d 100644 --- a/src/engine/fox_360.c +++ b/src/engine/fox_360.c @@ -8,6 +8,8 @@ #include "assets/ast_versus.h" #include "assets/ast_enmy_planet.h" #include "assets/ast_sector_z.h" +#include "port/ui/CosmeticEditor.h" + typedef enum ActorAllRangeState { STATE360_0, @@ -2383,15 +2385,19 @@ void ActorAllRange_Draw(ActorAllRange* this) { case AI360_LEON: case AI360_PIGMA: case AI360_ANDREW: + { //For some reason this won't compile on MacOS unless I add these braces. + bool cosmeticGlowChanged = gCosmeticEngineGlowChanged(gLevelType, COSMETIC_GLOW_WOLFEN); + Color_RGBA8 customColorPrimary = gCosmeticEngineGlowColor(gLevelType, COSMETIC_GLOW_WOLFEN, false); + Color_RGBA8 customColorSecondary = gCosmeticEngineGlowColor(gLevelType, COSMETIC_GLOW_WOLFEN, true); if (gCurrentLevel == LEVEL_VENOM_2) { gSPDisplayList(gMasterDisp++, aStarWolfUpgradedShipDL); Matrix_Push(&gGfxMatrix); Matrix_Translate(gGfxMatrix, 30.0f, 0.0f, -60.0f, MTXF_APPLY); - Actor_DrawEngineGlow(this, EG_GREEN); + cosmeticGlowChanged ? Actor_DrawEngineGlowCustom(this, customColorPrimary, customColorSecondary) : Actor_DrawEngineGlow(this, EG_GREEN); Matrix_Pop(&gGfxMatrix); Matrix_Push(&gGfxMatrix); Matrix_Translate(gGfxMatrix, -30.0f, 0.0f, -60.0f, MTXF_APPLY); - Actor_DrawEngineGlow(this, EG_GREEN); + cosmeticGlowChanged ? Actor_DrawEngineGlowCustom(this, customColorPrimary, customColorSecondary) : Actor_DrawEngineGlow(this, EG_GREEN); Matrix_Pop(&gGfxMatrix); ActorAllRange_DrawBarrelRoll(this); ActorAllRange_DrawShield(this); @@ -2399,12 +2405,13 @@ void ActorAllRange_Draw(ActorAllRange* this) { gSPDisplayList(gMasterDisp++, aStarWolfStandardShipDL); Matrix_Translate(gGfxMatrix, 0.0f, 0.0f, -60.0f, MTXF_APPLY); if (gCurrentLevel == LEVEL_BOLSE) { - Actor_DrawEngineGlow(this, EG_ORANGE); + cosmeticGlowChanged ? Actor_DrawEngineGlowCustom(this, customColorPrimary, customColorSecondary) : Actor_DrawEngineGlow(this, EG_ORANGE); } else { - Actor_DrawEngineGlow(this, EG_GREEN); + cosmeticGlowChanged ? Actor_DrawEngineGlowCustom(this, customColorPrimary, customColorSecondary) : Actor_DrawEngineGlow(this, EG_GREEN); } } break; + } case AI360_KATT: gSPDisplayList(gMasterDisp++, aKattShipDL); diff --git a/src/engine/fox_display.c b/src/engine/fox_display.c index 38135a6ef..45604a583 100644 --- a/src/engine/fox_display.c +++ b/src/engine/fox_display.c @@ -7,6 +7,7 @@ #include "assets/ast_sector_z.h" #include "port/interpolation/FrameInterpolation.h" #include "port/hooks/list/EngineEvent.h" +#include "port/ui/CosmeticEditor.h" // f32 path1 = 0.0f; // f32 path2 = 0.0f; @@ -898,6 +899,13 @@ void Display_DrawEngineGlow(EngineGlowColor color) { } gSPDisplayList(gMasterDisp++, aOrbDL); } +void Display_DrawEngineGlowCustom(Color_RGBA8 primary, Color_RGBA8 secondary){ + RCP_SetupDL(&gMasterDisp, SETUPDL_67); + //Despite the names primary/secondary not matching, that's their behavior in game. Maybe rename them to inner and outer glows would work better + gDPSetPrimColor(gMasterDisp++, 0x00, 0x00, secondary.r, secondary.g, secondary.b, secondary.a); + gDPSetEnvColor(gMasterDisp++, primary.r, primary.g, primary.b, primary.a); + gSPDisplayList(gMasterDisp++, aOrbDL); +} void Display_LandmasterEngineGlow_Draw(Player* player) { RCP_SetupDL_64(); @@ -920,7 +928,15 @@ void Display_LandmasterEngineGlow_Draw(Player* player) { Matrix_Scale(gGfxMatrix, 0.9f * 0.9f, 0.9f * 0.63f, 1.0f, MTXF_APPLY); } Matrix_SetGfxMtx(&gMasterDisp); - Display_DrawEngineGlow(gLevelType); + if (gCosmeticEngineGlowChanged(gLevelType, COSMETIC_GLOW_ARWING)){ + Color_RGBA8 customColorPrimary = gCosmeticEngineGlowColor(gLevelType, COSMETIC_GLOW_ARWING, false); + Color_RGBA8 customColorSecondary = gCosmeticEngineGlowColor(gLevelType, COSMETIC_GLOW_ARWING, true); + + Display_DrawEngineGlowCustom(customColorPrimary,customColorSecondary); + } + else{ + Display_DrawEngineGlow(gLevelType); + } Matrix_Pop(&gGfxMatrix); } diff --git a/src/engine/fox_edisplay.c b/src/engine/fox_edisplay.c index 38af6894a..dd03cb5fb 100644 --- a/src/engine/fox_edisplay.c +++ b/src/engine/fox_edisplay.c @@ -29,6 +29,7 @@ #include "assets/ast_zoness.h" #include "port/interpolation/FrameInterpolation.h" #include "port/hooks/Events.h" +#include "port/ui/CosmeticEditor.h" Vec3f D_edisplay_801615D0; Vec3f sViewPos; @@ -529,7 +530,65 @@ void Actor_DrawEngineAndContrails(Actor* this) { Matrix_Pop(&gGfxMatrix); } } +void Actor_DrawEngineAndContrailsCustom(Actor* this, Color_RGBA8 primary, Color_RGBA8 secondary) { + f32 sp5C; + f32 temp1; + f32 sp54; + s32 pad[5]; + + if ((this->iwork[11] != 0) && (this->obj.status == OBJ_ACTIVE)) { + temp1 = 652.5f * 0.001f; // 0.65250003f; + if (this->iwork[11] >= 2) { + temp1 = 1.3050001f; + } + Math_SmoothStepToF(&this->fwork[29], temp1, 0.3f, 5.0f, 0.0f); + + sp5C = this->fwork[29]; + if ((gGameFrameCount % 2) != 0) { + sp5C *= 1.111f; + } + Matrix_Push(&gGfxMatrix); + Matrix_Translate(gGfxMatrix, 0.0f, 0.0f, -60.0f, MTXF_APPLY); + Matrix_Scale(gGfxMatrix, sp5C, sp5C * 0.7f, sp5C, MTXF_APPLY); + Matrix_RotateZ(gGfxMatrix, -this->obj.rot.z * M_DTOR, MTXF_APPLY); + Matrix_RotateX(gGfxMatrix, -this->obj.rot.x * M_DTOR, MTXF_APPLY); + Matrix_RotateY(gGfxMatrix, -this->obj.rot.y * M_DTOR, MTXF_APPLY); + Matrix_RotateY(gGfxMatrix, -gPlayer[gPlayerNum].camYaw, MTXF_APPLY); + Matrix_RotateX(gGfxMatrix, gPlayer[gPlayerNum].camPitch, MTXF_APPLY); + Matrix_SetGfxMtx(&gMasterDisp); + Display_DrawEngineGlowCustom(primary, secondary); + Matrix_Pop(&gGfxMatrix); + } + + sp5C = this->fwork[21]; + if ((sp5C != 0.0f) && (gLevelType == LEVELTYPE_PLANET)) { + sp54 = 0.0f; + if ((gGameFrameCount % 2) != 0) { + sp54 = 180.0f; + } + RCP_SetupDL_64_2(); + gDPSetPrimColor(gMasterDisp++, 0x00, 0x00, 255, 255, 255, 100); + Matrix_Push(&gGfxMatrix); + Matrix_Translate(gGfxMatrix, 70.0f, -10.0f, -100.0f, MTXF_APPLY); + Matrix_Scale(gGfxMatrix, sp5C, 1.0f, 50.0f, MTXF_APPLY); + Matrix_Translate(gGfxMatrix, 0.0f, 0.0f, -17.5f, MTXF_APPLY); + Matrix_RotateX(gGfxMatrix, M_PI / 2, MTXF_APPLY); + Matrix_RotateY(gGfxMatrix, M_DTOR * sp54, MTXF_APPLY); + Matrix_SetGfxMtx(&gMasterDisp); + gSPDisplayList(gMasterDisp++, aBallDL); + Matrix_Pop(&gGfxMatrix); + Matrix_Push(&gGfxMatrix); + Matrix_Translate(gGfxMatrix, -70.0f, -10.0f, -100.0f, MTXF_APPLY); + Matrix_Scale(gGfxMatrix, sp5C, 1.0f, 50.0f, MTXF_APPLY); + Matrix_Translate(gGfxMatrix, 0.0f, 0.0f, -17.5f, MTXF_APPLY); + Matrix_RotateX(gGfxMatrix, M_PI / 2, MTXF_APPLY); + Matrix_RotateY(gGfxMatrix, M_DTOR * sp54, MTXF_APPLY); + Matrix_SetGfxMtx(&gMasterDisp); + gSPDisplayList(gMasterDisp++, aBallDL); + Matrix_Pop(&gGfxMatrix); + } +} f32 D_edisplay_800CFCA0[] = { 1.7f, 1.8f, 2.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f, }; @@ -556,7 +615,28 @@ void Actor_DrawEngineGlow(Actor* actor, EngineGlowColor color) { Matrix_Pop(&gGfxMatrix); } } +void Actor_DrawEngineGlowCustom(Actor* actor, Color_RGBA8 primary, Color_RGBA8 secondary){ + f32 scale; + if ((actor->iwork[11] != 0) && (actor->obj.status == OBJ_ACTIVE)) { + scale = 0.63f; + if (actor->iwork[11] >= 2) { + scale = D_edisplay_800CFCA0[actor->iwork[11] - 2] * 0.45f; + } + if ((gGameFrameCount % 2) != 0) { + scale *= 1.2f; + } + Matrix_Push(&gGfxMatrix); + Matrix_Scale(gGfxMatrix, scale, scale, scale, MTXF_APPLY); + Matrix_RotateZ(gGfxMatrix, -actor->obj.rot.z * M_DTOR, MTXF_APPLY); + Matrix_RotateX(gGfxMatrix, -actor->obj.rot.x * M_DTOR, MTXF_APPLY); + Matrix_RotateY(gGfxMatrix, -actor->obj.rot.y * M_DTOR, MTXF_APPLY); + Matrix_RotateY(gGfxMatrix, -gPlayer[gPlayerNum].camYaw, MTXF_APPLY); + Matrix_SetGfxMtx(&gMasterDisp); + Display_DrawEngineGlowCustom(primary, secondary); + Matrix_Pop(&gGfxMatrix); + } +} void ActorTeamArwing_Draw(ActorTeamArwing* this) { Vec3f src = { 0.0f, 0.0f, 0.0f }; Vec3f dest; @@ -606,7 +686,15 @@ void ActorTeamArwing_Draw(ActorTeamArwing* this) { } else { gSPDisplayList(gMasterDisp++, D_ENMY_SPACE_4007870); } - Actor_DrawEngineAndContrails(this); + if (gCosmeticEngineGlowChanged(gLevelType, COSMETIC_GLOW_ARWING)){ + Color_RGBA8 customColorPrimary = gCosmeticEngineGlowColor(gLevelType, COSMETIC_GLOW_ARWING, false); + Color_RGBA8 customColorSecondary = gCosmeticEngineGlowColor(gLevelType, COSMETIC_GLOW_ARWING, true); + + Actor_DrawEngineAndContrailsCustom(this, customColorPrimary, customColorSecondary); + } + else{ + Actor_DrawEngineAndContrails(this); + } } void MeMolarRock_Draw(MeMolarRock* this) { diff --git a/src/engine/fox_enmy2.c b/src/engine/fox_enmy2.c index 9553d3a23..7c9217fc5 100644 --- a/src/engine/fox_enmy2.c +++ b/src/engine/fox_enmy2.c @@ -21,6 +21,7 @@ #include "assets/ast_ve1_boss.h" #include "assets/ast_zoness.h" #include "port/hooks/Events.h" +#include "port/ui/CosmeticEditor.h" s32 gTeamEventActorIndex[4] = { 0, 0, 0, 0 }; s32 gCallVoiceParam = 0; @@ -3981,7 +3982,15 @@ void ActorEvent_Draw(ActorEvent* this) { } else { gSPDisplayList(gMasterDisp++, D_ENMY_SPACE_4007870); } - Actor_DrawEngineAndContrails(this); + if (gCosmeticEngineGlowChanged(gLevelType, COSMETIC_GLOW_ARWING)){ + Color_RGBA8 customColorPrimary = gCosmeticEngineGlowColor(gLevelType, COSMETIC_GLOW_ARWING, false); + Color_RGBA8 customColorSecondary = gCosmeticEngineGlowColor(gLevelType, COSMETIC_GLOW_ARWING, true); + + Actor_DrawEngineAndContrailsCustom(this, customColorPrimary, customColorSecondary); + } + else{ + Actor_DrawEngineAndContrails(this); + } break; case EVID_GRANGA_FIGHTER_2: diff --git a/src/engine/fox_hud.c b/src/engine/fox_hud.c index 051ec0b65..df779a411 100644 --- a/src/engine/fox_hud.c +++ b/src/engine/fox_hud.c @@ -2,6 +2,7 @@ #include "fox_hud.h" #include "prevent_bss_reordering.h" #include "port/interpolation/FrameInterpolation.h" +#include "port/ui/CosmeticEditor.h" #include "port/hooks/Events.h" Vec3f D_801616A0; @@ -1777,6 +1778,11 @@ void HUD_RadarMark_Arwing_Draw(s32 colorIdx) { { 177, 242, 12, 255 }, { 89, 121, 6, 128 }, { 90, 90, 255, 255 }, { 45, 45, 128, 128 }, { 0, 179, 67, 255 }, { 0, 90, 34, 128 }, { 255, 30, 0, 255 }, { 128, 15, 0, 128 }, }; + char* arwingMarkColorOverrides[] = { "Radar.Fox", "Radar.Fox_Dark", + "Radar.Falco", "Radar.Falco_Dark", + "Radar.Slippy", "Radar.Slippy_Dark", + "Radar.Peppy", "Radar.Peppy_Dark" + }; f32 var_fv1; f32 var_fv2; @@ -1789,16 +1795,16 @@ void HUD_RadarMark_Arwing_Draw(s32 colorIdx) { } RCP_SetupDL(&gMasterDisp, SETUPDL_62); - gDPSetPrimColor(gMasterDisp++, 0, 0, arwingMarkColor[colorIdx][0], arwingMarkColor[colorIdx][1], - arwingMarkColor[colorIdx][2], arwingMarkColor[colorIdx][3]); + gDPSetPrimColorWithOverride(gMasterDisp++, 0, 0, arwingMarkColor[colorIdx][0], arwingMarkColor[colorIdx][1], + arwingMarkColor[colorIdx][2], arwingMarkColor[colorIdx][3], arwingMarkColorOverrides[colorIdx]); Matrix_Scale(gGfxMatrix, var_fv1, var_fv2, 1.0f, MTXF_APPLY); Matrix_SetGfxMtx(&gMasterDisp); gSPDisplayList(gMasterDisp++, aRadarMarkArwingDL); } -void HUD_RadarMark_StarWolf_Draw(void) { +void HUD_RadarMark_StarWolf_Draw(char* colorOverride) { RCP_SetupDL(&gMasterDisp, SETUPDL_62); - gDPSetPrimColor(gMasterDisp++, 0, 0, 0, 0, 0, 255); + gDPSetPrimColorWithOverride(gMasterDisp++, 0, 0, 0, 0, 0, 255, colorOverride); Matrix_Scale(gGfxMatrix, 54.0f, 54.0f, 1.0f, MTXF_APPLY); Matrix_SetGfxMtx(&gMasterDisp); gSPDisplayList(gMasterDisp++, aStarWolfRadarMarkDL); @@ -1890,10 +1896,16 @@ void HUD_RadarMark_Draw(s32 type) { break; case RADARMARK_WOLF: + HUD_RadarMark_StarWolf_Draw("Radar.Wolf"); + break; case RADARMARK_LEON: + HUD_RadarMark_StarWolf_Draw("Radar.Leon"); + break; case RADARMARK_PIGMA: + HUD_RadarMark_StarWolf_Draw("Radar.Pigma"); + break; case RADARMARK_ANDREW: - HUD_RadarMark_StarWolf_Draw(); + HUD_RadarMark_StarWolf_Draw("Radar.Andrew"); break; case RADARMARK_KATT: diff --git a/src/port/ui/CosmeticEditor.cpp b/src/port/ui/CosmeticEditor.cpp new file mode 100644 index 000000000..edd6cba6b --- /dev/null +++ b/src/port/ui/CosmeticEditor.cpp @@ -0,0 +1,325 @@ +#include "CosmeticEditor.h" +#include "port/ui/UIWidgets.h" +#include "macros.h" + +std::vector cosmeticEditorParentElements; + + +CosmeticEditorElement cosmeticEditorElements[COSMETIC_ELEMENT_MAX] = { + COSMETIC_EDITOR_ELEMENT(COSMETIC_ELEMENT_FOX_RADAR_COLOR, "Radar (Star Fox)", "Fox", "Radar.Fox", 177, 242, 12, 255), + COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_FOX_RADAR_COLOR_DARK, "Radar (Star Fox)", "", "Radar.Fox_Dark", 89, 121, 6, 128, COSMETIC_ELEMENT_FOX_RADAR_COLOR, 0.5f), + COSMETIC_EDITOR_ELEMENT(COSMETIC_ELEMENT_FALCO_RADAR_COLOR, "Radar (Star Fox)", "Falco", "Radar.Falco", 90, 90, 255, 255), + // COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_FALCO_RADAR_COLOR_DARK, "Radar (Star Fox)", "Falco (Blink)", "Radar.Falco_Dark", 45, 45, 128, 128, COSMETIC_ELEMENT_FALCO_RADAR_COLOR, 0.5f), + COSMETIC_EDITOR_ELEMENT(COSMETIC_ELEMENT_PEPPY_RADAR_COLOR, "Radar (Star Fox)", "Peppy", "Radar.Peppy", 255, 30, 0, 255), + // COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_PEPPY_RADAR_COLOR_DARK, "Radar (Star Fox)", "Peppy (Blink)", "Radar.Peppy_Dark", 128, 15, 0, 128, COSMETIC_ELEMENT_PEPPY_RADAR_COLOR, 0.5f), + COSMETIC_EDITOR_ELEMENT(COSMETIC_ELEMENT_SLIPPY_RADAR_COLOR, "Radar (Star Fox)", "Slippy", "Radar.Slippy", 0, 179, 67, 255), + // COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_SLIPPY_RADAR_COLOR_DARK, "Radar (Star Fox)", "Slippy (Blink)", "Radar.Slippy_Dark", 0, 90, 34, 128, COSMETIC_ELEMENT_SLIPPY_RADAR_COLOR, 0.5f), + + COSMETIC_EDITOR_ELEMENT(COSMETIC_ELEMENT_WOLF_RADAR_COLOR, "Radar (Star Wolf)", "Wolf", "Radar.Wolf", 0, 0, 0, 255), + COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_LEON_RADAR_COLOR, "Radar (Star Wolf)", "Leon", "Radar.Leon", 0, 0, 0, 255, COSMETIC_ELEMENT_WOLF_RADAR_COLOR, 1.0f), + COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_PIGMA_RADAR_COLOR, "Radar (Star Wolf)", "Pigma", "Radar.Pigma", 0, 0, 0, 255, COSMETIC_ELEMENT_WOLF_RADAR_COLOR, 1.0f), + COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_ANDREW_RADAR_COLOR, "Radar (Star Wolf)", "Andrew", "Radar.Andrew", 0, 0, 0, 255, COSMETIC_ELEMENT_WOLF_RADAR_COLOR, 1.0f), + + COSMETIC_EDITOR_ELEMENT(COSMETIC_ELEMENT_ARWING_ENGINE_PLANET, "Arwing Engine Glows", "Atmosphere", "Engine.Arwing.Planet", 255, 0, 0, 255), + COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_ARWING_ENGINE_PLANET_SECONDARY, "Arwing Engine Glows", "", "Engine.Arwing.Planet_Secondary", 255, 255, 255, 255, COSMETIC_ELEMENT_ARWING_ENGINE_PLANET, 1.0f), + COSMETIC_EDITOR_ELEMENT(COSMETIC_ELEMENT_ARWING_ENGINE_SPACE, "Arwing Engine Glows", "Space", "Engine.Arwing.Space", 0, 0, 255, 255), + COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_ARWING_ENGINE_SPACE_SECONDARY, "Arwing Engine Glows", "", "Engine.Arwing.Space_Secondary", 255, 255, 255, 255, COSMETIC_ELEMENT_ARWING_ENGINE_SPACE, 1.0f), + + COSMETIC_EDITOR_ELEMENT(COSMETIC_ELEMENT_WOLFEN_ENGINE_PLANET, "Wolfen Engine Glows", "Atmosphere", "Engine.Wolfen.Planet", 0, 255, 0, 255), + COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_WOLFEN_ENGINE_PLANET_SECONDARY, "Wolfen Engine Glows", "", "Engine.Wolfen.Planet_Secondary", 255, 255, 255, 255, COSMETIC_ELEMENT_WOLFEN_ENGINE_PLANET, 1.0f), + COSMETIC_EDITOR_ELEMENT(COSMETIC_ELEMENT_WOLFEN_ENGINE_SPACE, "Wolfen Engine Glows", "Space", "Engine.Wolfen.Space", 255, 64, 0, 255), + COSMETIC_EDITOR_DERIVED_ELEMENT(COSMETIC_ELEMENT_WOLFEN_ENGINE_SPACE_SECONDARY, "Wolfen Engine Glows", "", "Engine.Wolfen.Space_Secondary", 255, 255, 255, 255, COSMETIC_ELEMENT_WOLFEN_ENGINE_SPACE, 1.0f), + +}; + +void CopyFloatArray(CosmeticEditorElementID id, float currentColor[4], bool isChanged) { + if (isChanged) { + Color_RGBA8 changedColor = CVarGetColor(cosmeticEditorElements[id].colorCvar, {}); + currentColor[0] = changedColor.r / 255.0f; + currentColor[1] = changedColor.g / 255.0f; + currentColor[2] = changedColor.b / 255.0f; + currentColor[3] = changedColor.a / 255.0f; + } else { + currentColor[0] = cosmeticEditorElements[id].defaultR / 255.0f; + currentColor[1] = cosmeticEditorElements[id].defaultG / 255.0f; + currentColor[2] = cosmeticEditorElements[id].defaultB / 255.0f; + currentColor[3] = cosmeticEditorElements[id].defaultA / 255.0f; + } +}; + +Color_RGBA8 CosmeticEditor_getChangedColor(u8 r, u8 g, u8 b, u8 a, const char* cvar) { + std::string cvarString = "gCosmetic."; + cvarString += cvar; + + Color_RGBA8 returnedColor; + + if (CVarGetInteger((cvarString + ".Changed").c_str(), false)) { + Color_RGBA8 changedColor = CVarGetColor((cvarString + ".Color").c_str(), {}); + float gammaBoost = CVarGetInteger("gGraphics.GammaMode", 1) == 1 ? 2.14f : 1.0f; // We want to not distort the color the user chooses. + returnedColor.r = static_cast(ImPow(changedColor.r/256.f, (gammaBoost))*256.f); + returnedColor.g = static_cast(ImPow(changedColor.g/256.f, (gammaBoost))*256.f); + returnedColor.b = static_cast(ImPow(changedColor.b/256.f, (gammaBoost))*256.f); + returnedColor.a = static_cast(changedColor.a); + } else { + returnedColor.r = r; + returnedColor.g = g; + returnedColor.b = b; + returnedColor.a = a; + } + + return returnedColor; +} + +extern "C" void gDPSetPrimColorWithOverride(Gfx* pkt, u8 m, u8 l, u8 r, u8 g, u8 b, u8 a, const char* cvar) { + Color_RGBA8 setColor = CosmeticEditor_getChangedColor(r, g, b, a, cvar); + gDPSetPrimColor(pkt, m, l, setColor.r, setColor.g, setColor.b, setColor.a); +} +extern "C" void gDPSetEnvColorWithOverride(Gfx* pkt, u8 r, u8 g, u8 b, u8 a, const char* cvar){ + Color_RGBA8 setColor = CosmeticEditor_getChangedColor(r, g, b, a, cvar); + gDPSetEnvColor(pkt, setColor.r, setColor.g, setColor.b, setColor.a); +} + +std::vector GetAllDerivedFrom(CosmeticEditorElementID id) +{ + std::vector Found; + u8 i = 0; + for (auto& entry : cosmeticEditorElements) { + if (entry.derivedFrom == id) + { + Found.push_back(entry.id); + } + } + + return Found; +} + +extern "C" const char* GetEngineGlowString(CosmeticEngineGlow glow) +{ + switch (glow){ + case COSMETIC_GLOW_ARWING: + return "Arwing"; + case COSMETIC_GLOW_WOLFEN: + return "Wolfen"; + default: //temp + return "Arwing"; + } +} + + +extern "C" bool gCosmeticEngineGlowChanged(u8 levelType, CosmeticEngineGlow glowType){ + const char* glowString = GetEngineGlowString(glowType); + const char* levelTypeString = levelType == 0 ? "Planet" : "Space"; + const char* suffix = "_Secondary"; + + char cVarString[200]; + sprintf(cVarString, "gCosmetic.Engine.%s.%s.Changed", glowString, levelTypeString); + + char cVarStringSecondary[200]; + sprintf(cVarStringSecondary, "gCosmetic.Engine.%s.%s%s.Changed" , glowString, levelTypeString, suffix); + + return CVarGetInteger(cVarString, 0) || CVarGetInteger(cVarStringSecondary, 0); +} +extern "C" Color_RGBA8 gCosmeticEngineGlowColor(u8 levelType, CosmeticEngineGlow glowType, bool secondary){ + const char* glowString = GetEngineGlowString(glowType); + const char* levelTypeString = levelType == 0 ? "Planet" : "Space"; + const char* suffix = secondary ? "_Secondary" : ""; + char cVarString[200]; + sprintf(cVarString, "Engine.%s.%s%s" , glowString, levelTypeString, suffix); + return CosmeticEditor_getChangedColor(255,0,255, 255, cVarString); //Magenta to detect issues +} +void CosmeticEditorRandomizeElement(CosmeticEditorElement id) { + Color_RGBA8 colorSelected; + colorSelected.r = static_cast((rand() % 256) * 255.0f); + colorSelected.g = static_cast((rand() % 256) * 255.0f); + colorSelected.b = static_cast((rand() % 256) * 255.0f); + colorSelected.a = static_cast((rand() % 256) * 255.0f); + + CVarSetColor(id.colorCvar, colorSelected); + CVarSetInteger(id.colorChangedCvar, true); +} + +bool CosmeticEditorCompareColors(Color_RGBA8 first, Color_RGBA8 second){ + return (first.r == second.r && first.g == second.g && first.b == second.b && first.a == second.a); +} + +void CosmeticEditorCalculateDerivedElement(CosmeticEditorElement entry) { + if (entry.derivedFrom == COSMETIC_ELEMENT_NONE) { + return; + } + CosmeticEditorElement originalEntry = cosmeticEditorElements[entry.derivedFrom]; + Color_RGBA8 myDefault = {entry.defaultR, entry.defaultG, entry.defaultB, entry.defaultA}; + Color_RGBA8 original = CVarGetColor(originalEntry.colorCvar, {originalEntry.defaultR, originalEntry.defaultG, originalEntry.defaultB, originalEntry.defaultA}); + Color_RGBA8 result; + result.r = static_cast(CLAMP(original.r * entry.multiplier, 0, 255)); + result.g = static_cast(CLAMP(original.g * entry.multiplier, 0, 255)); + result.b = static_cast(CLAMP(original.b * entry.multiplier, 0, 255)); + result.a = static_cast(CLAMP(original.a * entry.multiplier, 0, 255)); + + CVarSetColor(entry.colorCvar, result); + CVarSetInteger(entry.colorChangedCvar, CVarGetInteger(originalEntry.colorChangedCvar, 0)); +} + + +void CosmeticEditorRandomizeAllElements() { + for (auto& element : cosmeticEditorElements) { + CosmeticEditorRandomizeElement(element); + } +} + +void CosmeticEditorResetAllElements() { + for (auto& element : cosmeticEditorElements) { + CVarClear(element.colorCvar); + CVarClear(element.colorChangedCvar); + } +} + +void CosmeticEditorCalculateAllDerived() { + for (auto& element : cosmeticEditorElements) { + if (element.derivedFrom != COSMETIC_ELEMENT_NONE){ + CosmeticEditorCalculateDerivedElement(element); + } + } +} +void CosmeticEditorDrawColorTab() { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 1.0f, 1.0f, 0.2f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 0.1f)); + std::string resetAllText = ICON_FA_UNDO; + resetAllText += " All"; + std::string randomAllText = ICON_FA_RECYCLE; + randomAllText += " All"; + std::string calculateAllText = ICON_FA_ARROW_DOWN; + calculateAllText += " All"; + if (ImGui::Button(resetAllText.c_str())) { + CosmeticEditorResetAllElements(); + } + UIWidgets::Tooltip("Resets All Elements to their Defaults"); + ImGui::SameLine(); + if (ImGui::Button(randomAllText.c_str())) { + CosmeticEditorRandomizeAllElements(); + } + ImGui::SameLine(); + if (ImGui::Button(calculateAllText.c_str())) { + CosmeticEditorCalculateAllDerived(); + } + UIWidgets::Tooltip("Randomizes All Elements"); + for (auto& parent : cosmeticEditorParentElements) { + ImGui::SeparatorText(parent); + ImGui::BeginTable(parent, 2); + ImGui::TableSetupColumn("Element Name", ImGuiTableColumnFlags_WidthStretch, 1.4f); + ImGui::TableSetupColumn("Options", ImGuiTableColumnFlags_WidthStretch, 2.0f); + for (auto& entry : cosmeticEditorElements) { + if (parent != entry.parentName) { + continue; + } + bool derived = entry.derivedFrom != COSMETIC_ELEMENT_NONE; + if (entry.name == "" && derived) { //Is a subEntry + continue; + } + + float currentColor[4]; + + ImGui::PushID(entry.id); + ImGui::TableNextColumn(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + + ((ImGui::GetFrameHeight() - (ImGui::CalcTextSize(entry.name).y)) / 2.0f)); + ImGui::Text(entry.name); + ImGui::TableNextColumn(); + CopyFloatArray(entry.id, currentColor, CVarGetInteger(entry.colorChangedCvar, false)); + bool colorChanged = + ImGui::ColorEdit4("Color", currentColor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel); + + std::vector subEntries = GetAllDerivedFrom(entry.id); + bool subEntryChanged = false; + for (int i = 0; i < subEntries.size(); i++){ + + float currentSecondaryColor[4]; + ImGui::SameLine(); + CosmeticEditorElement subEntry = cosmeticEditorElements[subEntries[i]]; + if (subEntry.name != "") { + continue; + } + CopyFloatArray(subEntry.id, currentSecondaryColor, CVarGetInteger(subEntry.colorChangedCvar, false)); + bool secondaryColorChanged = + ImGui::ColorEdit4("SubColor", currentSecondaryColor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel); + if (secondaryColorChanged || colorChanged) { + subEntryChanged = true; + Color_RGBA8 colorSelected; + colorSelected.r = static_cast(currentSecondaryColor[0] * 255.0f); + colorSelected.g = static_cast(currentSecondaryColor[1] * 255.0f); + colorSelected.b = static_cast(currentSecondaryColor[2] * 255.0f); + colorSelected.a = static_cast(currentSecondaryColor[3] * 255.0f); + + CVarSetColor(subEntry.colorCvar, colorSelected); + CVarSetInteger(subEntry.colorChangedCvar, true); + } + } + + if (colorChanged || subEntryChanged) { + Color_RGBA8 colorSelected; + colorSelected.r = static_cast(currentColor[0] * 255.0f); + colorSelected.g = static_cast(currentColor[1] * 255.0f); + colorSelected.b = static_cast(currentColor[2] * 255.0f); + colorSelected.a = static_cast(currentColor[3] * 255.0f); + + CVarSetColor(entry.colorCvar, colorSelected); + CVarSetInteger(entry.colorChangedCvar, true); + } + + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_UNDO, ImVec2(27.0f, 27.0f))) { + CVarClear(entry.colorCvar); + CVarClear(entry.colorChangedCvar); + for (int i = 0; i < subEntries.size(); i++){ + CosmeticEditorElement subEntry = cosmeticEditorElements[subEntries[i]]; + CVarClear(subEntry.colorCvar); + CVarClear(subEntry.colorChangedCvar); + } + } + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_RECYCLE, ImVec2(27.0f, 27.0f))) { + CosmeticEditorRandomizeElement(entry); + } + ImGui::SameLine(); + ImGui::TextColored(CVarGetInteger(entry.colorChangedCvar, 0) ? UIWidgets::Colors::LightGreen + : UIWidgets::Colors::Gray, + CVarGetInteger(entry.colorChangedCvar, 0) ? "Modified" : "Default"); + if (derived) { + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_ARROW_DOWN, ImVec2(27.0f, 27.0f))) { + CosmeticEditorCalculateDerivedElement(entry); + } + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::PopStyleColor(3); +} + +// Tab Bar is unused until other options are available. +void CosmeticEditorDrawTabBar() { + ImGui::BeginTabBar("Cosmetic Tab Bar"); + if (ImGui::BeginTabItem("Colors")) { + CosmeticEditorDrawColorTab(); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); +} + +namespace CosmeticEditor { +void CosmeticEditorWindow::DrawElement() { + CosmeticEditorDrawColorTab(); +} + +void CosmeticEditorWindow::InitElement() { + cosmeticEditorParentElements.clear(); + for (auto& insert : cosmeticEditorElements) { + if (std::find(cosmeticEditorParentElements.begin(), cosmeticEditorParentElements.end(), insert.parentName) != + cosmeticEditorParentElements.end()) { + continue; + } + cosmeticEditorParentElements.push_back(insert.parentName); + } +} +} \ No newline at end of file diff --git a/src/port/ui/CosmeticEditor.h b/src/port/ui/CosmeticEditor.h new file mode 100644 index 000000000..875cb8ad5 --- /dev/null +++ b/src/port/ui/CosmeticEditor.h @@ -0,0 +1,96 @@ +#include + +#ifdef __cplusplus + +namespace CosmeticEditor { +class CosmeticEditorWindow : public Ship::GuiWindow { + public: + using GuiWindow::GuiWindow; + + void InitElement() override; + void DrawElement() override; + void UpdateElement() override{}; +}; +} +extern "C" { +#endif //__cplusplus + +void gDPSetPrimColorWithOverride(Gfx* pkt, u8 m, u8 l, u8 r, u8 g, u8 b, u8 a, const char* cvar); + +void gDPSetEnvColorWithOverride(Gfx* pkt, u8 r, u8 g, u8 b, u8 a, const char* cvar); + +typedef enum CosmeticEditorElementID{ + COSMETIC_ELEMENT_NONE = -1, + COSMETIC_ELEMENT_FOX_RADAR_COLOR, + COSMETIC_ELEMENT_FOX_RADAR_COLOR_DARK, + COSMETIC_ELEMENT_FALCO_RADAR_COLOR, + // COSMETIC_ELEMENT_FALCO_RADAR_COLOR_DARK, //These will only be useful when we have Multiplayer + COSMETIC_ELEMENT_PEPPY_RADAR_COLOR, + // COSMETIC_ELEMENT_PEPPY_RADAR_COLOR_DARK, + COSMETIC_ELEMENT_SLIPPY_RADAR_COLOR, + // COSMETIC_ELEMENT_SLIPPY_RADAR_COLOR_DARK, + + COSMETIC_ELEMENT_WOLF_RADAR_COLOR, + COSMETIC_ELEMENT_LEON_RADAR_COLOR, + COSMETIC_ELEMENT_PIGMA_RADAR_COLOR, + COSMETIC_ELEMENT_ANDREW_RADAR_COLOR, + + COSMETIC_ELEMENT_ARWING_ENGINE_PLANET, + COSMETIC_ELEMENT_ARWING_ENGINE_PLANET_SECONDARY, + COSMETIC_ELEMENT_ARWING_ENGINE_SPACE, + COSMETIC_ELEMENT_ARWING_ENGINE_SPACE_SECONDARY, + + COSMETIC_ELEMENT_WOLFEN_ENGINE_PLANET, + COSMETIC_ELEMENT_WOLFEN_ENGINE_PLANET_SECONDARY, + COSMETIC_ELEMENT_WOLFEN_ENGINE_SPACE, + COSMETIC_ELEMENT_WOLFEN_ENGINE_SPACE_SECONDARY, + + COSMETIC_ELEMENT_MAX +} CosmeticEditorElementID; + +typedef struct { + CosmeticEditorElementID id; + const char* parentName; + const char* name; + uint8_t defaultR; + uint8_t defaultG; + uint8_t defaultB; + uint8_t defaultA; + CosmeticEditorElementID derivedFrom; + float multiplier; + const char* colorCvar; + const char* colorChangedCvar; +} CosmeticEditorElement; + +typedef enum CosmeticEngineGlow { + COSMETIC_GLOW_ARWING, + COSMETIC_GLOW_WOLFEN, + COSMETIC_GLOW_RED, + COSMETIC_GLOW_BLUE, + COSMETIC_GLOW_GREEN, + COSMETIC_GLOW_ORANGE, +} CosmeticEngineGlow; + +const char* GetEngineGlowString(CosmeticEngineGlow glow); + +bool gCosmeticEngineGlowChanged(u8 levelType, CosmeticEngineGlow glowType); + +Color_RGBA8 gCosmeticEngineGlowColor(u8 levelType, CosmeticEngineGlow glowType, bool secondary); + +Color_RGBA8 CosmeticEditor_getChangedColor(u8 r, u8 g, u8 b, u8 a, const char* cvar); + +#define COSMETIC_EDITOR_ELEMENT(id, parentName, name, cvar, defaultR, defaultG, defaultB, defaultA) \ + { \ + (CosmeticEditorElementID)id, parentName, name, defaultR, defaultG, defaultB, defaultA, COSMETIC_ELEMENT_NONE, 0.0f, "gCosmetic." cvar ".Color", \ + "gCosmetic." cvar ".Changed" \ + } + +#define COSMETIC_EDITOR_DERIVED_ELEMENT(id, parentName, name, cvar, defaultR, defaultG, defaultB, defaultA, derivedFrom, multiplier)\ + { \ + (CosmeticEditorElementID)id, parentName, name, defaultR, defaultG, defaultB, defaultA, derivedFrom, multiplier, "gCosmetic." cvar ".Color", \ + "gCosmetic." cvar ".Changed" \ + } +#ifdef __cplusplus +} +std::vector GetAllDerivedFrom(CosmeticEditorElementID id); +#endif //__cplusplus \ No newline at end of file diff --git a/src/port/ui/ImguiUI.cpp b/src/port/ui/ImguiUI.cpp index 122c446b8..0e1741810 100644 --- a/src/port/ui/ImguiUI.cpp +++ b/src/port/ui/ImguiUI.cpp @@ -1,6 +1,7 @@ #include "ImguiUI.h" #include "UIWidgets.h" #include "ResolutionEditor.h" +#include "CosmeticEditor.h" #include #include @@ -26,6 +27,7 @@ std::shared_ptr mConsoleWindow; std::shared_ptr mStatsWindow; std::shared_ptr mInputEditorWindow; std::shared_ptr mGfxDebuggerWindow; +std::shared_ptr mCosmeticEditorWindow; std::shared_ptr mNotificationWindow; std::shared_ptr mAdvancedResolutionSettingsWindow; @@ -74,6 +76,8 @@ void SetupGuiElements() { mNotificationWindow = std::make_shared("gNotifications", "Notifications Window"); gui->AddGuiWindow(mNotificationWindow); mNotificationWindow->Show(); + mCosmeticEditorWindow = std::make_shared("gCosmeticEditor", "Cosmetic Editor"); + gui->AddGuiWindow(mCosmeticEditorWindow); } void Destroy() { @@ -85,6 +89,7 @@ void Destroy() { mStatsWindow = nullptr; mInputEditorWindow = nullptr; mNotificationWindow = nullptr; + mCosmeticEditorWindow = nullptr; } std::string GetWindowButtonText(const char* text, bool menuOpen) { @@ -573,6 +578,20 @@ void DrawEnhancementsMenu() { } } +void DrawCosmeticsMenu(){ + + if (UIWidgets::BeginMenu("Cosmetics")) { + + ImGui::Dummy(ImVec2(150.0f, 0.0f)); + UIWidgets::WindowButton("Cosmetic Editor", "gCosmeticsWindow", GameUI::mCosmeticEditorWindow, { + .tooltip = "Shows the cosmetic editor" + }); + + UIWidgets::Spacer(0); + ImGui::EndMenu(); + } +} + void DrawCheatsMenu() { if (UIWidgets::BeginMenu("Cheats")) { UIWidgets::CVarCheckbox("Infinite Lives", "gInfiniteLives"); @@ -757,10 +776,12 @@ void GameMenuBar::DrawElement() { ImGui::SetCursorPosY(0.0f); - DrawCheatsMenu(); - + DrawCosmeticsMenu(); + ImGui::SetCursorPosY(0.0f); + DrawCheatsMenu(); + ImGui::SetCursorPosY(0.0f); DrawDebugMenu(); diff --git a/src/port/ui/UIWidgets.cpp b/src/port/ui/UIWidgets.cpp index 00f6499b5..5844c5e3c 100644 --- a/src/port/ui/UIWidgets.cpp +++ b/src/port/ui/UIWidgets.cpp @@ -678,7 +678,7 @@ namespace UIWidgets { if (Button(buttonText.c_str(), options)) { windowPtr->ToggleVisibility(); dirty = true; - } + } ImGui::PopStyleVar(); return dirty; }