diff --git a/Makefile b/Makefile index 16b25fb..d9aeca2 100644 --- a/Makefile +++ b/Makefile @@ -192,7 +192,7 @@ build/src/scene/portal.o: $(MODEL_HEADERS) ## Test Chambers #################### -TEST_CHAMBERS = assets/test_chambers/test_chamber_00/test_chamber_00.blend +TEST_CHAMBERS = assets/test_chambers/test_chamber_00.blend TEST_CHAMBER_HEADERS = $(TEST_CHAMBERS:%.blend=build/%.h) TEST_CHAMBER_OBJECTS = $(TEST_CHAMBERS:%.blend=build/%_geo.o) diff --git a/assets/test_chambers/test_chamber_00/test_chamber_00.blend b/assets/test_chambers/test_chamber_00.blend similarity index 100% rename from assets/test_chambers/test_chamber_00/test_chamber_00.blend rename to assets/test_chambers/test_chamber_00.blend diff --git a/src/defs.h b/src/defs.h index 3f4b9cc..971a35f 100644 --- a/src/defs.h +++ b/src/defs.h @@ -16,6 +16,8 @@ #define SCHEDULER_PRIORITY 13 #define NUM_FIELDS 1 +#define LEVEL_SEGMENT 2 + #define DMA_QUEUE_SIZE 200 #define SCENE_SCALE 256 diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index cb46856..dbdd00d 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -9,6 +9,8 @@ struct GraphicsTask gGraphicsTasks[2]; extern OSMesgQueue gfxFrameMsgQ; extern OSMesgQueue *schedulerCommandQueue; +void* gLevelSegment; + #if WITH_GFX_VALIDATOR #include "../../gfxvalidator/validator.h" #endif @@ -53,6 +55,7 @@ void graphicsCreateTask(struct GraphicsTask* targetTask, GraphicsCallback callba renderStateInit(renderState, targetTask->framebuffer, zbuffer); gSPSegment(renderState->dl++, 0, 0); + gSPSegment(renderState->dl++, LEVEL_SEGMENT, gLevelSegment); gSPDisplayList(renderState->dl++, setup_rspstate); if (firsttime) { diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index f223af1..1ab4a85 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -25,6 +25,8 @@ struct GraphicsTask { extern struct GraphicsTask gGraphicsTasks[2]; extern Vp fullscreenViewport; +extern void* gLevelSegment; + #define GET_GFX_TYPE(gfx) (_SHIFTR((gfx)->words.w0, 24, 8)) typedef void (*GraphicsCallback)(void* data, struct RenderState* renderState, struct GraphicsTask* task); diff --git a/src/levels/level_metadata.h b/src/levels/level_metadata.h new file mode 100644 index 0000000..9e72f39 --- /dev/null +++ b/src/levels/level_metadata.h @@ -0,0 +1,13 @@ +#ifndef __LEVEL_METADATA_H__ +#define __LEVEL_METADATA_H__ + +#include "level_definition.h" + +struct LevelMetadata { + struct LevelDefinition* levelDefinition; + char* segmentRomStart; + char* segmentRomEnd; + char* segmentStart; +}; + +#endif \ No newline at end of file diff --git a/src/levels/levels.c b/src/levels/levels.c index fb774a9..0b9ff59 100644 --- a/src/levels/levels.c +++ b/src/levels/levels.c @@ -6,6 +6,10 @@ #include "physics/collision_scene.h" #include "static_render.h" #include "cutscene_runner.h" +#include "../graphics/graphics.h" + +#include "../util/rom.h" +#include "../util/memory.h" struct LevelDefinition* gCurrentLevel; u64 gTriggeredCutscenes; @@ -14,12 +18,73 @@ int levelCount() { return LEVEL_COUNT; } +#define ADJUST_POINTER_POS(ptr, offset) (void*)((ptr) ? (char*)(ptr) + (offset) : 0) + +struct LevelDefinition* levelFixPointers(struct LevelDefinition* from, int pointerOffset) { + struct LevelDefinition* result = ADJUST_POINTER_POS(from, pointerOffset); + + result->collisionQuads = ADJUST_POINTER_POS(result->collisionQuads, pointerOffset); + + for (int i = 0; i < result->collisionQuadCount; ++i) { + result->collisionQuads[i].collider = ADJUST_POINTER_POS(result->collisionQuads[i].collider, pointerOffset); + result->collisionQuads[i].collider->data = ADJUST_POINTER_POS(result->collisionQuads[i].collider->data, pointerOffset); + result->collisionQuads[i].body = ADJUST_POINTER_POS(result->collisionQuads[i].body, pointerOffset); + result->collisionQuads[i].data = ADJUST_POINTER_POS(result->collisionQuads[i].data, pointerOffset); + } + + result->staticContent = ADJUST_POINTER_POS(result->staticContent, pointerOffset); + result->roomStaticMapping = ADJUST_POINTER_POS(result->roomStaticMapping, pointerOffset); + result->staticBoundingBoxes = ADJUST_POINTER_POS(result->staticBoundingBoxes, pointerOffset); + result->portalSurfaces = ADJUST_POINTER_POS(result->portalSurfaces, pointerOffset); + + for (int i = 0; i < result->portalSurfaceCount; ++i) { + result->portalSurfaces[i].vertices = ADJUST_POINTER_POS(result->portalSurfaces[i].vertices, pointerOffset); + result->portalSurfaces[i].edges = ADJUST_POINTER_POS(result->portalSurfaces[i].edges, pointerOffset); + result->portalSurfaces[i].gfxVertices = ADJUST_POINTER_POS(result->portalSurfaces[i].gfxVertices, pointerOffset); + } + + result->portalSurfaceMappingRange = ADJUST_POINTER_POS(result->portalSurfaceMappingRange, pointerOffset); + result->portalSurfaceMappingIndices = ADJUST_POINTER_POS(result->portalSurfaceMappingIndices, pointerOffset); + result->triggers = ADJUST_POINTER_POS(result->triggers, pointerOffset); + result->cutscenes = ADJUST_POINTER_POS(result->cutscenes, pointerOffset); + + for (int i = 0; i < result->cutsceneCount; ++i) { + result->cutscenes[i].steps = ADJUST_POINTER_POS(result->cutscenes[i].steps, pointerOffset); + } + + result->locations = ADJUST_POINTER_POS(result->locations, pointerOffset); + result->world.rooms = ADJUST_POINTER_POS(result->world.rooms, pointerOffset); + result->world.doorways = ADJUST_POINTER_POS(result->world.doorways, pointerOffset); + + for (int i = 0; i < result->world.roomCount; ++i) { + result->world.rooms[i].quadIndices = ADJUST_POINTER_POS(result->world.rooms[i].quadIndices, pointerOffset); + result->world.rooms[i].cellContents = ADJUST_POINTER_POS(result->world.rooms[i].cellContents, pointerOffset); + result->world.rooms[i].doorwayIndices = ADJUST_POINTER_POS(result->world.rooms[i].doorwayIndices, pointerOffset); + } + + result->doors = ADJUST_POINTER_POS(result->doors, pointerOffset); + result->buttons = ADJUST_POINTER_POS(result->buttons, pointerOffset); + result->signalOperators = ADJUST_POINTER_POS(result->signalOperators, pointerOffset); + result->decor = ADJUST_POINTER_POS(result->decor, pointerOffset); + result->fizzlers = ADJUST_POINTER_POS(result->fizzlers, pointerOffset); + result->elevators = ADJUST_POINTER_POS(result->elevators, pointerOffset); + + return result; +} + void levelLoad(int index) { if (index < 0 || index >= LEVEL_COUNT) { return; } - gCurrentLevel = gLevelList[index]; + struct LevelMetadata* metadata = &gLevelList[index]; + + void* memory = malloc(metadata->segmentRomEnd - metadata->segmentRomStart); + romCopy(metadata->segmentRomStart, memory, metadata->segmentRomEnd - metadata->segmentRomStart); + + gLevelSegment = memory; + + gCurrentLevel = levelFixPointers(metadata->levelDefinition, (char*)memory - metadata->segmentStart); gTriggeredCutscenes = 0; collisionSceneInit(&gCollisionScene, gCurrentLevel->collisionQuads, gCurrentLevel->collisionQuadCount, &gCurrentLevel->world); diff --git a/tools/generate_level_ld.js b/tools/generate_level_ld.js index 5b87183..25e77d3 100644 --- a/tools/generate_level_ld.js +++ b/tools/generate_level_ld.js @@ -3,11 +3,15 @@ const path = require('path'); const InvalidTokenCharacter = /[^A-Za-z0-9_]/gim; -function generateLD(objectLocation) { +function getSegmentName(objectLocation) { const levelName = path.basename(objectLocation); const noExtension = levelName.slice(0, levelName.length - path.extname(levelName).length); - const segmentName = noExtension.replace(InvalidTokenCharacter, '_'); + return noExtension.replace(InvalidTokenCharacter, '_'); +} + +function generateLD(objectLocation) { + const segmentName = getSegmentName(objectLocation); return ` BEGIN_SEG(${segmentName}, 0x02000000) diff --git a/tools/generate_level_list.js b/tools/generate_level_list.js index 100577f..67e9a17 100644 --- a/tools/generate_level_list.js +++ b/tools/generate_level_list.js @@ -7,14 +7,41 @@ function generateInclude(outputLocation, headerLocation) { const InvalidTokenCharacter = /[^A-Za-z0-9_]/gim; +function getSegmentName(headerLocation) { + const levelName = path.basename(headerLocation); + const noExtension = levelName.slice(0, levelName.length - path.extname(levelName).length); + + return noExtension.replace(InvalidTokenCharacter, '_'); +} + function generateLevelName(outputLocation, headerLocation) { const relative = path.relative(path.dirname(outputLocation), headerLocation).slice(0, -2); return relative.replace(InvalidTokenCharacter, '_') + '_level'; } +function generateMetadata(outputLocation, headerLocation) { + const segmentName = getSegmentName(headerLocation); + return ` { + &${generateLevelName(outputLocation, headerLocation)}, + _${segmentName}_geoSegmentRomStart, + _${segmentName}_geoSegmentRomEnd, + _${segmentName}_geoSegmentStart, + },`; +} + +function generateExterns(headerLocation) { + const segmentName = getSegmentName(headerLocation); + return ` +extern char _${segmentName}_geoSegmentRomStart[]; +extern char _${segmentName}_geoSegmentRomEnd[]; +extern char _${segmentName}_geoSegmentStart[]; +`; + +} + function generateLevelList(outputLocation, headerLocations) { - return `struct LevelDefinition* gLevelList[] = { -${headerLocations.map(headerLocation => ` &${generateLevelName(outputLocation, headerLocation)},`).join('\n')} + return `struct LevelMetadata gLevelList[] = { +${headerLocations.map(headerLocation => generateMetadata(outputLocation, headerLocation)).join('\n')} }; `; } @@ -23,12 +50,14 @@ function generateData(outputLocation, headerLocations) { return `#ifndef __BUILD_LEVEL_LIST_H__ #define __BUILD_LEVEL_LIST_H__ -#include "levels/level_definition.h" +#include "levels/level_metadata.h" ${headerLocations.map(headerLocation => generateInclude(outputLocation, headerLocation)).join('\n')} #define LEVEL_COUNT ${headerLocations.length} +${headerLocations.map(generateExterns).join('\n')} + ${generateLevelList(outputLocation, headerLocations)} #endif