Skip to content
Merged
4 changes: 4 additions & 0 deletions src/engine/CoreMath.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ struct FVector {
return FVector(0, 0, 0);
}

float Square() const {
return x * x + y * y + z * z;
}

FVector() : x(0), y(0), z(0) {}
FVector(float x, float y, float z) : x(x), y(y), z(z) {}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(FVector, x, y, z)
Expand Down
7 changes: 4 additions & 3 deletions src/engine/TrackBrowser.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "TrackBrowser.h"
#include "port/Engine.h"
#include "engine/editor/SceneManager.h"
#include "engine/tracks/CustomTrack.h"
#include <imgui.h>

TrackBrowser* TrackBrowser::Instance;
Expand Down Expand Up @@ -32,7 +33,7 @@ void TrackBrowser::FindCustomTracks() {
}
printf("[TrackBrowser] Added custom track %s\n", info.Name.c_str());
gTrackRegistry.Add(info, [info, archive]() {
auto track = std::make_unique<Track>();
auto track = std::make_unique<CustomTrack>();
track->ResourceName = info.ResourceName;
track->Archive = archive;
GetWorld()->SetCurrentTrack(std::move(track));
Expand All @@ -55,15 +56,15 @@ void TrackBrowser::FindCustomTracks() {

// Create the track
auto archive = manager->GetArchiveFromFile(file);
auto track = std::make_unique<Track>();
auto track = std::make_unique<CustomTrack>();
track->Archive = archive;
track->ResourceName = info.ResourceName;
TrackEditor::SaveLevel(track.get(), static_cast<const TrackInfo*>(&info)); // Write scene file so it will show up in the track browser
printf("[TrackBrowser] [FindCustomTracks] Saved scene.json to new track!\n");

// Passing these through seems kinda bad. But it works?
gTrackRegistry.Add(info, [info, archive]() {
auto track = std::make_unique<Track>();
auto track = std::make_unique<CustomTrack>();
track->Archive = archive;
track->ResourceName = info.ResourceName;
GetWorld()->SetCurrentTrack(std::move(track));
Expand Down
2 changes: 1 addition & 1 deletion src/engine/tracks/BansheeBoardwalk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ void BansheeBoardwalk::Waypoints(Player* player, int8_t playerId) {
}
}

void BansheeBoardwalk::DrawWater(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot,
void BansheeBoardwalk::DrawTransparency(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot,
uint16_t playerDirection) {
gDPPipeSync(gDisplayListHead++);
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
Expand Down
2 changes: 1 addition & 1 deletion src/engine/tracks/BansheeBoardwalk.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class BansheeBoardwalk : public Track {
virtual void DrawCredits() override;
virtual void ScrollingTextures() override;
virtual void Waypoints(Player*, int8_t) override;
virtual void DrawWater(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) override;
virtual void DrawTransparency(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) override;
virtual void CreditsSpawnActors() override;
virtual void Destroy() override;
};
2 changes: 1 addition & 1 deletion src/engine/tracks/BowsersCastle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ void BowsersCastle::Waypoints(Player* player, int8_t playerId) {
}
}

void BowsersCastle::DrawWater(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot,
void BowsersCastle::DrawTransparency(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot,
uint16_t playerDirection) {
if (gActiveScreenMode != SCREEN_MODE_1P) {
return;
Expand Down
2 changes: 1 addition & 1 deletion src/engine/tracks/BowsersCastle.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class BowsersCastle : public Track {
virtual void DrawCredits() override;
virtual void SomeCollisionThing(Player *player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) override;
virtual void Waypoints(Player*, int8_t) override;
virtual void DrawWater(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection);
virtual void DrawTransparency(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection);
virtual void CreditsSpawnActors() override;
virtual void Destroy() override;
};
313 changes: 313 additions & 0 deletions src/engine/tracks/CustomTrack.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
#include "CustomTrack.h"
#include "Track.h"

#include <libultraship/libultraship.h>
#include "libultraship/bridge/resourcebridge.h"
#include "align_asset_macro.h"
#include <unordered_set>
#include <string>
#include <cstring>
#include <algorithm>

#include "engine/Matrix.h"
#include "engine/editor/SceneManager.h"

extern "C" {
#include "collision.h"
#include "render_courses.h"
#include "actors.h"
#include "math_util.h"
}

CustomTrack::CustomTrack() {
Props.SetText(Props.Name, "Blank Track", sizeof(Props.Name));
Props.SetText(Props.DebugName, "blnktrck", sizeof(Props.DebugName));
Props.SetText(Props.TrackLength, "100m", sizeof(Props.TrackLength));
ResourceName = "mod:blank_track";
Props.Minimap.Texture = minimap_mario_raceway;
Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture);
Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture);
Props.Minimap.Pos[0].X = 257;
Props.Minimap.Pos[0].Y = 170;
Props.Minimap.PlayerX = 0;
Props.Minimap.PlayerY = 0;
Props.Minimap.PlayerScaleFactor = 0.22f;
Props.Minimap.FinishlineX = 0;
Props.Minimap.FinishlineY = 0;
Props.Minimap.Colour = { 255, 255, 255 };

Props.WaterLevel = FLT_MAX;

Props.LakituTowType = (s32) OLakitu::LakituTowType::NORMAL;
Props.AIBehaviour = D_0D008F28;
Props.AIMaximumSeparation = 50.0f;
Props.AIMinimumSeparation = 0.3f;
Props.AIDistance = gMarioRacewayAIDistances;
Props.AISteeringSensitivity = 48;

Props.NearPersp = 3.0f;
Props.FarPersp = 6800.0f;

Props.PathSizes = { 600, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 };

Props.CurveTargetSpeed[0] = 4.1666665f;
Props.CurveTargetSpeed[1] = 5.5833334f;
Props.CurveTargetSpeed[2] = 6.1666665f;
Props.CurveTargetSpeed[3] = 6.75f;

Props.NormalTargetSpeed[0] = 3.75f;
Props.NormalTargetSpeed[1] = 5.1666665f;
Props.NormalTargetSpeed[2] = 5.75f;
Props.NormalTargetSpeed[3] = 6.3333334f;

Props.D_0D0096B8[0] = 3.3333332f;
Props.D_0D0096B8[1] = 3.9166667f;
Props.D_0D0096B8[2] = 4.5f;
Props.D_0D0096B8[3] = 5.0833334f;

Props.OffTrackTargetSpeed[0] = 3.75f;
Props.OffTrackTargetSpeed[1] = 5.1666665f;
Props.OffTrackTargetSpeed[2] = 5.75f;
Props.OffTrackTargetSpeed[3] = 6.3333334f;

Props.PathTable[0] = NULL;
Props.PathTable[1] = NULL;
Props.PathTable[2] = NULL;
Props.PathTable[3] = NULL;

Props.PathTable2[0] = NULL;
Props.PathTable2[1] = NULL;
Props.PathTable2[2] = NULL;
Props.PathTable2[3] = NULL;
Props.PathTable2[4] = NULL;

Props.Clouds = NULL;
Props.CloudList = NULL;
Props.Sequence = MusicSeq::MUSIC_SEQ_UNKNOWN;

bFog = false;
gFogColour.r = 0;
gFogColour.g = 0;
gFogColour.b = 0;
gFogColour.a = 255;
gFogMin = 995;
gFogMax = 1000;
}

void CustomTrack::Load() {
/** Get TrackInfo **/
printf("[CustomTrack] Loading... %s\n", ResourceName.c_str());
const TrackInfo* info = gTrackRegistry.GetInfo(ResourceName);
if (nullptr == info) {
printf("[CustomTrack] Could not find TrackInfo for %s\n", ResourceName.c_str());
return;
}

/** Get Directory to Track files **/
const std::string& path = info->Path;
if (path.empty()) {
printf("[CustomTrack] No track path\n");
return;
}

/** Get Props, Minimap, Actors, Environment settings from scene.json **/
TrackEditor::LoadTrackDataFromJson(this, path);

/** Get Track Mesh **/
const std::string meshPath = (path + "/data_track_sections");

TrackSections* meshData = (TrackSections*) LOAD_ASSET_RAW(meshPath.c_str());
if (!meshData) {
printf("[CustomTrack] No valid mesh found!\n");
return;
}

size_t numMesh = ( ResourceGetSizeByName(meshPath.c_str()) / sizeof(TrackSections) );

/** Iterate over meshes **/
for (size_t i = 0; i < numMesh; i++) {
if (gIsMirrorMode != 0) {
CustomTrack::InvertTriangleWindingModdedByName(ResourceGetNameByCrc(meshData[i].crc));
}

/** Sort meshes into DrawLayer queues **/
switch (static_cast<DrawLayer>(meshData[i].layer)) {
case DrawLayer::DRAW_INVISIBLE:
break;
default:
case DrawLayer::DRAW_OPAQUE:
mOpaqueItems.push_back(meshData[i].crc);
break;
case DrawLayer::DRAW_TRANSLUCENT:
mTranslucentItems.push_back(meshData[i]);
break;
case DrawLayer::DRAW_TRANSLUCENT_NO_ZBUFFER:
mTranslucentNoZBufferItems.push_back(meshData[i]);
break;
}
}

Track::Init(); // Base class

/** Generate Collision Mesh **/
CustomTrack::ParseMeshForCollision(meshData, numMesh);
func_80295C6C(); // generate collision grid

/** Dumb hack that needs to be removed **/
if (Props.WaterLevel == FLT_MAX) {
Props.WaterLevel = gTrackMinY - 10.0f;
}
}

void CustomTrack::InvertTriangleWindingModdedByName(const char* name) {
if (name == nullptr) {
return;
}
Gfx* gfx = (Gfx*)ResourceGetDataByName(name);
InvertTriangleWindingModdedInternal(gfx, name);
}

// C++ version of parse_track_displaylists()
void CustomTrack::ParseMeshForCollision(TrackSections* sections, size_t numMesh) {
printf("\n[Track] Generating Collision Meshes...\n");

// Set configurations to zero
D_8015F59C = 0;
D_8015F5A0 = 0;
D_8015F5A4 = 0;

for (size_t i = 0; i < numMesh; i++) {
switch(static_cast<SurfaceClip>(sections[i].clip)) {
case SurfaceClip::CLIP_NONE:
continue;
case SurfaceClip::CLIP_SINGLE_SIDED_WALL:
D_8015F59C = 1;
break;
case SurfaceClip::CLIP_SURFACE:
D_8015F5A0 = 1;
break;
case SurfaceClip::CLIP_DOUBLE_SIDED_WALL:
D_8015F5A4 = 1;
break;
}

const char* name = ResourceGetNameByCrc(sections[i].crc);
printf(" %s\n", name);
generate_collision_mesh((Gfx*) ResourceGetDataByCrc(sections[i].crc), sections[i].surfaceType,
sections[i].sectionId);
}
printf("[Track] Collision Mesh Generation Complete!\n\n");
}

void CustomTrack::TestPath() {
// DEBUG ONLY TO VISUALIZE PATH
return;
s16 x;
s16 y;
s16 z;
Vec3s rot = { 0, 0, 0 };
Vec3f vel = { 0, 0, 0 };

for (size_t i = 0; i < gPathCountByPathIndex[0]; i++) {
x = gTrackPaths[0][i].x;
y = gTrackPaths[0][i].y;
z = gTrackPaths[0][i].z;

if (((x & 0xFFFF) == 0x8000) && ((y & 0xFFFF) == 0x8000) && ((z & 0xFFFF) == 0x8000)) {
break;
}

f32 height = spawn_actor_on_surface(x, 2000.0f, z);
Vec3f itemPos = { (f32) x, height, (f32) z };
add_actor_to_empty_slot(itemPos, rot, vel, ACTOR_ITEM_BOX);
}
}

void CustomTrack::BeginPlay() {
printf("[Track] BeginPlay\n");
CustomTrack::TestPath();
this->SpawnActors();
}

void CustomTrack::Draw(ScreenContext* arg0) {
gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH);
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);

if (bFog) {
gDPSetCycleType(gDisplayListHead++, G_CYC_2CYCLE);
gDPSetRenderMode(gDisplayListHead++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_OPA_SURF2);
gSPSetGeometryMode(gDisplayListHead++, G_FOG);

gDPSetFogColor(gDisplayListHead++, gFogColour.r, gFogColour.g, gFogColour.b, gFogColour.a);
gSPFogPosition(gDisplayListHead++, gFogMin, gFogMax);
gDPPipeSync(gDisplayListHead++);
} else {
gSPClearGeometryMode(gDisplayListHead++, G_FOG);
}

set_track_light_direction(D_800DC610, D_802B87D4, 0, 1);
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH);

if (func_80290C20(arg0->camera) == 1) {
gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE);
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
}

const TrackInfo* info = gTrackRegistry.GetInfo(ResourceName);
if (nullptr == info) {
printf("[Track] [Draw] Resource name did not return a valid TrackInfo %s\n", ResourceName.c_str());
return;
}
std::string res = info->Path + "/data_track_sections";

TrackSections* sections = (TrackSections*) LOAD_ASSET_RAW(res.c_str());
size_t size = ResourceGetSizeByName(res.c_str());
size_t totalSections = size / sizeof(TrackSections);
for (uint64_t item : mOpaqueItems) {
gSPDisplayList(gDisplayListHead++, (Gfx*) ResourceGetDataByCrc(item));
}
}

// This should be a step for tick material
void CustomTrack::ScrollingTextures() {
// D_802B87BC -= 20;
// if (D_802B87BC < 0) {
// D_802B87BC = 0xFF;
// }
// // d_course_royal_raceway_packed_dl_A6A8
// find_and_set_tile_size((uintptr_t) d_course_royal_raceway_packed_dl_A6A8, 0, D_802B87BC);
}

void CustomTrack::DrawTransparency(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) {
FVector cam = { screen->camera->pos[0], screen->camera->pos[1], screen->camera->pos[2] };

std::sort(mTranslucentItems.begin(), mTranslucentItems.end(),
[&](TrackSections a, TrackSections b) {
FVector posA = FVector(a.location[0], a.location[1], a.location[2]);
FVector posB = FVector(b.location[0], b.location[1], b.location[2]);;

float distA = (posA - cam).Square();
float distB = (posB - cam).Square();

return distA > distB; // farthest first
});

for (TrackSections& item : mTranslucentItems) {
Mat4 matrix;
FVector pos = {item.location[0], item.location[1], item.location[2]};
ApplyMatrixTransformations(matrix, pos, IRotator(0, 0, 0), FVector(1, 1, 1));
AddObjectMatrix(matrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(gDisplayListHead++, (Gfx*) ResourceGetDataByCrc(item.crc));
}

gSPClearGeometryMode(gDisplayListHead++, G_ZBUFFER);
for (TrackSections& item : mTranslucentNoZBufferItems) {
Mat4 matrix;
FVector pos = {item.location[0], item.location[1], item.location[2]};
ApplyMatrixTransformations(matrix, pos, IRotator(0, 0, 0), FVector(1, 1, 1));
AddObjectMatrix(matrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(gDisplayListHead++, (Gfx*) ResourceGetDataByCrc(item.crc));
}
gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER);
}
Loading
Loading