diff options
| author | MegaMech <MegaMech@users.noreply.github.com> | 2025-01-09 23:46:18 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-09 23:46:18 -0700 |
| commit | aaba052407728b2f13d11900f2e81a85991c1a91 (patch) | |
| tree | 91d14b8c162a79d7c019454a36374bb3d25a77f4 /src/engine/ModelLoader.cpp | |
| parent | 29872e43c7a98550cfa2f896bdc61589f383d705 (diff) | |
Impl ModelLoader (#150)
* Impl modelloader
Diffstat (limited to 'src/engine/ModelLoader.cpp')
| -rw-r--r-- | src/engine/ModelLoader.cpp | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/engine/ModelLoader.cpp b/src/engine/ModelLoader.cpp new file mode 100644 index 000000000..1c41a8ca9 --- /dev/null +++ b/src/engine/ModelLoader.cpp @@ -0,0 +1,94 @@ +#include "ModelLoader.h" +#include "port/Engine.h" +#include "engine/courses/Course.h" + +extern "C" { +#include "memory.h" +} + +void ModelLoader::Add(LoadModelList list) { + _deferredList.push_back(list); +} + +void ModelLoader::Load() { + if (_hasRan) { // Ensure this does not get ran multiple times + printf("ModelLoader.cpp has already been ran once.\n"); + return; + } + _hasRan = true; + + // Set to track processed courses + std::unordered_set<Course*> processedCourses; + + for (auto& list : _deferredList) { + // Check if the course has already been processed + if (processedCourses.find(list.course) != processedCourses.end()) { + continue; // Skip if already processed + } + + // Process the course + ModelLoader::Extract(list.course); + + // Mark this course as processed + processedCourses.insert(list.course); + } +} + +void ModelLoader::Extract(Course* course) { + Course* saveCourse = gWorldInstance.CurrentCourse; + gWorldInstance.CurrentCourse = course; // Quick hack so that `get_texture` will find the right textures. + + size_t vtxSize = (ResourceGetSizeByName(course->vtx) / sizeof(CourseVtx)) * sizeof(Vtx); + size_t texSegSize; + + // Convert course vtx to vtx + Vtx* vtx = reinterpret_cast<Vtx*>(malloc(vtxSize)); + if (vtx == NULL) { + printf("ModelLoader: Failed to allocate vertex buffer for course: %s\n", course->Props.Name); + return; + } + func_802A86A8(reinterpret_cast<CourseVtx*>(LOAD_ASSET_RAW(course->vtx)), vtx, vtxSize / sizeof(Vtx)); + + // Extract packed DLs + u8* packed = reinterpret_cast<u8*>(LOAD_ASSET_RAW(course->gfx)); + Gfx* gfx = reinterpret_cast<Gfx*>(malloc(sizeof(Gfx) * course->gfxSize)); // Size of unpacked DLs + if (gfx == NULL) { + printf("ModelLoader: Failed to allocate course displaylist memory for course: %s\n", course->Props.Name); + return; + } + + displaylist_unpack(reinterpret_cast<uintptr_t*>(gfx), reinterpret_cast<uintptr_t>(packed), 0); + + // Now that the data has been retrieved, extract the model data and save to provided buffers. + for (auto& list : _deferredList) { + // Ensure the list matches the course being extracted. + if (list.course != course) { + return; + } + + memcpy(list.vtxBuffer, &vtx[list.vtxStart], list.vtxBufferSize * sizeof(Vtx)); + memcpy(list.gfxBuffer, &gfx[list.gfxStart], list.gfxBufferSize * sizeof(Gfx)); + + UpdateVtx(list); + + } + + free(vtx); + free(gfx); + + _deferredList.clear(); + gWorldInstance.CurrentCourse = saveCourse; +} + +void ModelLoader::UpdateVtx(LoadModelList list) { + for (size_t i = 0; i < list.gfxStart + list.gfxBufferSize; i++) { + Gfx* gfx = &list.gfxBuffer[i]; + + // Check if the current Gfx command is G_VTX + if (GFX_GET_OPCODE(gfx->words.w0) == (G_VTX << 24)) { + // Re-write the vtx to point at the provided vtx buffer. + size_t vtxIndex = (gfx->words.w1 / sizeof(Vtx)) - list.vtxStart; + gfx->words.w1 = reinterpret_cast<uintptr_t>(&list.vtxBuffer[vtxIndex]); + } + } +} |
