mirror of
https://github.com/mwpenny/portal64-still-alive.git
synced 2024-10-19 22:27:36 -04:00
Start work on dynamic loading of models
This commit is contained in:
parent
1e45fbc6aa
commit
148534a67f
28
Makefile
28
Makefile
|
@ -169,13 +169,12 @@ build/src/scene/elevator.o: build/assets/models/props/round_elevator_collision.h
|
|||
#
|
||||
|
||||
MODEL_LIST = assets/models/cube/cube.blend \
|
||||
assets/models/signage/clock.blend \
|
||||
assets/models/signage/clock_digits.blend \
|
||||
assets/models/player/chell.blend \
|
||||
assets/models/portal_gun/v_portalgun.blend \
|
||||
assets/models/portal_gun/w_portalgun.blend \
|
||||
assets/models/props/autoportal_frame/autoportal_frame.blend \
|
||||
assets/models/props/button.blend \
|
||||
assets/models/signage/clock_digits.blend \
|
||||
assets/models/props/door_01.blend \
|
||||
assets/models/props/door_02.blend \
|
||||
assets/models/props/combine_ball_catcher.blend \
|
||||
|
@ -202,6 +201,9 @@ MODEL_LIST = assets/models/cube/cube.blend \
|
|||
assets/models/grav_flare.blend \
|
||||
assets/models/fleck_ash2.blend
|
||||
|
||||
DYNAMIC_MODEL_LIST = assets/models/signage/clock.blend
|
||||
|
||||
|
||||
ANIM_LIST = build/assets/models/pedestal_anim.o \
|
||||
build/assets/models/props/box_dropper_anim.o \
|
||||
build/assets/models/props/combine_ball_catcher_anim.o \
|
||||
|
@ -214,6 +216,9 @@ ANIM_LIST = build/assets/models/pedestal_anim.o \
|
|||
MODEL_HEADERS = $(MODEL_LIST:%.blend=build/%.h)
|
||||
MODEL_OBJECTS = $(MODEL_LIST:%.blend=build/%_geo.o)
|
||||
|
||||
DYNAMIC_MODEL_HEADERS = $(DYNAMIC_MODEL_LIST:%.blend=build/%.h)
|
||||
DYNAMIC_MODEL_OBJECTS = $(DYNAMIC_MODEL_LIST:%.blend=build/%_geo.o)
|
||||
|
||||
build/assets/models/%.h build/assets/models/%_geo.c build/assets/models/%_anim.c: build/assets/models/%.fbx assets/models/%.flags assets/materials/elevator.skm.yaml assets/materials/objects.skm.yaml assets/materials/static.skm.yaml $(TEXTURE_IMAGES) $(SKELATOOL64)
|
||||
$(SKELATOOL64) --fixed-point-scale 256 --model-scale 0.01 --name $(<:build/assets/models/%.fbx=%) $(shell cat $(<:build/assets/models/%.fbx=assets/models/%.flags)) -o $(<:%.fbx=%.h) $<
|
||||
|
||||
|
@ -233,7 +238,7 @@ build/src/scene/render_plan.o: $(MODEL_HEADERS)
|
|||
|
||||
build/src/scene/portal_render.o: $(MODEL_HEADERS)
|
||||
|
||||
build/src/scene/clock.o: $(MODEL_HEADERS)
|
||||
build/src/scene/clock.o: build/assets/models/dynamic_model_list.h
|
||||
|
||||
build/src/scene/fizzler.o: $(MODEL_HEADERS)
|
||||
|
||||
|
@ -271,12 +276,15 @@ build/src/menu/joystick_options.o: build/assets/materials/ui.h build/src/audio/c
|
|||
|
||||
build/src/menu/controls.o: build/assets/materials/ui.h build/src/audio/clips.h
|
||||
|
||||
build/src/util/dynamic_asset_data.o: build/assets/models/dynamic_model_list_data.h
|
||||
|
||||
build/assets/models/player/chell.h: assets/materials/chell.skm.yaml
|
||||
|
||||
build/assets/models/props/combine_ball_catcher.h: assets/materials/ball_catcher.skm.yaml
|
||||
|
||||
build/assets/models/props/combine_ball_launcher.h: assets/materials/ball_catcher.skm.yaml
|
||||
|
||||
|
||||
ANIM_TEST_CHAMBERS = build/assets/test_chambers/test_chamber_00/test_chamber_00_anim.o \
|
||||
build/assets/test_chambers/test_chamber_03/test_chamber_03_anim.o \
|
||||
build/assets/test_chambers/test_chamber_04/test_chamber_04_anim.o \
|
||||
|
@ -329,9 +337,17 @@ build/assets/test_chambers/level_list.h: $(TEST_CHAMBER_HEADERS) tools/generate_
|
|||
@mkdir -p $(@D)
|
||||
node tools/generate_level_list.js $@ $(TEST_CHAMBER_HEADERS)
|
||||
|
||||
build/assets/models/dynamic_model_list.h build/assets/models/dynamic_model_list_data.h: $(DYNAMIC_MODEL_HEADERS) tools/generate_dynamic_model_list.js
|
||||
@mkdir -p $(@D)
|
||||
node tools/generate_dynamic_model_list.js build/assets/models/dynamic_model_list.h build/assets/models/dynamic_model_list_data.h $(DYNAMIC_MODEL_HEADERS)
|
||||
|
||||
build/levels.ld: $(TEST_CHAMBER_OBJECTS) tools/generate_level_ld.js
|
||||
@mkdir -p $(@D)
|
||||
node tools/generate_level_ld.js $@ $(TEST_CHAMBER_OBJECTS)
|
||||
node tools/generate_level_ld.js $@ 0x02000000 $(TEST_CHAMBER_OBJECTS)
|
||||
|
||||
build/dynamic_models.ld: $(DYNAMIC_MODEL_OBJECTS) tools/generate_level_ld.js
|
||||
@mkdir -p $(@D)
|
||||
node tools/generate_level_ld.js $@ 0x03000000 $(DYNAMIC_MODEL_OBJECTS)
|
||||
|
||||
build/src/levels/levels.o: build/assets/test_chambers/level_list.h build/assets/materials/static.h
|
||||
|
||||
|
@ -407,7 +423,7 @@ $(CODESEGMENT)_no_debug.o: $(CODEOBJECTS_NO_DEBUG)
|
|||
$(LD) -o $(CODESEGMENT)_no_debug.o -r $(CODEOBJECTS_NO_DEBUG) $(LDFLAGS)
|
||||
|
||||
|
||||
$(CP_LD_SCRIPT)_no_debug.ld: $(LD_SCRIPT) build/levels.ld build/anims.ld
|
||||
$(CP_LD_SCRIPT)_no_debug.ld: $(LD_SCRIPT) build/levels.ld build/dynamic_models.ld build/anims.ld
|
||||
cpp -P -Wno-trigraphs $(LCDEFS) -DCODE_SEGMENT=$(CODESEGMENT)_no_debug.o -o $@ $<
|
||||
|
||||
$(BASE_TARGET_NAME).z64: $(CODESEGMENT)_no_debug.o $(OBJECTS) $(DATA_OBJECTS) $(CP_LD_SCRIPT)_no_debug.ld
|
||||
|
@ -425,7 +441,7 @@ endif
|
|||
$(CODESEGMENT)_debug.o: $(CODEOBJECTS_DEBUG)
|
||||
$(LD) -o $(CODESEGMENT)_debug.o -r $(CODEOBJECTS_DEBUG) $(LDFLAGS)
|
||||
|
||||
$(CP_LD_SCRIPT)_debug.ld: $(LD_SCRIPT) build/levels.ld build/anims.ld
|
||||
$(CP_LD_SCRIPT)_debug.ld: $(LD_SCRIPT) build/levels.ld build/dynamic_models.ld build/anims.ld
|
||||
cpp -P -Wno-trigraphs $(LCDEFS) -DCODE_SEGMENT=$(CODESEGMENT)_debug.o -o $@ $<
|
||||
|
||||
$(BASE_TARGET_NAME)_debug.z64: $(CODESEGMENT)_debug.o $(OBJECTS) $(DATA_OBJECTS) $(CP_LD_SCRIPT)_debug.ld
|
||||
|
|
|
@ -78,6 +78,7 @@ SECTIONS
|
|||
END_SEG(images)
|
||||
|
||||
#include "build/levels.ld"
|
||||
#include "build/dynamic_models.ld"
|
||||
#include "build/anims.ld"
|
||||
|
||||
/* Discard everything not specifically mentioned above. */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#define NUM_FIELDS 1
|
||||
|
||||
#define LEVEL_SEGMENT 2
|
||||
#define DYNAMIC_MODEL_SEGMENT 3
|
||||
|
||||
#define DMA_QUEUE_SIZE 200
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "levels/cutscene_runner.h"
|
||||
#include "savefile/savefile.h"
|
||||
#include "sk64/skelatool_animator.h"
|
||||
#include "util/dynamic_asset_loader.h"
|
||||
|
||||
#include "levels/levels.h"
|
||||
#include "savefile/checkpoint.h"
|
||||
|
@ -232,6 +233,7 @@ static void gameProc(void* arg) {
|
|||
heapInit(_heapStart, memoryEnd);
|
||||
levelLoadWithCallbacks(levelGetQueued());
|
||||
cutsceneRunnerReset();
|
||||
dynamicAssetsReset();
|
||||
gSceneCallbacks->initCallback(gSceneCallbacks->data);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,14 @@
|
|||
|
||||
#include "../levels/levels.h"
|
||||
#include "../levels/cutscene_runner.h"
|
||||
#include "../build/assets/models/signage/clock.h"
|
||||
#include "../build/assets/models/signage/clock_digits.h"
|
||||
|
||||
#include "../build/assets/models/dynamic_model_list.h"
|
||||
|
||||
#include "../../build/assets/materials/static.h"
|
||||
|
||||
#include "../util/dynamic_asset_loader.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define DIGIT_WIDTH 512
|
||||
|
@ -86,7 +89,7 @@ void clockRenderRender(void* data, struct DynamicRenderDataList* renderList, str
|
|||
|
||||
dynamicRenderListAddData(
|
||||
renderList,
|
||||
signage_clock_model_gfx,
|
||||
dynamicAssetModel(SIGNAGE_CLOCK_DYNAMIC_MODEL),
|
||||
matrix,
|
||||
AUTOPORTAL_FRAME_INDEX,
|
||||
&clock->transform.position,
|
||||
|
@ -104,6 +107,8 @@ void clockRenderRender(void* data, struct DynamicRenderDataList* renderList, str
|
|||
}
|
||||
|
||||
void clockInit(struct Clock* clock, struct ClockDefinition* definition) {
|
||||
dynamicAssetPreload(SIGNAGE_CLOCK_DYNAMIC_MODEL);
|
||||
|
||||
clock->transform.position = definition->position;
|
||||
clock->transform.rotation = definition->rotation;
|
||||
clock->transform.scale = gOneVec;
|
||||
|
|
2
src/util/dynamic_asset_data.c
Normal file
2
src/util/dynamic_asset_data.c
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
#include "../build/assets/models/dynamic_model_list_data.h"
|
72
src/util/dynamic_asset_loader.c
Normal file
72
src/util/dynamic_asset_loader.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "dynamic_asset_loader.h"
|
||||
#include "memory.h"
|
||||
#include "rom.h"
|
||||
|
||||
#include "../build/assets/models/dynamic_model_list.h"
|
||||
|
||||
extern struct DynamicAssetModel gDynamicModels[];
|
||||
Gfx* gLoadedModels[DYNAMIC_MODEL_COUNT];
|
||||
|
||||
Gfx gBlankGfx[] = {
|
||||
gsSPEndDisplayList(),
|
||||
};
|
||||
|
||||
void dynamicAssetsReset() {
|
||||
zeroMemory(gLoadedModels, sizeof(gLoadedModels));
|
||||
}
|
||||
|
||||
#define ADJUST_POINTER_POS(ptr, offset) (void*)((ptr) ? (char*)(ptr) + (offset) : 0)
|
||||
|
||||
Gfx* dynamicAssetFixModelPointers(Gfx* gfx, u32 pointerOffset, u32 segmentStart, u32 segmentEnd) {
|
||||
// only adjust pointers that land within the segment
|
||||
if ((u32)gfx < segmentStart || (u32)gfx >= segmentEnd) {
|
||||
return gfx;
|
||||
}
|
||||
|
||||
gfx = ADJUST_POINTER_POS(gfx, pointerOffset);
|
||||
while (1) {
|
||||
int commandType = _SHIFTR(gfx->words.w0, 24, 8);
|
||||
|
||||
switch (commandType) {
|
||||
case G_ENDDL:
|
||||
return gfx;
|
||||
case G_DL:
|
||||
if (gfx->dma.par == G_DL_NOPUSH) {
|
||||
break;
|
||||
}
|
||||
gfx->dma.addr = (u32)dynamicAssetFixModelPointers((Gfx*)gfx->dma.addr, pointerOffset, segmentStart, segmentEnd);
|
||||
break;
|
||||
case G_VTX:
|
||||
gfx->dma.addr = (u32)ADJUST_POINTER_POS(gfx->dma.addr, pointerOffset);
|
||||
break;
|
||||
};
|
||||
|
||||
++gfx;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Gfx* dynamicAssetLoadModel(struct DynamicAssetModel* model) {
|
||||
u32 length = (u32)model->addressEnd - (u32)model->addressStart;
|
||||
void* assetMemoryChunk = malloc(length);
|
||||
romCopy(model->addressStart, assetMemoryChunk, length);
|
||||
u32 pointerOffset = (u32)assetMemoryChunk - (u32)model->segmentStart;
|
||||
return dynamicAssetFixModelPointers(model->model, pointerOffset, (u32)model->segmentStart, (u32)model->segmentStart + length);
|
||||
}
|
||||
|
||||
void dynamicAssetPreload(int index) {
|
||||
if (index < 0 || index >= DYNAMIC_MODEL_COUNT || gLoadedModels[index] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
gLoadedModels[index] = dynamicAssetLoadModel(&gDynamicModels[index]);
|
||||
}
|
||||
|
||||
Gfx* dynamicAssetModel(int index) {
|
||||
if (index < 0 || index >= DYNAMIC_MODEL_COUNT || !gLoadedModels[index]) {
|
||||
return gBlankGfx;
|
||||
}
|
||||
|
||||
return gLoadedModels[index];
|
||||
}
|
20
src/util/dynamic_asset_loader.h
Normal file
20
src/util/dynamic_asset_loader.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef __DYNAMIC_ASSET_LOADER_H__
|
||||
#define __DYNAMIC_ASSET_LOADER_H__
|
||||
|
||||
#include <ultra64.h>
|
||||
|
||||
struct DynamicAssetModel {
|
||||
void* addressStart;
|
||||
void* addressEnd;
|
||||
void* segmentStart;
|
||||
Gfx* model;
|
||||
};
|
||||
|
||||
Gfx* dynamicAssetLoadModel(struct DynamicAssetModel* model);
|
||||
|
||||
void dynamicAssetsReset();
|
||||
|
||||
void dynamicAssetPreload(int index);
|
||||
Gfx* dynamicAssetModel(int index);
|
||||
|
||||
#endif
|
91
tools/generate_dynamic_model_list.js
Executable file
91
tools/generate_dynamic_model_list.js
Executable file
|
@ -0,0 +1,91 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function generateInclude(outputLocation, headerLocation) {
|
||||
return `#include "${path.relative(path.dirname(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 generateModelName(outputLocation, headerLocation) {
|
||||
const relative = path.relative(path.dirname(outputLocation), headerLocation).slice(0, -2);
|
||||
return relative.replace(InvalidTokenCharacter, '_') + '_model_gfx';
|
||||
}
|
||||
|
||||
function generateDynamicModelName(outputLocation, headerLocation, index) {
|
||||
const relative = path.relative(path.dirname(outputLocation), headerLocation).slice(0, -2);
|
||||
return relative.replace(InvalidTokenCharacter, '_') + '_dynamic_model';
|
||||
}
|
||||
|
||||
function generateMetadata(outputLocation, headerLocation) {
|
||||
const segmentName = getSegmentName(headerLocation);
|
||||
return ` {
|
||||
_${segmentName}_geoSegmentRomStart,
|
||||
_${segmentName}_geoSegmentRomEnd,
|
||||
_${segmentName}_geoSegmentStart,
|
||||
${generateModelName(outputLocation, headerLocation)},
|
||||
},`;
|
||||
}
|
||||
|
||||
function generateExterns(headerLocation) {
|
||||
const segmentName = getSegmentName(headerLocation);
|
||||
return `
|
||||
extern char _${segmentName}_geoSegmentRomStart[];
|
||||
extern char _${segmentName}_geoSegmentRomEnd[];
|
||||
extern char _${segmentName}_geoSegmentStart[];
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
function generateModelList(outputLocation, headerLocations) {
|
||||
return `struct DynamicAssetModel gDynamicModels[] = {
|
||||
${headerLocations.map(headerLocation => generateMetadata(outputLocation, headerLocation)).join('\n')}
|
||||
};`
|
||||
}
|
||||
|
||||
function generateMetadataDeclaration(outputLocation, headerLocation, index) {
|
||||
const segmentName = getSegmentName(headerLocation);
|
||||
return `#define ${generateDynamicModelName(outputLocation, headerLocation).toUpperCase()} ${index}`;
|
||||
}
|
||||
|
||||
function generateModelHeaderList(outputLocation, headerLocations) {
|
||||
return headerLocations.map((headerLocation, index) => generateMetadataDeclaration(outputLocation, headerLocation, index)).join('\n');
|
||||
}
|
||||
|
||||
function generateData(outputLocation, headerLocations) {
|
||||
return `#ifndef __DYNAMIC_MODEL_LIST_DATA_H__
|
||||
#define __DYNAMIC_MODEL_LIST_DATA_H__
|
||||
|
||||
#include "util/dynamic_asset_loader.h"
|
||||
|
||||
${headerLocations.map(headerLocation => generateInclude(outputLocation, headerLocation)).join('\n')}
|
||||
|
||||
${headerLocations.map(generateExterns).join('\n')}
|
||||
|
||||
${generateModelList(outputLocation, headerLocations)}
|
||||
|
||||
#endif
|
||||
`;
|
||||
}
|
||||
|
||||
function generateHeader(outputLocation, headerLocations) {
|
||||
return `#ifndef __DYNAMIC_MODEL_LIST_DEFINITION_H__
|
||||
#define __DYNAMIC_MODEL_LIST_DEFINITION_H__
|
||||
|
||||
#define DYNAMIC_MODEL_COUNT ${headerLocations.length}
|
||||
|
||||
${generateModelHeaderList(outputLocation, headerLocations)}
|
||||
|
||||
#endif
|
||||
`;
|
||||
}
|
||||
|
||||
fs.writeFileSync(process.argv[2], generateHeader(process.argv[2], process.argv.slice(4)));
|
||||
fs.writeFileSync(process.argv[3], generateData(process.argv[3], process.argv.slice(4)));
|
|
@ -10,11 +10,11 @@ function getSegmentName(objectLocation) {
|
|||
return noExtension.replace(InvalidTokenCharacter, '_');
|
||||
}
|
||||
|
||||
function generateLD(objectLocation) {
|
||||
function generateLD(segmentLocation, objectLocation) {
|
||||
const segmentName = getSegmentName(objectLocation);
|
||||
|
||||
return `
|
||||
BEGIN_SEG(${segmentName}, 0x02000000)
|
||||
BEGIN_SEG(${segmentName}, ${segmentLocation})
|
||||
{
|
||||
${objectLocation}(.data);
|
||||
${objectLocation}(.bss);
|
||||
|
@ -23,10 +23,11 @@ function generateLD(objectLocation) {
|
|||
`;
|
||||
}
|
||||
|
||||
function generateData(objectLocations) {
|
||||
return objectLocations.map(objectLocation => generateLD(objectLocation)).join('\n');
|
||||
function generateData(segmentLocation, objectLocations) {
|
||||
return objectLocations.map(objectLocation => generateLD(segmentLocation, objectLocation)).join('\n');
|
||||
}
|
||||
|
||||
const output = process.argv[2];
|
||||
const segmentLocation = process.argv[3];
|
||||
|
||||
fs.writeFileSync(output, generateData(process.argv.slice(3)));
|
||||
fs.writeFileSync(output, generateData(segmentLocation, process.argv.slice(4)));
|
Loading…
Reference in a new issue