diff options
| author | MegaMech <MegaMech@users.noreply.github.com> | 2025-12-29 15:51:12 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-29 15:51:12 -0700 |
| commit | 81d200e74b6fc245424d13631836e7d1c77ba953 (patch) | |
| tree | ec9fb5bb787391aaeb0caff652da0a94091638c5 /src/engine/tracks/CustomTrack.cpp | |
| parent | 5fc7aebf87b91cc9f4c27812dbf6b034012a72df (diff) | |
Refactor Track to CustomTrack Class, impl render layers (#606)
* impl Custom track transparency and clip
* Rename DrawWater to DrawTransparency
* Impl z-sorting for transparent mesh
* Interp work
* rename track function
* cleanup
* Revert texture interp
* Further revert
* Update Harbour
* Impl custom track path select
* Add check
* Fix compile
* Fix function extern
---------
Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com>
Diffstat (limited to 'src/engine/tracks/CustomTrack.cpp')
| -rw-r--r-- | src/engine/tracks/CustomTrack.cpp | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/src/engine/tracks/CustomTrack.cpp b/src/engine/tracks/CustomTrack.cpp new file mode 100644 index 000000000..76fe21afe --- /dev/null +++ b/src/engine/tracks/CustomTrack.cpp @@ -0,0 +1,306 @@ +#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)); + } +} + +void CustomTrack::Tick() { +} + +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); +} |
