diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c67ae5..d589d5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,14 +33,17 @@ add_library(platform INTERFACE) find_package(Libultra REQUIRED) target_link_libraries(platform INTERFACE libultra::libultra) target_compile_definitions(platform INTERFACE F3DEX_GBI_2) +target_include_directories(platform INTERFACE + "${PROJECT_SOURCE_DIR}/src" +) add_subdirectory(${ASM_DIR}) add_subdirectory(${ASSETS_DIR}) add_subdirectory(${SRC_DIR}) add_subdirectory(${VPK_DIR}) -add_library(code_segment OBJECT) -target_link_libraries(code_segment +add_library(code_segment STATIC) +target_link_libraries(code_segment PRIVATE platform engine @@ -51,3 +54,46 @@ target_link_libraries(code_segment sound_lookup_tables string_lookup_tables ) + +add_executable(portal) +target_link_libraries(portal PRIVATE + asm_sources + code_segment + levels + models_dynamic + string_data_tables +) + +if (N64) + # Generate linker script + set(INPUT_LINKER_SCRIPT "${PROJECT_SOURCE_DIR}/portal.ld") + set(OUTPUT_LINKER_SCRIPT "${LINKER_SCRIPT_DIR}/portal.ld") + add_custom_command( + DEPENDS + ${INPUT_LINKER_SCRIPT} + anims_linker_script + level_linker_script + models_dynamic_linker_script + string_linker_script + OUTPUT + ${OUTPUT_LINKER_SCRIPT} + COMMAND + ${CMAKE_CPP} -P -Wall -Werror + -I${LINKER_SCRIPT_DIR} + -o ${OUTPUT_LINKER_SCRIPT} ${INPUT_LINKER_SCRIPT} + COMMENT + "Generating $" + VERBATIM + ) + add_custom_target(linker_script + DEPENDS ${OUTPUT_LINKER_SCRIPT} + ) + add_dependencies(portal linker_script) + + # Link + set(LINKER_MAP_FILE "${LINKER_SCRIPT_DIR}/portal.map") + target_link_options(portal PRIVATE + -T ${OUTPUT_LINKER_SCRIPT} + -Map ${LINKER_MAP_FILE} + ) +endif() diff --git a/asm/CMakeLists.txt b/asm/CMakeLists.txt index 5cb74da..302cd98 100644 --- a/asm/CMakeLists.txt +++ b/asm/CMakeLists.txt @@ -3,15 +3,20 @@ #################### set(ASM_FILES + boot.s entry.s rom_header.s sound_data.s ) -add_library(asm_sources INTERFACE) +add_library(asm_sources OBJECT) add_dependencies(asm_sources sound_data_tables ) -target_sources(asm_sources INTERFACE +target_sources(asm_sources PRIVATE ${ASM_FILES} ) +target_compile_definitions(asm_sources PRIVATE + # TODO + #BOOT_CODE=... +) diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt index ceed4a6..24b67e7 100644 --- a/assets/CMakeLists.txt +++ b/assets/CMakeLists.txt @@ -1,6 +1,6 @@ set(VALVE_INTRO_VIDEO "${VPK_DIR}/Portal/hl2/media/valve.bik") -if(NOT EXISTS ${VALVE_INTRO_VIDEO}) +if (NOT EXISTS ${VALVE_INTRO_VIDEO}) # The Mac release of Portal uses a .mov instead of a .bik string(REPLACE ".mov" ".bik" VALVE_INTRO_VIDEO_MAC "${VALVE_INTRO_VIDEO}") @@ -26,6 +26,7 @@ set(SCENE_SCALE 128) # Tools for asset conversion set(CONVERT_ASSET "${PROJECT_SOURCE_DIR}/tools/convert_asset.py") +set(GEN_SEGMENT_LD "${PROJECT_SOURCE_DIR}/tools/generate_segment_ld.js") set(EXPORT_FBX "${PROJECT_SOURCE_DIR}/tools/models/export_fbx.py") set(MODEL_LIST_UTILS "${PROJECT_SOURCE_DIR}/tools/models/model_list_utils.js") @@ -34,3 +35,27 @@ add_subdirectory(models) add_subdirectory(sound) add_subdirectory(test_chambers) add_subdirectory(translations) + +# For linking model and level animations +set(ANIMS_LINKER_SCRIPT "${LINKER_SCRIPT_DIR}/anims.ld") +add_custom_command( + DEPENDS + ${GEN_SEGMENT_LD} + OUTPUT + ${ANIMS_LINKER_SCRIPT} + COMMAND + ${NodeJs_EXECUTABLE} ${GEN_SEGMENT_LD} + --single-segment-name animation_segment + ${ANIMS_LINKER_SCRIPT} + 0x0D000000 + "$,INCLUDE,_anim\..+$>" + "$,INCLUDE,_anim\..+$>" + COMMENT + "Generating $" + COMMAND_EXPAND_LISTS + VERBATIM +) + +add_custom_target(anims_linker_script + DEPENDS ${ANIMS_LINKER_SCRIPT} +) diff --git a/assets/materials/CMakeLists.txt b/assets/materials/CMakeLists.txt index 9019b97..b6d55e7 100644 --- a/assets/materials/CMakeLists.txt +++ b/assets/materials/CMakeLists.txt @@ -98,7 +98,7 @@ function(_add_texture_convert_command INPUT_FILE OUTPUT_FILE) set(OUTPUT_FILE "${PAK_MATERIALS_DIR}/${OUTPUT_FILE}.png") set(ARGS "${ARGN}") - if(NOT ARGS) + if (NOT ARGS) get_source_file_property(FILE_ARGS ${INPUT_FILE} ARGS) if (FILE_ARGS) set(ARGS "${FILE_ARGS}") diff --git a/assets/models/CMakeLists.txt b/assets/models/CMakeLists.txt index d08a3ca..e3882e9 100644 --- a/assets/models/CMakeLists.txt +++ b/assets/models/CMakeLists.txt @@ -222,7 +222,7 @@ foreach(MODEL ${MODELS}) _add_model_export_command(${MODEL} MODEL_FBX) _add_model_generate_command(${MODEL} ${MODEL_FBX} GENERATED_FILES) - if(MODEL IN_LIST DYNAMIC_MODELS) + if (MODEL IN_LIST DYNAMIC_MODELS) list(APPEND DYNAMIC_MODEL_GENERATED_FILES ${GENERATED_FILES}) else() list(APPEND STATIC_MODEL_GENERATED_FILES ${GENERATED_FILES}) @@ -235,6 +235,30 @@ add_custom_target(models DEPENDS ${MODEL_GENERATED_FILES} ) +add_library(models_static OBJECT) +add_dependencies(models_static + materials + models +) +target_sources(models_static PRIVATE + ${STATIC_MODEL_GENERATED_FILES} +) +target_link_libraries(models_static PRIVATE + platform +) + +add_library(models_dynamic OBJECT) +add_dependencies(models_dynamic + materials + models +) +target_sources(models_dynamic PRIVATE + ${DYNAMIC_MODEL_GENERATED_FILES} +) +target_link_libraries(models_dynamic PRIVATE + platform +) + # Add commands for generating dynamic model lists set(MODEL_GENERATED_HEADERS ${MODEL_GENERATED_FILES}) @@ -254,8 +278,8 @@ foreach(GENERATED_HEADER ${MODEL_GENERATED_HEADERS}) OUTPUT_VARIABLE MODEL_NAME ) - if(MODEL_NAME IN_LIST DYNAMIC_MODELS) - if(MODEL_NAME IN_LIST ANIMATED_MODELS) + if (MODEL_NAME IN_LIST DYNAMIC_MODELS) + if (MODEL_NAME IN_LIST ANIMATED_MODELS) list(APPEND DYNAMIC_ANIMATED_MODEL_HEADERS ${GENERATED_HEADER}) else() list(APPEND DYNAMIC_MODEL_HEADERS ${GENERATED_HEADER}) @@ -316,8 +340,25 @@ target_sources(model_lists INTERFACE ${MODEL_LIST_FILES} ) -add_library(models_static INTERFACE) -add_dependencies(models_static models) -target_sources(models_static INTERFACE - ${STATIC_MODEL_GENERATED_FILES} +# Add command for generating dynamic model linker script fragment + +set(DYNAMIC_MODELS_LINKER_SCRIPT "${LINKER_SCRIPT_DIR}/dynamic_models.ld") +add_custom_command( + DEPENDS + ${GEN_SEGMENT_LD} + OUTPUT + ${DYNAMIC_MODELS_LINKER_SCRIPT} + COMMAND + ${NodeJs_EXECUTABLE} ${GEN_SEGMENT_LD} + ${DYNAMIC_MODELS_LINKER_SCRIPT} + 0x03000000 + "$,INCLUDE,_geo\..+$>" + COMMENT + "Generating $" + COMMAND_EXPAND_LISTS + VERBATIM +) + +add_custom_target(models_dynamic_linker_script + DEPENDS ${DYNAMIC_MODELS_LINKER_SCRIPT} ) diff --git a/assets/sound/CMakeLists.txt b/assets/sound/CMakeLists.txt index d5e6246..60d514c 100644 --- a/assets/sound/CMakeLists.txt +++ b/assets/sound/CMakeLists.txt @@ -272,7 +272,7 @@ function(_add_sound_transform_command SOUND_SCRIPT OUTPUT_LIST) set(INPUT_FILE "${PAK_SOUND_DIR}/${SOUND_NAME}.wav") set(OUTPUT_FILE "${PROJECT_BINARY_DIR}/${RELATIVE_CURRENT_DIR}/${SOUND_NAME}.wav") - if(SOUND_SCRIPT MATCHES ".*\.jsox") + if (SOUND_SCRIPT MATCHES ".*\.jsox") _add_sound_transform_command_jsox(${SOUND_SCRIPT} ${INPUT_FILE} ${OUTPUT_FILE}) else() _add_sound_transform_command_sox(${SOUND_SCRIPT} ${INPUT_FILE} ${OUTPUT_FILE}) @@ -411,7 +411,7 @@ foreach(CONVERTED_SOUND ${SOUNDS_CONVERTED}) ) # Only include the sound if an instrument bank doesn't already do so - if(NOT INS_BANK IN_LIST INSTRUMENT_BANKS) + if (NOT INS_BANK IN_LIST INSTRUMENT_BANKS) list(APPEND SOUND_TABLE_INPUTS ${CONVERTED_SOUND}) endif() endforeach() diff --git a/assets/test_chambers/CMakeLists.txt b/assets/test_chambers/CMakeLists.txt index 9bb84f0..379e37c 100644 --- a/assets/test_chambers/CMakeLists.txt +++ b/assets/test_chambers/CMakeLists.txt @@ -154,6 +154,18 @@ add_custom_target(generated_levels DEPENDS ${LEVEL_GENERATED_FILES} ) +add_library(levels OBJECT) +add_dependencies(levels + materials + generated_levels +) +target_sources(levels PRIVATE + ${LEVEL_GENERATED_FILES} +) +target_link_libraries(levels PRIVATE + platform +) + # Add command for generating level list header set(LEVEL_GENERATED_HEADERS ${LEVEL_GENERATED_FILES}) @@ -187,3 +199,26 @@ add_dependencies(level_list generated_level_list) target_sources(level_list INTERFACE ${LEVEL_LIST} ) + +# Add command for generating level linker script fragment + +set(LEVEL_LINKER_SCRIPT "${LINKER_SCRIPT_DIR}/levels.ld") +add_custom_command( + DEPENDS + ${GEN_SEGMENT_LD} + OUTPUT + ${LEVEL_LINKER_SCRIPT} + COMMAND + ${NodeJs_EXECUTABLE} ${GEN_SEGMENT_LD} + ${LEVEL_LINKER_SCRIPT} + 0x02000000 + "$,INCLUDE,_geo\..+$>" + COMMENT + "Generating $" + COMMAND_EXPAND_LISTS + VERBATIM +) + +add_custom_target(level_linker_script + DEPENDS ${LEVEL_LINKER_SCRIPT} +) diff --git a/assets/translations/CMakeLists.txt b/assets/translations/CMakeLists.txt index 9333e91..71f9f45 100644 --- a/assets/translations/CMakeLists.txt +++ b/assets/translations/CMakeLists.txt @@ -75,9 +75,9 @@ add_custom_target(strings ${STRING_DATA_TABLE_FILES} ) -add_library(string_data_tables INTERFACE) +add_library(string_data_tables OBJECT) add_dependencies(string_data_tables strings) -target_sources(string_data_tables INTERFACE +target_sources(string_data_tables PRIVATE ${STRING_DATA_TABLE_FILES} ) @@ -86,3 +86,27 @@ add_dependencies(string_lookup_tables strings) target_sources(string_lookup_tables INTERFACE ${STRING_LOOKUP_TABLE_FILES} ) + +# Add command for generating strings linker script fragment + +set(STRING_LINKER_SCRIPT "${LINKER_SCRIPT_DIR}/subtitles.ld") +add_custom_command( + DEPENDS + ${GEN_SEGMENT_LD} + OUTPUT + ${STRING_LINKER_SCRIPT} + COMMAND + ${NodeJs_EXECUTABLE} ${GEN_SEGMENT_LD} + --alignment 16 + ${STRING_LINKER_SCRIPT} + 0x04000000 + "$" + COMMENT + "Generating $" + COMMAND_EXPAND_LISTS + VERBATIM +) + +add_custom_target(string_linker_script + DEPENDS ${STRING_LINKER_SCRIPT} +) diff --git a/cmake/Toolchain-N64.cmake b/cmake/Toolchain-N64.cmake index 31c2ca3..c468cb2 100644 --- a/cmake/Toolchain-N64.cmake +++ b/cmake/Toolchain-N64.cmake @@ -24,6 +24,7 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) find_program(CMAKE_ASM_COMPILER ${N64_TOOLCHAIN_PREFIX}gcc REQUIRED) find_program(CMAKE_C_COMPILER ${N64_TOOLCHAIN_PREFIX}gcc REQUIRED) +find_program(CMAKE_CPP ${N64_TOOLCHAIN_PREFIX}cpp REQUIRED) find_program(CMAKE_CXX_COMPILER ${N64_TOOLCHAIN_PREFIX}g++ REQUIRED) find_program(CMAKE_LINKER ${N64_TOOLCHAIN_PREFIX}ld REQUIRED) diff --git a/portal.ld b/portal.ld index d59d65f..e3852cb 100644 --- a/portal.ld +++ b/portal.ld @@ -1,5 +1,5 @@ OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-littlemips") -OUTPUT_ARCH(mips) +OUTPUT_ARCH("mips") #define BEGIN_SEG(name, addr) \ _##name##SegmentStart = ADDR(.name); \ @@ -26,15 +26,15 @@ SECTIONS BEGIN_SEG(boot, 0x04000000) { - *asm/rom_header.*(.text); - *asm/boot.*(.text); + */rom_header.*(.text); + */boot.*(.text); } END_SEG(boot) BEGIN_SEG(code, 0x80000400) SUBALIGN(16) { /* code */ - *asm/entry.*(.text); + */entry.*(.text); CODE_SEGMENT(.text); RSP_OBJ(.text); GSP_OBJ(.text); @@ -68,8 +68,8 @@ SECTIONS BEGIN_SEG(sound_data, __romPos) { - *asm/sound_data.*(.data); - *asm/sound_data.*(.bss); + */sound_data.*(.data); + */sound_data.*(.bss); } END_SEG(sound_data) diff --git a/skeletool64/CMakeLists.txt b/skeletool64/CMakeLists.txt index 10ca6d4..da29840 100644 --- a/skeletool64/CMakeLists.txt +++ b/skeletool64/CMakeLists.txt @@ -73,7 +73,7 @@ target_include_directories(skeletool64 PRIVATE ${LUA_INCLUDE_DIR} ) -target_link_libraries(skeletool64 +target_link_libraries(skeletool64 PRIVATE assimp::assimp cimg::cimg PNG::PNG diff --git a/src/util/string.c b/src/util/string.c index 498edf0..0e072a4 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -1,7 +1,7 @@ #include "string.h" size_t strLength(char* s) { - int size = 0; + size_t size = 0; while (*s++ != '\0') { ++size; diff --git a/tools/generate_segment_ld.js b/tools/generate_segment_ld.js index 5f4c078..83ed8b7 100644 --- a/tools/generate_segment_ld.js +++ b/tools/generate_segment_ld.js @@ -10,7 +10,7 @@ function sanitize(s) { function generateSegmentNameFromObject(objectPath) { const { name } = path.parse(objectPath); - return sanitize(name); + return sanitize(name.split('.')[0]); } function generateSegmentContent(objectPath) { @@ -58,6 +58,11 @@ const [outputLinkerScript, loadAddress, ...objectPaths] = positionals; const singleSegmentName = values['single-segment-name']; const alignment = values['alignment']; +const outputParentDir = path.dirname(outputLinkerScript); +if (!fs.existsSync(outputParentDir)) { + fs.mkdirSync(outputParentDir, { recursive: true }); +} + const output = singleSegmentName ? generateSegment(singleSegmentName, loadAddress, alignment, objectPaths) : generateMultiSegments(loadAddress, alignment, objectPaths);