diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d560ab..4c8cad6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,11 +19,6 @@ set(SOX "sox") set(VPK "vpk") set(VTF2PNG "vtf2png") -set(CONVERT_ASSET "${PROJECT_SOURCE_DIR}/tools/convert_asset.py") -set(EXPORT_FBX "${PROJECT_SOURCE_DIR}/tools/export_fbx.py") -set(GEN_LEVEL_LIST "${PROJECT_SOURCE_DIR}/tools/generate_level_list.js") -set(GEN_SOUND_IDS "${PROJECT_SOURCE_DIR}/tools/generate_sound_ids.js") -set(JSOX "${PROJECT_SOURCE_DIR}/tools/jsox.js") set(SKELETOOL64 "${PROJECT_SOURCE_DIR}/skelatool64/skeletool64") # Directories diff --git a/Makefile b/Makefile index 56f7106..362e614 100644 --- a/Makefile +++ b/Makefile @@ -359,7 +359,9 @@ ANIM_LIST = build/assets/models/pedestal_anim.o \ build/assets/models/props/switch001_anim.o MODEL_HEADERS = $(MODEL_LIST:%.blend=build/%.h) -MODEL_OBJECTS = $(MODEL_LIST:%.blend=build/%_geo.o) +MODEL_OBJECTS = $(MODEL_LIST:%.blend=build/%_geo.o) \ + build/assets/models/dynamic_model_list.o \ + build/assets/models/dynamic_animated_model_list.o DYNAMIC_MODEL_HEADERS = $(DYNAMIC_MODEL_LIST:%.blend=build/%.h) DYNAMIC_MODEL_OBJECTS = $(DYNAMIC_MODEL_LIST:%.blend=build/%_geo.o) @@ -415,8 +417,6 @@ build/src/scene/render_plan.o: $(MODEL_HEADERS) build/src/scene/security_camera.o: build/src/audio/clips.h build/assets/models/props/security_camera.h build/assets/models/dynamic_animated_model_list.h build/src/scene/signage.o: $(MODEL_HEADERS) build/src/scene/switch.o: build/assets/models/props/switch001.h build/assets/materials/static.h build/assets/models/dynamic_animated_model_list.h -build/src/util/dynamic_asset_data.o: build/assets/models/dynamic_model_list_data.h -build/src/util/dynamic_animated_asset_data.o: build/assets/models/dynamic_animated_model_list_data.h build/src/util/dynamic_asset_loader.o: build/assets/models/dynamic_model_list.h build/assets/models/dynamic_animated_model_list.h build/src/menu/audio_options.o: build/src/audio/subtitles.h build/src/menu/video_options.o: build/src/audio/subtitles.h @@ -460,7 +460,7 @@ LUA_FILES = $(shell find tools/ -type f -name '*.lua') build/%.fbx: %.blend @mkdir -p $(@D) - $(BLENDER_3_6) $< --background --python tools/export_fbx.py -- $@ + $(BLENDER_3_6) $< --background --python tools/models/export_fbx.py -- $@ build/assets/test_chambers/%.h build/assets/test_chambers/%_geo.c build/assets/test_chambers/%_anim.c: build/assets/test_chambers/%.fbx assets/test_chambers/%.yaml build/assets/materials/static.h build/src/audio/subtitles.h $(SKELATOOL64) $(TEXTURE_IMAGES) $(LUA_FILES) $(SKELATOOL64) --script tools/level_scripts/export_level.lua --fixed-point-scale ${SCENE_SCALE} --model-scale 0.01 --name $(<:build/assets/test_chambers/%.fbx=%) -m assets/materials/static.skm.yaml -o $(<:%.fbx=%.h) $< @@ -478,17 +478,17 @@ build/assets/materials/%_mat.o: build/assets/materials/%_mat.c levels: $(TEST_CHAMBER_HEADERS) echo $(TEST_CHAMBER_HEADERS) -build/assets/test_chambers/level_list.h: $(TEST_CHAMBER_HEADERS) tools/generate_level_list.js +build/assets/test_chambers/level_list.h: $(TEST_CHAMBER_HEADERS) tools/models/generate_level_list.js tools/models/model_list_utils.js @mkdir -p $(@D) - node tools/generate_level_list.js $@ $(TEST_CHAMBER_HEADERS) + node tools/models/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 build/assets/models/cube/cube.h +build/assets/models/dynamic_model_list.h build/assets/models/dynamic_model_list.c: $(DYNAMIC_MODEL_HEADERS) tools/models/generate_dynamic_model_list.js tools/models/model_list_utils.js build/assets/models/cube/cube.h @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) + node tools/models/generate_dynamic_model_list.js build/assets/models/dynamic_model_list.h $(DYNAMIC_MODEL_HEADERS) -build/assets/models/dynamic_animated_model_list.h build/assets/models/dynamic_animated_model_list_data.h: $(DYNAMIC_ANIMATED_MODEL_HEADERS) tools/generate_dynamic_animated_model_list.js +build/assets/models/dynamic_animated_model_list.h build/assets/models/dynamic_animated_model_list.c: $(DYNAMIC_ANIMATED_MODEL_HEADERS) tools/models/generate_dynamic_animated_model_list.js tools/models/model_list_utils.js @mkdir -p $(@D) - node tools/generate_dynamic_animated_model_list.js build/assets/models/dynamic_animated_model_list.h build/assets/models/dynamic_animated_model_list_data.h $(DYNAMIC_ANIMATED_MODEL_HEADERS) + node tools/models/generate_dynamic_animated_model_list.js build/assets/models/dynamic_animated_model_list.h $(DYNAMIC_ANIMATED_MODEL_HEADERS) build/levels.ld: $(TEST_CHAMBER_OBJECTS) tools/generate_level_ld.js @mkdir -p $(@D) @@ -536,9 +536,9 @@ build/assets/%.aifc: assets/%.sox portal_pak_dir/%.wav sox $(<:assets/%.sox=portal_pak_dir/%.wav) $(shell cat $<) $(@:%.aifc=%.wav) $(SFZ2N64) -o $@ $(@:%.aifc=%.wav) -build/assets/%.aifc: assets/%.jsox tools/jsox.js portal_pak_dir/%.wav +build/assets/%.aifc: assets/%.jsox tools/sound/jsox.js portal_pak_dir/%.wav @mkdir -p $(@D) - node tools/jsox.js $< $(<:assets/%.jsox=portal_pak_dir/%.wav) $(@:%.aifc=%.wav) + node tools/sound/jsox.js $< $(<:assets/%.jsox=portal_pak_dir/%.wav) $(@:%.aifc=%.wav) $(SFZ2N64) -o $@ $(@:%.aifc=%.wav) build/assets/%.aifc: assets/%.msox portal_pak_dir/%.mp3 @@ -554,9 +554,9 @@ build/assets/sound/sounds.sounds build/assets/sound/sounds.sounds.tbl: $(SOUND_C build/asm/sound_data.o: build/assets/sound/sounds.sounds build/assets/sound/sounds.sounds.tbl -build/src/audio/clips.h build/src/audio/languages.h build/src/audio/languages.c: tools/generate_sound_ids.js $(SOUND_CLIPS) +build/src/audio/clips.h build/src/audio/languages.h build/src/audio/languages.c: tools/sound/generate_sound_ids.js $(SOUND_CLIPS) @mkdir -p $(@D) - node tools/generate_sound_ids.js -o $(@D) -p SOUNDS_ $(SOUND_CLIPS) + node tools/sound/generate_sound_ids.js -o $(@D) -p SOUNDS_ $(SOUND_CLIPS) build/src/audio/clips.o: build/src/audio/clips.h build/src/decor/decor_object_list.o: build/src/audio/clips.h diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt index 9d7a262..ec9b762 100644 --- a/assets/CMakeLists.txt +++ b/assets/CMakeLists.txt @@ -24,6 +24,11 @@ set(MODEL_SCALE 0.01) # Scaling factor for render space set(SCENE_SCALE 128) +# Tools for asset conversion +set(CONVERT_ASSET "${PROJECT_SOURCE_DIR}/tools/convert_asset.py") +set(EXPORT_FBX "${PROJECT_SOURCE_DIR}/tools/models/export_fbx.py") +set(MODEL_LIST_UTILS "${PROJECT_SOURCE_DIR}/tools/models/model_list_utils.js") + add_subdirectory(materials) add_subdirectory(models) add_subdirectory(sound) diff --git a/assets/models/CMakeLists.txt b/assets/models/CMakeLists.txt index 7ab0b4a..525a89a 100644 --- a/assets/models/CMakeLists.txt +++ b/assets/models/CMakeLists.txt @@ -1,14 +1,51 @@ +cmake_path( + RELATIVE_PATH CMAKE_CURRENT_SOURCE_DIR + BASE_DIRECTORY "${PROJECT_SOURCE_DIR}" + OUTPUT_VARIABLE RELATIVE_CURRENT_DIR +) + ################## ## Model export ## ################## -# TODO: dynamic and animated models - -set(MODELS +# Models whose data is loaded/unloaded as needed +set(DYNAMIC_MODELS cube/cube + props/autoportal_frame/autoportal_frame + props/box_dropper_glass + props/cylinder_test + props/lab_chair + props/lab_desk/lab_desk01 + props/lab_desk/lab_desk02 + props/lab_desk/lab_desk03 + props/lab_desk/lab_desk04 + props/lab_monitor + props/light_rail_endcap + props/portal_cleanser + props/radio + signage/clock + signage/clock_digits +) + +# Animated models whose data is loaded/unloaded as needed +set(DYNAMIC_ANIMATED_MODELS + pedestal + props/box_dropper + props/button + props/combine_ball_catcher + props/combine_ball_launcher + props/door_01 + props/door_02 + props/security_camera + props/switch001 +) + +# All models +set(MODELS + ${DYNAMIC_MODELS} + ${DYNAMIC_ANIMATED_MODELS} fleck_ash2 grav_flare - pedestal player/chell portal_gun/ball_trail portal_gun/v_portalgun @@ -21,32 +58,10 @@ set(MODELS portal/portal_orange portal/portal_orange_face portal/portal_orange_filled - props/autoportal_frame/autoportal_frame - props/box_dropper - props/box_dropper_glass - props/button - props/combine_ball_catcher - props/combine_ball_launcher - props/cylinder_test - props/door_01 - props/door_02 - props/lab_chair - props/lab_desk/lab_desk01 - props/lab_desk/lab_desk02 - props/lab_desk/lab_desk03 - props/lab_desk/lab_desk04 - props/lab_monitor - props/light_rail_endcap - props/portal_cleanser - props/radio props/round_elevator props/round_elevator_collision props/round_elevator_interior - props/security_camera props/signage - props/switch001 - signage/clock - signage/clock_digits ) # Most models depend on both of these. Some only depend on one or the other, @@ -56,13 +71,10 @@ set(MODEL_DEFAULT_MATERIALS ${ASSETS_DIR}/materials/objects.skm.yaml ) -function(_add_model_export_command MODEL_NAME OUTPUT_VARIABLE) - cmake_path( - RELATIVE_PATH CMAKE_CURRENT_SOURCE_DIR - BASE_DIRECTORY "${PROJECT_SOURCE_DIR}" - OUTPUT_VARIABLE RELATIVE_CURRENT_DIR - ) +set(GEN_DYNAMIC_MODEL_LIST "${PROJECT_SOURCE_DIR}/tools/models/generate_dynamic_model_list.js") +set(GEN_DYNAMIC_ANIM_MODEL_LIST "${PROJECT_SOURCE_DIR}/tools/models/generate_dynamic_animated_model_list.js") +function(_add_model_export_command MODEL_NAME OUTPUT_VARIABLE) set(INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}.blend") set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/${RELATIVE_CURRENT_DIR}/${MODEL_NAME}.fbx") @@ -121,7 +133,7 @@ function(_add_model_generate_command MODEL_NAME MODEL_FBX OUTPUT_LIST) COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR} COMMAND - ${CONVERT_ASSET} + ${PYTHON3} ${CONVERT_ASSET} ${SKELETOOL64} ${MODEL_FBX} ${MODEL_FLAGS} @@ -184,3 +196,73 @@ add_custom_target( models DEPENDS ${MODEL_GENERATED_FILES} ) + +# Add commands for generating dynamic model lists + +set(MODEL_GENERATED_HEADERS ${MODEL_GENERATED_FILES}) +list(FILTER MODEL_GENERATED_HEADERS INCLUDE REGEX "\.h$") + +set(DYNAMIC_MODEL_HEADERS "") +set(DYNAMIC_ANIMATED_MODEL_HEADERS "") + +foreach(GENERATED_HEADER ${MODEL_GENERATED_HEADERS}) + cmake_path( + RELATIVE_PATH GENERATED_HEADER + BASE_DIRECTORY "${CMAKE_BINARY_DIR}/${RELATIVE_CURRENT_DIR}" + OUTPUT_VARIABLE MODEL_NAME + ) + cmake_path( + REMOVE_EXTENSION MODEL_NAME + OUTPUT_VARIABLE MODEL_NAME + ) + + if(MODEL_NAME IN_LIST DYNAMIC_MODELS) + list(APPEND DYNAMIC_MODEL_HEADERS ${GENERATED_HEADER}) + elseif(MODEL_NAME IN_LIST DYNAMIC_ANIMATED_MODELS) + list(APPEND DYNAMIC_ANIMATED_MODEL_HEADERS ${GENERATED_HEADER}) + endif() +endforeach() + +set(DYNAMIC_MODEL_LIST_OUT_DIR "${CMAKE_BINARY_DIR}/${RELATIVE_CURRENT_DIR}") + +set(DYNAMIC_MODEL_LIST_H "${DYNAMIC_MODEL_LIST_OUT_DIR}/dynamic_model_list.h") +set(DYNAMIC_MODEL_LIST_C "${DYNAMIC_MODEL_LIST_OUT_DIR}/dynamic_model_list.c") +add_custom_command( + DEPENDS + ${GEN_DYNAMIC_MODEL_LIST} ${MODEL_LIST_UTILS} ${DYNAMIC_MODEL_HEADERS} + OUTPUT + ${DYNAMIC_MODEL_LIST_H} ${DYNAMIC_MODEL_LIST_C} + COMMAND + ${NODEJS} ${GEN_DYNAMIC_MODEL_LIST} + ${DYNAMIC_MODEL_LIST_H} + ${DYNAMIC_MODEL_HEADERS} + COMMENT + "Generating dynamic model list" + VERBATIM +) + +set(DYNAMIC_ANIMATED_MODEL_LIST_H "${DYNAMIC_MODEL_LIST_OUT_DIR}/dynamic_animated_model_list.h") +set(DYNAMIC_ANIMATED_MODEL_LIST_C "${DYNAMIC_MODEL_LIST_OUT_DIR}/dynamic_animated_model_list.c") +add_custom_command( + DEPENDS + ${GEN_DYNAMIC_ANIM_MODEL_LIST} ${MODEL_LIST_UTILS} ${DYNAMIC_ANIMATED_MODEL_HEADERS} + OUTPUT + ${DYNAMIC_ANIMATED_MODEL_LIST_H} ${DYNAMIC_ANIMATED_MODEL_LIST_C} + COMMAND + ${NODEJS} ${GEN_DYNAMIC_ANIM_MODEL_LIST} + ${DYNAMIC_ANIMATED_MODEL_LIST_H} + ${DYNAMIC_ANIMATED_MODEL_HEADERS} + COMMENT + "Generating dynamic animated model list" + VERBATIM +) + +add_custom_target( + model_lists + DEPENDS + ${MODEL_GENERATED_FILES} + ${DYNAMIC_MODEL_LIST_H} + ${DYNAMIC_MODEL_LIST_C} + ${DYNAMIC_ANIMATED_MODEL_LIST_H} + ${DYNAMIC_ANIMATED_MODEL_LIST_C} +) diff --git a/assets/sound/CMakeLists.txt b/assets/sound/CMakeLists.txt index c98f67a..0630495 100644 --- a/assets/sound/CMakeLists.txt +++ b/assets/sound/CMakeLists.txt @@ -186,6 +186,8 @@ set(INSTRUMENT_BANKS weapons/physcannon/energy_sing_loop4.ins ) +set(JSOX "${PROJECT_SOURCE_DIR}/tools/sound/jsox.js") + # TODO: remove function(_add_sound_transform_command_direct SOUND_NAME ARGS OUTPUT_LIST) set(INPUT_FILE "${PAK_SOUND_DIR}/${SOUND_NAME}.wav") @@ -251,7 +253,7 @@ function(_add_sound_transform_command_sox SOUND_SCRIPT INPUT_FILE OUTPUT_FILE) COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR} COMMAND - ${Python3_EXECUTABLE} ${CONVERT_ASSET} ${SOX} ${INPUT_FILE} ${SOUND_SCRIPT} ${OUTPUT_FILE} + ${PYTHON3} ${CONVERT_ASSET} ${SOX} ${INPUT_FILE} ${SOUND_SCRIPT} ${OUTPUT_FILE} COMMENT "Transforming $" VERBATIM @@ -373,6 +375,8 @@ add_custom_target( ## Sound table generation ## ############################ +set(GEN_SOUND_IDS "${PROJECT_SOURCE_DIR}/tools/sound/generate_sound_ids.js") + set(SOUND_TABLE_DEPENDENCIES ${SOUNDS_CONVERTED}) set(SOUND_TABLE_INPUTS "") diff --git a/assets/test_chambers/CMakeLists.txt b/assets/test_chambers/CMakeLists.txt index bf5bdfb..80772ba 100644 --- a/assets/test_chambers/CMakeLists.txt +++ b/assets/test_chambers/CMakeLists.txt @@ -43,6 +43,8 @@ set(EXPORT_SCRIPTS ${PROJECT_SOURCE_DIR}/tools/level_scripts/yaml_loader.lua ) +set(GEN_LEVEL_LIST "${PROJECT_SOURCE_DIR}/tools/models/generate_level_list.js") + function(_add_level_export_command LEVEL_NAME OUTPUT_VARIABLE) set(INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${LEVEL_NAME}/${LEVEL_NAME}.blend") set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/${RELATIVE_CURRENT_DIR}/${LEVEL_NAME}/${LEVEL_NAME}.fbx") @@ -144,7 +146,7 @@ set(LEVEL_LIST "${LEVEL_LIST_OUT_DIR}/level_list.h") add_custom_command( DEPENDS - ${GEN_LEVEL_LIST} ${LEVEL_GENERATED_HEADERS} + ${GEN_LEVEL_LIST} ${MODEL_LIST_UTILS} ${LEVEL_GENERATED_HEADERS} OUTPUT ${LEVEL_LIST} COMMAND diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1df51ce..4de7eaa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,7 @@ add_dependencies(portal # TODO: rework when including models in compilation level_list - models + model_lists ) ############### @@ -159,10 +159,7 @@ target_sources(portal PRIVATE sk64/skelatool_animator.c sk64/skelatool_armature.c util/assert.c - util/dynamic_animated_asset_data.c - util/dynamic_asset_data.c util/dynamic_asset_loader.c - util/linked_list.c util/memory.c util/profile.c util/rom.c diff --git a/src/levels/levels.c b/src/levels/levels.c index 346fedc..a037d89 100644 --- a/src/levels/levels.c +++ b/src/levels/levels.c @@ -117,7 +117,7 @@ void levelLoad(int index) { return; } - struct LevelMetadata* metadata = &gLevelList[index]; + struct LevelMetadata* metadata = &gLevels[index]; void* memory = malloc(metadata->segmentRomEnd - metadata->segmentRomStart); romCopy(metadata->segmentRomStart, memory, metadata->segmentRomEnd - metadata->segmentRomStart); diff --git a/src/levels/levels.h b/src/levels/levels.h index 3b2254d..4e024e8 100644 --- a/src/levels/levels.h +++ b/src/levels/levels.h @@ -1,5 +1,5 @@ -#ifndef __LEVEL_LIST_H__ -#define __LEVEL_LIST_H__ +#ifndef __LEVELS_H__ +#define __LEVELS_H__ #include "physics/collision_object.h" #include "level_definition.h" diff --git a/src/util/dynamic_animated_asset_data.c b/src/util/dynamic_animated_asset_data.c deleted file mode 100644 index 5b73ba2..0000000 --- a/src/util/dynamic_animated_asset_data.c +++ /dev/null @@ -1,2 +0,0 @@ - -#include "../build/assets/models/dynamic_animated_model_list_data.h" \ No newline at end of file diff --git a/src/util/dynamic_asset_data.c b/src/util/dynamic_asset_data.c deleted file mode 100644 index f7fdc32..0000000 --- a/src/util/dynamic_asset_data.c +++ /dev/null @@ -1,2 +0,0 @@ - -#include "../build/assets/models/dynamic_model_list_data.h" \ No newline at end of file diff --git a/src/util/dynamic_asset_loader.c b/src/util/dynamic_asset_loader.c index 813faed..db0f057 100644 --- a/src/util/dynamic_asset_loader.c +++ b/src/util/dynamic_asset_loader.c @@ -6,9 +6,6 @@ #include "../build/assets/models/dynamic_model_list.h" #include "../build/assets/models/dynamic_animated_model_list.h" -extern struct DynamicAssetModel gDynamicModels[]; -extern struct DynamicAnimatedAssetModel gDynamicAnimatedModels[]; - Gfx* gLoadedModels[DYNAMIC_MODEL_COUNT]; u32 gModelPointerOffset[DYNAMIC_MODEL_COUNT]; diff --git a/src/util/dynamic_asset_loader.h b/src/util/dynamic_asset_loader.h index 1b3caf9..2581aaa 100644 --- a/src/util/dynamic_asset_loader.h +++ b/src/util/dynamic_asset_loader.h @@ -3,27 +3,11 @@ #include +#include "dynamic_asset_model.h" + #include "../sk64/skelatool_armature.h" #include "../sk64/skelatool_clip.h" -struct DynamicAssetModel { - void* addressStart; - void* addressEnd; - void* segmentStart; - Gfx* model; - char* name; -}; - -struct DynamicAnimatedAssetModel { - void* addressStart; - void* addressEnd; - void* segmentStart; - struct SKArmatureDefinition* armature; - struct SKAnimationClip** clips; - short clipCount; - char* name; -}; - struct SKArmatureWithAnimations { struct SKArmatureDefinition* armature; struct SKAnimationClip** clips; diff --git a/src/util/dynamic_asset_model.h b/src/util/dynamic_asset_model.h new file mode 100644 index 0000000..10c71aa --- /dev/null +++ b/src/util/dynamic_asset_model.h @@ -0,0 +1,27 @@ +#ifndef __DYNAMIC_ASSET_MODEL_H__ +#define __DYNAMIC_ASSET_MODEL_H__ + +#include + +#include "../sk64/skelatool_armature.h" +#include "../sk64/skelatool_clip.h" + +struct DynamicAssetModel { + void* addressStart; + void* addressEnd; + void* segmentStart; + Gfx* model; + char* name; +}; + +struct DynamicAnimatedAssetModel { + void* addressStart; + void* addressEnd; + void* segmentStart; + struct SKArmatureDefinition* armature; + struct SKAnimationClip** clips; + short clipCount; + char* name; +}; + +#endif diff --git a/tools/generate_dynamic_animated_model_list.js b/tools/generate_dynamic_animated_model_list.js deleted file mode 100644 index d1f7639..0000000 --- a/tools/generate_dynamic_animated_model_list.js +++ /dev/null @@ -1,104 +0,0 @@ -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 generateArmatureName(outputLocation, headerLocation) { - const relative = path.relative(path.dirname(outputLocation), headerLocation).slice(0, -2); - return relative.replace(InvalidTokenCharacter, '_') + '_armature'; -} - -function generateClipsName(outputLocation, headerLocation) { - const relative = path.relative(path.dirname(outputLocation), headerLocation).slice(0, -2); - return relative.replace(InvalidTokenCharacter, '_') + '_clips'; -} - -function generateClipCountName(outputLocation, headerLocation) { - const relative = path.relative(path.dirname(outputLocation), headerLocation).slice(0, -2); - return relative.replace(InvalidTokenCharacter, '_').toUpperCase() + '_CLIP_COUNT'; -} - -function generateDynamicModelName(outputLocation, headerLocation, index) { - const relative = path.relative(path.dirname(outputLocation), headerLocation).slice(0, -2); - return relative.replace(InvalidTokenCharacter, '_') + '_DYNAMIC_ANIMATED_MODEL'; -} - -function generateMetadata(outputLocation, headerLocation) { - const segmentName = getSegmentName(headerLocation); - return ` { - _${segmentName}_geoSegmentRomStart, - _${segmentName}_geoSegmentRomEnd, - _${segmentName}_geoSegmentStart, - &${generateArmatureName(outputLocation, headerLocation)}, - ${generateClipsName(outputLocation, headerLocation)}, - ${generateClipCountName(outputLocation, headerLocation)}, - "${segmentName}", - },`; -} - -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 DynamicAnimatedAssetModel gDynamicAnimatedModels[] = { -${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_ANIMATED_MODEL_LIST_DATA_H__ -#define __DYNAMIC_ANIMATED_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_ANIMATED_MODEL_LIST_DEFINITION_H__ -#define __DYNAMIC_ANIMATED_MODEL_LIST_DEFINITION_H__ - -#define DYNAMIC_ANIMATED_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))); \ No newline at end of file diff --git a/tools/generate_dynamic_model_list.js b/tools/generate_dynamic_model_list.js deleted file mode 100755 index 5717f59..0000000 --- a/tools/generate_dynamic_model_list.js +++ /dev/null @@ -1,92 +0,0 @@ -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)}, - "${segmentName}", - },`; -} - -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))); \ No newline at end of file diff --git a/tools/generate_level_list.js b/tools/generate_level_list.js deleted file mode 100644 index 67e9a17..0000000 --- a/tools/generate_level_list.js +++ /dev/null @@ -1,69 +0,0 @@ -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 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 LevelMetadata gLevelList[] = { -${headerLocations.map(headerLocation => generateMetadata(outputLocation, headerLocation)).join('\n')} -}; -`; -} - -function generateData(outputLocation, headerLocations) { - return `#ifndef __BUILD_LEVEL_LIST_H__ -#define __BUILD_LEVEL_LIST_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 -`; -} - -const output = process.argv[2]; - -fs.writeFileSync(output, generateData(output, process.argv.slice(3))); \ No newline at end of file diff --git a/tools/generate_sound_config.js b/tools/generate_sound_config.js deleted file mode 100644 index 1206e6b..0000000 --- a/tools/generate_sound_config.js +++ /dev/null @@ -1,6 +0,0 @@ -const fs = require('fs'); -const path = require('path'); - -for (const wav of fs.readdirSync(process.argv[2])) { - fs.writeFileSync(path.join(process.argv[3], wav.slice(0, -4)) + '.sox', process.argv[4]); -} \ No newline at end of file diff --git a/tools/export_fbx.py b/tools/models/export_fbx.py similarity index 100% rename from tools/export_fbx.py rename to tools/models/export_fbx.py diff --git a/tools/models/generate_dynamic_animated_model_list.js b/tools/models/generate_dynamic_animated_model_list.js new file mode 100644 index 0000000..c53098a --- /dev/null +++ b/tools/models/generate_dynamic_animated_model_list.js @@ -0,0 +1,36 @@ +const fs = require('fs'); +const path = require('path'); +const util = require('./model_list_utils'); + +function generateModelListEntry(outputPath, modelHeader) { + const modelName = util.generateModelName(modelHeader); + return ` { + _${modelName}_geoSegmentRomStart, + _${modelName}_geoSegmentRomEnd, + _${modelName}_geoSegmentStart, + &${util.generateRelativeModelName(outputPath, modelHeader, '_armature')}, + ${util.generateRelativeModelName(outputPath, modelHeader, '_clips')}, + ${util.generateRelativeModelName(outputPath, modelHeader, '_clip_count').toUpperCase()}, + "${modelName}", + },`; +} + +const [outputHeaderFile, ...modelHeaders] = process.argv.slice(2); +const { dir: outputDir, name: outputName } = path.parse(outputHeaderFile); +const outputSourceFile = `${outputDir}/${outputName}.c` + +const config = { + modelHeaders, + modelGroup: "dynamic_animated_model", + modelType: "DynamicAnimatedAssetModel", + listEntryGenerator: generateModelListEntry +}; + +fs.writeFileSync( + outputHeaderFile, + util.generateHeader(outputHeaderFile, config) +); +fs.writeFileSync( + outputSourceFile, + util.generateData(outputSourceFile, config) +); diff --git a/tools/models/generate_dynamic_model_list.js b/tools/models/generate_dynamic_model_list.js new file mode 100644 index 0000000..1a0f8fb --- /dev/null +++ b/tools/models/generate_dynamic_model_list.js @@ -0,0 +1,34 @@ +const fs = require('fs'); +const path = require('path'); +const util = require('./model_list_utils'); + +function generateModelListEntry(outputPath, modelHeader) { + const modelName = util.generateModelName(modelHeader); + return ` { + _${modelName}_geoSegmentRomStart, + _${modelName}_geoSegmentRomEnd, + _${modelName}_geoSegmentStart, + ${util.generateRelativeModelName(outputPath, modelHeader, '_model_gfx')}, + "${modelName}", + },`; +} + +const [outputHeaderFile, ...modelHeaders] = process.argv.slice(2); +const { dir: outputDir, name: outputName } = path.parse(outputHeaderFile); +const outputSourceFile = `${outputDir}/${outputName}.c` + +const config = { + modelHeaders, + modelGroup: "dynamic_model", + modelType: "DynamicAssetModel", + listEntryGenerator: generateModelListEntry +}; + +fs.writeFileSync( + outputHeaderFile, + util.generateHeader(outputHeaderFile, config) +); +fs.writeFileSync( + outputSourceFile, + util.generateData(outputSourceFile, config) +); diff --git a/tools/models/generate_level_list.js b/tools/models/generate_level_list.js new file mode 100644 index 0000000..3b30859 --- /dev/null +++ b/tools/models/generate_level_list.js @@ -0,0 +1,42 @@ +const fs = require('fs'); +const util = require('./model_list_utils'); + +function generateLevelListEntry(outputPath, levelHeader) { + const levelName = util.generateModelName(levelHeader); + return ` { + &${util.generateRelativeModelName(outputPath, levelHeader, '_level')}, + _${levelName}_geoSegmentRomStart, + _${levelName}_geoSegmentRomEnd, + _${levelName}_geoSegmentStart, + },`; +} + +function generateHeader(outputPath, config) { + const { modelHeaders, modelGroup } = config; + + return util.wrapWithIncludeGuard(outputPath, +`#include "levels/level_metadata.h" + +${util.generateIncludes(outputPath, modelHeaders)} + +${util.generateCount(modelGroup, modelHeaders)} + +${util.generateExterns(modelHeaders)} + +${util.generateModelList(outputPath, config)}` + ); +} + +const [outputHeaderFile, ...modelHeaders] = process.argv.slice(2); + +const config = { + modelHeaders, + modelGroup: "level", + modelType: "LevelMetadata", + listEntryGenerator: generateLevelListEntry +}; + +fs.writeFileSync( + outputHeaderFile, + generateHeader(outputHeaderFile, config) +); diff --git a/tools/models/model_list_utils.js b/tools/models/model_list_utils.js new file mode 100644 index 0000000..dbeadac --- /dev/null +++ b/tools/models/model_list_utils.js @@ -0,0 +1,132 @@ +const path = require('path'); + +const INVALID_TOKEN_CHARACTER = /[^A-Za-z0-9_]/gim; + +// Common + +function sanitize(s) { + return s.replace(INVALID_TOKEN_CHARACTER, '_'); +} + +function wrapWithIncludeGuard(outputPath, content) { + const outputName = path.basename(outputPath); + const includeGuardName = `__${sanitize(outputName).toUpperCase()}__`; + return `#ifndef ${includeGuardName} +#define ${includeGuardName} + +${content} + +#endif +`; +} + +function generateRelativeModelName(outputPath, modelHeader, suffix='') { + const outputDirName = path.dirname(outputPath); + const { dir: headerDirName, name: headerName } = path.parse(modelHeader); + + const relative = path.join( + path.relative(outputDirName, headerDirName), + headerName + ); + + return sanitize(relative + suffix); +} + +function generateModelName(modelHeader) { + return generateRelativeModelName(modelHeader, modelHeader); +} + +function generateListDefinition(modelGroup, modelType) { + const groupPascalCase = modelGroup + .split('_') + .map(s => s && s.replace(/^(\w)/g, m => m.toUpperCase())) + .join(''); + + const listName = `g${groupPascalCase}s`; + return `struct ${modelType} ${listName}[]`; +} + +// Header generation + +function generateCount(modelGroup, modelHeaders) { + return `#define ${modelGroup.toUpperCase()}_COUNT ${modelHeaders.length}`; +} + +function generateModelIndices(outputPath, modelHeaders, modelGroup) { + return modelHeaders.map((modelHeader, index) => { + const modelName = generateRelativeModelName(outputPath, modelHeader, `_${modelGroup}`); + return `#define ${modelName.toUpperCase()} ${index}`; + }).join('\n'); +} + +function generateListExtern(modelGroup, modelType) { + return `extern ${generateListDefinition(modelGroup, modelType)};`; +} + +function generateHeader(outputPath, config) { + const { modelHeaders, modelGroup, modelType } = config; + + return wrapWithIncludeGuard(outputPath, +`#include "util/dynamic_asset_model.h" + +${generateCount(modelGroup, modelHeaders)} + +${generateModelIndices(outputPath, modelHeaders, modelGroup)} + +${generateListExtern(modelGroup, modelType)}` + ); +} + +// Data generation + +function generateIncludes(outputPath, modelHeaders) { + return modelHeaders.map(modelHeader => { + const relativePath = path.relative(path.dirname(outputPath), modelHeader); + return `#include "${relativePath}"`; + }).join('\n'); +} + +function generateExterns(modelHeaders) { + return modelHeaders.map(modelHeader => { + const modelName = generateModelName(modelHeader); + return `extern char _${modelName}_geoSegmentRomStart[]; +extern char _${modelName}_geoSegmentRomEnd[]; +extern char _${modelName}_geoSegmentStart[];`; + }).join('\n\n'); +} + +function generateModelList(outputPath, config) { + const { modelHeaders, modelGroup, modelType, listEntryGenerator } = config; + + return `${generateListDefinition(modelGroup, modelType)} = { +${modelHeaders.map(modelHeader => listEntryGenerator(outputPath, modelHeader)).join('\n')} +};` +} + +function generateData(outputPath, config) { + const { name } = path.parse(outputPath); + const { modelHeaders } = config; + + return `#include "${name}.h" + +${generateIncludes(outputPath, modelHeaders)} + +${generateExterns(modelHeaders)} + +${generateModelList(outputPath, config)} +`; +} + +module.exports = { + wrapWithIncludeGuard, + generateRelativeModelName, + generateModelName, + + generateCount, + generateHeader, + + generateIncludes, + generateExterns, + generateModelList, + generateData +}; diff --git a/tools/generate_sound_ids.js b/tools/sound/generate_sound_ids.js similarity index 100% rename from tools/generate_sound_ids.js rename to tools/sound/generate_sound_ids.js diff --git a/tools/jsox.js b/tools/sound/jsox.js similarity index 100% rename from tools/jsox.js rename to tools/sound/jsox.js